Files
the-custodian/workplans/CUST-WP-0031-capability-registry.md

9.8 KiB

id, type, title, domain, repo, status, owner, topic_slug, created, updated, state_hub_workstream_id
id type title domain repo status owner topic_slug created updated state_hub_workstream_id
CUST-WP-0031 workplan Domain Capability Registry custodian the-custodian done custodian custodian 2026-03-31 2026-03-31 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

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"
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=<slug>&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"
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": "<topic 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=<slug> and
  GET /capability-catalog/?domain=<slug>&status=active, then assemble.
  For the all-domains case iterate over GET /domains/ (active only).
state_hub_task_id: "b380fd2b-28fa-4c47-96d6-4c65a0300c44"
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-cluster (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"
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"
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"
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"