GitHub Copilot support¶
steer is built for Claude Code, but teammates who use GitHub Copilot - either the Copilot CLI or Copilot in VS Code - can pick up the same org engineering standards. This page explains how all surfaces share one source of truth and how to install and refresh the Copilot side.
Scope
The Copilot target covers the always-on standards
(.github/copilot-instructions.md, read by both the CLI and VS Code), the
skills (as cross-tool SKILL.md on the CLI, and as
.agents/skills/steer-*/ in the open Agent Skills format, read by every
non-Claude agent), custom agents
(.github/agents/*.agent.md - the steer-reviewer port), path-scoped
instructions (.github/instructions/*.instructions.md), MCP servers
(.vscode/mcp.json), an opt-in cloud coding-agent setup workflow
(copilot-setup-steps.yml). It does not cover hooks: the Copilot CLI
hook variant retired, so hook enforcement is guaranteed on Claude Code
only. Copilot Chat in VS Code runs hooks/hooks.json directly and gets
them incidentally, with no parity promise. Skill enforcement still differs
from Claude Code - see the sections below for the caveats.
Surfaces at a glance¶
| Capability | Claude Code | Copilot CLI | Copilot in VS Code |
|---|---|---|---|
| Always-on standards | SessionStart hook -> raw stdout, in parts | .github/copilot-instructions.md (no hooks - the CLI variant retired) |
SessionStart hook (the plugin's hooks/hooks.json, run by VS Code) -> hookSpecificOutput.additionalContext, incidental and unguaranteed; .github/copilot-instructions.md as the reliable path |
| Path-scoped standards | rule inject-when traits |
not delivered - emitted only to .github/instructions/ (see below) |
.github/instructions/*.instructions.md (applyTo glob) |
| Skills | plugin skills/ (/steer:<skill>) |
plugin skills/ via Copilot manifest |
.agents/skills/steer-*/ (/steer-<skill>) |
| Subagents | plugin agents/ |
not declared - the Copilot manifest carries skills only |
.github/agents/*.agent.md (agent picker) |
| MCP servers | plugin .mcp.json |
not declared - the Copilot manifest has no mcpServers key |
.vscode/mcp.json |
| Cloud coding agent | - (Claude @claude workflow) |
- | .github/workflows/copilot-setup-steps.yml (opt-in) |
| Gate hooks | hooks/hooks.json (deny on version pins, ask on the trunk-push gate) |
none - the CLI hook variant retired | hooks/hooks.json as-is, incidentally - VS Code runs the Claude-format hooks (hard deny on version pins), with no parity promise |
| Source of truth | rules/*.md + skills/ + agents/ |
the same rules/ + skills/ + agents/ |
the same rules/ + skills/ + agents/ |
Every one of those artifacts - instructions, the cross-tool .agents/skills/ tree, custom agents, the
VS Code mcp.json, and the plugin + marketplace manifest
versions - is generated from that one source and guarded by a build-time drift
gate (see below) that fails the build the moment a
committed artifact drifts. A symmetry meta-gate (check_copilot_symmetry.py,
part of plugin-check) further asserts the same wiring across both generated
families - *_copilot_* (the Copilot-only artifacts) and *_agent_* (the
cross-tool .agents/skills/ tree): every gen_*.py in either is wired into
gen:copilot, and every check_*.py into plugin-check - so a generator
no task runs, or a gate no task invokes, fails the build. It asserts wiring, not
generator<->gate pairing: gen_copilot_manifests.py has no check_copilot_manifests.py
counterpart, because the manifest versions are gated by check_plugin.py's
version-sync check instead. None of them is hand-maintained.
Why the surfaces differ¶
On every surface, steer's rules reach the session through the SessionStart
hook (inject-standards.sh) - but the three harnesses want its stdout in
three shapes, and the script tells them apart (steer_hook_host in
hooks/lib/json.sh):
- Claude Code takes raw text and caps one hook command's stdout at 10,000
characters, so the ruleset arrives in parts (one registration of the script
per part in
hooks/hooks.json). - Copilot CLI runs no steer hooks: the Copilot manifest declares
skillsonly, and the always-on standards reach it through the committed.github/copilot-instructions.md. Its hook surface can take injected context (a top-leveladditionalContextunder the camelCasesessionStartevent), and steer shipped a generated manifest for it until hook parity retired - a second manifest, a generator, a drift gate and a per-hook porting decision, for a surface nothing guaranteed. - Copilot Chat in VS Code does not read the Copilot manifest at all: it
detects steer as a Claude-format plugin (
.claude-plugin/plugin.json) and runshooks/hooks.jsonas-is. It injects only fromhookSpecificOutput.additionalContextand logs everything else as "returned non-JSON output". The script recognises VS Code's payload (snake_caseSessionStartcarryingmodelandtimestamp, and nopermission_mode- the documented Claude Code field) and emits the same envelope from part 1, staying silent on the other eight registrations.
One JSON object carries both keys, so a single code path serves both Copilot
surfaces: the CLI reads the top-level key and ignores the nested one, VS Code the
reverse. A Claude Code payload, or any shape the script does not recognise, keeps
the raw parted output - a mis-read can only ever fall back to today's behaviour,
never lose the ruleset on Claude. The inject-when scoping, knowledge-work mode
and the missing-rules fallback banner all ride inside the envelope.
The static custom-instructions file, .github/copilot-instructions.md, stays
as the fallback: the Copilot cloud coding agent and Copilot code review
load no plugins (the cloud agent runs hooks only from a repo's own
.github/hooks/*.json), so for them the committed file is the whole standards
surface, and it also covers a session where the hook cannot run. A build-time
generator (mise run gen:copilot) concatenates the rules into that committed
artifact, and a sync gate (check_copilot_instructions.py, part of
plugin-check) fails the build if the artifact ever drifts from the rules. The
same generator step also renders the cross-tool skill tree (below), with its own
drift gate (check_agent_skills.py).
Why .github/copilot-instructions.md, not AGENTS.md¶
Copilot reads several repository instruction files and merges them - including
AGENTS.md and CLAUDE.md/GEMINI.md - resolving conflicts
non-deterministically. Emitting an AGENTS.md would therefore double-load the
org standards alongside a repo's existing CLAUDE.md, while Claude Code (which
does not read AGENTS.md) would ignore it entirely.
.github/copilot-instructions.md is Copilot's primary instructions file, is
never read by Claude Code, and lives under .github/ so it does not compete
at the repo root with CLAUDE.md. That keeps each surface reading exactly one
copy of the standards.
Using it as a Copilot teammate¶
The standards file and the skill tree are installed by /steer:setup init (new repos)
or /steer:setup adopt (existing repos), run from Claude Code during bootstrap -
see the Adopt workflow. Copilot teammates only consume
the files; they do not need to generate them.
Copilot CLI¶
The CLI loads the skills via the Copilot plugin manifest and reads the standards
from .github/copilot-instructions.md in the repo.
Copilot in VS Code¶
VS Code does not use the Copilot CLI plugin marketplace, so there is nothing
to install - it reads the committed repo files directly:
- Standards -
.github/copilot-instructions.mdis read automatically as the repository's custom instructions (governed by thegithub.copilot.chat.codeGeneration.useInstructionFilessetting, default-on in recent VS Code). To confirm it loaded, expand the References section of a Copilot Chat response - the file is listed there (or right-click the Chat view -> Diagnostics). - Skills - every steer skill ships as a real
SKILL.mdunder.agents/skills/steer-<skill>/, one of the three project-skill locations VS Code discovers (alongside.github/skills/and.claude/skills/). Each is surfaced in Chat as a/steer-<skill>slash-command. Type/steer-in Chat to see them. Nothing in.vscode/settings.jsongates this - skill discovery is on by default.
The bundled .vscode/settings.json sets both settings explicitly, so the
standards load regardless of a teammate's VS Code defaults.
Refreshing after a steer update¶
In VS Code the always-on rules need no refresh: the SessionStart hook reads them
from the installed plugin, so a plugin update is the whole upgrade path there
(the Extensions view). On the Copilot CLI, which runs no steer hooks, the
rules arrive only through the committed .github/copilot-instructions.md, so a
copilot plugin update steer refreshes the skills and the instructions file
must be regenerated to match. The committed Copilot files - the instructions
fallback, the cross-tool skill tree, custom agents, path-scoped instructions -
are a static snapshot, so they go stale when steer's rules or skills change.
Refresh them with /steer:setup sync from Claude Code:
copilot plugin update steer # CLI only: pull the new plugin version
# then, from Claude Code in the repo:
/steer:setup sync # re-copies copilot-instructions.md,
# .agents/skills/, agents/, instructions/
/steer:setup sync --check # read-only: reports the surface as mis-wired
# when it has fallen behind
/steer:setup sync owns this because the refresh is a capability repair:
agent-surface-current is wired only when every generated file is
byte-identical to its plugin source and no retired steer-*.prompt.md
lingers under .github/prompts/. The repair is a verbatim re-copy plus the
deletion of any lingering steer--prefixed prompt file - a copy cannot remove
one, so without that half the capability reports mis-wired after every repair.
A prompt file the team wrote themselves is theirs and stays.
/steer:setup init is not the refresh path - it installs the surface at bootstrap
and then deliberately stops on an already-initialized repo, so re-running it does
nothing.
For the Copilot cloud coding agent and code review, which load no plugins, this static set is the entire standards surface - so a repo that never refreshes leaves those surfaces working against the rules of whatever plugin version bootstrapped it, while Copilot CLI, VS Code and Claude Code sessions are current. Put the refresh on whoever owns plugin updates; the launch checklist carries it as a rollout item.
The files are fully steer-managed - overwritten on refresh and never
hand-edited. Repo-specific Copilot guidance belongs in a separate
*.instructions.md file, not in these; the re-copy never touches a file you own.
Skills on Copilot¶
steer's skills are authored as SKILL.md files. They reach the two Copilot
surfaces differently:
- Copilot CLI reads
SKILL.mdnatively (an open cross-tool standard). A Copilot-specific plugin manifest (plugins/steer/.github/plugin/plugin.json, which Copilot prefers over the.claude-plugin/manifest Claude Code uses) points Copilot atskills/. Its version - and the Copilot marketplace manifest's - is stamped from the sourceplugin.jsonbygen_copilot_manifests.py(mise run gen:copilot), so no Copilot manifest is hand-versioned either. - Copilot in VS Code reads the committed
.agents/skills/tree. This is not a Copilot-specific rendering:.agents/skills/is one of the interoperable locations defined by the Agent Skills open standard, so the same tree is discovered by Cursor, Gemini CLI and Codex without any further work.
The build renders one .agents/skills/steer-<skill>/ directory per skill -
including every user-invocable: false gateway, which the model can reach even
though no one can type them - carrying the real skill body and its supporting
mode files, not a summary. A body has to be rewritten to work off Claude
Code (gen_agent_skills.py):
| In the authored skill | In the portable copy | Why |
|---|---|---|
${CLAUDE_PLUGIN_ROOT}/skills/<self>/modes/x.md |
modes/x.md |
The file travels with the skill, which is exactly the spec's colocation convention. |
${CLAUDE_PLUGIN_ROOT}/templates/reference/..., and relative ../../templates/... links |
a blob/main URL on this repo |
Shared by many skills; vendoring several hundred KB - MIGRATIONS.md alone is the largest single file - into every consumer repo is not worth it, and the repo is public. These URLs are not currently fetchable - see Known limitations. |
/steer:<skill> |
/steer-<skill> |
Plugin namespacing is Claude Code's; the slash name here is the skill's directory name. |
Three differences from Claude Code remain on the Copilot surfaces - the first two
on both, the third on VS Code only (which runs the plugin's hooks.json
incidentally, per the table above; the CLI runs no steer hooks at all). Their
mitigations do not: both notes below are injected by the generator into the
portable .agents/skills/ tree, so the VS Code surface carries them. The
Copilot CLI loads the authored skills/ directly, where context: fork and
disallowed-tools are present-but-unhonoured and no note appears - read the two
bullets there as caveats you apply yourself.
- Forked skills are not forked here.
context: forknames a Claude Code execution mode no other agent implements, so the portable copy drops it - but the two skills that use it (steer-explain,/steer-status) argue from forked execution in their bodies -steer-explainmost sharply, telling the reader "this skill runs forked, andAskUserQuestionis removed from every subagent". That premise is false on this surface, and it would forbid a correct action. Both portable copies therefore open with a note saying the fork passages describe Claude Code, and that where a step says it cannot ask, you may. - Tool-permission scoping is inert. No non-Claude agent honors steer's
allowed-tools/disallowed-tools, and their values are Claude tool syntax anyway - so the portable copy drops both fields rather than shipping a grant that means nothing. A skill that was frontmatter-restricted upstream instead opens with an explicit note that the restriction is now enforced by instruction, not by tooling, so a body reading "the edit tools are unavailable" is not mistaken for a guarantee. Treat those skills as advisory there. - No steer hook gates a skill mid-run on either Copilot surface - the CLI
runs none, and the hooks VS Code picks up from
hooks.jsonguard writes and Bash calls, not skill bodies.
Custom agents on Copilot¶
steer's subagents in the plugin's agents/ reach VS Code as custom agents -
.github/agents/<name>.agent.md, selectable from the Copilot Chat agent picker
(this is the format formerly called "custom chat modes"/.chatmode.md). Today
that is steer-reviewer, the read-only reviewer that /steer-audit and
/steer-work --reviewed delegate a single bounded slice to. The scheduled loop
delegates to it too, but it is not a slash-command there: a user-invocable:
false skill gets no /steer-<name> command.
The build renders one .agent.md per subagent (gen_copilot_agents.py, drift
gate check_copilot_agents.py). The subagent's Claude tools (Read/Grep/
Glob) are mapped to Copilot's read-only built-in tool sets (codebase,
search), so the ported reviewer stays write-free on VS Code the same way it is
in Claude Code.
Scope preconditions in the flat file¶
A scoped rule that is not area-specific stays in copilot-instructions.md,
because there is no applyTo glob that means "this repo is on the e22 org pack"
or "this repo's tracker is GitHub". The flat file cannot test a repo trait, so
the generator states the trait as a precondition the reader can check
instead: SCOPE_PRECONDITIONS in gen_copilot_instructions.py emits a
blockquote under the rule's heading -
Applies only to a repo on the e22 org pack -
policy/org.ymlwithpack: e22, which is also what an absent file means. [...]
Five sections carry one today (the org pack's stack and commands rules, the
OpenSpec backend, issue-first, and the autonomous-loop rule). The map is keyed by
token, not by rule, so a new trait-scoped rule inherits the qualification
rather than depending on its author writing a conditional first sentence - and
check_copilot_instructions.py fails when a token appears in neither
SCOPE_PRECONDITIONS nor the deliberate UNQUALIFIED_TOKENS exemption list.
That gate exists because of #577,
where rule 33 told native spec/ repos "This repo carries an openspec/
spine".
A path-scoped rule (next section) needs none of this: applyTo already gates
the file, so the sentence would be redundant.
Path-scoped instructions¶
Most rules are repo-wide and live in the flat copilot-instructions.md. A rule
that is genuinely area-specific - currently the infra/IaC stack rule - is emitted
instead as a path-scoped instruction file,
.github/instructions/<name>.instructions.md, carrying an applyTo glob so
Copilot loads it only when working on matching files (e.g. **/*.tf, infra/**).
This is the Copilot analog of the Claude SessionStart hook's inject-when trait
gating; the same rule source drives both, and a scoped rule is excluded from
the flat file so it never double-loads. The same generator + drift gate as the
flat instructions (gen_copilot_instructions.py / check_copilot_instructions.py)
keeps them in sync.
A scoped rule reaches VS Code only
Because the exclusion is unconditional (iter_rule_files filters SCOPED_RULES),
a path-scoped rule is not in .github/copilot-instructions.md - today that
means rule 12-stack-infra, the IaC stack standards. That directory is read by
Copilot in VS Code and by the cloud coding agent; whether the Copilot CLI
reads it is unverified here, so a CLI teammate working on Terraform may receive
no IaC standards. If you need them there, load the file explicitly.
Do not "fix" this by dropping the rule from SCOPED_RULES: that key drives both
the flat-file exclusion and the scoped emission, and main() prunes the
orphaned file - so you would move the rule into every consumer's always-on
context and delete infra.instructions.md, not resolve the gap.
Repo-specific Copilot guidance you author yourself also goes in a separate
*.instructions.md you own - never edit the steer-generated ones.
MCP servers in VS Code¶
Copilot in VS Code does not read the plugin's .mcp.json (that wires Claude
Code only). So the scaffold ships .vscode/mcp.json - VS Code's servers
schema - mirroring the same servers: the GitHub MCP server that the tracker
gateway (tracker-sync, reached through /steer-work and its issues mode - it is
user-invocable: false, so no one types it directly) is built around, and
context7 for current library docs. The GitHub server prompts once for a PAT
(stored in VS Code secret storage). Without it, Copilot's tracker workflow falls
back to gh only.
Like the other Copilot artifacts, this file is generated - gen_copilot_mcp.py
renders it from the plugin's .mcp.json (mise run gen:copilot), translating the
one sanctioned difference: the auth placeholder (env var -> prompted input, mapped
in the generator's AUTH_INPUTS). A byte-equality drift gate
(check_copilot_mcp.py, part of plugin-check) fails the build if the committed
mirror falls out of sync. Edit .mcp.json and regenerate - never hand-edit the
template in this repo.
That byte-gate governs the plugin-side template only. Unlike the four artifacts
under .github/, the installed .vscode/mcp.json is not steer-managed: it sits
outside /steer:setup sync's agent-surface-current capability, so a consumer owns
their copy and is expected to merge additively and remove servers they don't use.
Nothing re-copies it over their edits; only a one-shot ledger migration amends it.
Cloud coding agent (opt-in)¶
The GitHub-side Copilot coding agent (assign it an issue, it works in an
ephemeral environment and opens a PR) reads the same
.github/copilot-instructions.md + .github/instructions/ for standards. To make
it boot a steer repo correctly, the scaffold carries
.github/workflows/copilot-setup-steps.yml - it installs the pinned mise
toolchain and runs dev:setup. The job name copilot-setup-steps is required;
MCP + firewall for the agent are set in repo Settings -> Copilot -> Coding agent,
not in-repo.
It is opt-in - /steer:setup init does not install it automatically; add it only
for repos that use the coding agent. It fits steer's autonomous-loop rules: the
coding agent opens draft PRs and never merges, so the human merge gate stands.
Point it only at PR-flow repos (protected main), never solo-trunk.
Gate hooks on Copilot¶
Hook enforcement is guaranteed on Claude Code only. The Copilot CLI hook
variant - hooks/copilot-hooks.json, its generator, its drift gate and the
STEER_HOOK_TARGET=copilot branches inside the hook scripts - retired: it cost a
second manifest, a per-hook porting decision and a softened envelope for a surface
steer never promised parity on, and the gates it carried were ported, not proven
(whether the CLI exports CLAUDE_PLUGIN_ROOT was never verified). The standards
themselves still reach the CLI, through .github/copilot-instructions.md.
Copilot Chat in VS Code gets the hooks incidentally. It detects steer as a
Claude-format plugin and runs hooks/hooks.json directly, with Claude's envelope
and matcher syntax (matchers are ignored there, so every hook runs on every
matching event). So the PreToolUse gates do fire in VS Code, as Claude's hard
deny on version pins, and the SessionStart and Stop hooks run too: the
ruleset injector recognises VS Code's payload shape and answers with the JSON
envelope it reads (see Why the surfaces differ), while
the advisory notices (session-checks.sh, orient-session.sh) emit raw text that
VS Code discards. None of that is a promise - it is what the surface happens to
do today, and a VS Code change could stop it without steer being at fault.
The advisory spec-first / issue-first nudges, and the issue-create contract guard
in check-bash-actions.sh, were never ported anywhere: their intent is carried by
the standards in .github/copilot-instructions.md.
Known limitations¶
- The rewritten shared-file URLs are not fetchable. The rewrite in the table
above points at GitHub's HTML
blob/view rather thanraw.githubusercontent.com, and it is applied inside runnable command lines too, so those ship assh "https://...". Because the rewrite is unconditional, any step that depends on reading a shared file or running a shared script is affected - for some skills that costs a link, for others the whole procedure. Detail, and what is unaffected, in Known limitations. - Tool-permission scoping is inert. See Skills on Copilot -
the bodies themselves port in full, but neither frontmatter tool field does
anything here.
disallowed-toolsremoves nothing from the pool, where Claude Code at least removes those tools for the invoking turn;allowed-toolspre-approves nothing, though it grants without restricting in Claude Code either. Both limits port as instructions only. (Thesteer-reviewersubagent does port as a custom agent.) - No hook guarantee off Claude Code. The CLI runs no steer hooks at all; VS
Code runs
hooks/hooks.jsonincidentally, so it gets Claude's harddenyon version pins rather than anything tuned for it. The advisory nudges live in the standards text, not as hooks, and the advisory SessionStart notices emit raw text that VS Code discards. - Invocation form differs by surface, and the instructions file is shared.
.github/copilot-instructions.mdcarries the rules verbatim, so every skill cross-reference in them reads/steer:<skill>. In VS Code the invocable form is/steer-<skill>(the.agents/skills/tree); on the CLI skills load from the plugin manifest. Because one file serves both surfaces, a blanket rewrite would be wrong for one of them - the generated file therefore opens with a note stating the mapping. The skill-tree artifacts are rewritten to the hyphen form bygen_agent_skills.py. - Standards delivery on the CLI is the committed file, not a hook. Nothing
steer ships executes on the Copilot CLI, so
.github/copilot-instructions.mdis the whole always-on surface there. It is installed by/steer:setup initand refreshed by/steer:setup sync; a repo that never ran either gets no standards on that surface. - Polyrepo topology is Claude-only. Workspace/member role detection is emitted
by the
orient-session.shSessionStart hook as raw text, which the Copilot surfaces discard (only the ruleset injector emits their JSON envelope so far). There is deliberately no always-on polyrepo rule for the generator to carry, so a Copilot session gets no topology note. The full topology is in the polyrepo reference, which Claude Code loads (/steer:reference polyrepo). - Worktree
mise trustinheritance is Claude-only.check-worktree-trust.shruns on two Claude-Code registrations -SessionStartandCwdChanged- so a Copilot session started in or entered into a linked worktree does not inherit the primary checkout's trust, and its firstmise run ...fails on trust, not on the task - the cost a polyrepo pays per member per feature. The standards carry the remedy instead of a hook: rule45-delivery§ Parallel worktrees tells the agent to runmise trustin the worktree before its firstmise run ...- only when the primary checkout is already trusted, the same condition the hook applies - and otherwise to ask the human to runmise trust && mise installthere, so no surface creates first-time trust.mise trustis idempotent, so the instruction is also free on Claude Code where the check already ran. - Worktree teardown is Claude-only too. Stopping a worktree's Docker stack
is now done by two Claude-Code lifecycle hooks (
SessionEnd->docker:down,WorktreeRemove->docker:clean), and neither event exists on a Copilot surface - so Copilot gets neither. This is exactly the trap this page exists to avoid: an unscoped rule asserting a safety net that is not there. Rules45-delivery§ Parallel worktrees and50-done§ End-of-session checklist therefore scope the hook claim to Claude Code and leavemise run docker:cleanas the agent's own job everywhere else. (On Claude Code only theWorktreeRemovehalf is dependable; theSessionEndhalf is best-effort - see Hooks -> Lifecycle events.) What is surface-agnostic is the per-worktreeCOMPOSE_PROJECT_NAME/port offset: it comes from the scaffold'smiseconfig (scripts/worktree-env.sh), not from a hook. - SessionStart notices never arrive, so the rules no longer promise them.
Beyond the worktree check above, three always-on notices used to tell the
agent a SessionStart hook would flag a condition: a missing
/specspine (rule00-router), an in-progressspec/BUILD-STATUS.md(rule05-roles), and recorded hook faults (00-router§ When steer itself misbehaves - two of the three now live in the router, which absorbed the self-report rule in 6.6). Copilot'ssessionStartignores stdout, so the notice never comes - and its absence reads as "condition not present," which is worse than no promise at all. Each rule now scopes the flag to Claude Code and, where there is something a reader could look for themselves (rules00-routerand05-roles), says to do that instead; rule00-router§ When steer itself misbehaves only scopes, because recorded hook faults exist on no other surface. Likewise rule10-stackno longer claims a hook denies stale image-major pins without qualification: the ported gate only asks on the Copilot CLI (VS Code, which runs the Claude hooks as-is, does deny), so the rule now says to keep the pins current yourself. - One further rule scoped, two whose detail moved out, plus one skill. The same
sweep, finished. Rule
90-design-sourcespointed at thefrontend-designplugin, which the Copilot marketplace does not list, so it was scoped to Claude Code inline (the rule has since left the always-on payload forDESIGN-SOURCES.md, which carries the same qualification). Two others no longer need scoping because the surface-specific detail left the rule entirely: rule61-gates§ Hotfix is now surface-neutral about thehotfix/<n>-slugprefix (the reconciliation it used to name is theStophookreconcile-issue-first.sh, which is not ported - noStophook is, so on Copilot the prefix carries the convention alone), and rule36-issue-firstno longer enumerates theallow/askpermission tiers. Those tiers are Claude Code's - they live in.claude/settings.jsonand Claude skill frontmatter, and are documented in the plugin'sISSUE-WORKFLOW.md, which the flat Copilot standards file does not carry; Copilot applies its own host permissions instead, which is what the rule's surviving text describes. And/steer:spec questionsleaned oncheck-open-questions.shfor both the backlog nudge and the 14-day blocking escalation with no alternative - its body now tells any other surface to apply that age test by hand. - Manual refresh. Unlike Claude Code's live injection, the Copilot files must be regenerated after a plugin update (see above).
- Hooks are Preview. Copilot's plugin hooks are Preview and can be disabled by org policy, so the standards delivery never depends on them; the Copilot hook is hardened to fail open (it can never block an edit on error).