Learning loop
September 21, 2026 · View on GitHub
Audience: Dogfooding agent_deck on the monorepo dev stack
Prereqs: npm run dev:all · seed playbooks · use with dev MCP port
Related: learning-loop design · architecture revisit
One-time dev setup
npm run dev:all
# Optional: seed a visual diff demo proposal
bash .temporal/scripts/seed-pr-handoff-proposal.sh
AGENT_DECK_DEV=1 npm run agent-deck:dev -- use dev --mcp-port 3001 --client both
Restart Cursor / Claude Code so MCP reloads :3001. Dashboard: http://localhost:3000 · Review queue: http://localhost:3000/playbook-patches
| Check | Expected |
|---|---|
.cursor/mcp.json | "url": "http://127.0.0.1:3001/mcp" |
.agent-deck/use.json | deckId for dev deck in ~/.agent-deck/dev |
.cursor/rules/agent-deck-stubs/ | pb_*.mdc stubs with Use when the user asks about… in description: |
| Session bind | Agent uses use.json deckId or you say "use dev deck" |
Scenario A — Undertriggering telemetry (read path)
Goal: playbook_events records fetches; dashboard shows count.
- New chat, bind dev deck.
- Ask: "Follow the dev smoke checklist" (should match stub /
pb_dev_smoke_checklist). - Confirm agent calls
get_playbook("pb_dev_smoke_checklist")(not improvised steps only). - Dashboard → open that playbook → fetch count increased.
Pass: fetch count ≥ 1 after step 2.
Fail signals: agent improvises without get_playbook; count stays 0.
Scenario B — Update case (correction → proposal)
Goal: User correction on playbook-shaped output creates an update proposal with evidence.
- Ask: "Summarize this PR" (matches
pb_pr_summary). - Agent produces a summary (ideally after
get_playbook). - Correct it: "Always include a Test plan section — you missed it."
- Agent should
propose_playbook_patch(notupdate_playbook) with e.g.add_item+evidence.user_feedback_excerptquoting your correction. - Dashboard → Playbook patches → open proposal → preview diff shows new checklist/gotcha line.
- Accept → playbook body updates; proposal status
accepted.
Pass: queue shows one update proposal; after accept, get_playbook body includes the lesson.
Fail signals: update_playbook without you asking; no evidence; full rewrite_body for a one-line fix.
Scenario C — Genesis case (no playbook → create proposal)
Goal: Correction on a task no playbook covers files a tiny create proposal.
- Ask something not in dev deck triggers, e.g. "Draft a standup update for the team" (no matching stub).
- Agent answers; you correct: "Keep it under 5 bullets and lead with blockers."
- Before ending, agent should
propose_playbook_patch { kind: "create", new_playbook: { title, triggers, body with one gotcha } }. - Dashboard → accept create → new
pb_*on collection; add to dev deck if not auto-linked. - Run
AGENT_DECK_DEV=1 npm run agent-deck:dev -- use dev --mcp-port 3001 --refreshif triggers were set.
Pass: new playbook in queue; after accept, stub appears on next use --refresh.
Fail signals: agent skips proposal; writes a 2-page playbook in the proposal.
Scenario D — Explicit edit (user-directed)
Goal: When you direct a playbook edit, agent uses update_playbook (immediate), not the queue.
- Say: "Update the PR summary playbook to say we prefer conventional commit titles in the summary."
- Agent calls
update_playbook(you already reviewed intent in chat). - No new row in playbook-patches queue (or only if agent mis-fires propose).
Pass: playbook body changes immediately; no pending proposal for the same change.
Scenario E — Accept → stub refresh hint
Goal: Trigger changes surface a refresh hint.
- From Scenario B or C, accept a patch that changes
triggers(or create with new triggers). - Accept API response includes message about
agent-deck use --refresh. - Run refresh; stub
description:matches new triggers.
Pass: stub file updated; old trigger text gone from .mdc frontmatter.
Scenario F — Reject path
Goal: Rejected proposals do not mutate playbooks.
- File any proposal (B or C).
- Dashboard → Reject with reason "too specific to this repo".
get_playbookbody unchanged; patch statusrejected.
Scenario G — Agent-first deck switch (no use)
Goal: Your normal workflow still works without repo files.
- Temporarily rename
.agent-deck/use.jsonaside. - New chat: "Use the dev deck" →
bind_workspace(bootstrap) — orswitch_deck+ human approval when already bound. - Playbooks available via
get_bound_deck; stubs optional.
Pass: deck binds; playbooks listed; no dependency on use.json.
Scenario H — Propose-time 409 (bad ops rejected)
Goal: Invalid or no-op patches fail at propose, not as silent empty diffs.
- With dev stack running, attempt (via agent or curl)
propose_playbook_patchwithamend_itemon a prose line (not a-list item). - Expect 409 with message about list-item anchors or
rewrite_body. - Attempt
set_triggerswith the same triggers as the live playbook. - Expect 409
no change— proposal is not stored.
Pass: no new row in queue for failed proposes; error text is actionable.
Fail signals: 201 created with identical before/after in preview.
# Prose amend (should 409)
curl -s -X POST http://127.0.0.1:8000/api/playbook-patches \
-H 'Content-Type: application/json' \
-d '{
"kind": "update",
"playbook_id": "pb_pr_summary",
"ops": [{
"op": "amend_item",
"section": "Output",
"anchor": "- 3 bullets: what changed, why, test plan",
"text": "- 4 bullets including risks"
}],
"rationale": "409 smoke"
}' | python3 -m json.tool
Scenario I — Visual diff review (dashboard)
Goal: Review queue shows GitHub-style unified diff and explicit empty/error states.
- Run
bash .temporal/scripts/seed-pr-handoff-proposal.sh(or accept an existingrewrite_bodyproposal). - Open http://localhost:3000/playbook-patches — select the proposal.
- Confirm Detail panel:
- Narrow proposals list, wide detail column
- Your correction evidence above the diff
- Unified diff with red
-/ green+rows (not side-by-side full bodies) - Your decision cluster below the diff (Accept, then Reject + reason)
- For a legacy no-op proposal (if any): amber No change detected banner; Accept disabled.
- For a stale/broken preview: red Preview failed banner with 409 message.
Pass: changed lines are obvious at a glance; empty/error states are explicit.
Fail signals: two identical full-text columns; Accept enabled with no diff rows.
Quick API smoke (no IDE)
# Propose update (agent client — propose does not require dashboard header)
curl -s -X POST http://127.0.0.1:8000/api/playbook-patches \
-H 'Content-Type: application/json' \
-d '{
"kind": "update",
"playbook_id": "pb_pr_summary",
"ops": [{ "op": "add_item", "section": "Gotchas", "text": "Include Test plan section" }],
"rationale": "API smoke test",
"evidence": {
"failure_summary": "PR summary omitted Test plan section",
"user_feedback_excerpt": "you missed Test plan"
}
}' | python3 -m json.tool
# List queue → accept by id → fetch count
curl -s http://127.0.0.1:8000/api/playbook-patches?status=proposed \
-H 'x-agent-deck-client: dashboard' | python3 -m json.tool
What we are not testing here
- agent-dealer reflect →
POST /api/playbook-patches(deferred PR) - merge / retire patch kinds (schema only today)
- Production ports
:1110/~/.agent-deck(useAGENT_DECK_DEV=1for isolated dev DB)