Skip to content

sandbox daemon: push and streaming surface for live consumers (ranked asks) #2053

Description

@rohitg00

The sandbox daemon's surface is complete for request/response agent use, but everything a live console (or any subscriber) needs is missing: nothing is observable without polling, long output cannot stream, and several state fields never leave the daemon. These asks came out of building the sandbox console surface in iii-hq/workers#762 (plus #766/#767), each was hit in practice, and three now have a second confirmed consumer from live agent sessions.

Ranked by unblocked value:

  1. Lifecycle events on the bus — emit created / ready / stopped / reaped (with reason) as a subscribable trigger. Today the reaper kills VMs invisibly. Workers#762 ships a watcher that polls sandbox::list server-side and re-emits change-only snapshots purely to fake this; that module deletes itself the day the daemon emits its own events.
  2. Streaming exec — stdout/stderr chunk channels on sandbox::exec, plus a truncated flag on ExecResponse (the 1 MiB cap is currently silent). Consumers: live output tail in the console, and shell's sandbox-targeted background jobs, which today can only capture output at completion because they sit on one buffered exec.
  3. Exec cancel — no way to abort a running exec short of stopping the whole sandbox. A hung foreground command holds one of 4 slots for its full timeout. Confirmed twice: the console can only watch, and shell::kill on a sandbox job flips its record but cannot reach the in-VM process.
  4. Idle visibility on sandbox::listidle_secs + idle_timeout_secs (or a computed reap_in_secs) per sandbox. The console ships a dormant TTL countdown that lights up when these fields appear. Client-side approximation is impossible: a viewer cannot see other actors' fs activity, which bumps the idle clock.
  5. sandbox::describe — cpus, memory_mb, network on/off, wall-clock created_at. cpus/memory are dropped after boot today (not retained on the daemon's own state), and created_at is a monotonic Instant that cannot serialize.
  6. Real pull progress — the create-phase events exist but fire after the pull with progress_bytes: 0; cold creates are 5 to 30 seconds of dead air. Byte-level progress during the pull enables an honest boot checklist.
  7. Honor stop.wait — the field is accepted and ignored; callers cannot block on teardown.
  8. Config echo — effective max_concurrent_sandboxes, image allowlist, and defaults are not queryable; exec_slots_free is the only limit that leaks out.
  9. Docs drift — README's sandbox::list response documents fields that do not exist (status, created_at, last_exec_at), FsMatch is documented as {path, line_no, byte_offset, line} vs the actual {path, line, content}, and iii.worker.yaml says "14 triggers" vs the actual 16.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status
Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions