merge master (1.49.0 and later) into the MacBook test branch

One conflict, in install.sh's help text: both sides extended the same line of
environment variables. Kept both additions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-11-06 18:00:25 +01:00
commit fec052f402
181 files changed
+14849 -872

No files matched your search

+17 -1
View File
@@ -140,8 +140,24 @@ Explicit `codexConfig.model` / `codexConfig.reasoningEffort` values take precede
Custom model endpoints, Docker containers and remote host command overrides keep their own settings.
Changing a default affects new sessions and does not edit Codex configuration files.
Two behaviours that are deliberate and worth knowing:
**Allow network access** reaches the same local launches. It opens the network only where
Codex runs the folder in its workspace-write sandbox and does not change Codex's sandbox
mode: a folder Codex runs read-only keeps the network closed, and Codex asks per command.
With it on, commands in the sandbox can call Codeman's API, which can start a session
outside the sandbox with no approval prompt, even when a password is set. See
[The Codeman Skill](Codeman-Skill#when-the-agent-is-codex) and
[Security](Security#what-codeman-does-not-protect-against).
Behaviours that are deliberate and worth knowing:
- **Each local session runs its own app server.** Codex 0.162 and later otherwise hands
every client's commands to one shared background server, which runs them with the
environment of whichever session started it, and a server left by another Codex version
stops every launch on a dialog. So Codeman starts a local Codex 0.162 or later with
`--no-daemon`. The trade-off, going by Codex's own help text: `codex agents` browses the
sessions on that shared server and `codex remote-control` manages it, so do not expect
either to see a session started this way. Remote and Docker launches do not get the
flag, and neither does a local launch whose Codex version Codeman could not read.
- **Predictive echo instead of buffered echo.** Codex's composer reacts to every keystroke,
a `/` opens a live-filtering picker, arrows edit server-side state. Buffering keystrokes
until Enter starved it, so Codex paints each keystroke at the predicted cell while the
+20 -4
View File
@@ -140,12 +140,28 @@ message a worker directly instead of typing into its terminal.
Two things to know:
- Codex's default sandbox blocks network access, even to this machine, so the skill needs
**Bypass approvals and sandbox** (App Settings, Codex).
- Codex's default sandbox blocks network access, even to this machine, so a Codex session
needs **Allow network access** (App Settings, Codex) before it can start and drive
others. The setting is app-wide: it applies to every local Codex session started after
you switch it on, not only the ones you mean to orchestrate. It also has a cost: commands
in Codex's sandbox can then call Codeman's API, which can start a session outside the
sandbox with no approval prompt, even when a password is set, so the sandbox no longer
contains a prompt-injected command. See
[Security](Security#what-codeman-does-not-protect-against). It opens the network only
where Codex runs the folder in its workspace-write sandbox, which is what Codex does for
a project you trusted. It does not change Codex's sandbox mode: a folder Codex runs
read-only (a new case that is not a git repository, for one) keeps the network closed,
and Codex asks you to approve each call to Codeman. Trust the project in Codex, or use `/permissions` in
Codex for that session, to get workspace-write there. **Bypass approvals and sandbox**
works everywhere, but removes the sandbox and the approval prompts.
- Codex 0.162 runs its commands in a shared background process, whose Codeman variables can
belong to the session that started it.
belong to the session that started it. Codeman starts a local Codex 0.162 or later with
`--no-daemon`, so each session runs its own. A remote or Docker session does not get the
flag, and neither does a local one whose Codex version Codeman could not read; there,
and with an older Codex, the skill notices and says so instead of acting.
The skill checks for both and says so instead of acting.
OpenCode and DeepSeek Harness need nothing extra: in their default setup neither keeps its
shell commands off the network, so the skill works there as soon as it is injected.
## What is in the skill
+1 -1
View File
@@ -25,7 +25,7 @@ Three ways to get one, all under **New or link a case…** at the bottom of the
| How | Result |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Create New** | A fresh `~/codeman-cases/<name>` with a scaffolded `CLAUDE.md`, or with **Create in a custom folder**, a new folder inside a parent you choose, scaffolded the same way and registered in place like a linked case. |
| **Clone Repo** | A repo cloned into `~/codeman-cases/<name>` (or straight into a folder you choose, which must be empty or not exist yet) and registered as a case. Private repos need this machine's own git credentials (see below). |
| **Clone Repo** | A repo cloned into `~/codeman-cases/<name>` (or, with **Clone into a custom folder**, into `<parent folder you choose>/<name>`, which must be empty or not exist yet) and registered as a case. Private repos need this machine's own git credentials (see below). |
| **Link Existing** | An existing folder anywhere on disk, registered in place. Nothing is copied or moved. |
Linked cases keep living where they are. Deleting a case in Codeman removes the
+4
View File
@@ -213,6 +213,10 @@ missing entry is the more current answer.
- **No button to un-point a session from the UI yet.** Clearing back to native cloud is an
HTTP call (`POST .../custom-model {"clear": true}`) or deleting the session; the settings
panel manages saved endpoints, not what a running session is currently pointed at.
A clear, or a switch to another endpoint, gives the session back what it had set itself under
a key the endpoint replaced, such as its own `DSH_HOME` or `CLAUDE_CONFIG_DIR`. If Codeman
restarted in between, only the home directory comes back, and an own `DSH_HOME`, `CODEX_HOME`
or `GROK_HOME` only when the endpoint was picked before that restart.
- **Nothing is shared with your real cloud credentials.** The endpoint's own key, if any,
never touches your Anthropic/OpenAI/Google login — a custom endpoint is a separate,
explicit choice per session.
+6 -1
View File
@@ -98,6 +98,10 @@ Adoption is **admin-only in multi-user mode**. Linking creates Codeman's own con
with one bind mount that has already been checked; an adopted container's mounts belong to
whoever started it, and one that mounts `/` hands the adopter the host.
That is about a container. A tmux session someone started by hand inside a container is opened
from the home screen instead, and it needs a Docker case pointing at that container: see
[Opened outside Codeman](The-Dashboard#opened-outside-codeman).
## Credentials
Your existing host logins work inside the container without logging in again. Credentials
@@ -225,7 +229,8 @@ this does not widen your network exposure. Add it to the service unit and restar
- Per-session environment overrides, effort, and per-CLI configuration are **rejected** for
docker cases, because they do not cross into the container. Configure the container through
the docker host's per-mode command override instead.
the docker host's per-mode command override instead. A `$` in that override expands inside
the container, not on the Codeman machine.
- tmux must exist in the base image. It is a hard prerequisite and is probed when linking a
host.
- On macOS, Docker Desktop takes a dedicated uid path, and memory caps are subject to the
+2 -1
View File
@@ -179,12 +179,13 @@ the defaults discovers and attaches your live sessions.
| Install route | Update with |
| ------------- | --------------------------------------------------------------------------- |
| Installer | Re-run the install one-liner, or **App Settings → System → Updates**. |
| Installer, without git | Re-run the install one-liner. The in-app updater says so instead of offering an update. |
| npm | `npm update -g aicodeman` |
| git clone | `git pull && npm install && npm run build`, then restart the service. |
The in-app updater covers git-clone installs supervised by systemd or launchd. It stashes a
dirty tree rather than discarding it, and streams progress across the restart. npm installs
report as non-updatable.
and installs without git report as non-updatable.
### Will updating kill my running sessions?
+20
View File
@@ -39,6 +39,26 @@ name.
**Open** on a worktree's row starts another session in it, with the CLI chosen above.
## When an agent moves into a worktree
Claude Code can move a running session into a worktree part way through (its EnterWorktree tool),
and the session's tab stays on the case. While the session's pane is in a worktree inside the
session's folder, the **Files** panel lists that worktree, so you see the files the agent is
editing. A strip under the panel's title names the worktree, and its **Session folder** button
switches to the session's own folder (**Back to worktree** returns). The panel follows the agent
in and back out on its own while it is open.
Only the Files panel moves. The **Git** panel stays on the session's folder, so it can show
`main` while the strip names the worktree. And `.claude` is a hidden folder of the session's
folder, so an `.html` file in `.claude/worktrees/<name>` opens as source rather than as a
rendered page. A session started in the worktree does not have that limit.
A worktree outside the session's folder (`git worktree add ../feature`) is not followed: Codeman
only serves files inside the session's folder. The same goes for a session started in a subfolder
of the repository, because Claude Code puts the worktree at the top of the repository, which is
outside that session's folder. Open such a worktree as a case of its own with Add Case > Link
Existing.
## Removing one
Two ways, and both use `git worktree remove` **without** `--force`:
+26 -7
View File
@@ -127,11 +127,20 @@ installer says so in its summary (`Admin not used (...)`) and gets those anothe
This route is taken by itself when `sudo` is not installed, when the account is outside the
`sudo`, `wheel` and `admin` groups and `sudo` will not run without a password, when the
`sudo` password is refused, and on a Mac for an account that is not an administrator.
`sudo` password is refused, and on a Mac for an account that is not an administrator and
has no Homebrew it can write to.
`--no-admin` (or `CODEMAN_NO_ADMIN=1`) forces it on an account that does have the rights;
`CODEMAN_NO_ADMIN=0` switches the detection off. Nothing on this route runs `sudo`,
Homebrew or the Xcode tools installer.
The group check cannot see a sudoers entry, so an account that sudoers lists by name, with
a password, takes this route too. The summary then reads `could not confirm that this
account may use sudo`, and to use `sudo` anyway:
```bash
curl -fsSL https://getcodeman.com/install | CODEMAN_NO_ADMIN=0 bash
```
What to know about it:
- **Linux needs make, a C++ compiler and python3 to be there already.** node-pty compiles
@@ -197,16 +206,24 @@ See [Contributing](Contributing) for the rest of the development loop.
## Route D: Docker Compose
Codeman itself can run in a container and spawn Docker cases as sibling containers through
the host's Docker socket. Copy `docker/.env.example` to `docker/.env`, set
`CODEMAN_PASSWORD`, then:
the host's Docker socket. You need Docker with the Compose v2 plugin (2.27.2 or newer), and
an account that can use Docker without sudo (on Linux, the `docker` group). Then, on Linux:
```bash
git clone https://github.com/Ark0N/Codeman.git && cd Codeman
bash docker/Start-Codeman.sh
```
The first run asks for a data folder, a port and a password. Enter takes each default,
including a generated password, shown on your terminal and kept in `docker/.env`. It then
writes that file, builds the image (a few minutes the first time) and ends on the URL once
Codeman answers. The image
already includes Claude Code, Codex, Gemini CLI and OpenCode: start a session and log the CLI
in once, and the login is kept in the data folder.
Run the script again after updating rather than a plain `docker compose up`, so the rebuilt
image, the refreshed volumes and the entrypoint arrive together. The full guide, including
storage and networking options, is
Unraid, storage and networking options, is
[`docker/README.md`](https://github.com/Ark0N/Codeman/blob/master/docker/README.md).
## Installing an agent CLI
@@ -274,7 +291,7 @@ Full detail, including logs and the self-updater, is in
| Installer, without git | Re-run the one-liner. The in-app updater says so instead of offering an update. |
| npm | `npm update -g aicodeman` |
| git clone | `git pull && npm install && npm run build`, then restart. |
| Docker Compose | Re-run `Start-Codeman.sh`. The in-app updater works too, and refuses a release that changes the container definition until you re-run the script. |
| Docker Compose | `git pull`, then re-run `Start-Codeman.sh`. The in-app updater works too, and refuses a release that changes the container definition until you re-run the script. |
The in-app updater covers git-clone installs supervised by systemd or launchd. It restarts
the process that is running it, so the actual work happens in a detached script and the
@@ -289,8 +306,10 @@ npm uninstall -g aicodeman # npm route
The installer route asks before it removes `~/.codeman/runtime` (the Node.js and tmux it
downloaded, if any), and keeps it by default when you installed CLIs there with
`npm install -g`. Neither removes `~/.codeman/` or `~/codeman-cases/`. Delete those by hand if you want the
state and your case folders gone as well, and check `~/codeman-cases/` first: linked cases
`npm install -g`. That folder is inside `~/.codeman/`, so saying yes to the data directory
question that follows removes it even if you kept it a step earlier, and the question says
so. By default neither route removes `~/.codeman/` or `~/codeman-cases/`. Delete those by hand
if you want the state and your case folders gone as well, and check `~/codeman-cases/` first: linked cases
point at directories you already had, but cases created from scratch have their only copy
there.
+4 -2
View File
@@ -66,8 +66,9 @@ A row of keys above the virtual keyboard, and what it contains depends on the se
**Agent sessions** get quick actions: `/init`, `/clear`, `/compact`, a Compose key, `Esc`,
a path picker, and 🧠 when Read My Mind is on. Compose opens a multiline editor with
autocorrect: Enter adds a new line, and only Send delivers the text, as one paste followed
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,
by Enter, so your line breaks reach the agent intact. A prompt written in Persian, Arabic or
Hebrew lays out right to left. 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 Attach button attaches photos, videos or documents and puts their paths
into the draft.
@@ -187,6 +188,7 @@ Setup in [Notifications And Approvals](Notifications-And-Approvals).
The terminal viewport is small. **Last Response** (opt-in header button) renders the agent's
last answer as scrollable text instead, with a **More** button for additional context.
Persian, Arabic and Hebrew answers read right to left there.
The [File Viewer](Working-With-Files) works on phones too, including edit mode, which is
enough to fix a typo an agent introduced while you are away from your desk.
+5 -2
View File
@@ -85,8 +85,10 @@ In the browser this means:
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.
pending QR login) and cleaning up stale session state. So is the **Opened outside Codeman**
block on the home screens, which shows everyone's processes and opens a shell as the server's
account. **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.
@@ -99,6 +101,7 @@ Non-admins get tighter defaults, and lifting them is an explicit per-user grant:
| Claude runs in `auto` permission mode | Anthropic's classifier-guarded mode instead of skip-prompts. |
| Raw shell sessions require a grant | A plain shell is unmediated machine access. |
| Skip-permissions requires a grant | Same reasoning. |
| Codex **Allow network access** requires a grant | It lets a sandboxed command reach any host, Codeman's own API included. |
| Cron `launchCommand` requires a grant | It is an arbitrary command on a schedule. |
| Pi project trust defaults to off | Trust makes Pi execute repo-local TypeScript. |
+17 -4
View File
@@ -29,11 +29,18 @@ through a jump host. Your laptop can sleep, change networks, or close, and the r
Hosts are saved and reusable, so a second case on the same machine is just a path. Host
profiles can also carry per-run-mode launch command overrides, for when the binary lives
somewhere unusual on that host.
somewhere unusual on that host. An override runs on the remote in your login shell, so a `$`
in it expands there, not on the Codeman machine.
The remote host needs **tmux**. Codeman probes for it when you link the host rather than
failing later at launch.
The remote login shell can be bash, zsh, dash, fish, csh or tcsh. A tcsh session reads `.tcshrc`
and not `.login`, so set the PATH that finds `tmux` and your agent CLI in `.tcshrc`. The tmux check
also needs a `command` executable under tcsh: macOS and the BSDs ship one, Debian and Ubuntu do
not, so linking a tcsh host there stops at `could not verify tmux`. nushell and elvish cannot run a
remote session at all.
## What actually runs
The agent lives inside a dedicated tmux server on the **remote** host, and Codeman fronts it
@@ -73,13 +80,19 @@ Attaching to someone else's session and closing your tab must not end their run,
not. Several clients can attach the same remote session at different window sizes without
clamping each other, and discovery shows a shared badge with the client count.
This list holds Codeman's own sessions. A tmux session someone started by hand on the host is
found by the home screen instead: see
[Opened outside Codeman](The-Dashboard#opened-outside-codeman).
## Files
Previews, downloads and text reads in a remote case go over the same ssh connection the
session uses, so a clicked path opens the file on the machine the agent is on, `Range`
seeking included. Nothing is copied to the Codeman host. Editing, Office previews,
thumbnails, the file tree and the tail viewer are not available remotely and answer a clear
400 rather than a misleading 404. Details in [Working With Files](Working-With-Files).
seeking included. Nothing is copied to the Codeman host, apart from the diffs the
[Edit history](Working-With-Files#edit-history) panel keeps, which works for remote Claude
sessions too. Editing, Office previews, thumbnails, the file tree and the tail viewer are not
available remotely and answer a clear 400 rather than a misleading 404. Details in
[Working With Files](Working-With-Files).
## Security
+11 -4
View File
@@ -145,15 +145,16 @@ log stream --predicate 'process == "node"' # macOS, noisy
| Install route | Update with |
| ------------- | ------------------------------------------------------------------------ |
| Installer | Re-run the one-liner, or **App Settings → System → Updates**. |
| Installer, without git | Re-run the one-liner. The in-app updater says so instead of offering an update. |
| npm | `npm update -g aicodeman` |
| git clone | `git pull && npm install && npm run build`, then restart. |
| Docker Compose | Re-run `Start-Codeman.sh`, or the in-app updater, which restarts the container in place. |
| Docker Compose | The in-app updater, which restarts the container in place, or `git pull`, then re-run `Start-Codeman.sh`. |
### The in-app updater
**App Settings → System → Updates**, for git-clone installs supervised by systemd or
launchd. npm installs report as non-updatable, and an unsupervised install is told to
restart manually.
launchd. npm installs and installs without git report as non-updatable, and an unsupervised
install is told to restart manually.
The interesting part is that the update restarts the very process running it. So the real
work runs in a **detached script that outlives the restart** and writes progress to a status
@@ -188,7 +189,13 @@ the bind-mounted directories with the right owner, honours a `docker-compose.ove
and refreshes the build volumes when the checkout moved under them. The in-app updater
applies code only and restarts by letting the container exit, so it refuses a release that
changes the Dockerfile, the compose file, or adds a new `.env` key, until you re-run the
script. Guide:
script.
With no `docker/.env` yet, the script first asks for a data folder, a port and a password and
writes that file. It then waits up to 180 seconds for Codeman to answer and exits 1 if the
container crash-loops or never answers; pass `--no-wait` for scripted use. `Start-Codeman.sh`
and `Update-Codeman.sh` both refuse to run while `CODEMAN_PASSWORD` is still the example
`changeme`. Guide:
[`docker/README.md`](https://github.com/Ark0N/Codeman/blob/master/docker/README.md).
## The tunnel as a service
+7 -1
View File
@@ -68,7 +68,7 @@ be wrong for at least one of them:
| **File Viewer** | Real path resolution before boundary checks, so symlinks cannot escape. Sensitive trees blocked. Edit mode adds an extension allowlist, a size cap, `.git` denial, and optimistic concurrency. It never creates files. |
| **Attachments** | An id-based registry, so browser requests never carry absolute paths. The magic-link scanner is prompt-injectable by nature and is therefore force-confined to the session's workspace. Extension allowlist, not a blocklist. |
| **Path picker** | Its own root allowlist rather than the workspace confinement. In multi-user mode a non-admin gets only their own user space, because per-user spaces live inside the home directory. |
| **Remote cases** | Reads go over the session's own ssh connection and are resolved and contained on the remote host, with a bounded number of ssh children. Nothing is copied to the Codeman host; writes, Office previews and thumbnails are refused. |
| **Remote cases** | Reads go over the session's own ssh connection and are resolved and contained on the remote host, with a bounded number of ssh children. Nothing is copied to the Codeman host, apart from the diffs the Edit history panel reads from a remote Claude session's transcripts while it is open, kept in a private bounded store (0600) that is deleted with the session's record. Writes, Office previews and thumbnails are refused. |
Downloads block sensitive paths outright (`.env`, credentials files, `~/.ssh`, AWS
credentials), and SVG and HTML are served as downloads with `nosniff` so they cannot execute
@@ -99,6 +99,12 @@ Stated plainly, because a security page that only lists strengths is not useful:
bypass requires a secret unconditionally when auth is on.
- **The agent CLIs have their own trust models.** Pi's project trust executes repo-local
TypeScript, for instance. See [Agent CLIs](Agent-CLIs).
- **Allow network access takes Codex's sandbox out of the picture.** The setting (App
Settings, Codex, off by default) lets commands in Codex's sandbox call Codeman's API,
which can start a session outside the sandbox with no approval prompt. A password does
not stop this, because a session inherits the server's password. It applies to every new
local Codex session, so a prompt-injected command in any of them can run anything you
can. Leave it off unless you trust what those sessions run.
## Privacy
+5 -4
View File
@@ -38,8 +38,8 @@ as usual and tells them that server-wide settings can only be changed by an admi
### Updates
Current version, a manual check, and the in-app updater. Covers git-clone installs
supervised by systemd or launchd; npm installs report as non-updatable. See
[Running As A Service](Running-As-A-Service).
supervised by systemd or launchd; npm installs and installs without git report as
non-updatable. See [Running As A Service](Running-As-A-Service).
### Terminal & Input
@@ -49,7 +49,7 @@ supervised by systemd or launchd; npm installs report as non-updatable. See
| Keep Size Under Keyboard | On | For local Claude sessions, the on-screen keyboard no longer resizes the session: the terminal keeps its rows and the view scrolls so the prompt sits just above the keyboard. Resizing made Claude reprint its screen and drop transcript lines from history. Codex, Claude's fullscreen mode, remote and Docker sessions resize as before. See [Mobile Guide](Mobile-Guide). |
| CJK Input | Off | IME composition through a dedicated text field. |
| Extended Keyboard Bar | Per device | Which accessory bar phones get. Shell sessions override it while they are active. |
| Wheel Scrolls Local History | Off | Keeps the wheel on the local buffer instead of forwarding it to the CLI. |
| Wheel Scrolls Local History | Off | Keeps the wheel on the local buffer instead of forwarding it to the CLI. Fullscreen pi leaves that buffer empty and has no paging fallback, so with this on the wheel does nothing there. |
| Auto Copy Selection | Off | Copies highlighted terminal text to the clipboard the moment you finish selecting it. Ctrl+C still copies on demand. |
| Trim The Pane Margin On Copy | On | Takes the left margin a full-screen agent CLI paints down its own edge off a copy, so the text pastes flush. Each CLI declares its own width, and the strip never exceeds the indent every selected line shares, so nesting is kept. Claude Code and Codex declare a margin; a shell does not. |
| Normal / Bold font weight | xterm defaults | Per device, each slot from 100 to 900. The bundled JetBrains Mono renders every step, so a lighter normal weight makes Claude's bold headings stand out. Applies live to the terminal, both echo overlays and open team panes. |
@@ -108,7 +108,7 @@ records an unknown host key in `~/.ssh/known_hosts` without asking: BatchMode st
**Edit history** (per device, off by default, never on phones) adds a header button for the
active session's edit history: every edit the agent and its subagents made, with its diff, and
images it produced. Local Claude sessions only. Nothing is read until you open the window, and it
images it produced. Claude sessions, local and remote (SSH). Nothing is read until you open the window, and it
stores those diffs (secrets included) under `~/.codeman/edit-history/`; see
[Working With Files](Working-With-Files#edit-history).
@@ -208,6 +208,7 @@ instead of its native cloud backend. See [Custom Model Endpoints](Custom-Model-E
| Default Codex model | Model for new local Codex sessions; empty uses Codex's own config. Letters, digits, `.` `_` `-` `/` only. |
| Default Codex reasoning effort | Reasoning level for new local Codex sessions; empty uses Codex's own config. |
| Bypass approvals and sandbox | Starts new Codex sessions with `--dangerously-bypass-approvals-and-sandbox`. Read [Agent CLIs](Agent-CLIs) before enabling. |
| Allow network access | Starts new local Codex sessions (Run menu, Resume and the API; not scheduled jobs) with `sandbox_workspace_write.network_access=true`, so commands in Codex's workspace-write sandbox can use the network. The [Codeman Skill](Codeman-Skill) needs it to reach this server from a Codex session. It applies to every such session, and those commands can then call Codeman's API, which can start a session outside the sandbox with no approval prompt, even when a password is set: see [Security](Security#what-codeman-does-not-protect-against). It applies where Codex runs the folder in workspace-write (a project you trusted in Codex) and does not change Codex's sandbox mode: a folder Codex runs read-only keeps the network closed, and Codex asks for approval per command. Synced, off by default; forced off for users without the privileged-commands grant in multi-user mode. |
| Animated status effects | Cosmetic. |
| MCP server sync | Copies the MCP servers each installed, enabled CLI (Claude, Codex, Gemini, OpenCode, Antigravity) and GitHub Copilot CLI has into the others' own config files. Synced, off by default, admin only in multi-user mode. Turn it on and **Apply** or **Save** (Apply keeps Settings open), then **Preview** shows what would change and **Sync now** applies it. It only adds missing servers, keeps the previous file as `.codeman-bak`, and leaves a file that receives env values or headers readable by you only. A config dir moved by `CODEX_HOME`, `CLAUDE_CONFIG_DIR`, `XDG_CONFIG_HOME`, `GEMINI_CLI_HOME` or `COPILOT_HOME` in Codeman's own environment is followed. |
+33
View File
@@ -287,6 +287,39 @@ Two extras depending on the device:
- **Phones**: tapping the "C" logo gives a session overview instead: NEEDS YOU first, then
current sessions, then past ones. On by default.
### Opened outside Codeman
A tmux session you started by hand (`tmux new -s work`, then `claude`, or just a shell) shows
up on the home screen under **Opened outside Codeman**, on the desktop and in the phone
overview. **Open** wraps it in a tab, and **Go to tab** on a row means it already has one.
| Where it runs | How it is found |
| -------------------- | ---------------------------------------------------------------------------- |
| **This machine** | Automatically, every few seconds while the home screen is up. |
| **A container** | The `⟳` button in the block's header scans the containers behind your Docker cases. |
| **Over SSH** | The same button scans your saved remote hosts. |
The container and SSH scan costs one connection per target, so it runs when you press the
button, and **Rescan** runs it again.
- **Closing the tab only detaches.** The session keeps running, and the close dialog offers no
kill. Opening one types nothing into it.
- **Codeman did not start it,** so it will not drive it: respawn, Ralph, auto-clear,
auto-compact, auto-resume, custom model endpoints, prompt uploads and the image watcher are
refused, the git panel shows nothing, and Edit history says it is not available.
- **The tab opens on the session's first window,** and the row describes that same window.
- **It joins like a second tmux client.** While the tab is open it can resize a session
someone else is viewing, the way any second client does, and that reverses when it closes.
- **A short line in the block says why a session is missing.** One whose name holds unusual
characters is skipped, and so is one named so that tmux reads the name as something else (it
starts with `=`, `@` or `%`, or is a bare `~`). Rename it with `tmux rename-session`. A tmux
server that stopped answering costs only its own sessions. One case gets no line: a session
named `codeman-*` or `claudeman-*`, or on a Codeman socket, counts as Codeman's own.
Only sockets in tmux's own folder are scanned, so `tmux -L <name>` is found and
`tmux -S /custom/path` is not. In multi-user mode the block is for admins, since it shows
everyone's processes.
## Panels
| Panel | Opened from | Covered in |
+41 -1
View File
@@ -221,6 +221,17 @@ Things to try:
Codex with mouse tracking on gets the wheel forwarded like fullscreen Claude; otherwise
it pages its transcript or scrolls locally, while `Shift+Wheel` always uses local scrollback.
### The wheel does nothing in a pi session
Fullscreen pi, the default since pi 1.0.0, scrolls its own transcript, so the wheel is
forwarded to it while it has mouse tracking on. If the wheel does nothing, turn off
**Wheel Scrolls Local History**: that setting keeps the wheel on a local buffer pi leaves
empty, and pi has no paging fallback. `PageUp` and `PageDown` on a keyboard still reach pi.
Codeman strips pi's mouse enables, so a drag selects text in the browser rather than using
pi's own selection or scrollbar drag. With `tuiMode: regular` pi is inline and the wheel
scrolls local history.
### Selected text is invisible on a light skin
Update. Every skin named its selection colour under a key xterm renamed in v5, so the four
@@ -246,6 +257,20 @@ If you are sending input over the API instead, your payload must end with `\r` o
is ever sent. The request still succeeds and the text sits unsubmitted in the composer. See
[Driving Codeman From An Agent](Driving-Codeman-From-An-Agent).
### Persian, Arabic or Hebrew looks wrong in the terminal
The terminal is xterm.js, which does not support right-to-left text yet
([xtermjs/xterm.js#701](https://github.com/xtermjs/xterm.js/issues/701)). It puts each
character in its own cell from left to right, so a sentence comes out reversed, and the
default WebGL renderer also draws the letters unjoined. Codeman cannot fix that without
replacing the terminal.
Read the answer in **Last Response** instead, where it lays out right to left, or open a
Markdown file in the [File Viewer](Working-With-Files). On desktop, turning off **WebGL
Renderer** in **App Settings → Terminal & Input** and reloading joins the letters, so each
word reads correctly, but the words of a sentence still run left to right. Phones already
use that renderer.
## Mobile
### The keyboard covers the terminal, or scroll position jumps
@@ -329,6 +354,21 @@ Start the stack with `bash docker/Start-Codeman.sh` rather than a plain `docker
and update: since 1.29.0 the entrypoint corrects a root-owned bind mount before dropping
privileges. See [Running As A Service](Running-As-A-Service).
### Compose: `CODEMAN_PASSWORD is still the example value "changeme"`
`Start-Codeman.sh` and `Update-Codeman.sh` refuse that password before they build or stop
anything, because the container publishes its port on every interface and holds the Docker
socket, so whoever signs in controls Docker on the host. Set a real password in `docker/.env`
and run the script again.
### Compose: `Codeman did not come up`, or no answer after 180 seconds
`Start-Codeman.sh` waits for the server after `up -d`. `did not come up` means the container
exited, restarted or went unhealthy, and the script prints its last log lines. `has not
answered after 180 seconds` means it is still running but silent, so on a slow host it may
just need longer: follow it with `docker compose logs -f codeman` from `docker/`. Either way
the script exits 1, and `--no-wait` skips the wait for scripts that check on their own.
### A remote SSH session dropped and did not come back
A bounded-backoff watcher reattaches dropped sessions, and it is on by default. Intentional
@@ -353,7 +393,7 @@ On an HTTPS install, add `-k` to the curl commands and use the `https://` URL.
Open an [issue](https://github.com/Ark0N/Codeman/issues) with:
- OS and version.
- Install method: installer, npm, or git clone.
- Install method: installer (with or without git), npm, or git clone.
- `codeman --version`.
- Browser and version, if the problem is in the UI.
- Which CLI the session was running, and its version.
+3 -1
View File
@@ -77,7 +77,9 @@ Turning on either starts the watcher.
**Last Response** (header button, opt-in) renders the agent's last answer as scrollable text
rather than terminal output. It exists mostly for phones, where reading a long answer in a
terminal viewport is painful. **More** loads additional context.
terminal viewport is painful. **More** loads additional context. Persian, Arabic and Hebrew
answers read right to left here, which the terminal cannot do, while code and the file paths
it links stay left to right.
## After the fact
+55 -26
View File
@@ -6,15 +6,25 @@ until you get home.
## The File Viewer
A panel that browses the active session's working directory. Its header button is on by
default; if it is missing, re-enable it in **App Settings → Header & Panels**.
A panel that browses the active session's working directory, or the git worktree its agent
moved into ([Git Worktrees](Git-Worktrees#when-an-agent-moves-into-a-worktree)). Its header
button is on by default; if it is missing, re-enable it in **App Settings → Header & Panels**.
The panel and its search list up to 5,000 files and folders per load, shallow levels first and
taking turns between folders, so one huge folder cannot use up that limit before the ones after it,
or the folders inside it, get a turn. They also stop opening folders after reading 250,000 entries,
so a workspace with several enormous folders can still leave later ones unread. When a workspace is
bigger than either limit the status line says `(truncated)`, and an expanded folder the scan did
not finish shows **Not fully scanned** rather than looking empty. A folder that does not answer,
such as a network mount that went away, is skipped rather than waited on and is marked the same way,
so a search can miss what is inside it. The panel's Refresh button tries it again.
It renders what it can:
| Kind | Behaviour |
| ------------------------ | ------------------------------------------------------------------------- |
| Text and code | Plain preview with Lines (line numbers) and Wrap toggles in the header. Long files are truncated in plain preview. |
| Markdown | Rendered by default: headings, tables, code blocks with copy buttons, images and links relative to the file (root-relative ones resolve from the workspace root, as on GitHub). Links to another heading of the same file (`[Install](#installation)`) scroll to it, with GitHub's heading names (lower-case, punctuation dropped, repeats numbered `-1`, `-2`), and never leave the page. Opened from an attachment card, where the file's folder is unknown, relative images show their alt text and relative links show as plain text. The MD pill in the header flips to source. |
| Markdown | Rendered by default: headings, tables, code blocks with copy buttons, images and links relative to the file (root-relative ones resolve from the workspace root, as on GitHub). Links to another heading of the same file (`[Install](#installation)`) scroll to it, with GitHub's heading names (lower-case, punctuation dropped, repeats numbered `-1`, `-2`), and never leave the page. Opened from an attachment card, where the file's folder is unknown, relative images show their alt text and relative links show as plain text. Persian, Arabic and Hebrew read right to left, each block following its own first letter, while code stays left to right. The MD pill in the header flips to source. |
| Images | Inline. |
| Audio and video | Inline with a working scrub bar, because range requests are supported. |
| Spreadsheets (`.xlsx`) | Read-only grid, parsed in your browser (never on the server), up to 10 MB. `.xls` and `.ods` are download only. |
@@ -126,9 +136,11 @@ can send what it can read to any host, open HTML only from sources you trust, as
your own desktop. The **Page**
pill in the viewer header switches to the source view (where **Edit** works as for any text
file), and the viewer falls back to source on its own when a page cannot be rendered: a remote
(SSH) case, an HTML file inside a hidden folder, or one sitting directly in a broad folder such
as your home folder or `/tmp` (the page may read the files in its own folder tree, so move it
into a folder of its own). The raw file routes still serve HTML as a download only.
(SSH) case, an HTML file inside a hidden folder (which includes `.claude/worktrees/<name>` after
an agent [moved into a worktree](Git-Worktrees#when-an-agent-moves-into-a-worktree)), or one
sitting directly in a broad folder such as your home folder or `/tmp` (the page may read the
files in its own folder tree, so move it into a folder of its own). The raw file routes still
serve HTML as a download only.
Text previews are capped at the first 500 lines, fetched as a partial read, so clicking a
one-gigabyte log does not try to paint one.
@@ -147,8 +159,8 @@ session uses: one `realpath` plus `stat` probe for the file and the workspace ro
streamed `cat` (or a slice of it, so video seeking works). Symlinks are resolved on the host
that can resolve them, the size cap applies to the remote size before a byte is requested,
and an unreachable host answers 502 rather than pretending the file is missing. Nothing is
ever copied onto the Codeman host, and a same-named local file is never served under a
remote name.
ever copied onto the Codeman host, apart from the diffs the [edit history](#edit-history)
stores, and a same-named local file is never served under a remote name.
Not available over ssh, and said so with a 400 instead of a misleading 404: editing in
place, Office previews and generated thumbnails (both need the bytes on the server's disk),
@@ -157,30 +169,38 @@ their workspace is bind-mounted at the same path.
## The path picker
For choosing a path rather than typing one. It appears in two places:
For choosing a path rather than typing one. It appears in these places:
- **Browse** in **Add Case → Link Existing**.
- **Browse** in **Add Case → Create New**, under **Create in a custom folder**.
- **Browse** in **Add Case → Clone Repo**, under **Clone into a custom folder**.
- **Browse** on the folder fields of **Add Case → Docker**.
- The **📁 Path** key on the mobile keyboard bar.
It browses one directory at a time and can show hidden entries on request. The current
folder is an editable field: type or paste a path and press Enter (or **Go**) to jump
straight there, and a full file path lands in its folder with that file selected. The
**Sort** control orders each listing by name or by modified time (newest first is the
quick way to the file an agent just wrote), with folders always ahead of files; the
choice is remembered per device. The picker inserts the path into your prompt
**without** pressing Enter, so nothing is submitted by accident. Its sibling **⌫ All**
key clears the unsent prompt, and never sends the agent's `/clear` command.
It browses one directory at a time and can show hidden entries on request (the Docker
**Container Workdir** picker always lists them). The current folder is an editable
field: type or paste a path and press Enter (or **Go**) to jump straight there, and a
full file path lands in its folder with that file selected. The **Sort** control orders
each listing by name or by modified time (newest first is the quick way to the file an
agent just wrote), with folders always ahead of files; the choice is remembered per
device. A **Browse** button fills the field beside it. The **📁 Path** key inserts the
path into your prompt **without** pressing Enter, so nothing is submitted by accident.
Its sibling **⌫ All** key clears the unsent prompt, and never sends the agent's `/clear`
command.
In **Link Existing**'s picker, **+📁** (New folder) makes a folder inside the folder you
are viewing and selects it. Names use letters, numbers, spaces and `_ - . ~` (not starting
with a dot or `~`). The cases folder is refused, since every folder there is already a
case: use **Add Case → New Case** instead.
In the **Link Existing**, **Create New** (custom folder) and **Clone Repo** (custom folder)
pickers, **+📁** (New folder) makes a folder inside the folder you are viewing and selects
it. Names use letters, numbers, spaces and `_ - . ~` (not starting with a dot or `~`). The
cases folder is refused, since every folder there is already a case: pick a folder outside
it, or make the case with **Add Case → Create New** or **Clone Repo** (no custom folder).
This is a separate file-serving surface from the viewer, with its own rules: it allowlists
your home directory, the cases directory, and anything in `CODEMAN_FILE_PICKER_ROOTS`, and
blocks sensitive trees. In multi-user mode a non-admin gets only their own user space as a
root, because per-user spaces live inside the home directory and a home-directory root would
expose everyone.
expose everyone. The Docker **Container Workdir** picker lists the inside of the container
instead, read-only, so these host rules do not apply to it; it is admin-only in multi-user
mode.
## Files into a session
@@ -306,20 +326,29 @@ Click it for a draggable window listing the active session's edits, newest first
first catches up on the ones it had not read yet. **Load older** then goes back within the new
conversation.
It works for local Claude sessions only. Remote (SSH), Docker and other CLIs' sessions say so instead.
It works for Claude sessions, local and remote (SSH). Docker sessions, other CLIs' sessions and
tmux sessions opened outside Codeman say so instead.
A remote session's images show no thumbnail (each would be one more SSH read); click one to
preview it. A remote host that is asleep is never woken for the history: the window shows the
stored edits with the SSH error on top.
How it reads:
- **Only while you look.** The history is read from the session's Claude transcript when you open
the window, and again after each tool call that can change files and at the end of each turn,
while it stays open on that session. A closed window reads nothing, and Codeman does no work in
the background for sessions nobody looks at.
while it stays open on that session (a remote session at the end of each turn only: its host
sends no tool events). A closed window reads nothing, and Codeman does no work in the
background for sessions nobody looks at.
- **The transcript is found through the session's hooks.** Each prompt tells Codeman where the
session's transcript is. Right after a server restart, before the next prompt, Codeman looks in
the session's `CLAUDE_CONFIG_DIR` if you set one for it in Codeman, else in the default config
directory. A `CLAUDE_CONFIG_DIR` set outside Codeman (in a shell profile or a wrapper script)
is only known after the next prompt; until then the window says "No transcript found for this
session yet".
session yet". A remote session's transcript is looked up on its host over SSH: the
conversation its Claude writes now, else the most recently written of the one the window
showed last and the session's own, under the remote user's `~/.claude`, or under
`CLAUDE_CONFIG_DIR` when the host sets it for every SSH command (`.zshenv`,
`/etc/environment`); one set only in `.profile`, `.bash_profile` or `.zshrc` is not seen.
- **The history is stored, and it holds secrets.** Every diff an agent wrote is copied to
`~/.codeman/edit-history/<session-id>.json`, including API keys or `.env` contents it edited. The file is
readable by your user only, capped at 500 edits and 4 MiB of diff text per session (the oldest