Files
byre/docs/operations.md
T

57 lines
4.2 KiB
Markdown
Raw Normal View History

# Operations
## Layout
- `cmd/byre`: `byre serve` runs the server; `byre run` drives one Claude session in the current directory from the terminal.
- `api/openapi.yaml` is the API source of truth. `go generate ./internal/api` regenerates `internal/api/api.gen.go`, whose types are also the store's model types.
- `internal/store`: SQLite (WAL). Every mutation and its event commit in one transaction; events are published to SSE subscribers in `seq` order.
- `internal/server`: HTTP handlers, identity, SSE.
- `internal/git`: worktree create and remove.
- `internal/agents`: the agent session manager. It owns the running Claude processes and records their activity as events.
- `internal/claude`: the Claude Code stream-json client (see `docs/claude-protocol.md`).
- `internal/report`: the `report` MCP tool and the Stop hook that requires it each turn.
- `web/`: the SPA, embedded into the binary. `byre serve --dev` serves `./web` from disk instead (run from the repo root).
## Data
State lives in the `byre` directory under Go's `os.UserConfigDir()` (on macOS, `~/Library/Application Support/byre`): `byre.db` and `worktrees/<project-id>/<task-id>`. Task branches are `byre/<task-id>` in the project's repo.
## Running as a service
The listen address is `listenAddr` in `cmd/byre/serve.go`; it binds loopback only.
```
go install ./cmd/byre
cp deploy/run.fc.byre.plist ~/Library/LaunchAgents/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/run.fc.byre.plist
tailscale serve --bg --https=<port from listenAddr> http://<listenAddr>
```
byre gets its own HTTPS port on the machine's `ts.net` name rather than a path under another service: the SPA and API use absolute paths, which break under a path prefix. `tailscale serve status` shows the URL and what else the machine serves.
After rebuilding: `go install ./cmd/byre && launchctl kickstart -k gui/$(id -u)/run.fc.byre`. Logs go to `~/Library/Logs/byre.log`.
Clients reach `tailscale serve` over HTTP/2; it proxies to byre over HTTP/1.1 and passes SSE through unbuffered.
## Identity
`tailscale serve` adds `Tailscale-User-Login` and `Tailscale-User-Name` to proxied requests. The server accepts API requests only from loopback and only with both headers; anything else gets 401 or 403. The SPA's static files need no identity. Users are created on first request; each sets their commit identity with `PUT /api/me`.
To call the API locally without Tailscale, send the headers yourself:
```
curl -H 'Tailscale-User-Login: you@example.com' -H 'Tailscale-User-Name: You' http://<listenAddr>/api/me
```
## Agent sessions
`POST /api/tasks/{id}/sessions` starts a Claude session in the task's worktree and sends the prompt as its first turn; `POST /api/sessions/{id}/messages` starts later turns and `POST /api/sessions/{id}/interrupt` ends the current one. A task has at most one session that isn't `completed`. The session's commits use the git identity of the user who created it, so that user must have set one with `PUT /api/me`.
byre chooses the Claude session ID (`vendor_session_id`) up front, so every session can be resumed. Processes start on demand: the first message after a restart resumes the session with `--resume`. Sessions are `running` from the moment a turn is sent until its `result` arrives; on startup, every session still marked `running` was cut off mid-turn, and byre resumes it and sends a message telling the agent to re-check the working tree. Stopping the server kills all agent processes. Completing a task kills its sessions and marks them `completed`.
Agent activity becomes events with `agent_session_id` set: `user.message`, `agent.message`, `agent.thinking`, `agent.tool_call`, `agent.tool_result`, `agent.report`, `turn.ended`, and `session.state`. Anything else Claude Code emits (rate-limit status, task progress, state changes) is recorded unchanged as `agent.vendor`.
## Events
`GET /api/events` is server-sent events: `id` is the event's `seq`, `data` the Event JSON. Reconnecting with `Last-Event-ID` (EventSource does this itself) or `?after=` replays everything after that seq before going live. A client that falls further behind than its subscriber buffer (`subscribe` in `internal/server/hub.go`) is disconnected and catches up by reconnecting.