Skip to content

Tracking: Go HTTP Daemon — REST #10

@neversettle17-101

Description

@neversettle17-101

⚠️ Disclaimer: This issue is primarily focused on defining interfaces and service boundaries. Implementation details, data models, and internal wiring are intentionally pushed to later phases — the goal right now is to agree on the shape of the system before writing any code.


Tracking issue for the Go HTTP Daemon lane of the backend rewrite.

Goal

Replace the current Next.js API routes with a single Go binary on 127.0.0.1:3001 that serves:

  • /api/v1/* — REST endpoints (25 routes, path-parity with current TS)

The daemon is spawned as a sidecar child process by the Electron main process, supervised over loopback only. No auth, no CORS, no public URL.

Approach: phase-by-phase, contract-first

feat/go-http-daemon is the lane integration branch: every sub-PR branches off it and merges into it; the whole lane lands on main as one unit once complete.

Design doc & HTML overview: https://htmlpreview.github.io/?https://gist.githubusercontent.com/neversettle17-101/00c659adf978b80b1e2eb600d451932a/raw/ao-backend-rewrite-phase1.html


Startup sequence

1. Electron main spawns ./ao-daemon
2. Daemon binds :3001, starts listening
3. Main polls /healthz until ready
4. Renderer connects and loads UI

TODO — open question: How are agent sessions & projects loaded on daemon startup?
Warm cache from disk, lazy-load on first request, or explicit restore step?


PR sequence

Phase 1 — HTTP server skeleton + Electron integration

  • 1a — Skeleton — Go module init, config (port, env), 127.0.0.1 bind, 5-middleware stack (recoverer → request ID → logger → real IP → timeout), /healthz + /readyz, graceful shutdown (10s timeout, SIGTERM/SIGINT)

  • 1b — Route shell — All 25 routes registered under /api/v1 as 501 Not Implemented stubs; subrouter layout (/events, /mux, /api/v1, /) with correct middleware applied per surface

  • 1c — Electron integrationembed.FS static serving, Electron main process spawns + supervises daemon, health-check polling before renderer connects, dev proxy (Next.js :3000 → Go :3001), packaged build with extraResources

  • Sessions — list (with ?project, ?active, ?orchestratorOnly, ?fresh), get, spawn, kill, message, send, restore

  • Projects — list, get, reload

  • Issues, backlog, PRsGET /issues, GET /backlog, POST /prs/:id/merge

  • MetaGET /version, POST /update, POST /webhooks/*

  • Unclear routes remain explicit no-ops — /remap, /patches, /orchestrators, /observability, /verify, /setup-labels


Key decisions (settled)

# Decision
Framework chihttp.Handler-compatible, subrouters, standard middleware ecosystem
Port strategy Single port localhost:3001 — same-origin, no CORS, one token, one lifecycle
State push SSE for backend → frontend; WS reserved for terminal (/mux) only
Route surface 25 routes at exact path parity with current TS under /api/v1; unclear routes ship as no-ops
Port binding Bind 127.0.0.1 only; default 3001; fail fast on conflict
Shutdown signal.NotifyContext; 10s hard timeout; SSE connections just closed (EventSource auto-reconnects)
Middleware recoverer → request ID → logger → real IP → timeout (timeout on /api/v1 only)
Future split 6 disciplines adopted day-one so a port split stays a ~50-line change, not a rewrite

Open items

  • TODO — How are agent sessions & projects loaded on daemon startup? (warm cache, lazy-load, or explicit restore)
  • Q1.3 — Error envelope shape + /api/v1 versioning strategy
  • Q1.5 — OpenAPI: hand-written spec vs. code-first vs. spec-first codegen
  • Q1.6 — Static asset embed.FS cache-control headers
  • Q1.11 — Filesystem routes (/api/v1/filesystem/browse) — native machine FS design pending
  • Phase 2 blocker — Event taxonomy (which events each topic emits, exact payload shapes) must be agreed before wiring frontend dispatch
  • Q2.x — WebSocket /mux full design (mux semantics, framing, backpressure, auth on upgrade)

Architecture overview

┌─────────────── Electron App ───────────────────────┐
│  Renderer (React)  ←IPC→  Main process (Node.js)   │
│                               │ spawn + supervise   │
└───────────────────────────────┼────────────────────┘
                                │ HTTP + WS
                                ▼ 127.0.0.1:3001
                    ┌───────────────────────────┐
                    │  Go daemon                │
                    │  /            static      │
                    │  /api/v1/*    REST         │
                    │  /events      SSE          │
                    │  /mux         WS terminal  │
                    └───────────────────────────┘

Open contract questions — for integration partners

  • PersistenceLifecycleStore adapter: does the storage layer expose what the Go daemon needs for session read-model? (Tom)
  • SCM facts — does the SCM poller output match what /api/v1/issues + /api/v1/backlog need to read? (adil)
  • API shape — are the 25 route response shapes OpenAPI-friendly as-is, or do we need a normalisation pass before Phase 3? (aditi)
  • Event taxonomy — which events does each SSE topic (sessions, prs, ci) actually emit, and what are the payload shapes? (all lanes)

Owner: @neversettle17-101

Metadata

Metadata

Labels

coreCore FunctionalitydaemonHTTP daemon lane

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions