Skip to content

CM-71014 copilot agent dialect - #520

Merged
Ilanlido merged 3 commits into
mainfrom
CM-71014-copilot-agent-dialect
Aug 17, 2026
Merged

CM-71014 copilot agent dialect#520
Ilanlido merged 3 commits into
mainfrom
CM-71014-copilot-agent-dialect

Conversation

@Ilanlido

Copy link
Copy Markdown
Collaborator

One hooks file is executed by more than one runtime: VS Code's chat runtime and
the Copilot agent runtime (Copilot CLI, and VS Code agent sessions). The agent
runtime keys its payload dialect off the CASE of the configured event key. Cycode
registered camelCase, so it answered with its own dialect (sessionId, no
hook_event_name), which matches_payload rejects - scans were skipped fail-open
with nothing surfaced beyond a -v debug line.

Register PascalCase event keys. Both runtimes then deliver the Claude-style
dialect already parsed here, verified live on Copilot CLI 1.0.75 and VS Code
1.133.

The tool vocabulary still differs per runtime, so accept both rather than switch:
VS Code reads files as read_file/filePath and names MCP tools mcp__;
the agent runtime uses Read/path and -. Agent MCP servers are
declared in ~/.copilot/mcp-config.json, so that is read alongside VS Code's
mcp.json, and the server split is longest-match since server names may themselves
contain the separator. The agent reuses its read tool for directory listings with
an identical payload shape, so the path is stat-ed before it counts as a file read.

Also drop the timestamp-absent condition from ClaudeCode.matches_payload. Matching
on a field being absent is what broke Copilot scanning in the first place, and the
documented transcript_path is a sufficient positive test on its own.

Stale camelCase installs stay rejected; they are corrected by reinstalling hooks.

Ilanlido and others added 2 commits August 16, 2026 11:30
…tool vocabulary

One hooks file is executed by more than one runtime: VS Code's chat runtime and
the Copilot agent runtime (Copilot CLI, and VS Code agent sessions). The agent
runtime keys its payload dialect off the CASE of the configured event key. Cycode
registered camelCase, so it answered with its own dialect (sessionId, no
hook_event_name), which matches_payload rejects - scans were skipped fail-open
with nothing surfaced beyond a -v debug line.

Confirmed against a customer capture where VS Code itself uses the agent runtime,
so this was never CLI-only: their VS Code chat prompts were going unscanned.

Register PascalCase event keys. Both runtimes then deliver the Claude-style
dialect already parsed here, verified live on Copilot CLI 1.0.75 and VS Code
1.133, and against the customer's capture.

The tool vocabulary still differs per runtime, so accept both rather than switch:
VS Code reads files as read_file/filePath and names MCP tools mcp_<server>_<tool>;
the agent runtime uses Read/path and <server>-<tool>. Agent MCP servers are
declared in ~/.copilot/mcp-config.json, so that is read alongside VS Code's
mcp.json, and the server split is longest-match since server names may themselves
contain the separator. The agent reuses its read tool for directory listings with
an identical payload shape, so the path is stat-ed before it counts as a file read.

Also drop the timestamp-absent condition from ClaudeCode.matches_payload. Matching
on a field being absent is what broke Copilot scanning in the first place, and the
documented transcript_path is a sufficient positive test on its own.

Stale camelCase installs stay rejected; they are corrected by reinstalling hooks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nt flag

Report mode was never asynchronous. The rendered command backgrounded the scan
with `<&0 &`, but the backgrounded child inherits the hook's stdout and the runner
reads that pipe until EOF, so the response waited for the scan anyway. Measured:
the runner is released after 0s with the stdout redirect and after the full scan
duration without it. `<&0` is still required - a bare `cmd &` has its stdin
reattached to /dev/null, so the scan reads an empty payload and allows without
scanning anything, which looks non-blocking only because it does nothing.

Render `<&0 >/dev/null 2>&1 &` so the payload flows and the runner is released.

Also stop passing --event and remove the flag. It was added when Copilot CLI
payloads carried no event name, to avoid a reinstall when CLI support landed;
registering the events in PascalCase means every runtime now self-describes via
hook_event_name, so it never had a consumer beyond one debug field.

NOTE: hooks installed before this change still pass --event, and the CLI now
exits 2 on the unknown option. Copilot treats a non-zero PreToolUse exit as a
denial of every tool call, so the MDM scripts must drop --event in the same
rollout that ships this binary.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

Comment thread cycode/cli/apps/ai_guardrails/ides/copilot.py
Comment thread cycode/cli/apps/ai_guardrails/ides/copilot.py Outdated
The stat guard swallowed OSError silently, so a file read that was skipped because
its path could not be reached looked identical to one skipped for being a
directory. Log it at debug with the path.

Reachable on the older interpreters in the support matrix: Path.is_file() raises
PermissionError on 3.9 and 3.11 (verified), while on 3.13+ it delegates to
os.path.isfile and swallows the error itself. requires-python is >=3.9 and the
Docker image and release builds run 3.9, so the branch is live for those installs
and inert for the bundled executable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Ilanlido
Ilanlido enabled auto-merge (squash) August 17, 2026 08:05
@Ilanlido
Ilanlido merged commit c5e1f99 into main Aug 17, 2026
28 checks passed
@Ilanlido
Ilanlido deleted the CM-71014-copilot-agent-dialect branch August 17, 2026 08:52
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.

2 participants