Stdin JSON Agent Protocol & Strict Exit Code Semantics #32
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implement the robust CLI input/output transport and semantic process exit code system for automated agents (OMP, Hermes) and human operators. This includes streaming JSON payloads via standard input (
--input -) to eliminate argument vector data leakage, enforcing clean stdout/stderr channel separation (stdout contains strictly a single JSON envelope when--jsonis supplied), and mapping semantic response states to precise POSIX exit codes (notably exit code 3 for required clarification/approval and exit code 6 for partial, pending, or uncertain outcomes).Background & Technical Rationale
The Process Boundary & Data Leakage Prevention
Automated agent frameworks frequently invoke CLI tools through child processes (
execve/ subprocesses). When tools accept structured payloads via command-line arguments (e.g.--title "My Secret Task"or--json '{"title":"..."}'), sensitive user data, private calendar events, and credentials leak into:/bin/ps,/proc/<pid>/cmdline), accessible by other users and monitoring daemons on the host..bash_history,.zsh_history).auditd).To ensure strict privacy and operational safety, the
lifeCLI requires all complex, structured, or sensitive mutation bodies to be passed through standard input via--input -. The stdin stream is read with an upper size bound (1 MB default) to prevent memory exhaustion from runaway processes.Single Envelope Channel Separation
When
--jsonis passed, the CLI process must guarantee thatstdoutemits exclusively valid JSON consisting of exactly one top-level envelope. Diagnostics, informational logging, tracing spans, and connection warnings must be routed strictly tostderr. This prevents agent JSON parsers from choking on interspersed log lines.Semantic Exit Codes vs HTTP Status Mapping
A standard HTTP client typically maps HTTP 200 to exit code 0 and all HTTP 4xx/5xx errors to exit code 1. This is fundamentally inadequate for automated agent orchestration:
status: "needs_clarification"orstatus: "partial". Treating this as exit 0 causes agents to assume total success and proceed incorrectly.Therefore, the
lifeCLI evaluates the semantic outcome before applying generic HTTP mappings:operation_idto stdout so the agent can investigate vialife operation get <OP_ID> --jsonrather than re-running the command or declaring failure.Exact Technical References & Specifications
1. Exit Code Mapping Contract
From
docs/technical/cli-api.md(lines 11–22):needs_clarification; 403approval_requiredpartialNormative Rule:
2. Common Envelope Structure
From
docs/technical/cli-api.md(lines 7–10):When
erroris present:3. Illustrative Response Envelopes & Exit Scenarios
From
docs/technical/cli-api.md(lines 169–174) &docs/technical/verification.md(lines 103–109):Scenario A: Partial Proposal Application (HTTP 200, Exit 6)
Scenario B: Remote Outcome Uncertain / Timeout (HTTP 200/504/Timeout, Exit 6)
Scenario C: Baseline Conflict (HTTP 412, Exit 4)
4. Normative Error Identifiers
From
docs/technical/cli-api.md(lines 108–127):invalid_input,configuration_invalid-> Exit 2unauthenticated,forbidden-> Exit 1approval_required-> Exit 3clarification_required-> Exit 3not_found-> Exit 2 or 1etag_conflict-> Exit 4idempotency_conflict-> Exit 4proposal_expired-> Exit 2 (HTTP 400);proposal_not_applicable-> Exit 4 (HTTP 409 conflict when re-applying partially applied proposals under fresh keys, Scenario R15) or Exit 2dependency_unavailable-> Exit 5calendar_unsupported-> Exit 2limit_exceeded,cursor_expired-> Exit 2journal_unavailable-> Exit 5operation_unknown,needs_reconciliation-> Exit 6partial_apply,context_pending-> Exit 6judgment_unavailable,judgment_invalid-> Exit 5 or 3internal_error-> Exit 1Formal Citations
docs/technical/cli-api.md:docs/technical/agent-skill.md:docs/technical/verification.md:What to Build
1. Stdin Payload Streaming Reader (
src/cli/input.rs)Implement the standard input reader for command invocations:
--input -is passed, readstd::io::stdin()up to a hard limit of 1,048,576 bytes (1 MB).invalid_input) and write an error envelope to stdout.serde_json::Value. If the JSON is malformed, terminate with exit code 2 and descriptive JSON error envelope.--inputspecifies a file path (for local testing), read that file under the same 1 MB constraint.2. Standard JSON Output & Diagnostic Writer (
src/cli/output.rs)--json:ResponseEnvelope<T>toio::stdout().\n).tracingevents, debug messages, and network status warnings toio::stderr().3. Semantic Exit Code Resolver (
src/cli/exit_code.rs)Implement the resolver converting API HTTP responses or client execution errors into semantic exit codes:
4. Client Timeout & Local Operation Recovery (
src/cli/client.rs)--operation-idwas not explicitly supplied.Idempotency-Keyheader and client request ID asX-Request-ID.status: "partial",error.code: "operation_unknown", and includeoperation_id.stdout.Acceptance Criteria
Observable Assertions & Verification
--input -consumes JSON from standard input, parsing payloads up to 1 MB without error.invalid_inputerror envelope.--json,stdoutemits strictly one parseable JSON object matching theResponseEnvelopeschema, with all tracing/diagnostic messages routed tostderr./proc/<pid>/cmdlineorps auxduring execution oflife task add --input -reveals zero task titles, descriptions, or bearer tokens.status: "needs_clarification"orerror.code: "approval_required"terminate the CLI process with exit code 3 (Scenario I10).status: "partial"orerror.code: "partial_apply"terminate with exit code 6 (Scenario I10, R09).operation_unknownerror envelope containing the generatedoperation_idto stdout and exit with code 6.etag_conflict) terminates with exit code 4.dependency_unavailable) terminates with exit code 5.Notes
partial+operation_unknown+ operation id, exit 6), an unbounded stdin body (now 1 MiB), credentials reachable via--token/LIFE_TOKEN(removed), undocumentedargvpayload flags (removed), and warnings printed to stdout on the human path (now stderr).limit_exceeded/timeout/event cancelentries were corrected in the same commit.life event cancelis documented in the contract but has no CLI verb or route: filed as a follow-up rather than left implied.Blocked by
Issue #032: Stdin JSON Agent Protocol & Strict Exit Code Semanticsto Stdin JSON Agent Protocol & Strict Exit Code Semanticslife event cancel/ POST /v1/events/{id}/cancel #75