Transport-level routing for MCP/ACP protocols
Getting Started
Build stdio Bus from source and run your first worker in minutes. This guide covers prerequisites, build instructions, configuration, and running stdio Bus in all three operating modes.
Prerequisites
stdio Bus has minimal dependencies. You need a C11 compiler and optionally Node.js for running the included example workers.
C11 Compiler
GCC 4.9+ or Clang 3.4+ with C11 support. The build uses strict flags (-Wall -Wextra -Werror).
Make or CMake
GNU Make for the primary build system, or CMake 3.10+ for IDE integration and out-of-source builds.
Node.js 18+
Optional. Required only for running the included JavaScript example workers and test client.
Platform Support
| Platform | I/O Multiplexing | Notes |
|---|---|---|
| Linux | epoll | Ubuntu 20.04+, Debian 11+, Fedora 35+, Amazon Linux 2 |
| macOS | kqueue | macOS 12 (Monterey) or later |
Build Instructions
stdio Bus can be built using either Make (recommended) or CMake. Both produce the same executable at build/kernel.
Building with Make
The Makefile is the primary build system and supports both debug and release builds.
Build with Make
# Clone the repositorygit clone https://github.com/stdiobus/stdiobus.gitcd kernel# Build with Make (debug build)make# Or build release versionmake BUILD=release# Verify the build./build/kernel --help
Building with CMake
CMake is useful for IDE integration and out-of-source builds.
Build with CMake
# Clone the repositorygit clone https://github.com/stdiobus/stdiobus.gitcd kernel# Build with CMakemkdir buildcd buildcmake ..make# Verify the build./kernel --help
Make Targets
| Target | Description |
|---|---|
make | Build debug executable (default) |
make BUILD=release | Build optimized release executable |
make test | Build and run the test suite |
make clean | Remove all build artifacts |
make install | Install to /usr/local/bin |
Configuration
stdio Bus reads configuration from a JSON file specified via --config <path>. The configuration defines worker pools and operational limits.
Minimal Configuration
A minimal configuration defines one worker pool. All limits use defaults when omitted.
config.json
{"pools": [{"id": "echo-worker","command": "/usr/bin/env","args": ["node", "./examples/echo-worker.js"],"instances": 2}]}
Configuration Fields
| Field | Type | Required | Description |
|---|---|---|---|
pools[].id | string | Yes | Unique identifier for the pool |
pools[].command | string | Yes | Path to executable |
pools[].args | string[] | No | Command-line arguments |
pools[].instances | number | Yes | Number of worker instances (≥1) |
Operating Modes
stdio Bus supports three operating modes for client connections. Choose based on your deployment scenario.
stdio Mode
Single client via stdin/stdout. Ideal for subprocess embedding where the parent process communicates directly with stdio Bus.
stdio mode
# Send a single request via stdioecho '{"jsonrpc":"2.0","id":"1","method":"echo","params":{"hello":"world"}}' | ./build/kernel --config config.json --stdio
Expected Output
{"jsonrpc": "2.0","id": "req-1","result": {"echo": {},"method": "echo","timestamp": "2024-01-15T10:30:00.000Z"}}
Unix Socket Mode
Multiple clients via Unix domain socket. Best for local IPC with multiple concurrent clients on the same machine.
Unix socket mode
# Terminal 1: Start stdio Bus with Unix socket./build/kernel --config config.json --unix /tmp/stdio_bus.sock# Terminal 2: Send test requestnode examples/ndjson-client.js --unix /tmp/stdio_bus.sock --method echo --id req-1
TCP Mode
Multiple clients via TCP socket. Use for network-accessible deployments or when clients run on different machines.
TCP mode
# Terminal 1: Start stdio Bus with TCP listener./build/kernel --config config.json --tcp 127.0.0.1:9000# Terminal 2: Send test requestnode examples/ndjson-client.js --tcp 127.0.0.1:9000 --method echo --id req-1
Mode Selection Guide
| Mode | Flag | Use Case |
|---|---|---|
| stdio | --stdio | Subprocess embedding, single client |
| Unix socket | --unix <path> | Local IPC, multiple clients |
| TCP | --tcp <host:port> | Network access, remote clients |
Echo Worker Example
The echo worker demonstrates the NDJSON worker contract. It reads JSON-RPC messages from stdin and writes responses to stdout.
Worker Contract
- Input (stdin): NDJSON messages from stdio Bus runtime
- Output (stdout): NDJSON responses only
- Errors (stderr): Logging and debug output
- Shutdown: Handle SIGTERM for graceful exit
Complete Example
echo-worker.js
#!/usr/bin/env node/*** Simple NDJSON echo worker for stdio Bus* Demonstrates the worker-to-daemon contract*/const readline = require('readline');let shuttingDown = false;const rl = readline.createInterface({input: process.stdin,output: process.stdout,terminal: false});function processMessage(line) {if (shuttingDown) return;try {const msg = JSON.parse(line);// Request: has both id and method - send responseif (msg.id !== undefined && msg.method !== undefined) {const response = {jsonrpc: '2.0',id: msg.id,result: {echo: msg.params || {},method: msg.method,timestamp: new Date().toISOString()}};// Preserve sessionId for session affinityif (msg.sessionId) {response.sessionId = msg.sessionId;}// Write response as NDJSONconsole.log(JSON.stringify(response));}} catch (err) {// Log errors to stderr (never stdout)console.error(`[echo-worker] Error: ${err.message}`);}}// Handle graceful shutdownprocess.on('SIGTERM', () => {shuttingDown = true;rl.close();});rl.on('line', processMessage);rl.on('close', () => process.exit(0));console.error('[echo-worker] Started, waiting for messages...');
Testing with NDJSON Client
Use the included NDJSON client to send test requests and verify stdio Bus routing behavior.
Basic Request
node examples/ndjson-client.js --tcp localhost:9000 --method echo --id req-1
Testing Session Affinity
Send multiple requests with the same sessionId to verify they route to the same worker:
# All requests with same session go to same workernode examples/ndjson-client.js --tcp localhost:9000 --method test --session sess-123 --id 1node examples/ndjson-client.js --tcp localhost:9000 --method test --session sess-123 --id 2node examples/ndjson-client.js --tcp localhost:9000 --method test --session sess-123 --id 3
Request with Custom Params
node examples/ndjson-client.js --tcp localhost:9000 \--method process \--id req-1 \--session sess-123 \--params '{"data": "test"}'
Expected Output
{"jsonrpc": "2.0","id": "req-1","sessionId": "sess-123","result": {"echo": {"data": "test"},"method": "process","timestamp": "2024-01-15T10:30:00.000Z"}}
Client Options
| Option | Description |
|---|---|
--tcp <host:port> | Connect via TCP |
--unix <path> | Connect via Unix socket |
--method <name> | JSON-RPC method name |
--id <value> | Request ID |
--session <id> | Session ID for affinity |
--params <json> | JSON params object |
--interactive | Interactive mode |
Next Steps
Now that you have stdio Bus running with a basic worker, explore these topics:
- Protocol Specification: Learn the normative requirements for building conforming implementations
- Architecture: Understand the internal runtime model and event loop behavior
- Integration Guide: Embed stdio Bus in your IDE, CLI, or agent framework
- Configuration Reference: Fine-tune limits, restart policies, and backpressure settings