Protocol and process lifecycle
Run supercast-agent --db PATH for durable storage or --memory for an ephemeral session. The process accepts newline-delimited JSON: one request object per line and one response per nonblank line. Output is flushed after every response so an agent can keep a subprocess open across tool calls.
The protocol is versioned independently from the crate release. Requests currently require version: 1, an ID, and a command object with an op discriminator. Unknown fields are rejected, including nested typed fields.
{"version":1,"id":"request-001","command":{"op":"binary_score","probability":0.3,"outcome":true}}
Success contains result; failure contains error. Every decoded request retains its ID in the response. Malformed or untyped input errors use a null ID because the envelope was not successfully decoded.
IDs and retries
IDs must contain nonwhitespace content and at most 200 UTF-8 bytes. For calculations and reads, an ID is response correlation only. For successful durable mutations, it is a database-wide idempotency key.
Use a new ID for a new intended mutation. After a timeout or lost response, resend the same decoded command and ID. The original receipt is returned, including its original commit timestamp. Whitespace and object-key order do not distinguish decoded commands. Reusing a committed ID with different content is a conflict.
The schema describes structural constraints. Runtime validation adds UTF-8 byte limits, numerical bounds, event lifecycle checks and cross-record relationships that JSON Schema alone does not capture.
Process limits and exits
Each input line is limited to 1 MiB including its newline. An oversized line receives request_too_large and ends the stream before its command executes. Blank lines are ignored. Other request errors return a response and processing continues.
| Exit code | Meaning |
|---|---|
| 0 | Every processed request succeeded |
| 1 | One or more request errors, including oversized input |
| 2 | Startup or I/O failure |
During serving, stdout is reserved for protocol responses. Startup diagnostics go to stderr. --help, --version and --schema are standalone informational modes and do not open a database.
Streaming client obligations
Keep writes and response reads coordinated. Never assume a successful stdin write means the database committed. Confirm the response ID and inspect result versus error. On process failure, restart and retry unresolved mutations with their original IDs.
An application that allows parallel tool calls should serialize access to one process’s stdin/stdout or use one process/connection per worker. SQLite handles database write contention, but it does not multiplex responses for a poorly coordinated client.
The Python demo uses a finite batch, closes stdin, and checks response count and IDs. It also proves that a committed update can be retried after a process restart. It is a subprocess example rather than a native Python binding.