feat: implement project bus MVP

This commit is contained in:
Codex Lead Engineer
2026-07-30 02:13:26 +02:00
commit bc55924198
28 changed files with 3518 additions and 0 deletions
+167
View File
@@ -0,0 +1,167 @@
# 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;
- `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.