chore: merge upstream master and retain tracked scrolling fixes

Resolve Copilot forwarding and registry/documentation overlaps against upstream e63bb65b. Reuse upstream always policy for measured version-independent forwarders and test slow clicks for Claude, Codex and Copilot.
This commit is contained in:
Saqeb Akhter committed 2026-10-18 14:07:36 +04:00
commit dbb41c70cf
228 files changed
+15240 -862

No files matched your search

+87 -9
View File
@@ -1,9 +1,9 @@
# Agent CLIs
Codeman drives ten run modes: nine agent CLIs plus a plain shell. This page covers picking
Codeman drives eleven run modes: ten agent CLIs plus a plain shell. This page covers picking
one, setting it up, and the differences that actually change how you work.
## The ten modes
## The eleven modes
| Mode | CLI | Get it |
| -------------------- | ---------------------------- | ---------------------------------------------------------------------- |
@@ -16,6 +16,7 @@ one, setting it up, and the differences that actually change how you work.
| **Grok Build** | `grok` | [github.com/xai-org/grok-build](https://github.com/xai-org/grok-build) |
| **DeepSeek Harness** | `dsh` | [github.com/deepseek-ai/deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) |
| **OMP** | `omp` | [github.com/can1357/oh-my-pi](https://github.com/can1357/oh-my-pi) |
| **GitHub Copilot** | `copilot` | [github.com/github/copilot-cli](https://github.com/github/copilot-cli) |
| **Terminal / Shell** | your `$SHELL` | Already installed. |
Any combination works, including all of them. The run mode is chosen per session from the
@@ -50,10 +51,10 @@ If a CLI is installed but a Run button for it never appears:
precisely to avoid this; a hand-written plist or unit will not.
3. Restart the server after installing a new CLI.
`pi`, `grok`, `omp` and `dsh` are additionally identity-probed rather than trusted by name:
`pi`, `grok`, `omp`, `copilot` and `dsh` are additionally identity-probed rather than trusted by name:
`pi` and `omp` are generic enough that something else on your PATH may answer to them,
`grok` has npm squatters, and Debian ships an unrelated `dsh` (dancer's shell). Each has a
status endpoint (`/api/grok/status`, `/api/deepseek/status`, `/api/omp/status`) that reports
status endpoint (`/api/grok/status`, `/api/deepseek/status`, `/api/omp/status`, `/api/copilot/status`) that reports
the path and version that actually resolved, so a misresolution is visible rather than
presenting as "the mode just does not work".
@@ -69,15 +70,15 @@ output. The other CLIs expose no equivalent.
| Respawn cycling and unattended runs | Yes | Yes |
| Cron jobs | Yes | Yes |
| Docker cases, remote SSH cases | Yes | Yes |
| Precise idle detection | Yes | Codex, Pi, OpenCode, OMP and Gemini: same screen check, via their own prompt and working line. DeepSeek: reports its state itself. Others: output stabilization, coarser |
| Precise idle detection | Yes | Codex, Pi, OpenCode, OMP, Copilot, Gemini and Antigravity: same screen check, via their own prompt and working line. DeepSeek: reports its end of turn itself. Grok: generic cues only, unreliable |
| Auto-resume when a usage limit resets | Yes | No |
| Plan usage chip | Yes | No |
| Approvals Inbox | Yes | DeepSeek yes; others no |
| Approvals Inbox | Yes | DeepSeek and Codex as alerts (answer in the terminal); others no |
| Read My Mind | Yes | No |
| Ralph loop and its task tracker | Yes | No |
| Subagent and team windows | Yes | No |
| Model, effort, advisor, and ultracode controls | Yes | No |
| `stop` and `blocked` wait signals | Yes | DeepSeek yes; elsewhere 400 if you ask for them explicitly |
| `stop` and `blocked` wait signals | Yes | DeepSeek yes; Codex `blocked` only; elsewhere 400 if you ask for them explicitly |
| The bundled agent skill | Yes | No |
Everything that makes a session a session works everywhere. What is Claude-only is mostly
@@ -153,6 +154,17 @@ Two behaviours that are deliberate and worth knowing:
does; before 1.26.1 every Codex session reported idle for its whole life. Codex
conversations also appear in Past Sessions and can be resumed, and on phones the keyboard
bar grows `⇧←` / `⇧→` for Codex's queued-message editing and prompt stack.
- **A dialog waiting for you turns the tab red.** Codex is launched with its approvals on
unless you tick the bypass option, and it has no hooks to say it stopped, so Codeman reads
its dialogs off the screen: a command, edit or network approval, a question it asks you
(Plan mode), and the "Trust this folder?" prompt when it starts in a new folder. Each one
raises the same red "needs you" alert a Claude permission prompt does, with the desktop
notification, web push, webhook, the phone overview's NEEDS YOU row and an Approvals Inbox
card, and the alert clears a few seconds after you answer. Answer in the terminal: Codeman
never answers a Codex dialog for you, so the inbox card and the push carry no Approve or
Deny buttons. While such a dialog is up the session shows as idle (a question used to show
as working), and agents can wait on it with the `blocked` signal. "Implement this plan?"
at the end of a plan is not counted, since the turn has ended there.
### Gemini
@@ -173,6 +185,17 @@ Google's successor to the consumer Gemini CLI, invoked as `agy`. It keeps all of
in `~/.gemini/antigravity-cli/`, so the credential handling that applies to Gemini applies
to it as well.
- **Work detection reads its spinner row.** While a turn runs, `agy` animates an 8-dot braille
frame and a label one row above the composer (`⣯ Generating...`; `Working...` and
`Loading...` too), and its footer reads `esc to cancel`. Codeman matches that row, which is
what puts the activity indicator on the tab. The frames are not the braille set Claude and
Gemini use, which is why the tab used to look idle through a whole turn.
- **At rest the footer hint is the idle mark.** The composer's `>` is no good for that, since
the submitted prompt is echoed as `> <text>` as well. `? for shortcuts` is drawn only at
rest, and the turn's last repaint carries it. A shell call that waits for approval replaces
the composer and the footer hint is not drawn there, so the tab keeps reading as working
until you answer.
### Pi
Pi needs the opposite instincts from every other CLI here.
@@ -251,6 +274,59 @@ an OMP session that had started a turn showed as working for good.
Guide: [`docs/omp-integration.md`](https://github.com/Ark0N/Codeman/blob/master/docs/omp-integration.md).
### GitHub Copilot CLI
GitHub's `copilot`, installed with `npm install -g @github/copilot` (CLI management can run
that for you). Codeman recognises it only when `--version` answers `GitHub Copilot CLI`, and
`GET /api/copilot/status` reports the path and version that resolved.
**Signing in.** Codeman does not log it in: run `copilot` once and use `/login`, or sign in
inside a Codeman tab. Copilot keeps the token in the OS keychain when there is one; a headless
server has none, so it offers to save it as **plain text in `~/.copilot/config.json`**, which is
what a service ends up with. To keep a token out of a file, give the service
`COPILOT_GITHUB_TOKEN` (Copilot reads it first, then `GH_TOKEN`, `GITHUB_TOKEN`). The token is
never copied into a [Docker case](Docker-Cases): sign in inside the container.
**Run button and permissions.** Run starts `copilot --yolo` (allow every tool, path and URL),
the same bypass switch the other agent CLIs get, so an unattended session never stops on an
approval. A multi-user user without the bypass grant gets a plain `copilot`, which is
Copilot's own Manual Approval mode. Model, permission mode and the rest are also changeable
inside its TUI.
**Options and resume.** `--model` is sent only by an API caller that sets `copilotConfig.model`; the Run menu has no Copilot model picker (a saved custom endpoint sets `COPILOT_MODEL` instead). A session from
Past Sessions continues with `--continue`, which resumes the most recent Copilot conversation
in that directory. A tab name you set yourself is passed as `--name`, so Copilot's own session
list reads like that tab (an automatic `w1-myapp` name is not pinned); Copilot refuses `--name`
together with `--resume`/`--continue`, so a continued session keeps the name it had.
**Your own endpoint.** With [custom model endpoints](Custom-Model-Endpoints) on, a saved
endpoint appears in the Run menu for Copilot. It is launched with Copilot's BYOK variables
(`COPILOT_PROVIDER_BASE_URL` with the `/v1` an OpenAI route needs, `COPILOT_PROVIDER_API_KEY`,
`COPILOT_MODEL`), needs no GitHub sign-in, and applies at launch with no restart.
**Working and idle.** A turn shows `◉ Working` in the footer, which is what Codeman reads;
a tool waiting for your approval replaces the composer and reads as idle. The model name is
read from the footer too. Copilot has no hooks, so the `stop` and `blocked` wait signals are
not available: wait on `idle`, `exit` or an output marker.
**Selecting and scrolling.** Copilot turns mouse tracking on itself. Codeman strips that, so a
plain drag selects text (and Auto Copy works) and clicks still reach Copilot. The wheel, and a
swipe on a phone, scroll Copilot's own transcript; Shift+wheel scrolls Codeman's local history.
**MCP servers.** [MCP server sync](Settings-Reference) includes Copilot's
`~/.copilot/mcp-config.json` (relocated by `COPILOT_HOME`), as a target and a source.
**From another agent.** The `codeman agent` verbs work from inside a Copilot tab and against
Copilot workers: `spawn` waits for the composer (not the folder-trust dialog), `send --wait`
resolves on `idle`, and `read` returns the last answer from the pane's visible screen. Tool-call
rows are not modelled and read as part of the answer, and `--until stop` is refused as for
every hook-less mode.
**Not available.** Auto-resume on a usage limit, the Approvals Inbox, Read My Mind and the
Ralph tracker, as for the other non-Claude CLIs.
Guide: [`docs/copilot-integration.md`](https://github.com/Ark0N/Codeman/blob/master/docs/copilot-integration.md).
### Terminal / Shell
A plain shell in a tmux session. No agent, no hooks, no idle detection.
@@ -277,6 +353,7 @@ respawns. Which variables are accepted depends on the mode:
| Grok | `GROK_*`, `XAI_*` |
| DeepSeek | `DSH_*`, `DEEPSEEK_*` |
| OMP | `OMP_*` |
| Copilot | `COPILOT_*` (a token goes in `COPILOT_GITHUB_TOKEN`; `GH_TOKEN` and `GITHUB_TOKEN` are not accepted as per-session overrides) |
Anything outside the allowlist is rejected at the schema. This is intentional: the allowlist
is one global list, so widening it for one CLI widens it for all of them. In multi-user mode
@@ -292,9 +369,10 @@ into the case's `.claude/settings.local.json` so that `/model` keeps working.
- **Claude Code** if you want every Codeman feature. Unattended overnight runs, usage-limit
auto-resume, the Approvals Inbox, and subagent visualization all assume it.
- **Codex, OpenCode, Gemini, Antigravity, Grok, OMP** when you prefer that agent or that
- **Codex, OpenCode, Gemini, Antigravity, Grok, OMP, GitHub Copilot** when you prefer that agent or that
model. You get the session layer, respawn, cron, Docker, and remote SSH; you do not get the
hook-driven features.
hook-driven features (Codex dialogs still raise the red alert and an alert-only inbox card,
see [Codex](#codex) above).
- **DeepSeek Harness** if you want DeepSeek's models with real status signals. It is the one
non-Claude mode that reports idle, working and blocked to Codeman itself.
- **Pi** if you want a fast, unsandboxed agent and you understand what project trust does.
+1 -1
View File
@@ -120,7 +120,7 @@ Conventions for wiki pages:
- Images are referenced from the main repository over raw URLs rather than being copied into
the wiki.
- Say what the default is, especially when it is off. Most of Codeman is opt-in.
- Label Claude-only behaviour every time it appears. Nine of the ten run modes are not
- Label Claude-only behaviour every time it appears. Ten of the eleven run modes are not
Claude.
## Conduct
+10 -7
View File
@@ -46,7 +46,8 @@ case. Each has a stable id, and that id is what the API, the wait primitives, an
event use.
Several sessions can share one case. That is the normal way to parallelize: three workers
in the same repo, three tabs, one case.
in the same repo, three tabs, one case. They then also share one folder; when the workers
edit and commit in parallel, give each its own checkout with [Git Worktrees](Git-Worktrees).
A session carries state the case does not:
@@ -58,7 +59,7 @@ A session carries state the case does not:
## Run mode
The **run mode** is which CLI the session runs: `claude`, `opencode`, `codex`, `gemini`,
`antigravity`, `pi`, `grok`, `deepseek`, `omp`, or `shell`. It is chosen at start and does not change afterwards; to
`antigravity`, `pi`, `grok`, `deepseek`, `omp`, `copilot`, or `shell`. It is chosen at start and does not change afterwards; to
switch, start another session.
Claude is the reference mode. Nine of the ten are not Claude, and a number of Codeman
@@ -77,7 +78,7 @@ Where a case runs is **separate from** which CLI it runs. There are three locati
| **Remote SSH** | A durable tmux server on the remote host, fronted by a local pane running `ssh`. See [Remote SSH Sessions](Remote-SSH-Sessions). |
This matters because it is a common source of confusion: Docker is **not** an eleventh run
mode. All ten run modes work in all three locations. A case is docker-backed or
mode. All eleven run modes work in all three locations. A case is docker-backed or
ssh-backed; a session is claude or codex or shell.
**Web tabs** are the other thing that is not a session. A saved dashboard URL renders as a
@@ -163,9 +164,11 @@ report events back: a permission prompt appeared, the turn finished, the agent w
task completed. Those events drive tab alerts, the Approvals Inbox, notifications, and the
wait primitives.
This is why some features are Claude-only. The one partial exception is DeepSeek Harness,
This is why some features are Claude-only. One partial exception is DeepSeek Harness,
whose terminal front door reports idle, working and blocked to Codeman over the harness's
own supervisor contract, so it gets the hook-driven signals without a hook file. The other
own supervisor contract, so it gets the hook-driven signals without a hook file. Codex gets
one of them from its screen: Codeman reads its approval, question and trust dialogs off the
pane and raises the same red "needs you" alert a `permission_prompt` hook raises. The other
CLIs have no equivalent, so for them Codeman falls back to watching terminal output, which
is coarser: it can see that something happened, not what it was.
@@ -177,7 +180,7 @@ See [Hooks And Integrations](Hooks-And-Integrations).
| --------------- | ---------------------------------------------------------------------------- |
| **Case** | Named working directory. |
| **Session** | One CLI in one tmux session. |
| **Run mode** | Which CLI: claude, opencode, codex, gemini, antigravity, pi, grok, deepseek, omp, shell. |
| **Run mode** | Which CLI: claude, opencode, codex, gemini, antigravity, pi, grok, deepseek, omp, copilot, shell. |
| **Respawn** | Restarting the CLI on idle to keep an unattended run going. |
| **Ralph loop** | An autonomous single-session task loop. |
| **Orchestrator**| A phased plan driven across multiple agents. |
@@ -188,6 +191,6 @@ See [Hooks And Integrations](Hooks-And-Integrations).
## Read next
- [The Dashboard](The-Dashboard) - what the UI is showing you.
- [Agent CLIs](Agent-CLIs) - the ten run modes in detail.
- [Agent CLIs](Agent-CLIs) - the eleven run modes in detail.
- [Keeping Agents Running](Keeping-Agents-Running) - respawn, idle detection, usage limits.
- [`docs/architecture-invariants.md`](https://github.com/Ark0N/Codeman/blob/master/docs/architecture-invariants.md) - the mechanisms behind all of this, for contributors.
+3 -2
View File
@@ -58,11 +58,11 @@ another device starts from its own history). The default model keeps its own **D
in both cases, and nothing is ever auto-chosen: the promoted row is simply the one under your
thumb.
**For opencode, Codex, Gemini, Pi, Grok, DeepSeek and OMP, picking an entry launches
**For opencode, Codex, Gemini, Pi, Grok, DeepSeek, OMP and GitHub Copilot, picking an entry launches
straight onto the endpoint** — no restart, because the endpoint is applied before the
session's process ever starts. **Claude still restarts the harness's process in place** —
same tab, same conversation (`--resume`) — after a normal native launch, since that restart
is far less jarring for Claude than for the other seven, whose own TUI can fully
is far less jarring for Claude than for the others, whose own TUI can fully
reinitialize on a restart. Either way, every supported harness reads its endpoint config at
process start, never per turn, so there is no live hot-swap while a turn is running.
@@ -154,6 +154,7 @@ entry. "Launch anyway" is still there if you want to try regardless.
| Harness | Status |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **GitHub Copilot CLI** | Verified at the CLI level (1.0.95) against a local OpenAI-compatible endpoint: it posts to `/v1/chat/completions` with your key and model name and needs no GitHub sign-in. Tool calls through a custom endpoint were not exercised. |
| **Claude Code, opencode, Pi, Grok, OMP** | Verified end-to-end against a real local server. |
| **Codex** | Config is correct, and plain chat can work against a server that speaks the Responses API — but a real tool-call attempt comes back as inert text instead of running, so it's still not usable for real coding work. |
| **Gemini** | Fails with an auth error gemini-cli raises once redirected. Unresolved; don't rely on it yet. |
+7 -1
View File
@@ -4,7 +4,7 @@ Run a case inside its own container instead of directly on your host: for isolat
reproducible toolchain, and for the ability to pick the whole environment up and move it to
another machine.
A docker case is a **location overlay**, not a run mode. All ten run modes work inside a
A docker case is a **location overlay**, not a run mode. All eleven run modes work inside a
container. See [Core Concepts](Core-Concepts).
## One-time setup: the base image
@@ -118,6 +118,12 @@ invisible from the host (`pi -c` and `grok -c` inside a docker case see only tha
container's history). OMP's `sessions/` is the exception and is shared read-write, because
Codeman reads it host-side for history and resume.
GitHub Copilot CLI is not seeded: on a host without a keyring its sign-in token sits in plain
text in `~/.copilot/config.json`, and there is no Docker credential row for it. Sign in inside
the container (`copilot login`). A `COPILOT_GITHUB_TOKEN` cannot be handed in instead: a docker
case refuses per-session environment overrides, and Copilot forwards no server variable into
the container.
**Git hosts.** The agent image can also include the GitHub CLI (`gh`) and the Azure CLI (`az`,
with the `azure-devops` extension), off by default, and its git then uses them as credential
helpers for github.com and Azure DevOps. When the matching switch is on, their sign-ins are
+10 -7
View File
@@ -141,17 +141,20 @@ Read these before writing any code. Each one has cost somebody an afternoon.
5. **Wait instead of polling, and a timeout is not an error.** The wait endpoints answer
`200` with `wait.timedOut: true`. Loop over short waits rather than one long call, because
tunnels cut idle connections.
6. **Only `claude` and `deepseek` sessions emit `stop` and `blocked`.** Claude's come from
Claude Code hooks, DeepSeek's from the harness reporting its state to Codeman. Shell and
the other external CLIs accept only `idle`, `working`, and `exit`; asking for `stop`
explicitly there is a `400`, while omitting `until` is always safe. On a shell session
6. **Only `claude` and `deepseek` sessions emit `stop`; `blocked` also fires for `codex`.**
Claude's come from Claude Code hooks, DeepSeek's from the harness reporting its state to
Codeman, and Codex's `blocked` from Codeman reading its approval, question and trust
dialogs off the screen (a wait that asks for `blocked` while such a dialog is already up
answers at once). Shell and the other external CLIs accept only `idle`, `working`, and
`exit`; asking for `stop` explicitly there (codex included) is a `400`, while omitting
`until` is always safe. On a shell session
`idle` fires **once at startup and never again**, so synchronize hook-less sessions with an
output marker instead.
7. **Nothing reports "ready", so wait for it explicitly.** A new session answers
`{"signal":"exit","immediate":true}` until its PID exists, and that means *not started*,
not *crashed*. A Claude worker in a fresh case then sits on the CLI's trust dialog; prompt
it there and the wait resolves on idle in about two seconds looking exactly like a finished
turn, while your text sits stuck in the dialog.
not *crashed*. A Claude worker in a fresh case then sits on the CLI's trust dialog, whose
highlighted option is `No, exit`: prompt it there and your Enter quits the CLI. Codeman
holds `idle` while the dialog is on screen, but that is not a readiness signal either.
### Recipes
+2 -2
View File
@@ -23,8 +23,8 @@ stores, or refreshes your credentials.
### Which agent CLIs does it support?
Claude Code, OpenCode, Codex, Gemini, Antigravity, Pi, Grok Build, DeepSeek Harness and
OMP, plus a plain shell, chosen per session. Claude is the reference mode and a few features
Claude Code, OpenCode, Codex, Gemini, Antigravity, Pi, Grok Build, DeepSeek Harness,
OMP and GitHub Copilot CLI, plus a plain shell, chosen per session. Claude is the reference mode and a few features
are Claude-only; [Agent CLIs](Agent-CLIs) has the table.
### Does Codeman send my code or prompts anywhere?
+73
View File
@@ -0,0 +1,73 @@
# Git Worktrees
Sessions in one case share its folder. That is fine for one agent, but three agents in the
same checkout edit the same files, overwrite each other's builds, and commit each other's
half-finished work. A **git worktree** gives each of them a checkout of its own: same
repository, same history, a separate folder on a separate branch.
Codeman creates worktrees for a case whose folder is a git repository, starts sessions in
them, and removes them again when the work is done.
## Where they live
`<case>/.claude/worktrees/<name>`, on a new branch `worktree-<name>`. That is exactly where
Claude Code's own `claude --worktree <name>` puts them, so a worktree made in Codeman is one
Claude Code recognizes, and the other way round. Codeman's Recent Sessions and Session Manager
lists mark a session that runs in one with a `⑂ <name>` pill.
The main checkout does not show the worktrees as untracked: Codeman adds `/.claude/worktrees/`
(and `/.claude/settings.local.json`, the hooks file it writes for every Claude session, plus the
`codeman` folder it writes when **Codeman Agent Skill** is on) to the repository's local
`.git/info/exclude` when git does not ignore them already. Without that, those files would make
every worktree look modified and git would refuse to remove it. Your tracked `.gitignore` is
never touched.
## Creating one and starting a session in it
1. Pick the case in the toolbar's case picker.
2. Open the picker again and choose **Git worktrees…** (on a phone: the case sheet's
**Worktrees** button).
3. Under **New worktree**, type a name (letters, digits, `.`, `_`, `-`, up to 64 characters).
4. Pick the CLI under **Start sessions with** (Claude Code, Codex, a shell, any installed run
mode).
5. **Create & start session**.
The worktree is created from the case's current commit, and the session opens in it as a tab
named `w1-<name>`. Under **Branch and start point** you can name the branch yourself or start
from another branch, tag or commit. An existing branch is never reused or reset: pick another
name.
**Open** on a worktree's row starts another session in it, with the CLI chosen above.
## Removing one
Two ways, and both use `git worktree remove` **without** `--force`:
- **Remove…** on the worktree's row in the dialog.
- Closing a session that runs in a worktree: the Close Session dialog offers **Kill & remove
worktree**, which kills the session and then removes its worktree.
git refuses to remove a worktree that still holds uncommitted or untracked files, and Codeman
shows that refusal as git worded it and leaves everything in place. Commit, stash or delete the
work first, then remove again. A worktree a live session still runs in is refused too.
**Also delete its branch** deletes the branch with `git branch -d`, which keeps a branch whose
commits are not merged yet. The worktree is still removed, and the message says the branch was
kept.
If a worktree's folder was deleted by hand, its row says **missing** and offers only
**Remove…**: that clears the record git keeps of it, so the name can be used for a new worktree.
## What is not supported
- **Docker cases and remote (SSH) cases.** A container can write to its workspace, and creating
a worktree runs the repository's hooks and checkout filters on the Codeman machine, so git is
never run there. A remote case's repository is on another machine. For the same reason a
worktree that a Docker case uses as its workspace (or that holds one) is never removed from
here: remove the Docker case first.
- A case folder that is not the top of a repository (a subfolder of one), a bare repository, or
an empty repository with no commit yet.
- Worktrees outside `.claude/worktrees/` (made by hand with `git worktree add`) are listed, but
Codeman neither starts sessions in them from the dialog nor removes them.
The HTTP endpoints are in the [HTTP API](HTTP-API) reference (`/api/cases/:name/worktrees`).
+5 -4
View File
@@ -72,7 +72,7 @@ Roughly 235 handlers across 26 route modules. By domain:
| ------------------- | -------- | --------------------------------------------------- |
| System | 56 | Status, settings, digest, updates, tunnel. |
| Sessions | 34 | Create, input, terminal, wait, last response, kill. |
| Cases | 34 | Create, link, clone, remote and docker cases. |
| Cases | 37 | Create, link, clone, worktrees, remote and docker cases. |
| Files | 17 | Preview, edit, raw, attachments, path picker. |
| Orchestrator | 10 | Plans and phases. |
| Ralph | 9 | Loop control and configuration. |
@@ -142,9 +142,10 @@ Three semantics that break callers who assume otherwise:
`wait-output` matches a **literal substring, never a regex.** That is deliberate: no regex
means no catastrophic backtracking on attacker-influenced output.
Only `claude` and `deepseek` sessions emit `stop` and `blocked`: Claude's come from Claude
Code hooks, DeepSeek's from the harness reporting its state to Codeman. Shell and the other
external CLI sessions accept `idle`, `working`, and `exit`.
Only `claude` and `deepseek` sessions emit `stop`: Claude's come from Claude Code hooks,
DeepSeek's from the harness reporting its state to Codeman. `blocked` fires for those two
and for `codex`, whose approval, question and trust dialogs Codeman reads off the screen.
Shell and the other external CLI sessions accept `idle`, `working`, and `exit`.
## SSE
+4 -3
View File
@@ -6,7 +6,7 @@
Codeman runs your coding agents on your own machine and puts them behind one dashboard you
can open from any device. It spawns Claude Code, OpenCode, Codex, Antigravity, Gemini, Pi,
Grok, DeepSeek Harness, or OMP inside persistent tmux sessions, streams the real terminal to the browser, and keeps
Grok, DeepSeek Harness, OMP, or GitHub Copilot CLI inside persistent tmux sessions, streams the real terminal to the browser, and keeps
working while you are away from the keyboard: it re-prompts idle agents, resumes when a
subscription limit resets, runs jobs on a schedule, and shows every background subagent
live.
@@ -33,7 +33,7 @@ codeman web # then open http://localhost:3000
**Already running it**
- [Agent CLIs](Agent-CLIs) - the ten run modes, their setup, and which features are Claude-only.
- [Agent CLIs](Agent-CLIs) - the eleven run modes, their setup, and which features are Claude-only.
- [Mobile Guide](Mobile-Guide) - phone and tablet use, QR login, the touch keyboard bar.
- [Remote Access](Remote-Access) - Tailscale, Cloudflare tunnel, LAN plus password, QR login.
- [Keeping Agents Running](Keeping-Agents-Running) - idle detection, respawn cycling, auto-resume on usage limits.
@@ -67,6 +67,7 @@ codeman web # then open http://localhost:3000
| [Agent CLIs](Agent-CLIs) | Which agent should this session run, and how do I set it up? |
| [Custom Model Endpoints](Custom-Model-Endpoints) | How do I point a session at my own OpenAI-compatible endpoint? |
| [Working With Files](Working-With-Files) | How do I read, edit, and attach files? |
| [Git Worktrees](Git-Worktrees) | How do several agents work on one repository without sharing a folder? |
| [Input And Voice](Input-And-Voice) | How do I talk to an agent, including by voice? |
| [Mobile Guide](Mobile-Guide) | How well does this work on a phone? |
| [Keyboard Shortcuts](Keyboard-Shortcuts) | What can I drive from the keyboard? |
@@ -126,7 +127,7 @@ codeman web # then open http://localhost:3000
| OS | macOS or Linux. Windows works through WSL2. |
| Node.js | 22 or newer. |
| tmux | Required. Sessions live in tmux, which is what makes them survive restarts. |
| An agent CLI | At least one of Claude Code, OpenCode, Codex, Gemini, Antigravity, Pi, Grok Build, DeepSeek Harness, OMP. Plain shell sessions need none. |
| An agent CLI | At least one of Claude Code, OpenCode, Codex, Gemini, Antigravity, Pi, Grok Build, DeepSeek Harness, OMP, GitHub Copilot CLI. Plain shell sessions need none. |
| Network | Binds to `127.0.0.1` by default. Reaching it from another device is a deliberate step: see [Remote Access](Remote-Access). |
Codeman is MIT licensed, self-hosted, and sends no telemetry. Everything runs on your
+6 -3
View File
@@ -19,11 +19,14 @@ terminal into something that can notify you.
| `teammate_idle` | An agent-team member goes idle. | Team surfaces. |
| `task_completed` | A task finishes. | Task tracking, run summary. |
This is why several Codeman features are Claude-only. The one partial exception is DeepSeek
This is why several Codeman features are Claude-only. One partial exception is DeepSeek
Harness, whose terminal front door reports idle, working and blocked to Codeman over the
harness's own supervisor contract, so it gets the hook-driven surfaces without any hook
file. The other CLIs have no equivalent, so for them Codeman watches terminal output, which
reveals that something happened but not what it was.
file. Codex gets one of them from its screen: Codeman reads its approval, question and
trust dialogs off the pane and raises the same red "needs you" alert a `permission_prompt`
hook raises (see [Agent CLIs](Agent-CLIs#codex)). The other CLIs have no equivalent, so for
them Codeman watches terminal output, which reveals that something happened but not what it
was.
### How hooks get installed
+12 -8
View File
@@ -27,12 +27,14 @@ keystroke echo. Idle now lands a few seconds after a turn genuinely ends.
There are several layers stacked on that: a completion message from the CLI, an AI check,
output silence, and token stability.
**For the other CLIs** it depends on what the CLI tells Codeman. Codex declares its own
prompt glyph and working line, so it gets the same screen check Claude does (before 1.26.1
every Codex session reported idle for its whole life). DeepSeek Harness reports idle,
working and blocked to Codeman itself, which is as precise as hooks. Everything else is
output stabilization: the session is idle when output stops changing. Coarser, and it is
why the features further down this page are Claude-only.
**For the other CLIs** it depends on what the CLI tells Codeman. Codex, OpenCode, Gemini
CLI, Pi, OMP and Antigravity each declare their own prompt marker and working line, so they
get the same screen check Claude does (before 1.26.1 every Codex session reported idle for
its whole life). DeepSeek Harness reports its end of turn and its dialogs to Codeman itself,
which is as precise as hooks; its working and idle display still comes from its output.
Grok Build declares neither. Codeman calls a new grok pane idle 3 seconds after launch, and
after that it has only generic cues to go on (Claude's `❯` prompt marker, a braille spinner
glyph), which grok may not draw, so its working and idle status is unreliable.
## The Respawn Controller
@@ -161,8 +163,10 @@ run summary and lifecycle log carry the detail.
- **The update prompt is what makes a reset survivable.** After `/clear`, everything the
agent knows comes from that summary and the project files. A vague update prompt produces
a vague next cycle.
- **Non-Claude sessions can respawn**, but with output-based idle detection and no
usage-limit auto-resume.
- **Non-Claude sessions can respawn**, but with no usage-limit auto-resume, and with
output-based idle detection except on DeepSeek Harness, whose own end-of-turn report
reaches the respawn controller the way Claude's `stop` hook does while its status bridge
is on (a local session, by default).
- **Do not run respawn on a session you are actively typing in.** It will send prompts
underneath you.
+12 -2
View File
@@ -67,6 +67,13 @@ default. See [Tile Grid](Tile-Grid).
**App Settings → Shortcuts.** Bindings live in a registry with per-user overrides, so a
rebind is stored as an override on top of the default rather than replacing the table.
Previous Session (`Alt+[`) and Next Session (alternate, `Alt+]`) are rows like any other,
so they can be rebound too.
A chord another action already uses is refused, and the message names that action. The same
check runs when you re-enable a disabled shortcut and when you press Reset: if its chord was
given to something else in the meantime, it stays as it was. `Alt+1` to `Alt+9`,
`Shift+Enter`/`Ctrl+Enter` and `Ctrl+V`/`Cmd+V` are reserved.
Two things are deliberately not rebindable:
@@ -79,8 +86,11 @@ Two things are deliberately not rebindable:
The terminal sees keystrokes before the app does. Any chord the app claims has to also be
swallowed at the terminal layer, or xterm writes the control byte into the session as well
as triggering the action. If you rebind something to a chord the terminal cares about
(`Ctrl+D`, say), expect the CLI to see it too.
as triggering the action. A chord **you** rebind an action to is kept out of the terminal
too, so rebinding Previous Session to `Alt+J` switches the session and sends nothing to the
CLI. The built-in defaults are deliberately not held back this way: `Ctrl+L` clears the
screen and also reaches the CLI, which redraws on it. Binding an action back onto its own
default behaves like the default.
`Alt+1` through `Alt+9` are matched on **physical key position** rather than the character
produced, so macOS Option layouts that produce `¡™£` still switch tabs.
+19 -13
View File
@@ -43,8 +43,9 @@ as the keyboard appearing.
Tapping the "C" logo gives a session overview rather than a welcome page:
1. **NEEDS YOU** first: sessions blocked on a question, with answer strips so you can
resolve them without opening the session.
1. **NEEDS YOU** first: sessions blocked on a question, with answer strips (Approvals Inbox
on) so you can resolve a Claude dialog without opening the session. A Codex or DeepSeek
Harness row offers **Answer in terminal** instead, which opens the session.
2. **CURRENT SESSIONS** with live status.
3. **PAST SESSIONS**, resumable.
@@ -66,7 +67,8 @@ autocorrect: Enter adds a new line, and only Send delivers the text, as one past
by Enter, so your line breaks reach the agent intact. Anything already typed on the terminal
prompt moves into the editor when it opens. Drafts are kept per session and in memory only,
so switching tabs keeps them and a page reload forgets them; a dot on the key shows a draft
is parked. The editor's Image button attaches photos or videos and puts their paths into the draft.
is parked. The editor's Attach button attaches photos, videos or documents and puts their paths
into the draft.
Destructive commands need a double press, so you cannot fire `/clear` with a stray thumb. On
Codex sessions the bar also shows `⇧←` and `⇧→`, the Shift-modified arrows Codex binds to
editing the last queued message and walking the prompt stack.
@@ -103,12 +105,16 @@ into the Run dropdown.
## The Attach button
The toolbar's **Attach** button (the picture icon beside the mic) is the keyboard-down way to
hand the agent a photo or a video. One tap opens the camera and photo library sheet, nothing
else: no editor, no keyboard. The chosen files upload and their paths land on the prompt, so
you then tap the terminal, write the rest of your message and press Enter. Videos (mp4, webm,
mov, m4v, ogv) upload as recorded, up to 1 GB each by default
(`CODEMAN_MAX_PASTE_VIDEO_BYTES` on the server changes it), so a long 4K clip takes a moment
on the way up.
hand the agent a photo, a video or a document. One tap opens the system's sheet (camera,
photo library, or a file from Files or a cloud drive), nothing else: no editor, no keyboard.
The chosen files upload and their paths land on the prompt, so you then tap the terminal,
write the rest of your message and press Enter. Videos (mp4, webm, mov, m4v, ogv)
upload as recorded, up to 1 GB each by default (`CODEMAN_MAX_PASTE_VIDEO_BYTES` on the
server changes it), so a long 4K clip takes a moment on the way up. Documents are PDFs,
Office files (docx, pptx, xlsx), zips and plain-text formats such as txt, md, csv and json;
a document keeps the plain-letters part of its name in the saved file, so the agent and you
can tell the uploads apart. See [Working With Files](Working-With-Files) for where they land and how long they
stay.
If the keyboard was up when you tapped Attach, iOS closes it to show the photo sheet and does
not bring it back, so the tap on the terminal is how you get it again. That is the system's
@@ -120,7 +126,7 @@ anything you had already typed, so you can write in front of a path, fix a word,
**Use terminal keyboard** hands a single-line message back the other way, onto the prompt,
so neither surface holds a half of your message. A multi-line message cannot make that trip
(the prompt is a single line), so it stays parked as a draft and the dot on the Compose key
shows it is waiting. The Compose editor's own Image button remains for the times you are
shows it is waiting. The Compose editor's own Attach button remains for the times you are
already writing in the editor.
## Tapping, links and copying
@@ -162,9 +168,9 @@ phone, and it is the main reason the feature exists.
## Notifications
Push notifications reach you with no tab open, and with the Approvals Inbox on they carry
**Approve** and **Deny** buttons handled by the service worker, so you can unblock an agent
from the lock screen.
Push notifications reach you with no tab open, and with the Approvals Inbox on, those for a
Claude permission prompt carry **Approve** and **Deny** buttons handled by the service
worker, so you can unblock a Claude agent from the lock screen.
Setup in [Notifications And Approvals](Notifications-And-Approvals).
+30
View File
@@ -60,6 +60,36 @@ Admins see everything.
Ownership threads through every list endpoint, the session lookup helper, the WebSocket
layer, and file previews. A user cannot address another user's session even by id.
## Server-wide settings are admin only
There is one set of server settings (`~/.codeman/settings.json`) for everyone: the feature
switches, the run mode, respawn presets, the case order, the Cloudflare tunnel, the default
models. Every user can **read** them, but only an **admin** can change them. For a regular
user the settings write routes answer `403 FORBIDDEN` (see the
[HTTP API](HTTP-API) and [`docs/api-reference.md`](https://github.com/Ark0N/Codeman/blob/master/docs/api-reference.md)).
A regular user reads them without what is the admin's: the Deepgram key an admin saved for
voice dictation, and the admin's case names (case order, last used case).
In the browser this means:
- **App Settings → Save** still keeps a regular user's per-device settings (skin, fonts,
header buttons, keyboard bar and the rest of the per-device keys) on that device. If they
also changed a server-wide setting, one notice says it can only be changed by an admin,
and the setting keeps the server's value.
- A regular user's run-mode pick and respawn presets are their own: kept in that browser
under their name, not sent to the server, and still theirs on the next visit (over what
an admin set). Their last used case is not recorded server-wide.
- Reordering cases and switching the tunnel on or off are admin actions.
- If the page could not tell yet who is signed in (a slow or failed sign-in check), the
server's refusal is read the same way: the same notice, and nothing more is sent.
The operations that act on the whole server are admin actions too: updating Codeman,
opening the multi-display window, regenerating the tunnel QR code (it clears every user's
pending QR login) and cleaning up stale session state. **Revoke All** signs a regular user
out of their own logins only, and the tunnel panel lists only their own.
Per-user server settings are not part of this version.
## Safer defaults for regular users
Non-admins get tighter defaults, and lifting them is an explicit per-user grant:
+28 -16
View File
@@ -13,7 +13,7 @@ opening the session.
| Desktop notification | Another window on the same machine | Opt-in |
| Push notification | Anywhere, even with no tab open | Opt-in |
| Webhook (ntfy, Slack, Discord) | Anywhere, with no browser or subscription at all | Opt-in |
| Approvals Inbox | One queue across every session | Opt-in |
| Approvals Inbox | One queue for Claude, Codex and DeepSeek prompts | Opt-in |
| Phone overview | Phone home screen, NEEDS YOU section | On |
| Away Digest | Afterwards, as a summary | Opt-in |
@@ -34,8 +34,13 @@ reloading the dashboard while a permission dialog is blocking a session does not
with a normal-looking tab.
For Claude sessions, these come from Claude Code's hooks and are precise about *why* the
session stopped; DeepSeek Harness sessions report the same states themselves. For the other
CLIs there are no hooks, so you get the coarser output-based signal.
session stopped; DeepSeek Harness sessions report the same states themselves. Codex has no
hooks, but its dialogs are distinctive enough to read off the screen, so a Codex session
waiting on an approval, a question or the "Trust this folder?" prompt turns red too, and
clears a few seconds after you answer. For the other CLIs there are no hooks and no dialog
reading, so you get only the coarser working and idle state: read off the screen for
OpenCode, Gemini CLI, Pi, OMP and Antigravity, and unreliable for Grok Build, which
declares nothing Codeman can read it from.
## Window title and OS notifications
@@ -109,11 +114,13 @@ Behaviour worth knowing:
## The Approvals Inbox
**Opt-in, off by default. Claude sessions, plus DeepSeek Harness sessions, whose terminal
front door reports its prompts to Codeman.**
front door reports its prompts to Codeman, and Codex sessions, whose dialogs Codeman reads
off the screen.** DeepSeek and Codex cards are alerts: they say "Answer in the terminal" and
carry no answer buttons, because Codeman cannot verify a keystroke into those dialogs.
One queue of every prompt currently waiting on a human, across all your sessions, answerable
in place. When you have eight workers running, this is the difference between checking eight
tabs and checking one list.
One queue of the prompts currently waiting on a human, across all your sessions, with the
Claude ones answerable in place. When you have eight workers running, this is the difference
between checking eight tabs and checking one list.
Turn it on in **App Settings**. Surfaces:
@@ -134,17 +141,20 @@ Behaviour worth knowing:
sending, and refuses with a conflict if the dialog is no longer there. Otherwise your
keystroke would land in the composer as stray text.
- **Permission and question items clear only on definitive signals**: the turn ending, the
dialog completing, an answer, a supersede, the session exiting, or a 12 hour timeout. They
do not clear on a heuristic "looks busy again" signal, because that signal is wrong often
enough to lose a real prompt.
dialog completing, an answer, a supersede, the session exiting, or a 12 hour timeout. A
Codex item also clears a few seconds after its dialog leaves the screen, and a DeepSeek
Harness item when the harness reports it is working again. They do not clear on a
heuristic "looks busy again" signal, because that signal is wrong often enough to lose a
real prompt.
- **In memory only.** Restarting the server clears the queue; the prompts themselves are
still sitting in the sessions.
### Approve and Deny from the notification
With the inbox enabled, push notifications carry **Approve** and **Deny** buttons. Those are
handled by the service worker directly, so they work with no tab open: tap Approve on a
locked phone and the agent continues.
With the inbox enabled, push notifications for a Claude permission prompt carry **Approve**
and **Deny** buttons. Those are handled by the service worker directly, so they work with no
tab open: tap Approve on a locked phone and the agent continues. A Codex or DeepSeek Harness
notification carries no Approve or Deny, since those dialogs are answered in the terminal.
With the inbox off, the buttons are stripped from the notification payload entirely rather
than being shown and failing.
@@ -184,8 +194,9 @@ current sessions, then past ones. Rows use the same language as the tab strip: a
when fine, pulsing while working, yellow when waiting for input, red when a question is
pending.
Answer strips let you resolve a prompt straight from the home screen without opening the
session.
With the Approvals Inbox on, answer strips let you resolve a Claude permission or question
dialog straight from the home screen without opening the session. A Codex or DeepSeek
Harness strip offers **Answer in terminal** instead, which opens the session.
## The Away Digest
@@ -214,7 +225,8 @@ from the lock screen.
- **iOS needs the home screen install.** A Safari tab will never receive push.
- **The bell is invisible at zero.** That is deliberate, not a broken setting.
- **Approvals need real signals.** They are built on hook events, which Claude emits and
DeepSeek Harness reports itself; the other CLIs do neither.
DeepSeek Harness reports itself, and on Codex's dialogs as its screen shows them; the
other CLIs give neither.
- **A stale menu answer is refused, not sent.** If you answer a card for a dialog that has
since gone away, Codeman declines rather than typing a digit into the composer.
+1 -1
View File
@@ -4,7 +4,7 @@ Point a case at another machine and the agent runs **there**, with the same dash
mobile UI, and autonomy features. Your laptop becomes a window onto a session living on the
remote host.
Like Docker, this is a **location overlay** on a case, not a run mode. All ten run modes
Like Docker, this is a **location overlay** on a case, not a run mode. All eleven run modes
work remotely. See [Core Concepts](Core-Concepts).
## Why bother
+6 -1
View File
@@ -29,6 +29,10 @@ The practical rule: **appearance and input are per device, behaviour is shared.*
did not follow you, it is in one of the first two rows, and you change it again on that
device.
In [Multi-User Mode](Multi-User-Mode) the server's settings are shared by every user, so
only an **admin** can change them. A regular user's **Save** keeps their per-device settings
as usual and tells them that server-wide settings can only be changed by an admin.
## App Settings
### Updates
@@ -146,6 +150,7 @@ instead of its native cloud backend. See [Custom Model Endpoints](Custom-Model-E
| Allowed Tools | The list used by the explicit mode. |
| Ralph / Todo Tracker | Enables the Ralph loop surfaces. |
| Agent Teams | Experimental teams. Also needs the CLI's own environment flag. |
| Pin tab names on the CLI | Launches every Claude session with `--name` set to its tab name, so Claude Code's prompt label and `/resume` list match your tabs. Claude then stops generating its own titles for those sessions, and a rename in Codeman holds only until the next turn. Synced, off by default; applies from the next session start or respawn. |
| Codeman Agent Skill | Under **All agent CLIs**. Injects the agent skill into each new session's case, where that session's CLI looks for skills (every CLI except Pi and a plain shell). Off by default. See [The Codeman Skill](Codeman-Skill). |
| Remote auto-reconnect | Reattaches dropped remote SSH sessions. On by default. |
| Nice priority / value | Runs agent processes at a lower CPU priority. |
@@ -217,7 +222,7 @@ Some things are configured before the server starts, not in the UI:
| `CODEMAN_ALLOW_UNAUTHENTICATED_NETWORK` | Acknowledges exposing the server with no password. |
| `CODEMAN_BASE_URL` | Mounts Codeman under a sub-path behind a reverse proxy that forwards the prefix unchanged. See [Remote Access](Remote-Access). |
| `CODEMAN_MAX_DOWNLOAD_BYTES` | Cap on raw file bodies and downloads. 2 GB by default, `0` for none. |
| `CODEMAN_MAX_PASTE_IMAGE_BYTES` | Cap on one pasted, dropped or attached image. 50 MB by default. |
| `CODEMAN_MAX_PASTE_IMAGE_BYTES` | Cap on one pasted, dropped or attached image or document. 50 MB by default. |
| `CODEMAN_MAX_PASTE_VIDEO_BYTES` | Cap on one attached video (phone Attach, drop). 1 GB by default; videos stream to disk, so this bounds disk use, not memory. |
| `CODEMAN_MAX_REMOTE_FILE_SSH` | Concurrent ssh reads for files in remote cases. 4 by default. |
| `CODEMAN_PATH_PROBE_TIMEOUT_MS` | How long a linked case's folder may take to answer before it is shown as unreachable. 1500 ms by default; raise it for a slow but healthy mount. |
+9
View File
@@ -202,6 +202,15 @@ Both wait about 2.5 seconds before appearing, so a deploy that restarts the serv
flash a warning at you every time. If the browser reports itself offline, the grace period
is skipped.
**The transport readout.** With a session open, the header shows how its terminal is
connected: `WS` (WebSocket, the normal case), `WS…` (connecting or reconnecting) or `HTTP`
(the WebSocket is unavailable and input goes over HTTP). If typed or pasted input is backing
up faster than it is acknowledged, the readout grows a suffix such as `WS · 1.2KB queued`.
That suffix appears only after the backlog has stayed up for about a second, so a paste or a
fast burst that clears at once does not make the pill widen and shrink. (It is part of the
text line, so you see it in the Compact and As before header styles; Tiles hides that line and
shows `WS live`, and phones hide it too.)
There is also a watchdog for the case where the connection stops delivering without
erroring. If the server's heartbeat stops arriving, Codeman reconnects on its own rather
than sitting on a green dot showing frozen data.
+8 -3
View File
@@ -116,9 +116,14 @@ seconds in. Current versions confirm against the actual screen before believing
### A session is stuck showing busy
For non-Claude CLIs, idle detection is output-based and coarser by necessity: those CLIs
expose no hooks. A session that has genuinely gone quiet will settle. If it never does,
interrupt it (`Ctrl+C` with nothing selected).
For Grok Build the busy and idle status is unreliable: it exposes no hooks and declares no
working line, so after launch Codeman has only generic cues to go on (Claude's `❯` prompt
marker, a braille spinner glyph), which it may not draw. Codex, OpenCode, Gemini CLI, Pi,
OMP and Antigravity get the same screen check Claude does, so a session of theirs that has
genuinely gone quiet will settle. An Antigravity session waiting on a shell-command approval
("Run this command?") shows busy until you answer it: `agy` draws nothing Codeman reads as
"at rest" while that list is up. If a session never settles, interrupt it (`Ctrl+C` with
nothing selected).
### The agent asks about bypass permissions every time
+32 -8
View File
@@ -168,17 +168,41 @@ blocks sensitive trees. In multi-user mode a non-admin gets only their own user
root, because per-user spaces live inside the home directory and a home-directory root would
expose everyone.
## Images into a session
## Files into a session
Paste from the clipboard or drag and drop straight onto the terminal. The image is written
Paste from the clipboard or drag and drop straight onto the terminal. The file is written
where the agent can read it and the reference is inserted into your prompt. On a phone, the
toolbar's Attach button opens the camera or photo library, videos included, and puts the path
on your prompt, where it behaves like text you typed; the Image button inside the Compose
editor does the same into the editor. Dropping a video onto the terminal works the same way.
toolbar's Attach button opens the camera, photo library or files, and puts the path on your
prompt, where it behaves like text you typed; the Attach button inside the Compose editor
does the same into the editor. Dropping a video or a document onto the terminal works the
same way.
HEIC images from an iPhone are converted to JPEG on the way in.
Videos (mp4, webm, mov, m4v, ogv) are stored as recorded, up to 1 GB each by default
(`CODEMAN_MAX_PASTE_VIDEO_BYTES`); they stream to disk rather than through server memory.
Images (png, jpg, gif, webp, bmp, heic) are re-encoded on the device before they go up (a GIF
goes as is, so it keeps its frames), and HEIC from an iPhone is converted to JPEG. Videos (mp4, webm, mov, m4v, ogv) are stored as recorded,
up to 1 GB each by default (`CODEMAN_MAX_PASTE_VIDEO_BYTES`); they stream to disk rather than
through server memory. Documents are the office formats (pdf, docx, pptx, xlsx, zip) and the
text family (txt, md, csv, tsv, json, log, yaml, yml, xml). Each is checked on the way in,
against its file signature for the binary formats and against its encoding for text (UTF-8,
no NUL bytes), so a script renamed to `.pdf` is refused while a `.txt` can hold any text at
all. A text file in another encoding is refused with a message saying it is not UTF-8 (or that
it is UTF-16, which Excel's "Unicode Text" and Notepad's "Unicode" produce); save it as UTF-8
(in Excel, "CSV UTF-8") and attach it again. Files with script or page extensions (sh, py,
js, html) are not accepted, since a prompt upload is something for the agent to read, not
something for Codeman to store and serve. A document keeps a trimmed copy of its original
name, letters, digits, dot, dash and underscore with anything else turned into a dash, so
`Q3 report.pdf` is findable as `paste-<time>-<id>-Q3-report.pdf`; a name made entirely of
other characters saves without one. Uploads are refused for remote (SSH) sessions, whose
working directory is on the other host.
Uploads land in `.codeman-uploads/` inside the case, next to the code the agent is working
on, because that is the one path a local agent and a Docker case (whose workspace is mounted
at the same absolute path) both see the same way. The first upload writes a `.gitignore` of `*` into `.codeman-uploads/`, so the
directory ignores itself and your repository never picks the files up, while your own ignore file is
left alone; a `.gitignore` you already had there is never overwritten. Files older than seven
days are swept hourly, and the directory goes when the last session of the case is closed (a
session that is only detached keeps it). Earlier releases wrote to `.claude-images/`; that
directory is still swept and cleaned up the same way for one release so a case in use before
the move is not left with stray files.
## Generated artifacts
+1
View File
@@ -15,6 +15,7 @@
- [Agent CLIs](Agent-CLIs)
- [Custom Model Endpoints](Custom-Model-Endpoints)
- [Working With Files](Working-With-Files)
- [Git Worktrees](Git-Worktrees)
- [Input And Voice](Input-And-Voice)
- [Mobile Guide](Mobile-Guide)
- [Keyboard Shortcuts](Keyboard-Shortcuts)