Subprocess Tools: Bounded and Isolated

SubprocessTool hosts an arbitrary external CLI as a Lonis Tool — the thesis made concrete. Decided in ADR-0003.

The wire protocol

DirectionChannelShape
InstdinOne JSON value, then EOF
SuccessstdoutBlocks: JSON array, ndjson lines, or a single block object
Failurestderr + nonzero exitStructured ToolError JSON, propagated verbatim

Anything else on stderr maps to kind tool_failed with the child's exit code. Non-block stdout maps to invalid_output (exit 9).

Bounds are first-class

Every invocation runs under:

  • a hard wall-clock timeout (default 5 s),
  • byte caps on stdout (default 1 MiB) and stderr (default 256 KiB).

Exceeding either kills and reaps the child and reports LIMIT_EXCEEDED (exit 7).

Isolation

Following the amari-discovery probe blueprint: direct exec (no shell), a cleared environment (only PATH inherited, plus explicit additions), and a neutral working directory (the system temp dir, configurable).

Consequence for tool authors: targets arrive via stdin input or argv — never env or cwd.

Availability

A tri-state probe (Ready / Missing / NotExecutable + reason) — a tool the harness knows about may still be absent on this host. invoke on an unavailable tool fails without spawning.

Legacy CLIs

StdoutMapping::Text wraps raw stdout in an attributed result block with a pinned input_hash — grep/jq-style tools work today; prefer real blocks for anything you control.

Legacy text wrap

See Authoring Tools for the Subprocess Seam for the full protocol guide, including streaming (ndjson + flush) and the provider surface.