- Migration p3k4l5m6n7o8: nullable repo_id FK on capability_catalog
- PATCH /capability-catalog/{id} endpoint for back-filling repo attribution
- register_capability MCP tool accepts optional repo_slug
- get_domain_summary now includes compact capabilities list (type+title+repo_slug)
- New get_capability_profile MCP tool: domain → repos → capabilities tree
- 6 repo descriptions populated; 25 catalog entries attributed to repos
- 9 new capabilities registered for personhood, foerster_capabilities, coulomb_social
- TOOLS.md: Capability Catalog & Requests section with full tool reference
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
268 lines
9.8 KiB
Markdown
268 lines
9.8 KiB
Markdown
---
|
|
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=<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"
|
|
```
|
|
|
|
```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": "<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"
|
|
```
|
|
|
|
```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"
|
|
```
|