Transport-level routing for MCP/ACP protocols
stdio Bus Specificationv0.1.0
Normative specification for Agent Transport OS (stdio Bus), a minimal, deterministic stdio-based kernel in C providing transport-level routing for ACP/MCP-style agent protocols.
1. Introduction
1.1 Purpose
This document defines the normative specification for Agent Transport OS (stdio Bus), a deterministic stdio-based kernel in C providing transport-level routing for ACP/MCP-style agent protocols.
1.2 Scope
This specification covers:
- Entity model and terminology
- Client-to-Daemon contract
- Worker-to-Daemon contract
- Routing rules
- Failure and recovery model
- Resource limits and configuration
This specification does NOT cover:
- Protocol semantics (ACP, MCP, JSON-RPC validation)
- Worker implementation details
- Platform-specific implementation internals
1.3 Conformance
The key words "SHALL", "SHOULD", "MAY", "MUST", "MUST NOT", "REQUIRED", "RECOMMENDED", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
1.4 References
- RFC 2119: Key words for use in RFCs to Indicate Requirement Levels
- JSON-RPC 2.0 Specification
- NDJSON (Newline Delimited JSON) format
2. Terminology and Definitions
2.1 Entity Model
| Entity | Definition |
|---|---|
| stdio_Bus_Daemon | The main cos process that manages workers and routes messages between clients and workers. |
| Client | An external connection (via stdio, Unix socket, or TCP) that sends messages to stdio_Bus_Daemon. |
| Worker | A child process spawned by stdio_Bus_Daemon that handles protocol logic. Workers communicate via stdin/stdout pipes. |
| Session | A logical grouping of messages identified by sessionId with worker affinity. |
| Request | A JSON-RPC message with an id field expecting a response. |
| Notification | A JSON-RPC message without an id field (no response expected). |
| Response | A JSON-RPC message containing result or error field in reply to a Request. |
2.2 Message Format
| Term | Definition |
|---|---|
| NDJSON | Newline-delimited JSON format. Each message is a single JSON object followed by a newline character (\n). |
| Routing Fields | The id, sessionId, and method fields extracted from JSON messages for routing purposes. |
2.3 Connection Types
| Type | Definition |
|---|---|
| Client Connection | A connection from an external client to stdio_Bus_Daemon. |
| Worker Connection | The stdin/stdout pipe pair between stdio_Bus_Daemon and a Worker process. |
3. Entity Model
3.1 stdio_Bus_Daemon
The stdio_Bus_Daemon is the central process that:
- SHALL read configuration from a JSON file at startup
- SHALL spawn and monitor Worker processes according to pool definitions
- SHALL accept Client connections via one of three operating modes
- SHALL route messages between Clients and Workers based on routing rules
- SHALL operate in a single thread using non-blocking I/O
- SHALL handle graceful shutdown on SIGTERM or SIGINT
3.2 Client
A Client represents an external connection to stdio_Bus_Daemon:
- A Client SHALL connect via one of: stdio, Unix domain socket, or TCP socket
- A Client SHALL send NDJSON-formatted messages
- A Client MAY have multiple Sessions associated with it
- A Client connection SHALL be uniquely identified by its file descriptor
3.3 Worker
A Worker is a child process managed by stdio_Bus_Daemon:
- A Worker SHALL be spawned via fork/exec with stdin/stdout pipes
- A Worker SHALL read NDJSON messages from stdin
- A Worker SHALL write NDJSON responses to stdout
- A Worker SHOULD write diagnostic output to stderr (not stdout)
- A Worker SHALL handle SIGTERM for graceful shutdown
- A Worker SHALL be uniquely identified by a Worker ID (integer)
3.4 Session
A Session provides worker affinity for related messages:
- A Session SHALL be identified by a
sessionIdstring - A Session SHALL be bound to exactly one Worker
- A Session SHALL be owned by exactly one Client
- A Session SHALL be invalidated when its Worker exits
- A Session SHALL be invalidated when its owning Client disconnects
3.5 Request
A Request is a message expecting a response:
- A Request SHALL contain an
idfield - A Request SHALL contain a
methodfield - A Request MAY contain a
sessionIdfield - A Request MAY contain a
paramsfield
4. Client-to-Daemon Contract
4.1 Connection Semantics
4.1.1 Operating Modes
| Mode | Flag | Description |
|---|---|---|
| stdio | --stdio | Single Client via stdin/stdout (default) |
| Unix socket | --unix <path> | Multiple Clients via Unix domain socket |
| TCP | --tcp <host:port> | Multiple Clients via TCP socket |
4.1.2 Connection Lifecycle
- In stdio mode, there SHALL be exactly one Client connection
- In socket modes, stdio_Bus_Daemon SHALL accept multiple concurrent Client connections
- A Client connection SHALL remain open until: the Client closes the connection, stdio_Bus_Daemon closes the connection due to error or resource limits, or stdio_Bus_Daemon initiates graceful shutdown
4.2 Message Format Requirements
4.2.1 Input Format
- Clients SHALL send messages in NDJSON format (one JSON object per line)
- Each message SHALL be a valid JSON object
- Each message SHALL be terminated by a newline character (
\n) - Messages SHOULD conform to JSON-RPC 2.0 structure
4.2.2 Routing Fields
| Field | Type | Purpose |
|---|---|---|
id | string or number | Request-response correlation |
sessionId | string | Session-based worker affinity |
method | string | Request identification |
Note: stdio_Bus_Daemon performs minimal JSON parsing. It SHALL NOT validate complete JSON-RPC structure beyond extracting routing fields.
4.2.3 Output Format
- stdio_Bus_Daemon SHALL forward Worker responses to Clients in NDJSON format
- Each response SHALL be terminated by a newline character (
\n) - stdio_Bus_Daemon SHALL NOT modify message content (pass-through)
4.3 Malformed Input Handling
- If a Client sends data that cannot be parsed as JSON, stdio_Bus_Daemon SHALL close the Client connection
- If routing fields cannot be extracted, stdio_Bus_Daemon SHALL log a warning and close the Client connection
- stdio_Bus_Daemon SHALL NOT validate JSON-RPC semantics (e.g., required fields, method existence)
5. Worker-to-Daemon Contract
5.1 I/O Expectations
5.1.1 Input (Worker stdin)
- stdio_Bus_Daemon SHALL write NDJSON messages to Worker stdin
- Each message SHALL be terminated by a newline character (
\n) - Messages SHALL be forwarded unchanged from Client input
5.1.2 Output (Worker stdout)
- Workers SHALL write NDJSON responses to stdout
- Each response SHALL be terminated by a newline character (
\n) - Workers SHALL NOT write non-JSON content to stdout
5.1.3 Diagnostic Output (Worker stderr)
- Workers SHOULD write logs and diagnostics to stderr
- stdio_Bus_Daemon SHALL NOT process Worker stderr content
- Worker stderr output is implementation-defined (TBD: whether it is forwarded or discarded)
5.2 Response Requirements
5.2.1 Request-Response Correlation
- For each Request received, a Worker SHOULD send exactly one Response
- The Response SHALL contain the same
idas the Request - The Response SHALL contain either a
resultfield or anerrorfield
5.2.2 Session Preservation
- If a Request contains a
sessionId, the Response SHOULD include the samesessionId - Notifications sent by Workers SHOULD include
sessionIdfor routing
5.3 Malformed JSON Handling
- Log an error with Worker context
- Invalidate all Sessions assigned to that Worker
- Terminate the Worker (send SIGTERM)
- Attempt to restart the Worker per restart policy
6. Routing Rules
Loading diagram...
6.1 Session-Based Routing (Client → Worker)
6.1.1 New Session Assignment
sessionId not in the Session table:- stdio_Bus_Daemon SHALL assign a Worker using round-robin selection
- stdio_Bus_Daemon SHALL create a Session entry mapping
sessionIdto the assigned Worker - stdio_Bus_Daemon SHALL record the Client as the Session owner
6.1.2 Existing Session Routing
sessionId in the Session table:- stdio_Bus_Daemon SHALL route the message to the assigned Worker
- stdio_Bus_Daemon SHALL NOT reassign the Session to a different Worker
6.1.3 No Session Routing
sessionId:- stdio_Bus_Daemon SHALL route the message using round-robin Worker selection
- stdio_Bus_Daemon SHALL NOT create a Session entry
6.2 Request-Based Routing (Client → Worker)
id field (Request):- stdio_Bus_Daemon SHALL record the
idin the pending Request table - stdio_Bus_Daemon SHALL associate the
idwith the originating Client - stdio_Bus_Daemon SHALL associate the
idwith the target Worker
6.3 Response Routing (Worker → Client)
6.3.1 Response Messages
result or error field (Response):- stdio_Bus_Daemon SHALL look up the
idin the pending Request table - If found, stdio_Bus_Daemon SHALL route the Response to the originating Client
- stdio_Bus_Daemon SHALL remove the entry from the pending Request table
- If not found, stdio_Bus_Daemon SHALL log a warning and discard the Response
6.3.2 Notification Messages
sessionId but no result/error (Notification):- stdio_Bus_Daemon SHALL look up the
sessionIdin the Session table - If found, stdio_Bus_Daemon SHALL route the Notification to the Session owner
- If not found, stdio_Bus_Daemon SHALL log a warning and discard the Notification
6.3.3 Unroutable Messages
id with result/error nor sessionId:- stdio_Bus_Daemon SHALL log a warning
- stdio_Bus_Daemon SHALL discard the message
7. Failure and Recovery Model
7.1 Worker Exit Handling
7.1.1 Detection
- stdio_Bus_Daemon SHALL detect Worker exit via SIGCHLD signal
- stdio_Bus_Daemon SHALL reap exited Workers using waitpid with WNOHANG
7.1.2 Cleanup
- Transition Worker state to STOPPED
- Close communication file descriptors
- Invalidate all Sessions assigned to that Worker
- Discard all pending Requests to that Worker (log warnings)
7.1.3 Restart Policy
- stdio_Bus_Daemon SHALL attempt to restart Workers that exit unexpectedly
- stdio_Bus_Daemon SHALL use exponential backoff for restart delays
- stdio_Bus_Daemon SHALL stop restarting if
max_restartsis exceeded withinrestart_window_sec
7.2 Client Disconnect Handling
- Invalidate all Sessions owned by that Client
- Discard all pending Requests from that Client
- Close the Client connection file descriptor
7.3 Queue Overflow Behavior
7.3.1 Output Queue Overflow
max_output_queue:- stdio_Bus_Daemon SHALL apply backpressure (pause reading from corresponding input)
- stdio_Bus_Daemon SHALL record the timestamp when the queue became full
max_output_queue:- stdio_Bus_Daemon SHALL release backpressure (resume reading)
backpressure_timeout_sec:- stdio_Bus_Daemon SHALL close the connection
7.3.2 Input Buffer Overflow
max_input_buffer:- stdio_Bus_Daemon SHALL close the connection
- stdio_Bus_Daemon SHALL log an error with connection context
8. Resource Limits
8.1 Default Values
| Limit | Default Value | Description |
|---|---|---|
max_input_buffer | 1,048,576 (1 MB) | Maximum bytes buffered per input connection |
max_output_queue | 4,194,304 (4 MB) | Maximum bytes queued per output connection |
max_restarts | 5 | Maximum Worker restarts within time window |
restart_window_sec | 60 | Time window for counting restarts (seconds) |
drain_timeout_sec | 30 | Graceful shutdown timeout (seconds) |
backpressure_timeout_sec | 60 | Close connection if queue full this long (seconds) |
8.2 Hard-Coded Limits
| Limit | Value | Description |
|---|---|---|
MAX_CONNECTIONS | 1024 | Maximum number of file descriptors |
STDIO_BUS_MAX_SESSIONS | 1024 | Maximum number of active Sessions |
STDIO_BUS_MAX_PENDING_REQUESTS | 4096 | Maximum number of pending Requests |
STDIO_BUS_MAX_SESSION_ID_LEN | 256 | Maximum length of sessionId string |
STDIO_BUS_MAX_REQUEST_ID_LEN | 128 | Maximum length of request id string |
8.3 Limit Enforcement
- stdio_Bus_Daemon SHALL enforce
max_input_bufferby closing connections that exceed it - stdio_Bus_Daemon SHALL enforce
max_output_queueby applying backpressure - stdio_Bus_Daemon SHALL enforce
max_restartsby stopping Worker restart attempts - stdio_Bus_Daemon SHALL enforce
backpressure_timeout_secby closing stalled connections
9. Configuration Schema
9.1 Configuration File Format
--config <path>.9.2 Schema Definition
config.json
{"pools": [{"id": "string", // REQUIRED: unique pool identifier"command": "string", // REQUIRED: executable path"args": ["string", ...], // OPTIONAL: command-line arguments"instances": number // REQUIRED: number of worker instances (≥1)}],"limits": {"max_input_buffer": number, // OPTIONAL: per-FD input buffer limit (bytes)"max_output_queue": number, // OPTIONAL: per-FD output queue limit (bytes)"max_restarts": number, // OPTIONAL: max restarts within time window"restart_window_sec": number, // OPTIONAL: time window for restart counting"drain_timeout_sec": number, // OPTIONAL: graceful shutdown timeout"backpressure_timeout_sec": number // OPTIONAL: backpressure timeout}}
9.3 Validation Rules
- The
poolsarray SHALL contain at least one pool definition - Each pool SHALL have a unique
id - Each pool SHALL have a valid
commandpath - Each pool SHALL have
instances≥ 1 - If
limitsis omitted, default values SHALL be used - If individual limit fields are omitted, default values SHALL be used
10. Graceful Shutdown
10.1 Shutdown Trigger
10.2 Shutdown Sequence
- Stop accepting new Client connections (close listening socket if applicable)
- Send SIGTERM to all running Workers
- Wait up to
drain_timeout_secfor Workers to exit - Send SIGKILL to any remaining Workers
- Clean up all resources (close file descriptors, free memory)
- Exit with code 0
Appendix A: Return Codes
| Code | Name | Value | Description |
|---|---|---|---|
STDIO_BUS_OK | Success | 0 | Operation succeeded |
STDIO_BUS_ERR | Error | -1 | Generic error |
STDIO_BUS_EAGAIN | Would Block | -2 | Non-blocking I/O would block |
STDIO_BUS_EOF | End of File | -3 | Connection closed |
STDIO_BUS_EFULL | Buffer Full | -4 | Buffer or queue limit exceeded |
STDIO_BUS_ENOTFOUND | Not Found | -5 | Resource not found |
STDIO_BUS_EINVAL | Invalid | -6 | Invalid argument |
Appendix B: Worker States
| State | Description |
|---|---|
STARTING | Worker is being spawned (fork/exec in progress) |
RUNNING | Worker is running and accepting messages |
STOPPING | Worker is being terminated (SIGTERM sent) |
STOPPED | Worker has exited and been reaped |
Appendix C: Log Levels
| Level | Description |
|---|---|
DEBUG | Debug-level messages (verbose) |
INFO | Informational messages |
WARN | Warning messages |
ERROR | Error messages |
All log messages SHALL be written to stderr, never stdout.