diff options
Diffstat (limited to 'CLAUDE.md')
| -rw-r--r-- | CLAUDE.md | 63 |
1 files changed, 62 insertions, 1 deletions
@@ -78,7 +78,7 @@ Config defaults to `~/.claudomator/config.toml`. Data is stored in `~/.claudomat | `internal/agentloop` | Provider-neutral tool-use control-flow loop shared by all `NativeRunner`s | | `internal/sandbox` | `Sandbox` interface (`HostSandbox`/`DockerSandbox`) + pre-tool-use guardrail hooks | | `internal/role` | `RoleConfig`/`Tier`/`Rung` — per-role system prompt + provider/model escalation ladder | -| `internal/scheduler` | `Scheduler` — polls role-typed FAILED tasks and retries/escalates them per their role's ladder, and (Phase 7c) role-typed BLOCKED tasks whose ask_user question has timed out; `StoryOrchestrator` (Phase 7b) — polls stories and drives Builder → Evaluators → Arbitration → REVIEW_READY | +| `internal/scheduler` | `Scheduler` — polls role-typed FAILED tasks and retries/escalates them per their role's ladder, and (Phase 7c) role-typed BLOCKED tasks whose ask_user question has timed out; `StoryOrchestrator` (Phase 7b) — polls stories and drives Builder → Evaluators → Arbitration → REVIEW_READY, and (Phase 8) a `DONE` story through a retro stage proposing `role_configs` drafts | | `internal/story` | `Epic`/`Story` — planning layer above the flat task tree; data model + CRUD only (see `internal/scheduler.StoryOrchestrator` for the orchestration that drives it) | | `web` | Embedded static UI (`embed.go`) | @@ -518,6 +518,67 @@ distinguishable in the event stream. `GET /api/tasks?needs_review=true` surfaces flagged tasks for a human to double-check the system's stand-in answer later. +### Retro & the self-improvement loop (Phase 8) + +Closes the loop the whole role-versioning system (Phase 5) was built for: +when a story reaches `DONE`, `internal/scheduler.StoryOrchestrator` spawns a +`retro`-role task that reflects on the story and proposes improved +`role_configs` drafts for a human to review and activate. + +- **Trigger**: `StoryOrchestrator.Tick` now routes a story at status `DONE` + to `processRetro` instead of `processStory` (`CANCELLED` stories are still + skipped entirely, unchanged). `processRetro` never spawns or mutates a + Builder/Evaluator/Arbitration task itself — it only *looks up* the + already-settled pipeline via read-only `findEvaluators`/`findArbitration` + (structurally identical to `ensureEvaluators`/`ensureArbitration` but + without their spawn side effects) to find the Arbitration task the retro + task should depend on. If the pipeline isn't fully settled yet (shouldn't + happen for a real `DONE` story), it simply has nothing to do this tick. +- **Idempotency**: structural, like the rest of this file — it looks for an + existing `retro`-role dependent of the Arbitration task before spawning + one, the same "does a role-matched dependent already exist" check + `ensureArbitration` uses. +- **Instructions**: `buildRetroInstructions` assembles the story's spec/ + acceptance criteria, its full task tree (`taskTree`, the same + parent/dependents BFS `GET /api/stories/{id}/task-tree` performs, walked + directly against `StoryStore` rather than over HTTP), each task's + accumulated cost and highest escalation rung (`ListExecutions`), the + currently active `role_configs` for every role encountered + (`GetActiveRoleConfig`), and the story's own event stream — evaluator + verdicts, arbitration decision (`ListEvents`) — then instructs the retro + agent to call `propose_role_config` for any role worth revising and + `report_summary` with the qualitative lessons either way. +- **Reporting mechanism**: a 6th `AgentChannel` method, + `ProposeRoleConfig(ctx, role.RoleConfig) (version int, err error)`, added + following `ProposeEpic`'s precedent (structured tool call over + summary-parsing). `storeChannel.ProposeRoleConfig` + (`internal/executor/channel.go`) calls the same `Store.CreateRoleConfig` + `POST /api/roles/{role}/versions` already uses, hardcoding + `proposed_by: "retro"`, and — never reading or touching whatever version + is currently `active` for that role. It also records + `event.KindRoleConfigProposed` (payload `{role, version}`) attached to the + *calling task's own ID* (roles have no first-class row of their own the + way epics/stories do). Exposed as a `propose_role_config` tool on both + transports — `internal/agentloop/tools.go` and + `internal/executor/agentmcp.go` — decoding directly into + `role.RoleConfig`'s own JSON shape (no parallel input type). +- **`event.KindRetroCaptured`**: once the retro task reaches `COMPLETED` + (auto-accepted from `READY` exactly like every other task in this + pipeline), `finalizeRetro` reads the retro task's own event stream for + every `KindRoleConfigProposed` it recorded and aggregates them into a + single event attached to the **story's** ID: payload `{task_id, + proposals: [{role, version}, ...], summary}` — `summary` is the retro + task's own reported summary, satisfying "capturing lessons" even when zero + config changes are proposed. Guarded by an in-memory `handledRetro` set + (keyed by retro task ID) so a story sitting at `DONE` forever doesn't + re-emit the event every tick — the same accepted per-process-only + simplification as `Scheduler.handled`/`handledVerdicts` above. +- **Human activation, unchanged**: `POST /api/roles/{role}/activate` (Phase + 5) is untouched — draft rows land via the exact same `CreateRoleConfig` + path the human-facing `POST /api/roles/{role}/versions` endpoint uses, so + they're structurally identical and immediately visible via the existing + `GET /api/roles/{role}/versions` with no changes required. + --- |
