Skip to main content
Working with an agent? Give them a link to this page as markdown.

GitHub Copilot CLI

The Watcher client records Copilot sessions and reviews tool calls through blocking review. Copilot monitoring is enabled by default. Existing user choices and administrator locks still apply through managed settings.

Set up and verify​

If you use COPILOT_HOME, set the same absolute path for Copilot and all Watcher commands that manage its hooks.

  1. Close Copilot.

  2. Install and sign in to Watcher. Check that Copilot can answer a prompt with your existing provider settings.

  3. With Watcher running, check monitoring:

    watcher agents list
    watcher doctor hooks

    The Copilot row should say current. If it says needs setup, run watcher hooks install. If your settings list agents explicitly, such as agents.enabled: [claude_code, codex], add copilot. Administrator locks still win.

  4. Restart Copilot and ask it to read a harmless file. Find the session in the Analyzer and check its messages, tool call and decision. Hook status alone does not prove delivery.

The session shows GitHub Copilot CLI as its agent and Watcher Live as its source.

Copilot needs a Watcher server from the same release as the client, or later, since the server reads Copilot's own session log. Update the server before the clients. An older server refuses Copilot uploads and grading requests, while Claude Code and Codex keep working. Each call that needs grading gets the failure policy, and its reason says the server cannot read Copilot logs. Refused uploads are retried in the background like any failed upload.

Turn monitoring off or on​

Run watcher agents disable copilot or watcher agents enable copilot, then restart Copilot. The choice survives profiles, updates and hook repair. Disabling stops new transcript reads; captured decisions may still upload. See Agent hooks for statuses and administrator locks.

Watcher owns ~/.copilot/hooks/watcher.json, or $COPILOT_HOME/hooks/watcher.json. User processes can edit these hooks. Copilot settings that disable hooks or permit only managed hooks stop this integration. For custom launchers, see Start on login.

Setup also adds a status line to Copilot's settings.json in ~/.copilot, or $COPILOT_HOME. It shows Watcher signed out: uploads paused or Watcher auth error: uploads paused as Claude Code's status line does, and Session excluded from Watcher in an excluded directory. If you already have a statusLine, or the file is not plain JSON, for example because it has comments, setup leaves the file unchanged and prints the setting to add. Removing the hooks removes only Watcher's own status line.

Decisions and Copilot permissions​

Watcher applies your command rules and thresholds. For those, Copilot's bash, view, edit and ask_user count as Bash, Read, Edit and AskUserQuestion. The stored conversation and decisions keep Copilot's own tool names. Copilot's apply_patch keeps its name and is judged as one call, as Codex's is, so rules and thresholds for apply_patch apply to it. Questions pass through by default; question rules need custom AskUserQuestion thresholds, such as flag 7 and deny 9.

In enforce mode, Watcher can deny a call or request approval in Copilot's terminal. When Watcher allows a call, it answers Copilot with an explicit allow. Copilot then runs the call without its own permission prompt, also in copilot -p without --allow-all-tools. This includes a configured allow when grading fails. In copilot -p, an escalation is refused because nobody can answer. Observe mode leaves execution to Copilot's permissions.

A Watcher allow or an approved escalation overrides Copilot deny rules, such as --deny-tool. Claude Code differs: it still applies its own deny rules after a Watcher allow. Put the restrictions you rely on in Watcher's command rules, such as a deny rule.

An explicit human answer is recorded separately from execution. A later refusal or cancellation preserves that answer. The Analyzer shows refusal text under a Blocked label; execution failures may show as errors.

Local rules still apply during backend failures and when Watcher cannot read, verify or link the session's own log. Calls needing grading then use the configured failure policy. Copilot's own permissions apply, and Watcher cannot grade or record the call, without usable credentials or a working hook, or when Watcher cannot tell which session the call belongs to, such as a new session with no log. This includes downgrading to a client without the integration. watcher doctor counts, by reason, the calls from the last 24 hours that Watcher could not place in a session or judged without their log.

Only a new human prompt resets the denial budget. Resumes, repeated reads and automated messages do not.

Recording limits​

Directory exclusions cover every directory in the session's history. Child sessions keep their own directory history. Ambiguous identical calls can be graded without a decision linked to a recorded call.

Watcher uploads Copilot's own session log, and the server turns it into the stored conversation. The main conversation and each subagent are stored as separate sessions. The conversation is uploaded after tool calls, at the end of each turn and when the session ends, and later uploads append what is new. While Copilot runs, an upload stops before a call that has no result yet. If the Copilot process is killed during a call, that call may be stored with an unknown outcome, or only once the session is resumed.

When an upload fails, Watcher retries it in the background, as it does for Claude Code and Codex, also after Copilot exits. Keep the native log so Watcher can recover missing history after a restart. watcher doctor warns about a session whose final recording is not yet confirmed stored. watcher doctor decisions checks decisions separately.

Tool results and errors are stored whole, as for Claude Code and Codex. Image bytes are replaced by their name, type, size and hash. A log line Watcher cannot read, such as one over 16 MiB, is stored as a notice in its place, and later turns are stored as usual. Native message times are kept, and sessions carry the machine's hostname.