Blocked: zot cannot autospawn — spawner uses stdin(Stdio::null()) #143

Closed
opened 2026-06-21 22:30:53 +02:00 by clawdie · 5 comments
Owner

Pi auto-spawns today because pi --mode json is autonomous (emits NDJSON with zero input). Zot's --json exits immediately ("requires a prompt") and rpc blocks on stdin — both fail with stdin(Stdio::null()) (crates/colibri-daemon/src/spawner.rs:321).

What's needed (3 steps)

  1. Capture a real zot rpc transcript on OSA with DEEPSEEK_API_KEY set. Glasspane's parser (zot_event_type) handles the type system but is only tested against hand-written fixtures (crates/colibri-glasspane/src/lib.rs:996) — validate against reality.
  2. Add a zot-rpc spawn path in spawner.rs: switch stdin to Stdio::piped(), add a driver task that sends the task as JSON-RPC and pumps the response stream into glasspane.
  3. Define the task contract. Pi with no prompt runs autonomously (just "one agent alive"). Zot rpc won't sit idle-useful. Decisions:
    • Open an idle-ready session (handshake, keepalive, wait for operator)?
    • Seed a task ("you are Clawdie operator agent, waiting for input")?
    • Both, gated by COLIBRI_AUTOSPAWN_TASK?

Context

  • ADR: docs/ADR-agent-harness-consolidation.md — zot = future default.
  • Runtime proof: zot --json </dev/null exits immediately; zot rpc </dev/null blocks but expects JSON-RPC on stdin.
  • Guardrail: clawdie-iso stage-colibri-iso.sh comment points here.

Not this

  • Config flip (COLIBRI_PI_BINARY=zot) — broken, produces zero agents.
  • Patch zot to add --mode server — ADR forbids forking upstream.
Pi auto-spawns today because `pi --mode json` is autonomous (emits NDJSON with zero input). Zot's `--json` exits immediately ("requires a prompt") and `rpc` blocks on stdin — both fail with `stdin(Stdio::null())` (`crates/colibri-daemon/src/spawner.rs:321`). ## What's needed (3 steps) 1. **Capture a real `zot rpc` transcript** on OSA with `DEEPSEEK_API_KEY` set. Glasspane's parser (`zot_event_type`) handles the type system but is only tested against hand-written fixtures (`crates/colibri-glasspane/src/lib.rs:996`) — validate against reality. 2. **Add a zot-rpc spawn path** in `spawner.rs`: switch stdin to `Stdio::piped()`, add a driver task that sends the task as JSON-RPC and pumps the response stream into glasspane. 3. **Define the task contract.** Pi with no prompt runs autonomously (just "one agent alive"). Zot rpc won't sit idle-useful. Decisions: - Open an idle-ready session (handshake, keepalive, wait for operator)? - Seed a task ("you are Clawdie operator agent, waiting for input")? - Both, gated by `COLIBRI_AUTOSPAWN_TASK`? ## Context - ADR: `docs/ADR-agent-harness-consolidation.md` — zot = future default. - Runtime proof: `zot --json </dev/null` exits immediately; `zot rpc </dev/null` blocks but expects JSON-RPC on stdin. - Guardrail: clawdie-iso `stage-colibri-iso.sh` comment points here. ## Not this - ❌ Config flip (`COLIBRI_PI_BINARY=zot`) — broken, produces zero agents. - ❌ Patch zot to add `--mode server` — ADR forbids forking upstream.
Author
Owner

Step 1 assigned to Hermes (OSA). Capture a real zot rpc transcript (DeepSeek-backed, one full turn with a tool call) to validate glasspane's zot_event_type parser against reality instead of the hand-written fixture (colibri-glasspane/src/lib.rs:996).

Deliverables back: raw line-by-line stdout transcript (secrets redacted); the stdin JSON-RPC request shape sent; and the deciding wire-format answer — does zot rpc emit bare event objects ({"type":"turn_start"}…) or wrap them in a JSON-RPC envelope (jsonrpc/method/params or result)? Plus any type values not in the current mapping.

Steps 2 (zot-rpc spawn path) and 3 (task contract) stay blocked on this transcript.

**Step 1 assigned to Hermes (OSA).** Capture a real `zot rpc` transcript (DeepSeek-backed, one full turn with a tool call) to validate glasspane's `zot_event_type` parser against reality instead of the hand-written fixture (`colibri-glasspane/src/lib.rs:996`). Deliverables back: raw line-by-line stdout transcript (secrets redacted); the stdin JSON-RPC request shape sent; and the deciding wire-format answer — does zot rpc emit bare event objects (`{"type":"turn_start"}`…) or wrap them in a JSON-RPC envelope (`jsonrpc/method/params` or `result`)? Plus any `type` values not in the current mapping. Steps 2 (zot-rpc spawn path) and 3 (task contract) stay blocked on this transcript.
Author
Owner

Step 1 done — real-key transcript landed in docs/ZOT-RPC-TRANSCRIPT.md (PR #146). Confirmed against real output: wire format = bare event objects (no JSON-RPC envelope), request shape {id,type:prompt,message}, and 14 of 15 mapped event types from a full tool cycle (tool_use_start/args/endtool_progresstool_result, plus text_delta streaming, usage with cache/cost, turn_end.stop).

One open item before step 2 trusts it: the standalone tool_call event was not observed in this run — the tool cycle used tool_use_* only. glasspane maps both tool_use_start and tool_call to tool_execution_start, so if zot emits a standalone tool_call on some path it would double-fire (driver must treat the second as a no-op). The doc records this as open, not as fact.

Action (Hermes/OSA): check the full transcript at /tmp/zot_transcript_full.txt for a {"type":"tool_call"} line.

  • If present → paste the line into the doc's raw stdout to substantiate the double-fire, and the driver handles it.
  • If absent → tool_call is dead code in glasspane's mapping for this path; note it and the driver ignores it.

Steps 2 (zot-rpc spawn path) and 3 (task contract) are unblocked either way — this only affects how the driver treats tool_execution_start re-fires.

**Step 1 done** — real-key transcript landed in `docs/ZOT-RPC-TRANSCRIPT.md` (PR #146). Confirmed against real output: wire format = bare event objects (no JSON-RPC envelope), request shape `{id,type:prompt,message}`, and **14 of 15** mapped event types from a full tool cycle (`tool_use_start/args/end` → `tool_progress` → `tool_result`, plus `text_delta` streaming, `usage` with cache/cost, `turn_end.stop`). **One open item before step 2 trusts it:** the standalone `tool_call` event was **not observed** in this run — the tool cycle used `tool_use_*` only. glasspane maps both `tool_use_start` and `tool_call` to `tool_execution_start`, so *if* zot emits a standalone `tool_call` on some path it would **double-fire** (driver must treat the second as a no-op). The doc records this as open, not as fact. **Action (Hermes/OSA):** check the full transcript at `/tmp/zot_transcript_full.txt` for a `{"type":"tool_call"}` line. - If present → paste the line into the doc's raw stdout to substantiate the double-fire, and the driver handles it. - If absent → `tool_call` is dead code in glasspane's mapping for this path; note it and the driver ignores it. Steps 2 (zot-rpc spawn path) and 3 (task contract) are unblocked either way — this only affects how the driver treats `tool_execution_start` re-fires.
Author
Owner

Caveat — zot version bump may invalidate this transcript. The glasspane parser validation here (PR #146) was captured against zot v0.2.29. clawdie-iso #105 pins the image to zot v0.2.42. A version bump can add/rename event type values or shift the wire format.

When v0.2.42 lands on the build host: re-run the step-1 capture (real key, force a tool call) against v0.2.42 and diff the event types against docs/ZOT-RPC-TRANSCRIPT.md. If anything moved, update zot_event_type (colibri-glasspane/src/lib.rs) before the step-2 driver relies on it.

This folds into the still-open step-1 item (confirm whether tool_call ever fires) — do both checks in the same v0.2.42 run.

**Caveat — zot version bump may invalidate this transcript.** The glasspane parser validation here (PR #146) was captured against **zot v0.2.29**. clawdie-iso #105 pins the image to **zot v0.2.42**. A version bump can add/rename event `type` values or shift the wire format. **When v0.2.42 lands on the build host:** re-run the step-1 capture (real key, force a tool call) against v0.2.42 and diff the event types against `docs/ZOT-RPC-TRANSCRIPT.md`. If anything moved, update `zot_event_type` (`colibri-glasspane/src/lib.rs`) before the step-2 driver relies on it. This folds into the still-open step-1 item (confirm whether `tool_call` ever fires) — do both checks in the same v0.2.42 run.
Author
Owner

Pointer: onboarding-simplification work spun out a separate task.

clawdie-iso #110 (merged) makes the live seed importer route an active agent's provider keys into colibri_daemon's provider.env, so a personalized FAT32 seed boots straight into a live auto-spawned agent — zero-touch, no Join Hive click, no Vaultwarden round-trip. This is the seed-partition lever from ONBOARDING-SIMPLIFICATION.md, now implemented (supersedes the xdg-autostart plan).

Follow-up assigned to Hermes (OSA): generate the personalized seed payload → clawdie-iso #111 (clawdie/clawdie-iso#111).

Unrelated to this issue's blocker — #143 stays about the zot-rpc driver (OOTB agent remains pi until that lands). Recording here only so the onboarding thread is cross-linked.

Pointer: onboarding-simplification work spun out a separate task. clawdie-iso #110 (merged) makes the live seed importer route an active agent's provider keys into `colibri_daemon`'s `provider.env`, so a personalized FAT32 seed boots straight into a live auto-spawned agent — zero-touch, no Join Hive click, no Vaultwarden round-trip. This is the seed-partition lever from `ONBOARDING-SIMPLIFICATION.md`, now implemented (supersedes the xdg-autostart plan). Follow-up assigned to Hermes (OSA): generate the personalized seed payload → clawdie-iso #111 (https://code.smilepowered.org/clawdie/clawdie-iso/issues/111). Unrelated to this issue's blocker — #143 stays about the zot-rpc driver (OOTB agent remains pi until that lands). Recording here only so the onboarding thread is cross-linked.
Author
Owner

"Route board tasks to rpc-agent stdin (send_prompt from
task-claim)" — so the tracker reflects reality (the blocker's resolved; only the dispatch
enhancement remains).

"Route board tasks to rpc-agent stdin (send_prompt from task-claim)" — so the tracker reflects reality (the blocker's resolved; only the dispatch enhancement remains).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: clawdie/colibri#143
No description provided.