Four narrowly-scoped fixes against the LCM + Session Manager lane from an external review of the current backend state. R2 (failed-restore lifecycle stranding) is intentionally deferred to PR #15, which already closes it via the new OnSpawnInitiated path; R3 also stays on that PR. - R1 (BLOCKER): Manager.Spawn never persisted AgentSessionID, so Manager.Restore's hard-required metadata key was always missing and every restore failed. Persist the assembled launch prompt as MetaPrompt at spawn time and add a fresh-launch fallback to Restore that uses Agent.GetLaunchCommand with the seeded prompt when the captured agent session id is absent (the id-capture hook is a separate path that may never have run). Restore still fails fast when neither the id nor a prompt is on hand — there is nothing to relaunch from. - RA (BLOCKER): adapters/workspace/gitworktree/commands.go's worktreeRemoveForceArgs passed --force, which deletes uncommitted agent work. Renamed to worktreeRemoveArgs and dropped --force so the post-prune "still registered" guard in Workspace.Destroy surfaces the refusal to Manager.Cleanup, which routes the session to Skipped instead of destroying in-progress changes. - R11 (SHOULD-FIX): reactions.go's two Notifier.Notify call sites (executeReaction's notify and escalate) built OrchestratorEvent without ProjectID. Captured projectID on the transition (via a store.Get in mutate) and on reactionTracker (so TickEscalations can still populate it on duration-based escalations), and threaded it through executeReaction/sendToAgent/escalate. - RB (SHOULD-FIX): gitworktree.Workspace.managedPath used filepath.Join which cleans .. segments before validateManagedPath ran, so session=\"../other\" stayed inside managedRoot while breaking per-project isolation. validateConfig now rejects path separators and the . / .. components on ProjectID and SessionID at the source. go build ./..., go vet ./..., and go test -race ./... all pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| backend | ||
| docs | ||
| frontend | ||
| .gitignore | ||
| README.md | ||
README.md
agent-orchestrator
Rewrite of the agent-orchestrator: a long-running Go backend daemon (backend/)
paired with an Electron + TypeScript frontend (frontend/).
See docs/ for architecture and status — start with the
Lifecycle Manager + Session Manager lane in docs/architecture.md.
Backend daemon
The Go binary in backend/ is the HTTP daemon — a loopback-only
sidecar the Electron supervisor will spawn (Phase 1c). Phase 1a landed the
skeleton: chi router, middleware stack (recoverer → request-id → logger →
real-ip), /healthz + /readyz, atomic running.json PID/port handshake,
graceful shutdown on SIGINT/SIGTERM.
Run
cd backend
go run . # binds 127.0.0.1:3001 with all defaults
AO_PORT=3019 go run . # override per invocation
Health check:
curl localhost:3001/healthz # {"status":"ok"}
curl localhost:3001/readyz # {"status":"ready"}
Configuration (env only)
The bind host is always 127.0.0.1: the daemon is a loopback-only sidecar
and binding any other interface would be a security regression, so the host
is intentionally not env-configurable.
| Var | Default | Purpose |
|---|---|---|
AO_PORT |
3001 |
bind port; fails fast if taken |
AO_REQUEST_TIMEOUT |
60s |
per-request timeout (Go duration) |
AO_SHUTDOWN_TIMEOUT |
10s |
graceful-shutdown hard cap |
AO_RUN_FILE |
<UserConfigDir>/agent-orchestrator/running.json |
PID + port handshake path |
Test
cd backend
gofmt -l . && go build ./... && go vet ./... && go test -race ./...