The Copilot quota chip row moves to its own PR (branch feat/copilot-plan-usage on the fork). This removes its docs, changeset line and CLAUDE.md note.
9.8 KiB
GitHub Copilot CLI sessions
Codeman can drive GitHub Copilot CLI (copilot,
npm @github/copilot) as a session backend, alongside Claude Code, OpenCode, Codex, Gemini,
Antigravity, Pi, Grok, DeepSeek Harness and OMP. copilot is a run mode: its own PTY, its
own tmux session, its own tab identity (purple, a drawn mark rather than GitHub's logo). It is
not a location overlay like Docker or remote-SSH cases, and it is not a web tab.
Everything here was measured against Copilot CLI 1.0.94 and 1.0.95 inside tmux. The entry
itself is registry data (src/config/cli-registry/stock.ts); see
cli-registry.md for the field-by-field reference.
Install
npm install -g @github/copilot
CLI management (Settings → Agents & CLIs) can run exactly that for you. Codeman resolves the
binary from the server's PATH and the usual npm/nvm prefixes, then runs copilot --version
and accepts it only if the output says GitHub Copilot CLI <x.y.z>. A bare copilot on PATH
that answers anything else is ignored. Check what it resolved:
curl -s localhost:3000/api/copilot/status | jq
# { "available": true, "path": "/home/you/.local/bin", "version": "1.0.95" }
Authenticate
Codeman never logs Copilot in or stores its credentials.
- Interactive. Run
copilotonce and use/login(orcopilot login), or do it inside a Codeman tab. The token goes to the OS keychain when one is available. - Headless server. There is no keychain on a service, so Copilot offers to keep the token
as plain text in
~/.copilot/config.json(authTokens). That is where it ends up when you accept. To keep a token out of a file, setCOPILOT_GITHUB_TOKENin the service environment; Copilot reads it first, thenGH_TOKEN, thenGITHUB_TOKEN. - Per-session override.
COPILOT_*is the only prefix the env allowlist admits for Copilot.GH_TOKENandGITHUB_TOKENare deliberately not accepted as per-session overrides: the allowlist is one global list with no mode context, so admitting them would make them settable on every session. UseCOPILOT_GITHUB_TOKEN. - No GitHub sign-in is needed when a session points at your own endpoint (below).
What Codeman wires up
| Thing | Behaviour |
|---|---|
| Launch | copilot, in Copilot's own Manual Approval mode. |
| Run button | copilot --yolo (allow every tool, path and URL), like the other CLIs' bypass switches, so an unattended session never stops on an approval. |
| Permission clamp | allowAll is a privilegedParam. A multi-user owner without the bypass grant has it forced back to false; an absent config is never materialized (a bare copilot is already safe). COPILOT_HOME, COPILOT_ALLOW_ALL, COPILOT_PROVIDER_* and COPILOT_MODEL are privileged env keys. |
| Model | --model <id> from the Run menu / Session Options. |
| Resume | --resume <value>, sent only by an API caller that sets copilotConfig.resumeSessionId (Past Sessions does not). The value (an id, an id prefix or a session name) must be one plain word starting with a letter or digit: --resume's value is optional, so --resume --yolo would otherwise make --yolo its own flag and bypass the clamp. |
| Continue | --continue, from Past Sessions: it resumes the most recent conversation Copilot has for that directory. Nothing sets it on a respawn. Skipped when a resume value is set. |
| Name | A tab name you set yourself is passed as --name <tab name>, so Copilot's own session list reads like that tab. An automatic name (w1-myapp, or an auto-named title) is not pinned. Copilot refuses --name with --resume/--continue, so it is dropped there and a continued session keeps the name it had. |
| Working / idle | The footer. A turn shows ◉ Working esc edit prompt (the dot alternates ◉/◎); the composer is the ❯ between two rules. A tool waiting for approval replaces the composer and reads as idle. |
| Model detection | The right-hand field of the footer's last row, at rest and mid-turn. |
| Status probe | GET /api/copilot/status, plus an entry in the CLI-installed probes and codeman doctor. |
| MCP | The entry declares mcpConfig (~/.copilot/mcp-config.json, dialect copilot-json, relocated by COPILOT_HOME), so MCP server sync treats it as a target and a source. copilot mcp disable is honoured (read from settings.json, never written). |
| Docker | The agent image installs @github/copilot. No credential directory is seeded (see below). |
Your own endpoint (BYOK)
With custom model endpoints on, a saved endpoint is offered in the Run menu for Copilot and launches straight onto it (no restart; the env is applied before the process starts):
| Codeman field | Variable |
|---|---|
base URL (+ /v1) |
COPILOT_PROVIDER_BASE_URL |
| key | COPILOT_PROVIDER_API_KEY |
| model | COPILOT_MODEL |
COPILOT_PROVIDER_TYPE is not set: it defaults to openai, which is what a Codeman custom
endpoint is (llama.cpp, vLLM, Ollama). All of these are privileged env keys.
Checked at the CLI level against a local OpenAI-compatible endpoint (1.0.95): it posted to
/v1/chat/completions with the key and the model name, needed no GitHub sign-in, and
--resume <id> --model <m> / --continue --model <m> resumed earlier sessions. Tool calls
through a custom endpoint were not exercised. Only keys are persisted (never values).
Terminal behavior
Copilot is an alternate-screen TUI with mouse tracking on, so it needed one non-default decision, the same one OpenCode needed:
- Selection. Left in, xterm reports a plain drag to the TUI instead of selecting, so
Auto Copy and copy-on-select silently did nothing (only Shift+drag selected). The entry is
altScreen: 'strip-mux-and-mouse': the tracking DECSETs are stripped under tmux, a drag is a local selection, and clicks still reach Copilot through the browser's hand-encoded tap (cliMouseTrackingis published as the server strips). - Wheel and touch. Stripping the DECSETs also stops xterm encoding the wheel, so
_shouldForwardWheelToAppforwards it by hand as SGR reports while Copilot is tracking the mouse; a phone swipe goes through the same gate. Shift+wheel scrolls Codeman's local history. If the tracking flag is stale after a server restart, the gesture falls back to PageUp/PageDown rather than going dead (Copilot pages its own transcript on those keys: three PageUp moved a 140-line answer from lines 109-140 to 010-042). - Keys. Keystrokes from
tmux send-keysandPOST /api/sessions/:id/inputreach the composer; Shift+Enter inserts a newline; shell tool calls complete inside tmux (github/copilot-cli#4180 and #4223 report both failing on 1.0.70 to 1.0.74; neither reproduces on 1.0.94). - Scrollbar. Copilot draws a
┃gutter at the right edge of every row; the response reader strips it.
codeman agent verbs
The three CODEMAN_* variables are exported into every pane, so the
session-to-session verbs
work from inside a Copilot tab and against Copilot workers:
spawnwaits for the composer. The ready mark is the footer hint/ commands · ? help, not❯: the folder-trust dialog draws❯ 1. Yes, so the glyph would call a worker ready while it is still asking whether to trust the folder. An untrusted folder therefore makesspawnwarn that the composer was not seen instead of claiming ready.send --waitresolves onidle.--until stopis refused (400, "no Claude Code hooks") like every hook-less mode; useidle,exitor a--matchmarker.readreturns the last answer. Copilot's output stream is absolute cursor moves rather than lines, so the route reads the pane's visible screen (tmuxcapture-pane) and cuts it with a per-CLI pane dialect (src/web/response-viewer-transcript.ts):❯ <prompt> HH:MM,● <answer>with indented continuation, and the cwd /Session: N AIC usedrow, composer, footer and scrollbar as chrome. Everything before the first prompt (banner, trust dialog) is dropped, so a session that has not been asked anything answers nothing.interruptsends a bare ESC;rmrefuses itself.
Docker cases
The agent image installs @github/copilot, and a docker case runs Copilot like any mode. No
credential directory is seeded: without a keyring the sign-in token is plain text in
config.json, and CRED_STORES (src/docker-hosts.ts) deliberately has no .copilot row.
Sign in inside the container (copilot login), or set COPILOT_GITHUB_TOKEN for the session.
Remote SSH cases
The launch line is built by the same registry path as a local session (the same flags, the same
privileged-param clamp). A remote host needs its own copilot on its own PATH and its own
sign-in. This path has unit coverage for the built command but was not exercised against a
real remote host.
What Codeman deliberately does NOT wire up
- No login or token storage. See Authenticate.
- No bypass inferred.
--yolois sent only by the Run button'sallowAll, never guessed from anything else, and is clamped for non-granted owners. - No
--api-key-style flag on the command line. Secrets travel as environment variables throughtmux setenv. - No Claude-only features. Auto-resume on a usage limit, the Approvals Inbox, Read My Mind, the Ralph tracker, subagent windows and the bundled agent skill are Claude-shaped.
Known gaps
agent readdoes not model tool-call rows: they open with the same●bullet and read as part of the answer.agent readsees the visible screen, so an answer longer than one screen is its tail.- Custom endpoints: tool calls through a BYOK endpoint were not exercised.
- Remote SSH was not exercised against a real remote host.