mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
docs: publish docs/wiki as the user manual, with a sync workflow
30 pages covering install, concepts, the dashboard, the agent CLIs, unattended
runs, remote and Docker cases, security and the HTTP API, plus a sidebar and a
footer. The wiki repo has no CI and no review, so docs/wiki is the source of
truth and .github/workflows/wiki-sync.yml mirrors it on every push to master.
The workflow refuses to mirror when docs/wiki is missing or holds no pages,
because it deletes before it copies and would otherwise publish the deletion of
every page. The footer carries a {{VERSION}} placeholder stamped at publish
time rather than a hand-written version, which went stale on every release.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
name: Sync Wiki
|
||||
|
||||
# Publishes docs/wiki/ to the repository's GitHub wiki.
|
||||
#
|
||||
# The wiki is a separate git repo with no CI and no review, so the source of truth
|
||||
# lives in docs/wiki/ and this workflow mirrors it. Browser edits to the wiki are
|
||||
# overwritten by the next sync; fix pages with a PR against docs/wiki/ instead.
|
||||
#
|
||||
# One-time setup: GitHub only creates <repo>.wiki.git once the first page has been
|
||||
# saved in the browser. Save a stub page at /wiki/_new before the first run.
|
||||
#
|
||||
# Token: GITHUB_TOKEN can push to the wiki on most repos but not all. If a run fails
|
||||
# with 403, add a fine-grained PAT with wiki write access as the WIKI_TOKEN secret;
|
||||
# it is preferred automatically when present. Note the 403 usually surfaces on the
|
||||
# PUSH, not the clone: this repo is public, so a read-only token still clones the
|
||||
# wiki fine. Both steps carry the hint.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
paths:
|
||||
- 'docs/wiki/**'
|
||||
- '.github/workflows/wiki-sync.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency: ${{ github.workflow }}
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
name: Push docs/wiki to the wiki
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Clone wiki
|
||||
env:
|
||||
WIKI_TOKEN: ${{ secrets.WIKI_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if ! git clone "https://x-access-token:${WIKI_TOKEN}@github.com/${GITHUB_REPOSITORY}.wiki.git" wiki 2>"${RUNNER_TEMP}/clone-err.txt"; then
|
||||
cat "${RUNNER_TEMP}/clone-err.txt"
|
||||
echo "::error::Could not clone ${GITHUB_REPOSITORY}.wiki.git. If this says 'Repository not found', the wiki has never had a page: save one at https://github.com/${GITHUB_REPOSITORY}/wiki/_new and re-run. If it says 403, add a WIKI_TOKEN secret."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Mirror pages
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# The mirror deletes before it copies, so an empty source would wipe
|
||||
# every published page and the commit step would happily push that. A
|
||||
# MISSING directory already fails safely (cp aborts under set -e); an
|
||||
# empty one does not, so check explicitly. This is the one failure mode
|
||||
# here that destroys something a browser edit cannot get back.
|
||||
if [ ! -d docs/wiki ]; then
|
||||
echo "::error::docs/wiki does not exist. Refusing to mirror, which would delete the entire published wiki."
|
||||
exit 1
|
||||
fi
|
||||
pages=$(find docs/wiki -maxdepth 1 -name '*.md' | wc -l)
|
||||
if [ "$pages" -eq 0 ]; then
|
||||
echo "::error::docs/wiki contains no .md pages. Refusing to mirror, which would delete the entire published wiki."
|
||||
exit 1
|
||||
fi
|
||||
echo "Mirroring ${pages} pages."
|
||||
|
||||
find wiki -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} +
|
||||
cp -R docs/wiki/. wiki/
|
||||
|
||||
- name: Stamp the documented version
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# _Footer.md renders on every page and used to carry a hand-written
|
||||
# version, which went stale on every release because nothing refreshed
|
||||
# it. It carries {{VERSION}} instead and the series is stamped here.
|
||||
series="$(node -p "require('./package.json').version.split('.').slice(0,2).join('.') + '.x'")"
|
||||
# grep exits 1 when it matches nothing, which under `set -o pipefail`
|
||||
# would fail the step instead of warning, so test before substituting.
|
||||
if grep -rlq '{{VERSION}}' wiki/; then
|
||||
grep -rlZ '{{VERSION}}' wiki/ | xargs -0 -r sed -i "s/{{VERSION}}/${series}/g"
|
||||
else
|
||||
echo "::warning::No {{VERSION}} placeholder found in docs/wiki. The published version line can no longer be refreshed automatically."
|
||||
fi
|
||||
if grep -rq '{{VERSION}}' wiki/; then
|
||||
echo "::error::A {{VERSION}} placeholder survived substitution and would be published verbatim."
|
||||
exit 1
|
||||
fi
|
||||
echo "Stamped version ${series}."
|
||||
|
||||
- name: Commit and push
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd wiki
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
git add -A
|
||||
if git diff --quiet --cached; then
|
||||
echo "Wiki already up to date."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "docs: sync wiki from docs/wiki @ ${GITHUB_SHA:0:7}"
|
||||
if ! git push 2>"${RUNNER_TEMP}/push-err.txt"; then
|
||||
cat "${RUNNER_TEMP}/push-err.txt"
|
||||
echo "::error::Could not push to ${GITHUB_REPOSITORY}.wiki.git. A 403 here means the token can read the wiki but not write it, which is the usual GITHUB_TOKEN case: add a fine-grained PAT with wiki write access as the WIKI_TOKEN secret."
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,207 @@
|
||||
# Agent CLIs
|
||||
|
||||
Codeman drives seven run modes: six agent CLIs plus a plain shell. This page covers picking
|
||||
one, setting it up, and the differences that actually change how you work.
|
||||
|
||||
## The seven modes
|
||||
|
||||
| Mode | CLI | Get it |
|
||||
| -------------------- | ---------------------------- | ---------------------------------------------------------------------- |
|
||||
| **Claude Code** | `claude` | [docs.anthropic.com](https://docs.anthropic.com/en/docs/claude-code) |
|
||||
| **OpenCode** | `opencode` | [opencode.ai](https://opencode.ai) |
|
||||
| **Codex** | `codex` | [developers.openai.com/codex/cli](https://developers.openai.com/codex/cli) |
|
||||
| **Gemini** | `gemini` | [github.com/google-gemini/gemini-cli](https://github.com/google-gemini/gemini-cli) |
|
||||
| **Antigravity** | `agy` | [antigravity.google](https://antigravity.google) |
|
||||
| **Pi** | `pi` | [pi.dev](https://pi.dev) |
|
||||
| **Terminal / Shell** | your `$SHELL` | Already installed. |
|
||||
|
||||
Any combination works, including all of them. The run mode is chosen per session from the
|
||||
arrow beside the **Run** button, so one case can have a Claude session and a Codex session
|
||||
open side by side.
|
||||
|
||||
## Codeman does not manage your logins
|
||||
|
||||
Install each CLI yourself and log it in once by hand. Codeman never collects, stores, or
|
||||
refreshes your CLI credentials. It launches the binary and attaches to the result.
|
||||
|
||||
The one place credentials are touched is [Docker Cases](Docker-Cases), where host
|
||||
credentials are copied into a container read-only at launch so you do not have to log in
|
||||
again inside it. Even there, the container keeps its own copies and never writes back to
|
||||
your host credential stores.
|
||||
|
||||
## Making a CLI visible to Codeman
|
||||
|
||||
Codeman resolves each binary from the environment the **server** runs in, which is not
|
||||
necessarily the shell you tested in.
|
||||
|
||||
```bash
|
||||
codeman doctor # what Codeman can actually see
|
||||
codeman doctor --json
|
||||
```
|
||||
|
||||
If a CLI is installed but a Run button for it never appears:
|
||||
|
||||
1. Check `which <cli>` in a plain login shell, not just your interactive one.
|
||||
2. If Codeman runs as a service, remember that launchd hands a job
|
||||
`/usr/bin:/bin:/usr/sbin:/sbin`. `codeman service install` bakes your PATH into the unit
|
||||
precisely to avoid this; a hand-written plist or unit will not.
|
||||
3. Restart the server after installing a new CLI.
|
||||
|
||||
`pi` is additionally version-probed rather than trusted by name, because `pi` is a generic
|
||||
enough command that something else on your PATH may answer to it.
|
||||
|
||||
## Claude is the reference mode
|
||||
|
||||
A number of Codeman features exist only for Claude sessions. This is structural, not a
|
||||
backlog: they depend on Claude Code's hook system, or on parsing Claude's specific terminal
|
||||
output. The other CLIs expose no equivalent.
|
||||
|
||||
| Feature | Claude | Other CLIs |
|
||||
| ------------------------------------------------ | ------ | --------------------------------------------------- |
|
||||
| Sessions, tabs, scrollback, exactly-once input | Yes | Yes |
|
||||
| Respawn cycling and unattended runs | Yes | Yes |
|
||||
| Cron jobs | Yes | Yes |
|
||||
| Docker cases, remote SSH cases | Yes | Yes |
|
||||
| Precise idle detection (hook-driven) | Yes | Output-stabilization fallback, coarser |
|
||||
| Auto-resume when a usage limit resets | Yes | No |
|
||||
| Plan usage chip | Yes | No |
|
||||
| Approvals Inbox | Yes | No |
|
||||
| Read My Mind | Yes | No |
|
||||
| Ralph loop and its task tracker | Yes | No |
|
||||
| Subagent and team windows | Yes | No |
|
||||
| Model, effort, and ultracode controls | Yes | No |
|
||||
| `stop` and `blocked` wait signals | Yes | 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
|
||||
the machinery that needs to know *what* the agent is doing rather than *that* it is doing
|
||||
something.
|
||||
|
||||
## Per-CLI notes
|
||||
|
||||
### Claude Code
|
||||
|
||||
The defaults you will care about, all under **App Settings**:
|
||||
|
||||
- **Model** (Models section). Written into the case's `.claude/settings.local.json` as a
|
||||
soft default, so `/model` still works mid-session. The 1M-context Opus variant is a
|
||||
switch on the model card rather than a separate model.
|
||||
- **Effort** (`low` through `max`) or **ultracode** for dynamic multi-agent workflows. Also
|
||||
a soft default: `/effort` overrides it any time. Effort is deliberately not passed as an
|
||||
environment variable, because that would hard-lock it and block in-session switching.
|
||||
- **Startup permission mode** (Agents & CLIs section). The default is
|
||||
`--dangerously-skip-permissions`, which is why the security model matters. You can switch
|
||||
new sessions to Anthropic's classifier-guarded `auto` mode, normal prompting, or an
|
||||
explicit allowed-tools list.
|
||||
|
||||
**Separate Claude accounts per session.** Set `CLAUDE_CONFIG_DIR` in a session's environment
|
||||
overrides to point it at a different Claude config directory, which is how you run one
|
||||
session on a client's subscription and another on your own. One caveat: a relocated config
|
||||
directory writes transcripts outside `~/.claude/projects`, which blinds the response viewer,
|
||||
subagent windows, ultracode panel, and Read My Mind for that session. Symlink `projects`
|
||||
back into the shared tree to keep them working:
|
||||
|
||||
```bash
|
||||
ln -s ~/.claude/projects <configDir>/projects
|
||||
```
|
||||
|
||||
### OpenCode
|
||||
|
||||
Renders its own TUI, so Codeman treats readiness as output stabilization rather than
|
||||
watching for a prompt marker. Requires tmux, with no direct-PTY fallback, because its
|
||||
environment is injected through socket-scoped `tmux setenv` rather than the command line.
|
||||
|
||||
Integration detail: [`docs/opencode-integration.md`](https://github.com/Ark0N/Codeman/blob/master/docs/opencode-integration.md).
|
||||
|
||||
### Codex
|
||||
|
||||
Two behaviours that are deliberate and worth knowing:
|
||||
|
||||
- **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
|
||||
bytes on the wire stay byte-identical to what you typed.
|
||||
- **The wheel is not forwarded** into its transcript. Codex ignores the mouse reports
|
||||
Codeman would send, so forwarding produced a dead wheel. Scrolling in a Codex session is
|
||||
local scrollback.
|
||||
|
||||
### Gemini
|
||||
|
||||
Enterprise only, since Google's June 2026 consumer cutover. Its environment allowlist
|
||||
includes the broad `GOOGLE_*` namespace, deliberately, because Vertex AI authentication
|
||||
needs `GOOGLE_CLOUD_PROJECT`, `GOOGLE_APPLICATION_CREDENTIALS`, and
|
||||
`GOOGLE_GENAI_USE_VERTEXAI`. That is the loosest allowlist entry in Codeman and it affects
|
||||
only the CLI you spawned yourself.
|
||||
|
||||
### Antigravity
|
||||
|
||||
Google's successor to the consumer Gemini CLI, invoked as `agy`. It keeps all of its state
|
||||
in `~/.gemini/antigravity-cli/`, so the credential handling that applies to Gemini applies
|
||||
to it as well.
|
||||
|
||||
### Pi
|
||||
|
||||
Pi needs the opposite instincts from every other CLI here.
|
||||
|
||||
- **It has no permission prompts and no sandbox.** There is no bypass flag to send, and
|
||||
Codeman does not invent one.
|
||||
- **Its privileged setting is project trust**, a three-way `--approve` / `--no-approve` /
|
||||
unset. Approving trust makes Pi **execute repo-local `.pi/extensions` TypeScript**, so
|
||||
point it at a repository you trust. In multi-user mode, a user without an explicit grant
|
||||
gets `--no-approve` even when no configuration exists.
|
||||
- **Authentication is `/login` inside the session**, or the server process's own
|
||||
environment. Pi's roughly 34 provider keys (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
|
||||
`HF_TOKEN`, and so on) share no common prefix, and the environment allowlist is global
|
||||
rather than per mode, so admitting them for Pi would widen the allowlist for every mode at
|
||||
once. They stay out.
|
||||
|
||||
Guide: [`docs/pi-integration.md`](https://github.com/Ark0N/Codeman/blob/master/docs/pi-integration.md).
|
||||
|
||||
### Terminal / Shell
|
||||
|
||||
A plain shell in a tmux session. No agent, no hooks, no idle detection.
|
||||
|
||||
On phones a shell session automatically swaps the keyboard accessory bar for terminal
|
||||
controls: Ctrl, Esc, Tab, arrows, paste. **Ctrl is a one-shot modifier**: tap it, then tap a
|
||||
letter, and the control byte is sent. It disarms on use, on a second tap, on any other
|
||||
accessory key, on a session switch, and when the keyboard closes. Details in
|
||||
[Mobile Guide](Mobile-Guide).
|
||||
|
||||
## Environment overrides
|
||||
|
||||
Per-session environment variables are set when creating a session and persist across
|
||||
respawns. Which variables are accepted depends on the mode:
|
||||
|
||||
| Mode | Allowed prefixes |
|
||||
| ----------- | --------------------------------- |
|
||||
| Claude | `CLAUDE_CODE_*`, plus the exact key `CLAUDE_CONFIG_DIR` |
|
||||
| OpenCode | `OPENCODE_*` |
|
||||
| Codex | `CODEX_*` |
|
||||
| Gemini | `GEMINI_*`, `GOOGLE_*` |
|
||||
| Antigravity | `ANTIGRAVITY_*` |
|
||||
| Pi | `PI_*` |
|
||||
|
||||
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.
|
||||
|
||||
Two things that deliberately do **not** travel as environment variables: **effort**, because
|
||||
an environment variable hard-locks it and blocks `/effort`, and **model**, which is written
|
||||
into the case's `.claude/settings.local.json` so that `/model` keeps working.
|
||||
|
||||
## Choosing a mode
|
||||
|
||||
- **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** 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.
|
||||
- **Pi** if you want a fast, unsandboxed agent and you understand what project trust does.
|
||||
- **Shell** for the times you want a terminal on your phone with no agent at all. It is a
|
||||
genuinely useful mode, not a fallback.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Core Concepts](Core-Concepts) - run modes versus location overlays.
|
||||
- [Settings Reference](Settings-Reference) - model, effort, and permission-mode settings.
|
||||
- [Keeping Agents Running](Keeping-Agents-Running) - what idle detection does per mode.
|
||||
- [Security](Security) - what skipping permission prompts actually means.
|
||||
@@ -0,0 +1,97 @@
|
||||
# Autonomous Loops
|
||||
|
||||
Two features that go further than "keep the session going": the **Ralph loop**, which works
|
||||
a task list to completion in one session, and the **Orchestrator**, which turns a goal into
|
||||
a phased plan and drives it across agents.
|
||||
|
||||
Both are Claude-only, both are off by default, and neither is where to start. If what you
|
||||
want is an agent that keeps working overnight, that is
|
||||
[Keeping Agents Running](Keeping-Agents-Running), and it is simpler, better understood, and
|
||||
what most people actually use.
|
||||
|
||||
## Which one, if either
|
||||
|
||||
| You have | Use |
|
||||
| ------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| A session that stops too early | [Respawn](Keeping-Agents-Running) |
|
||||
| A written task list to grind through | Ralph loop |
|
||||
| One large goal that needs planning and checkpoints | Orchestrator |
|
||||
| Work that should start at a certain time | [Cron Jobs](Cron-Jobs) |
|
||||
| Several workers to fan out and supervise | [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent) |
|
||||
|
||||
## The Ralph loop
|
||||
|
||||
Named after the Ralph Wiggum pattern: keep feeding the agent its own task list until the
|
||||
list is empty.
|
||||
|
||||
The shape of it:
|
||||
|
||||
- The task list lives in a plan file in the case, conventionally `fix_plan.md`.
|
||||
- Each cycle the agent reads the plan, works the next incomplete task, and marks progress.
|
||||
- Codeman watches the file, tracks todos, and detects stalls.
|
||||
- The loop ends when the agent signals completion, when the iteration cap is reached, or
|
||||
when you stop it.
|
||||
|
||||
Start it from **Session Options → Ralph / Todo**, or from the wizard on the welcome screen.
|
||||
|
||||
| Setting | What it does |
|
||||
| ---------------------- | ------------------------------------------------------------------------ |
|
||||
| Max iterations | Hard ceiling on cycles. |
|
||||
| Max todos | Cap on tracked tasks, default 500, oldest evicted first. |
|
||||
| Todo expiration | Auto-expiry for stale todos, default 60 minutes. |
|
||||
| Plan file | Which file holds the task list. |
|
||||
|
||||
A **circuit breaker** sits behind it to stop respawn thrashing: it moves from closed to
|
||||
half-open to open, and is reset explicitly from the session's Ralph controls.
|
||||
|
||||
Honest assessment: Ralph is functional but is not where development attention goes. It
|
||||
predates the respawn presets, which cover most of what people originally used it for with
|
||||
less ceremony. Treat it as a specialised tool rather than the headline feature.
|
||||
|
||||
Full background, including the upstream pattern it is based on:
|
||||
[`docs/ralph-wiggum-guide.md`](https://github.com/Ark0N/Codeman/blob/master/docs/ralph-wiggum-guide.md).
|
||||
|
||||
## The Orchestrator
|
||||
|
||||
A state machine that turns one goal into a phased plan and drives it to completion:
|
||||
|
||||
```
|
||||
idle → planning → approval → executing → verifying → (replanning) → completed / failed
|
||||
```
|
||||
|
||||
- **Planning** turns your goal into phases.
|
||||
- **Approval** is yours. You see the plan before anything runs.
|
||||
- **Executing** runs each phase, using team agents and the task queue.
|
||||
- **Verifying** gates each phase before the next one starts. A failed gate can send it back
|
||||
to replanning rather than forward.
|
||||
|
||||
Open it from the Orchestrator panel in the toolbar. State persists in `state.json`, so a
|
||||
server restart does not lose an in-flight plan.
|
||||
|
||||
Where it differs from Ralph: Ralph is one session grinding a list, the Orchestrator
|
||||
coordinates phases and agents with verification between them. It suits work that has a
|
||||
natural shape ("migrate this, then update callers, then update the tests") rather than a
|
||||
flat backlog.
|
||||
|
||||
Architecture: [`docs/orchestrator-loop-architecture.md`](https://github.com/Ark0N/Codeman/blob/master/docs/orchestrator-loop-architecture.md).
|
||||
|
||||
## Running any of this safely
|
||||
|
||||
Autonomous loops are the features most able to spend money and change code while you are not
|
||||
looking. Some habits that pay off:
|
||||
|
||||
- **Run them in a case that is a git repository**, on a branch you are willing to throw
|
||||
away. Being able to read the diff afterwards is the whole safety net.
|
||||
- **Consider a container.** [Docker Cases](Docker-Cases) gives the agent its own filesystem
|
||||
and network, and one checkbox is all it costs.
|
||||
- **Set the iteration cap deliberately.** It is the ceiling on the spend.
|
||||
- **Turn on notifications** so a blocked loop reaches you: see
|
||||
[Notifications And Approvals](Notifications-And-Approvals).
|
||||
- **Read the run summary and lifecycle log afterwards**, not just the final diff. They show
|
||||
where it went sideways and recovered.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Keeping Agents Running](Keeping-Agents-Running) - the simpler feature that usually fits better.
|
||||
- [Watching Agents Work](Watching-Agents-Work) - seeing what a loop is doing while it runs.
|
||||
- [Docker Cases](Docker-Cases) - a sandbox for unattended work.
|
||||
@@ -0,0 +1,118 @@
|
||||
# Contributing
|
||||
|
||||
The full guide lives in
|
||||
[CONTRIBUTING.md](https://github.com/Ark0N/Codeman/blob/master/.github/CONTRIBUTING.md).
|
||||
This page is the short orientation, plus how to fix a page in this wiki.
|
||||
|
||||
## Where things go
|
||||
|
||||
| You have | Send it to |
|
||||
| --------------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| A bug | An [issue](https://github.com/Ark0N/Codeman/issues), with OS, install method, browser, and which CLI the session was running. |
|
||||
| A question or setup problem | [Discussions](https://github.com/Ark0N/Codeman/discussions). |
|
||||
| An idea | [Ideas](https://github.com/Ark0N/Codeman/discussions/categories/ideas), where it gets voted on. |
|
||||
| A small fix | Straight to a PR. |
|
||||
| A bigger feature | An issue or Discussion first, then build once the design has a nod. |
|
||||
| A security problem | Never a public issue. See [SECURITY.md](https://github.com/Ark0N/Codeman/blob/master/.github/SECURITY.md). |
|
||||
|
||||
Issues usually get a response within a day, and every release credits its contributors and
|
||||
bug reporters by name.
|
||||
|
||||
## Dev setup
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Ark0N/Codeman.git
|
||||
cd Codeman
|
||||
npm install # postinstall builds the vendored xterm addon bundles
|
||||
npm run dev # http://localhost:3000
|
||||
```
|
||||
|
||||
Requirements: Node 22+, tmux, and at least one agent CLI on your PATH.
|
||||
|
||||
The frontend is plain JavaScript with no bundler in dev: edit a `.js` or `.css` file and
|
||||
reload. The exception is `index.html`, which is read once at server start, so markup changes
|
||||
need a restart.
|
||||
|
||||
## Before you push
|
||||
|
||||
CI runs all of these, so running them locally saves a round trip:
|
||||
|
||||
```bash
|
||||
npm run typecheck
|
||||
npm run lint
|
||||
npm run format:check
|
||||
npm run check:frontend-syntax
|
||||
npm test -- test/<file>.test.ts # one file, the normal way
|
||||
npm run test:ci # the full CI sweep
|
||||
```
|
||||
|
||||
**Never run bare `npm test`.** The default configuration includes browser-driven Playwright
|
||||
suites that need a live server, Chromium, and environment-specific baselines; they hang or
|
||||
fail on a normal machine. `test:ci` is the honest "run everything".
|
||||
|
||||
Tests are tmux-safe by design: under vitest the tmux layer becomes an in-memory mock, so
|
||||
tests cannot touch real sessions. If you add a test that binds a port, pick a unique one at
|
||||
3150 or above, and never 3000.
|
||||
|
||||
## Finding your way around
|
||||
|
||||
- Every source file opens with a `@fileoverview` block. Read it before the file; it is the
|
||||
map.
|
||||
- [`CLAUDE.md`](https://github.com/Ark0N/Codeman/blob/master/CLAUDE.md) at the repo root is
|
||||
the densest architecture primer there is. It is written for AI coding agents, but its
|
||||
invariants apply identically to humans, and most review feedback traces back to something
|
||||
already written there.
|
||||
- [`docs/architecture-invariants.md`](https://github.com/Ark0N/Codeman/blob/master/docs/architecture-invariants.md)
|
||||
holds the deep mechanisms and the history behind each rule.
|
||||
|
||||
## Good first contributions
|
||||
|
||||
- **A theme skin.** A skin is four things kept in sync, and a static test checks the sync, so
|
||||
if the test passes your skin works.
|
||||
- **A language.** The i18n module is dependency-free, English is canonical, and Simplified
|
||||
Chinese is a complete example to copy.
|
||||
- **Docs.** If you got stuck and then figured it out, the sentence that would have unstuck
|
||||
you is a pull request.
|
||||
- Anything labelled
|
||||
[good first issue](https://github.com/Ark0N/Codeman/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
|
||||
|
||||
Worth discussing first: new CLI backends, and real-device testing reports, especially
|
||||
mobile, which always find things emulation cannot.
|
||||
|
||||
## PR expectations
|
||||
|
||||
- One change per PR. Small and focused reviews fast; a grab bag stalls.
|
||||
- Target `master`.
|
||||
- **Keep your branch mergeable.** A PR with conflicts silently gets no CI runs at all, which
|
||||
is a GitHub quirk rather than a Codeman one. Rebase when conflicts appear.
|
||||
- Include or update tests when you change behaviour.
|
||||
- Do not bump versions or edit the changelog; releases are handled after merge.
|
||||
- AI-assisted contributions are welcome, with one condition: understand what you are
|
||||
submitting, and actually run it. "The model said it works" is not a test.
|
||||
|
||||
## Fixing this wiki
|
||||
|
||||
These pages are generated from
|
||||
[`docs/wiki/`](https://github.com/Ark0N/Codeman/tree/master/docs/wiki) in the main
|
||||
repository, and pushed here automatically when master changes.
|
||||
|
||||
**Editing a page in the browser will be overwritten by the next sync.** Send a pull request
|
||||
against `docs/wiki/` instead. It is plain markdown, and a documentation PR is a genuinely
|
||||
useful contribution.
|
||||
|
||||
Conventions for wiki pages:
|
||||
|
||||
- Links between pages use the wiki form: `[Remote Access](Remote-Access)`, no `.md`.
|
||||
- Links into the repository are absolute `https://github.com/Ark0N/Codeman/blob/master/...`
|
||||
URLs.
|
||||
- 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. Six of the seven run modes are not
|
||||
Claude.
|
||||
|
||||
## Conduct
|
||||
|
||||
Be kind, be direct, assume good faith. Report unacceptable behaviour privately via the
|
||||
contact in
|
||||
[SECURITY.md](https://github.com/Ark0N/Codeman/blob/master/.github/SECURITY.md).
|
||||
@@ -0,0 +1,183 @@
|
||||
# Core Concepts
|
||||
|
||||
The five ideas the rest of the manual assumes: cases, sessions, run modes, location
|
||||
overlays, and tmux. Plus what actually persists, and where it lives on disk.
|
||||
|
||||
## Case
|
||||
|
||||
A **case** is a named working directory that Codeman remembers. It is the unit you pick in
|
||||
the toolbar before hitting Run, and every session belongs to exactly one.
|
||||
|
||||
A case is not a container or a sandbox. It is a folder plus a name plus a little
|
||||
Codeman-side configuration:
|
||||
|
||||
- Which CLI the Run button should default to.
|
||||
- Per-case toggles (Agent Teams, 1M Opus context).
|
||||
- Where it runs, if it is not the local filesystem: see [Location overlays](#location-overlays).
|
||||
|
||||
Three ways to get one, all under **+** next to the case picker:
|
||||
|
||||
| How | Result |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| **Create New** | A fresh `~/codeman-cases/<name>` with a scaffolded `CLAUDE.md`. |
|
||||
| **Clone Repo** | A public repo cloned into `~/codeman-cases/<name>` and registered as a case. |
|
||||
| **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
|
||||
registration, and for a linked case that is all it removes.
|
||||
|
||||
**Cases created from scratch are the only copy of that code.** Uninstalling Codeman does not
|
||||
delete `~/codeman-cases/`, but treat that directory as real work, not scratch space.
|
||||
|
||||
## Session
|
||||
|
||||
A **session** is one CLI process running in one tmux session, streamed to your browser.
|
||||
|
||||
Sessions are named `w<n>-<case>`, so `w1-myproject` is the first worker in the `myproject`
|
||||
case. Each has a stable id, and that id is what the API, the wait primitives, and every
|
||||
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.
|
||||
|
||||
A session carries state the case does not:
|
||||
|
||||
- Its run mode, model, effort level, and environment overrides.
|
||||
- Its respawn configuration and Ralph loop state.
|
||||
- Its terminal scrollback.
|
||||
- Its owner, in [Multi-User Mode](Multi-User-Mode).
|
||||
|
||||
## Run mode
|
||||
|
||||
The **run mode** is which CLI the session runs: `claude`, `opencode`, `codex`, `gemini`,
|
||||
`antigravity`, `pi`, or `shell`. It is chosen at start and does not change afterwards; to
|
||||
switch, start another session.
|
||||
|
||||
Claude is the reference mode. Six of the seven are not Claude, and a number of Codeman
|
||||
features are Claude-only for structural reasons rather than missing effort: they depend on
|
||||
Claude Code's hook system or on parsing its terminal output. Every such feature is labelled
|
||||
Claude-only where it appears, and [Agent CLIs](Agent-CLIs) lists them in one place.
|
||||
|
||||
## Location overlays
|
||||
|
||||
Where a case runs is **separate from** which CLI it runs. There are three locations:
|
||||
|
||||
| Location | What happens |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| **Local** | The default. tmux and the CLI run on the Codeman host. |
|
||||
| **Docker** | One long-lived container per case; sessions `docker exec` into it. See [Docker Cases](Docker-Cases). |
|
||||
| **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 eighth run
|
||||
mode. All seven 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
|
||||
tab beside your agents, but there is no PTY, no tmux, and no respawn behind it. See
|
||||
[Web Tabs](Web-Tabs).
|
||||
|
||||
## Why tmux
|
||||
|
||||
tmux is a hard requirement, and it is the reason Codeman behaves the way it does.
|
||||
|
||||
The agent runs inside a tmux session. Codeman attaches to it, the same way your terminal
|
||||
would. That indirection buys:
|
||||
|
||||
- **Survival.** The agent outlives your browser tab, your network, your laptop lid, and a
|
||||
restart of the Codeman server itself.
|
||||
- **Real scrollback.** History is held by tmux, so reconnecting replays what happened while
|
||||
you were gone instead of starting from blank.
|
||||
- **Attach from anywhere else.** The same session is reachable from a terminal over SSH
|
||||
with the `sc` chooser, or plain `tmux -L codeman attach`.
|
||||
- **Secrets off the command line.** Environment overrides are injected with socket-scoped
|
||||
`tmux setenv` rather than being visible in the spawn command.
|
||||
|
||||
The socket is `tmux -L codeman`, separate from your personal tmux server, so Codeman
|
||||
sessions never appear in a bare `tmux ls`.
|
||||
|
||||
## What persists
|
||||
|
||||
| Survives | Does not survive |
|
||||
| -------------------------------------------- | --------------------------------------------------- |
|
||||
| Closing the browser | `tmux -L codeman kill-server` |
|
||||
| Losing the network | A machine reboot (tmux dies with it) |
|
||||
| Restarting the Codeman server | Killing the session from the UI |
|
||||
| `codeman web --stop` | |
|
||||
| A dropped SSH link, for remote cases | |
|
||||
| A container restart, for docker cases | |
|
||||
|
||||
Conversation history is a separate question: Claude transcripts live in `~/.claude/`, so a
|
||||
conversation can be resumed even after the tmux session is gone. That is what the welcome
|
||||
screen's **Resume Conversation** list offers.
|
||||
|
||||
## State on disk
|
||||
|
||||
Everything Codeman knows lives under `~/.codeman/`:
|
||||
|
||||
| File | Holds |
|
||||
| ---------------------------------------- | -------------------------------------------------------------------- |
|
||||
| `state.json` | Sessions, settings, respawn config, orchestrator state, cron jobs. |
|
||||
| `settings.json` | User preferences that sync across your devices. |
|
||||
| `mux-sessions.json` | tmux recovery data. |
|
||||
| `session-lifecycle.jsonl` | Append-only audit log of session starts, exits, and kills. |
|
||||
| `linked-cases.json` | Registered cases. |
|
||||
| `remote-hosts.json`, `docker-hosts.json` | Location overlay configuration. |
|
||||
| `webviews.json` | Saved dashboard URLs. |
|
||||
| `users.json` | Multi-user accounts, mode 0600. |
|
||||
| `push-*.json` | Web push keys and subscriptions. |
|
||||
| `certs/` | Self-signed TLS for `--https`. |
|
||||
|
||||
None of it needs root, none of it leaves the machine, and deleting `~/.codeman/` resets
|
||||
Codeman to a fresh install without touching your code.
|
||||
|
||||
## Instances
|
||||
|
||||
The data directory and the tmux socket are both **process wide**. Two Codeman servers
|
||||
started on one machine share them, which means the second one discovers the first one's
|
||||
live sessions and attaches to them, resizing and mutating sessions you did not expect it to
|
||||
touch.
|
||||
|
||||
To run two on purpose, give each its own instance name:
|
||||
|
||||
```bash
|
||||
CODEMAN_INSTANCE=beta CODEMAN_PORT=5000 codeman web
|
||||
```
|
||||
|
||||
That scopes the data directory and the tmux socket together, which is the only safe way to
|
||||
do it. `CODEMAN_DATA_DIR` and `CODEMAN_TMUX_SOCKET` can be set individually if you need
|
||||
them apart, but setting only one of the two reproduces exactly the problem you were trying
|
||||
to avoid.
|
||||
|
||||
## Hooks
|
||||
|
||||
For Claude sessions, Codeman writes a hooks configuration into the case so Claude Code can
|
||||
report events back: a permission prompt appeared, the turn finished, the agent went idle, a
|
||||
task completed. Those events drive tab alerts, the Approvals Inbox, notifications, and the
|
||||
wait primitives.
|
||||
|
||||
This is why some features are Claude-only. The other CLIs have no equivalent hook system,
|
||||
so for them Codeman falls back to watching terminal output, which is coarser: it can see
|
||||
that something happened, not what it was.
|
||||
|
||||
See [Hooks And Integrations](Hooks-And-Integrations).
|
||||
|
||||
## Vocabulary
|
||||
|
||||
| Term | Means |
|
||||
| --------------- | ---------------------------------------------------------------------------- |
|
||||
| **Case** | Named working directory. |
|
||||
| **Session** | One CLI in one tmux session. |
|
||||
| **Run mode** | Which CLI: claude, opencode, codex, gemini, antigravity, pi, 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. |
|
||||
| **Subagent** | An agent the CLI spawned itself, shown live in its own window. |
|
||||
| **Web tab** | A saved dashboard URL rendered as a tab. Not a session. |
|
||||
| **Instance** | One Codeman server with its own data directory and tmux socket. |
|
||||
|
||||
## Read next
|
||||
|
||||
- [The Dashboard](The-Dashboard) - what the UI is showing you.
|
||||
- [Agent CLIs](Agent-CLIs) - the seven 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.
|
||||
@@ -0,0 +1,161 @@
|
||||
# Cron Jobs
|
||||
|
||||
Saved, named jobs that start a session and send it a prompt on a schedule. Cron for agent
|
||||
sessions: *every weekday at 03:00, open a Claude session in `~/proj` and tell it to update
|
||||
dependencies and open a PR.*
|
||||
|
||||
The ⏰ **Cron** header button is opt-in. Turn it on in
|
||||
**App Settings → Header & Panels**.
|
||||
|
||||
## Creating a job
|
||||
|
||||
1. Click **⏰ Cron**, then **+ New Job**.
|
||||
2. Give it a name, pick the agent type and working directory.
|
||||
3. Write the prompt, or point at a file containing it.
|
||||
4. Choose a schedule and leave **Enabled** on.
|
||||
5. **Save**. The job appears with its computed next run.
|
||||
|
||||
**Run Now** fires it immediately without touching the schedule, which is the fastest way to
|
||||
find out whether the prompt does what you meant.
|
||||
|
||||
## The fields
|
||||
|
||||
| Field | Notes |
|
||||
| ------------------------ | ------------------------------------------------------------------------------------------- |
|
||||
| **Name** | Also used as the created session's name. |
|
||||
| **Agent type** | Any run mode, including `shell`. |
|
||||
| **Working directory** | Validated when you save **and** again when the job fires. Blocked system trees are refused. |
|
||||
| **Launch command** | Shell jobs only. Sent as the first line once the shell is up, before the prompt. |
|
||||
| **Prompt** | Inline text, or a path to a file read at fire time. |
|
||||
| **Input mode** | `typed` behaves like a human typing. `paste` writes directly. |
|
||||
| **Schedule** | `once`, `interval`, `daily`, or `weekly`. |
|
||||
| **Enabled** | Disabled jobs never fire on their own. **Run Now** still works. |
|
||||
| **Concurrency policy** | What to do if sessions of the same type are already running. |
|
||||
| **Auto-close previous** | Recurring jobs only. Closes the session the previous run created. Default on. |
|
||||
| **Notes** | Free text for you. |
|
||||
|
||||
## Schedules
|
||||
|
||||
All wall-clock times are in the **server's local timezone**, not your browser's. A job set
|
||||
for 03:00 fires at 03:00 where the server is.
|
||||
|
||||
| Type | Behaviour |
|
||||
| ---------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `once` | Fires at an absolute time, then disables itself. A job missed because the server was down still fires once on the next tick. |
|
||||
| `interval` | Every N minutes, from 1 minute to a year. |
|
||||
| `daily` | At `HH:MM` every day. If today's time has passed, the next run is tomorrow. |
|
||||
| `weekly` | At `HH:MM` on the weekdays you pick. |
|
||||
|
||||
Interval jobs re-anchor to when they actually fired, not to an ideal cadence, so a slow tick
|
||||
or a server restart shifts later runs slightly. That drift is accepted rather than corrected.
|
||||
|
||||
## Prompts are single line
|
||||
|
||||
This is the rule people trip over. Programmatic input into an agent session is single line
|
||||
everywhere in Codeman, because the terminal UIs these CLIs use treat a newline as submit. A
|
||||
multi-line prompt would be silently mangled, so it is **rejected** instead: the form refuses
|
||||
it, and a prompt file whose contents are multi-line fails the run with a clear message.
|
||||
|
||||
For anything longer than a sentence, put the instructions in a file and make the prompt tell
|
||||
the agent to read it:
|
||||
|
||||
```
|
||||
read TASKS.md and work through it
|
||||
```
|
||||
|
||||
That is also easier to edit than a job field.
|
||||
|
||||
### Prompt files
|
||||
|
||||
Reading the prompt from a file at fire time is useful when the instructions change more
|
||||
often than the schedule. The path is confined to the job's working directory, symlinks are
|
||||
resolved before the check, sensitive trees are refused, and the file has to be a regular
|
||||
file under 1 MiB.
|
||||
|
||||
If any of that fails, the run is recorded as failed and **no session is created**.
|
||||
|
||||
## Concurrency
|
||||
|
||||
Applies to scheduled runs only, never to **Run Now**:
|
||||
|
||||
| Policy | Behaviour |
|
||||
| ------------------------------- | -------------------------------------------------------------------------------------- |
|
||||
| `warn_only` | Always launch. The count of live same-type sessions is shown but does not block. |
|
||||
| `skip_if_same_agent_running` | Skip this fire if another live session of that mode exists. |
|
||||
|
||||
The skip policy has the details you would want it to have:
|
||||
|
||||
- Only **live** sessions block. A tab whose CLI already exited does not count.
|
||||
- Sessions the job created on its own previous runs never block it, otherwise a recurring
|
||||
job would deadlock on itself after the first fire.
|
||||
- A skipped `once` job is not consumed. It stays armed and fires when the blocker goes away.
|
||||
- Consecutive skips are collapsed into one record per streak, so a perpetually skipped job
|
||||
cannot bloat your state file.
|
||||
|
||||
## Run history
|
||||
|
||||
Every fire is recorded per job, with a status:
|
||||
|
||||
| Status | Meaning |
|
||||
| --------- | -------------------------------------------------------------------- |
|
||||
| `created` | The run started and a session was created. |
|
||||
| `skipped` | The concurrency policy blocked it. Not counted as a run. |
|
||||
| `failed` | The prompt could not be resolved, or the working directory was gone. |
|
||||
|
||||
The schedule is advanced **before** the session launches, so a slow start cannot cause the
|
||||
same job to re-trigger.
|
||||
|
||||
## Cron versus the other autonomy features
|
||||
|
||||
| Want | Use |
|
||||
| --------------------------------------------------- | ------------------------------------------------------- |
|
||||
| Start work at a specific time | Cron |
|
||||
| Keep an existing session working | [Keeping Agents Running](Keeping-Agents-Running) |
|
||||
| Drive one goal to completion across phases | [Autonomous Loops](Autonomous-Loops) |
|
||||
|
||||
There is also an older, deliberately separate `ScheduledRun` concept behind
|
||||
`/api/scheduled`: a run-now, duration-bounded loop with no recurrence and no saved jobs. The
|
||||
two systems never interact, and Cron is the one you want.
|
||||
|
||||
## From the API
|
||||
|
||||
```bash
|
||||
API=http://localhost:3000
|
||||
|
||||
curl -s -X POST "$API/api/cron/jobs" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"name": "nightly-deps",
|
||||
"agentType": "claude",
|
||||
"workingDir": "/home/me/proj",
|
||||
"promptMode": "inline_text",
|
||||
"promptText": "Update dependencies and open a PR",
|
||||
"inputMode": "typed",
|
||||
"scheduleType": "daily",
|
||||
"dailyTime": "03:00",
|
||||
"enabled": true,
|
||||
"concurrencyPolicy": "warn_only"
|
||||
}' | jq
|
||||
|
||||
curl -s "$API/api/cron/jobs" | jq
|
||||
curl -s -X POST "$API/api/cron/jobs/<jobId>/run" | jq
|
||||
curl -s "$API/api/cron/jobs/<jobId>/runs" | jq
|
||||
```
|
||||
|
||||
Add `-u admin:"$CODEMAN_PASSWORD"` when a password is set, and `-k` with the `https://` URL
|
||||
on an HTTPS install.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Times are the server's, not yours.** Obvious until you are travelling.
|
||||
- **A `pi` job starts slowly.** The readiness poll looks for markers pi does not print, so it
|
||||
burns its poll budget before sending the prompt. The job still works.
|
||||
- **A deleted working directory fails the run**, by design, rather than creating a session
|
||||
somewhere unexpected.
|
||||
- **Auto-close only touches sessions this job created.** Your own tabs are never closed.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Keeping Agents Running](Keeping-Agents-Running) - continuing work rather than starting it.
|
||||
- [Notifications And Approvals](Notifications-And-Approvals) - hearing about a job that got stuck.
|
||||
- [`docs/cron-guide.md`](https://github.com/Ark0N/Codeman/blob/master/docs/cron-guide.md) - the complete reference, including the API and SSE events.
|
||||
@@ -0,0 +1,177 @@
|
||||
# Docker Cases
|
||||
|
||||
Run a case inside its own container instead of directly on your host: for isolation, for a
|
||||
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 seven run modes work inside a
|
||||
container. See [Core Concepts](Core-Concepts).
|
||||
|
||||
## One-time setup: the base image
|
||||
|
||||
The container needs an image carrying the agent toolchain (node, the CLIs, git, tmux). It
|
||||
builds itself on first use with progress streamed to the UI, or you can build it ahead of
|
||||
time:
|
||||
|
||||
```bash
|
||||
node scripts/build-agent-image.mjs --no-cache
|
||||
```
|
||||
|
||||
**Always pass `--no-cache`.** The CLIs are installed in a single `npm install -g` layer, so
|
||||
a plain rebuild reuses that layer from the cache and the CLIs stay frozen at whatever
|
||||
versions the image was *first* built with. This has shipped a broken CLI while reporting a
|
||||
successful build.
|
||||
|
||||
A zero exit code proves the layers ran, not that the toolchain works. Verify:
|
||||
|
||||
```bash
|
||||
docker run --rm codeman/agent:base bash -lc \
|
||||
'for c in claude codex gemini opencode agy pi; do printf "%-9s " $c; $c --version 2>&1 | head -1; done'
|
||||
```
|
||||
|
||||
The image is secret-free. Credentials are delivered at runtime, never baked in, so exports
|
||||
never leak them. A full image lands around 1.6GB.
|
||||
|
||||
Prerequisite: Docker or Podman with a reachable daemon.
|
||||
|
||||
## The quick way
|
||||
|
||||
On **Add Case → Create New**, tick **🐳 Run in an isolated Docker container**. That alone is
|
||||
enough: Codeman creates the case folder, spins up a hardened container with sensible
|
||||
defaults, and starts the session inside it.
|
||||
|
||||
Expanding **Container settings** offers a template:
|
||||
|
||||
| Template | Memory | CPUs | GPUs |
|
||||
| ----------------- | ------ | ---- | ------------------------------------- |
|
||||
| Small | 2 GB | 1 | none |
|
||||
| Medium (default) | 4 GB | 2 | none |
|
||||
| Large | 8 GB | 4 | none |
|
||||
| GPU | 8 GB | 4 | all (needs the NVIDIA container toolkit) |
|
||||
|
||||
Disk is elastic: storage grows as data arrives, bounded only by host disk. Changing any
|
||||
setting creates a dedicated host profile for that case, so it never mutates the shared
|
||||
default.
|
||||
|
||||
## The full way
|
||||
|
||||
**Add Case → Docker** exposes everything:
|
||||
|
||||
| Field | Meaning |
|
||||
| -------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| **Case name** | As usual. |
|
||||
| **Workspace path** | A real host directory, bind-mounted into the container at the **same absolute path**. |
|
||||
| **Host ID** | A reusable profile (image, network, resources). Share one across cases to share settings. |
|
||||
| **Network** | `bridge` (internet on, default), `none` (fully isolated), or a custom bridge. |
|
||||
| **Advanced** | Memory and CPU caps, host credential seeding, and whether to resume the last conversation on relaunch. |
|
||||
|
||||
The same-absolute-path bind mount is what keeps the File Viewer, attachments, and watchers
|
||||
operating on real host bytes rather than a copy.
|
||||
|
||||
## One container per case
|
||||
|
||||
Exactly one long-lived container per case, shared by every session in it.
|
||||
|
||||
- Killing one session kills only that session's in-container tmux. Siblings keep running and
|
||||
the container stays up.
|
||||
- Reconnecting after a Codeman restart lands back in the same live agent.
|
||||
- A container stop or a host reboot restarts the container and **resumes the last
|
||||
conversation** from the bind-mounted transcript.
|
||||
- Deleting the case removes the container. The workspace on the host survives.
|
||||
|
||||
## Credentials
|
||||
|
||||
Your existing host logins work inside the container without logging in again. Credentials
|
||||
are **seeded**: mounted read-only and copied in once at launch, so in-container CLIs never
|
||||
write refreshed tokens back to your host credential stores. Onboarding and trust prompts are
|
||||
pre-answered so no wizard appears.
|
||||
|
||||
Turn seeding **off** for a sealed sandbox: no host credentials, and with `network: none`, no
|
||||
outbound access either. That is the profile for genuinely untrusted work; you log in inside
|
||||
the container instead.
|
||||
|
||||
Bind mounts are excluded from image capture, so exports stay secret-free.
|
||||
|
||||
One consequence worth knowing: Pi's credentials are seeded per file rather than as a whole
|
||||
directory, because that directory also holds sessions, extensions, and installed packages,
|
||||
which can be gigabytes. So in-container Pi sessions are invisible from the host, and `pi -c`
|
||||
inside a docker case sees only that container's history.
|
||||
|
||||
## Isolation
|
||||
|
||||
Every container runs hardened by default:
|
||||
|
||||
- `--cap-drop ALL`
|
||||
- `--security-opt no-new-privileges`
|
||||
- Non-root, running as your host uid so workspace files stay host-owned
|
||||
- PID limit, memory cap with swap pinned to it, `--init`
|
||||
- **Never** `--privileged`, and **never** the docker socket
|
||||
|
||||
Rootless engines without cgroup-v2 systemd delegation cannot enforce resource caps; linking
|
||||
such a host warns that the caps are advisory.
|
||||
|
||||
## Configuration drift is refused, not ignored
|
||||
|
||||
Editing a docker host's configuration (image, memory, network) after a container exists is
|
||||
detected on the next launch by comparing a configuration hash against the container's label.
|
||||
A mismatch **refuses the launch** and offers to recreate rather than silently running with
|
||||
stale configuration.
|
||||
|
||||
Recreating is refused while sessions of that case are live. The workspace and the
|
||||
conversation both survive it.
|
||||
|
||||
## Moving a case to another machine
|
||||
|
||||
**Export**, from the Docker tab:
|
||||
|
||||
| Option | Contents |
|
||||
| -------------------------- | ------------------------------------------------------------------------- |
|
||||
| **Full image + workspace** | The whole toolchain, installed packages, and files, in one `.tgz`. |
|
||||
| **Workspace only** | Just the project files. Fast and small. |
|
||||
|
||||
The container is paused across the capture so image and workspace are consistent, free space
|
||||
is checked first, and the intermediate image is cleaned up. Exports run in the background
|
||||
and notify you when the bundle is ready.
|
||||
|
||||
**Import** on the other machine: copy the `.tgz` into `~/.codeman/docker-exports/` and
|
||||
import it into a new case. The manifest and per-member checksums are verified, the workspace
|
||||
tar is extracted with a traversal guard, and the image is loaded under a **quarantined tag**
|
||||
so it can never overwrite a local image. The destination supplies its own credentials, so
|
||||
nothing secret crosses machines.
|
||||
|
||||
## Hooks need to reach the server
|
||||
|
||||
In-container hooks (permission events, idle and stop notifications) call back to Codeman
|
||||
over the docker bridge gateway. If Codeman binds **loopback only**, which is the default and
|
||||
the production configuration, the container cannot reach it and **in-container hooks do not
|
||||
fire**.
|
||||
|
||||
The session still works fully: idle detection falls back to output-based detection through
|
||||
the exec PTY, and with permission prompts skipped there is nothing to forward anyway.
|
||||
|
||||
To enable them:
|
||||
|
||||
```bash
|
||||
CODEMAN_DOCKER_BRIDGE_HOOKS=1
|
||||
```
|
||||
|
||||
Codeman then starts a second listener bound to the docker bridge gateway that serves **only**
|
||||
the hook endpoints and rejects everything else with a 403. The bridge is host-internal, so
|
||||
this does not widen your network exposure. Add it to the service unit and restart.
|
||||
|
||||
## Limits
|
||||
|
||||
- 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.
|
||||
- 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
|
||||
VM's own ceiling.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Core Concepts](Core-Concepts) - why this is an overlay rather than a run mode.
|
||||
- [Security](Security) - where containers fit in the model.
|
||||
- [Remote SSH Sessions](Remote-SSH-Sessions) - the other overlay.
|
||||
- [`docs/docker-cases.md`](https://github.com/Ark0N/Codeman/blob/master/docs/docker-cases.md) - the full reference.
|
||||
@@ -0,0 +1,188 @@
|
||||
# Driving Codeman From An Agent
|
||||
|
||||
Everything the dashboard does is HTTP, so an agent can do it too. This page is for the case
|
||||
that makes Codeman interesting: **Claude Code running inside a Codeman session, spawning and
|
||||
supervising other sessions.**
|
||||
|
||||
Two routes. Start with the skill.
|
||||
|
||||
## The agent skill
|
||||
|
||||
A Claude Code skill that teaches the agent the whole API, so you ask in plain English
|
||||
instead of pasting endpoint documentation into prompts.
|
||||
|
||||
### Install it
|
||||
|
||||
| How | Command | Scope |
|
||||
| ------------ | ----------------------------------------------------------- | ----------------------------------------------------------- |
|
||||
| Skills CLI | `npx skills add Ark0N/Codeman --skill codeman -g` | Global, any skills-aware agent. |
|
||||
| Bundled CLI | `codeman skill install` | Global, at `~/.claude/skills/codeman`. |
|
||||
| Bundled CLI | `codeman skill install --case <name>` | One case. |
|
||||
| Web UI | **App Settings → Agents & CLIs → Claude → Agent Skill** | Injects into each case when a Claude session is created. Off by default. |
|
||||
|
||||
`codeman skill uninstall [--case <name>]` reverses the CLI installs, and never touches a
|
||||
`skills/codeman` you wrote yourself.
|
||||
|
||||
### Then just ask
|
||||
|
||||
| You say | What happens |
|
||||
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| "What sessions are running right now?" | Lists them with name, mode, and status. Read-only. |
|
||||
| "Start a shell worker on the `myapp` case, run the test suite, tell me if it passes." | Spawns, waits on a completion marker, reads the exit code, cleans up. |
|
||||
| "Spin up 3 workers for lint, typecheck and tests, run them in parallel, report failures." | One session per task, all started first, then gathered as each finishes. |
|
||||
| "Have a claude worker summarize `src/session.ts`, then close it." | Spawns, runs the readiness ladder, sends and waits, reads the answer, deletes the session. |
|
||||
| "Watch session w4 and tell me if it gets stuck on a permission prompt." | Blocks on the `blocked` signal and surfaces the question to **you**. |
|
||||
|
||||
Sessions the agent creates get deleted when it is done. You can watch the tabs appear and
|
||||
disappear in the dashboard while it works.
|
||||
|
||||
### What it will and will not do
|
||||
|
||||
- **It self-gates.** Outside a Codeman session it refuses to act and does not guess an API
|
||||
URL, so a global install costs an unrelated Claude Code session nothing.
|
||||
- **Unprompted, it may only** spawn sessions, prompt them, and delete ones **it created in
|
||||
that conversation, by exact id**, behind a guard that refuses to delete the agent's own
|
||||
session.
|
||||
- **It will not** answer another session's permission prompt on your behalf. It surfaces the
|
||||
question instead.
|
||||
- **Deleting a case** (which erases a real directory of your code), bulk kills, respawn,
|
||||
Ralph, cron, orchestrator, and settings writes all require you to ask, naming the target.
|
||||
|
||||
Turning the setting back off **does not remove already-injected copies**, because a
|
||||
create-time sweep would yank the skill out from under other live sessions sharing that
|
||||
directory. Remove them per case with `codeman skill uninstall --case <name>`.
|
||||
|
||||
The skill ships with the verb index always loaded, plus on-demand references for the verbs,
|
||||
worked multi-worker recipes, endpoint tables, and cross-session messaging.
|
||||
|
||||
## The manual path
|
||||
|
||||
The same operations as raw HTTP, for a CI bot, a shell script, or an agent without skill
|
||||
support.
|
||||
|
||||
### Detect that you are inside Codeman
|
||||
|
||||
These are set in every managed session. Read them rather than hardcoding anything:
|
||||
|
||||
| Variable | Meaning |
|
||||
| -------------------------- | ------------------------------------------------------------------------ |
|
||||
| `CODEMAN_MUX=1` | You are in a managed tmux session. Never `tmux kill-session`, `pkill claude`, or `pkill tmux`: you will kill yourself or a sibling. |
|
||||
| `CODEMAN_API_URL` | Base URL, with the correct scheme. |
|
||||
| `CODEMAN_SESSION_ID` | Your own session id. Use it to avoid acting on yourself. |
|
||||
| `CODEMAN_HOOK_SECRET_FILE` | Path to the hook secret. |
|
||||
|
||||
### Rules of the road
|
||||
|
||||
Read these before writing any code. Each one has cost somebody an afternoon.
|
||||
|
||||
1. **Input is single line and must end with `\r`.** Enter fires only when the payload
|
||||
contains a carriage return. Without it the text sits unsubmitted on the prompt, the
|
||||
request still succeeds, and a combined wait burns its full timeout on a turn that never
|
||||
started. Embedded newlines are stripped rather than rejected, so `"echo A\necho B\r"` runs
|
||||
the joined `echo Aecho B`. One line per call.
|
||||
2. **Make input idempotent.** Send a stable `clientId` and a monotonic per-session `seq`. The
|
||||
server deduplicates, so a retry after a dropped connection cannot double-deliver.
|
||||
3. **Auth.** With `CODEMAN_PASSWORD` set, use HTTP Basic or the session cookie. A missing
|
||||
`Origin` is allowed, so plain curl works. A `401` replies with the bare string
|
||||
`Unauthorized`, **not** the JSON envelope, so piping it into `jq` throws a parse error
|
||||
instead of showing the failure. Check the status before parsing.
|
||||
4. **Envelope.** Most endpoints return `{ "success": true, "data": ... }`. A few legacy GETs
|
||||
return bare bodies, so handle both: `body.data ?? body`.
|
||||
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` sessions emit `stop` and `blocked`.** They come from Claude Code hooks.
|
||||
Shell and the 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
|
||||
`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.
|
||||
|
||||
### Recipes
|
||||
|
||||
```bash
|
||||
API="${CODEMAN_API_URL:-http://localhost:3000}"
|
||||
# Add -u admin:"$CODEMAN_PASSWORD" if a password is set, and -k on an HTTPS install.
|
||||
|
||||
# What is running
|
||||
curl -s "$API/api/sessions" | jq '.data[] | {id, name, mode, status}'
|
||||
|
||||
# Spawn a worker in a case
|
||||
curl -s -X POST "$API/api/quick-start" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"caseName":"myapp","mode":"shell"}' | jq
|
||||
|
||||
# Send a prompt (note the \r)
|
||||
curl -s -X POST "$API/api/sessions/$ID/input" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"input":"run the tests\r","clientId":"my-agent","seq":1}' | jq
|
||||
|
||||
# Send and block until the turn finishes (registers the wait BEFORE writing)
|
||||
curl -s -X POST "$API/api/sessions/$ID/input" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"input":"summarize src/session.ts\r","wait":["stop"],"waitTimeout":120000}' | jq
|
||||
|
||||
# Or wait for a marker in the output, which works on shell sessions too
|
||||
curl -s "$API/api/sessions/$ID/wait-output?contains=DONE_17909&from=buffer" | jq
|
||||
|
||||
# Read the terminal back
|
||||
curl -s "$API/api/sessions/$ID/terminal?tail=4000" | jq -r '.data.output'
|
||||
|
||||
# Clean up, by exact id
|
||||
curl -s -X DELETE "$API/api/sessions/$ID" | jq
|
||||
```
|
||||
|
||||
Use `POST /api/quick-start` rather than `POST /api/sessions` when a case might be remote:
|
||||
the plain create endpoint validates the working directory locally and has no case concept.
|
||||
|
||||
### The split-marker trick
|
||||
|
||||
For hook-less sessions, synchronize on a marker in the output. The catch: your own
|
||||
keystrokes echo into the output stream, so an unsplit marker matches **before the command
|
||||
has run**.
|
||||
|
||||
Split it so the typed line never contains the string you are waiting for:
|
||||
|
||||
```bash
|
||||
M=DONE; R=17909
|
||||
# typed: echo ${M}_${R} → output contains DONE_17909, the typed line does not
|
||||
```
|
||||
|
||||
Make it unique per call, because tmux repaints replay old screen text.
|
||||
|
||||
### Reading output
|
||||
|
||||
Use `terminal?tail=`, not `/output`. The latter's text field is empty for every tmux-backed
|
||||
session, which is every interactive session. `tail` counts **bytes**, and what comes back is
|
||||
terminal data with ANSI sequences included.
|
||||
|
||||
## Fan-out, and why it needs care
|
||||
|
||||
Wait signals are **edge triggered with no history**. A signal that fires with no waiter
|
||||
registered is unobservable afterwards.
|
||||
|
||||
So a fan-out must register its waits before or as it dispatches: use send-and-wait per
|
||||
worker, or latched output markers. Dispatching all the workers and then waiting on them one
|
||||
at a time loses the signals of everyone who finished early.
|
||||
|
||||
Send-and-wait registers the waiter **before** the write for the same reason. A separate POST
|
||||
followed by a wait races, and reports the previous turn's state.
|
||||
|
||||
## Lineage
|
||||
|
||||
A create request can name the session that spawned it, through a body field or a header, and
|
||||
the dashboard then draws a lineage arc from parent to child. The skill sets it automatically.
|
||||
|
||||
It is resolved rather than trusted: an unresolvable parent is dropped silently rather than
|
||||
failing the spawn, because a cosmetic field must never break a worker.
|
||||
|
||||
## Read next
|
||||
|
||||
- [HTTP API](HTTP-API) - the endpoint map and the envelope.
|
||||
- [Hooks And Integrations](Hooks-And-Integrations) - events flowing the other way.
|
||||
- [Watching Agents Work](Watching-Agents-Work) - seeing the fan-out in the UI.
|
||||
- [`skills/codeman/SKILL.md`](https://github.com/Ark0N/Codeman/blob/master/skills/codeman/SKILL.md) - the skill itself.
|
||||
@@ -0,0 +1,250 @@
|
||||
# FAQ
|
||||
|
||||
The questions that keep arriving in
|
||||
[Discussions](https://github.com/Ark0N/Codeman/discussions) and issues. For "why is it
|
||||
doing that", go to [Troubleshooting](Troubleshooting) instead.
|
||||
|
||||
## The basics
|
||||
|
||||
### What is Codeman, in one sentence?
|
||||
|
||||
A self-hosted dashboard that runs AI coding agents in persistent tmux sessions on your own
|
||||
machine and lets you drive them from any browser, including a phone.
|
||||
|
||||
### Is it free? What is the licence?
|
||||
|
||||
MIT, free, and open source. There is no paid tier and no account.
|
||||
|
||||
### Do I need an API key?
|
||||
|
||||
No. Codeman drives agent CLIs you have already installed and logged in yourself. Whatever
|
||||
subscription or key that CLI uses is what pays for the tokens. Codeman never collects,
|
||||
stores, or refreshes your credentials.
|
||||
|
||||
### Does Codeman send my code or prompts anywhere?
|
||||
|
||||
No. There is no telemetry, no analytics, and no phone-home. The only network traffic
|
||||
Codeman itself makes is between your browser and your server.
|
||||
|
||||
Your agent CLI is a separate matter: Claude Code talks to Anthropic, Codex talks to OpenAI,
|
||||
and so on. That traffic is the CLI's, on your own account, exactly as it would be in a
|
||||
terminal.
|
||||
|
||||
Two features do send data outward, both off by default and both stated where they appear:
|
||||
voice dictation through your own Claude login, and the Read My Mind prediction call.
|
||||
|
||||
### Does it work on Windows?
|
||||
|
||||
Through WSL2. Codeman requires tmux. Install it inside WSL, run your agent CLI inside WSL,
|
||||
and `http://localhost:3000` works from your Windows browser. Work in the Linux filesystem
|
||||
rather than `/mnt/c/...`, which is dramatically slower for file watching and git.
|
||||
|
||||
### Is there a mobile app?
|
||||
|
||||
The web UI is built for phones and installs as a PWA. There is no App Store or Play Store
|
||||
app.
|
||||
|
||||
## Sessions and persistence
|
||||
|
||||
### Do my agents keep running when I close the browser?
|
||||
|
||||
Yes. Agents run in tmux on the server, not in your browser. Close the tab, close the laptop,
|
||||
lose the network. When you come back, the session is still there with its scrollback.
|
||||
|
||||
The same holds when the Codeman server itself restarts. What does end a session is killing
|
||||
the tmux server or rebooting the machine.
|
||||
|
||||
### What happens after a reboot?
|
||||
|
||||
tmux dies with the machine, so the sessions are gone. Conversations are not: Claude
|
||||
transcripts persist on disk, and the welcome screen's **Resume Conversation** list picks
|
||||
them back up. Install Codeman as a service and the server itself comes back on boot.
|
||||
|
||||
### How many sessions can I run at once?
|
||||
|
||||
The design target is 20 sessions and 50 agent windows at 60fps. The hard cap is higher, and
|
||||
what you will actually hit first is the CPU and memory of the machine running the agents.
|
||||
|
||||
### Can I run Claude Code and Codex side by side?
|
||||
|
||||
Yes, that is a normal setup. The run mode is per session, so one case can have a Claude tab,
|
||||
a Codex tab, and a shell tab open at the same time, each with its own colour. Some Codeman
|
||||
features are Claude-only; [Agent CLIs](Agent-CLIs) lists exactly which.
|
||||
|
||||
### Can I attach to a session from a terminal instead of the browser?
|
||||
|
||||
Yes. `sc` is an interactive chooser (`sc 2` attaches directly, `sc -l` lists), or use tmux
|
||||
directly on the `codeman` socket. Detach with `Ctrl+A D`.
|
||||
|
||||
## Running unattended
|
||||
|
||||
### I hit my Claude usage limit overnight. Can Codeman resume automatically?
|
||||
|
||||
Yes, and it is the reason the feature exists. Turn on auto-resume at the top of the Respawn
|
||||
tab for that session. When Claude halts on a subscription limit, Codeman parses the reset
|
||||
time from the message, waits until two minutes past it, and continues the conversation.
|
||||
|
||||
Respawn cycles are blocked while a session is limit-paused, which is what stops a `/clear`
|
||||
from wiping the conversation you are waiting to resume. Claude-only.
|
||||
|
||||
### Will it keep prompting my agent forever?
|
||||
|
||||
Only if you configure it to. Respawn cycling is per session and off unless you turn it on,
|
||||
and it has presets ranging from a 60 minute solo session to an 8 hour overnight run. There
|
||||
are circuit breakers to stop a thrashing session from spinning indefinitely. See
|
||||
[Keeping Agents Running](Keeping-Agents-Running).
|
||||
|
||||
### Does an idle session cost tokens?
|
||||
|
||||
No. An idle agent is a process waiting for input. Tokens are spent when a turn runs, so what
|
||||
costs money is the re-prompting you configured, not the session sitting there.
|
||||
|
||||
### Can I schedule work for a specific time?
|
||||
|
||||
Yes. [Cron Jobs](Cron-Jobs) saves named jobs on a `once`, `interval`, `daily`, or `weekly`
|
||||
schedule; each spins up a session and sends a prompt when due, with per-job run history.
|
||||
|
||||
## Access
|
||||
|
||||
### How do I reach Codeman from my phone when I am away from home?
|
||||
|
||||
Tailscale is the recommended answer: your devices join a private network, Codeman keeps its
|
||||
loopback bind, and you get real HTTPS. The installer sets it up, and `install.sh tailscale`
|
||||
retrofits it onto an existing install.
|
||||
|
||||
A Cloudflare tunnel gives a public URL faster, and requires `CODEMAN_PASSWORD`. Full
|
||||
comparison in [Remote Access](Remote-Access).
|
||||
|
||||
### Why can't other devices reach Codeman?
|
||||
|
||||
Because the default bind is `127.0.0.1`, on purpose. Codeman starts agents with permission
|
||||
prompts skipped, so whoever reaches the dashboard can run code on your machine. Exposing it
|
||||
is a deliberate step, and [Remote Access](Remote-Access) covers the safe ways.
|
||||
|
||||
### My reverse proxy domain is rejected with `403 host not allowed`
|
||||
|
||||
The always-on Host-header allowlist blocks DNS rebinding, and it does not know your domain.
|
||||
Add it:
|
||||
|
||||
```bash
|
||||
CODEMAN_ALLOWED_HOSTS='codeman.example.com,.internal.example.com'
|
||||
```
|
||||
|
||||
A leading dot matches subdomains. Also make sure the proxy forwards WebSocket upgrades.
|
||||
|
||||
### Do I have to type a password on my phone?
|
||||
|
||||
No. Scan the QR code shown on the desktop dashboard. Tokens are single use and rotate every
|
||||
60 seconds. The password remains the fallback.
|
||||
|
||||
## Multiple people, multiple instances
|
||||
|
||||
### Can several people share one Codeman?
|
||||
|
||||
Yes, with `codeman web --multiuser`. Each person gets a login and their own case space, and
|
||||
sessions, cases, search, and events are scoped to their owner.
|
||||
|
||||
Be clear about what that is: it separates **workspaces**, not operating system accounts.
|
||||
Every session still runs as the same OS user, so a determined user's agent can reach another
|
||||
user's files. For real isolation, pair users with Docker cases or run separate instances
|
||||
under separate OS accounts. See [Multi-User Mode](Multi-User-Mode).
|
||||
|
||||
### How do I run a second instance, a beta beside my main one?
|
||||
|
||||
Give it its own instance name, which scopes the data directory and the tmux socket together:
|
||||
|
||||
```bash
|
||||
CODEMAN_INSTANCE=beta CODEMAN_PORT=5000 codeman web
|
||||
```
|
||||
|
||||
Do not skip this. The data directory and tmux socket are process wide, so a second server on
|
||||
the defaults discovers and attaches your live sessions.
|
||||
|
||||
## Updating and maintenance
|
||||
|
||||
### What is the right way to update Codeman?
|
||||
|
||||
| Install route | Update with |
|
||||
| ------------- | --------------------------------------------------------------------------- |
|
||||
| Installer | Re-run the install one-liner, or **App Settings → System → Updates**. |
|
||||
| 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.
|
||||
|
||||
### Will updating kill my running sessions?
|
||||
|
||||
No. Sessions live in tmux, so restarting the server reattaches to them.
|
||||
|
||||
### Where is my data?
|
||||
|
||||
Everything under `~/.codeman/`, with cases created from scratch in `~/codeman-cases/`.
|
||||
Nothing needs root and nothing leaves the machine. Uninstalling does not delete either
|
||||
directory.
|
||||
|
||||
## Features
|
||||
|
||||
### What is the difference between respawn, Ralph, and the orchestrator?
|
||||
|
||||
- **Respawn** restarts a session's CLI when it goes idle, to keep a long run going. It is the
|
||||
one most people want.
|
||||
- **Ralph loop** is an autonomous single-session task loop with its own tracker.
|
||||
- **Orchestrator** turns one goal into a phased plan and drives it across agents.
|
||||
|
||||
[Keeping Agents Running](Keeping-Agents-Running) and [Autonomous Loops](Autonomous-Loops)
|
||||
cover them properly.
|
||||
|
||||
### Can agents start and supervise other agents?
|
||||
|
||||
Yes. Codeman ships an agent skill that lets an agent inside a session drive the HTTP API:
|
||||
list sessions, spawn workers, send prompts, and block until a worker's turn finishes. It is
|
||||
off by default and enabled per case.
|
||||
|
||||
See [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent).
|
||||
|
||||
### Can I run a case in a container?
|
||||
|
||||
Yes. One container per case, shared by all its sessions, non-root and capability-dropped by
|
||||
default, with your host CLI logins seeded in so nothing asks you to log in again. You can
|
||||
export a container plus its workspace and move it to another machine. See
|
||||
[Docker Cases](Docker-Cases).
|
||||
|
||||
### Can the agent run on a different machine?
|
||||
|
||||
Yes. Point a case at a remote host over SSH and the agent runs there, inside a durable
|
||||
remote tmux, so a dropped connection does not kill the run. See
|
||||
[Remote SSH Sessions](Remote-SSH-Sessions).
|
||||
|
||||
### Can I put my Grafana or other dashboards in here?
|
||||
|
||||
Yes. Saved URLs render as tabs beside your sessions, proxied through Codeman's own origin so
|
||||
that mixed content and frame-blocking headers do not break them. See [Web Tabs](Web-Tabs).
|
||||
|
||||
### Why is a feature I read about not on screen?
|
||||
|
||||
Most of Codeman's UI is opt-in and defaults to off, so a stock install stays small. Check
|
||||
**App Settings → Header & Panels**. [Settings Reference](Settings-Reference) lists the
|
||||
defaults.
|
||||
|
||||
## Contributing
|
||||
|
||||
### How do I request a feature?
|
||||
|
||||
Open an [Idea](https://github.com/Ark0N/Codeman/discussions/categories/ideas) and it gets
|
||||
voted on. Roadmap decisions happen there.
|
||||
|
||||
### How do I contribute code?
|
||||
|
||||
[CONTRIBUTING.md](https://github.com/Ark0N/Codeman/blob/master/.github/CONTRIBUTING.md) has
|
||||
the full map. Small fixes can go straight to a PR; anything larger starts as an issue or
|
||||
Discussion so the design gets a nod first. Skins, translations, and docs are good first
|
||||
contributions.
|
||||
|
||||
### How do I fix a mistake in this wiki?
|
||||
|
||||
These pages are generated from
|
||||
[`docs/wiki/`](https://github.com/Ark0N/Codeman/tree/master/docs/wiki) in the main
|
||||
repository. Editing a page in the browser gets overwritten on the next sync, so send a PR
|
||||
against that directory instead.
|
||||
@@ -0,0 +1,164 @@
|
||||
# HTTP API
|
||||
|
||||
Codeman's HTTP and SSE API is a **stable contract**. Everything the dashboard does goes
|
||||
through it, so anything the dashboard can do, a script can do.
|
||||
|
||||
This page is the orientation. The complete specification, including every wait semantic and
|
||||
the SSE catalogue, is
|
||||
[`docs/api-reference.md`](https://github.com/Ark0N/Codeman/blob/master/docs/api-reference.md).
|
||||
|
||||
## What is stable
|
||||
|
||||
Covered by semantic versioning: endpoint paths under `/api/v1`, the response envelope,
|
||||
`errorCode` values, and SSE event names.
|
||||
|
||||
Not covered, and free to change in a patch release: on-disk state files, internal modules,
|
||||
and anything marked experimental. The full statement is in
|
||||
[Versioning](Versioning).
|
||||
|
||||
`/api/v1/*` is a versioned alias of `/api/*`. Prefer the versioned form in anything you
|
||||
intend to keep.
|
||||
|
||||
## The envelope
|
||||
|
||||
```json
|
||||
{ "success": true, "data": { } }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "success": false, "error": "human readable", "errorCode": "NOT_FOUND" }
|
||||
```
|
||||
|
||||
A few legacy GET handlers return bare bodies rather than the envelope, so a robust client
|
||||
reads `body.data ?? body`.
|
||||
|
||||
Branch on `errorCode`, which is stable. The HTTP status is reliable too:
|
||||
|
||||
| `errorCode` | HTTP | Meaning |
|
||||
| ------------------ | ---- | ------------------------------------------------ |
|
||||
| `INVALID_INPUT` | 400 | Malformed request or failed validation. |
|
||||
| `UNAUTHORIZED` | 401 | Authentication required or failed. |
|
||||
| `NOT_FOUND` | 404 | No such resource. |
|
||||
| `SESSION_BUSY` | 409 | The session is busy. |
|
||||
| `CONFLICT` | 409 | Conflicts with current state. |
|
||||
| `ALREADY_EXISTS` | 409 | Resource already exists. |
|
||||
| `OPERATION_FAILED` | 422 | Well formed, could not be completed. |
|
||||
| `RATE_LIMITED` | 429 | Too many requests. |
|
||||
| `INTERNAL_ERROR` | 500 | Unexpected server error. |
|
||||
|
||||
New error codes are non-breaking. Removing or renaming one is a major change.
|
||||
|
||||
**A `401` is the bare string `Unauthorized`, not the envelope.** Piping it into `jq` throws
|
||||
a parse error rather than showing the failure, so check the status first.
|
||||
|
||||
## Authentication
|
||||
|
||||
With no password set, and the default loopback bind, there is none. With `CODEMAN_PASSWORD`
|
||||
set, use HTTP Basic or the session cookie:
|
||||
|
||||
```bash
|
||||
curl -s -u admin:"$CODEMAN_PASSWORD" "$API/api/sessions"
|
||||
```
|
||||
|
||||
A **missing** `Origin` header is allowed, so curl and CLI tools work unchanged. A
|
||||
present-but-foreign origin is rejected by the CSRF guard. On an HTTPS install with the
|
||||
self-signed certificate, add `-k`.
|
||||
|
||||
## Endpoint map
|
||||
|
||||
Roughly 200 handlers across 24 route modules. By domain:
|
||||
|
||||
| Domain | Handlers | Covers |
|
||||
| ------------------- | -------- | --------------------------------------------------- |
|
||||
| System | 45 | Status, settings, search, digest, updates. |
|
||||
| Sessions | 34 | Create, input, terminal, wait, kill. |
|
||||
| Cases | 29 | Create, link, clone, remote and docker cases. |
|
||||
| Files | 16 | Preview, edit, raw, attachments, path picker. |
|
||||
| Orchestrator | 10 | Plans and phases. |
|
||||
| Ralph | 9 | Loop control and configuration. |
|
||||
| Cron | 9 | Jobs and run history. |
|
||||
| Admin | 8 | Multi-user administration. |
|
||||
| Plan | 8 | Plan orchestration. |
|
||||
| Respawn | 7 | Respawn configuration and presets. |
|
||||
| Webviews | 6 | Saved dashboards, plus the proxy. |
|
||||
| Mux | 5 | tmux operations. |
|
||||
| Push | 4 | Web push subscriptions. |
|
||||
| Read My Mind | 4 | Intent profiles and prediction. |
|
||||
| Scheduled | 4 | The legacy scheduled-run concept. |
|
||||
| Approvals | 3 | The inbox and answering. |
|
||||
| Teams, me, search, hooks, clipboard, telemetry, voice, ws | 1-2 each | |
|
||||
|
||||
Each route module documents its own endpoints in its file header.
|
||||
|
||||
## Long-polling instead of polling
|
||||
|
||||
Three calls block until something happens, so an agent driving Codeman from a shell can wait
|
||||
rather than spin:
|
||||
|
||||
| Call | Blocks until |
|
||||
| ----------------------------------------- | -------------------------------------------------------- |
|
||||
| `GET /api/v1/sessions/:id/wait` | One of a set of lifecycle signals fires. |
|
||||
| `GET /api/v1/sessions/:id/wait-output` | A literal string appears in the session's output. |
|
||||
| `POST /api/v1/sessions/:id/input` + `wait`| The input is delivered **and then** a signal fires. |
|
||||
|
||||
Three semantics that break callers who assume otherwise:
|
||||
|
||||
1. **A timeout is `200`, not an error.** It answers with `wait.timedOut: true`. Loop over
|
||||
short waits; a single long call gets cut by tunnels and proxies.
|
||||
2. **Send-and-wait is not a POST followed by a wait.** It registers the waiter *before*
|
||||
writing, which closes the window where a separate wait sees the session still idle from
|
||||
the previous turn and answers instantly about the wrong turn.
|
||||
3. **Signals are edge triggered with no history.** One that fires with no waiter registered
|
||||
is unobservable afterwards. Fan-outs must register their waits as they dispatch.
|
||||
|
||||
`wait-output` matches a **literal substring, never a regex.** That is deliberate: no regex
|
||||
means no catastrophic backtracking on attacker-influenced output.
|
||||
|
||||
Only `claude` sessions emit `stop` and `blocked`, because those come from Claude Code hooks.
|
||||
Shell and external CLI sessions accept `idle`, `working`, and `exit`.
|
||||
|
||||
## SSE
|
||||
|
||||
`GET /api/events` is the live event stream. 155 event names, kept in sync between server and
|
||||
client with a test that fails on drift.
|
||||
|
||||
The heartbeat is a **named** `sse:heartbeat` event rather than an SSE comment, because
|
||||
comments are invisible to `EventSource` by specification and a client could not observe
|
||||
them. That is what lets the browser detect a stream that has silently stopped delivering.
|
||||
|
||||
```js
|
||||
const es = new EventSource('/api/events');
|
||||
es.addEventListener('session:created', (e) => console.log(JSON.parse(e.data)));
|
||||
```
|
||||
|
||||
## Quick examples
|
||||
|
||||
```bash
|
||||
API="${CODEMAN_API_URL:-http://localhost:3000}"
|
||||
|
||||
curl -s "$API/api/status" | jq # whole-system snapshot
|
||||
curl -s "$API/api/sessions" | jq '.data[].name' # live sessions
|
||||
curl -s "$API/api/sessions/unified" | jq # live + historical, deduped
|
||||
curl -s "$API/api/subagents" | jq # background agents
|
||||
curl -s "$API/api/search?q=deploy" | jq # cross-session search
|
||||
```
|
||||
|
||||
## Limits
|
||||
|
||||
| Limit | Default |
|
||||
| --------------------- | ------------------------------------------ |
|
||||
| Max sessions | 50 |
|
||||
| Max agent windows | 500 |
|
||||
| Max SSE clients | 100 |
|
||||
| Terminal buffer | 32 MB per session |
|
||||
| Text payload | 1 MB |
|
||||
| Wait timeout ceiling | 600 s, and the response tells you what was applied |
|
||||
|
||||
Most are environment-overridable. See `src/config/`.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent) - the practical version, with recipes.
|
||||
- [Hooks And Integrations](Hooks-And-Integrations) - events flowing back into Codeman.
|
||||
- [Versioning](Versioning) - what the version number promises.
|
||||
- [`docs/api-reference.md`](https://github.com/Ark0N/Codeman/blob/master/docs/api-reference.md) - the full specification.
|
||||
@@ -0,0 +1,136 @@
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/Ark0N/Codeman/master/docs/images/codeman-title.svg" alt="Codeman" height="56">
|
||||
</p>
|
||||
|
||||
<h3 align="center">Mission control for AI coding agents</h3>
|
||||
|
||||
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, or
|
||||
Pi 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.
|
||||
|
||||
This wiki is the manual. The [README](https://github.com/Ark0N/Codeman) is the overview,
|
||||
and the deep internals live in
|
||||
[`docs/`](https://github.com/Ark0N/Codeman/tree/master/docs).
|
||||
|
||||
```bash
|
||||
curl -fsSL https://getcodeman.com/install | bash
|
||||
codeman web # then open http://localhost:3000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Start here
|
||||
|
||||
**New to Codeman**
|
||||
|
||||
1. [Installation](Installation) - requirements, the installer, npm and git clone routes, updating.
|
||||
2. [Quick Start](Quick-Start) - from a running server to a working agent in five minutes.
|
||||
3. [Core Concepts](Core-Concepts) - cases, sessions, run modes, and what survives a restart.
|
||||
4. [The Dashboard](The-Dashboard) - reading the tab strip, the status dots, and the alerts.
|
||||
|
||||
**Already running it**
|
||||
|
||||
- [Agent CLIs](Agent-CLIs) - the seven 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.
|
||||
- [Troubleshooting](Troubleshooting) - symptom-first index of things that actually break.
|
||||
|
||||
**Driving it from code**
|
||||
|
||||
- [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent) - the bundled skill, worker sessions, wait primitives.
|
||||
- [HTTP API](HTTP-API) - the envelope, auth, the endpoint map, SSE events.
|
||||
- [Hooks And Integrations](Hooks-And-Integrations) - events flowing back into Codeman.
|
||||
|
||||
---
|
||||
|
||||
## Everything in the manual
|
||||
|
||||
### Getting started
|
||||
|
||||
| Page | What it answers |
|
||||
| ------------------------------- | --------------------------------------------------- |
|
||||
| [Installation](Installation) | How do I install it, update it, and remove it? |
|
||||
| [Quick Start](Quick-Start) | How do I get one agent working right now? |
|
||||
| [Core Concepts](Core-Concepts) | What is a case, a session, a run mode? |
|
||||
|
||||
### Using it
|
||||
|
||||
| Page | What it answers |
|
||||
| ------------------------------------------ | ---------------------------------------------------------- |
|
||||
| [The Dashboard](The-Dashboard) | What is the UI telling me? |
|
||||
| [Agent CLIs](Agent-CLIs) | Which agent should this session run, and how do I set it up? |
|
||||
| [Working With Files](Working-With-Files) | How do I read, edit, and attach files? |
|
||||
| [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? |
|
||||
| [Settings Reference](Settings-Reference) | What does this setting do, and why did it not follow me to my phone? |
|
||||
|
||||
### Keeping agents running
|
||||
|
||||
| Page | What it answers |
|
||||
| ------------------------------------------------------------- | --------------------------------------------------- |
|
||||
| [Keeping Agents Running](Keeping-Agents-Running) | How does it run unattended overnight? |
|
||||
| [Notifications And Approvals](Notifications-And-Approvals) | How do I know an agent needs me, and answer from my phone? |
|
||||
| [Cron Jobs](Cron-Jobs) | How do I run an agent on a schedule? |
|
||||
| [Autonomous Loops](Autonomous-Loops) | What are the Ralph and Orchestrator loops for? |
|
||||
| [Watching Agents Work](Watching-Agents-Work) | How do I see what the subagents are doing? |
|
||||
|
||||
### Where it runs
|
||||
|
||||
| Page | What it answers |
|
||||
| --------------------------------------------- | -------------------------------------------- |
|
||||
| [Docker Cases](Docker-Cases) | How do I sandbox a project in a container? |
|
||||
| [Remote SSH Sessions](Remote-SSH-Sessions) | How do I run the agent on another machine? |
|
||||
| [Web Tabs](Web-Tabs) | Can my Grafana live in here too? |
|
||||
| [Multi-User Mode](Multi-User-Mode) | Can several people share one Codeman? |
|
||||
|
||||
### Access and security
|
||||
|
||||
| Page | What it answers |
|
||||
| ------------------------------- | ---------------------------------------------------------- |
|
||||
| [Remote Access](Remote-Access) | How do I reach it from outside this machine, safely? |
|
||||
| [Security](Security) | What is exposed, what protects it, what do I have to do? |
|
||||
|
||||
### Automation and integration
|
||||
|
||||
| Page | What it answers |
|
||||
| ----------------------------------------------------------------- | -------------------------------------------- |
|
||||
| [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent) | How does an agent spawn and drive workers? |
|
||||
| [HTTP API](HTTP-API) | What can I call, and what comes back? |
|
||||
| [Hooks And Integrations](Hooks-And-Integrations) | How do I wire Codeman into something else? |
|
||||
|
||||
### Operating it
|
||||
|
||||
| Page | What it answers |
|
||||
| --------------------------------------------- | -------------------------------------------------- |
|
||||
| [Running As A Service](Running-As-A-Service) | How do I keep it up across reboots, and update it? |
|
||||
| [Troubleshooting](Troubleshooting) | Why is it doing that? |
|
||||
| [FAQ](FAQ) | The questions that keep coming up. |
|
||||
| [Contributing](Contributing) | How do I send a fix? |
|
||||
| [Versioning](Versioning) | What does the version number promise? |
|
||||
|
||||
---
|
||||
|
||||
## Requirements at a glance
|
||||
|
||||
| Thing | Needed |
|
||||
| ------------ | --------------------------------------------------------------------------- |
|
||||
| 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. 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
|
||||
machine.
|
||||
|
||||
## Getting help
|
||||
|
||||
- **Questions and setup help**: [Discussions](https://github.com/Ark0N/Codeman/discussions), especially [Q&A](https://github.com/Ark0N/Codeman/discussions/categories/q-a).
|
||||
- **Bugs**: [Issues](https://github.com/Ark0N/Codeman/issues). Include your OS, install method, browser, and which CLI the session was running.
|
||||
- **Ideas and roadmap**: [Ideas](https://github.com/Ark0N/Codeman/discussions/categories/ideas).
|
||||
- **Security**: never a public issue. See [SECURITY.md](https://github.com/Ark0N/Codeman/blob/master/.github/SECURITY.md).
|
||||
@@ -0,0 +1,97 @@
|
||||
# Hooks and Integrations
|
||||
|
||||
Events flowing **back** into Codeman, and the four seams a third party can build against.
|
||||
|
||||
## Hooks
|
||||
|
||||
Claude Code can run a command when something happens in a session. Codeman writes a hooks
|
||||
configuration into each Claude case so those events post back to it, which is what turns a
|
||||
terminal into something that can notify you.
|
||||
|
||||
| Event | Fires when | Drives |
|
||||
| ---------------------- | ----------------------------------------------- | --------------------------------------------- |
|
||||
| `permission_prompt` | The agent asks for permission. | Red tab alert, Approvals Inbox, push. |
|
||||
| `idle_prompt` | The agent is waiting for input. | Yellow tab alert, the `idle` wait signal. |
|
||||
| `stop` | A turn ends. | The `stop` wait signal, idle detection. |
|
||||
| `elicitation_dialog` | A dialog opens. | Approvals Inbox. |
|
||||
| `elicitation_complete` | The dialog closes. | Clearing the alert. |
|
||||
| `elicitation_response` | The dialog is answered. | Clearing the alert. |
|
||||
| `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 other CLIs have no hook system, so
|
||||
for them Codeman watches terminal output, which reveals that something happened but not what
|
||||
it was.
|
||||
|
||||
### How hooks get installed
|
||||
|
||||
Codeman writes them into the case when a Claude session is created. Hook blocks are
|
||||
**marker-owned**: Codeman only ever updates a block it wrote, and never touches
|
||||
configuration you added yourself.
|
||||
|
||||
If tab alerts and approvals never fire in a particular case, that case is missing its hook
|
||||
block. Recreating the case rewrites it.
|
||||
|
||||
### The hook secret
|
||||
|
||||
`/api/hook-event` and `/api/status-telemetry` skip HTTP Basic authentication, because they
|
||||
are called from localhost by the CLI itself. When authentication is on, that bypass
|
||||
additionally requires a per-instance hook secret, because Codeman cannot tell a genuine
|
||||
loopback call from a request arriving through your own loopback reverse proxy.
|
||||
|
||||
The secret lives in the data directory, and its path is exported into every managed session.
|
||||
|
||||
### Two things that break hooks
|
||||
|
||||
- **HTTPS.** Hook callbacks must accept the self-signed certificate. Recent versions
|
||||
self-heal existing cases; older cases need recreating.
|
||||
- **Docker cases on a loopback bind.** A container cannot reach `127.0.0.1` on the host, so
|
||||
in-container hooks silently do not fire. Set `CODEMAN_DOCKER_BRIDGE_HOOKS=1` to open a
|
||||
hooks-only listener on the bridge gateway. See [Docker Cases](Docker-Cases).
|
||||
|
||||
## Integration seams
|
||||
|
||||
Codeman has **no plugin runtime**, and that is a decision rather than a gap. A plugin runtime
|
||||
means running third-party code inside a process that spawns agents with your credentials, on
|
||||
a server people routinely expose over a tunnel. Codeman's security posture is one of its
|
||||
reasons to exist, so it does not trade that away for an extension mechanism.
|
||||
|
||||
What exists instead is four documented seams.
|
||||
|
||||
### 1. Web tabs
|
||||
|
||||
Anything with a web UI can live inside Codeman as a tab, proxied through Codeman's own
|
||||
origin. The lowest-effort integration by a wide margin: if your tool has a dashboard, it can
|
||||
sit beside the agents with no code at all. See [Web Tabs](Web-Tabs).
|
||||
|
||||
### 2. SSE events
|
||||
|
||||
`GET /api/events` streams everything Codeman knows: session lifecycle, output, agent
|
||||
activity, approvals, cron runs. 155 named events, stable under semantic versioning.
|
||||
|
||||
This is the seam for anything that reacts. A bot that pings your chat channel when an agent
|
||||
needs a human is a short script over this stream.
|
||||
|
||||
### 3. HTTP API and CLI
|
||||
|
||||
Everything the dashboard does. Create sessions, send input, block on wait primitives, read
|
||||
terminals, manage cron. See [HTTP API](HTTP-API) and
|
||||
[Driving Codeman From An Agent](Driving-Codeman-From-An-Agent).
|
||||
|
||||
### 4. Hooks
|
||||
|
||||
The seam above, in the other direction: your own hook commands can run alongside Codeman's
|
||||
in a case, as long as you leave Codeman's marker-owned block alone.
|
||||
|
||||
## Publishing an integration
|
||||
|
||||
There is no registry to submit to. Share it in
|
||||
[Show and tell](https://github.com/Ark0N/Codeman/discussions/300), and if it needs a change
|
||||
in Codeman to work properly, open an issue or a Discussion first.
|
||||
|
||||
## Read next
|
||||
|
||||
- [HTTP API](HTTP-API) - the endpoint map and envelope.
|
||||
- [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent) - the agent-facing path.
|
||||
- [`docs/extending-codeman.md`](https://github.com/Ark0N/Codeman/blob/master/docs/extending-codeman.md) - the seams in full, with examples.
|
||||
- [`docs/claude-code-hooks-reference.md`](https://github.com/Ark0N/Codeman/blob/master/docs/claude-code-hooks-reference.md) - upstream hook semantics.
|
||||
@@ -0,0 +1,135 @@
|
||||
# Input and Voice
|
||||
|
||||
Getting words into an agent: typing, dictating, and letting Codeman guess. Plus the input
|
||||
machinery that only shows up when it goes wrong.
|
||||
|
||||
## Typing
|
||||
|
||||
Click into the terminal and type. It is a real terminal, so everything the CLI supports
|
||||
works, slash commands included.
|
||||
|
||||
| Key | Effect |
|
||||
| ---------------------------- | --------------------------------------------- |
|
||||
| `Enter` | Send. |
|
||||
| `Shift+Enter` / `Ctrl+Enter` | Newline without sending. |
|
||||
| `Ctrl+C` | Copy if text is selected, otherwise interrupt. |
|
||||
| `Ctrl+Shift+C` | Copy, never interrupts. |
|
||||
| `Ctrl+L` | Clear the terminal. |
|
||||
|
||||
### Exactly-once delivery
|
||||
|
||||
Browser input goes through a durable layer rather than a plain socket write. Each prompt
|
||||
carries a stable client id and a per-session sequence number, held in local storage until
|
||||
the server acknowledges it.
|
||||
|
||||
The result is the property you want on a phone: a connection that drops mid-prompt never
|
||||
loses the prompt and never delivers it twice. Two browser tabs on the same session coexist,
|
||||
and only a reconnect from the *same* tab supersedes the old connection.
|
||||
|
||||
## Zero-lag local echo
|
||||
|
||||
On touch devices, keystrokes are painted in the terminal immediately and sent when you press
|
||||
Enter, instead of waiting for each character to round-trip to the server and back. Over a
|
||||
mobile connection that is the difference between usable and not.
|
||||
|
||||

|
||||
|
||||
The consequence to remember: **text on screen has not necessarily reached the agent yet.**
|
||||
It is flushed on Enter. If a prompt appears to have been ignored, press Enter, or the phone
|
||||
toolbar's **Enter** button.
|
||||
|
||||
Default on for touch devices, off for desktop, and switchable in
|
||||
**App Settings → Terminal & Input**.
|
||||
|
||||
### Codex is different on purpose
|
||||
|
||||
Codex's composer reacts to every keystroke: `/` opens a live-filtering picker, arrows edit
|
||||
state on its side, the composer grows as text wraps. Buffering until Enter starved it, so
|
||||
Codex sessions use **predictive echo** instead: each keystroke is painted at its predicted
|
||||
position while the bytes actually sent stay identical to what you typed. Predictions
|
||||
reconcile against the real buffer and only apply while the cursor is on the composer row.
|
||||
|
||||
## CJK input
|
||||
|
||||
Chinese, Japanese, and Korean input needs an IME, and an IME needs a real text field.
|
||||
Turning on CJK input in **App Settings → Terminal & Input** puts an always-visible textarea
|
||||
below the terminal that owns composition, then delivers the composed text to the session.
|
||||
|
||||
## Voice dictation
|
||||
|
||||
`Ctrl+Shift+V`, or the microphone button. There are three providers and the default is
|
||||
`auto`, which prefers them in this order:
|
||||
|
||||
| Provider | Needs | Notes |
|
||||
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------ |
|
||||
| **Claude** | Claude Code logged in on the server. Opt-in. | Uses this machine's existing Claude login. No extra key. |
|
||||
| **Deepgram** | A Deepgram API key. | Nova-3, with automatic silence detection. |
|
||||
| **Web Speech** | Nothing. | Browser-provided, quality varies. |
|
||||
|
||||
### Dictating through your Claude login
|
||||
|
||||
Off by default; enable it in **App Settings → Voice**.
|
||||
|
||||
Claude Code has its own voice mode, but it opens the **host's** microphone, and in Codeman
|
||||
the CLI runs headless in a tmux pane while you are in a browser somewhere else entirely. So
|
||||
Codeman captures audio in your browser and borrows only the backend: audio goes browser to
|
||||
Codeman to Anthropic, and the page never sees the OAuth token.
|
||||
|
||||
Two deliberate limits:
|
||||
|
||||
- **Credentials are read only.** Codeman never refreshes your Claude token, because a
|
||||
refresh rotates the refresh token and could sign you out of your own CLI. An expired token
|
||||
is reported as expired rather than silently renewed.
|
||||
- **Capture is raw PCM** at 16 kHz mono, which requires an AudioWorklet rather than the
|
||||
usual browser recorder.
|
||||
|
||||
## Read My Mind
|
||||
|
||||
**Claude only, off by default.** Turn it on in **App Settings**, and a 🧠 button appears in
|
||||
the header (on phones, in the keyboard bar instead).
|
||||
|
||||
It keeps a per-case **intent profile**: goals you or your agent write down, plus the prompts
|
||||
you actually submitted in that case. Pressing 🧠 feeds that profile plus live session signals
|
||||
to a single model call and shows a predicted next prompt.
|
||||
|
||||
What you can do with the result:
|
||||
|
||||
- **Send** it, **Insert** it into the composer, or edit it first.
|
||||
- Pick one of the alternate suggestions, which swaps into the editable field without losing
|
||||
your edits.
|
||||
- **Rethink**, optionally with a steer note, to reject the whole set and try again.
|
||||
|
||||
**Nothing is ever sent automatically.** Every path requires a click.
|
||||
|
||||
Where the data lives: the profile is keyed by owner and the resolved working directory, so
|
||||
it survives `/clear` and respawns. Prompts can contain secrets, so the store is written
|
||||
0600 and is deliberately excluded from cross-session search.
|
||||
|
||||
Guide: [`docs/readmymind.md`](https://github.com/Ark0N/Codeman/blob/master/docs/readmymind.md).
|
||||
|
||||
## Programmatic input
|
||||
|
||||
Sending prompts over the API has one rule that catches everyone: **the payload must end with
|
||||
`\r`** or Enter is never sent. The request still succeeds, the text sits unsubmitted in the
|
||||
composer, and any wait burns its whole timeout on a turn that never started.
|
||||
|
||||
Input is also **single line**. Embedded newlines are stripped rather than rejected, so
|
||||
`"echo A\necho B\r"` runs the joined `echo Aecho B`. Put multi-line content in a file and
|
||||
tell the agent to read it.
|
||||
|
||||
See [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Typed text sitting on screen has not been sent.** Press Enter.
|
||||
- **`Ctrl+C` with a selection copies.** Clear the selection to interrupt.
|
||||
- **Voice needs HTTPS.** Microphone access requires a secure context, same as push
|
||||
notifications.
|
||||
- **Read My Mind goes blind for sessions using a relocated Claude config directory**, along
|
||||
with the other transcript-backed features. See [Agent CLIs](Agent-CLIs).
|
||||
|
||||
## Read next
|
||||
|
||||
- [Mobile Guide](Mobile-Guide) - the keyboard bar and touch input.
|
||||
- [Keyboard Shortcuts](Keyboard-Shortcuts) - the full list.
|
||||
- [Working With Files](Working-With-Files) - images and attachments as input.
|
||||
@@ -0,0 +1,234 @@
|
||||
# Installation
|
||||
|
||||
Getting Codeman onto a machine, verifying it works, updating it, and removing it.
|
||||
|
||||
## Requirements
|
||||
|
||||
| Requirement | Notes |
|
||||
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **macOS or Linux** | Windows works through WSL2. See [Windows](#windows-wsl) below. |
|
||||
| **Node.js 22+** | The installer offers to install it if missing. |
|
||||
| **tmux** | Not optional. Sessions live inside tmux, which is what makes them survive a server restart, a dropped connection, or a closed laptop. |
|
||||
| **An agent CLI** | At least one of [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [OpenCode](https://opencode.ai), [Codex](https://developers.openai.com/codex/cli), [Antigravity](https://antigravity.google), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Pi](https://pi.dev). Plain shell sessions need none. See [Agent CLIs](Agent-CLIs). |
|
||||
|
||||
Codeman itself sends no telemetry and phones no home. The only network traffic is your
|
||||
browser to your server, and whatever the agent CLI you chose does on its own.
|
||||
|
||||
## Route A: the installer (recommended)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://getcodeman.com/install | bash
|
||||
```
|
||||
|
||||
This installs Node.js and tmux if they are missing, clones Codeman into `~/.codeman/app`,
|
||||
and builds it.
|
||||
|
||||
What it asks you:
|
||||
|
||||
1. **Permission for every system change.** Package installs and agent CLI downloads are
|
||||
prompted individually. Nothing is installed silently.
|
||||
2. **How the dashboard should be reachable.** Three choices:
|
||||
- **Tailscale** (recommended for phone access): keeps the loopback bind and walks you
|
||||
through `tailscale serve`, including the tailnet HTTPS toggle, then verifies the result
|
||||
end to end.
|
||||
- **Your local network** (`0.0.0.0`): prompts for a password. Skipping the password takes
|
||||
an explicit confirmation and ends on a loud warning.
|
||||
- **This machine only** (`127.0.0.1`): the safest option, and the default for a bare
|
||||
`codeman web` regardless of what you pick here.
|
||||
|
||||
Which one is preselected depends on what the installer finds. A fresh install defaults to
|
||||
the local network, unless Tailscale is already connected, in which case it defaults to
|
||||
Tailscale. An existing loopback install defaults to keeping loopback, or to Tailscale when
|
||||
a serve mapping for Codeman is already there. A bare Enter never pulls in new software,
|
||||
and a non-interactive run always keeps the safe loopback default.
|
||||
3. **What to do when it finishes.** Run in this terminal, install as a background service
|
||||
that starts on boot, or do nothing yet.
|
||||
|
||||
Re-running the same one-liner **updates an existing install in place**. Local changes in
|
||||
`~/.codeman/app` are stashed rather than discarded, a running service is restarted and
|
||||
verified, and your existing network binding is preserved. An interrupted first install
|
||||
resumes instead of restarting.
|
||||
|
||||
Two other entry points exist:
|
||||
|
||||
```bash
|
||||
install.sh update # update only
|
||||
install.sh uninstall # remove
|
||||
install.sh tailscale # retrofit Tailscale access onto an existing install
|
||||
```
|
||||
|
||||
**Automation and CI**: with no terminal attached, any step that would change the system
|
||||
aborts with instructions instead of running silently. Set `CODEMAN_NONINTERACTIVE=1` to
|
||||
approve those steps. `CODEMAN_TAILSCALE=1` preselects the Tailscale answer, and never
|
||||
installs Tailscale itself non-interactively.
|
||||
|
||||
## Route B: npm
|
||||
|
||||
```bash
|
||||
npm install -g aicodeman
|
||||
codeman web
|
||||
```
|
||||
|
||||
The npm package is named `aicodeman`; the product is Codeman. Both `codeman` and
|
||||
`aicodeman` are installed as commands.
|
||||
|
||||
The trade-off against Route A: no guided network setup, and the in-app self-updater does
|
||||
not apply. npm installs report as non-updatable in **App Settings → System → Updates**, and
|
||||
you update with `npm update -g aicodeman`.
|
||||
|
||||
## Route C: git clone
|
||||
|
||||
For contributing, or for running unreleased code.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Ark0N/Codeman.git
|
||||
cd Codeman
|
||||
npm install # postinstall builds the vendored xterm addon bundles
|
||||
npm run dev # dev server on http://localhost:3000
|
||||
```
|
||||
|
||||
For a production run from a clone:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm run start
|
||||
```
|
||||
|
||||
`npm run dev` runs TypeScript directly through `tsx` with no build step. The frontend is
|
||||
plain JavaScript served from `src/web/public/` with no bundler, so editing a `.js` or `.css`
|
||||
file and reloading the page is enough. The one exception is `index.html`, which is read once
|
||||
at server start, so markup changes need a restart.
|
||||
|
||||
See [Contributing](Contributing) for the rest of the development loop.
|
||||
|
||||
## Installing an agent CLI
|
||||
|
||||
Codeman drives CLIs, it does not bundle them. Install at least one:
|
||||
|
||||
| CLI | Install | Notes |
|
||||
| --------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
||||
| **Claude Code** | `npm i -g @anthropic-ai/claude-code` | The primary target. Some Codeman features are Claude-only: see [Agent CLIs](Agent-CLIs). |
|
||||
| **OpenCode** | See [opencode.ai](https://opencode.ai) | |
|
||||
| **Codex** | See [developers.openai.com/codex/cli](https://developers.openai.com/codex/cli) | |
|
||||
| **Antigravity** | See [antigravity.google](https://antigravity.google) | Google's successor to the consumer Gemini CLI. |
|
||||
| **Gemini CLI** | See [github.com/google-gemini/gemini-cli](https://github.com/google-gemini/gemini-cli) | Enterprise only since Google's June 2026 consumer cutover. |
|
||||
| **Pi** | See [pi.dev](https://pi.dev) | No permission prompts and no sandbox by design. Read [Agent CLIs](Agent-CLIs) before using it on a repo you care about. |
|
||||
|
||||
Log each CLI in once, by hand, before pointing Codeman at it. Codeman never collects or
|
||||
stores your CLI credentials.
|
||||
|
||||
## Verify the install
|
||||
|
||||
```bash
|
||||
codeman doctor # checks Node, tmux, the agent CLIs, document converters
|
||||
codeman --version
|
||||
codeman web # then open http://localhost:3000
|
||||
```
|
||||
|
||||
`codeman doctor --json` gives machine-readable output, and `--category core` narrows it to
|
||||
the things a session cannot start without.
|
||||
|
||||
If the dashboard loads and **+ New Session** opens, you are done. Continue to
|
||||
[Quick Start](Quick-Start).
|
||||
|
||||
## Where things live
|
||||
|
||||
| Path | What |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| `~/.codeman/app` | The installed code (installer route only). |
|
||||
| `~/.codeman/` | All state: `state.json`, settings, session history, push keys, TLS certs. See [Core Concepts](Core-Concepts). |
|
||||
| `~/codeman-cases/` | Cases created from scratch. Linked cases stay wherever they already are. |
|
||||
| `~/.codeman/web.log` | Log for a detached (`-d`) server. |
|
||||
|
||||
Everything is under your home directory, and nothing needs root.
|
||||
|
||||
## Keeping it running
|
||||
|
||||
A bare `codeman web` dies with the shell that started it. Two ways to outlive that:
|
||||
|
||||
```bash
|
||||
codeman web -d # detached; --status and --stop manage it
|
||||
codeman service install # systemd user unit or macOS LaunchAgent; survives reboots
|
||||
```
|
||||
|
||||
Full detail, including logs and the self-updater, is in
|
||||
[Running As A Service](Running-As-A-Service).
|
||||
|
||||
## Updating
|
||||
|
||||
| Install route | How to update |
|
||||
| ------------- | ----------------------------------------------------------------- |
|
||||
| Installer | Re-run the one-liner, or **App Settings → System → Updates** in the UI. |
|
||||
| npm | `npm update -g aicodeman` |
|
||||
| git clone | `git pull && npm install && npm run build`, then restart. |
|
||||
|
||||
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
|
||||
browser polls across the restart. Progress appears in the UI.
|
||||
|
||||
## Uninstalling
|
||||
|
||||
```bash
|
||||
install.sh uninstall # installer route
|
||||
npm uninstall -g aicodeman # npm route
|
||||
```
|
||||
|
||||
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
|
||||
point at directories you already had, but cases created from scratch have their only copy
|
||||
there.
|
||||
|
||||
Running tmux sessions are not killed by an uninstall. `tmux -L codeman kill-server` ends
|
||||
them.
|
||||
|
||||
## Windows (WSL)
|
||||
|
||||
```powershell
|
||||
wsl bash -c "curl -fsSL https://getcodeman.com/install | bash"
|
||||
```
|
||||
|
||||
Codeman requires tmux, so Windows runs it inside
|
||||
[WSL2](https://learn.microsoft.com/en-us/windows/wsl/install). If you do not have WSL yet:
|
||||
run `wsl --install` in an admin PowerShell, reboot, open Ubuntu, and install your agent CLI
|
||||
*inside* WSL. `http://localhost:3000` then works from your Windows browser.
|
||||
|
||||
Work inside the Linux filesystem (`~/project`), not `/mnt/c/...`. Filesystem watching and
|
||||
git are both dramatically slower across the Windows mount, and agents notice.
|
||||
|
||||
## macOS notes
|
||||
|
||||
**`Error: posix_spawnp failed.` on every session start.** node-pty publishes its macOS
|
||||
`spawn-helper` without the executable bit, and macOS launches every PTY through it. Codeman
|
||||
detects this and repairs it automatically on the first failure. If you hit it on a clone
|
||||
install and want to fix it by hand:
|
||||
|
||||
```bash
|
||||
npm run fix:node-pty
|
||||
```
|
||||
|
||||
This is a `chmod`, not a rebuild. Look in `prebuilds/darwin-<arch>/`, not
|
||||
`build/Release/`, which does not exist on macOS. Linux cannot reproduce this.
|
||||
|
||||
**launchd and PATH.** A LaunchAgent gets `/usr/bin:/bin:/usr/sbin:/sbin`, which finds
|
||||
neither a Homebrew or nvm `node` nor `tmux` or `claude`. `codeman service install` bakes
|
||||
your current PATH into the unit for exactly this reason, so prefer it over a hand-written
|
||||
plist.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **`tmux: command not found` after a successful install.** The installer asks before
|
||||
installing packages, and a declined prompt is a valid answer it remembers. Install tmux
|
||||
and re-run.
|
||||
- **Port 3000 in use.** `codeman web --port 8080`, or set `CODEMAN_PORT`.
|
||||
- **Two Codemans on one machine.** The data directory and the tmux socket are both process
|
||||
wide, so a second instance discovers and attaches the first one's live sessions. Give each
|
||||
a distinct `CODEMAN_INSTANCE` before starting a second. See [Core Concepts](Core-Concepts).
|
||||
- **The dashboard is not reachable from your phone.** That is the default, not a fault. The
|
||||
server binds `127.0.0.1`. See [Remote Access](Remote-Access).
|
||||
|
||||
## Read next
|
||||
|
||||
- [Quick Start](Quick-Start) - your first working session.
|
||||
- [Agent CLIs](Agent-CLIs) - picking and setting up a run mode.
|
||||
- [Remote Access](Remote-Access) - reaching it from another device.
|
||||
- [Troubleshooting](Troubleshooting) - when the above did not go as written.
|
||||
@@ -0,0 +1,159 @@
|
||||
# Keeping Agents Running
|
||||
|
||||
Codeman exists for the hours you are not at the keyboard. This page covers how it notices an
|
||||
agent has stopped, what it does about it, and how to run a session overnight without
|
||||
babysitting it.
|
||||
|
||||
Everything here is **per session and off by default**. A session you never configure just
|
||||
sits there when it finishes, which is usually what you want.
|
||||
|
||||
## How Codeman knows an agent is idle
|
||||
|
||||
Harder than it sounds, and worth understanding, because it is what every other feature here
|
||||
is built on.
|
||||
|
||||
**For Claude sessions**, the naive signal does not work. Claude redraws its prompt marker
|
||||
roughly once a second all the way through a turn, so "saw a prompt, waited two seconds,
|
||||
called it idle" flipped working sessions to idle a couple of seconds into every turn. Its
|
||||
real working indicator is an animated line whose glyph and wording both change, and terminal
|
||||
repaints arrive in partial fragments, so matching it in the output stream does not work
|
||||
either.
|
||||
|
||||
So Codeman waits for the pane to go quiet, then **asks the screen** what is on it before
|
||||
believing the session is idle. Turn-start detection works the same way in reverse: a
|
||||
sustained run of repaints marks a turn as started, with the same screen check vetoing mere
|
||||
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 every other CLI**, there are no hooks to lean on, so detection 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.
|
||||
|
||||
## The Respawn Controller
|
||||
|
||||
Respawn keeps a session working past the point where the agent would otherwise stop. When
|
||||
the session goes idle, Codeman runs a cycle and starts it again.
|
||||
|
||||
A cycle is up to four steps, each optional:
|
||||
|
||||
1. **Update prompt.** Ask the agent to write down where it got to, so the next round can pick
|
||||
it up.
|
||||
2. **`/clear`.** Reset the context window.
|
||||
3. **`/init`.** Re-read the project's `CLAUDE.md`.
|
||||
4. **Kickstart prompt.** Tell it to continue.
|
||||
|
||||
Steps 2 and 3 are what make long runs possible: without a context reset, a multi-hour
|
||||
session eventually spends its whole window on its own history.
|
||||
|
||||
Configure it in **Session Options → Respawn**, then press **Enable**. It repeats until the
|
||||
duration you set runs out.
|
||||
|
||||
| Setting | What it controls |
|
||||
| ---------------------- | ----------------------------------------------------------------------- |
|
||||
| **Idle timeout** | How long the session must be quiet before a cycle starts. |
|
||||
| **Duration** | How long the whole arrangement stays armed. |
|
||||
| **Inter-step delay** | Pause between the steps above, so a step is not sent into a busy pane. |
|
||||
| **`/clear` + `/init`** | Whether the context reset happens at all. |
|
||||
| **Update prompt** | What the agent is asked to record before the reset. |
|
||||
| **Kickstart prompt** | What starts the next round. |
|
||||
| **Auto-accept prompts**| Answer routine confirmation dialogs automatically. |
|
||||
|
||||
### Presets
|
||||
|
||||
Five built-ins, and the numbers matter more than the names. The idle timeout is the main
|
||||
difference: a lead session coordinating subagents is legitimately silent for a minute at a
|
||||
time, and a three second timeout would interrupt it constantly.
|
||||
|
||||
| Preset | Idle timeout | Duration | Built for |
|
||||
| -------------- | ------------ | -------- | --------------------------------------------------------------- |
|
||||
| **Solo** | 3s | 60 min | One agent working alone, fast cycles with a context reset. |
|
||||
| **Subagents** | 45s | 240 min | A lead session running Task subagents; tolerates their silences. |
|
||||
| **Team** | 90s | 480 min | Leading an agent team; tolerates long silences. |
|
||||
| **Ralph/Todo** | 8s | 480 min | Working through a task list with progress tracking. |
|
||||
| **Overnight** | 10s | 480 min | Unattended overnight runs with a full reset between cycles. |
|
||||
|
||||
Start from the preset that matches your shape of work and adjust the idle timeout first.
|
||||
Presets you build yourself can be saved alongside these.
|
||||
|
||||
### What it costs
|
||||
|
||||
Every cycle is real tokens: the update prompt, the reset, and the kickstart, plus whatever
|
||||
work follows. An overnight run is a deliberate spend, not a background nicety. The duration
|
||||
setting is the ceiling, and it is worth setting honestly.
|
||||
|
||||
## Auto-resume when a usage limit resets
|
||||
|
||||
**Claude only.** At the top of the Respawn tab.
|
||||
|
||||
When Claude halts on a subscription limit, the message names the time the limit resets.
|
||||
Codeman parses it, arms a timer for two minutes after that, then sends Escape followed by
|
||||
`continue`.
|
||||
|
||||
The important part is what it does **not** do: respawn cycles are blocked while a session is
|
||||
limit-paused. Without that, the next cycle would fire `/clear` and wipe the conversation you
|
||||
are waiting to resume. This is the single most useful setting for overnight runs on a
|
||||
subscription plan.
|
||||
|
||||
## The plan usage chip
|
||||
|
||||
**Claude only.** A header chip showing live subscription usage, on by default on desktop and
|
||||
off on phones.
|
||||
|
||||
It works by installing a status line exporter into Claude Code, which posts Claude's own
|
||||
rate limit data back to Codeman. The exporter is marker-identified, so it only ever touches
|
||||
a status line Codeman installed, never one you wrote yourself, and it prints your footer
|
||||
through so the in-terminal status line still works.
|
||||
|
||||
The chip and the exporter are the same setting. Turning the chip on without the exporter
|
||||
would leave it showing a dash forever, so resolve it in one place: **App Settings**.
|
||||
|
||||
## Circuit breakers
|
||||
|
||||
Two, and they are unrelated:
|
||||
|
||||
- **The Ralph breaker** stops respawn thrashing. It moves from closed to half-open to open,
|
||||
and is reset from the session's Ralph controls.
|
||||
- **The PTY-exit breaker** trips when a session's process exits repeatedly and quickly, and
|
||||
blocks automatic restarts so a broken configuration cannot spin forever.
|
||||
|
||||
The PTY-exit breaker resets **only** on an explicit clear. Reattaching to the session does
|
||||
not clear it, deliberately, so a UI reconnect cannot paper over a session that is genuinely
|
||||
failing to start.
|
||||
|
||||
## A working overnight setup
|
||||
|
||||
1. Start a Claude session in the case you want worked on.
|
||||
2. Give it a clear goal and let it start. Respawn continues work, it does not invent it.
|
||||
3. **Session Options → Respawn → Overnight preset.**
|
||||
4. Turn on **auto-resume on usage limit**.
|
||||
5. Set the duration to how long you actually want it running.
|
||||
6. Press **Enable**.
|
||||
7. Optionally turn on push notifications so a blocking question reaches your phone: see
|
||||
[Notifications And Approvals](Notifications-And-Approvals).
|
||||
|
||||
In the morning, the **Away Digest** summarizes what happened while you were gone, and the
|
||||
run summary and lifecycle log carry the detail.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Respawn without a context reset stalls eventually.** The window fills with history and
|
||||
the agent gets less useful every cycle.
|
||||
- **An idle timeout that is too short interrupts real work.** If the agent runs long tool
|
||||
calls or coordinates subagents, raise it. That is what the Subagents and Team presets are.
|
||||
- **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.
|
||||
- **Do not run respawn on a session you are actively typing in.** It will send prompts
|
||||
underneath you.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Autonomous Loops](Autonomous-Loops) - Ralph and the orchestrator, for structured
|
||||
autonomous work rather than "keep going".
|
||||
- [Cron Jobs](Cron-Jobs) - starting work on a schedule instead of continuing it.
|
||||
- [Notifications And Approvals](Notifications-And-Approvals) - being told when it needs you.
|
||||
- [`docs/respawn-state-machine.md`](https://github.com/Ark0N/Codeman/blob/master/docs/respawn-state-machine.md) - the state machine itself.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Keyboard Shortcuts
|
||||
|
||||
Every binding, and how to change them. `Ctrl` also accepts `Cmd` on macOS.
|
||||
|
||||
Press `Ctrl+?` in the app for the same list in a floating overlay.
|
||||
|
||||
## Sessions and tabs
|
||||
|
||||
| Shortcut | Action |
|
||||
| ------------------------------- | --------------------------------------------------------------- |
|
||||
| `Ctrl+K` (also `Cmd+K`, `Alt+K`)| Find an open session or start a new one. |
|
||||
| `Ctrl+W` | Kill the active session. |
|
||||
| `Ctrl+Tab` | Next session. |
|
||||
| `Alt+[` / `Alt+]` | Previous / next tab. |
|
||||
| `Alt+1` to `Alt+9` | Switch to tab N. Physical keys, so macOS Option layouts work. |
|
||||
| `Ctrl+Shift+{` / `Ctrl+Shift+}` | Move the active tab left / right. |
|
||||
| `Alt+B` | Collapse / expand the session sidebar, when that layout is on. |
|
||||
|
||||
## Terminal
|
||||
|
||||
| Shortcut | Action |
|
||||
| ----------------------- | --------------------------------------------------------------- |
|
||||
| `Enter` | Send. |
|
||||
| `Shift+Enter` | Insert a newline without sending. |
|
||||
| `Ctrl+Enter` | Same. |
|
||||
| `Ctrl+C` | Copy the selection, or interrupt when nothing is selected. |
|
||||
| `Ctrl+Shift+C` | Copy the selection. Never interrupts. |
|
||||
| `Ctrl+L` | Clear the terminal. |
|
||||
| `Ctrl+Shift+R` | Restore terminal size. |
|
||||
| `Ctrl` `+` / `Ctrl` `-` | Font size. |
|
||||
| `Shift+Wheel` | Scroll the local buffer, even where the wheel is forwarded to the CLI. |
|
||||
|
||||
## Everything else
|
||||
|
||||
| Shortcut | Action |
|
||||
| -------------- | ------------------------------- |
|
||||
| `Ctrl+Shift+V` | Toggle voice input. |
|
||||
| `Ctrl+?` | Shortcut reference overlay. |
|
||||
| `Escape` | Close panels and modals. |
|
||||
|
||||
## Rebinding
|
||||
|
||||
**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.
|
||||
|
||||
Two things are deliberately not rebindable:
|
||||
|
||||
- **`Ctrl+C` smart copy.** The generic dispatch loop calls `preventDefault()` on every
|
||||
shortcut it handles, and doing that to `Ctrl+C` would swallow the interrupt when nothing
|
||||
is selected. It is handled separately for that reason.
|
||||
- **`Escape`**, which closes whatever is open.
|
||||
|
||||
## Why some chords behave oddly
|
||||
|
||||
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.
|
||||
|
||||
`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.
|
||||
|
||||
## On phones
|
||||
|
||||
There is no physical keyboard, so the equivalents live in the keyboard accessory bar: `Esc`,
|
||||
`Ctrl` as a one-shot modifier, `Tab`, arrows, and quick actions. See
|
||||
[Mobile Guide](Mobile-Guide).
|
||||
|
||||
## Read next
|
||||
|
||||
- [The Dashboard](The-Dashboard) - what the shortcuts are navigating.
|
||||
- [Settings Reference](Settings-Reference) - where the overrides are stored.
|
||||
@@ -0,0 +1,145 @@
|
||||
# Mobile Guide
|
||||
|
||||
Codeman on a phone is not a shrunken desktop UI. It is the surface most of its design
|
||||
attention has gone into, because checking on an agent from a bus is the thing this software
|
||||
is for.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/Ark0N/Codeman/master/docs/screenshots/mobile-session-keyboard-20260727.png" alt="Answering an agent prompt on a phone" width="300">
|
||||
</p>
|
||||
|
||||
## Getting there
|
||||
|
||||
1. **Set up access.** Tailscale is the recommended route and gives you real HTTPS. See
|
||||
[Remote Access](Remote-Access).
|
||||
2. **Log in by QR.** Open the dashboard on your desktop and scan the code. No password
|
||||
typing. Tokens are single use and rotate every 60 seconds.
|
||||
3. **Install it to your home screen.** On iOS this is mandatory for push notifications;
|
||||
Safari does not deliver push to tabs. On Android it makes the app full screen.
|
||||
|
||||
HTTPS matters for more than security here: microphone access and push notifications both
|
||||
require a secure context.
|
||||
|
||||
## The layout
|
||||
|
||||
| Element | Where |
|
||||
| -------------------- | --------------------------------------------------------------------- |
|
||||
| Header | Fixed at the top, deliberately minimal. Desktop-only controls never appear. |
|
||||
| Tab strip | Scrolls horizontally. The active tab is always scrolled into view. |
|
||||
| Terminal | The rest of the screen. |
|
||||
| Toolbar | Bottom: Run, Stop, **Enter**, case picker, voice, settings. |
|
||||
| Keyboard bar | Above the on-screen keyboard when it is open. |
|
||||
|
||||
Layout respects notch and home-indicator safe areas, touch targets are 44px, and the case
|
||||
picker is a bottom sheet rather than a dropdown.
|
||||
|
||||
**Swipe left and right** on the terminal to switch sessions.
|
||||
|
||||
## The home screen
|
||||
|
||||
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.
|
||||
2. **CURRENT SESSIONS** with live status.
|
||||
3. **PAST SESSIONS**, resumable.
|
||||
|
||||
Row status uses the same language as the tabs: green when fine, pulsing while working,
|
||||
yellow when waiting for input, red when a question is pending.
|
||||
|
||||
The split Run button carries the same per-backend colours as the desktop toolbar, and its
|
||||
picker mirrors the desktop run-mode menu.
|
||||
|
||||
On by default; it can be turned off in settings.
|
||||
|
||||
## The keyboard accessory bar
|
||||
|
||||
A row of keys above the virtual keyboard, and what it contains depends on the session.
|
||||
|
||||
**Agent sessions** get quick actions: `/init`, `/clear`, `/compact`, a clipboard key, `Esc`,
|
||||
a path picker, an image key, and 🧠 when Read My Mind is on. Destructive commands need a
|
||||
double press, so you cannot fire `/clear` with a stray thumb.
|
||||
|
||||
**Shell sessions** automatically swap it for terminal controls: `Ctrl`, `Esc`, `Tab`, four
|
||||
arrows, paste, and dismiss. Your normal preference is remembered and restored when you
|
||||
switch back to an agent session, so a settings change during a shell session cannot strip
|
||||
the bar away permanently.
|
||||
|
||||
### One-shot Ctrl
|
||||
|
||||
`Ctrl` on the shell bar is a **one-shot modifier**: tap `Ctrl`, then tap `c`, and the
|
||||
control byte is sent. It disarms on use, on a second tap, on any other accessory key, on a
|
||||
session switch, and when the keyboard closes.
|
||||
|
||||
That list matters. A modifier left armed turns your next innocent keystroke into a control
|
||||
byte, so it is deliberately eager to disarm. Keys with no control equivalent pass through
|
||||
unchanged, exactly like a hardware keyboard.
|
||||
|
||||
## The Enter button
|
||||
|
||||
The toolbar's dedicated **Enter** button exists because of local echo. On a phone, the
|
||||
characters you type are painted locally and have not reached the agent yet; Enter flushes
|
||||
them and then submits.
|
||||
|
||||
It replays the keypress through the terminal rather than sending a bare carriage return.
|
||||
Sending a bare `\r` would submit an empty line and strand your typed text on screen, which
|
||||
looks exactly like a dead button.
|
||||
|
||||
On phones this button replaces the desktop's **Run Shell** control; starting a shell moved
|
||||
into the Run dropdown.
|
||||
|
||||
## Scrolling and the keyboard
|
||||
|
||||
- The terminal and toolbar shift up when the keyboard opens, tracked through the browser's
|
||||
visual viewport rather than guessed.
|
||||
- **Two ways to dismiss the keyboard**: tap outside the terminal on inert space, or tap twice
|
||||
on inert terminal content. Tapping a control never dismisses it, and tapping the prompt row
|
||||
keeps focus so you can place the caret.
|
||||
- A scroll is never mistaken for a tap: travel is measured from the start of the gesture, and
|
||||
multi-touch never counts.
|
||||
|
||||
## Voice
|
||||
|
||||
The microphone button, or the keyboard bar. Providers and setup are covered in
|
||||
[Input And Voice](Input-And-Voice). Dictating is often faster than typing a prompt on a
|
||||
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.
|
||||
|
||||
Setup in [Notifications And Approvals](Notifications-And-Approvals).
|
||||
|
||||
## Reading long answers
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
## What is deliberately not on phones
|
||||
|
||||
- Extra header buttons. New header controls are kept off phones by policy, with a test that
|
||||
enforces it.
|
||||
- The Approvals bell. Phones get the NEEDS YOU strips on the home screen instead.
|
||||
- The desktop home tab rail, which needs a wide window.
|
||||
- Lineage arcs, which are a desktop overlay.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Typed text sitting on screen has not been sent.** Press Enter.
|
||||
- **iOS needs the home screen install for push**, not just a bookmark.
|
||||
- **iOS Safari can serve stale JavaScript after an update** until the tab is fully closed.
|
||||
Close it and reopen.
|
||||
- **Plain HTTP over a LAN address disables voice and push.** Use HTTPS.
|
||||
- **An armed `Ctrl` is visibly highlighted.** If it looks the same as a resting key, you are
|
||||
on an old version, on a light skin.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Remote Access](Remote-Access) - getting the phone connected in the first place.
|
||||
- [Notifications And Approvals](Notifications-And-Approvals) - being told when you are needed.
|
||||
- [Input And Voice](Input-And-Voice) - local echo, dictation, and the input rules.
|
||||
@@ -0,0 +1,97 @@
|
||||
# Multi-User Mode
|
||||
|
||||
Share one Codeman with a small trusted team. Each person gets their own login and workspace,
|
||||
and sessions, cases, search, and live events are scoped to their owner.
|
||||
|
||||
**Off by default.** Without the flag, behaviour is identical to single-user Codeman, because
|
||||
every scoping check short-circuits.
|
||||
|
||||
## Read this before enabling it
|
||||
|
||||
**Multi-user mode separates workspaces. It does not sandbox users from each other.**
|
||||
|
||||
Every session still runs as the **same operating system account**. A determined user's agent
|
||||
can reach another user's files, because at the OS level they are the same user. This is a
|
||||
convenience and organization feature, not a security boundary.
|
||||
|
||||
If you need real isolation:
|
||||
|
||||
- Pair each user with [Docker Cases](Docker-Cases), which gives their work its own
|
||||
filesystem and network.
|
||||
- Or run separate Codeman instances under separate OS accounts, each with its own
|
||||
`CODEMAN_INSTANCE`.
|
||||
|
||||
"Small trusted team" is the honest description of who this is for.
|
||||
|
||||
## Enabling it
|
||||
|
||||
```bash
|
||||
codeman users add alice --admin # create the first admin, prompts for a password
|
||||
codeman web --multiuser # or CODEMAN_MULTIUSER=1
|
||||
```
|
||||
|
||||
Then manage users from the CLI or the **Users** entry in App Settings:
|
||||
|
||||
```bash
|
||||
codeman users add bob # a regular user
|
||||
codeman users list
|
||||
codeman users passwd bob # reset to a one-time password
|
||||
codeman users rm bob
|
||||
```
|
||||
|
||||
`--password-stdin` reads the password from standard input, for scripts.
|
||||
|
||||
Accounts live in `~/.codeman/users.json` with scrypt-hashed passwords, mode 0600.
|
||||
Administrative actions are audited to `~/.codeman/admin-audit.jsonl`.
|
||||
|
||||
## What each user gets
|
||||
|
||||
| Thing | Scope |
|
||||
| ------------------- | ---------------------------------------------------------------------------- |
|
||||
| **Case space** | `~/codeman-users/<name>/cases`, their own. |
|
||||
| **Sessions** | Only theirs are listed, reachable, or controllable. |
|
||||
| **Events** | Live event routing is per owner, and fails closed. |
|
||||
| **Search** | Scoped on read, including historical results. |
|
||||
| **File previews** | Scoped to sessions they own. |
|
||||
| **Path picker** | Only their own user space as a root, not the whole home directory. |
|
||||
|
||||
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.
|
||||
|
||||
## Safer defaults for regular users
|
||||
|
||||
Non-admins get tighter defaults, and lifting them is an explicit per-user grant:
|
||||
|
||||
| Default | Meaning |
|
||||
| ---------------------------------- | ------------------------------------------------------------------------ |
|
||||
| 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. |
|
||||
| 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. |
|
||||
|
||||
These exist because the OS boundary is shared. They narrow what a normal account can do
|
||||
casually; they do not make the account a sandbox.
|
||||
|
||||
## Accounts and sessions
|
||||
|
||||
Each user authenticates with their own name and password rather than the shared
|
||||
`CODEMAN_PASSWORD`. Logins are individually revocable: disable, reset, or delete an account
|
||||
at any time, and existing browser sessions can be revoked.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Enabling it does not migrate existing cases** into a user space. They stay where they
|
||||
are, owned by whoever the ownership rules resolve them to.
|
||||
- **Admins see everything**, including other users' sessions. Choose admins accordingly.
|
||||
- **The audit log is append-only and local.** Ship it somewhere if you care about it.
|
||||
- **It is not a substitute for OS accounts.** Restating this because it is the one thing
|
||||
people get wrong.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Security](Security) - where this fits in the model, and what it does not cover.
|
||||
- [Docker Cases](Docker-Cases) - the isolation story that actually isolates.
|
||||
- [`docs/multi-user-plan.md`](https://github.com/Ark0N/Codeman/blob/master/docs/multi-user-plan.md) - the design.
|
||||
@@ -0,0 +1,147 @@
|
||||
# Notifications and Approvals
|
||||
|
||||
An agent that stops to ask a question, with nobody watching, is a run that quietly wasted an
|
||||
hour. This page covers every way Codeman tells you it needs you, and how to answer without
|
||||
opening the session.
|
||||
|
||||
## The signals, cheapest first
|
||||
|
||||
| Surface | Reaches you | Default |
|
||||
| ---------------------- | ------------------------------------------------- | ------- |
|
||||
| Tab alert | While the dashboard is open | On |
|
||||
| Browser title flash | Another tab in the same browser | On |
|
||||
| Desktop notification | Another window on the same machine | Opt-in |
|
||||
| Push notification | Anywhere, even with no tab open | Opt-in |
|
||||
| Approvals Inbox | One queue across every session | Opt-in |
|
||||
| Phone overview | Phone home screen, NEEDS YOU section | On |
|
||||
| Away Digest | Afterwards, as a summary | Opt-in |
|
||||
|
||||
## Tab alerts
|
||||
|
||||
The tab itself changes state:
|
||||
|
||||
| State | Meaning |
|
||||
| -------------------- | ---------------------------------------------------------- |
|
||||
| Yellow, blinking | The agent is waiting for input from you. |
|
||||
| Red, blinking | A question or permission prompt is blocking the session. |
|
||||
|
||||
These are a steady colour with a pulse layered on top, not a blink to transparent, so a tab
|
||||
needing attention looks that way at every point in the cycle.
|
||||
|
||||
They survive a reload. The alert state is re-seeded from the server on page load, so
|
||||
reloading the dashboard while a permission dialog is blocking a session does not leave you
|
||||
with a normal-looking tab.
|
||||
|
||||
For Claude sessions, these come from Claude Code's hooks and are precise about *why* the
|
||||
session stopped. For other CLIs there are no hooks, so you get the coarser output-based
|
||||
signal.
|
||||
|
||||
## Window title and OS notifications
|
||||
|
||||
The browser tab title is prefixed `codeman:<host>`, so several Codeman instances across
|
||||
several machines stay distinguishable at a glance. Override the hostname with
|
||||
`codeman web --title-hostname <name>`.
|
||||
|
||||
Desktop notifications use the same prefix. Enable them in **App Settings → Notifications**.
|
||||
|
||||
## Push notifications
|
||||
|
||||
Push reaches your phone with **no Codeman tab open at all**, which is the only option that
|
||||
works while you are actually away.
|
||||
|
||||
Setup:
|
||||
|
||||
1. Open Codeman over **HTTPS**. Web push requires a secure context. Tailscale gives you real
|
||||
HTTPS; `--https` gives you a self-signed certificate; plain HTTP over a LAN address will
|
||||
not work.
|
||||
2. **App Settings → Notifications → Subscribe**, and accept the browser prompt.
|
||||
3. On **iOS**, add Codeman to your home screen first. Safari only delivers web push to
|
||||
installed web apps, not to tabs.
|
||||
|
||||
Once subscribed, a blocking prompt reaches your phone even from a locked screen.
|
||||
|
||||
## The Approvals Inbox
|
||||
|
||||
**Opt-in, off by default. Claude sessions only.**
|
||||
|
||||
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.
|
||||
|
||||
Turn it on in **App Settings**. Surfaces:
|
||||
|
||||
- **A header bell** with a count, hidden entirely while the count is zero. Never shown on
|
||||
phones.
|
||||
- **A drawer** listing each waiting card.
|
||||
- **NEEDS YOU strips** at the top of the phone overview home screen.
|
||||
|
||||
Each card shows the session, the case, and the captured prompt with its options. Answering
|
||||
sends the keystroke into the session for you: a digit for a menu choice, Escape to decline,
|
||||
or free text for an idle prompt.
|
||||
|
||||
Behaviour worth knowing:
|
||||
|
||||
- **One item per session.** A newer prompt supersedes the older one, because the older one
|
||||
is no longer on screen.
|
||||
- **Menu answers are validated against the live screen.** Codeman re-captures the pane before
|
||||
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.
|
||||
- **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 off, the buttons are stripped from the notification payload entirely rather
|
||||
than being shown and failing.
|
||||
|
||||
## The phone overview
|
||||
|
||||
On phones, tapping the "C" logo gives a session overview with **NEEDS YOU** first, then
|
||||
current sessions, then past ones. Rows use the same language as the tab strip: a green dot
|
||||
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.
|
||||
|
||||
## The Away Digest
|
||||
|
||||
Retrospective rather than live: what happened while you were gone, aggregated from the
|
||||
lifecycle log, run summaries, live sessions, token statistics, and recent subagents.
|
||||
|
||||
It is the morning-after view for an overnight run. Enable its header button in
|
||||
**App Settings → Header & Panels**.
|
||||
|
||||
## Recommended setup for unattended runs
|
||||
|
||||
1. HTTPS access, ideally Tailscale. See [Remote Access](Remote-Access).
|
||||
2. Push notifications subscribed, with Codeman installed to the home screen on iOS.
|
||||
3. Approvals Inbox on.
|
||||
4. Auto-resume on usage limit on, for each session you leave running. See
|
||||
[Keeping Agents Running](Keeping-Agents-Running).
|
||||
|
||||
That combination means a blocking question wakes your phone and can be answered in two taps
|
||||
from the lock screen.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **No push over plain HTTP.** It is a browser requirement, not a Codeman one.
|
||||
- **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 are Claude-only.** They are built on hook events the other CLIs do not emit.
|
||||
- **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.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Keeping Agents Running](Keeping-Agents-Running) - what to configure before walking away.
|
||||
- [Mobile Guide](Mobile-Guide) - the phone surfaces in full.
|
||||
- [Settings Reference](Settings-Reference) - where each of these toggles lives.
|
||||
@@ -0,0 +1,153 @@
|
||||
# Quick Start
|
||||
|
||||
From an installed Codeman to a working agent, in about five minutes. If you have not
|
||||
installed yet, start at [Installation](Installation).
|
||||
|
||||
## 1. Start the server
|
||||
|
||||
```bash
|
||||
codeman web
|
||||
```
|
||||
|
||||
It prints a URL, `http://localhost:3000` by default. Open it.
|
||||
|
||||
The server binds `127.0.0.1` only, so this URL works from the machine running it and
|
||||
nowhere else. That is deliberate: Codeman starts agents with permission prompts skipped by
|
||||
default, so anyone who can reach the dashboard can run code on this machine. Reaching it
|
||||
from your phone is a separate, deliberate step covered in [Remote Access](Remote-Access).
|
||||
|
||||
To keep it alive after you close the terminal, use `codeman web -d` instead, or install it
|
||||
as a service. See [Running As A Service](Running-As-A-Service).
|
||||
|
||||
## 2. Meet the welcome screen
|
||||
|
||||
With no sessions running you get the welcome screen:
|
||||
|
||||
- **Run buttons** for each agent CLI Codeman found on your PATH. If you expected one and it
|
||||
is missing, its binary is not visible to the server; see [Agent CLIs](Agent-CLIs).
|
||||
- **A QR code**, if a password is set. Scanning it logs a phone in without typing anything.
|
||||
- **Resume Conversation**, a list of past sessions, including Claude conversations started
|
||||
outside Codeman. Empty on a fresh install.
|
||||
- **Search**, across sessions, events, and files.
|
||||
|
||||
You can click a Run button right now and get a working agent in your current case. The rest
|
||||
of this page is the deliberate version.
|
||||
|
||||
## 3. Pick or create a case
|
||||
|
||||
A **case** is a named working directory that Codeman remembers. Every session runs inside
|
||||
one. The case picker is in the bottom toolbar.
|
||||
|
||||
To make a new one, click **+** next to the picker. The Add Case dialog has three tabs:
|
||||
|
||||
| Tab | Use it when |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Create New** | Starting a fresh project. Creates `~/codeman-cases/<name>` and scaffolds a `CLAUDE.md` into it. |
|
||||
| **Clone Repo** | Working on an existing public repo. Paste the URL; Codeman preflights it as you type, offers the repo's real branches and tags, and fills in the case name. |
|
||||
| **Link Existing** | The code is already on disk. Point at the folder, with **Browse** if you would rather click than type. |
|
||||
|
||||
The gear next to the picker holds two per-case toggles: **Agent Teams** and
|
||||
**1M Opus Context**. Both are off by default and both are safe to ignore for now.
|
||||
|
||||
**Create New** also has a checkbox for running the case inside a Docker container, and a
|
||||
**Remote** panel for running it over SSH on another machine. Those are
|
||||
[Docker Cases](Docker-Cases) and [Remote SSH Sessions](Remote-SSH-Sessions); skip them for
|
||||
your first session.
|
||||
|
||||
## 4. Pick a run mode and hit Run
|
||||
|
||||
The **Run** button starts an agent in the selected case. The arrow next to it picks which
|
||||
one:
|
||||
|
||||
| Mode | What starts |
|
||||
| -------------------- | -------------------------------------------------------------- |
|
||||
| **Claude Code** | The default, and the mode every Codeman feature supports. |
|
||||
| **OpenCode** | |
|
||||
| **Codex** | OpenAI's CLI. |
|
||||
| **Gemini** | Enterprise only since Google's consumer cutover. |
|
||||
| **Antigravity** | Google's successor to the consumer Gemini CLI. |
|
||||
| **Pi** | No permission prompts and no sandbox by design. |
|
||||
| **Terminal / Shell** | A plain shell, no agent. Also the **Run Shell** button. |
|
||||
|
||||
The dropdown also lists any saved dashboard URLs ([Web Tabs](Web-Tabs)) and your recent
|
||||
sessions. Those do not change the run mode: Run always means "start an agent".
|
||||
|
||||
Click **Run**. A tab appears, and Codeman spawns the CLI on a real PTY inside a tmux
|
||||
session and streams it to your browser.
|
||||
|
||||
The number spinner beside the button starts several sessions at once, up to 20. Useful for
|
||||
fanning the same case out across parallel workers; unnecessary for a first run.
|
||||
|
||||
## 5. Talk to the agent
|
||||
|
||||
Click into the terminal and type. It is a real terminal (xterm.js over a real PTY), so full
|
||||
TUIs render properly and everything the CLI supports works, slash commands included.
|
||||
|
||||
| Key | Effect |
|
||||
| ---------------------------- | --------------------------------------------- |
|
||||
| `Enter` | Send. |
|
||||
| `Shift+Enter` / `Ctrl+Enter` | Newline without sending. |
|
||||
| `Ctrl+C` | Copy if text is selected, otherwise interrupt. |
|
||||
| `Ctrl+Shift+V` | Voice input. |
|
||||
|
||||
You can also paste or drag an image straight into the session, and register external files
|
||||
as attachments. See [Working With Files](Working-With-Files) and
|
||||
[Input And Voice](Input-And-Voice).
|
||||
|
||||
Input is delivered **exactly once**, even if your connection drops mid-prompt. A dropped
|
||||
link never loses a prompt and never sends it twice.
|
||||
|
||||
## 6. Read the tab
|
||||
|
||||
The tab tells you what the session is doing without opening it:
|
||||
|
||||
| Signal | Meaning |
|
||||
| --------------------- | ---------------------------------------------------------- |
|
||||
| Green dot | Alive and idle. |
|
||||
| Pulsing green dot | Working on a turn. |
|
||||
| Yellow, blinking | Waiting for you to type something. |
|
||||
| Red, blinking | A question or permission prompt is blocking the agent. |
|
||||
|
||||
Full tour in [The Dashboard](The-Dashboard). If you want a phone notification when an agent
|
||||
needs you, that is [Notifications And Approvals](Notifications-And-Approvals).
|
||||
|
||||
## 7. Leave, and come back
|
||||
|
||||
Close the browser tab. Close the laptop. The agent keeps running, because it lives in tmux
|
||||
and not in your browser.
|
||||
|
||||
Reopen the dashboard and the session is still there with its scrollback intact. First load
|
||||
of a session pulls the full tmux scrollback, so you get the history, not just what arrived
|
||||
after you reconnected.
|
||||
|
||||
This also survives restarting the Codeman server itself. What does not survive is killing
|
||||
the tmux server or rebooting the machine.
|
||||
|
||||
## 8. Stop things
|
||||
|
||||
| To do this | Do that |
|
||||
| ------------------------- | ------------------------------------------------------------------- |
|
||||
| Interrupt the current turn | `Ctrl+C` with nothing selected, or the **Stop** button. |
|
||||
| Close one session | `Ctrl+W`, or the tab's close control. |
|
||||
| Stop the server, keep agents | `codeman web --stop`. The tmux sessions stay alive. |
|
||||
| Stop everything | `tmux -L codeman kill-server`. |
|
||||
|
||||
If you are working *inside* a Codeman-managed session (`echo $CODEMAN_MUX` prints `1`),
|
||||
never run `tmux kill-session` or `pkill claude` by hand. You will kill the session you are
|
||||
sitting in, along with its siblings.
|
||||
|
||||
## Where to go next
|
||||
|
||||
**Make it run without you.** [Keeping Agents Running](Keeping-Agents-Running) covers idle
|
||||
detection, respawn cycling, and auto-resume when a subscription limit resets. That is the
|
||||
feature Codeman exists for.
|
||||
|
||||
**Get it on your phone.** [Remote Access](Remote-Access), then
|
||||
[Mobile Guide](Mobile-Guide).
|
||||
|
||||
**Understand what you just used.** [Core Concepts](Core-Concepts) explains cases, sessions,
|
||||
run modes, and what state lives where.
|
||||
|
||||
**Automate it.** [Cron Jobs](Cron-Jobs) for scheduled work,
|
||||
[Driving Codeman From An Agent](Driving-Codeman-From-An-Agent) for agents that spawn and
|
||||
supervise other agents.
|
||||
@@ -0,0 +1,209 @@
|
||||
# Remote Access
|
||||
|
||||
Reaching your Codeman from a phone, a laptop on the other side of the house, or a hotel
|
||||
network. This is the page to read carefully, because Codeman's dashboard is a
|
||||
remote-code-execution surface by design: it starts agents with permission prompts skipped,
|
||||
so whoever can reach it can run code on your machine.
|
||||
|
||||
## Start from the default
|
||||
|
||||
`codeman web` binds `127.0.0.1`. It is reachable from the machine running it and nothing
|
||||
else, which is why the no-password default is safe out of the box. Every option below is a
|
||||
deliberate step away from that.
|
||||
|
||||
Two rules that make the rest of this page simple:
|
||||
|
||||
1. **Never expose Codeman on a network without `CODEMAN_PASSWORD`.** Binding a non-loopback
|
||||
host without one starts, but prints a loud warning with the fixes.
|
||||
2. **Prefer keeping the loopback bind** and putting an authenticated tunnel in front of it,
|
||||
over binding wide and relying on a password alone.
|
||||
|
||||
## Pick an approach
|
||||
|
||||
| Approach | Good for | Cost |
|
||||
| --------------------- | ----------------------------------------------------- | --------------------------------------------------------- |
|
||||
| **Tailscale** | Phone access, permanently. The recommended setup. | Install Tailscale on both devices. |
|
||||
| **Cloudflare tunnel** | A public URL, quickly, from anywhere. | Public URL, so a password is mandatory. |
|
||||
| **LAN + password** | Home network only, no extra software. | Every device on your LAN can reach the login page. |
|
||||
| **SSH port forward** | You already SSH to the box. | Manual, per session, terminal-bound. |
|
||||
|
||||
## Tailscale (recommended)
|
||||
|
||||
Your devices join a private network, and Codeman stays bound to loopback. Nothing is
|
||||
published to the internet, and you get real HTTPS with a real certificate.
|
||||
|
||||
The installer sets this up for you, including installing Tailscale, logging in, enabling
|
||||
tailnet HTTPS, and verifying the result end to end. To retrofit it onto an existing
|
||||
install:
|
||||
|
||||
```bash
|
||||
install.sh tailscale
|
||||
```
|
||||
|
||||
By hand:
|
||||
|
||||
```bash
|
||||
tailscale serve --bg 3000
|
||||
tailscale serve status
|
||||
```
|
||||
|
||||
Then open `https://<machine>.<tailnet>.ts.net` from any device on your tailnet.
|
||||
|
||||
Notes:
|
||||
|
||||
- Keep the loopback bind. `tailscale serve` connects to `127.0.0.1:3000` locally, so
|
||||
binding wider adds exposure and buys nothing.
|
||||
- Your tailnet is the authentication boundary. Setting `CODEMAN_PASSWORD` as well is
|
||||
reasonable defence in depth, especially if other people have devices on your tailnet.
|
||||
- Codeman's Host-header allowlist already accepts `.ts.net`, so no extra configuration is
|
||||
needed.
|
||||
- The installer never resets or rewrites `serve` mappings other than the one pointing at
|
||||
Codeman's port, so unrelated serve configuration is left alone.
|
||||
|
||||
## Cloudflare tunnel
|
||||
|
||||
A free [quick tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/)
|
||||
gives you a public HTTPS URL with no port forwarding, no DNS, and no static IP:
|
||||
|
||||
```
|
||||
Browser → Cloudflare edge (HTTPS) → cloudflared → localhost:3000
|
||||
```
|
||||
|
||||
Prerequisites: [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)
|
||||
installed, and `CODEMAN_PASSWORD` set.
|
||||
|
||||
```bash
|
||||
./scripts/tunnel.sh start # starts the tunnel, prints the public URL
|
||||
./scripts/tunnel.sh url
|
||||
./scripts/tunnel.sh status
|
||||
./scripts/tunnel.sh stop
|
||||
```
|
||||
|
||||
The quick-tunnel URL is a random `*.trycloudflare.com` address that changes every time the
|
||||
tunnel restarts. For a stable hostname, `./scripts/tunnel.sh named setup` walks through a
|
||||
named tunnel.
|
||||
|
||||
To survive reboots:
|
||||
|
||||
```bash
|
||||
systemctl --user enable codeman-tunnel
|
||||
loginctl enable-linger $USER
|
||||
```
|
||||
|
||||
There is also a toggle in **App Settings → System → Remote access**.
|
||||
|
||||
**The tunnel refuses to start without a password.** That is on purpose: a public URL with no
|
||||
authentication is a terminal on your machine handed to the internet. Acknowledging the risk
|
||||
explicitly is possible from the UI toggle, and only from there; the API will not do it for
|
||||
you.
|
||||
|
||||
## LAN plus password
|
||||
|
||||
```bash
|
||||
export CODEMAN_PASSWORD='something long'
|
||||
codeman web -H 0.0.0.0 --https
|
||||
```
|
||||
|
||||
Every device on your local network can now reach the login page. `--https` generates a
|
||||
self-signed certificate into `~/.codeman/certs/`, which your browser will warn about once.
|
||||
|
||||
`CODEMAN_USERNAME` defaults to `admin`.
|
||||
|
||||
The installer offers this path and prompts for the password. On re-runs it preserves
|
||||
whichever binding you already chose.
|
||||
|
||||
## SSH port forward
|
||||
|
||||
No configuration at all, if you already have SSH access:
|
||||
|
||||
```bash
|
||||
ssh -L 3000:localhost:3000 you@your-box
|
||||
```
|
||||
|
||||
Then open `http://localhost:3000` on the local machine. Codeman keeps its loopback bind and
|
||||
sees a local connection. Good for occasional access, awkward as a permanent arrangement
|
||||
because it dies with the SSH session.
|
||||
|
||||
## Logging in from a phone
|
||||
|
||||
Typing a long password on a phone keyboard is miserable, so Codeman issues **single-use QR
|
||||
tokens**. The desktop dashboard shows a QR code; scan it and the phone is authenticated.
|
||||
|
||||
How it behaves:
|
||||
|
||||
- The code rotates every 60 seconds, with a 90 second grace window so scanning during a
|
||||
rotation still works.
|
||||
- Each token is **single use**. The moment a phone consumes it, a new one is generated.
|
||||
- The URL contains a 6-character lookup code, not the secret, so it does not leak through
|
||||
browser history, `Referer` headers, or the tunnel provider's logs.
|
||||
- The desktop shows a toast naming the device and browser that just authenticated, with a
|
||||
one-click revoke.
|
||||
- QR attempts are rate limited separately from password attempts, so a mistyped password
|
||||
cannot lock out your QR login and vice versa.
|
||||
|
||||
Someone holding only the tunnel URL still meets the normal password prompt. The QR is the
|
||||
fast path, not a bypass.
|
||||
|
||||
Design detail and the threat analysis it is built against:
|
||||
[`docs/qr-auth-plan.md`](https://github.com/Ark0N/Codeman/blob/master/docs/qr-auth-plan.md).
|
||||
|
||||
## Behind a reverse proxy
|
||||
|
||||
Codeman enforces a Host-header allowlist on every request to block DNS rebinding, and the
|
||||
same allowlist gates the cross-site Origin check. It accepts `localhost`, IP literals, the
|
||||
bind host, `.ts.net`, `.trycloudflare.com`, `.cfargotunnel.com`, and the active managed
|
||||
tunnel.
|
||||
|
||||
**Your own domain is not on that list.** Add it:
|
||||
|
||||
```bash
|
||||
CODEMAN_ALLOWED_HOSTS='codeman.example.com,.internal.example.com'
|
||||
```
|
||||
|
||||
A bare entry matches that exact host; a leading dot matches subdomains. Without this, a
|
||||
correctly configured proxy still gets `403 host not allowed`, which reads like a proxy bug
|
||||
and is not one.
|
||||
|
||||
Also make sure the proxy forwards WebSocket upgrades. The terminal is a WebSocket, and the
|
||||
upgrade runs the same Host and Origin checks, closing with code `4003` on failure.
|
||||
|
||||
## Session cookies and rate limits
|
||||
|
||||
The first request prompts for HTTP Basic credentials. On success the server issues an opaque
|
||||
`codeman_session` cookie (24 hour lifetime, extended on activity, validated server-side so
|
||||
it cannot be forged offline). Ten failed attempts from one IP produce a `429` with a 15
|
||||
minute decay.
|
||||
|
||||
A valid cookie or a correct password recovers immediately even while an attacker is hammering
|
||||
the same IP, which matters because all tunnel traffic arrives from one loopback address.
|
||||
|
||||
## Terminal alternatives
|
||||
|
||||
You do not have to use a browser. `sc` is a thumb-friendly session chooser for SSH clients
|
||||
like Termius or Blink:
|
||||
|
||||
```bash
|
||||
sc # interactive chooser
|
||||
sc 2 # attach to session 2
|
||||
sc -l # list
|
||||
```
|
||||
|
||||
Detach with `Ctrl+A D`. The sessions are the same ones the dashboard shows.
|
||||
|
||||
## Common problems
|
||||
|
||||
| Symptom | Cause and fix |
|
||||
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `403 host not allowed` | Your domain is not in the allowlist. Set `CODEMAN_ALLOWED_HOSTS`. |
|
||||
| Phone shows the login page but the terminal never connects | The proxy is not forwarding WebSocket upgrades. |
|
||||
| Browser warns about the certificate | Expected with `--https` and its self-signed certificate. Tailscale gives you a real one instead. |
|
||||
| LAN IP does not respond, but a tunnel to the same box works | The server is bound to loopback. That is the default. A tunnel reaches it; a LAN browser cannot. |
|
||||
| Hooks stopped working after switching to HTTPS | Hook callbacks need `-k` for the self-signed certificate. Recent versions self-heal existing cases; if yours predates that, recreate the case's hooks. |
|
||||
| Everything is slow over the tunnel | Quick tunnels route through Cloudflare's edge. Tailscale is usually a direct connection and much faster. |
|
||||
|
||||
## Read next
|
||||
|
||||
- [Security](Security) - the whole model, and the hardening checklist.
|
||||
- [Mobile Guide](Mobile-Guide) - once you can reach it from the phone.
|
||||
- [Running As A Service](Running-As-A-Service) - keeping server and tunnel up across reboots.
|
||||
- [`docs/security-architecture.md`](https://github.com/Ark0N/Codeman/blob/master/docs/security-architecture.md) - the full model.
|
||||
@@ -0,0 +1,101 @@
|
||||
# Remote SSH Sessions
|
||||
|
||||
Point a case at another machine and the agent runs **there**, with the same dashboard,
|
||||
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 seven run modes
|
||||
work remotely. See [Core Concepts](Core-Concepts).
|
||||
|
||||
## Why bother
|
||||
|
||||
The agent runs where the work is: a build server, a NAS, a GPU box, a machine reachable only
|
||||
through a jump host. Your laptop can sleep, change networks, or close, and the run continues.
|
||||
|
||||
## Setting it up
|
||||
|
||||
**Add Case → Remote**:
|
||||
|
||||
| Field | Notes |
|
||||
| --------------------- | -------------------------------------------------------------------- |
|
||||
| **Host** | Hostname or IP. |
|
||||
| **Username** | The SSH user. |
|
||||
| **Port** | Defaults to 22. |
|
||||
| **Identity file** | `~` and `$HOME` are expanded for you. |
|
||||
| **Jump host** | The `-J` equivalent, `[user@]host[:port]`. |
|
||||
| **SOCKS proxy** | For hosts reachable only through a proxy. |
|
||||
| **Extra SSH options** | Any `KEY=VALUE` options your normal connection needs. |
|
||||
| **Remote path** | The working directory on that machine. |
|
||||
|
||||
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.
|
||||
|
||||
The remote host needs **tmux**. Codeman probes for it when you link the host rather than
|
||||
failing later at launch.
|
||||
|
||||
## What actually runs
|
||||
|
||||
The agent lives inside a dedicated tmux server on the **remote** host, and Codeman fronts it
|
||||
with a local tmux pane running `ssh`.
|
||||
|
||||
That two-layer arrangement is what makes it durable: a dropped SSH connection, a network
|
||||
change, or a closed laptop kills the local pane, not the remote session. Reconnecting lands
|
||||
back in the same live conversation.
|
||||
|
||||
The remote session name is deliberately chosen so that a Codeman **running on the target
|
||||
host** will not adopt it as one of its own. Two Codemans, one host, no interference.
|
||||
|
||||
## Auto-reconnect
|
||||
|
||||
A watcher with bounded backoff notices a dead SSH pane and quietly reattaches to the still
|
||||
running remote session. On by default; the kill switch is in
|
||||
**App Settings → Agents & CLIs → Remote auto-reconnect**.
|
||||
|
||||
Intentional kills are never revived. Closing a session means closing it.
|
||||
|
||||
## Discover and attach
|
||||
|
||||
Codeman can list the `codeman-*` sessions already running on a host, whether that machine's
|
||||
own Codeman started them or another operator did, and attach to one.
|
||||
|
||||
The distinction that matters:
|
||||
|
||||
| Session | On tab close |
|
||||
| ------------ | ------------------------------------------------ |
|
||||
| **Launched** | Killed, like any local session. |
|
||||
| **Attached** | **Detached, never killed.** |
|
||||
|
||||
Attaching to someone else's session and closing your tab must not end their run, so it does
|
||||
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.
|
||||
|
||||
## Security
|
||||
|
||||
Every SSH command line in Codeman flows through one builder that shell-escapes every
|
||||
user-supplied field: identity paths, jump hosts, proxy commands, and extra options. That is
|
||||
the entire injection surface, and it is deliberately a single function rather than string
|
||||
concatenation spread across the codebase.
|
||||
|
||||
Host, path, and identity fields are schema-validated on top of that.
|
||||
|
||||
Codeman does not store SSH passwords. Use keys, as you would for any other automation.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **The remote host needs tmux.** Probed at link time, so you find out immediately.
|
||||
- **The local working directory is meaningless** for a remote session, and is not used.
|
||||
- **Run flows must go through the quick-start path** for remote cases. This matters if you
|
||||
are driving Codeman over the API: the plain session-create endpoint validates the working
|
||||
directory locally and has no case concept, so it will reject or misroute a remote case.
|
||||
- **Latency is SSH latency.** Local echo helps the typing feel, but a slow link is a slow
|
||||
link.
|
||||
- **Transcript-backed features follow the transcript.** Subagent windows and similar surfaces
|
||||
read files on the machine where the agent runs.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Core Concepts](Core-Concepts) - overlays versus run modes.
|
||||
- [Docker Cases](Docker-Cases) - the other overlay.
|
||||
- [Security](Security) - the wider model.
|
||||
- [`docs/remote-sessions.md`](https://github.com/Ark0N/Codeman/blob/master/docs/remote-sessions.md) - the full design.
|
||||
@@ -0,0 +1,197 @@
|
||||
# Running As A Service
|
||||
|
||||
Keeping Codeman up: past the shell you started it in, past a logout, past a reboot. Plus
|
||||
logs, updates, and running more than one instance.
|
||||
|
||||
## Three levels
|
||||
|
||||
| Level | Survives | Command |
|
||||
| -------------------- | ----------------------------------------- | ------------------------- |
|
||||
| Foreground | Nothing. Dies with the terminal. | `codeman web` |
|
||||
| Detached | Closing the shell and logging out. | `codeman web -d` |
|
||||
| Service | Reboots. | `codeman service install` |
|
||||
|
||||
Agents themselves survive all three, because they live in tmux. Stopping the server never
|
||||
stops the agents.
|
||||
|
||||
## Detached mode
|
||||
|
||||
```bash
|
||||
codeman web -d # start detached; logs to ~/.codeman/web.log
|
||||
codeman web --status # is it up, and on which pid
|
||||
codeman web --stop # graceful stop; agents keep running
|
||||
```
|
||||
|
||||
`-d` waits until the server actually answers before reporting success, so a port clash never
|
||||
reads as a successful start.
|
||||
|
||||
Two implementation details that explain the behaviour:
|
||||
|
||||
- It relaunches the same entry script detached, so there is no controlling terminal and no
|
||||
shell job entry. `nohup` is **not** what makes this work: Node re-arms the hangup signal to
|
||||
its default even when it inherits "ignore", and Codeman handles that signal with a graceful
|
||||
shutdown, so a delivered hangup would still stop the server.
|
||||
- `--stop` verifies the process still looks like a Codeman server before signalling it,
|
||||
because process ids get recycled.
|
||||
|
||||
**It refuses to start a second server on the same data directory.** Two servers sharing a
|
||||
tmux socket attach to each other's live sessions.
|
||||
|
||||
## Installing as a service
|
||||
|
||||
```bash
|
||||
codeman service install # systemd user unit on Linux, LaunchAgent on macOS
|
||||
codeman service status
|
||||
codeman service uninstall
|
||||
```
|
||||
|
||||
The installer's final menu offers this too.
|
||||
|
||||
Notable behaviours:
|
||||
|
||||
- **Your PATH is baked into the unit.** launchd hands a job
|
||||
`/usr/bin:/bin:/usr/sbin:/sbin`, which finds neither a Homebrew or nvm `node` nor `tmux`
|
||||
or `claude`. This is the single most common cause of a hand-written unit that starts and
|
||||
immediately dies.
|
||||
- **`CODEMAN_PASSWORD` is never written into the unit file.** Add it yourself if the service
|
||||
needs authentication.
|
||||
- **It refuses when a server is already running** on that data directory, for the same reason
|
||||
detached mode does.
|
||||
- **It verifies rather than assumes.** `launchctl load` and a clean spawn are both silent
|
||||
about a server that starts and immediately exits, so the parent polls until the child
|
||||
answers or dies.
|
||||
|
||||
On Linux, if you want the service running while you are not logged in:
|
||||
|
||||
```bash
|
||||
loginctl enable-linger $USER
|
||||
```
|
||||
|
||||
### Writing the unit by hand
|
||||
|
||||
**Linux (systemd user unit):**
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/systemd/user
|
||||
cat > ~/.config/systemd/user/codeman-web.service << EOF
|
||||
[Unit]
|
||||
Description=Codeman Web Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=$(which node) $HOME/.codeman/app/dist/index.js web
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now codeman-web
|
||||
loginctl enable-linger $USER
|
||||
```
|
||||
|
||||
**macOS (LaunchAgent):**
|
||||
|
||||
```bash
|
||||
mkdir -p ~/Library/LaunchAgents
|
||||
cat > ~/Library/LaunchAgents/com.codeman.web.plist << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.codeman.web</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>$(which node)</string>
|
||||
<string>$HOME/.codeman/app/dist/index.js</string>
|
||||
<string>web</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key><true/>
|
||||
<key>KeepAlive</key><true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/codeman.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/codeman.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.codeman.web.plist
|
||||
```
|
||||
|
||||
Prefer `codeman service install` where you can. It handles the PATH problem for you.
|
||||
|
||||
## Logs
|
||||
|
||||
```bash
|
||||
journalctl --user -u codeman-web -f # systemd
|
||||
tail -f ~/.codeman/web.log # detached mode
|
||||
log stream --predicate 'process == "node"' # macOS, noisy
|
||||
```
|
||||
|
||||
## Updating
|
||||
|
||||
| Install route | Update with |
|
||||
| ------------- | ------------------------------------------------------------------------ |
|
||||
| Installer | Re-run the one-liner, or **App Settings → System → Updates**. |
|
||||
| npm | `npm update -g aicodeman` |
|
||||
| git clone | `git pull && npm install && npm run build`, then restart. |
|
||||
|
||||
### 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.
|
||||
|
||||
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
|
||||
file, which the browser polls across the connection drop. A dirty tree is stashed rather
|
||||
than discarded.
|
||||
|
||||
### After updating
|
||||
|
||||
Sessions are unaffected: they live in tmux and the server reattaches. If the UI looks stale,
|
||||
reload; on iOS Safari, close the tab completely and reopen.
|
||||
|
||||
## Running two instances
|
||||
|
||||
The data directory and the tmux socket are process wide, so a second server on the defaults
|
||||
will discover and attach the first one's sessions. Scope both together:
|
||||
|
||||
```bash
|
||||
CODEMAN_INSTANCE=beta CODEMAN_PORT=5000 codeman web
|
||||
```
|
||||
|
||||
Service unit names are instance-scoped too, so a beta instance can be installed as its own
|
||||
service without colliding with the main one. `CODEMAN_DATA_DIR` and `CODEMAN_TMUX_SOCKET`
|
||||
exist for the rare case where they need to differ, but setting only one of them recreates
|
||||
exactly the problem you were avoiding.
|
||||
|
||||
## The tunnel as a service
|
||||
|
||||
```bash
|
||||
systemctl --user enable codeman-tunnel
|
||||
loginctl enable-linger $USER
|
||||
```
|
||||
|
||||
Or the toggle in **App Settings → System → Remote access**. See
|
||||
[Remote Access](Remote-Access).
|
||||
|
||||
## Health checks
|
||||
|
||||
```bash
|
||||
curl -s localhost:3000/api/status | jq '.version, .uptime'
|
||||
codeman web --status
|
||||
codeman doctor
|
||||
```
|
||||
|
||||
Add `-k` and the `https://` URL on an HTTPS install.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Installation](Installation) - the routes and what each supports.
|
||||
- [Remote Access](Remote-Access) - exposing it once it stays up.
|
||||
- [Troubleshooting](Troubleshooting) - when it does not.
|
||||
@@ -0,0 +1,120 @@
|
||||
# Security
|
||||
|
||||
The honest version first: **Codeman's dashboard is a remote code execution surface, by
|
||||
design.** It starts agents with permission prompts skipped by default, so anyone who can
|
||||
reach it can run arbitrary code as your user, on your machine. Every protection in Codeman
|
||||
exists to control who that is.
|
||||
|
||||
That is not a flaw to be fixed. It is what "run my coding agent for me" means. The job is to
|
||||
make sure the set of people who can reach it is exactly the set you intended.
|
||||
|
||||
## The default is safe
|
||||
|
||||
A bare `codeman web` binds `127.0.0.1`. Only processes on that machine can reach it, which
|
||||
is why shipping with no password by default is defensible. Everything risky starts when you
|
||||
expose it.
|
||||
|
||||
## Hardening checklist
|
||||
|
||||
In order of how much they matter:
|
||||
|
||||
1. **Do not expose it without `CODEMAN_PASSWORD`.** Binding a non-loopback host without one
|
||||
starts, but warns loudly. A tunnel refuses outright unless you acknowledge the exposure
|
||||
in the UI.
|
||||
2. **Prefer Tailscale over a public tunnel.** Keeping the loopback bind and putting a
|
||||
private network in front of it removes the public attack surface entirely, and gives you
|
||||
real HTTPS. See [Remote Access](Remote-Access).
|
||||
3. **Use a long password.** It is the only thing between a public URL and your shell.
|
||||
4. **Consider the permission mode.** **App Settings → Agents & CLIs → Claude → Startup
|
||||
Mode** can switch new sessions from skip-prompts to Anthropic's classifier-guarded `auto`
|
||||
mode, to normal prompting, or to an explicit allowed-tools list.
|
||||
5. **Use Docker cases for untrusted work.** If you are pointing an autonomous loop at a repo
|
||||
you did not write, [Docker Cases](Docker-Cases) gives it its own filesystem and network
|
||||
for the cost of one checkbox.
|
||||
6. **Keep it updated.** Browser-driven attack paths were closed in 0.9.x and hardening is
|
||||
ongoing.
|
||||
|
||||
## What protects what
|
||||
|
||||
These run on **every** request, including on a default no-password loopback install:
|
||||
|
||||
| Layer | What it stops |
|
||||
| ---------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| **Host-header allowlist** | DNS rebinding. A domain rebound to `127.0.0.1` is rejected before any handler runs. Add your own domains with `CODEMAN_ALLOWED_HOSTS`. |
|
||||
| **Cross-site Origin guard** | CSRF on state-changing requests. A *missing* Origin is allowed so curl, the CLI, and hooks keep working; a foreign or opaque one is rejected. |
|
||||
| **Raw `text/plain` bodies** | The CORS simple-request CSRF vector, where a cross-site form could smuggle JSON into a write route with no preflight. |
|
||||
| **WebSocket origin check** | Cross-site WebSocket hijacking. The terminal upgrade closes with code `4003` on failure. |
|
||||
| **Output escaping** | Stored XSS from agent-derived strings: tool names, command arguments, subagent descriptions. |
|
||||
| **Security headers** | A strict content security policy, `nosniff`, frame options, and HSTS over HTTPS. CORS is reflected only for loopback origins. |
|
||||
|
||||
When authentication is enabled:
|
||||
|
||||
| Layer | Behaviour |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| **HTTP Basic** | `CODEMAN_USERNAME` (default `admin`) and `CODEMAN_PASSWORD`. |
|
||||
| **Session cookie** | A 256-bit opaque token validated server side, so it cannot be forged offline. 24 hours, extended on activity, with a device-context audit trail. |
|
||||
| **Rate limiting** | Ten failed attempts per IP produce a `429` with a 15 minute decay. A correct password or valid cookie recovers immediately even under attack, which matters because all tunnel traffic shares one loopback address. |
|
||||
| **QR auth** | Single-use 60-second tokens with their own separate rate limiter, so a mistyped password cannot lock out QR login. |
|
||||
| **Hook endpoints** | The hook and telemetry endpoints skip Basic auth because they are called from localhost by the CLI, but when auth is on, that bypass additionally requires a per-instance hook secret. |
|
||||
|
||||
## File access
|
||||
|
||||
Three separate file surfaces, each confined differently, because a single shared rule would
|
||||
be wrong for at least one of them:
|
||||
|
||||
| Surface | Rules |
|
||||
| -------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| **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. |
|
||||
|
||||
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
|
||||
in the page.
|
||||
|
||||
## Supply chain and isolation
|
||||
|
||||
- Security-sensitive transitive dependencies are pinned to patched versions, and lockfile
|
||||
integrity is checked on every push and pull request: every entry must resolve to the public
|
||||
registry with a hash.
|
||||
- Public assets are scanned for NUL bytes and syntax-checked in CI.
|
||||
- `CODEMAN_INSTANCE` scopes the tmux socket and the data directory together, so two
|
||||
instances never attach each other's live sessions.
|
||||
|
||||
## What Codeman does not protect against
|
||||
|
||||
Stated plainly, because a security page that only lists strengths is not useful:
|
||||
|
||||
- **Multi-user mode is not a sandbox.** It separates workspaces. Every session still runs as
|
||||
the same OS account, so a determined user's agent can reach another user's files. For real
|
||||
isolation, pair users with Docker cases or run separate instances under separate OS
|
||||
accounts.
|
||||
- **An agent you gave shell access can do anything you can.** Permission modes narrow this;
|
||||
they do not remove it.
|
||||
- **A tunnel makes your machine reachable from the internet.** The password is the whole
|
||||
boundary. Treat it accordingly.
|
||||
- **Codeman cannot detect your own loopback reverse proxy**, which is why the hook-endpoint
|
||||
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).
|
||||
|
||||
## Privacy
|
||||
|
||||
No telemetry, no analytics, no phone-home. Codeman's only network traffic is between your
|
||||
browser and your server. Your agent CLI's traffic is its own, on your account.
|
||||
|
||||
Two features send data outward, both off by default and both stated where they appear: voice
|
||||
dictation through your Claude login, and the Read My Mind prediction call.
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
**Never in a public issue.**
|
||||
[SECURITY.md](https://github.com/Ark0N/Codeman/blob/master/.github/SECURITY.md) has the
|
||||
private disclosure process and the current list of known limitations.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Remote Access](Remote-Access) - the safe ways to expose it.
|
||||
- [Multi-User Mode](Multi-User-Mode) - what it does and does not separate.
|
||||
- [Docker Cases](Docker-Cases) - real isolation for untrusted work.
|
||||
- [`docs/security-architecture.md`](https://github.com/Ark0N/Codeman/blob/master/docs/security-architecture.md) - the complete model.
|
||||
@@ -0,0 +1,172 @@
|
||||
# Settings Reference
|
||||
|
||||
Two settings surfaces, and the rule that explains why a setting you changed on your laptop
|
||||
did not follow you to your phone.
|
||||
|
||||
| Surface | Scope | Opened from |
|
||||
| ------------------- | ------------------------------ | ---------------------------- |
|
||||
| **App Settings** | Global, this Codeman install. | The header gear. |
|
||||
| **Session Options** | One session. | The session's tab. |
|
||||
|
||||
App Settings is a single scrolling document with a rail acting as a table of contents;
|
||||
clicking a rail entry scrolls rather than switching. Session Options genuinely switches
|
||||
panels.
|
||||
|
||||
## Per-device versus synced
|
||||
|
||||
Some settings live on the server and follow you to every device. Others are stored in the
|
||||
browser and stay put. This is deliberate, not an oversight: your phone wants a different
|
||||
font size, a different keyboard bar, and a different set of header buttons than your
|
||||
desktop.
|
||||
|
||||
| Category | Examples |
|
||||
| ----------------------- | ------------------------------------------------------------------------------- |
|
||||
| **Per-device, local** | Skin, WebGL renderer, local echo, CJK input, extended keyboard bar, File Viewer and Cron header buttons. Never sent to the server at all. |
|
||||
| **Per-device policy** | Most `show*` toggles, plan usage chip, language. Stored server-side, but a device only takes the server value when it has no local one of its own. |
|
||||
| **Synced** | Models, effort, CLI options, notification preferences, voice settings, display name, the agent skill and approvals toggles. |
|
||||
|
||||
The practical rule: **appearance and input are per device, behaviour is shared.** If a change
|
||||
did not follow you, it is in one of the first two rows, and you change it again on that
|
||||
device.
|
||||
|
||||
## App Settings
|
||||
|
||||
### 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).
|
||||
|
||||
### Terminal & Input
|
||||
|
||||
| Setting | Default | Notes |
|
||||
| ----------------------------- | -------------------- | --------------------------------------------------------------------- |
|
||||
| Local Echo | On for touch devices | Paints keystrokes locally and flushes on Enter. See [Input And Voice](Input-And-Voice). |
|
||||
| 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. |
|
||||
| WebGL Renderer | On | With a GPU-stall watchdog that falls back to DOM rendering. |
|
||||
| Gesture Control | Off | Camera hand tracking. Also needs `CODEMAN_GESTURE=1` on the server. |
|
||||
|
||||
### Header & Panels
|
||||
|
||||
Chips for every optional header control, with a live preview of the resulting header:
|
||||
|
||||
Run, Font Size, System Stats, Redraw Terminal, Response Viewer, Away Digest, Session
|
||||
Manager, Attachments, File Viewer, Multi-monitor, Plan Usage, Lifecycle Log, Monitor,
|
||||
Project Insights, File Browser, Subagents, Approvals Inbox, Read My Mind, Ultracode Agents,
|
||||
Ultracode Windows, Cron.
|
||||
|
||||
Most default to off. The stock desktop header is system stats, File Viewer, and the gear.
|
||||
New header controls never appear on phones.
|
||||
|
||||
This section also holds background-agent tracking, including whether to track agents for
|
||||
every session or only the active tab.
|
||||
|
||||
### Appearance
|
||||
|
||||
| Setting | Notes |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| Skin | Theme palettes, light ones included. Applied before first paint, so no flash of the wrong theme. |
|
||||
| Entrance Animations | Per-surface animation styles for tabs, terminals, windows, and lineage lines. All default to the legacy no-animation behaviour. |
|
||||
| Display Name | Your name in the UI. Cosmetic only; it never renames the package, CLI, API, or storage. |
|
||||
| Interface Language | English or Simplified Chinese. Per device. |
|
||||
| Session List Layout | Header tab strip (default) or a collapsible left sidebar. See [The Dashboard](The-Dashboard#session-list-layout). |
|
||||
| Tall Tabs | Taller tab strip. |
|
||||
| Pop-out Button on Tabs | Adds the detach control to tabs, with a per-tab override. |
|
||||
| Spawn Lineage Lines | Arcs from a parent tab to sessions it spawned. Desktop only, on by default. |
|
||||
| Overview Home Screen | The phone home screen. On by default. |
|
||||
|
||||
### Models
|
||||
|
||||
Claude model cards, the 1M context window switch, and the thinking effort segment. The cards
|
||||
and the switch compose into one model choice, so there is no separate "which one wins"
|
||||
question.
|
||||
|
||||
Model and effort are both **soft defaults**: the model is written into the case's
|
||||
`.claude/settings.local.json` and effort is passed at start, so `/model` and `/effort`
|
||||
inside a session override them at any time.
|
||||
|
||||
### Agents & CLIs
|
||||
|
||||
| Setting | Notes |
|
||||
| -------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| Startup Mode | Claude's permission mode for new sessions. Default skips prompts; `auto` uses Anthropic's classifier-guarded mode; `normal` prompts; or give an explicit allowed-tools list. |
|
||||
| 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. |
|
||||
| Codeman Agent Skill | Injects the agent skill into new Claude sessions per case. Off by default. See [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent). |
|
||||
| Remote auto-reconnect | Reattaches dropped remote SSH sessions. On by default. |
|
||||
| Nice priority / value | Runs agent processes at a lower CPU priority. |
|
||||
| Bypass approvals and sandbox | Pi's project trust. Read [Agent CLIs](Agent-CLIs) before enabling. |
|
||||
| Animated status effects | Cosmetic. |
|
||||
|
||||
### Notifications
|
||||
|
||||
Master toggle, browser notifications, push subscription, audio alerts, and the idle
|
||||
threshold that decides when a quiet session counts as needing you. See
|
||||
[Notifications And Approvals](Notifications-And-Approvals).
|
||||
|
||||
### Voice
|
||||
|
||||
Active provider and the engine behind it, insert mode, language, domain keywords to bias
|
||||
recognition, the Deepgram API key, and the opt-in switch for transcribing through this
|
||||
server's Claude login, with its live credential status. See
|
||||
[Input And Voice](Input-And-Voice).
|
||||
|
||||
### Shortcuts
|
||||
|
||||
Rebinding for the shortcut registry. See [Keyboard Shortcuts](Keyboard-Shortcuts).
|
||||
|
||||
### System
|
||||
|
||||
`CLAUDE.md` template for new cases, default working directory, the image watcher, and
|
||||
Cloudflare tunnel controls including the tunnel and upload URLs. In multi-user mode, the
|
||||
**Users** administration entry is injected here.
|
||||
|
||||
## Session Options
|
||||
|
||||
Per session, from the tab.
|
||||
|
||||
| Panel | Contains |
|
||||
| ---------------- | ------------------------------------------------------------------------------------------- |
|
||||
| **Respawn** | Auto-resume on usage limit, the respawn cycle configuration, presets, duration. See [Keeping Agents Running](Keeping-Agents-Running). |
|
||||
| **Session** | Name, working directory, environment overrides, per-tab pop-out override. |
|
||||
| **Ralph / Todo** | Loop configuration, iteration and todo caps, circuit breaker reset. See [Autonomous Loops](Autonomous-Loops). |
|
||||
| **Summary** | What this session has done: tokens, activity, run summary. |
|
||||
|
||||
Panels that only make sense for Claude are hidden for other run modes rather than shown and
|
||||
failing.
|
||||
|
||||
## Environment variables
|
||||
|
||||
Some things are configured before the server starts, not in the UI:
|
||||
|
||||
| Variable | Effect |
|
||||
| ----------------------------------- | ---------------------------------------------------------------------- |
|
||||
| `CODEMAN_PORT` | Listen port. |
|
||||
| `CODEMAN_HOST` | Bind address. Loopback by default. |
|
||||
| `CODEMAN_PASSWORD` / `CODEMAN_USERNAME` | HTTP Basic credentials. Username defaults to `admin`. |
|
||||
| `CODEMAN_ALLOWED_HOSTS` | Extra Host and Origin allowlist entries for a reverse proxy. |
|
||||
| `CODEMAN_INSTANCE` | Scopes the data directory and tmux socket together. Required for a second instance. |
|
||||
| `CODEMAN_MULTIUSER` | Enables multi-user mode. |
|
||||
| `CODEMAN_GESTURE` | Makes gesture control available to be enabled. |
|
||||
| `CODEMAN_DOCKER_BRIDGE_HOOKS` | Lets in-container hooks reach the host on a loopback bind. |
|
||||
| `CODEMAN_FILE_PICKER_ROOTS` | Extra roots for the path picker. |
|
||||
| `CODEMAN_ALLOW_UNAUTHENTICATED_NETWORK` | Acknowledges exposing the server with no password. |
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **A setting that did not sync is per device.** Change it again on that device.
|
||||
- **The plan usage chip and its telemetry exporter are one setting.** Enabling the chip
|
||||
without the exporter would leave it blank forever, so it is deliberately not separable.
|
||||
- **Toggling a header button does nothing on a phone.** Phones deliberately ignore most of
|
||||
the header chips.
|
||||
- **Enabling a feature does not retroactively configure existing sessions.** The agent skill
|
||||
injection, for instance, applies at session creation.
|
||||
|
||||
## Read next
|
||||
|
||||
- [The Dashboard](The-Dashboard) - what each control does once visible.
|
||||
- [Keeping Agents Running](Keeping-Agents-Running) - the Respawn panel in depth.
|
||||
- [Agent CLIs](Agent-CLIs) - model, effort, and permission modes.
|
||||
@@ -0,0 +1,204 @@
|
||||
# The Dashboard
|
||||
|
||||
What the interface is telling you, and which parts of it are hidden until you turn them on.
|
||||
|
||||
Most of Codeman's UI is **opt-in**. A stock install shows a deliberately small header, and a
|
||||
feature you read about here may simply not be on screen yet. Where that is the case, this
|
||||
page says so and names the setting.
|
||||
|
||||

|
||||
|
||||
## Layout
|
||||
|
||||
| Region | What lives there |
|
||||
| ------------------ | -------------------------------------------------------------------------------------- |
|
||||
| **Header, left** | The "C" logo (goes home) and the session list, unless you moved it to the sidebar. |
|
||||
| **Header, right** | Status chips and panel buttons, most of them off by default. |
|
||||
| **Center** | The terminal for the active session, or the home screen when nothing is selected. |
|
||||
| **Bottom toolbar** | Run, Stop, Run Shell, the case picker, and the instance counters. |
|
||||
| **Overlays** | Panels and modals: Respawn, Cron, Subagents, File Viewer, Settings. |
|
||||
|
||||
## Session list layout
|
||||
|
||||
The session list lives in the header as a horizontal strip by default. With a lot of
|
||||
sessions open that strip stops being scannable, so **App Settings → Appearance → Tabs →
|
||||
Session List Layout** can move it into a vertical sidebar on the left instead.
|
||||
|
||||
| Layout | Behaviour |
|
||||
| -------------------- | --------------------------------------------------------------------------------- |
|
||||
| **Header tab strip** | The default. Wraps to a second row on desktop, scrolls sideways on a phone. |
|
||||
| **Left sidebar** | A vertical list with a filter box and a live session count. `Alt+B` collapses it to a narrow rail that keeps the status dots and task badges visible. On a phone it is an off-canvas drawer rather than a docked rail. |
|
||||
|
||||
It is the same list either way, just re-hosted: tab order, drag-to-reorder, the `Alt+1`
|
||||
to `Alt+9` numbers and every status colour below behave identically in both. The setting is
|
||||
per device, so a sidebar on your desktop does not force one onto your phone.
|
||||
|
||||
## Session tabs
|
||||
|
||||
One tab per session, in your order, and that order syncs across your devices.
|
||||
|
||||
**Status is carried by the dot and the tab's own styling:**
|
||||
|
||||
| Look | Meaning |
|
||||
| ----------------------------- | ----------------------------------------------------------------------- |
|
||||
| Green dot | Alive, not currently working. |
|
||||
| Pulsing green dot with a ring | Working on a turn. |
|
||||
| Yellow tab, blinking | The agent is waiting for input from you. |
|
||||
| Red tab, blinking | A question or permission prompt is blocking the session. |
|
||||
| No dot | The session is not running. |
|
||||
|
||||

|
||||
|
||||
The alert states are steady colour with a pulse layered on top, not a blink between the
|
||||
alert colour and nothing, so a tab that needs you looks like it needs you at every point in
|
||||
the cycle. They survive a page reload: the state is re-seeded from the server on load, so
|
||||
reloading while a permission prompt is blocking does not lose the red tab.
|
||||
|
||||
**Navigation:**
|
||||
|
||||
| Action | Keys |
|
||||
| ------------------------------- | ------------------------------------------------------- |
|
||||
| Jump to tab N | `Alt+1` to `Alt+9` (the number on the tab) |
|
||||
| Next / previous | `Ctrl+Tab`, `Alt+[`, `Alt+]` |
|
||||
| Move the active tab | `Ctrl+Shift+{`, `Ctrl+Shift+}` |
|
||||
| Close | `Ctrl+W` |
|
||||
| Find any session, open or past | `Ctrl+K` (also `Cmd+K` and `Alt+K`) |
|
||||
|
||||
Tabs can also be dragged to reorder.
|
||||
|
||||
On phones the strip scrolls horizontally instead of wrapping, and the active tab is always
|
||||
scrolled into view. It is not reordered to the front, so the `Alt+N` numbering stays stable.
|
||||
|
||||
### Lineage arcs
|
||||
|
||||
When one session spawns another (an agent starting a worker through the API), Codeman draws
|
||||
a coloured arc under the strip connecting parent to child, with one colour per child. It is
|
||||
how a fan-out of eight workers stays readable.
|
||||
|
||||
Desktop only, and on by default. Turn it off in **App Settings → Appearance**. Arcs are
|
||||
skipped for tabs scrolled out of the strip.
|
||||
|
||||
## Header controls
|
||||
|
||||
The right side of the header. Almost all of these are off until you enable them in
|
||||
**App Settings → Header & Panels**.
|
||||
|
||||
| Control | Default | What it does |
|
||||
| ---------------------- | ------------------ | ------------------------------------------------------------------------------- |
|
||||
| Connection dot | Always on | SSE connection health. Green is connected. |
|
||||
| Font size `-` / `+` | Always on | `Ctrl +` / `Ctrl -` do the same. |
|
||||
| CPU / MEM bars | On | Server resource use. |
|
||||
| File Viewer | On | Toggles the file browser panel. |
|
||||
| Settings gear | Always on | App Settings. |
|
||||
| Plan usage chip | On, desktop only | Live Claude subscription usage. Claude-only, and needs its telemetry exporter, which the same setting installs. |
|
||||
| Session Manager | Off | The full session list, live and historical. |
|
||||
| Approvals bell | Off | Cross-session queue of prompts waiting on a human. Appears only when the count is above zero. Never shown on phones. |
|
||||
| Read My Mind 🧠 | Off | Predicts your next prompt for this case. Claude-only. |
|
||||
| Attachments | Off | Registered external files. |
|
||||
| Away Digest | Off | What happened while you were gone. |
|
||||
| Last Response | Off | Readable view of the agent's last answer, useful on phones. |
|
||||
| Ultracode / Workflow | Off | Live workflow-run agents. |
|
||||
| Notifications | Off | Notification history and settings. |
|
||||
| Lifecycle Log | Off | Session start, exit, and kill audit trail. |
|
||||
| Cron ⏰ | Off | Scheduled jobs. |
|
||||
| Multi-monitor | Off, macOS | Opens a window spanning every display. |
|
||||
| Tunnel indicator | When a tunnel runs | Cloudflare tunnel status. |
|
||||
| Admin panel | Multi-user only | User administration. |
|
||||
|
||||
New header controls never appear on phones. Phone layout is deliberately minimal and is
|
||||
covered in [Mobile Guide](Mobile-Guide).
|
||||
|
||||
## Connection state
|
||||
|
||||
The dot in the header is the quick read. Two louder surfaces exist because a cached page
|
||||
with no server behind it used to look identical to a page with no sessions:
|
||||
|
||||
- **A full-screen overlay** when the page has never loaded server state. There is nothing
|
||||
behind it worth preserving.
|
||||
- **A banner** when the connection drops after state had loaded, so your scrollback stays
|
||||
readable.
|
||||
|
||||
Both wait about 2.5 seconds before appearing, so a deploy that restarts the server does not
|
||||
flash a warning at you every time. If the browser reports itself offline, the grace period
|
||||
is skipped.
|
||||
|
||||
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.
|
||||
|
||||
## The terminal
|
||||
|
||||
A real terminal: xterm.js in the browser, a real PTY on the server, tmux in between. Full
|
||||
TUIs render correctly.
|
||||
|
||||
Worth knowing:
|
||||
|
||||
- **Scrollback.** The first time you open a session, Codeman pulls the entire tmux
|
||||
scrollback, not just the recent tail. Scrolling to the very top pulls again on demand.
|
||||
- **Wheel and touch scrolling** are forwarded into Claude's own transcript on recent Claude
|
||||
versions, so the wheel scrolls the conversation rather than the terminal. `Shift+Wheel` is
|
||||
always local scrollback. Other CLIs scroll locally.
|
||||
- **Selection copy.** `Ctrl+C` copies when text is selected and interrupts when it is not.
|
||||
`Ctrl+Shift+C` always copies.
|
||||
- **Zero-lag input.** On touch devices, keystrokes paint locally before the round trip. See
|
||||
[Input And Voice](Input-And-Voice).
|
||||
- **Renderer.** WebGL by default, with a watchdog that falls back to DOM rendering if the
|
||||
GPU stalls. `?nowebgl` forces DOM rendering for one page load.
|
||||
|
||||
## The home screen
|
||||
|
||||
With no session selected you get the welcome screen: run buttons for the CLIs Codeman
|
||||
found, a QR code when a password is set, cross-session search, and **Resume Conversation**,
|
||||
which lists past sessions including Claude conversations started outside Codeman entirely.
|
||||
|
||||
Two extras depending on the device:
|
||||
|
||||
- **Desktop, wide windows**: your open tabs appear as a rail docked to the left edge, in tab
|
||||
order, with created and last-active stamps. It needs at least 1180px of width; below that
|
||||
it is hidden so it cannot overlap the search panel.
|
||||
- **Phones**: tapping the "C" logo gives a session overview instead: NEEDS YOU first, then
|
||||
current sessions, then past ones. On by default.
|
||||
|
||||
## Panels
|
||||
|
||||
| Panel | Opened from | Covered in |
|
||||
| ---------------- | --------------------------------- | ---------------------------------------------------------------- |
|
||||
| Respawn | Session Options | [Keeping Agents Running](Keeping-Agents-Running) |
|
||||
| Ralph | Session Options | [Autonomous Loops](Autonomous-Loops) |
|
||||
| Orchestrator | Toolbar | [Autonomous Loops](Autonomous-Loops) |
|
||||
| Cron | Header ⏰ (opt-in) | [Cron Jobs](Cron-Jobs) |
|
||||
| Subagents | Automatic while agents run | [Watching Agents Work](Watching-Agents-Work) |
|
||||
| Ultracode | Header (opt-in) | [Watching Agents Work](Watching-Agents-Work) |
|
||||
| File Viewer | Header | [Working With Files](Working-With-Files) |
|
||||
| Attachments | Header (opt-in) | [Working With Files](Working-With-Files) |
|
||||
| Approvals | Header bell (opt-in) | [Notifications And Approvals](Notifications-And-Approvals) |
|
||||
| App Settings | Header gear | [Settings Reference](Settings-Reference) |
|
||||
|
||||
Session-specific configuration lives in **Session Options**, reachable from the tab. App
|
||||
Settings is global; Session Options is per session.
|
||||
|
||||
## Search and the session palette
|
||||
|
||||
`Ctrl+K` opens the session palette: every session, live or historical, filtered as you
|
||||
type. Picking a past one resumes its conversation.
|
||||
|
||||
The search box on the home screen is wider in scope. It federates over session metadata,
|
||||
run-summary events, and attachment history, filtered by type, case, status, and date. It
|
||||
does substring matching over data already in memory, with no regex and no filesystem reads,
|
||||
so it is fast and cannot be turned into a traversal.
|
||||
|
||||
## Appearance
|
||||
|
||||
**App Settings → Appearance** carries the theme skins, including light ones. The choice is
|
||||
applied before the first paint, so there is no flash of the wrong theme on load.
|
||||
|
||||
The same section has the entrance animations for tabs, terminals, agent windows, and
|
||||
lineage lines. All of them default to the legacy no-animation behaviour, so an untouched
|
||||
install animates nothing.
|
||||
|
||||
## Read next
|
||||
|
||||
- [Keyboard Shortcuts](Keyboard-Shortcuts) - the full list, and how to rebind.
|
||||
- [Settings Reference](Settings-Reference) - every setting, and why some follow you across devices and others do not.
|
||||
- [Mobile Guide](Mobile-Guide) - what changes on a phone.
|
||||
- [Watching Agents Work](Watching-Agents-Work) - subagent windows and workflow runs.
|
||||
@@ -0,0 +1,290 @@
|
||||
# Troubleshooting
|
||||
|
||||
Symptom first. Find the line that matches what you are seeing.
|
||||
|
||||
Before anything else, check what version you are on and whether the problem is already
|
||||
fixed:
|
||||
|
||||
```bash
|
||||
codeman --version
|
||||
codeman doctor
|
||||
```
|
||||
|
||||
## Installing and starting
|
||||
|
||||
### `Failed to start claude: error: posix_spawnp failed` on macOS
|
||||
|
||||
node-pty ships its macOS `spawn-helper` without the executable bit, and macOS launches
|
||||
every PTY through it. Codeman detects this and repairs it on the first failure, so updating
|
||||
usually fixes it outright. To repair by hand on a clone install:
|
||||
|
||||
```bash
|
||||
npm run fix:node-pty
|
||||
```
|
||||
|
||||
It is a `chmod`, not a rebuild, so it does not need Xcode command line tools. The helper
|
||||
lives in `prebuilds/darwin-<arch>/`, not `build/Release/`, which does not exist on macOS.
|
||||
Linux never sees this.
|
||||
|
||||
### `tmux: command not found`
|
||||
|
||||
The installer asks before installing packages and remembers a declined answer. Install tmux
|
||||
and start again. There is no tmux-free mode: sessions live in tmux.
|
||||
|
||||
### The port is already in use
|
||||
|
||||
```bash
|
||||
codeman web --port 8080 # or set CODEMAN_PORT
|
||||
```
|
||||
|
||||
If you believe nothing is on 3000, check for a Codeman you already started:
|
||||
|
||||
```bash
|
||||
codeman web --status
|
||||
```
|
||||
|
||||
### The terminal area is blank, and the console mentions a missing vendor file
|
||||
|
||||
Clone installs build the vendored xterm addon bundles in `postinstall`. If `npm install`
|
||||
was interrupted or run with `--ignore-scripts`, those bundles are missing:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
They are intentionally not committed to the repository.
|
||||
|
||||
### `Case path not found` when clicking Run
|
||||
|
||||
The case points at a directory that no longer exists, usually because it was deleted or
|
||||
moved outside Codeman. Re-link the case, or create it again.
|
||||
|
||||
### The server starts but nothing is reachable
|
||||
|
||||
That is the default behaviour, not a failure. Codeman binds `127.0.0.1`. See
|
||||
[Remote Access](Remote-Access).
|
||||
|
||||
## Reaching the interface
|
||||
|
||||
### The dashboard will not load from another device
|
||||
|
||||
Check, in order: the bind (loopback by default), a firewall, and then
|
||||
[Remote Access](Remote-Access) for a supported way to expose it.
|
||||
|
||||
### `403 host not allowed`
|
||||
|
||||
The Host header is not in the allowlist, which is the DNS-rebinding guard doing its job. Add
|
||||
your domain:
|
||||
|
||||
```bash
|
||||
CODEMAN_ALLOWED_HOSTS='codeman.example.com,.internal.example.com'
|
||||
```
|
||||
|
||||
A leading dot matches subdomains.
|
||||
|
||||
### The page loads but the terminal never connects
|
||||
|
||||
The terminal is a WebSocket. Behind a reverse proxy, the upgrade must be forwarded. The
|
||||
upgrade also runs the Host and Origin checks and closes with code `4003` when they fail.
|
||||
|
||||
### The UI looks stale after updating
|
||||
|
||||
The app shell is cached by a service worker, and static assets are served with a long cache
|
||||
lifetime. `index.html` is not cached, and every asset reference is version-stamped, so a
|
||||
normal reload picks up a new build.
|
||||
|
||||
Two exceptions worth knowing:
|
||||
|
||||
- **iOS Safari** can keep serving old JavaScript until the tab is fully closed, not just
|
||||
reloaded. Close the tab and reopen it.
|
||||
- If you edit files in dev, changes to `index.html` need a server restart. Changes to `.js`
|
||||
and `.css` do not.
|
||||
|
||||
### A full-screen "cannot reach the server" overlay appears
|
||||
|
||||
The server is genuinely unreachable, or the connection dropped. Codeman waits about 2.5
|
||||
seconds before showing it, so a quick restart does not flash it. Retry re-arms both the
|
||||
event stream and the terminal socket.
|
||||
|
||||
## Sessions
|
||||
|
||||
### A session shows idle while it is clearly working
|
||||
|
||||
Update. Claude redraws its prompt roughly once a second throughout a turn, and older idle
|
||||
detection treated that as the end of the turn, flipping working sessions to idle a couple of
|
||||
seconds in. Current versions confirm against the actual screen before believing it.
|
||||
|
||||
### 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).
|
||||
|
||||
### The agent asks about bypass permissions every time
|
||||
|
||||
That prompt comes from Claude Code, not Codeman. Codeman's default is to start with
|
||||
permission prompts skipped, which is what the security model is built around. If you would
|
||||
rather it prompted, change **App Settings → Agents & CLIs → Claude → Startup Mode**.
|
||||
|
||||
### Sessions vanished after a reboot
|
||||
|
||||
Expected. tmux does not survive a reboot, so the sessions are gone. Conversations are not:
|
||||
Claude transcripts persist, so the welcome screen's **Resume Conversation** list can pick
|
||||
them back up.
|
||||
|
||||
### A session restarts, then refuses to restart again
|
||||
|
||||
That is the PTY-exit circuit breaker. Repeated rapid PTY exits trip it, and it blocks
|
||||
automatic restarts so a broken configuration does not spin forever. Reset it explicitly from
|
||||
the session's controls. Reattaching does not clear it, deliberately.
|
||||
|
||||
### Sessions I did not create appeared, or my session resized itself
|
||||
|
||||
Two Codeman servers are running against the same data directory and tmux socket. The second
|
||||
one discovers and attaches the first one's sessions. Give each instance its own scope:
|
||||
|
||||
```bash
|
||||
CODEMAN_INSTANCE=beta CODEMAN_PORT=5000 codeman web
|
||||
```
|
||||
|
||||
`codeman web -d` and `codeman service install` both refuse to start a second server on one
|
||||
data directory for exactly this reason.
|
||||
|
||||
## The terminal
|
||||
|
||||
### I cannot scroll back through history
|
||||
|
||||
Scrollback behaviour depends on the CLI, and Codeman adjusts what it strips per mode.
|
||||
Things to try:
|
||||
|
||||
- `Shift+Wheel` always scrolls the local buffer, whatever else is going on.
|
||||
- On Claude sessions with a recent CLI, the wheel is forwarded into Claude's own transcript,
|
||||
so it scrolls the conversation rather than the terminal buffer. That is intended.
|
||||
- Scrolling to the very top pulls the full tmux scrollback again on demand.
|
||||
|
||||
### The wheel does nothing in a Codex session
|
||||
|
||||
Codex ignores the mouse reports that forwarding would send, so Codeman does not forward
|
||||
there. Scrolling is local, and `Shift+Wheel` behaves the same way.
|
||||
|
||||
### `Ctrl+C` copies when I wanted to interrupt
|
||||
|
||||
With a selection, `Ctrl+C` copies. With no selection, it interrupts. Clear the selection
|
||||
first, or use the **Stop** button. `Ctrl+Shift+C` always copies and never interrupts.
|
||||
|
||||
### I typed a prompt but nothing was sent
|
||||
|
||||
On touch devices, keystrokes are painted locally and flushed when you press Enter, so text
|
||||
on screen has not necessarily reached the agent yet. Press Enter, or the phone toolbar's
|
||||
**Enter** button.
|
||||
|
||||
If you are sending input over the API instead, your payload must end with `\r` or no Enter
|
||||
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).
|
||||
|
||||
## Mobile
|
||||
|
||||
### The keyboard covers the terminal, or scroll position jumps
|
||||
|
||||
Update first; several rounds of fixes have gone into keyboard resize and scroll restoration.
|
||||
|
||||
### I cannot reach the rightmost tabs
|
||||
|
||||
The strip scrolls horizontally on phones and the active tab is scrolled into view
|
||||
automatically. Swipe the strip itself. If a background render snaps you back, update.
|
||||
|
||||
### The space key does nothing on Android
|
||||
|
||||
A long-standing Android keyboard bug, fixed some time ago. Update.
|
||||
|
||||
### The keyboard will not close
|
||||
|
||||
Tap outside the terminal, or tap twice on inert terminal content. Tapping a control does not
|
||||
dismiss it, by design.
|
||||
|
||||
## Agents and CLIs
|
||||
|
||||
### A CLI is installed but Codeman does not offer it
|
||||
|
||||
Codeman resolves binaries from the environment the **server** runs in.
|
||||
|
||||
```bash
|
||||
codeman doctor
|
||||
```
|
||||
|
||||
If it runs as a service, launchd gives the job a minimal PATH. `codeman service install`
|
||||
bakes your PATH into the unit; a hand-written plist does not. Restart the server after
|
||||
installing a new CLI.
|
||||
|
||||
### Hooks stopped working after switching to HTTPS
|
||||
|
||||
Hook callbacks have to accept the self-signed certificate. Recent versions self-heal
|
||||
existing cases; if yours predates that, recreate the case so its hooks are rewritten.
|
||||
|
||||
### The model or effort I chose is not being used
|
||||
|
||||
Both are **soft defaults**, on purpose. The model is written into the case's
|
||||
`.claude/settings.local.json` and effort is passed on the command line at start, so `/model`
|
||||
and `/effort` inside the session override them at any time. Effort is deliberately never
|
||||
passed as an environment variable, because that hard-locks it.
|
||||
|
||||
### Tab alerts and approvals never fire in one of my repos
|
||||
|
||||
That case is missing its hooks block. Recreating the case rewrites it.
|
||||
|
||||
## Docker and remote
|
||||
|
||||
### Docker sessions do not detect idle
|
||||
|
||||
On a loopback-only bind, a container cannot reach `127.0.0.1` on the host, so in-container
|
||||
hooks have nothing to call. Set `CODEMAN_DOCKER_BRIDGE_HOOKS=1` to open a hooks-only
|
||||
listener on the docker bridge gateway. Without it, idle detection falls back to output
|
||||
watching.
|
||||
|
||||
### A rebuilt agent image still has old CLI versions
|
||||
|
||||
Always rebuild with `--no-cache`:
|
||||
|
||||
```bash
|
||||
node scripts/build-agent-image.mjs --no-cache
|
||||
```
|
||||
|
||||
A plain rebuild reuses the cached `npm install -g` layer and keeps the CLIs frozen at their
|
||||
original versions while reporting success.
|
||||
|
||||
### A remote SSH session dropped and did not come back
|
||||
|
||||
A bounded-backoff watcher reattaches dropped sessions, and it is on by default. Intentional
|
||||
kills are never revived. Check the host is reachable and that the remote tmux server is
|
||||
still running.
|
||||
|
||||
## Gathering diagnostics
|
||||
|
||||
```bash
|
||||
codeman doctor # dependency check
|
||||
curl -s localhost:3000/api/status | jq # full app state
|
||||
tmux -L codeman list-sessions # what tmux thinks is alive
|
||||
journalctl --user -u codeman-web -f # service logs (Linux)
|
||||
tail -f ~/.codeman/web.log # detached mode logs
|
||||
```
|
||||
|
||||
On an HTTPS install, add `-k` to the curl commands and use the `https://` URL.
|
||||
|
||||
## Filing a good bug report
|
||||
|
||||
Open an [issue](https://github.com/Ark0N/Codeman/issues) with:
|
||||
|
||||
- OS and version.
|
||||
- Install method: installer, 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.
|
||||
- What you did, what happened, what you expected.
|
||||
|
||||
Reports usually get a response within a day, and every release credits its reporters by
|
||||
name.
|
||||
|
||||
Questions and setup help fit better in
|
||||
[Discussions](https://github.com/Ark0N/Codeman/discussions). Security problems never go in a
|
||||
public issue; see
|
||||
[SECURITY.md](https://github.com/Ark0N/Codeman/blob/master/.github/SECURITY.md).
|
||||
@@ -0,0 +1,72 @@
|
||||
# Versioning
|
||||
|
||||
Codeman follows [semantic versioning](https://semver.org/). This page says what the version
|
||||
number actually promises, which matters if you are building anything against Codeman.
|
||||
|
||||
## Covered by the version number
|
||||
|
||||
Breaking any of these after 1.0 requires a **major** bump:
|
||||
|
||||
1. **The CLI.** Command names, documented flags, and their behaviour. The npm package is
|
||||
`aicodeman` and installs both the `aicodeman` and `codeman` commands; renaming either is
|
||||
breaking.
|
||||
2. **The HTTP API and SSE channel**, served under `/api/v1` with the uniform envelope and
|
||||
conventional status codes. Endpoint paths, the envelope, `errorCode` values, and SSE event
|
||||
names are all stable.
|
||||
3. **Documented deployment environment variables**: `CODEMAN_PASSWORD`, `CODEMAN_USERNAME`,
|
||||
`CODEMAN_HOST`, `CODEMAN_PORT`, `CODEMAN_INSTANCE`, `CODEMAN_ALLOWED_HOSTS`,
|
||||
`CODEMAN_DATA_DIR`, `CODEMAN_TMUX_SOCKET`, plus the `--host`, `--port`, and `--https`
|
||||
flags.
|
||||
4. **The published `xterm-zerolag-input` library**, on its own independent version line.
|
||||
Codeman reaching 1.0 says nothing about that package's version.
|
||||
|
||||
Additive changes are **not** breaking: new endpoints, new optional fields, new error codes,
|
||||
new SSE events. Genuinely breaking API changes would ship under a new prefix rather than
|
||||
changing `/api/v1`.
|
||||
|
||||
## Not covered
|
||||
|
||||
These can change in a minor or even patch release:
|
||||
|
||||
1. **The `~/.codeman/` state file formats.** Migrations are made on a best-effort basis and
|
||||
have been done across renames, but the on-disk shape is not a contract. Do not write
|
||||
tooling against it.
|
||||
2. **Internal TypeScript modules.** The npm package is CLI-only. There is no stable library
|
||||
entry point, and importing it programmatically is unsupported.
|
||||
3. **Experimental and opt-in features**, whatever the app's version: gesture control, agent
|
||||
teams, and anything labelled experimental in the UI or docs.
|
||||
|
||||
## Deprecation
|
||||
|
||||
- Additive changes are preferred over breaking ones.
|
||||
- A covered surface slated for removal is deprecated first: it keeps working for at least one
|
||||
minor release, with a runtime warning and a changelog note pointing at the replacement,
|
||||
then is removed in the next major.
|
||||
- Backwards-compatibility shims are kept until a major boundary.
|
||||
|
||||
## Releases
|
||||
|
||||
Releases are managed with changesets. Every release:
|
||||
|
||||
- Bumps the version and updates
|
||||
[`CHANGELOG.md`](https://github.com/Ark0N/Codeman/blob/master/CHANGELOG.md).
|
||||
- Publishes to npm as `aicodeman`.
|
||||
- Cuts a GitHub release, tagged `codeman@X.Y.Z`.
|
||||
- **Credits its contributors and bug reporters by name** in the release notes.
|
||||
|
||||
There is no fixed cadence. Patches ship when fixes are ready, which in practice is often.
|
||||
|
||||
## Which version am I on?
|
||||
|
||||
```bash
|
||||
codeman --version
|
||||
```
|
||||
|
||||
Or **App Settings → Updates**, which also checks for a newer one and can install it. See
|
||||
[Running As A Service](Running-As-A-Service).
|
||||
|
||||
## Read next
|
||||
|
||||
- [HTTP API](HTTP-API) - the stable API surface itself.
|
||||
- [Contributing](Contributing) - how changes get made.
|
||||
- [`docs/versioning-policy.md`](https://github.com/Ark0N/Codeman/blob/master/docs/versioning-policy.md) - the authoritative statement.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Watching Agents Work
|
||||
|
||||
Modern agents fan out. A single Claude session can be running six subagents, and the parent
|
||||
terminal shows you almost none of it. Codeman surfaces that hidden work as live windows,
|
||||
panels, and after-the-fact summaries.
|
||||
|
||||
Everything on this page is Claude-only. It reads Claude Code's transcripts and team state;
|
||||
the other CLIs expose no equivalent.
|
||||
|
||||

|
||||
|
||||
## Subagent windows
|
||||
|
||||
When a Claude session spawns subagents, each one gets its own floating window with a live
|
||||
transcript: what it was asked to do, what it is doing, and what it returned.
|
||||
|
||||
- Windows are draggable and resizable, and their positions persist across reloads.
|
||||
- A connection line links each window to the session tab that spawned it, so with four
|
||||
sessions running you can still tell whose worker is whose.
|
||||
- Closing a window does not stop the subagent. It only stops you watching it.
|
||||
|
||||
This is the feature that makes a fan-out legible. Without it, a lead session that spawned
|
||||
eight workers looks like a stalled terminal for several minutes.
|
||||
|
||||
## Session lineage arcs
|
||||
|
||||
The tab strip draws a coloured arc from a parent tab to any tab it spawned, one colour per
|
||||
child. That covers the other direction of fan-out: not subagents inside one session, but
|
||||
whole sessions started by an agent through the API.
|
||||
|
||||
Desktop only, on by default, and toggled in **App Settings → Appearance**. Arcs are skipped
|
||||
for tabs scrolled out of view.
|
||||
|
||||
See [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent) for the spawning side.
|
||||
|
||||
## Agent teams
|
||||
|
||||
Claude Code's experimental agent teams appear as teammates alongside subagents. Enable them
|
||||
in the CLI's own environment:
|
||||
|
||||
```bash
|
||||
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
|
||||
```
|
||||
|
||||
and turn the per-case **Agent Teams** toggle on in the case settings gear.
|
||||
|
||||
Codeman watches the team directory and matches teammates to the session leading them.
|
||||
Teammates are in-process threads rather than separate CLI processes, so they show up as
|
||||
windows, not tabs.
|
||||
|
||||
Notes and the experiment log:
|
||||
[`docs/agent-teams/`](https://github.com/Ark0N/Codeman/tree/master/docs/agent-teams).
|
||||
|
||||
## Ultracode and workflow runs
|
||||
|
||||
When Claude runs a Workflow, dozens of agents can be in flight at once. The completion
|
||||
artifact for a run is only written at the **end**, so a live run would otherwise be
|
||||
invisible until it finished. Codeman synthesizes the in-flight view from the transcripts and
|
||||
lets the real artifact supersede it when it lands.
|
||||
|
||||
Two independent toggles, both off by default:
|
||||
|
||||
| Setting | Shows |
|
||||
| ---------------------- | ----------------------------------------- |
|
||||
| Ultracode panel | A docked panel listing the run's agents. |
|
||||
| Ultracode windows | Floating windows, like subagents. |
|
||||
|
||||
Turning on either starts the watcher.
|
||||
|
||||
## Reading the answer, not the terminal
|
||||
|
||||
**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.
|
||||
|
||||
## After the fact
|
||||
|
||||
| Surface | Answers |
|
||||
| ------------------ | -------------------------------------------------------------- |
|
||||
| **Away Digest** | What happened while I was gone? |
|
||||
| **Run summary** | What did this run actually do? |
|
||||
| **Lifecycle log** | When did sessions start, exit, or get killed, and why? |
|
||||
| **Token stats** | What did it cost? |
|
||||
|
||||
The Away Digest aggregates the lifecycle log, run summary events, live sessions, token
|
||||
statistics, and recent subagents into one view. It is the right first thing to open in the
|
||||
morning after an overnight run.
|
||||
|
||||
All of these header buttons are opt-in: **App Settings → Header & Panels**.
|
||||
|
||||
## Performance
|
||||
|
||||
The design target is 20 sessions and 50 agent windows at 60fps. If you routinely run more
|
||||
than that, expect the browser rather than the server to be the limit, and close windows you
|
||||
are not reading.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **A session pointed at a relocated Claude config directory goes blind here.** Transcripts
|
||||
written outside `~/.claude/projects` are invisible to the watchers, so subagent windows,
|
||||
the ultracode panel, the response viewer, and Read My Mind all stop working for that
|
||||
session. Symlink `projects` back into the shared tree to fix it. See
|
||||
[Agent CLIs](Agent-CLIs).
|
||||
- **Closing a window does not cancel the agent.** Nothing on this page controls agents; it
|
||||
observes them.
|
||||
- **Windows are opt-in for ultracode, automatic for subagents.**
|
||||
|
||||
## Read next
|
||||
|
||||
- [The Dashboard](The-Dashboard) - where these surfaces live.
|
||||
- [Driving Codeman From An Agent](Driving-Codeman-From-An-Agent) - the other kind of fan-out.
|
||||
- [Autonomous Loops](Autonomous-Loops) - the loops that generate this much activity.
|
||||
@@ -0,0 +1,101 @@
|
||||
# Web Tabs
|
||||
|
||||
Open any dashboard you run, Grafana, Uptime Kuma, Portainer, a status page on port 4000, as
|
||||
a tab beside your agent sessions. Codeman becomes one mission control instead of Codeman
|
||||
plus a pile of browser tabs.
|
||||
|
||||
A web tab is **not a session**. There is no PTY, no tmux, and no respawn behind it, the same
|
||||
way a docker case is not a run mode.
|
||||
|
||||
## Adding one
|
||||
|
||||
1. Click the chevron next to **Run**.
|
||||
2. Under **Web / URL**, pick **Add URL**.
|
||||
3. Name it, paste the URL, optionally hit **Test**, and **Save**.
|
||||
|
||||
It opens immediately and appears in the dropdown from then on. Web tabs share the tab strip
|
||||
with sessions, continue the same `Alt+1` to `Alt+9` numbering, and carry a globe icon so
|
||||
they never read as a running agent.
|
||||
|
||||
**Closing a tab is not deleting it.** The tab's `x` closes; the `x` on its **dropdown row**
|
||||
deletes the saved dashboard. Each dropdown row also has a gear for editing the URL.
|
||||
|
||||
Switching tabs does not reload a dashboard. Frames stay alive in the background, so one that
|
||||
took a while to authenticate is still there when you come back. Past six live frames, the
|
||||
least recently viewed is dropped to bound memory.
|
||||
|
||||
## Why dashboards are proxied
|
||||
|
||||
A plain cross-origin iframe fails three ways at once in the setup Codeman actually ships in:
|
||||
|
||||
| Blocker | What happens |
|
||||
| ------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| **Mixed content** | Production is HTTPS, and browsers hard-block `http://` iframes on an HTTPS page. No override, and none at all on iOS Safari. |
|
||||
| **Framing refusal** | Grafana, Portainer, Home Assistant and many others send `X-Frame-Options: DENY`. |
|
||||
| **Codeman's CSP** | `default-src 'self'` blocks a cross-origin frame before it starts. |
|
||||
|
||||
So by default the dashboard is served **through Codeman's own origin**: the browser loads a
|
||||
path on Codeman, and Codeman relays to the dashboard, stripping the framing refusal,
|
||||
rewriting redirects, cookies and root-absolute URLs, and relaying WebSockets so live panels
|
||||
still update.
|
||||
|
||||
A useful side effect: the dashboard is fetched **by the Codeman server**, so a tailnet-only
|
||||
or localhost-only dashboard works from any device that can reach Codeman, including a phone
|
||||
that is not on your tailnet.
|
||||
|
||||
There is also a `direct` mode, a plain cross-origin iframe, which is cheaper but only works
|
||||
for an HTTPS dashboard that permits framing.
|
||||
|
||||
## The Test button, and what it does not test
|
||||
|
||||
**Test** probes from the server and tells you which mode applies. It verifies
|
||||
**server-to-upstream reachability and nothing else**. It does not exercise the browser
|
||||
sandbox, cookies, CORS, CSP, or any reverse proxy in front of Codeman.
|
||||
|
||||
A passing Test does not guarantee the embedded page renders.
|
||||
|
||||
## The sandbox, and when to turn it off
|
||||
|
||||
Because a proxied dashboard is served from Codeman's own address, the browser considers it
|
||||
same-origin with Codeman. Unchecked, its JavaScript could read the Codeman page and call the
|
||||
API that spawns agents.
|
||||
|
||||
So the frame is sandboxed **without** same-origin access by default. The page runs in an
|
||||
opaque origin: it cannot touch Codeman, and it gets no cookies or local storage of its own.
|
||||
|
||||
Unchecking **Open sandboxed** grants a real origin. Do that only for a dashboard you fully
|
||||
trust, and only when you need it, which in practice means one with its own login that stores
|
||||
a session in a cookie.
|
||||
|
||||
Either way, Codeman never forwards its own credentials upstream. The `Authorization` header
|
||||
and the `codeman_session` cookie are stripped on the way out, so `CODEMAN_PASSWORD` cannot
|
||||
leak into a dashboard.
|
||||
|
||||
## Known incompatibility: cookie-authenticated reverse proxies
|
||||
|
||||
If Codeman itself sits behind Cloudflare Access, Authelia, oauth2-proxy, or similar, a
|
||||
**sandboxed** tab may render unstyled or broken while the Codeman page around it works fine.
|
||||
|
||||
The reason: an opaque-origin frame's stylesheet, script, and API requests do not carry the
|
||||
proxy's authentication cookie. The proxy redirects them to the login provider, and CORS or
|
||||
CSP kills them there.
|
||||
|
||||
Trusted mode keeps a real origin and the cookie, so it works. Test cannot catch this, because
|
||||
it checks the server's reach, not the browser's.
|
||||
|
||||
## Security notes
|
||||
|
||||
The proxy authenticates on an in-memory capability embedded in the path, which is why it is
|
||||
exempt from the cookie and Origin checks that every API route enforces. That exemption is
|
||||
fenced to safe methods and non-API paths, and there is a test pinning it in place.
|
||||
|
||||
Two failure modes that only appear inside a sandboxed frame, and that curl can never
|
||||
reproduce, are handled: runtime-built root-absolute URLs escaping the injected base, and
|
||||
same-host requests being CORS-checked with a null origin. Both present as the dashboard's own
|
||||
"Failed to fetch" while the page itself renders fine.
|
||||
|
||||
## Read next
|
||||
|
||||
- [The Dashboard](The-Dashboard) - the tab strip these share.
|
||||
- [Security](Security) - why the sandbox default is what it is.
|
||||
- [`docs/web-tabs.md`](https://github.com/Ark0N/Codeman/blob/master/docs/web-tabs.md) - the full reference.
|
||||
@@ -0,0 +1,159 @@
|
||||
# Working With Files
|
||||
|
||||
Reading, editing, attaching, and previewing files without leaving the dashboard. Useful on
|
||||
a desktop; on a phone it is the difference between reviewing an agent's work and waiting
|
||||
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**.
|
||||
|
||||
It renders what it can:
|
||||
|
||||
| Kind | Behaviour |
|
||||
| ------------------------ | ------------------------------------------------------------------------- |
|
||||
| Text and code | Syntax-aware preview. Long files are truncated in plain preview. |
|
||||
| Images | Inline. |
|
||||
| Audio and video | Inline with a working scrub bar, because range requests are supported. |
|
||||
| PDF and Office documents | Converted for preview when a converter is available. |
|
||||
| Anything else | Download. |
|
||||
|
||||
Caps: 10 MB for text preview, 50 MB for raw and download. Sensitive paths (`.env`, anything
|
||||
matching credentials, `~/.ssh`, AWS credentials) are blocked from download, and SVG and HTML
|
||||
are served as downloads rather than rendered, so they cannot execute in the page.
|
||||
|
||||
Closing the preview pauses and unloads any playing media. A video that keeps playing after
|
||||
you close the panel means you are on an old version.
|
||||
|
||||
## Editing in place
|
||||
|
||||
Text files can be edited and saved directly in the viewer. Click the pencil in the preview
|
||||
header, edit, **Save**.
|
||||
|
||||
The guardrails are worth knowing, because they are what makes editing safe rather than
|
||||
convenient:
|
||||
|
||||
- **Extension allowlist**, not a blocklist. Code, docs, config, and markup are editable.
|
||||
Anything not on the list is not.
|
||||
- **512 KB cap** on both read and write.
|
||||
- **Edit mode never truncates.** The plain preview does truncate long files, and saving a
|
||||
truncated buffer would silently delete the rest, so the editor loads the whole file or
|
||||
refuses.
|
||||
- **Optimistic concurrency.** The save carries a hash of what you started from. If the file
|
||||
changed underneath you (likely, when an agent is working in the same repo), the save is
|
||||
rejected rather than clobbering their work.
|
||||
- **No file creation.** Writes go to a temporary file and are renamed over the original, and
|
||||
the open never creates. Editing in place is structural, not a rule.
|
||||
- **Line endings are preserved** server-side, so editing two lines of a CRLF file does not
|
||||
produce a whole-file diff.
|
||||
- **`.git/` is denied outright.** Hooks are executable code, and a corrupted index looks
|
||||
unrecoverable to someone who wanted to fix a typo.
|
||||
- **Non-UTF-8 content is refused**, verified by a round-trip comparison.
|
||||
|
||||
## Attachments
|
||||
|
||||
Attachments are live references to files **outside** the session's workspace: a spec on your
|
||||
desktop, a PDF in Downloads, a design document elsewhere on the machine.
|
||||
|
||||
Register one from the CLI:
|
||||
|
||||
```bash
|
||||
codeman attach /path/to/spec.pdf
|
||||
```
|
||||
|
||||
An attachment card appears in the session, and the file can be previewed inline. The
|
||||
attachment gets a stable id, and browser requests use that id rather than carrying absolute
|
||||
paths around.
|
||||
|
||||
Agents can register attachments too, by emitting a `codeman://attach?...` link in their
|
||||
output. That path is **prompt-injectable by nature**, so it is force-confined to the
|
||||
session's workspace: a hostile prompt cannot use it to pull arbitrary host files into the
|
||||
event stream. The gate is an extension allowlist rather than a blocklist.
|
||||
|
||||
Document conversion for previews is globally rate limited. Without that, ten large documents
|
||||
detected at once would fork ten multi-minute converter processes.
|
||||
|
||||
## Clicking a path
|
||||
|
||||
File paths in a session are links. That works in two places:
|
||||
|
||||
- **In the terminal**, on any absolute path an agent prints.
|
||||
- **In the response viewer**, where paths are usually written as prose or in backticks. They
|
||||
render as underlined monospace links.
|
||||
|
||||
Clicking one opens it in the preview: images and PDFs render, video and audio play with a
|
||||
working scrub bar, documents convert, text and Markdown show inline. Log-shaped files open in
|
||||
the tail viewer instead, which follows a file that is still being written.
|
||||
|
||||
Paths **outside** the session's workspace work too, which matters because that is where most
|
||||
of an agent's output lands: a screenshot in `/tmp`, a capture in its own scratchpad, a file in
|
||||
another checkout. Those are served through the attachment routes rather than the workspace
|
||||
ones, so the same rules apply as to any other attachment: secret trees are blocked, the
|
||||
extension allowlist decides what can be opened, and symlinks are resolved before either check.
|
||||
|
||||
Outside the workspace the allowlist is images, video, audio, PDF, Office documents, and text
|
||||
files, where "text" is the same list the viewer will let you edit: code, config, logs, csv,
|
||||
markdown. The reasoning is that a session can already `cat` any of those, so the file suffix
|
||||
was never what kept anything secret; the path guard is. Types outside the list (`.svg`,
|
||||
`.bmp`) say so rather than failing silently, and `.html` previews as source rather than being
|
||||
rendered, so nothing served this way can execute in the page.
|
||||
|
||||
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.
|
||||
|
||||
Log-shaped files inside the workspace still open in the tail viewer, which follows a file as
|
||||
it is written. Outside the workspace they open in the preview instead: the tail viewer runs
|
||||
`tail -f`, and that is deliberately restricted to the workspace, `/var/log` and `~/logs`.
|
||||
|
||||
Nothing is registered until you click. Opening a file this way does not add an attachment card.
|
||||
|
||||
## The path picker
|
||||
|
||||
For choosing a path rather than typing one. It appears in two places:
|
||||
|
||||
- **Browse** in **Add Case → Link Existing**.
|
||||
- The **📁 Path** key on the mobile keyboard bar.
|
||||
|
||||
It browses one directory at a time and can show hidden entries on request. 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.
|
||||
|
||||
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.
|
||||
|
||||
## Images into a session
|
||||
|
||||
Paste from the clipboard or drag and drop straight onto the terminal. The image is written
|
||||
where the agent can read it and the reference is inserted into your prompt. On a phone, the
|
||||
image key in the keyboard bar opens the camera or photo library.
|
||||
|
||||
HEIC images from an iPhone are converted to JPEG on the way in.
|
||||
|
||||
## Generated artifacts
|
||||
|
||||
When an agent produces a file the UI can show (a chart, a diagram, a document), it can
|
||||
surface as an artifact attachment rather than a path you have to go and find.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **The viewer follows the active session's workspace.** Switching tabs changes what you are
|
||||
browsing.
|
||||
- **A save can be rejected, and that is the feature.** It means the agent edited the file
|
||||
while you were typing. Re-open, re-apply, save again.
|
||||
- **Attachments live outside the workspace on purpose.** For files inside it, just use the
|
||||
viewer.
|
||||
- **`.env` files are readable in the viewer if the extension policy allows the preview, but
|
||||
never downloadable.** Do not treat the viewer as a secrets boundary; treat the machine as
|
||||
the boundary.
|
||||
|
||||
## Read next
|
||||
|
||||
- [The Dashboard](The-Dashboard) - where the panels live.
|
||||
- [Input And Voice](Input-And-Voice) - other ways to get content into a session.
|
||||
- [Security](Security) - how the file surfaces are confined.
|
||||
- [`docs/file-viewer-edit-plan.md`](https://github.com/Ark0N/Codeman/blob/master/docs/file-viewer-edit-plan.md) - the edit-mode design.
|
||||
@@ -0,0 +1,9 @@
|
||||
Documents Codeman **{{VERSION}}**. Something wrong or missing on this page? These pages are
|
||||
generated from [`docs/wiki/`](https://github.com/Ark0N/Codeman/tree/master/docs/wiki) in
|
||||
the main repository, so browser edits here are overwritten on the next sync. Send a pull
|
||||
request against that directory instead, or open a
|
||||
[Discussion](https://github.com/Ark0N/Codeman/discussions).
|
||||
|
||||
<!-- {{VERSION}} is replaced with the current major.minor series by
|
||||
.github/workflows/wiki-sync.yml at publish time. Do not hardcode a
|
||||
version here: it went stale every release when it was hand-written. -->
|
||||
@@ -0,0 +1,53 @@
|
||||
### [Codeman Wiki](Home)
|
||||
|
||||
[README](https://github.com/Ark0N/Codeman)
|
||||
|
||||
**Getting started**
|
||||
|
||||
- [Installation](Installation)
|
||||
- [Quick Start](Quick-Start)
|
||||
- [Core Concepts](Core-Concepts)
|
||||
|
||||
**Using it**
|
||||
|
||||
- [The Dashboard](The-Dashboard)
|
||||
- [Agent CLIs](Agent-CLIs)
|
||||
- [Working With Files](Working-With-Files)
|
||||
- [Input And Voice](Input-And-Voice)
|
||||
- [Mobile Guide](Mobile-Guide)
|
||||
- [Keyboard Shortcuts](Keyboard-Shortcuts)
|
||||
- [Settings Reference](Settings-Reference)
|
||||
|
||||
**Keeping agents running**
|
||||
|
||||
- [Unattended Runs](Keeping-Agents-Running)
|
||||
- [Notifications & Approvals](Notifications-And-Approvals)
|
||||
- [Cron Jobs](Cron-Jobs)
|
||||
- [Autonomous Loops](Autonomous-Loops)
|
||||
- [Watching Agents Work](Watching-Agents-Work)
|
||||
|
||||
**Where it runs**
|
||||
|
||||
- [Docker Cases](Docker-Cases)
|
||||
- [Remote SSH Sessions](Remote-SSH-Sessions)
|
||||
- [Web Tabs](Web-Tabs)
|
||||
- [Multi-User Mode](Multi-User-Mode)
|
||||
|
||||
**Access & security**
|
||||
|
||||
- [Remote Access](Remote-Access)
|
||||
- [Security](Security)
|
||||
|
||||
**Automation**
|
||||
|
||||
- [Driving It From An Agent](Driving-Codeman-From-An-Agent)
|
||||
- [HTTP API](HTTP-API)
|
||||
- [Hooks & Integrations](Hooks-And-Integrations)
|
||||
|
||||
**Operating it**
|
||||
|
||||
- [Running As A Service](Running-As-A-Service)
|
||||
- [Troubleshooting](Troubleshooting)
|
||||
- [FAQ](FAQ)
|
||||
- [Contributing](Contributing)
|
||||
- [Versioning](Versioning)
|
||||
Reference in New Issue
Block a user