Herdr for v0 cloud orchestrator
Herdr for v0 cloud orchestrator
Section titled “Herdr for v0 cloud orchestrator”Verdict
Section titled “Verdict”Yes — Herdr can satisfy the locked v0 plan. Confidence: high on session ownership, workspace/agent create, live status, and observe-only streaming; medium on clean DB↔Herdr create/rollback edge cases and durable “agent id” semantics (Herdr’s live targets are pane ids / names, not a separate UUID).
Herdr is the right runtime layer: do not build a custom PTY manager; do not adopt herdr-web (separate Go stack that owns its own PTYs). Own a thin observe bridge + coordinator.
Locked v0 (what we evaluate)
Section titled “Locked v0 (what we evaluate)”From Cloud agent orchestrator (locked 2026-09-26):
| Lock | Intent |
|---|---|
| Herdr owns sessions | Status + I/O API; no DIY PTY |
| Our layer | Local coordinator + SQLite + Web UI |
| Bridge | Observe-only: herdr observe → WebSocket → Ghostty Web; no web PTY control; no web prompt steer (CLI/TUI); not herdr-web |
| SQLite | projects + runs only (no events / shared_context) |
| projects | id, name, path, herdr_workspace_id, created_at |
| runs | id, project_id, herdr_agent_id, started_at — no status column; live state from Herdr |
| Create lifecycle | Insert DB → create Herdr → write id back; on Herdr failure, delete DB row |
| Layout | 1 workspace ↔ 1 project; 1 agent ↔ 1 pane; multiple runs = multiple panes in that workspace |
API / capability checklist
Section titled “API / capability checklist”Sources: Socket API, CLI reference, Agent automation, Persistence and remote access, Quick start. Repo: herdrdev/herdr.
| v0 need | Herdr surface | Fit |
|---|---|---|
| Session ownership (no custom PTY) | Background server; panes keep running across detach; CLI + local socket API | Yes |
| Live agent status (not in SQLite) | agent.list / agent.get; statuses idle / working / blocked / done / unknown; events.subscribe for pane.agent_status_changed | Yes |
| Workspace create (project → workspace) | workspace.create / herdr workspace create [--cwd] [--label] [--no-focus]; returns .result.workspace.workspace_id, .result.tab, .result.root_pane.pane_id | Yes |
| Close / cleanup workspace | workspace.close / herdr workspace close | Yes |
| Pane for each run | Workspace create yields root pane; further runs via pane.split (direction right|down, optional --ratio) | Yes |
| Agent start (run → agent) | agent.start / herdr agent start NAME --kind KIND --pane ID; requires existing available shell pane; does not create layout | Yes (multi-step) |
| Prompt / wait (CLI/TUI, not web) | agent.prompt, agent.wait, agent.read, agent.send-keys | Yes (out of web UI for v0) |
| Observe-only stream for Ghostty Web | herdr terminal session observe <pane|term|agent> [--cols N] [--rows N] → NDJSON terminal.frame (base64 ANSI) + terminal.closed; multiple observers; no input/resize/scroll/takeover | Yes |
| Writable web control (explicitly out of v0) | herdr terminal session control (stdin JSON terminal.input / resize / scroll / release) | Available but do not use in v0 web |
| Snapshot / reconnect bootstrap | session.snapshot / herdr api snapshot; pair with events.subscribe to avoid gaps | Yes (useful for coordinator cache of ids/layout, not status store) |
| Schema introspection | herdr api schema --json | Yes |
| herdr-web as bridge | Separate product; owns PTYs via termhost + libghostty-vt | No — avoid (matches lock) |
Identity note for herdr_agent_id
Section titled “Identity note for herdr_agent_id”Herdr does not document a durable UUID “agent id” independent of layout. Automation targets are:
- Pane id (e.g.
w1:p1) — location of the terminal; survives rename; changes on cross-workspacepane.move - Agent name (e.g.
reviewer) — live alias required byagent start; cleared when the agent exits / is released / is replaced; must match[a-z][a-z0-9_-]{0,31}
Recommendation for the runs.herdr_agent_id column: store the pane id as the durable join key for observe + status (agent get <pane_id>), and treat the agent name as an optional live alias (or derive a stable name from the run id, e.g. run_<short>). Do not assume the name alone survives agent death.
Workspace side is clean: store .result.workspace.workspace_id in projects.herdr_workspace_id.
Gaps / risks
Section titled “Gaps / risks”1. Workspace create APIs — low risk
Section titled “1. Workspace create APIs — low risk”workspace.create is first-class (socket + CLI). Creating a workspace also creates first tab + root pane — good for “first run uses root pane; later runs split.” Capture ids from JSON; do not invent them (Agent automation).
Rollback when Herdr fails before create: delete DB project row — matches lock.
Orphan Herdr after success + crash before write-back: workspace.list / session.snapshot reconcile; GC unmatched workspaces. Document a startup reconcile pass.
2. Agent start APIs — medium risk (multi-step)
Section titled “2. Agent start APIs — medium risk (multi-step)”agent start never creates panes. Run create is at least:
- Insert
runsrow - Ensure pane (reuse workspace root for run #1, else
pane.split) agent start --kind … --pane …- Write pane id (and optional name) back to
runs.herdr_agent_id
Failure modes vs the simple “insert → create → write / rollback delete” story:
| Failure | DB row | Herdr residue | Suggested handling |
|---|---|---|---|
| Split fails | Delete run | None | OK |
Split OK, agent start fails / times out | Delete run | Empty shell pane | Close the new pane (pane.close) if it was created for this run; if it was the shared root pane, leave it |
agent start returns agent_not_ready (blocked at startup) | Name may still exist for read/send-keys | Agent present but not prompt-ready | Treat as partial success or retry after idle; do not blindly delete |
| Crash after Herdr success, before DB write-back | Missing / incomplete run | Live agent + pane | Reconcile via agent.list / pane list; attach or GC |
Also: pane must be at interactive shell prompt before agent start. Coordinator should not leave foreground junk in the pane.
Default start timeout 30s (3s–300s configurable). Integrations improve detection accuracy (herdr integration install …).
3. Observe streaming → Ghostty Web — low–medium risk (build, not capability)
Section titled “3. Observe streaming → Ghostty Web — low–medium risk (build, not capability)”Official observe path matches the lock exactly (Persistence and remote):
herdr terminal session observe w1:p1 --cols 120 --rows 40# NDJSON: terminal.frame { base64 ANSI } … terminal.closedCoordinator work:
- Spawn observe per visible pane; decode frames; push bytes over WebSocket to a browser Ghostty/WASM terminal (e.g. coder/ghostty-web or libghostty-vt WASM). Write path only in the browser — ignore / disable
onDatafor v0. - Pass
--cols/--rowsfrom the web viewport so the rendered surface matches; observe does not take resize ownership (control mode does — out of scope). - Stalled observer: on Linux/macOS, a socket write with no progress for 30s disconnects the observer; may end without
terminal.closed; pane keeps running. Bridge must reconnect. - Do not use
terminal session controlor herdr-web for v0.
Community precedent for browser ANSI over a relay: herdr-outpost (polls herdr agent list, streams ANSI). It also exposes approve/prompt from the browser — richer than v0; steal observe/relay patterns only, not web steer.
4. Rollback / orphan matrix (DB vs Herdr)
Section titled “4. Rollback / orphan matrix (DB vs Herdr)”| Case | Risk | Mitigation |
|---|---|---|
| DB insert, Herdr create fails | Low | Delete DB row (locked) |
| Herdr create OK, DB update fails | Medium | Reconcile + GC or retry attach by listing Herdr |
| Run multi-step: pane without agent | Medium | On failed start, pane.close if pane was run-scoped |
| Agent exits; name cleared; DB still has run | Expected | Status from Herdr shows gone/unknown; keep historical run row; observe may hit terminal.closed |
| Herdr server wipe / new session | High for id validity | Named sessions; detect missing workspace/pane; mark runs inactive or recreate |
Cross-workspace pane.move | Low if avoided | Pane id changes; v0 layout should keep panes in the project workspace |
“No orphan Herdr without DB” is aspirational under crash: you need a reconcile job. “No lingering null-id rows” is enforceable in the happy path by transactional insert → create → update, delete-on-fail.
5. Layout / clipping
Section titled “5. Layout / clipping”1 workspace ↔ 1 project maps cleanly to Herdr workspaces. Multiple agents = multiple panes via splits. Risk: many side-by-side splits clip columns. Mitigations within Herdr (no custom PTY):
- Prefer balanced
pane.splitratios; or new tabs inside the same workspace for overflow (still one workspace ↔ one project) pane.zoomfor focus-one-pane viewing in the native TUI; web UI can show one Ghostty surface per selected run- Avoid packing many agents into one tiny grid in the web view — one observe stream per selected pane is enough for v0
6. Explicitly out of scope (confirm non-blockers)
Section titled “6. Explicitly out of scope (confirm non-blockers)”- Personal-site pulse, Nix packaging, computer-use e2e — not required for Herdr fit
- Herdr Cloud waitlist = connectivity relay, not hosted agents (landscape digest) — irrelevant to v0 local coordinator
- Web prompt steer — defer; use CLI/TUI
agent prompt/ Herdr TUI
Clear recommendation for v0
Section titled “Clear recommendation for v0”- Proceed with Herdr as the session runtime. Fits the locked architecture.
- Build: local coordinator (CLI wrappers or socket client) + SQLite (
projects/runs) + Web UI that only observes viaherdr terminal session observe→ WebSocket → Ghostty Web. - Steer only from CLI/TUI (
agent prompt/ Herdr attach). Do not wire web input toterminal session controlin v0. - Map ids:
herdr_workspace_id← workspace id;herdr_agent_id← pane id (plus optional live agent name). - Create flows:
- Project: insert →
workspace create --cwd <path> --label … --no-focus→ write workspace id (optionally record root pane for run #1). - Run: insert → ensure pane →
agent start→ write pane id; on failure delete run and close run-scoped pane.
- Project: insert →
- Add a reconcile/GC on startup: list Herdr workspaces/agents vs SQLite; close or attach orphans; clear stale ids.
- Do not use herdr-web, do not cache status in SQLite, do not expand schema to events/shared_context in v0.
Related digests / project
Section titled “Related digests / project”- Cloud agent orchestrator — locked v0 scope
- 2026-09-26 Cloud agent orchestrators in the wild — landscape (Herdr vs Cursor Projects vs factories/outpost)
- 2026-09-25 Cursor Project and pstack — product vs playbook context
Sources (fetched 2026-09-26)
Section titled “Sources (fetched 2026-09-26)”- https://herdr.dev/docs/socket-api/
- https://herdr.dev/docs/cli-reference/
- https://herdr.dev/docs/agent-automation/
- https://herdr.dev/docs/persistence-remote/
- https://herdr.dev/docs/quick-start/
- https://github.com/herdrdev/herdr
- https://github.com/rohanthewiz/herdr-web (contrast — not for v0)
- https://github.com/harlanljones/herdr-outpost (browser ANSI relay precedent)
- https://github.com/coder/ghostty-web (browser Ghostty/WASM terminal)
Method: WebSearch, WebFetch, GitHub MCP (search_repositories), vault Read. Did not use Codex. Did not fabricate APIs; checklist items above are cited from current Herdr docs.
Confidence notes: Docs describe observe/control NDJSON and workspace/agent create clearly. Exact JSON field names inside .result.agent beyond the documented return path were not re-verified against a live herdr api schema dump on this box (Herdr may not be installed here) — use herdr api schema --json at implement time for the agent object shape.