Transport-level routing for MCP/ACP protocols
We appreciate your patience. The service is temporarily operating in an external runtime environment.
Transport-level routing for MCP/ACP protocols
We appreciate your patience. The service is temporarily operating in an external runtime environment.
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.
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 | I/O Multiplexing | Notes |
|---|---|---|
| Linux | epoll | Ubuntu 20.04+, Debian 11+, Fedora 35+, Amazon Linux 2 |
| macOS | kqueue | macOS 12 (Monterey) or later |
stdio Bus can be built using either Make (recommended) or CMake. Both produce the same executable at build/kernel.
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
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
| 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 |
stdio Bus reads configuration from a JSON file specified via --config <path>. The configuration defines worker pools and operational limits.
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}]}
| 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) |
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 | 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 |
The echo worker demonstrates the NDJSON worker contract. It reads JSON-RPC messages from stdin and writes responses to stdout.
echo-worker.js
1#!/usr/bin/env node2/**3* Simple NDJSON echo worker for stdio Bus4* Demonstrates the worker-to-daemon contract5*/6const readline = require('readline');78let shuttingDown = false;910const rl = readline.createInterface({11input: process.stdin,12output: process.stdout,13terminal: false14});1516function processMessage(line) {17if (shuttingDown) return;1819try {20const msg = JSON.parse(line);2122// Request: has both id and method - send response23if (msg.id !== undefined && msg.method !== undefined) {24const response = {25jsonrpc: '2.0',26id: msg.id,27result: {28echo: msg.params || {},29method: msg.method,30timestamp: new Date().toISOString()31}32};3334// Preserve sessionId for session affinity35if (msg.sessionId) {36response.sessionId = msg.sessionId;37}3839// Write response as NDJSON40console.log(JSON.stringify(response));41}42} catch (err) {43// Log errors to stderr (never stdout)44console.error(`[echo-worker] Error: ${err.message}`);45}46}4748// Handle graceful shutdown49process.on('SIGTERM', () => {50shuttingDown = true;51rl.close();52});5354rl.on('line', processMessage);55rl.on('close', () => process.exit(0));5657console.error('[echo-worker] Started, waiting for messages...');
Use the included NDJSON client to send test requests and verify stdio Bus routing behavior.
node examples/ndjson-client.js --tcp localhost:9000 --method echo --id req-1
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
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"}}
| 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 |
Now that you have stdio Bus running with a basic worker, explore these topics: