# Epimonos Project Bus Epimonos Project Bus is a small, generic coordination service for auditable human/agent projects. It exposes a stateless MCP Streamable HTTP endpoint and keeps an ordered, append-only event trail alongside relational projections. The core has no Sandbox, Epimonos product, billing, identity-provider, or backoffice domain logic. A project supplies its own actors, role assignments, work-package contents, decisions, evidence URIs, and repository references. ## MVP capabilities - isolated projects and actors with one formal role per project; - issued, atomically claimed, and evidenced work packages; - independent review requests and verdicts; - product, architecture, operational, and gate decisions; - escalations and formal resolution; - commit and artifact references; - PM/PO gate closure and baseline-release events; - ordered cursor-based event synchronization; - idempotent mutations and concurrency-safe local writes; - transport-derived identity and role-based authorization; - database-level protection against event update and deletion. ## Governance invariants The service enforces these minimum separations: - a PA cannot record product, architecture, operational, or gate decisions; - only a PO can record a product decision; - only a PM or PO can close a gate or release a baseline; - the actor who claimed/submitted a result cannot review it; - a gate cannot accept a result without an independent `APPROVE` review; - an actor who submitted a result cannot accept it; - a baseline can reference only accepted work packages. These are technical guardrails, not a replacement for the project role contracts or the PM's tolerance and escalation policy. ## Quick start Python 3.12 is the only runtime dependency. ```bash export PYTHONPATH=src export PROJECT_BUS_BOOTSTRAP_TOKEN='replace-this-with-long-secret' python -m project_bus --database ./project-bus.db --host 127.0.0.1 --port 8080 ``` Health endpoint: ```bash curl http://127.0.0.1:8080/healthz ``` Initialize MCP: ```bash curl http://127.0.0.1:8080/mcp \ -H 'Content-Type: application/json' \ --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}' ``` Create a project: ```bash curl http://127.0.0.1:8080/mcp \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer replace-this-with-long-secret' \ --data '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"create_project","arguments":{"project_id":"example","name":"Example","idempotency_key":"bootstrap-example-v1"}}}' ``` Use `register_actor` with the bootstrap identity to appoint a PO. Configure the actor's bearer credential through `PROJECT_BUS_TOKENS_JSON`, then let the PO/PM register the remaining members. Actor identity is always taken from the authenticated bearer credential; callers cannot supply an acting identity in tool arguments. Example credential configuration: ```bash export PROJECT_BUS_TOKENS_JSON='{ "long-random-po-token": { "actor_id": "po-1", "auth_subject": "po-1", "display_name": "Product Owner" } }' ``` The identity must match an actor registered in the target project. Environment changes require a process restart in this MVP. ## MCP client configuration For Claude Code: ```bash claude mcp add \ --scope project \ --transport http \ epimonos-project-bus \ https://project-bus.example/mcp ``` For a local-only development server, use the local HTTP URL. Credentials belong in the client/user secret store, never in `.mcp.json` or Git. ## Configuration | Variable | Default | Meaning | |---|---:|---| | `PROJECT_BUS_DATABASE` | `project-bus.db` | SQLite database path | | `PROJECT_BUS_MIGRATIONS` | source-tree discovery | Migration directory | | `PROJECT_BUS_HOST` | `127.0.0.1` | Bind address | | `PROJECT_BUS_PORT` | `8080` | HTTP port | | `PROJECT_BUS_BOOTSTRAP_TOKEN` | required, minimum 24 characters | SYSTEM bearer token | | `PROJECT_BUS_TOKENS_JSON` | empty | Static bearer-token identity map | | `PROJECT_BUS_ALLOWED_ORIGINS` | empty | Comma-separated exact browser origins | | `PROJECT_BUS_LOG_LEVEL` | `INFO` | Python log level | Never expose the bootstrap token. On an internet-facing deployment, terminate TLS at a trusted reverse proxy and set a strict origin allowlist. ## Test ```bash PYTHONPATH=src python -m unittest discover -v ``` The suite uses only temporary databases and includes concurrent writer tests. ## Local persistence and production profile SQLite runs in WAL mode and every mutation uses `BEGIN IMMEDIATE`. This gives a dependable single-process/single-node MVP and prevents claim and invariant check races. The append-only event table is protected with `UPDATE` and `DELETE` rejection triggers. Production differences are intentionally explicit: | Concern | MVP | Production target | |---|---|---| | Database | SQLite/WAL, one node | PostgreSQL 16+, transactions and row locks | | Identity | static bearer map | OIDC/JWT or mTLS workload identity | | Secrets | environment | secret manager, rotation, revocation | | Transport | plain HTTP capable | TLS-only reverse proxy/service mesh | | Scaling | one server process | multiple stateless MCP instances | | Audit durability | local DB/backup | PITR, replicas, external immutable export | | Availability | process supervisor | orchestrator probes, SLOs, alerting | | Abuse control | body cap/origin policy | edge rate limits, quotas, WAF where useful | The persistence boundary is deliberately small (`Database` plus SQL in the service), but this release does **not** contain a PostgreSQL adapter. SQLite must not be mounted on NFS or used for active-active replicas. ## Repository guide - `src/project_bus/` — domain service, auth abstraction, MCP and HTTP adapter; - `migrations/` — ordered relational schema; - `tests/` — service, concurrency, governance, and HTTP contract tests; - `docs/` — architecture, tool contract, threat model, production notes; - `deploy/` — container and Compose example; - `work-packages/` — governed implementation and activation scopes; - `evidence/` — WP-PA-001 verification and independent-review handoff. See [docs/TOOL_CONTRACT.md](docs/TOOL_CONTRACT.md) before integrating a new actor and [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md) before deployment. Sandbox activation is governed by [docs/SANDBOX_ACTIVATION_RUNBOOK.md](docs/SANDBOX_ACTIVATION_RUNBOOK.md).