Skip to content

fix: copilot host wiring targeted surfaces Copilot CLI does not read - #28

Merged
ivklgn merged 2 commits into
mainfrom
fix/copilot-mcp-path
Jul 27, 2026
Merged

fix: copilot host wiring targeted surfaces Copilot CLI does not read#28
ivklgn merged 2 commits into
mainfrom
fix/copilot-mcp-path

Conversation

@ivklgn

@ivklgn ivklgn commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

archcore init --agent copilot wired a Copilot CLI teammate to two things that host ignores, so the SessionStart hook fired into a session with no archcore tools and no context — silently, with a green install log.

MCP config went to a path Copilot CLI does not read

It wrote .vscode/mcp.json in VS Code shape ("servers" key, "type": "stdio"). Copilot CLI dropped that source in v1.0.37 (github/copilot-cli#3019); it belongs to VS Code alone, a surface copilot-adapter-design.adr explicitly scopes out.

The path it moves to is not .github/mcp.json either. GitHub's config-dir reference lists that one, but it has never been read as a workspace source (#1886, still open; confirmed by the maintainer closing #1291). The only project-level MCP source Copilot CLI reads is the workspace-root .mcp.json, keyed mcpServers, discovered from the working directory up to the git root.

That is the same file claude-code already writes, with the same key and the same bare {command, args} entry — so copilot now shares the standard writer instead of carrying its own. Wiring both hosts converges on one entry in either order, pinned by a test since a shared target is new here and a duplicating merge would reshape the file on every init.

Removing the VS Code writer takes the JSONC corruption policy with it: corruptSkipInstall existed solely because .vscode/mcp.json may carry comments. With no JSONC target left, writeMCPConfig drops the policy parameter and always backs up an unparsable file.

Session-start emitted the wrong output shape

archcore hooks copilot session-start emitted Claude's {"hookSpecificOutput": {...}} wrapper. We register the hook under camelCase sessionStart — Copilot's native format — whose documented output is a bare top-level additionalContext. Copilot's PascalCase compat mode changes only the input payload, never the output schema, so the wrapper parsed as nothing and the session started blind.

Session-start now takes a per-host output shape. Copilot gets the native form (no systemMessage slot on that host, so the connected banner is dropped rather than smuggled into context); every other host keeps the Claude-compatible one. Both shapes are pinned by tests.

Verification

go vet, gofmt, go test ./... clean. End to end against a scratch repo: init writes .mcp.json + .github/hooks/archcore.json + AGENTS.md and no .vscode/, and the two hosts' session-start outputs differ as intended.

🤖 Generated with Claude Code

ivklgn and others added 2 commits July 27, 2026 11:52
`archcore init --agent copilot` wired a Copilot CLI teammate to two
things that host ignores, so the hook fired into a session with no
archcore tools and no context — silently, with a green install log.

MCP config went to .vscode/mcp.json in VS Code shape ("servers" key,
"type": "stdio"). Copilot CLI dropped that source in v1.0.37
(github/copilot-cli#3019); it belongs to VS Code alone, a surface
copilot-adapter-design.adr explicitly scopes out. The path it moves to
is NOT .github/mcp.json either — GitHub's config-dir reference lists
that one, but it has never been read as a workspace source
(github/copilot-cli#1886, still open; confirmed by the maintainer
closing #1291). The only project-level MCP source Copilot CLI reads is
the workspace-root .mcp.json, keyed "mcpServers", discovered from the
working directory up to the git root.

That is the same file claude-code already writes, with the same key and
the same bare {command, args} entry, so copilot now shares the standard
writer instead of carrying its own. Wiring both hosts converges on one
entry in either order — pinned by a test, since a shared target is new
here and a duplicating merge would reshape the file on every init.

Removing the VS Code writer takes the JSONC corruption policy with it:
corruptSkipInstall existed solely because .vscode/mcp.json may carry
comments. With no JSONC target left, writeMCPConfig drops the policy
parameter and always backs up an unparsable file.

Second fix, same silent class: `archcore hooks copilot session-start`
emitted Claude's {"hookSpecificOutput": {...}} wrapper. We register the
hook under camelCase "sessionStart" — Copilot's native format — whose
documented output is a bare top-level additionalContext. Copilot's
PascalCase compat mode changes only the INPUT payload, never the output
schema, so the wrapper parsed as nothing and the session started blind.
Session-start now takes a per-host output shape; Copilot gets the native
form (no systemMessage slot on that host, so the connected banner is
dropped rather than smuggled into context), every other host keeps the
Claude-compatible one. Both shapes are pinned by tests.

Verified end to end: init writes .mcp.json + .github/hooks/archcore.json
+ AGENTS.md and no .vscode/, and the two hosts' session-start outputs
differ as intended.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`go test ./...` ran in exactly one place: release.yml, on a tag push.
So a broken test first surfaced during a release, with the tag already
pushed and the only remedy a follow-up tag. Nothing gated a PR — the
green checks on one were CodeQL alone, which says nothing about whether
the code works.

Same three commands the release already trusts, moved to where they can
still cheaply say no. Formatting runs first because it is the cheapest
signal and the one most likely to differ between a contributor's editor
and the repo; gofmt is checked rather than applied so CI never rewrites
a contributor's tree.

Concurrency cancels superseded runs on branches but not on main, where
every commit should keep a result of its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ivklgn
ivklgn merged commit c048cb8 into main Jul 27, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant