# GitHub Copilot (VS Code agent mode / CLI)

GitHub Copilot (VS Code agent mode / CLI) and chock: install methods and steps, what it can enforce, and the evidence behind it.

Install methods: sync. Agentseam tier block+rewrite, grade best-effort before a tool runs.

> Ask the user before running any command on this page: each one changes how their agent or repository behaves.

## Install methods

- Repo hooks: `chock sync --repo . --agents copilot` writes `.github/hooks/*.json` (ask the user before running it)

## What it can enforce

- Tier: block+rewrite
- Grade before a tool runs: best-effort
- Fail mode before a tool runs: open
- Basis: live-run-partial
- Recorded: 2026-09-28

## Events

| Event | Can block | Can rewrite | Fail mode |
| --- | --- | --- | --- |
| pre_tool | yes | yes | open |
| post_tool | yes | no | open |
| prompt_submit | yes | no | open |
| session_start | no | no | open |
| subagent_start | no | no | open |
| stop | yes | no | open |
| subagent_stop | yes | no | open |

## Ask support

Answers an ask with: ask. Honours ask: yes. Evidence: tested (tests/test_guard_fail_to_ask.py::test_a_crashed_guard_asks_rather_than_allowing).

## Hook timeout

The engine records no timeout for this agent.

## Test status

- Repo hooks: tested. A test of the plugin says nothing about repo hooks.
- Through the sync install, at hook point agent-hooks: Copilot CLI and VS Code agent mode, 2026-08-23. live probe: an exit-2 deny blocked a matched command on both (chock 5d78831)

## Known limits

Two products behind one row, and they do not spell events the same way: HOOKS_BY_TARGET gives VS Code agent mode PascalCase names (Claude Code's exactly) and the GitHub Copilot CLI camelCase ones (sessionStart, userPromptSubmitted, agentStop). This adapter claimed camelCase only until 2026-08-28, so it never claimed a real VS Code payload at all -- those went to claude_code alone and were answered in its dialect, which is right at PreToolUse and wrong everywhere else. `timestamp`, which chatHookService merges into every payload, is what separates the two; Tabnine sends it too, so SessionStart -- the one event name Tabnine and VS Code share -- is left ambiguous rather than guessed. `postToolUseFailure`, previously mapped, claimed and installed for, is in neither vendor's name map: it never existed. The hook file install writes is the object keyed by event that both products document for .github/hooks/*.json, and VS Code's own schema tolerates the _agentseam marker (microsoft/vscode@d93a384 hookSchema.ts: additionalProperties true on the file, the hooks map and each command; read 2026-10-13); whether the Copilot CLI tolerates it, or a file with no version, its docs do not say and its source is not public. Four response dialects, because the consumer reads a different shape at each: PreToolUse takes hookSpecificOutput.permissionDecision (ask and updatedInput both native, and updatedInput is validated against the tool's schema and silently discarded if it fails), UserPromptSubmit and PostToolUse take a top-level {decision: block, reason}, Stop and SubagentStop take those two fields nested in hookSpecificOutput and drop the block if the reason is missing, and SessionStart/SubagentStart run under ignoreErrors:true where even exit 2 is swallowed. hookEventName is echoed rather than hardcoded: _toHookResult strips hookSpecificOutput outright when the name does not match the event being run. Fails OPEN, not closed as this row claimed for two weeks: exit 2 blocks, but any other non-zero exit is a NonBlockingError that warns the user and lets the call proceed. Also parses Claude settings.json via hookClaudeCompat, and ignores `matcher` -- it is read and thrown away, so there is no tool filtering and the guard must check event.tool itself. Memory writes arrive as the 'memory' tool (create/str_replace/insert), not file edits. Copilot CLI's own camelCase preToolUse (docs.github.com/en/copilot/reference/hooks-configuration, read 2026-09-27; vendor docs, not yet witnessed live) sends no event name at all -- {sessionId, timestamp, cwd, toolName, toolArgs} -- so it is claimed by toolArgs and answered with a top-level {permissionDecision, permissionDecisionReason}; it has no input rewrite, so a transform there blocks. Live, Windows, 2026-09-28 (Copilot CLI runtime, one observation): a pre_tool hook whose command errored under PowerShell (the entry then had no `powershell` key) made Copilot deny EVERY tool call ("Denied by preToolUse hook ... (hook errored)"). That is not recorded as fail_mode closed: it is a single uncontrolled run of one runtime, the error was a shell parse failure rather than a hook that started and exited with a chosen non-2 code, and it contradicts the VS Code source reading (any non-zero exit other than 2 is a NonBlockingError) that the open claim rests on. Both may be true -- the CLI runtime and VS Code's own engine may differ -- but until a hook that runs and exits 1 is tried on each, `open` stays and a consumer must not rely on either behaviour. Which of the two products a Windows payload came from is not reliably visible in the payload. The camelCase `agentStop` payload names no event, so it is claimed by `stopReason` and parsed as a stop.


---

Built from engine [5a4b6287a46e](https://github.com/open-coder-ai/chock/commit/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021) and catalog [1e60d211c1bb](https://github.com/open-coder-ai/chock-catalog/commit/1e60d211c1bb767152c6ab0167932da06ab3a10f).
