Files
the-custodian/workplans/CUST-WP-0022-capability-requests.md
tegwick f85c5e4d49 feat(capability-requests): add cross-domain capability catalog and request routing
Introduces a capability catalog (CUST-WP-0022) so domains can advertise what
they provide and agents can request capabilities from other domains with
auto-routing, lifecycle tracking, and task-unblocking on completion.

- New models: CapabilityCatalog, CapabilityRequest with full lifecycle
  (requested → accepted → in_progress → ready_for_review → completed/rejected/withdrawn)
- Migration i6d7e8f9a0b1: capability_catalog + capability_requests tables
- Router /capability-catalog and /capability-requests with accept/status endpoints
- 7 new MCP tools: register_capability, list_capabilities, request_capability,
  accept_capability_request, update_capability_request_status,
  list_capability_requests, get_capability_request
- StateSummary gains open_capability_requests count
- Dashboard: capability-requests.md page + docs/capabilities.md + docs/scope.md
- SCOPE.md: three seed capabilities documented (MCP registration, state tracking, SBOM)
- scope.template: Provided Capabilities section with example block
- scripts/ingest_capabilities.py + make ingest-capabilities[/-all] targets

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:07:50 +01:00

147 lines
4.5 KiB
Markdown

---
id: CUST-WP-0022
type: workplan
title: Capability Request System
domain: custodian
status: done
owner: custodian
topic_slug: the-custodian
created: "2026-03-19"
updated: "2026-03-19"
state_hub_workstream_id: "7cc173c6-f63e-43b0-af8e-04df7f95b96c"
---
# CUST-WP-0022 — Capability Request System
## Purpose
Enable cross-domain capability requests without requiring the requester to know
which domain is responsible. A net-kingdom dev-worker can say "I need a privacy
idea instance on the cluster" and the system routes it to railiance, manages the
fulfillment lifecycle, and auto-notifies when work is ready for review.
## Scope
- `capability_catalog` table — domains register capabilities they can provide
- `capability_requests` table — lifecycle from requested → completed with auto-routing
- Soft routing via keyword matching; broadcast fallback when ambiguous
- Auto-notifications via AgentMessage on every lifecycle transition
- Auto-unblock of blocking tasks on completion
- 7 MCP tools, 1 dashboard page, StateSummary integration
## Files Changed
| File | Change |
|------|--------|
| `migrations/versions/i6d7e8f9a0b1_capability_requests.py` | New migration |
| `api/models/capability_catalog.py` | New model |
| `api/models/capability_request.py` | New model |
| `api/models/__init__.py` | Export new models |
| `api/schemas/capability_request.py` | New schemas (Catalog + Request CRUD) |
| `api/routers/capability_requests.py` | New router (lifecycle guard, routing, auto-notify) |
| `api/main.py` | Mount new router |
| `api/schemas/state.py` | Added `open_capability_requests` to StateSummary |
| `api/routers/state.py` | Count open requests in summary builder |
| `mcp_server/server.py` | 7 new MCP tools |
| `dashboard/src/capability-requests.md` | New dashboard page (Kanban + KPIs) |
| `dashboard/observablehq.config.js` | Nav entry |
| `tests/test_capability_requests.py` | 14 test cases |
| `scripts/ingest_capabilities.py` | Ingest `capability` blocks from SCOPE.md → catalog API |
| `scripts/project_rules/scope.template` | Added `## Provided Capabilities` section |
| `SCOPE.md` (repo root) | Added 3 capability blocks for custodian domain |
| `dashboard/src/docs/capabilities.md` | Reference doc for capabilities |
| `dashboard/src/docs/scope.md` | Reference doc for SCOPE.md |
## Tasks
### T01: Write TDD test suite
```task
id: CUST-WP-0022-T01
status: done
priority: high
state_hub_task_id: "34f40ede-3396-4ef2-ae5a-9af4edbfc17d"
```
### T02: Alembic migration
```task
id: CUST-WP-0022-T02
status: done
priority: high
state_hub_task_id: "094fd9de-e4fa-4b9f-bc70-31f049907fa9"
```
### T03: SQLAlchemy models
```task
id: CUST-WP-0022-T03
status: done
priority: high
state_hub_task_id: "5fadabfb-100e-493e-a950-2b5c3d286c6b"
```
### T04: Pydantic schemas
```task
id: CUST-WP-0022-T04
status: done
priority: high
state_hub_task_id: "1efabfde-e9de-41d9-a864-2eb1e9e2dae6"
```
### T05: Router with lifecycle + routing + auto-notify
```task
id: CUST-WP-0022-T05
status: done
priority: high
state_hub_task_id: "57f754b6-022c-4829-adb5-45629567d575"
```
### T06: Run tests, iterate until green
```task
id: CUST-WP-0022-T06
status: done
priority: high
state_hub_task_id: "41ef3722-ffbe-41bb-9ef4-8485db37bb0a"
```
### T07: MCP tools
```task
id: CUST-WP-0022-T07
status: done
priority: medium
state_hub_task_id: "12f28272-2767-4d8e-80a0-a28bb172d6af"
```
### T08: Dashboard page
```task
id: CUST-WP-0022-T08
status: done
priority: medium
state_hub_task_id: "d6596ac4-53ac-4b44-bdd2-635b5c109372"
```
### T09: StateSummary integration
```task
id: CUST-WP-0022-T09
status: done
priority: medium
state_hub_task_id: "964e7f8b-e9f6-41f9-9eb1-ba35e48adf55"
```
### T10: Seed catalog entries (file-first via SCOPE.md)
```task
id: CUST-WP-0022-T10
status: done
priority: low
state_hub_task_id: "2c747cde-bc00-4fd9-a3cd-625709ac6d6d"
```
## Design Notes
- **Routing algorithm**: Exact match on capability_type in catalog. If 1 result → auto-assign.
If multiple → keyword-score description against entry keywords, pick unambiguous winner.
If 0 or tied → fulfilling_domain_id=NULL, broadcast AgentMessage.
- **Lifecycle transitions** guarded by `_VALID_TRANSITIONS` dict (same pattern as contributions).
- **Auto-unblock**: On `completed`, if `blocking_task_id` set and task status is `blocked`,
patches it to `todo` and clears `blocking_reason`.
- **Status uses String(20)** not SA Enum — avoids ALTER TYPE pain in future migrations.
- **Third sanctioned write use case** — alongside resolve_decision and get_next_steps.