The custodians initial cross repo task and workplan tracking hub
Find a file
tegwick fc8ec49d9e
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Multi-Context Image / build-and-push (push) Successful in 24s
fix: package quality-debt CLI support
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a053ff-1d6f-7fe2-ac1c-a6eb40a42a0c
2026-08-30 23:36:23 +02:00
.claude/rules feat: DoX assessment recording and soft visibility (STATE-WP-0077) 2026-07-22 21:18:40 +02:00
.forgejo/workflows fix(ci): trigger image builds on every path the Dockerfile copies 2026-08-24 23:00:57 +02:00
api feat: add fast forge work-record reconciliation 2026-08-30 22:38:54 +02:00
dashboard docs: complete repository rename operator handoff 2026-08-29 15:46:43 +02:00
deploy/railiance deploy: promote fast work-record reconciliation 2026-08-30 23:21:30 +02:00
docs docs: capture legacy-meter weekly evidence 2026-08-30 23:27:47 +02:00
flows STATE-WP-0069 T06: add workplan flow entity and prefer open_workplans 2026-07-08 21:26:29 +02:00
history docs(history): cross-link BRIDGE-WP-0005 restart cleanup workplan 2026-06-21 20:12:17 +02:00
infra Finish CUST-WP-0011 and implement STATE-WP-0061 suggestion backlog. 2026-07-06 10:52:49 +02:00
mcp_server feat(mcp): deploy the MCP layer on central instead of tunnelling to a workstation 2026-08-24 22:54:24 +02:00
migrations feat: add repository rename lifecycle API 2026-08-29 03:17:37 +02:00
policies docs(STATE-WP-0079): retirement freeze policy, close T01 2026-08-20 07:20:56 +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 docs(ecosystem): boundary alignment and route audit (STATE-WP-0074) 2026-07-11 01:26:53 +02:00
research STATE-WP-0072: remediate remaining workstream HTTP callers 2026-07-09 01:48:53 +02:00
scripts feat: add fast forge work-record reconciliation 2026-08-30 22:38:54 +02:00
skills/state-hub docs: residual handoff in hub docs, AGENTS, and templates 2026-07-22 18:15:45 +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 fix: package quality-debt CLI support 2026-08-30 23:36:23 +02:00
workplans fix: package quality-debt CLI support 2026-08-30 23:36:23 +02:00
.custodian-brief.md chore(consistency): sync task status from DB [auto] 2026-08-30 23:14:33 +02:00
.dockerignore Locked in cytoscape.js as visualization for dep graph 2026-05-03 01:43:50 +02:00
.env.example Prepare State Hub retirement baseline 2026-08-09 16:19:53 +02:00
.gitignore docs: record August legacy-meter reviews 2026-08-19 15:04:32 +02:00
.repo-classification.yaml Mark .repo-classification.yaml human-reviewed (CUST-WP-0050 T02) 2026-06-22 11:40:43 +02:00
AGENTS.md feat: add fast forge work-record reconciliation 2026-08-30 22:38:54 +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 feat: add repository rename orchestration CLI 2026-08-29 12:00:22 +02:00
Dockerfile Include templates/ in image for RecentlyOnScope digests 2026-07-21 04:21:55 +02:00
INTENT.md Prepare State Hub retirement baseline 2026-08-09 16:19:53 +02:00
LICENSE Adopt Target Revenue Source License V1C1 (org-wide preliminary rollout) 2026-07-29 23:48:47 +02:00
Makefile feat: add fast forge work-record reconciliation 2026-08-30 22:38:54 +02:00
pyproject.toml fix: package quality-debt CLI support 2026-08-30 23:36:23 +02:00
README.md feat: add fast forge work-record reconciliation 2026-08-30 22:38:54 +02:00
repository_rename_cli.py feat: prove repository rename continuity 2026-08-29 15:05:09 +02:00
repository_rename_workplan.py docs: complete repository rename operator handoff 2026-08-29 15:46:43 +02:00
SCOPE.md docs(ecosystem): boundary alignment and route audit (STATE-WP-0074) 2026-07-11 01:26:53 +02:00
statehub_register.py feat: delegate project register; registrar-only ID minting 2026-08-18 21:51:30 +02:00
uv.lock chore(deps): refresh hub-core lock metadata 2026-08-21 21:50:44 +02:00
WORK-RECORDS.md fix: package quality-debt CLI support 2026-08-30 23:36:23 +02:00

State Hub

Hub stack glossary

Name Role
hub-core Shared library — router factories and MCP primitives
state-hub This service — dev coordination, workplans, agent MCP
core-hub Production framework — /api/v2 at hub.coulomb.social

Ecosystem architecture: /home/worsch/the-custodian/docs/hub-ecosystem-architecture.md

Cross-repo regression: /home/worsch/the-custodian/scripts/hub-ecosystem-regression.sh


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.

Production: the primary State Hub API runs in the railiance01-hosted k3s cluster. Workstation port 8000 reaches it through the ops-bridge state-hub-primary tunnel. See docs/cluster-operating-model.md for access, rollback, backups, and pragmatic limitations.

Repository rename operations use the phased, UUID-preserving workflow in docs/repository-rename-operations.md.


Setup

Prerequisites

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

First-time local development setup

The local database and API are retained for development and disaster fallback. They are not the normal production access path and conflict with the production tunnel on port 8000.

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                      # LOCAL fallback: db + migrate + uvicorn :8000

For a dashboard against that deliberate local backend, use make dashboard-local.

Production dashboard (normal operation)

The dashboard remains a workstation process, but its API is the primary State Hub on railiance01. Start the tunnel first, then start the dashboard:

make bridges      # connect workstation :8000 to primary/railiance01
make dashboard    # verify the primary identity, then serve http://127.0.0.1:3000

make dashboard refuses to start if port 8000 is unreachable or identifies itself as anything other than primary/railiance01. This prevents the empty local fallback database from being mistaken for production.

The MCP adapter is optional and is not required by the dashboard:

make mcp-http     # optional local SSE adapter on :8001

Fast work-record synchronization

Workplan files remain authoritative. Repo Manager assigns missing UUIDv5 identifiers locally, pushes the file commit, and asks the primary State Hub to derive that exact commit from Forgejo in one transactional request:

make bridges
make sync

The sync refuses an uncommitted or behind branch and will not write to a local empty database: the API must identify itself as primary/railliance01. If the primary is unavailable, Repo Manager writes an explicit pending receipt under the checkout's local .git/repo-manager/ state; rerunning make sync safely replays the current pushed state.

Use statehub fix-consistency only for the broader consistency/quality audit. It is no longer the normal registration and task-update path.

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 start Print the production UI and local fallback startup paths
make bridges Connect managed tunnels, including workstation :8000 to the railiance01 primary
make db Start the local fallback/development 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 (legacy bootstrap)
make register-from-classification REPO=slug Upsert repo from .repo-classification.yaml
make register-from-classification-all Bulk reclassify all repos with classification files
make api Start the local fallback API; replaces the production tunnel on :8000
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 Verify primary/railiance01, then start the Observable dashboard
make dashboard-local Start the dashboard against an intentional local/fallback API
make sync Push missing deterministic IDs and reconcile this repo from the exact Forgejo commit
make check Require a healthy primary/railiance01 on workstation :8000
make check-local Print /state/health without enforcing production identity
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

Repo-anchored coordination spine (STATE-WP-0065):

domains (14 market domains: infotech, financials, communication, …)
managed_repos (classification: category, domain, capability_tags, business_stake, …)
└── workplans (repo_id required; topic_id optional legacy tag)
    └── tasks
        └── progress_events
topics (optional cross-repo tag; domain_id → market domain)
decisions (FK: topic_id and/or workplan_id)

Each registered repo carries a committed .repo-classification.yaml (canon standard v1.0). Registration and reclassification use make register-from-classification.

Key enums / vocabularies

Field Values
workplan_status proposed · ready · active · blocked · backlog · finished · archived
task_status wait · todo · progress · done · cancel
repo category experimental · research · project · tooling · product · business
market domain 14 fixed slugs — see the-custodian/canon/standards/repo-classification.allowed.yaml

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_workplans": [...],
  "open_workstreams": [...]   // legacy alias of open_workplans until STATE-WP-0069 T06 retires it
}

Caching: responses are revision-gated — the API compares cheap per-table MAX(updated_at) / MAX(created_at) watermarks before rebuilding. Unchanged data returns the cached snapshot (X-StateHub-Cache: hit-revision). When core data changes, the last good snapshot may be served immediately while a background refresh runs (X-StateHub-Cache: stale). Force a synchronous rebuild with ?refresh=true or Cache-Control: no-cache. Infrastructure probes should use /state/health, not /state/summary.

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 · create_workplan · update_workplan_status · register_repo_from_classification

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

Legacy workstream_* tool names remain as aliases — see mcp_server/TOOLS.md.


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
  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.