The custodians initial cross repo task and workplan tracking hub
Find a file
2026-06-21 20:12:17 +02:00
.claude/rules Add shared credential-routing template and propagation tooling 2026-06-18 22:48:43 +02:00
api STATE-WP-0062 T2: /services catalog API over the two-dimension model 2026-06-19 20:56:19 +02:00
dashboard STATE-WP-0062 T5: docs, first-party↔repo test, mark workplan finished 2026-06-19 21:16:37 +02:00
docs feat: add workplan aliases and legacy meter 2026-06-04 08:25:31 +02:00
flows feat(tasks): adopt canonical task statuses 2026-05-26 01:32:50 +02:00
history docs(history): cross-link BRIDGE-WP-0005 restart cleanup workplan 2026-06-21 20:12:17 +02:00
infra fix(state-hub): STATE-WP-0063 T01/T02/T04 — restore local consistency sync 2026-06-21 18:06:34 +02:00
mcp_server feat: add State Hub bulk status skill 2026-06-07 20:11:07 +02:00
migrations STATE-WP-0062 T1: two-dimension service_catalog model + migration 2026-06-19 20:46:07 +02:00
policies STATE-WP-0062 T4: Service DoM uses "Level" not "Tier" 2026-06-19 21:03:35 +02:00
prompts feat(sbom): CUST-WP-0013 — expand SBOM infra to terraform, ansible, and tool manifests 2026-03-12 04:40:26 +01:00
registry Add capability registry scaffold and seed entries from reuse-surface 2026-06-16 01:34:23 +02:00
scripts Add shared credential-routing template and propagation tooling 2026-06-18 22:48:43 +02:00
skills/state-hub feat: add State Hub bulk status skill 2026-06-07 20:11:07 +02:00
task_flow_engine Harden flow advancement exit assertions 2026-05-23 16:41:21 +02:00
templates/recently-on-scope Implement RecentlyOnScope domain digest 2026-05-22 13:45:53 +02:00
tests STATE-WP-0062 T5: docs, first-party↔repo test, mark workplan finished 2026-06-19 21:16:37 +02:00
workplans docs(state-hub): STATE-WP-0063 T03 done — tunnel cleanup restored activity-core 2026-06-21 19:47:56 +02:00
.custodian-brief.md chore(consistency): sync task status from DB [auto] 2026-06-21 19:47:46 +02:00
.dockerignore Locked in cytoscape.js as visualization for dep graph 2026-05-03 01:43:50 +02:00
.env.example feat(CUST-WP-0014): repo sync automation & Gitea inventory 2026-03-16 01:41:16 +01:00
.gitignore Fix Claude instruction imports 2026-06-18 00:29:04 +02:00
AGENTS.md Add shared credential-routing template and propagation tooling 2026-06-18 22:48:43 +02:00
alembic.ini Add state-hub v0.1 — local-first state service for the Custodian 2026-02-24 17:47:49 +01:00
CLAUDE.md Add shared credential-routing template and propagation tooling 2026-06-18 22:48:43 +02:00
custodian_cli.py cli command statehub register with install 2026-06-05 13:09:25 +02:00
Dockerfile Locked in cytoscape.js as visualization for dep graph 2026-05-03 01:43:50 +02:00
INTENT.md docs: clarify state hub intent 2026-05-17 21:37:02 +02:00
LICENSE Initial commit 2026-05-17 16:15:50 +00:00
Makefile fix: stabilize consistency make wrappers 2026-06-07 19:49:17 +02:00
pyproject.toml feat: import core schemas from hub-core 2026-06-07 01:20:57 +02:00
README.md feat: add workplan aliases and legacy meter 2026-06-04 08:25:31 +02:00
SCOPE.md Normalize workplan IDs and activate parents on task start 2026-05-23 16:31:28 +02:00
statehub_register.py cli command statehub register with install 2026-06-05 13:09:25 +02:00
uv.lock feat: import core schemas from hub-core 2026-06-07 01:20:57 +02:00

State Hub

State Hub is the live coordination service for the Custodian ecosystem: PostgreSQL persistence, FastAPI API, FastMCP server, Observable dashboard, consistency tooling, and repo/workplan synchronization.

This repository is the standalone home for the service. It was extracted from the former embedded implementation at:

/home/worsch/the-custodian/state-hub

Extraction State

The extraction workplan CUST-WP-0043 - State Hub Repo Extraction is complete.

Current state:

  • The implementation has been imported here with subtree history.
  • CUST-WP-0042 has been re-homed into this repository.
  • The old embedded tree in the-custodian remains only as a pointer.
  • This repository is authoritative for State Hub code, docs, tests, dashboard, migrations, scripts, policies, and State Hub-local workplans.

Workplans

New State Hub-local workplans should use the prefix:

STATE-WP-0001

Legacy Custodian-hosted State Hub plans, such as CUST-WP-0042, may retain their existing IDs when that preserves State Hub workstream/task continuity. Do not create duplicate workstreams manually; write the workplan file first, then run consistency sync.


Stack

Layer Technology Port
Database PostgreSQL 16-alpine (Docker) 127.0.0.1:5432
API FastAPI + SQLAlchemy 2.0 async + asyncpg 127.0.0.1:8000
MCP server FastMCP SSE 127.0.0.1:8001
Dashboard Observable Framework 127.0.0.1:3000
CLI custodian (Python, uv entry point)

All services bind to 127.0.0.1 only — nothing exposed to the network.


Setup

Prerequisites

  • Docker Engine
  • Python 3.12+ with uv (pip install uv)
  • Node.js 18+ (dashboard only)

First-time

cd /home/worsch/state-hub

cp .env.example .env          # edit POSTGRES_PASSWORD
make install                  # uv sync
make db                       # docker compose up postgres
make migrate                  # alembic upgrade head
make seed                     # insert 6 canonical topics
make api                      # db + migrate + uvicorn :8000 (restarts if running)

Dashboard

make dashboard    # installs dashboard deps if needed, then Observable dev server on :3000
make dashboard-check  # installs deps if needed, then runs Observable build

Start Everything

To start all the infrastructure on separate consoles do:

make db           # docker compose up postgres
make mcp-http     # start state-hub mcp service
make dashboard    # Observable dev server on :3000
make bridges      # Set up ssh bridges for cross machines access

CLI

make install-cli              # symlink .venv/bin/custodian → ~/.local/bin
custodian status              # API health + summary totals
custodian register-project    # register cwd as a Custodian project

Makefile Targets

Target What it does
make install uv sync — install Python deps + entry points
make install-cli Symlink custodian to ~/.local/bin
make db Start postgres container
make db-tools Start postgres + pgadmin (http://127.0.0.1:5050)
make migrate alembic upgrade head
make seed Insert 6 canonical topics
make api db + wait + migrate + uvicorn (restarts if running)
make dashboard-install Install dashboard npm deps from dashboard/package-lock.json
make dashboard-check Build the Observable dashboard as a smoke/regression check
make dashboard Install deps if needed, then start Observable dev server (restarts if running)
make check curl /state/health
make test Python test suite plus make dashboard-check
make register-project DOMAIN=x PROJECT_PATH=y Register a project
make clean docker compose down -v (destroys DB volume)

Database Schema

Five tables in dependency order:

topics
└── workstreams
    └── tasks (self-FK: parent_task_id)
        └── progress_events
decisions (FK: topic_id, workstream_id — at least one required)
    └── progress_events

Enums

Enum Values
topic_status active · paused · archived
workstream_status proposed · ready · active · blocked · backlog · finished · archived
task_status wait · todo · progress · done · cancel
task_priority low · medium · high · critical
decision_type made · pending
decision_status open · resolved · escalated · superseded
domain custodian · railiance · markitect · coulomb_social · personhood · foerster_capabilities

Governance constraints encoded in schema

  • No hard DELETE endpoints — only soft: archived, cancel, superseded
  • progress_events has no updated_at and no DELETE endpoint (append-only per constitution §5)
  • decisions with financial/legal keywords + pending type → auto-set escalation_note (§4)

API

Interactive docs at http://127.0.0.1:8000/docs once the API is running.

Key endpoint: /state/summary

Returns a full snapshot in one call — used by both the MCP server and dashboard:

{
  "generated_at": "...",
  "totals": {
    "topics":      { "active": 6, "paused": 0, "archived": 0, "total": 6 },
    "workstreams": { "ready": 1, "active": 1, "blocked": 0, "finished": 1, "total": 3 },
    "tasks":       { "wait": 0, "todo": 9, "progress": 0, "done": 11, "cancel": 0, "total": 20 },
    "decisions":   { "open": 1, "resolved": 0, "escalated": 0, "total": 1 }
  },
  "topics": [...],             // topics with nested workstream stubs
  "blocking_decisions": [...], // pending decisions only
  "waiting_tasks": [...],
  "recent_progress": [...],    // last 20 events
  "open_workstreams": [...]
}

Router summary

Prefix Operations
/topics CRUD (soft-delete: archived)
/workplans Preferred CRUD surface for repo-backed workplans (soft-delete: archived)
/workstreams Legacy compatibility CRUD surface; usage is recorded by legacy-meter
/tasks CRUD (soft-delete: cancel); PATCH updates status
/decisions CRUD (soft-delete: superseded); auto-escalation
/progress GET list + POST append — no DELETE
/legacy-meter Register, meter, and review legacy interface usage
/state/summary Full snapshot
/state/health DB connectivity check

See docs/workplan-terminology-transition.md for the workstream-to-workplan compatibility policy and retirement criteria.


MCP Server

Runs as a persistent SSE service on :8001, independent of the Claude Code session. Restart it anytime without restarting Claude Code.

make mcp-http   # start (or restart) the MCP SSE server on :8001

Registered at user scope in ~/.claude.json:

{ "type": "sse", "url": "http://127.0.0.1:8001/sse" }

To re-register from scratch:

claude mcp remove state-hub -s user 2>/dev/null || true
claude mcp add-json -s user state-hub '{"type":"sse","url":"http://127.0.0.1:8001/sse"}'

See mcp_server/TOOLS.md for the full tool reference card (30 lines, faster than reading server.py).

Tools at a glance

Query (read-only): get_state_summary · get_topic · list_blocked_tasks · list_pending_decisions · get_recent_progress

Mutate (each auto-emits a progress event): create_task · update_task_status · record_decision · resolve_decision · add_progress_event · update_workstream_status

Resources: state://summary · state://topics · state://workstreams/{topic_slug} · state://decisions/blocking · state://tasks/blocked


custodian CLI

Installed into .venv/bin/custodian by uv sync; symlinked to ~/.local/bin by make install-cli.

custodian register-project [--domain DOMAIN] [--path PATH]
  • --path defaults to current working directory
  • --domain is auto-detected from project_charter_v*.md frontmatter if omitted
custodian status

Prints API health, totals, and any blocking decisions.

What register-project does

  1. Verifies the API is reachable (fails fast with make api hint)
  2. Looks up the topic ID for the domain via /topics/?status=active
  3. Checks that state-hub is in ~/.claude.json
  4. Writes $PROJECT_PATH/CLAUDE.md from scripts/project_claude_md.template
  5. Posts a milestone progress event recording the registration

Project Registration Scripts

Script Purpose
scripts/register_project.sh Shell version of custodian register-project
scripts/patch_mcp_cwd.py Legacy: patched cwd for the old stdio registration (no longer needed)
scripts/project_claude_md.template CLAUDE.md template with {PROJECT_NAME}, {DOMAIN}, {TOPIC_ID}
scripts/seed.py Insert the 6 canonical topics into a fresh database
scripts/pull_image.py WSL2 workaround: pull Docker images via Python urllib with Range-request chunking

Dashboard

Four pages at http://127.0.0.1:3000 (dev) or built with npm run build:

Page Content
Overview Status cards, task-by-status chart, recent activity feed, decisions due within 7 days
Workstreams Filterable table by domain/status/owner; selected workstream task list; progress timeline
Decisions Pending tab (with escalation highlights) and Made tab; resolution velocity chart
Progress Append-only event feed with author badges; 30-day event volume chart

Data loaders (src/data/*.json.py) are Python scripts that call the local API. They run at dev-server start and on npm run build. Clear the cache if data appears stale:

rm -rf dashboard/src/.observablehq/cache/

Known Issues / WSL2 Notes

  • TLS bad record MAC on large downloads: WSL2 corrupts packets on big TCP transfers. Use scripts/pull_image.py instead of docker pull for future image pulls.
  • MCP server is now SSE, not stdio: Re-registration is claude mcp add-json -s user state-hub '{"type":"sse","url":"http://127.0.0.1:8001/sse"}'. The patch_mcp_cwd.py script and .mcp.json config are legacy artifacts from the old stdio setup.
  • AsyncSession concurrency: SQLAlchemy 2.0 async sessions don't support concurrent operations. All queries in /state/summary run sequentially on a single session.