The repo now lives outside the homelab monorepo. Drop the homelab-specific deploy files from HEAD (docker-compose.yml, traefik.yml, deploy.sh, deploy.override.yml — canonical copies live in the homelab's services/ai-agent shim; history keeps these as reference), fix stale services/ai-agent path references, and make sidecar/install.sh resolve its .env (SIDECAR_ENV_FILE > repo .env > ~/homelab/.env) and SIDECAR_CWD instead of assuming the monorepo nesting. Mark the GOAL.md repo-split as done. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
83 lines
3.4 KiB
Markdown
83 lines
3.4 KiB
Markdown
# claude-sidecar
|
|
|
|
A tiny **host-side** FastAPI wrapper that launches `claude -p` sessions on behalf
|
|
of the [ai-agent](../) viewer.
|
|
|
|
## Why a host process (not a container)
|
|
|
|
The ai-agent viewer runs in Docker and can't reach the host's `claude` CLI — its
|
|
auth (`~/.claude/.credentials.json`), RTK/vault hooks, and skills all live in the
|
|
host user's home. This sidecar runs natively on the host **as the repo owner**, so
|
|
a session it spawns is exactly like one started from a terminal.
|
|
|
|
## Flow
|
|
|
|
```
|
|
Frontend (sticky input)
|
|
│ POST /api/spawn {prompt}
|
|
▼
|
|
ai-agent backend (container)
|
|
│ generates a session UUID, POST /spawn to the sidecar
|
|
▼ http://host.docker.internal:8790/spawn (Bearer SIDECAR_TOKEN)
|
|
claude-sidecar (host)
|
|
└─ claude -p <prompt> --session-id <uuid> --output-format json \
|
|
--permission-mode bypassPermissions --model opus \
|
|
--remote-control (detached)
|
|
```
|
|
|
|
`--remote-control` is added by default so every spawned run registers with
|
|
Claude Code Remote Control and shows up in the Claude app — you can watch and
|
|
drive the conversation from your phone. Set `SIDECAR_REMOTE_CONTROL=0` to opt
|
|
out.
|
|
|
|
Claude writes its transcript to
|
|
`~/.claude/projects/-home-gabrielvidal-homelab/<uuid>.jsonl`, which the ai-agent
|
|
container already watches read-only. The new conversation appears in the viewer
|
|
within ~2s and the frontend redirects to it once it has synced.
|
|
|
|
The conversation view has a matching sticky composer that continues an existing
|
|
thread: it POSTs `/api/spawn`'s sibling `/api/resume`, which the backend proxies
|
|
to `POST /resume` here — `claude -p <prompt> --resume <sessionId>` in the
|
|
session's original cwd. Because resume reuses the session id, the new turns
|
|
append to the same transcript and stream straight into the open conversation.
|
|
|
|
## Install (host)
|
|
|
|
```bash
|
|
sidecar/install.sh
|
|
```
|
|
|
|
Creates a venv, writes a systemd **user** unit (`~/.config/systemd/user/claude-sidecar.service`),
|
|
and starts it. Reboot survival needs `sudo loginctl enable-linger $USER`.
|
|
|
|
Config comes from the repo `.env`: `SIDECAR_TOKEN`, `SIDECAR_PORT` (default 8790).
|
|
The ai-agent container reads `SIDECAR_URL` + `SIDECAR_TOKEN` (see its
|
|
`docker-compose.yml`, which also adds `host.docker.internal:host-gateway`).
|
|
|
|
## Endpoints
|
|
|
|
- `GET /health` → `{ok, cwd, claude}`
|
|
- `POST /spawn` (Bearer auth) `{prompt, sessionId?, model?, cwd?}` →
|
|
`{sessionId, pid, log}` — spawns detached, returns immediately.
|
|
- `POST /resume` (Bearer auth) `{sessionId, prompt, model?, cwd?}` →
|
|
`{sessionId, pid, log}` — continues an existing conversation by running
|
|
`claude -p <prompt> --resume <sessionId>`. Reuses the original session id, so
|
|
the new turns append to the same transcript and stream into the open
|
|
conversation. `--resume` is directory-scoped, so pass the session's original
|
|
`cwd`.
|
|
- `POST /interrupt` (Bearer auth) `{sessionId}` → `{sessionId, pid, signal, ok}`
|
|
— sends the run's process group a `SIGINT` (like Ctrl+C), so Claude aborts the
|
|
turn, writes a `[Request interrupted by user]` marker and exits. `404` if no
|
|
live process is tracked for that session.
|
|
|
|
Per-session stdout/stderr is captured under `logs/<sessionId>.log`; the pid is
|
|
recorded in `logs/<sessionId>.pid` so `/interrupt` can find the run.
|
|
|
|
## Manage
|
|
|
|
```bash
|
|
systemctl --user status claude-sidecar
|
|
systemctl --user restart claude-sidecar
|
|
journalctl --user -u claude-sidecar -f
|
|
```
|