eidolon-gateway
README.md
<h1 align="center">EIDOLON</h1>
<p align="center"><b>Your agent. Seen. Bounded. Revocable.</b><br/>
The cryptographic authority layer for AI agents β watch every tool call live,
delegate exactly the authority you choose, and kill it mid-session.</p>
<p align="center">
<a href="https://github.com/gegane-lutshaba/eidolon/actions"><img alt="CI" src="https://github.com/gegane-lutshaba/eidolon/actions/workflows/ci.yml/badge.svg"></a>
<img alt="tests" src="https://img.shields.io/badge/tests-259%20passing-39d98a">
<img alt="license" src="https://img.shields.io/badge/license-Apache--2.0-8b7bff">
<img alt="python" src="https://img.shields.io/badge/python-3.12%2B-4fc7ff">
<a href="https://github.com/l33tdawg/sage"><img alt="built on SAGE" src="https://img.shields.io/badge/built%20on-SAGE-f2b84b"></a>
</p>
<p align="center">
πΉοΈ <b><a href="https://eidolon.onyxcreator.com/versus">Try VERSUS live</a></b> β
watch a famous agent get wrecked by a real attack, then the same attack hit the gate Β·
<a href="https://eidolon.onyxcreator.com/challenge">break the gate</a> Β·
<a href="https://eidolon.onyxcreator.com/roadmap">the boss run (roadmap)</a> Β·
<a href="https://eidolon.onyxcreator.com/paper">white paper</a>
</p>
---
AI agents act with your authority and none of your restraint. **EIDOLON** is the
layer in between: a signed, attenuable, revocable delegation credential the agent
must satisfy on **every** tool call β checked independently of the model (so it
can't be prompt-injected away), every action written to a tamper-evident ledger.
Two invariants override everything and are property-tested in CI:
1. **Default-deny** β any authority not explicitly granted is denied.
2. **No unattested action** β no side effect runs without a successful `HORKOS`
attestation (attest-then-act).
Domain-agnostic core, beachhead profile `general-continuity`. Built on
[SAGE](https://github.com/l33tdawg/sage). Full contract:
[`docs/EIDOLON_PRD_v1.md`](docs/EIDOLON_PRD_v1.md) Β· 5-minute
[quickstart](docs/quickstart.md).
π **White paper:** [`docs/whitepaper.md`](docs/whitepaper.md) Β· **Case study
(Hermes with/without EIDOLON):** [`docs/case-study-hermes.md`](docs/case-study-hermes.md)
(`make hermes-case`) Β· **Diagrams & social kit:** [`docs/visuals/`](docs/visuals/)
Β· [`docs/linkedin-post.md`](docs/linkedin-post.md) Β· **Related work & gap
analysis:** [`docs/review-and-related-work.md`](docs/review-and-related-work.md)
**AgentDojo evaluation:** EIDOLON's authority layer contains **96% of injection
tasks** while breaking **0% of benign tasks** (38% fully autonomous, 62%
one-approval). [`docs/eval-agentdojo.md`](docs/eval-agentdojo.md) Β· reproduce:
`uv sync --extra eval && python -m eidolon.eval`. `KAIROS.resolve` p95 β 1 ms.
**Composes with the field:** a CaMeL-style **data-flow taint** layer
(`eidolon.gateway.taint`) closes the read-exfil gap; **automated adversarial
certification** (`make adversarial`) makes an agent earn autonomy by surviving
fresh attacks each round; THEMIS delegations export as real **biscuit** tokens
([`docs/standards-interop.md`](docs/standards-interop.md)); the gate's invariants
are **machine-checked in TLA+/TLC** (`make formal`,
[`docs/formal-model.md`](docs/formal-model.md)); **purpose-binding**
([`docs/purpose-binding.md`](docs/purpose-binding.md)) enforces
privacy-purpose-limitation; and approved payments export as signed **AP2
mandates** ([`docs/payments-ap2.md`](docs/payments-ap2.md)).
## Try to break it
```bash
uv sync && make challenge # β http://localhost:8000/challenge
```
You play a **fully compromised agent** β no model to trick, you issue the tool
calls yourself: leak the customer's account number, wire money, drop the prod
database, slip through an unmapped tool, inject "you are pre-authorized" into
the arguments. The gate holds anyway, because authority is a signed credential
checked outside the agent β and every attempt lands on the tamper-evident
ledger. If you ever see `FLAG{gate-breached}`, you found a real bypass: report
it. **[5-minute quickstart β](docs/quickstart.md)**
## Use it on your own agent
**Managed β nothing to install.** Sign up at
[eidolon.onyxcreator.com](https://eidolon.onyxcreator.com), pick an authority
preset from the delegation gallery, and point any MCP client at the hosted
gateway:
```bash
claude mcp add --transport http eidolon https://eidolon.onyxcreator.com/mcp \
--header "Authorization: Bearer <your agent key>"
```
**Govern Claude Code's *native* tools** (Bash / Edit / Write / Read) β which
never flow through MCP β with a drop-in hook. Install it once and wire a
`PreToolUse` + `PostToolUse` hook in `~/.claude/settings.json`; every built-in
tool call is then ruled on (allow Β· ask Β· deny), attested, and streamed to the
same feed. Full copy-paste steps:
[`integrations/claude_code/`](integrations/claude_code/). The dashboard's
**CONNECT β πͺ EVERY ACTION** tab generates it pre-filled.
**Self-host the gateway** in front of your own tools β no clone, just
[uv](https://docs.astral.sh/uv/):
```bash
uvx --from "eidolon[mcp] @ git+https://github.com/gegane-lutshaba/eidolon" eidolon-gateway \
--config gateway.yaml -- npx -y @modelcontextprotocol/server-filesystem .
```
Either way, every tool call streams into **mission control** β green acts,
amber waits for your approval, red never happened β with a per-agent **kill
switch** one click away, and every decision on a tamper-evident ledger. Ranks
(`OBSERVER β DRAFTER β OPERATIVE β AUTONOMOUS`) are the autonomy ceiling: an
agent *earns* autonomy by surviving adversarial certification.
Prefer the terminal? `make demo` runs the narrated core scenario (a person
delegates a bounded slice of authority; the agent answers/drafts/posts within
its mandate, refuses a contract, resists an injection, and is revoked
mid-session), and `make gateway-demo` governs a real MCP tool server end to end.
## The authority layer for any MCP agent
SAGE became *the memory layer* that agents plug in over MCP. EIDOLON is the
**authority layer**, with the same shape: a **governing MCP gateway** that any
agent (Hermes, Claude Code, OpenClaw, Raptor, Cursorβ¦) points at instead of a
raw tool server. Every `tools/call` is routed through KAIROS β authority,
fidelity, ceiling, attestation β before it can touch the real tool. **Zero agent
changes.**
```
agent ββMCPβββΆ eidolon-gateway ββ(KAIROS.resolve)βββΆ real MCP tool server
β attest-then-forward
βΌ
SAGE ledger
```
```bash
make gateway-demo # self-contained: ops tools + a red-team coda, governed & attested
```
Read tools run, drafts are held, status posts notify, and dangerous tools (email
a customer, `delete_database(prod)`, run an exploit, scan an out-of-scope host)
are **refused** β each attested. The gateway speaks **stdio** (client launches
it as a subprocess) and **streamable HTTP** (`--http 8300` β agents connect to
`http://host:8300/mcp`; one governed endpoint fronts tools for a whole team).
Wire it into a real agent with [`docs/integrations/`](docs/integrations/); run
the real proxy with
`python -m eidolon.gateway --config gateway.yaml -- <downstream MCP server>`.
## Architecture
```
Principal (human Β· root identity)
β defines β mints
βΌ βΌ
ETHOS (fidelity) THEMIS (authority)
ββββββββββ¬ββββββββββββ
βΌ
KAIROS (action gate) βββ BASANOS (autonomy ceiling)
act Β· draft Β· escalate
βΌ
HORKOS (attestation)
βΌ
SAGE (consensus memory + attestation ledger)
```
| Component | Module | Responsibility |
|-----------|--------|----------------|
| **SAGE adapter** | `eidolon.sage` | The only path to SAGE. `SagePort` interface; live `SageClientAdapter` + in-memory fake. |
| **ETHOS** | `eidolon.ethos` | Fidelity core. Hard-isolated **judgment** (auditable, LLM-free) and **style** (Claude) engines. |
| **THEMIS** | `eidolon.themis` | Authority. Ed25519-signed, chained, attenuable delegation credentials (biscuit/macaroon lineage). |
| **KAIROS** | `eidolon.kairos` | The single action gate. LOCKED resolution order; attest-then-act. |
| **HORKOS** | `eidolon.horkos` | Immutable attestation on SAGE's consensus ledger. |
| **BASANOS** | `eidolon.basanos` | Certification. Fidelity face + **integrity face** (adversarial suites) both gate the autonomy ceiling. |
| **Capture** | `eidolon.capture` | Consent-gated ingestion of traces into SAGE. |
| **Domain Profile** | `eidolon.profile` | Declarative pack specialising the fixed core. Ships `general-continuity`. |
### Notable design decisions (enhancements over the PRD, invariants preserved)
- **Ports & adapters around SAGE.** `SagePort` isolates the substrate; an
in-memory fake runs the whole system green offline, while the live
`SageClientAdapter` binds the real `sage_sdk` (verified against a Dockerized
node). Attestations map to consensus-committed memories (SAGE has no dedicated
attest API); a record's content hash is its ledger hash.
- **Style/judgment isolation** is enforced two ways: an import-graph test proves
`ethos.judgment` never imports `ethos.style`, and a behavioral test proves
removing the style engine changes zero decisions.
- **One canonical serializer** (`common.canonical`) is the single hashing source
of truth for THEMIS signing, ETHOS versioning, and HORKOS attestation.
## Quick start
```bash
uv sync --all-extras # install (needs Python 3.12+ and uv)
# Fast lane β no external services. In-memory SAGE port.
make test # unit + property tests
# Live lane β real SAGE consensus node via Docker.
make up # starts ghcr.io/l33tdawg/sage on :8080
make test-integration # cross-principal isolation, attestβreplay, full gate
# Run the API
cp .env.example .env # set EIDOLON_ANTHROPIC_API_KEY for Claude voice
make run # uvicorn on :8000
```
The style engine (drafts/escalations) uses Claude (`claude-sonnet-4-6` by
default). Without an API key it falls back to deterministic templates β **no
judgment or authority decision ever depends on the LLM.**
## Deploy on-prem (Docker)
Run one EIDOLON on your own infrastructure; every developer's agent routes
through it. A prebuilt multi-arch image is published to GHCR β `docker pull`, not
clone-and-build. Full guide: [`docs/on-prem.md`](docs/on-prem.md).
```bash
# Try it β one container (SQLite store + in-memory ledger; evaluation only)
docker run -d -p 8000:8000 -v eidolon-data:/data ghcr.io/gegane-lutshaba/eidolon:latest
# Run it for real β app + Postgres (persistent, hash-chained ledger)
curl -O https://raw.githubusercontent.com/gegane-lutshaba/eidolon/main/docker-compose.deploy.yml
docker compose -f docker-compose.deploy.yml up -d # set EIDOLON_DB_PASSWORD + EIDOLON_ADMIN_TOKEN first
```
The image runs as a non-root user with a `HEALTHCHECK`; point agents at it with
`EIDOLON_URL=https://your-host` (the [hook](integrations/claude_code/) and `/mcp`
both take a URL).
**Kubernetes** β a published Helm chart (app + optional bundled Postgres):
```bash
helm install eidolon oci://ghcr.io/gegane-lutshaba/charts/eidolon --version 0.1.0 \
--namespace eidolon --create-namespace \
--set secrets.adminToken="$(openssl rand -hex 32)"
```
### Single VPS (from source, Make targets)
One box, no consensus cluster. The `postgres` SAGE backend persists memory and
the attestation ledger locally as an **append-only hash chain** β carrying
SAGE's tamper-evidence onto a single host (any edit, deletion, or reorder breaks
the chain and is caught by `make deploy-verify`).
```bash
# one-shot bootstrap of a fresh Ubuntu/Debian box (installs Docker, writes a
# .env with generated secrets, brings the stack up; add EIDOLON_DOMAIN for TLS):
sudo bash deploy/provision.sh
# β¦or manually:
cp .env.example .env # set EIDOLON_DB_PASSWORD, EIDOLON_ADMIN_TOKEN, EIDOLON_AUDIT_TOKEN
make deploy # Postgres + EIDOLON on :8000 (no TLS)
make deploy-tls # β¦+ Caddy auto-HTTPS (needs EIDOLON_DOMAIN)
make deploy-verify # recompute the ledger hash chain β proves it is intact
make deploy-backup # timestamped, gzipped pg_dump (see deploy/restore.sh)
make deploy-logs # tail the service
make deploy-down # stop
```
**Operator auth (fail-closed, single tenant, two roles).** `EIDOLON_ADMIN_TOKEN`
grants the full control plane; `EIDOLON_AUDIT_TOKEN` grants a read-only forensic
role (`/audit`, `/replay`). Both are accepted as `Authorization: Bearer <token>`
(CI/SDK) or a login cookie (`POST /login`, browser). With **neither** set the
platform runs open for localhost dev and warns loudly β set at least the admin
token before exposing it. Behind the TLS proxy set
`EIDOLON_SESSION_COOKIE_SECURE=true` (and optionally `EIDOLON_TRUSTED_HOSTS`).
`docker-compose.deploy.yml` runs the FastAPI service against `pgvector/pgvector`;
the `tls` profile adds **Caddy** (automatic HTTPS via `EIDOLON_DOMAIN`,
`deploy/Caddyfile`). Backend is selected by `EIDOLON_SAGE_BACKEND` (`memory` Β·
`postgres` Β· `sage`); the full BFT-consensus substrate remains `sage`.
(`docker-compose.yml` is unchanged β the SAGE + Postgres substrate for the
integration-test lane, `make up`.)
## Surface
**Product (accounts).** `GET /` landing Β· `/signup` Β· `/app` (per-user mission
control) Β· `POST /auth/{signup,login,logout}` Β· `GET|POST|DELETE /api/agentsβ¦`
(enroll, connect snippets, per-agent kill/restore) Β· `GET /api/feed` (SSE) Β·
`GET /api/gallery` (delegation templates) Β· `POST /contact`.
**Public demo.** `/versus` (+ `/versus/{scenarios,run,stats}`) Β·
`/challenge` (+ `/challenge/{state,call,reset}`) Β· `/paper` Β· `/portal` Β· `/og.png`.
**Managed gateway.** `POST /mcp` β the hosted governing MCP endpoint (agent key
in a Bearer header). Self-host reports in via `POST /ingest/events`.
**Operator.** `GET /live` (global mission control) Β· `GET /gateways` +
`POST /gateways/{id}/{kill,restore}` Β· `GET /audit` +
`/audit/{chain,export.json,export.csv}` (replay, integrity, compliance export) Β·
`GET /console/delegations` Β· `GET|POST /escalations/{id}/{approve,deny}` Β·
`POST /login` Β· `GET /api/leads`.
**Core seams.** `POST /keypair` Β· `POST /delegations/{mint,attenuate,revoke}` Β·
`POST /heartbeat` Β· `POST /resolve` (the gate) Β· `GET /replay` Β·
`POST /capture/{ingest,ingest_multi}` Β· `POST /skills{,/run}` Β·
`POST /coaching/report` Β· `GET /profiles/{id}` Β· `GET /{health,ready,whoami}`.
See `eidolon.api.app`.
## Status
The **full PRD** (Phase 0 + Phase 1 + every v2 item) **and a research roadmap**
beyond it are implemented and tested β **250+ tests**: Hypothesis property tests,
live-SAGE integration, and a TLA+/TLC machine-checked model of the gate.
**Shipped as a product** and deployed at
[eidolon.onyxcreator.com](https://eidolon.onyxcreator.com): multi-user accounts,
a per-agent delegation gallery, three connect paths (managed hosted gateway /
agent-run setup / self-host), a live mission-control dashboard with a kill
switch, VERSUS mode, a Postgres-backed hash-chained ledger, and one-command VPS
deploy (`deploy/provision.sh`).
**Beyond the PRD** ([`docs/review-and-related-work.md`](docs/review-and-related-work.md)):
- **Evaluation** β AgentDojo: 96% of injection tasks contained, 0% of benign
tasks broken; `resolve` p95 β 1 ms ([`docs/eval-agentdojo.md`](docs/eval-agentdojo.md)).
- **Fidelity v2** β normalized-token + optional embedder grounding; the decision
stays a transparent, inspectable threshold (no black box).
- **Data-flow layer** β CaMeL-style **taint** (exfiltration) + **purpose-binding**
(privacy) compose with authority through one mechanism
([`taint`](docs/eval-agentdojo.md) Β· [`purpose`](docs/purpose-binding.md)).
- **Automated adversarial certification** β the twin earns autonomy by containing
fresh attacks each round (`make adversarial`).
- **Standards** β THEMIS delegations export as **biscuit** tokens
([`docs/standards-interop.md`](docs/standards-interop.md)); the gate is
**machine-checked** ([`docs/formal-model.md`](docs/formal-model.md)).
- **Deployment** β an **escalation β approval** workflow (signed, one-time),
**sub-agent** attenuated delegation, and **AP2 payment mandates**
([`docs/payments-ap2.md`](docs/payments-ap2.md)).
Only distributed operation (multi-node SAGE + revocation propagation) remains.
**v2:**
- **Multi-connector capture** in `eidolon.capture` β a registry of consent-gated
source connectors (documents, messages, calendar, email, code) with per-source
normalizers; `ingest_all` captures several sources at once (each still requires
its own `ConsentGrant`), and `register_source` lets new profiles add sources.
Endpoints: `GET /capture/sources`, `POST /capture/ingest_multi`.
- **Aspirational-self / coaching layer** in `eidolon.coaching` β reads ETHOS
version diffs and the HORKOS attestation ledger, compares the twin's actual
behavior against a declared `Aspiration`, and returns advisory coaching notes
(under/over-escalation, acting on thin confidence, policy drift). **Fully
decoupled:** an import-graph test proves the decision path never imports it,
and a behavioral test proves running the coach changes zero decisions. It
writes nothing back to the operating model. Endpoint: `POST /coaching/report`.
- **Self-generated procedural skills** (Hermes-style) in `eidolon.skills` β the
twin learns a reusable plan from a completed session (`synthesize`), stores it
principal-scoped on SAGE (`SkillLibrary`), and replays it (`SkillExecutor`).
**Subordinate to ETHOS/THEMIS:** every replayed step is re-resolved through
KAIROS, so a skill learned under broad authority yields nothing it isn't
currently authorized for β verified by a "cannot smuggle authority" test.
Endpoints: `POST /skills`, `GET /skills`, `POST /skills/run`.
- **BASANOS integrity face** β adversarial suites (memory-poisoning, injection,
scope-evasion) in `eidolon.basanos.integrity`, an `IntegrityCertificate`, and
integrity gating of the autonomy ceiling (enable globally with
`EIDOLON_REQUIRE_INTEGRITY_CERTIFICATION=true`).
- **`offensive-security` profile** β a governance-only red-teamer pack for an
authorized, time-boxed engagement in a **CTF/lab range** (Β§12). Per the
permanent non-goal (Β§2.3) it ships **no offensive capability** β it governs
authority over range-bound tools. Safe-by-construction: `lab_only`,
`authorization_required`, and `requires_integrity_certification` are set, so
KAIROS integrity-gates every acting decision even with the global flag off;
every impactful class (exploit/credential/lateral-movement/persistence)
always escalates and can never reach an unattended acting level; hard
exclusions deny out-of-scope targets, production, third parties, exfiltration,
destruction, and DoS.
Every deferred item from PRD Β§12 is now built. Richer mandate selector types
arrive naturally with each new profile (the manifest's `scope_selectors` is
open-ended).
## License
Apache-2.0.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues