171 lines
6.3 KiB
Markdown
171 lines
6.3 KiB
Markdown
# 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).
|