wiki: CB-108 worker-space placement + herdr unique-name/output-detection facts

Dai Ha
2026-07-13 08:26:38 +02:00
parent aa93ed51c5
commit 8c37bb71c1
2 changed files with 25 additions and 2 deletions
+21 -1
@@ -238,7 +238,7 @@ primary out of herdr — see [Deployment model](#deployment-model).)*
>
> | Call | Params | Returns |
> |---|---|---|
> | `agent.start` | `{name, argv:[...], env:{...}}` | `{agent:{terminal_id, pane_id, workspace_id, agent_status}}` |
> | `agent.start` | `{name, argv:[...], env:{...}, tab_id?}` (8 fields; `tab_id` **honored** — worker lands in that tab, else it splits the focused tab) | `{agent:{terminal_id, pane_id, workspace_id, tab_id, agent_status}}` |
> | `agent.send` | `{target, text}` | ack |
> | `agent.read` | `{target, source}` — `source ∈ visible\|recent\|recent_unwrapped\|detection` | `{read:{text}}` |
> | `agent.get` | `{target}` | `{agent:{…, agent_session:{value:<uuid>}, agent_status}}` |
@@ -248,6 +248,26 @@ primary out of herdr — see [Deployment model](#deployment-model).)*
> `pane.close {pane_id}`. `agent_status ∈ idle\|working\|blocked\|unknown` drives the
> status-gated injector (inject only when idle/blocked).
>
> **CB-108 — worker placement: a tab per worker in a dedicated "worker space."** By default
> `agent.start` (no `tab_id`) *splits the currently-focused tab*, so it would clutter — and could
> co-tenant — the user's real work tabs. Instead `bridged` puts every worker in its **own tab**
> inside a dedicated **workspace** (`worker.workspace`, default `bridged-workers`), found-or-created
> once and shared (a future per-session layout is just a distinct label). The recipe, all verified
> live: `workspace.create {label}` (idempotent find-first) → `tab.create {workspace_id}` →
> `agent.start {…, tab_id}` → `pane.close {root_pane}` (drop herdr's seed shell so the tab holds
> only the worker) → `tab.rename {tab_id, label}`. Teardown: resolve the pane's tab via `pane.get`,
> `pane.close`, then `tab.close` **only if the tab holds one pane** (never a shared user tab). The
> shared space is persistent (its seed tab is a stable anchor); `worker.placement: pane` restores
> the legacy split behaviour.
>
> **Two more `agent.*` facts the CB-108 build pinned:** (1) an agent's **`name` must be unique**
> among running agents — a 2nd `agent.start {name:"claude"}` fails `agent_name_taken`, so `bridged`
> names workers `claude-<profile>-<nonce>-<seq>` (the per-process `nonce` survives a daemon restart
> where old workers linger). (2) herdr detects an agent's **kind and status from terminal output**
> (braille spinner / `❯` prompt patterns in the remote `*.toml` manifests), **not** from `name` — so
> the unique name is a pure label; the detected kind arrives later in `agent.get`/`agent.list`'s
> `agent` field (absent, hence kind unknown, at start-time).
>
> **Two wire facts the Stage-1 client (CB-101) pinned by contract test — both bit the first
> build:** (1) the request `id` **must be a JSON string** — an integer id is rejected with
> `invalid_request`. (2) herdr serves **one request/response per connection, then closes it** —
+4 -1
@@ -128,9 +128,12 @@ comes in Stage 2). This is the thinnest end-to-end vertical slice.
**Definition of done for the stage:** `CB-107` demo passes.
> **Build status (in `bridged/`, Maven · Java 25 · 25 tests green).**
> **Build status (in `bridged/`, Maven · Java 25 · 34 tests green — 29 unit/acceptance + 5 contract).**
> ✅ **CB-101** herdr client — connection-per-call, contract-tested vs live 0.7.0.
> ✅ **CB-102** worker spawn — native `agent.*` with env injection, guard-checked, live-verified.
> ✅ **CB-108** worker placement — one tab per worker in a dedicated, shared **worker space**
> (`worker.placement/workspace/tabLabel`); unique per-worker names; single-pane-guarded, tolerant
> teardown. Reviewed (high-effort multi-agent) and live-verified.
> ✅ **CB-106** config + logging — Jackson YAML + Logback.
> 🟡 **CB-104** REST core — `GET /healthz`, `/sessions`, `/agents`, `POST/DELETE /workers` done;
> the **blocking `POST /sessions/{id}/message` + reply capture** is the remaining piece.