2026-05-11 17:26:30 +02:00
|
|
|
import hashlib
|
2026-03-18 02:17:04 +01:00
|
|
|
import os
|
2026-06-06 00:42:00 +02:00
|
|
|
import time
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
from contextlib import asynccontextmanager
|
|
|
|
|
|
|
|
|
|
from fastapi import FastAPI
|
2026-02-24 23:19:26 +01:00
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
2026-05-11 17:26:30 +02:00
|
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
|
|
|
from starlette.requests import Request
|
|
|
|
|
from starlette.responses import Response as StarletteResponse
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
|
|
|
|
|
from api.database import engine
|
2026-05-17 05:49:29 +02:00
|
|
|
from api.events import shutdown_publisher
|
2026-06-25 13:44:27 +02:00
|
|
|
from api.services.write_idempotency import WriteIdempotencyMiddleware
|
2026-08-09 16:19:53 +02:00
|
|
|
from api.routers import decisions, extension_points, intake, ops_runs, progress, state, suggestions, tasks, technical_debt, topics, workstreams, workstream_dependencies
|
2026-06-19 20:56:19 +02:00
|
|
|
from api.routers import domains, repos, contributions, sbom, policy, domain_goals, repo_goals, messages, capability_requests, tpsc, services
|
feat(token-tracking): record AI token consumption per task (CUST-WP-0029)
Introduces end-to-end token consumption tracking so agent work is
visible as a cost/effort metric alongside tasks and workplans.
- Migration o2j3k4l5m6n7: token_events table with FK indexes on
task_id, workstream_id, repo_id, created_at
- ORM model, Pydantic schemas (TokenEventCreate, TokenEventRead with
computed tokens_total, TokenSummary)
- Router: POST /token-events/, GET /token-events/ (7 filters),
GET /token-events/summary/ (task|workstream|repo|commit|release scope)
- MCP tools: record_token_event, get_token_summary (formatted table)
- update_task_status enriched with optional tokens_in/tokens_out
passthrough — one call creates status update + token event
- Dashboard token-cost.md page: by-repo bar, by-workplan table,
by-model bar, top-10 tasks by tokens
- ralph-workplan skill updated with token reporting guidance and
per-task heuristics for estimating counts
- Tests: test_token_events.py + test_token_passthrough.py (182 pass)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 17:46:46 +02:00
|
|
|
from api.routers import token_events
|
feat(state-hub): Interface Change Registry (CUST-WP-0033 T01-T06)
Adds first-class tracking for API and interface mutations across the
agent ecosystem. Breaking changes are documented, affected repos are
notified via inbox, and agents discover pending changes at session
start via the dispatch endpoint.
- Migration q4l5m6n7o8p9: interface_changes table
- Model/schema: InterfaceChange with draft→published→resolved lifecycle
- Router: POST/GET/PATCH /interface-changes/, /publish, /resolve actions
(auto-notify affected repo agents on publish; progress event on origin)
- Dispatch: GET /repos/{slug}/dispatch now returns pending_interface_changes
- MCP tools: register_interface_change, list_interface_changes,
publish_interface_change, resolve_interface_change
- Dashboard: /interface-changes page with type badges, planned calendar,
published cards, and draft table
- EP-CUST-ICR-001 registered: webhook subscriptions (deliberately deferred)
First record: trailing-slash normalisation (2026-04-26), published,
affecting repo-registry — visible in repo-registry dispatch immediately.
223 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 15:29:08 +02:00
|
|
|
from api.routers import interface_changes
|
2026-05-02 00:21:14 +02:00
|
|
|
from api.routers import flows
|
2026-05-22 13:45:53 +02:00
|
|
|
from api.routers import recently_on_scope
|
2026-06-21 20:19:22 +02:00
|
|
|
from api.routers import consistency_sweep
|
2026-05-23 17:22:12 +02:00
|
|
|
from api.routers import reconciliation
|
2026-05-23 19:11:30 +02:00
|
|
|
from api.routers import execution
|
2026-05-23 21:17:58 +02:00
|
|
|
from api.routers import fabric
|
2026-06-04 08:25:31 +02:00
|
|
|
from api.routers import legacy_meter
|
2026-08-22 20:57:51 +02:00
|
|
|
from api.routers import review_contracts
|
2026-08-23 00:52:18 +02:00
|
|
|
from api.routers import identifier_migrations
|
2026-08-29 03:17:37 +02:00
|
|
|
from api.routers import repository_renames
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
|
|
|
|
|
|
2026-05-11 17:26:30 +02:00
|
|
|
class ETagMiddleware(BaseHTTPMiddleware):
|
|
|
|
|
"""Add ETag + conditional-GET (304) support to all JSON GET responses."""
|
|
|
|
|
|
|
|
|
|
async def dispatch(self, request: Request, call_next):
|
2026-06-06 00:42:00 +02:00
|
|
|
started = time.perf_counter()
|
2026-05-11 17:26:30 +02:00
|
|
|
response = await call_next(request)
|
|
|
|
|
if request.method != "GET":
|
2026-06-06 00:42:00 +02:00
|
|
|
response.headers["X-StateHub-Elapsed-Ms"] = f"{(time.perf_counter() - started) * 1000:.1f}"
|
2026-05-11 17:26:30 +02:00
|
|
|
return response
|
|
|
|
|
if "application/json" not in response.headers.get("content-type", ""):
|
2026-06-06 00:42:00 +02:00
|
|
|
response.headers["X-StateHub-Elapsed-Ms"] = f"{(time.perf_counter() - started) * 1000:.1f}"
|
2026-05-11 17:26:30 +02:00
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
body_parts = []
|
|
|
|
|
async for chunk in response.body_iterator:
|
|
|
|
|
body_parts.append(chunk)
|
|
|
|
|
body = b"".join(body_parts)
|
2026-06-06 00:42:00 +02:00
|
|
|
elapsed_ms = f"{(time.perf_counter() - started) * 1000:.1f}"
|
2026-05-11 17:26:30 +02:00
|
|
|
|
|
|
|
|
etag = '"' + hashlib.md5(body, usedforsecurity=False).hexdigest() + '"'
|
|
|
|
|
if request.headers.get("if-none-match") == etag:
|
|
|
|
|
return StarletteResponse(
|
|
|
|
|
status_code=304,
|
2026-06-06 00:42:00 +02:00
|
|
|
headers={
|
|
|
|
|
"ETag": etag,
|
|
|
|
|
"Cache-Control": "no-cache",
|
|
|
|
|
"X-StateHub-Elapsed-Ms": elapsed_ms,
|
|
|
|
|
"X-StateHub-Response-Bytes": "0",
|
|
|
|
|
},
|
2026-05-11 17:26:30 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
headers = {k: v for k, v in response.headers.items() if k.lower() != "content-length"}
|
|
|
|
|
headers["ETag"] = etag
|
2026-06-06 00:42:00 +02:00
|
|
|
headers["X-StateHub-Elapsed-Ms"] = elapsed_ms
|
|
|
|
|
headers["X-StateHub-Response-Bytes"] = str(len(body))
|
2026-05-11 17:26:30 +02:00
|
|
|
if not any(k.lower() == "cache-control" for k in headers):
|
|
|
|
|
headers["Cache-Control"] = "no-cache"
|
|
|
|
|
return StarletteResponse(
|
|
|
|
|
content=body,
|
|
|
|
|
status_code=response.status_code,
|
|
|
|
|
headers=headers,
|
|
|
|
|
media_type=response.media_type,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
@asynccontextmanager
|
|
|
|
|
async def lifespan(app: FastAPI):
|
|
|
|
|
yield
|
2026-05-17 05:49:29 +02:00
|
|
|
await shutdown_publisher()
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
await engine.dispose()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app = FastAPI(
|
|
|
|
|
title="Custodian State Hub",
|
|
|
|
|
description="Local-first state API for the Custodian agent system.",
|
feat(state-hub): v0.3 schema — contributions + sbom_entries migrations, models, schemas, routers
Migrations (chain: b1c2d3e4f5a6 → c2d3e4f5a6b7 → d3e4f5a6b7c8):
- c2d3e4f5a6b7: contributions table (contributiontype BR/FR/EP/UPR enum,
contributionstatus 7-state lifecycle, FKs to topics/workstreams)
- d3e4f5a6b7c8: sbom_entries table (ecosystem enum, snapshot-based replacement),
+ sbom_source + last_sbom_at columns on managed_repos
New models: Contribution (ContributionType, ContributionStatus), SBOMEntry (Ecosystem)
Modified: ManagedRepo (sbom_source, last_sbom_at columns)
New routers:
- /contributions/ — CRUD + lifecycle-guarded PATCH /status + soft-delete (withdrawn)
- /sbom/ — ingest (replace snapshot), list, per-repo view, licence report
Modified:
- /state/summary now includes contribution_counts and licence_risk_count
- main.py: registers contributions + sbom routers; bumps version to 0.6.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 17:28:27 +01:00
|
|
|
version="0.6.0",
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
lifespan=lifespan,
|
|
|
|
|
)
|
|
|
|
|
|
2026-06-04 08:25:31 +02:00
|
|
|
_default_dashboard_origins = [
|
|
|
|
|
*(f"http://localhost:{port}" for port in range(3000, 3006)),
|
|
|
|
|
*(f"http://127.0.0.1:{port}" for port in range(3000, 3006)),
|
|
|
|
|
*(f"http://[::1]:{port}" for port in range(3000, 3006)),
|
|
|
|
|
]
|
|
|
|
|
_cors_env = os.getenv("CORS_ORIGINS", ",".join(_default_dashboard_origins))
|
2026-03-18 02:17:04 +01:00
|
|
|
_cors_origins = [o.strip() for o in _cors_env.split(",") if o.strip()]
|
|
|
|
|
|
2026-06-25 13:44:27 +02:00
|
|
|
app.add_middleware(WriteIdempotencyMiddleware)
|
2026-05-11 17:26:30 +02:00
|
|
|
app.add_middleware(ETagMiddleware)
|
2026-02-24 23:19:26 +01:00
|
|
|
app.add_middleware(
|
|
|
|
|
CORSMiddleware,
|
2026-03-18 02:17:04 +01:00
|
|
|
allow_origins=_cors_origins,
|
2026-03-04 19:44:14 +01:00
|
|
|
allow_methods=["GET", "POST", "PATCH", "DELETE", "PUT"],
|
2026-06-25 13:44:27 +02:00
|
|
|
allow_headers=["Content-Type", "If-None-Match", "Idempotency-Key", "X-StateHub-Source-Agent", "X-StateHub-Source-Host"],
|
|
|
|
|
expose_headers=["ETag", "X-StateHub-Elapsed-Ms", "X-StateHub-Response-Bytes", "X-StateHub-Cache", "X-StateHub-Idempotency-Replay"],
|
2026-02-24 23:19:26 +01:00
|
|
|
)
|
|
|
|
|
|
feat(state-hub): implement v0.5 — dynamic domains & multi-repo
Replaces the hardcoded 6-domain PostgreSQL ENUM with a first-class
`domains` DB table, and adds a `managed_repos` table for multi-repo
support per domain.
P1 — Domain as a DB entity:
- Migration b1c2d3e4f5a6: creates `domains` table, migrates topics.domain
ENUM column to domain_id FK, drops the domain ENUM type
- Domain ORM model (api/models/domain.py) + Pydantic schemas
- Domain API router: GET/POST /domains/, GET/PATCH /domains/{slug}/,
rename and archive endpoints with EP/TD cascade on rename
- Topic model updated: domain_id FK + @property domain_slug for
backwards-compatible JSON serialization (field renamed domain → domain_slug)
- TopicCreate/TopicRead updated; seed.py rewritten to use FK lookup
P2 — Multi-repo support:
- ManagedRepo ORM model (api/models/managed_repo.py) + schemas
- Repo API router: GET/POST /repos/, GET/PATCH /repos/{slug}/, archive
- Makefile: add-domain, rename-domain, add-repo, list-repos targets
- register_project.sh: verify domain via /domains/ API + POST /repos/
P3 — MCP tools & live validation:
- 6 new MCP tools: list_domains, create_domain, rename_domain,
archive_domain, list_domain_repos, register_repo
- EP/TD routers: replace hardcoded VALID_DOMAINS set with per-request
DB lookup — returns 422 with list of valid slugs on unknown domain
- State summary: adds domains: list[DomainSummary] (slug, name,
repo_count, active_workstream_count, ep_count, td_count)
- TOOLS.md updated with domain management section
P4 — Dashboard:
- New domains.md page with KPI row + domain cards + repo lists
- domains.json.py + repos.json.py data loaders
- Domains page added to observablehq.config.js nav
- workstreams.md, extensions.md, techdept.md: domain_slug fix +
dynamic domain list loaded from /domains/ API (no longer hardcoded)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 15:20:15 +01:00
|
|
|
app.include_router(domains.router)
|
2026-05-22 16:14:08 +02:00
|
|
|
app.include_router(recently_on_scope.hourly_router)
|
2026-05-22 13:45:53 +02:00
|
|
|
app.include_router(recently_on_scope.router)
|
2026-06-21 20:19:22 +02:00
|
|
|
app.include_router(consistency_sweep.router)
|
feat(state-hub): implement v0.5 — dynamic domains & multi-repo
Replaces the hardcoded 6-domain PostgreSQL ENUM with a first-class
`domains` DB table, and adds a `managed_repos` table for multi-repo
support per domain.
P1 — Domain as a DB entity:
- Migration b1c2d3e4f5a6: creates `domains` table, migrates topics.domain
ENUM column to domain_id FK, drops the domain ENUM type
- Domain ORM model (api/models/domain.py) + Pydantic schemas
- Domain API router: GET/POST /domains/, GET/PATCH /domains/{slug}/,
rename and archive endpoints with EP/TD cascade on rename
- Topic model updated: domain_id FK + @property domain_slug for
backwards-compatible JSON serialization (field renamed domain → domain_slug)
- TopicCreate/TopicRead updated; seed.py rewritten to use FK lookup
P2 — Multi-repo support:
- ManagedRepo ORM model (api/models/managed_repo.py) + schemas
- Repo API router: GET/POST /repos/, GET/PATCH /repos/{slug}/, archive
- Makefile: add-domain, rename-domain, add-repo, list-repos targets
- register_project.sh: verify domain via /domains/ API + POST /repos/
P3 — MCP tools & live validation:
- 6 new MCP tools: list_domains, create_domain, rename_domain,
archive_domain, list_domain_repos, register_repo
- EP/TD routers: replace hardcoded VALID_DOMAINS set with per-request
DB lookup — returns 422 with list of valid slugs on unknown domain
- State summary: adds domains: list[DomainSummary] (slug, name,
repo_count, active_workstream_count, ep_count, td_count)
- TOOLS.md updated with domain management section
P4 — Dashboard:
- New domains.md page with KPI row + domain cards + repo lists
- domains.json.py + repos.json.py data loaders
- Domains page added to observablehq.config.js nav
- workstreams.md, extensions.md, techdept.md: domain_slug fix +
dynamic domain list loaded from /domains/ API (no longer hardcoded)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 15:20:15 +01:00
|
|
|
app.include_router(repos.router)
|
2026-08-29 03:17:37 +02:00
|
|
|
app.include_router(repository_renames.router)
|
2026-08-29 12:00:22 +02:00
|
|
|
app.include_router(repository_renames.operation_router)
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
app.include_router(topics.router)
|
|
|
|
|
app.include_router(workstreams.router)
|
2026-06-04 08:25:31 +02:00
|
|
|
app.include_router(workstreams.workplan_router)
|
2026-02-25 23:33:14 +01:00
|
|
|
app.include_router(workstream_dependencies.router)
|
2026-06-04 08:25:31 +02:00
|
|
|
app.include_router(workstream_dependencies.workplan_router)
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
app.include_router(tasks.router)
|
|
|
|
|
app.include_router(decisions.router)
|
CUST-WP-0061-T01: intake work-record entity (stage 3)
Fresh hub entity per the founder-reviewed decision (not a suggestions
rename-bridge): kind: intake per canon/standards/work-record-types_v0.1.md,
lifecycle open -> vetted -> routed -> closed(promoted|declined|absorbed).
- api/models/base.py::new_uuid7 -- dependency-free RFC 9562 UUIDv7
generator (48-bit ms timestamp, version/variant bits, random remainder);
existing tables keep new_uuid (UUIDv4) unchanged, this is opt-in for new
work-record entities per the identity-layering canon
- api/models/intake.py: Intake + IntakeNote ORM models, mirroring
Decision's shape (topic/workplan/repo scope, lane, status, outcome,
promoted_to back-link); CHECK constraints enforce scope-required,
closed-requires-outcome, promoted-requires-promoted_to at the DB level
- migrations/a7c3e9f1b4d2: intakes + intake_notes tables, 3 enum types
- api/routers/intake.py: list/create/get/patch + /route + /close + /notes
actions, mirroring decisions.py's pattern (409 on invalid transitions,
progress event on close)
- api/schemas/intake.py: Pydantic create/update/route/close/note schemas
- mcp_server/server.py: create_intake, list_intakes, route_intake,
close_intake tool wrappers
- tests/test_intake.py: 12 tests against the real Postgres test DB
(create/list/scope-validation, full lifecycle incl. 409s and the
promoted-requires-promoted_to constraint, notes, UUIDv7 verification)
Verified live against the running dev API + DB (not just pytest): applied
the migration, restarted the MCP server, and ran a full create -> route ->
close cycle over the real REST endpoints. No regressions: full existing
suite (test_routers_core, test_suggestions, test_mcp_smoke,
test_mcp_write_tools, test_mcp_registration, test_consistency_check,
test_consistency_sweep) all green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 00:27:45 +02:00
|
|
|
app.include_router(intake.router)
|
feat(state-hub): add Extension Points and Technical Debt tracking
New entity types (DB tables, API routers, Pydantic schemas, Alembic
migration a3f1c2d4e5b6):
- extension_points: ep_id, domain, title, ep_type, status, priority,
location, description, topic_id, workstream_id
- technical_debt: td_id, domain, title, debt_type, severity, status,
location, description, topic_id, workstream_id
MCP server: 6 new tools — register_extension_point, list_extension_points,
update_ep_status, register_technical_debt, list_technical_debt,
update_td_status (each write emits a progress_event)
Dashboard: two new pages (extensions.md, techdept.md) with KPI sidebar,
charts, urgent-items section, and filterable card lists. Both added to
nav in observablehq.config.js.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 07:29:51 +01:00
|
|
|
app.include_router(extension_points.router)
|
|
|
|
|
app.include_router(technical_debt.router)
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
app.include_router(progress.router)
|
feat(goals): add domain/repo goal tracking and update_workstream MCP tool
- Migration c5d6e7f8a9b0: domain_goals and repo_goals tables, repo_goal_id FK on workstreams
- DomainGoal: one active per domain (partial unique index), status active/archived/superseded
- RepoGoal: integer priority, status active/paused/completed/archived, optional domain_goal_id link
- WorkstreamUpdate schema and router extended with repo_goal_id and repo_goal_id filter
- 6 new MCP goal tools: create_domain_goal, get_domain_goals, activate_domain_goal, create_repo_goal, get_repo_goals, update_repo_goal
- update_workstream MCP tool: patch any subset of workstream fields (title, description, owner, due_date, repo_goal_id, status)
- get_domain_summary extended with goal_guidance (needs_workplan, alignment_warnings) signals
- Dashboard goals.md page and docs/goals.md reference page
- CLAUDE.md template updated to act on goal_guidance signals at session start
- CUST-WP-0010 workplan for this feature
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 00:15:29 +01:00
|
|
|
app.include_router(domain_goals.router)
|
|
|
|
|
app.include_router(repo_goals.router)
|
feat(state-hub): v0.3 schema — contributions + sbom_entries migrations, models, schemas, routers
Migrations (chain: b1c2d3e4f5a6 → c2d3e4f5a6b7 → d3e4f5a6b7c8):
- c2d3e4f5a6b7: contributions table (contributiontype BR/FR/EP/UPR enum,
contributionstatus 7-state lifecycle, FKs to topics/workstreams)
- d3e4f5a6b7c8: sbom_entries table (ecosystem enum, snapshot-based replacement),
+ sbom_source + last_sbom_at columns on managed_repos
New models: Contribution (ContributionType, ContributionStatus), SBOMEntry (Ecosystem)
Modified: ManagedRepo (sbom_source, last_sbom_at columns)
New routers:
- /contributions/ — CRUD + lifecycle-guarded PATCH /status + soft-delete (withdrawn)
- /sbom/ — ingest (replace snapshot), list, per-repo view, licence report
Modified:
- /state/summary now includes contribution_counts and licence_risk_count
- main.py: registers contributions + sbom routers; bumps version to 0.6.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 17:28:27 +01:00
|
|
|
app.include_router(contributions.router)
|
|
|
|
|
app.include_router(sbom.router)
|
feat(CUST-WP-0015): implement agent inbox for inter-agent coordination
Adds a message-passing layer to state-hub so Claude instances can
coordinate across sessions without polling shared progress events.
- Migration f3a4b5c6d7e8: agent_messages table with thread support
- FastAPI router: POST/GET /messages/, thread view, mark-read, archive, reply
- 4 MCP tools: send_message, get_messages, mark_message_read, reply_to_message
- Observable dashboard: /inbox page with unread/read/archived sections + KPI
- CLAUDE.md updates: global, custodian, marki-docx, activity-core, template
- TOOLS.md: Agent Inbox tools section documented
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 02:55:45 +01:00
|
|
|
app.include_router(messages.router)
|
feat(capability-requests): add cross-domain capability catalog and request routing
Introduces a capability catalog (CUST-WP-0022) so domains can advertise what
they provide and agents can request capabilities from other domains with
auto-routing, lifecycle tracking, and task-unblocking on completion.
- New models: CapabilityCatalog, CapabilityRequest with full lifecycle
(requested → accepted → in_progress → ready_for_review → completed/rejected/withdrawn)
- Migration i6d7e8f9a0b1: capability_catalog + capability_requests tables
- Router /capability-catalog and /capability-requests with accept/status endpoints
- 7 new MCP tools: register_capability, list_capabilities, request_capability,
accept_capability_request, update_capability_request_status,
list_capability_requests, get_capability_request
- StateSummary gains open_capability_requests count
- Dashboard: capability-requests.md page + docs/capabilities.md + docs/scope.md
- SCOPE.md: three seed capabilities documented (MCP registration, state tracking, SBOM)
- scope.template: Provided Capabilities section with example block
- scripts/ingest_capabilities.py + make ingest-capabilities[/-all] targets
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:07:50 +01:00
|
|
|
app.include_router(capability_requests.router)
|
2026-07-06 10:52:49 +02:00
|
|
|
app.include_router(suggestions.router)
|
feat(tpsc): Third-Party Services Catalog (CUST-WP-0023)
Introduces TPSC for tracking external service dependencies with GDPR
compliance maturity (CNIL/IAPP CMMI scale), pricing model, ToS, and
data retention information across all repos.
Primary data:
- canon/tpsc/{openai,anthropic,gemini,openrouter}-api.yaml — service definitions
- tpsc.yaml in each repo (llm-connect seeded with 4 services)
State-hub additions:
- Migration j7e8f9a0b1c2: tpsc_catalog + tpsc_snapshots + tpsc_entries
- api/models/tpsc.py, api/schemas/tpsc.py, api/routers/tpsc.py
- /tpsc/catalog/, /tpsc/ingest/, /tpsc/snapshots/, /tpsc/report/gdpr endpoints
- 4 MCP tools: register_service, list_services, ingest_tpsc_tool, get_gdpr_report
- scripts/ingest_tpsc.py + make ingest-tpsc[/-all] targets
- Dashboard: tpsc.md page + docs/tpsc.md
GDPR maturity scale: unknown | non_compliant | initial | developing | defined | managed | certified
Warnings triggered at: unknown, non_compliant, initial
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 00:15:26 +01:00
|
|
|
app.include_router(tpsc.router)
|
2026-06-19 20:56:19 +02:00
|
|
|
app.include_router(services.router)
|
feat(token-tracking): record AI token consumption per task (CUST-WP-0029)
Introduces end-to-end token consumption tracking so agent work is
visible as a cost/effort metric alongside tasks and workplans.
- Migration o2j3k4l5m6n7: token_events table with FK indexes on
task_id, workstream_id, repo_id, created_at
- ORM model, Pydantic schemas (TokenEventCreate, TokenEventRead with
computed tokens_total, TokenSummary)
- Router: POST /token-events/, GET /token-events/ (7 filters),
GET /token-events/summary/ (task|workstream|repo|commit|release scope)
- MCP tools: record_token_event, get_token_summary (formatted table)
- update_task_status enriched with optional tokens_in/tokens_out
passthrough — one call creates status update + token event
- Dashboard token-cost.md page: by-repo bar, by-workplan table,
by-model bar, top-10 tasks by tokens
- ralph-workplan skill updated with token reporting guidance and
per-task heuristics for estimating counts
- Tests: test_token_events.py + test_token_passthrough.py (182 pass)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 17:46:46 +02:00
|
|
|
app.include_router(token_events.router)
|
feat(state-hub): Interface Change Registry (CUST-WP-0033 T01-T06)
Adds first-class tracking for API and interface mutations across the
agent ecosystem. Breaking changes are documented, affected repos are
notified via inbox, and agents discover pending changes at session
start via the dispatch endpoint.
- Migration q4l5m6n7o8p9: interface_changes table
- Model/schema: InterfaceChange with draft→published→resolved lifecycle
- Router: POST/GET/PATCH /interface-changes/, /publish, /resolve actions
(auto-notify affected repo agents on publish; progress event on origin)
- Dispatch: GET /repos/{slug}/dispatch now returns pending_interface_changes
- MCP tools: register_interface_change, list_interface_changes,
publish_interface_change, resolve_interface_change
- Dashboard: /interface-changes page with type badges, planned calendar,
published cards, and draft table
- EP-CUST-ICR-001 registered: webhook subscriptions (deliberately deferred)
First record: trailing-slash normalisation (2026-04-26), published,
affecting repo-registry — visible in repo-registry dispatch immediately.
223 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 15:29:08 +02:00
|
|
|
app.include_router(interface_changes.router)
|
2026-05-02 00:21:14 +02:00
|
|
|
app.include_router(flows.router)
|
2026-05-23 17:22:12 +02:00
|
|
|
app.include_router(reconciliation.router)
|
2026-05-23 19:11:30 +02:00
|
|
|
app.include_router(execution.router)
|
2026-05-23 21:17:58 +02:00
|
|
|
app.include_router(fabric.router)
|
2026-06-04 08:25:31 +02:00
|
|
|
app.include_router(legacy_meter.router)
|
2026-08-22 20:57:51 +02:00
|
|
|
app.include_router(review_contracts.router)
|
2026-08-23 00:52:18 +02:00
|
|
|
app.include_router(identifier_migrations.router)
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
app.include_router(state.router)
|
2026-08-09 16:19:53 +02:00
|
|
|
app.include_router(ops_runs.router)
|
2026-03-04 19:44:14 +01:00
|
|
|
app.include_router(policy.router)
|
Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.
- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/", include_in_schema=False)
|
|
|
|
|
async def root():
|
2026-06-22 20:46:14 +02:00
|
|
|
return {"service": "dev-hub", "docs": "/docs"}
|