{"id":32168194,"url":"https://github.com/sovetnik/legatus","last_synced_at":"2026-02-22T19:02:56.929Z","repository":{"id":319022814,"uuid":"1076360461","full_name":"sovetnik/legatus","owner":"sovetnik","description":"A minimal STDIO ↔ HTTP proxy built in Elixir. Legatus bridges agents and MCP servers, translating JSON-RPC dialogue between local and remote worlds.","archived":false,"fork":false,"pushed_at":"2025-10-15T20:31:43.000Z","size":25,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-27T11:34:49.835Z","etag":null,"topics":["elixir","json-rpc","mcp","proxy","stdio"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sovetnik.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-14T18:46:09.000Z","updated_at":"2025-10-15T21:04:54.000Z","dependencies_parsed_at":"2025-10-17T20:01:39.013Z","dependency_job_id":"673649ce-0be4-46ec-b44b-e61cecb95e33","html_url":"https://github.com/sovetnik/legatus","commit_stats":null,"previous_names":["sovetnik/legatus"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sovetnik/legatus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sovetnik%2Flegatus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sovetnik%2Flegatus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sovetnik%2Flegatus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sovetnik%2Flegatus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sovetnik","download_url":"https://codeload.github.com/sovetnik/legatus/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sovetnik%2Flegatus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29723573,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T15:10:41.462Z","status":"ssl_error","status_checked_at":"2026-02-22T15:10:04.636Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","json-rpc","mcp","proxy","stdio"],"created_at":"2025-10-21T15:48:30.809Z","updated_at":"2026-02-22T19:02:56.924Z","avatar_url":"https://github.com/sovetnik.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Legatus\n\n\u003e **JSON-RPC STDIO ↔ HTTP Proxy**  \n\u003e _A messenger agent speaking between worlds_\n\n**Legatus** is a minimal, stateless bridge that translates dialogue over STDIN into HTTP actions. It embodies the Umwelt principle of perception–action unity: every request passes through a complete functional circle — perception, cognition, action — before returning as a meaningful response.\n\n## Why Legatus Exists\n\nLegatus solves a fundamental problem: **how to let any process speak JSON-RPC over STDIO while delegating execution to an HTTP realm.**\n\nUse cases:\n- **Editor integrations**: Connect your editor to language servers over HTTP\n- **CLI tools**: Build command-line tools that proxy to HTTP APIs\n- **Agent communication**: Enable processes to communicate via standard streams\n- **Testing**: Interact with HTTP JSON-RPC servers from shell scripts\n\nLegatus is not merely a tool; it is a **ritual of translation** — a disciplined pattern for agent-to-world communication.\n\n## Quick Start\n\n```bash\n# Build the escript\nmix escript.install hex legatus\n\n# or\ngit clone git@github.com:sovetnik/legatus.git\nmix escript.build\n\n# Start your JSON-RPC HTTP server (example on port 4000)\n# Then send a request:\necho '{\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":[2,3],\"id\":1}' | \\\n  ./legatus http://localhost:4000/rpc\n```\n\n**Expected output:**\n```json\n{\"jsonrpc\":\"2.0\",\"result\":5,\"id\":1}\n```\n\nThat's it. One line in, one line out. STDIO becomes HTTP, HTTP becomes STDIO.\n\n## Philosophy: The Umwelt Architecture\n\nThe architecture follows Jakob von Uexküll's **Umwelt** concept — organisms perceive and act within their own \"subjective universe\":\n\n- **Aussenwelt** — The external world (STDIO streams)\n- **Merkwelt** — Perception layer (request validation)\n- **Wirkwelt** — Action layer (HTTP transport)\n- **Umwelt** — The complete functional circle (pipeline coordinator)\n- **Geist** — The animating principle (main loop)\n\nLegatus acts within the **Clausura Operationalis** — it knows only the world it perceives and acts upon it coherently. Its simplicity is not limitation but discipline.\n\n## Usage Modes\n\n### As Escript (recommended for production)\n\n```bash\nmix escript.build\n./legatus http://localhost:4000/rpc\n```\n\n### As Mix Task (for development)\n\n```bash\nmix legatus http://localhost:4000/rpc\n```\n\n### With Bearer Token Authentication\n\nWhen your upstream server requires authentication, pass the token via environment variable:\n\n```bash\n# Using escript\ntoken=your_secret_token ./legatus http://localhost:4000/rpc\n\n# Using mix task\ntoken=your_secret_token mix legatus http://localhost:4000/rpc\n```\n\nLegatus will automatically add the `Authorization: Bearer \u003ctoken\u003e` header to all HTTP requests.\n\n**Editor integration example (Zed, Claude Code, etc.):**\n\n```json\n{\n  \"context_servers\": {\n    \"my_server\": {\n      \"source\": \"custom\",\n      \"enabled\": true,\n      \"command\": \"legatus\",\n      \"args\": [\"http://localhost:4000/rpc\"],\n      \"env\": {\"token\": \"your_secret_token\"}\n    }\n  }\n}\n```\n\n### Pipeline Flow\n\nEvery request flows through the complete Umwelt cycle:\n\n```\nSTDIN → Geist.loop → Aussenwelt.receptio → Merkwelt.percipere → \nWirkwelt.portare → Aussenwelt.profanatio → STDOUT\n```\n\nEach arrow represents a transformation of meaning, not just data.\n\n## Architecture\n\n### Data Flow\n\nThe pipeline uses tagged tuples to track data state:\n\n1. **Receptio** (Aussenwelt): Parse JSON  \n   `{:phaenomenon, map}` | `{:fiasco, json_error}`\n\n2. **Percipere** (Merkwelt): Validate request  \n   `{:actio, map}` | `{:fiasco, error_map}`\n\n3. **Portare** (Wirkwelt): HTTP transport  \n   `{:gloria, map}` | `{:fiasco, error_map}` | `{:silentium, map}`\n\n4. **Profanatio** (Aussenwelt): Format output  \n   `{:gloria, json}` | `{:fiasco, json}` | `{:silentium, \"Nullius in verba\"}`\n\n5. **Emit** (Geist): Write to STDOUT or skip\n\n### Module Responsibilities\n\n- **Legatus** — Entry point and configuration\n- **Geist** — Main loop (STDIN → STDOUT cycle)\n- **Aussenwelt** — I/O boundaries (parse/format JSON)\n- **Merkwelt** — Request validation (JSON-RPC compliance)\n- **Wirkwelt** — HTTP coordinator (interprets transport responses into Umwelt concepts)\n- **Wirkwelt.Httpc** — HTTP transport (pure POST with status/body)\n- **Chronica** — Logging (stderr diagnostics)\n\n### Transport Layer Design\n\nWirkwelt follows a clean separation of concerns:\n\n**Wirkwelt behaviour contract:**\n```elixir\n@callback post(request :: map()) :: \n  {status :: pos_integer(), body :: map() | String.t()} | {:error, reason :: term()}\n```\n\n- **Transport (Httpc)**: Returns raw HTTP responses `{200, body}` or `{:error, reason}`\n- **Coordinator (Wirkwelt)**: Interprets responses into `{:gloria, map()}`, `{:silentium, map()}`, or `{:fiasco, map()}`\n\nThis design makes it easy to add new HTTP adapters (Finch, Hackney) without changing business logic.\n\n### Error Handling\n\nAll errors are JSON-RPC compliant:\n\n- `-32700` Parse error (invalid JSON)\n- `-32600` Invalid Request (missing method)\n- `-32000` HTTP errors (4xx/5xx)\n- `-32001` Transport errors (connection refused)\n\n## Configuration\n\nLegatus is configured via **command-line argument** — no static config required:\n\n```bash\nmix legatus http://localhost:4000/rpc\n```\n\nThe upstream URL is set dynamically at runtime via `Application.put_env/3`.\n\n## Design Principles\n\n1. **Tagged tuples** for explicit data flow\n2. **Pure functions** where possible (I/O at boundaries)\n3. **Pattern matching** over conditionals\n4. **Separation of concerns** (parse, validate, transport, format)\n5. **Testability** through dependency injection\n\n## JSON-RPC Support\n\n### Requests\n- ✅ Standard requests with `id`\n- ✅ Notifications (no `id`)\n- ✅ Batches (array of requests)\n\n### Responses\n- ✅ Success responses (`result`)\n- ✅ Error responses (`error`)\n- ✅ HTTP 204 handling (notifications)\n- ✅ Batch responses\n\n### Limitations\n- STDIO-based (one request per line)\n- HTTP POST only (no WebSocket/SSE)\n- No built-in retry logic\n- Single upstream server\n\n## License\n\nSee LICENSE file.\n\n## Etymology\n\n- **Legatus** (Latin) — envoy, ambassador, messenger\n- **Umwelt** (German) — environment, \"self-centered world\"\n- **Geist** (German) — spirit, mind, animating principle\n- **Aussenwelt** (German) — outer world\n- **Merkwelt** (German) — perceptual world\n- **Wirkwelt** (German) — world of action\n\n## Next Steps\n\n**Explore further:**\n- Read [umwelt.dev/docs](https://umwelt.dev/docs) for philosophical foundations\n- Join the discussion in [Issues](https://github.com/sovetnik/legatus/issues)\n- Contribute via [Pull Requests](https://github.com/sovetnik/legatus/pulls)\n\n**Related projects:**\n- **Skull** — The cognitive substrate for agent systems\n- **Reticulum Universalis** — Communication patterns for distributed agents\n\nLegatus is an experiment in **operational closure** — every component speaks the same language of perception and action. If this resonates with you, welcome to the conversation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsovetnik%2Flegatus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsovetnik%2Flegatus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsovetnik%2Flegatus/lists"}