Files
the-custodian/runtime/README.md
tegwick 2fdbcb5d7a feat(CUST-WP-0001): implement Custodian Agent Runtime bootstrap
T2 complete: OODA loop skeleton with LLM integration, bounded actions,
and 32 offline unit tests.

Deliverables:
- runtime/agent.py     — CLI entry point (--domain/--all/--dry-run/--llm)
- runtime/context.py   — Observe: fetch_state + build_context
- runtime/actions.py   — Act: parse_plan + execute (3 sanctioned writes)
- runtime/README.md    — usage guide and architecture overview
- runtime/tests/       — 32 tests, fully offline
- runtime/pyproject.toml — standalone package with llm-connect dep
- canon/architecture/adr-002-custodian-agent-runtime-design.md

Key design decisions (ADR-002):
- Lives in runtime/ (not a new repo) — tight canon/state-hub coupling
- ClaudeCodeAdapter by default (local-first, no API key)
- Single-pass synchronous OODA for v0.1 simplicity
- Exactly 3 sanctioned write ops: add_progress_event, update_task_status, flag_for_human
- LLM returns JSON block in markdown for structured+auditable output

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 22:36:24 +01:00

110 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Custodian Agent Runtime — v0.1
Single-pass OODA agent loop. Observes project state via the State Hub, reasons
about it with an LLM, and executes bounded write operations.
## Architecture
```
agent.py CLI entry point + OODA orchestrator
context.py Observe: fetch state-hub data + build LLM context prompt
actions.py Act: execute sanctioned write operations
prompts/ System prompt templates (future)
policies/ Agent-level policies (future)
tool_adapters/ Additional MCP/API tool adapters (future)
tests/ Unit tests (offline, no live API required)
```
See `canon/architecture/adr-002-custodian-agent-runtime-design.md` for
all architectural decisions.
## OODA Loop
```
Observe → fetch_state(domain) # HTTP GET /state/summary or /state/domain/{slug}
Orient → load_constitution() # reads canon/constitution/
build_context(state, const) # assembles LLM prompt
Decide → LLM call via llm-connect # returns markdown + JSON action plan
Act → parse_plan(response) # extract JSON block
execute(plan) # run sanctioned writes
```
## Sanctioned Write Operations (ADR-002 D4)
Only three operations may be executed without human approval:
| Operation | State-hub endpoint | Reversible |
|---|---|---|
| `add_progress_event` | `POST /progress/` | Yes (append-only log) |
| `update_task_status` | `PATCH /tasks/{id}/` | Yes |
| `flag_for_human` | `PATCH /tasks/{id}/` | Yes (clear with `clear_human_flag`) |
## Prerequisites
- State-hub running: `cd state-hub && make api`
- LLM available: `claude` CLI in PATH (for default `claude-code` provider)
or set `OPENROUTER_API_KEY` / `GEMINI_API_KEY` for other providers
## Install
```bash
cd runtime
uv sync
```
## Usage
```bash
cd runtime
# Focus on custodian domain (cheaper — ~10% of full summary tokens)
uv run python agent.py --domain custodian
# Full cross-domain view
uv run python agent.py --all
# Preview actions without executing
uv run python agent.py --domain custodian --dry-run
# Use a different LLM provider
uv run python agent.py --domain custodian --llm gemini
uv run python agent.py --domain custodian --llm openrouter
# Custom state-hub URL
uv run python agent.py --domain custodian --api-base http://10.0.0.5:8000
```
## Output
The agent prints a trace to stdout:
```
[custodian-agent] 2026-03-12T20:00:00 scope=domain=custodian
[observe] fetching state from state-hub…
[orient] loading constitution and building context…
[decide] calling LLM via provider='claude-code'…
[act] executing plan (live): 1 events, 0 task updates, 0 flags
✓ add_progress_event: 'Reviewed custodian domain: 2 active workstreams…'
[custodian-agent] done — 1 actions.
```
The LLM's reasoning trace is saved to `memory/working/agent-session-{ts}-{scope}.md`.
## Tests
```bash
cd runtime
uv run pytest -v
```
All 32 tests run offline (no live state-hub, no LLM API key required).
## Extending
- **New observations**: extend `build_context()` in `context.py`
- **New actions**: add to `actions.py` and update `SANCTIONED_ACTIONS` — but
any expansion of the action surface requires a new ADR and human approval
(see constitution §2§4)
- **Tool adapters**: add to `tool_adapters/` following the llm-connect
`LLMAdapter` pattern