Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

BoJ Server — Elixir REST core

Purpose

The gated internal REST/SSE core that fronts the unified Zig ABI, on port 7700 by default. It is the Elixir "scalability multiplier" over the Idris2-logic / pure-Zig-interface stack (see docs/architecture/README.adoc, v1.1.0). It is NOT a public ingress — per ADR-0004 the only governed public surface is the http-capability-gateway (tier-2) in front of this core. This listener binds the trusted/internal interface and every invocation passes the TrustPolicy + CredentialDecryptor transaction gate before dispatch.

Endpoints:

  • GET /health{"status":"ok","version":…​,"cartridges_loaded":N}.

  • GET /menu — per-cartridge name / domain / tier / description.

  • GET /cartridges — cartridge-name list.

  • GET /cartridge/:name — full cartridge.json, or 404 if unknown.

  • POST /cartridge/:name/invokewired. Trust-gated, then dispatched via BojRest.Invoker (shells boj-invokedlopen`s the cartridge `.so → ADR-0006 boj_cartridge_invoke) for ffi cartridges, or the Deno JsWorkerPool fallback for no-ffi cartridges. Returns 200 with the cartridge’s JSON result.

  • POST /cartridge/:name/sse — same gated dispatch, streamed as text/event-stream (openresult|errordone). Makes the surface four-protocol (REST + SSE here; gRPC-compat + GraphQL via the per-cartridge internal Zig adapter).

Relationship to the stdio bridge

The Node.js stdio bridge at mcp-bridge/ is what Claude Code and Glama talk to. This core is the REST server behind it:

Endpoint Bridge tool

/health

boj_health

/menu

boj_menu

/cartridges

boj_cartridges

/cartridge/:name

boj_cartridge_info

/cartridge/:name/invoke

boj_cartridge_invoke (live — Zig ABI)

/cartridge/:name/sse

streaming variant of the above

Build

cd elixir
mix deps.get
mix compile
mix test          # full suite (router, invoker, catalog, trust, …)

The Zig dispatch CLI must be built once so the FFI path is live:

cd ../ffi/zig && zig build invoke   # produces zig-out/bin/boj-invoke

Run

cd elixir
mix run --no-halt
# listener binds http://127.0.0.1:7700 (internal; front with the gateway)

Configure via env vars:

  • BOJ_PORT — listener port (default 7700).

  • BOJ_CARTRIDGES_ROOT — where to scan for cartridge.json (default: ../cartridges relative to the Elixir project).

  • BOJ_INVOKE_CLI — path to the boj-invoke Zig CLI (else auto-probed).

Design notes

  • Cowboy + Plug, single listener. One supervised listener, routed internally (REST + SSE); NOT N parallel HTTP servers. The http-capability-gateway (ADR-0004) attaches in front as tier-2.

  • Transaction-gated dispatch. TrustPolicy derives required exposure from the cartridge’s auth.method; loopback callers are locally trusted; CredentialDecryptor runs before any dispatch. No gatekeeperless path to the ABI.

  • ETS-backed catalog, read-only. Loaded once at boot; re-scan needs a restart (matches the restart-gated cartridge.json mount lifecycle).

  • Best-effort load. A malformed cartridge.json is logged and skipped; the listener still comes up with whatever parsed cleanly.

Phase plan

  1. Phase 1 — REST metadata. Listener serves cartridge metadata. DONE 2026-04-18.

  2. Phase 2 — invocation wired. POST /cartridge/:name/invoke (and /sse) dispatch through the unified Zig ABI via boj-invoke, trust- gated. DONE.

  3. Phase 3 — gateway. Attach http-capability-gateway at tier-2 per ADR-0004 (verb governance, rate-limit tier-2, trust-level primary path). Accepted; production-wiring is a tracked programme — ADR-0004 estimates 8–12 weeks (mTLS-as-primary, E2E, benchmarks). Until then this core stays internal/loopback-bound.

  4. Phase 4 — mTLS / SDP. Per Trustfile.a2ml [SDP_RULES].