mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-04 22:49:41 +02:00
The wiki was written for seven run modes and never received Grok Build, DeepSeek Harness or OMP. They now appear everywhere the others do: the modes table and per-CLI notes, install commands, environment prefixes, the Quick Start table, the requirements rows, the vocabulary, and every "seven modes" count. The 1.27 to 1.29.0 changes land on the pages that own them: attaching a case to an existing container, multi-case adoption and the copy-a-case picker (Docker Cases); file reads over ssh in remote cases and what stays unavailable (Remote SSH Sessions, Working With Files, Security); single-page app routing, frame recovery, localhost links as tabs and the egress guard (Web Tabs); DeepSeek as the one non-Claude mode with real stop/blocked signals and Approvals items, Codex's own work detection, last-response, the model-endpoint routes and refreshed counts (HTTP API, Driving From An Agent, Hooks, Notifications, Keeping Agents Running, Core Concepts); Shift+drag, right-click copy, Auto Copy, the Ctrl+Z guard, font weight, the vertical rail and its activity sort (Keyboard Shortcuts, Input And Voice, The Dashboard, Settings Reference); the 600px phone cutoff, Codex shift arrows and iPhone Duo (Mobile Guide); the Docker Compose route and its update rule (Installation, Running As A Service); four new symptom entries and a "which CLIs" question (Troubleshooting, FAQ). Custom model endpoints are deliberately left to #430, which adds that page and edits Agent CLIs, Settings Reference and the sidebar; these edits stay out of the regions #430, #428 and #376 touch, and all three still merge cleanly on top. Both READMEs: the web-tab menu entry is labelled "Add URL" in the UI, not "Add dashboard". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
211 lines
7.4 KiB
Markdown
211 lines
7.4 KiB
Markdown
# 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. |
|
|
| Docker Compose | Re-run `Start-Codeman.sh`, or the in-app updater, which restarts the container in place. |
|
|
|
|
### 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.
|
|
|
|
## Running Codeman itself in Docker
|
|
|
|
The Compose deployment in `docker/` runs the server in a container and spawns Docker cases
|
|
as sibling containers through the mounted host socket. Start it with
|
|
`bash docker/Start-Codeman.sh` rather than a bare `docker compose up`: the script pre-creates
|
|
the bind-mounted directories with the right owner, honours a `docker-compose.override.yml`,
|
|
and refreshes the build volumes when the checkout moved under them. The in-app updater
|
|
applies code only and restarts by letting the container exit, so it refuses a release that
|
|
changes the Dockerfile, the compose file, or adds a new `.env` key, until you re-run the
|
|
script. Guide:
|
|
[`docker/README.md`](https://github.com/Ark0N/Codeman/blob/master/docker/README.md).
|
|
|
|
## 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.
|