Legatus

JSON-RPC boundary: STDIO ↔ HTTP / WebSocket

Legatus is a protocol boundary process.
It reads JSON-RPC from STDIN and relays messages through one of two modes:

Why Legatus Exists

Legatus solves one specific problem: make STDIO JSON-RPC clients speak to remote transports without embedding transport logic in the client.

Quick Start

# Build the escript
mix escript.install hex legatus
# or
git clone git@github.com:sovetnik/legatus.git
mix escript.build
# Start your JSON-RPC HTTP server (example on port 4000)
# Then send a request:
echo '{"jsonrpc":"2.0","method":"add","params":[2,3],"id":1}' | \
./legatus http://localhost:4000/rpc

mix escript.build собирает legatus локально, а mix escript.install устанавливает его как команду, доступную из PATH.

Expected output:

{"jsonrpc":"2.0","result":5,"id":1}

That's it. One line in, one line out. STDIO becomes HTTP, HTTP becomes STDIO.

Architecture (Current)

Layers

Usage Modes

mix escript.build
./legatus http://localhost:4000/rpc

With Bearer Token Authentication

When your upstream server requires authentication, pass the token via environment variable:

# Using escript
token=your_secret_token ./legatus http://localhost:4000/rpc
# Using escript
token=your_secret_token ./legatus http://localhost:4000/rpc

Legatus will automatically add the Authorization: Bearer <token> header to all HTTP requests.

Editor integration example (Zed, Claude Code, etc.):

{
"context_servers": {
"my_server": {
"source": "custom",
"enabled": true,
"command": "legatus",
"args": ["http://localhost:4000/rpc"],
"env": {"token": "your_secret_token"}
}
}
}

Flows

HTTP mode:

STDIN -> Aussenwelt.receptio -> Umwelt.percipere -> Canalis.Http.Client -> Aussenwelt.profanatio -> STDOUT

WebSocket mode:

STDIN (uplink) -> Aussenwelt.receptio -> Umwelt.percipere -> Canalis.Ws.send_request
Canalis.Ws.receive_message (downlink) -> Aussenwelt.receptio -> Umwelt.percipere -> STDOUT

Architecture

Data Flow

The pipeline uses tagged tuples to track data state:

  1. Receptio (Aussenwelt): Parse JSON
    {:phaenomenon, map} | {:fiasco, json_error}

  2. Percipere (Merkwelt): Validate request
    {:actio, map} | {:fiasco, error_map}

  3. Portare (Wirkwelt): HTTP transport
    {:gloria, map} | {:fiasco, error_map} | {:silentium, map}

  4. Profanatio (Aussenwelt): Format output
    {:gloria, json} | {:fiasco, json} | {:silentium, "Nullius in verba"}

  5. Emit (Geist): Write to STDOUT or skip

Key Modules

Runtime Semantics

Error Handling

All errors are JSON-RPC compliant:

Configuration

Legatus is configured via command-line arguments:

./legatus http://localhost:4000/rpc

Mode selection:

./legatus http://localhost:4000/rpc
./legatus ws://localhost:4000/ws --ws

Testing

JSON-RPC Support

Requests

Responses

Limitations

License

See LICENSE file.

Etymology