--- id: CUST-WP-0031 type: workplan title: "Domain Capability Registry" domain: custodian repo: the-custodian status: done owner: custodian topic_slug: custodian created: "2026-03-31" updated: "2026-03-31" state_hub_workstream_id: "7b480543-b18a-4d79-a30b-7b34bce27ee5" --- # Domain Capability Registry ## Goal Give worker agents a single efficient MCP call to understand what each domain/repo does and what capabilities it exposes — without having to explore source repositories directly. The immediate driver is that inter-hub workers on CoulombCore need to discuss operational setup and security architecture (e.g. key-cape's SSH CA role, net-kingdom's SSO platform) but can only see repos checked out locally. Key-cape and net-kingdom are not checked out there; the worker must fall back to the state-hub for this information. ## Background ### What exists - 25 `CapabilityCatalog` entries across four domains (railiance: 11, netkingdom: 6, custodian: 5, markitect: 3). - `CapabilityCatalog` is domain-scoped only — no `repo_id` FK, so the SSH CA capability in netkingdom cannot be attributed to key-cape vs net-kingdom. - `get_domain_summary` is the cheap worker orientation call (~10% token cost of full state summary) but returns **no capability information**. - `list_capabilities` works but returns verbose full records; workers must call it per domain and get unstructured JSON. - `ManagedRepo` has a `description` field but 8 of 17 repos have it empty. - personhood, foerster_capabilities, and coulomb_social have zero capabilities registered. ### Design Three complementary changes: 1. **Schema** — add nullable `repo_id` FK to `CapabilityCatalog` so each capability can be attributed to the repo that provides it. 2. **MCP orientation** — extend `get_domain_summary` to include a compact `capabilities` list (type + title + repo_slug only, no keywords/description) so the standard worker orientation call already surfaces what the domain provides. 3. **Full-detail tool** — new `get_capability_profile(domain_slug?)` MCP tool that returns a complete registry: domain → repos (with description) → capabilities (with description). Designed for deep-dive or cross-domain architectural discussion. Data tasks: populate missing repo descriptions and back-fill `repo_id` on existing catalog entries; register capabilities for the three empty domains. ## Implementation Plan ### Phase 1 — Schema + MCP - Add nullable `repo_id` FK on `CapabilityCatalog`; update `register_capability` to accept an optional `repo_slug` that resolves to `repo_id`. - Add `capabilities` compact list to `get_domain_summary` response. - New MCP tool `get_capability_profile`. ### Phase 2 — Data Population - Populate `description` for the 8 repos that lack it. - Back-fill `repo_id` on existing 25 catalog entries. - Register capabilities for personhood, foerster_capabilities, coulomb_social. ## Tasks ```task id: T01 title: "Add repo_id FK to CapabilityCatalog" status: done priority: high description: > 1. Write Alembic migration: add `repo_id` UUID nullable FK column to `capability_catalog` referencing `managed_repos.id` (ON DELETE SET NULL). Add index on `repo_id`. Down revision from latest head. 2. Add `repo_id: uuid.UUID | None` to the CapabilityCatalog model (managed_repo.py FK relationship, nullable). 3. Update CapabilityCatalog schema (CapabilityRead, CapabilityCreate) to include `repo_id: uuid.UUID | None` and `repo_slug: str | None` (computed via relationship). 4. Update the capability-catalog router: if `repo_slug` is provided on POST, resolve it to `repo_id` (404 if not found in the same domain). 5. Update `register_capability` MCP tool to accept optional `repo_slug` parameter and forward it. 6. Run `make test` — no regressions. state_hub_task_id: "8d5e3e37-c753-4cdc-9211-83ee39f6b0f2" ``` ```task id: T02 title: "Include compact capabilities in get_domain_summary" status: done priority: high description: > Extend the `get_domain_summary` MCP tool response to include a `capabilities` list alongside `repos` and `workstreams`. Each entry should be compact: {type, title, repo_slug} only (no description or keywords, to keep token cost low). Implementation: in mcp_server/server.py, after building the summary dict, call GET /capability-catalog/?domain=&status=active and append `capabilities: [{capability_type, title, repo_slug}]` to the response. The `repo_slug` field is nullable (domain-level capabilities have null). Cap at 20 entries to protect token budget; add a `capabilities_truncated` boolean flag if there are more. state_hub_task_id: "ac47994c-efe9-404f-8065-9adf2e923d4c" ``` ```task id: T03 title: "New MCP tool: get_capability_profile" status: done priority: high description: > Add a new MCP tool `get_capability_profile(domain_slug: str | None = None)` to mcp_server/server.py. Behaviour: - If domain_slug is provided: return the profile for that one domain. - If omitted: return profiles for all active domains. Response structure per domain: { "slug": "netkingdom", "title": "", "repos": [ { "slug": "key-cape", "name": "...", "description": "...", "capabilities": [ {"type": "security", "title": "SSH CA", "description": "...", "keywords": [...]} ] }, // domain-level capabilities (repo_slug null) listed at the end under // a synthetic repo entry {"slug": null, "name": "(domain-level)", ...} ] } Implementation: call GET /repos?domain= and GET /capability-catalog/?domain=&status=active, then assemble. For the all-domains case iterate over GET /domains/ (active only). state_hub_task_id: "b380fd2b-28fa-4c47-96d6-4c65a0300c44" ``` ```task id: T04 title: "Populate missing repo descriptions" status: done priority: medium description: > Use PATCH /repos/{slug}/ to set `description` for the 8 repos that currently have none. Write concise scope descriptions (2-3 sentences each) by reading the repo's CLAUDE.md or README if available; otherwise infer from the slug and domain context. Repos needing descriptions: - the-custodian (custodian domain) - activity-core (custodian domain) - kaizen-agentic (custodian domain) - llm-connect (custodian domain) — already has description, skip - markitect-project (markitect domain) - railiance-bootstrap (railiance domain) - railiance-hosts (railiance domain) - ops-bridge (custodian domain) — already has description, skip Confirm final list by re-checking GET /repos/ at task start. state_hub_task_id: "00d44110-fcb4-45cc-8bc8-454af2629d2f" ``` ```task id: T05 title: "Back-fill repo_id on existing capability catalog entries" status: done priority: medium description: > After T01 lands, update the 25 existing catalog entries to set repo_id where the capability is clearly from a specific repo. Use PATCH /capability-catalog/{id} (add this endpoint if missing) or re-register with repo_slug. Key attributions: netkingdom domain: - "Container image build and publish (GHCR)" → net-kingdom - "Bootstrap local identity service" → key-cape - "SSO/MFA platform (Keycloak)" → key-cape - "NetKingdom IAM Profile specification" → net-kingdom (spec lives there) - "Identity migration tooling" → key-cape - "OIDC/PKCE authentication (lightweight mode)" → key-cape railiance domain: - All 11 entries → railiance-platform or railiance-cluster or railiance-infra (review titles to assign; most go to railiance-platform) custodian domain: - "SSH reverse tunnel connectivity" → ops-bridge - "Durable event-triggered task factory" → activity-core - "SBOM and licence reporting" → the-custodian (state-hub) - "Cross-domain state tracking" → the-custodian (state-hub) - "MCP tool registration" → the-custodian (state-hub) markitect domain: - All 3 → markitect-project Note: a PATCH endpoint on /capability-catalog/{id} does not currently exist. Add a minimal one in T01 or add it here: PATCH /capability-catalog/{id} accepting {repo_slug?, description?, keywords?, status?}. state_hub_task_id: "7f0748c7-bdee-4801-b870-d4940a5a2e63" ``` ```task id: T06 title: "Register capabilities for personhood, foerster_capabilities, coulomb_social" status: done priority: medium description: > Register at least 3 capabilities per missing domain using register_capability (MCP tool or POST /capability-catalog/). personhood domain: - "Rights and obligations framework modelling" (type: governance) - "Entity consent and data-subject lifecycle" (type: governance) - "Privacy-by-design compliance checking" (type: security) foerster_capabilities domain: - "Agency capability taxonomy" (type: governance) - "Capability gap analysis" (type: data) - "Agent persona specification" (type: governance) coulomb_social domain: - "Co-creation marketplace workflow" (type: api) - "Contribution matching and brokerage" (type: data) - "Contributor reputation tracking" (type: data) Write descriptions and keywords that would route capability requests correctly to these domains. state_hub_task_id: "c6e1be52-961c-4e34-96b1-e450d64298df" ``` ```task id: T07 title: "Consistency gate and smoke test" status: done priority: low description: > 1. Run `make test` — all existing tests must pass. 2. Run `make fix-consistency REPO=the-custodian`. 3. Manual smoke test via Python MCP client: - Call get_domain_summary("netkingdom") and verify capabilities list appears with at least the 6 netkingdom entries. - Call get_capability_profile("netkingdom") and verify key-cape entries have repo_slug set. - Call get_capability_profile() (no arg) and verify all 7 active domains appear. 4. Add a note to TOOLS.md about the new get_capability_profile tool. state_hub_task_id: "7e07e32c-683d-47a1-951c-beace9f245a6" ```