Skip to content

Playbooks 1.0: composed rendering, subgraphs, run state, metadata-driven runner, lessons - #19

Closed
A wants to merge 156 commits into
masterfrom
v1.0
Closed

Playbooks 1.0: composed rendering, subgraphs, run state, metadata-driven runner, lessons#19
A wants to merge 156 commits into
masterfrom
v1.0

Conversation

@A

@A A commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Part of #18.

Overview

The playbook track toward 1.0 — eighteen sprints on the v1.0 branch:

  • Groom-as-Playbook pilot_playbook_driving.j2 shared driving protocol, core discovery scope, dir-form steps, Jinja-rendered bodies with --step / --project, the core groom playbook + experimental /groom-playbook skill (parallel to /groom, which stays canonical).

  • Jinja include resolution — playbook/step-dir-relative {% include %} via per-body ChoiceLoader chains.

  • Subgraphs with repeat — one level of nested graphs (dependencies + inner graph + driver-judged repeat prose), per-scope wave resolution, subgraph render sections; step bodies no longer embedded in the composed render.

  • Run state machines — opt-in states: in playbook.yaml (artifact-backed, {instance}-aware), playbook-state frontier reader + playbook-transition as the single writer of run state with frontmatter-update/script hooks, resumable runs. File-target frontmatter-update hooks bootstrap a frontmatter block on files that lack one.

  • Metadata-driven runner — uniform --step fetch for every section, bootstrap-spawn protocol: the driver never pastes step bodies, delegated agents fetch their own instructions.

  • Playbook lessons_lessons/ dirs at four scopes (global root, project root, playbook, step via step: frontmatter), merged across discovery roots most-specific-wins, injected by render-playbook: composed ## Lessons section for the run, step lessons appended to --step output, --no-lessons escape hatch. Playbook name shadowing replaced by a blocking name-clash STOP.

  • Playbook-authoring into core + delegation-level model — the playbook-authoring playbook and the shared _lib/ eval engine (promptfoo assert modules, subscription-auth claude provider, grader/rubric prompts, return-contract convention) move into the plugin as core assets; step field agent: renamed to detached: framework-wide (legacy key → blocking STOP); advisory inputs:/outputs: step frontmatter dropped from the framework (superseding the earlier metadata-runner shape); delegation levels + review-gate design taught to the authoring playbook.

  • Groom playbook respec (v3) — plan-as-directory: plans/{slug}/ doubles as plan directory and run workdir (index.md + plan.md), retiring _runs/; directory-plan support in the plan model; research_agent config key + driving-partial protocol updates; regenerated manifest, preamble, and _scripts/; step prompts rewritten to the new step contracts; per-step eval suites and fixtures realigned. Then the graph collapsed to six steps (intake → research-codebase / research-web → draft-plan → cross-review → present) with a new detached second-model cross-review step, intake reworked around context tables + an on-disk brief, and gate confirmations / step questions routed through AskUserQuestion (review gates stay prose asks).

  • Develop-as-Playbook port — the core develop playbook, parallel to /develop (which stays canonical): flat chain intake → provision → develop-loop → verify → wrap-up with inline_steps; one run machine writing the shared plan-lifecycle statuses straight onto the plan's own index.md (plan directory = run workdir, no _scripts/, no sprints.md re-render); verify is the only detached step (sonnet:medium), a guardrails-only validator with no user-review gate — the run's only stops are the branch-name confirmation and intake approval; step bodies stay near-verbatim to the skill prose with the referenced docs and partials wired (_git_guide shared at playbooks/_partials/); authoring _specs/ + decision log committed alongside.

  • Committed playbook reportsbooping render-playbook gains a repeatable --set <key>=<value> config-override flag and a config-pinnable now() (--set now=… freezes every rendered timestamp), making renders byte-reproducible; a minimal fixture vault at playbooks/_fixtures/vault/ makes them project-independent; just playbook-reports renders every core playbook into a committed playbooks/<name>/_reports/output.md, so source drift shows up as a diff.

  • Retro-as-Playbook port — the core retro playbook, parallel to /retro (which stays canonical): flat chain intake → prepare → gather-feedback → research-issues → synthesize → save, step bodies built verbatim on the skill's phases (intake = Phase 0, prepare = Phase 1 with the two parallel mining briefs, gather-feedback = Phase 2 whole — open-ended round then issue triage + per-plan goal verdicts, research-issues = Phase 3); run machine awaiting-retro → awaiting-learning on the primary plan's own index.md, exit edge stamping reviewed_at and closing the multi-plan working set via a close-working-set script; the save closing report tables the issues per plan with root causes + action items; the retrospective template moved out of the eagerly-embedded partial into lazy-loaded docs/retrospective_template.md, read at draft time by both the skill and the playbook; authoring _specs/ + decision log committed alongside. Plan discovery hardening rode along: plans/{slug}/index.md recognized beside plan.md (plan.md wins in legacy dual-file dirs), unloadable plan files skipped with a warning instead of crashing, and the develop-loop rule that every milestone group gets a fresh worker agent.

  • Config core namespacing + lifecycle retirement — every setting the shipped playbook set owns moves under config.core (playbook-owned at core.{name}_playbook, loop-wide or multi-playbook directly under core), leaving home_dir as the only other top-level key; the skills: block is deleted. Config validation goes with it — validate_skills, SkillConfig and the UNTRUSTED_PROJECT_KEYS tier filter are removed, so a user's own playbook namespace needs no plugin change to be legal and no tier drops a key (a project-tier core.macros entry now executes). The chat and help skills are deleted, leaving code-review and playbook; every delegation table renders from the single playbooks/_partials/playbook_agents.md and both available_agents surfaces are gone. The shared plan lifecycle is retired wholesale: config.plan, the transition and vault-commit commands and the plan_status: frontmatter mirror are all deleted, each playbook's own states: block becoming the whole status vocabulary — groom's three status-mirror scripts give way to an explicit commit-plan hook, retro's skipped-sibling close to a local drop-plan script, and develop's two vault-commit callers to plain staged git. marker-set learns latest_migration=@latest, booping-create-project seeds it on both branches, and migration 002_config_core_namespacing ships to carry existing vaults across the rename (global tier called out as a manual step). A shared _partials/timestamps.md gives any playbook the run's clock.

  • Plan date + summary hygienecreated is stamped to the minute (YYYY-MM-DD HH:MM) and rendered into the plan frontmatter shape from the run's own clock rather than documented as a bare date; groom's intake now carries that shape explicitly, having previously created index.md without ever being shown it. completed is normalised to the same shape across the vault, and the surrounding date keys are documented as sharing it.

  • Hook clock through the macro system — the bespoke @now / @today interpolation tokens are retired in favour of the same call the templates use, {{ macro('core.macros.date', '+%Y-%m-%d %H:%M') }}, written directly in the hook value and rendered as Jinja with the macro global; hook tokenising moves to shlex so a quoted expression survives the split. One clock source for the CLI and the rendered bodies, and --stub-macro now pins a transition exactly as it pins a render. @head stays a token — it resolves against the repo directory, where a macro would run in the process cwd.

  • Split-boundary cleanup — the three residue families the PR-19 architecture review catalogued, cleared in one sprint. cancelled becomes a real terminal on both the groom and develop machines, declared once per superstate (in-spec / awaiting-plan-review on groom, a new cancellable superstate on develop) and inherited by resolve_edges with zero engine change, so the latest_plans query's cancelled filter finally has a writer. The two near-identical close-working-set scripts collapse into one parameterized script in a new shared playbooks/_scripts/ root: _dispatch_script resolves hooks playbook-dir first then each discovery root, and passes trailing hook tokens to the script as argv (script close-working-set --status done --prefix learn), so per-playbook differences live in each playbook.yaml hook line. Playbook bodies stop restating the machine — retro/learn intake validate against "the status the ## State section names as this run's entry" instead of spelled literals, four transition-restating blocks reduce to one-line pointers, and three manifest graph narrations go (the step table is the contract). Fossil sweep: every retired-skill handoff rewritten to /playbook {name} form, the "parallel to /X" trigger clauses and develop's "stays canonical" rule dropped, the dead src/templates/_partials/_learn_targets.j2 folded into the live learn copy, docs/cross_validation.md deleted; dead engine code out (Edge.skill, DIR_PLAN_NAME, config["plan"] docstrings, macros.now-era help strings), specs_dir dropped from the bootstrap prompt, code-review prose repointed at the delegation table, and the chore/ branch rule reworded out of the task-type namespace.

  • Flat lessons with targets: — lessons collapse to two flat _lessons/ roots (global home + Project Vault), each file routed by a targets: frontmatter list ({playbook}, {playbook}/{step}, agent:{id}, skill:{name}); an untargeted lesson injects nowhere. The per-playbook/per-step _lessons/ dirs and the step: key are retired (legacy content surfaces a migration note), and learn now shows the playbook table of contents, fetches target spaces on demand, and pins exact targets: in its review table before writing.

  • Scaffold CLIbooping scaffold <dotted.path> <dest> materialises any config-declared file tree (playbook skeletons, the vault layout, a project's own trees) with Jinja-seeded file content, --force / --set / --stub-macro controls, and the setup flow reuses it for vault creation.

  • Frontmatter query surface — any markdown directory in the vault becomes queryable: booping query on the CLI, query / as_table Jinja filters in bodies, config-declared query specs addressable at any dotted path (mirroring scaffold / config-get), with --where filtering, sorting, column projection and table/JSON/YAML/paths output. macro() over config-declared core.macros replaces the fixed now() global, --stub-macro pins any macro for reproducible renders, plan discovery becomes the user-editable ordered core.plans.glob key, and sprints.md is seeded once as a live Obsidian Bases view — render-sprints and /chat's re-render are gone.

  • Query surface: migration support — the migrate playbook goes from listed to functional: every render surface gates on the .booping marker's latest_migration watermark and stops with a /playbook migrate notice when behind; migration authoring gets numeric --where ordering (:gt / :lt), query specs over the plugin's own files (root: core), {{ booping.latest_migration }} in templates, and format-preserving booping marker-set writes.

  • Testing infrastructure — committed render snapshots grow teeth: just snapshots diffs the committed playbook reports against a fresh hermetic fixture render (writing nothing), just snapshots-accept is the only baseline writer, mdcheck enforces structural rules over every report, and just ci chains lint → typecheck → pytest → snapshots → mdcheck, run by CI on every push and PR. core.macros entries gain command: + cwd: repo|vault scoping (the git_commit macro), --project pins the config merge as well as discovery for byte-identical renders, and the @head hook shorthand is retired in favour of the git_commit macro.

  • Retro track split — the plan track now ends at develop: plans close at done | fail | cancelled with no awaiting-retro tail. Retro and learn run as their own track over a standalone retrospectives/{slug}.md artifact (awaiting-retro → awaiting-learning → done), joined to plans only through the retro: frontmatter key (null = the retro queue); playbook-transition / playbook-state gain --target addressing and a machine may declare no artifact: at all; an idempotent migration relocates old plans/{slug}/retro.md files and normalises terminal statuses.

  • Code review track split — reviews persist as vault artifacts codereviews/{plan-dirname}/{ts}.md (ad-hoc scopes codereviews/{target-slug}/{ts}.md, plan: null) with their own machine in-agent-review → human-review → done; plans accumulate every closed review in code_reviews: as history rather than a queue flag, so every done plan stays reviewable and re-review is first class; review templates gain the global tier, layering core → global → project with by-name override.

Docs brought current against the delivered set in a spec-driven docs run: README, the full MkDocs site (documentation/), and CLAUDE.md rewritten and source-verified page by page; CHANGELOG.md seeded at v1.0.0 with the release's user-visible changes.

🤖 Generated with Claude Code

A and others added 30 commits July 27, 2026 22:23
…j2 partial (M1)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… loader (M2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… --project (M3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (M4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…k skill + docs (M5)

Kill criterion failed (+10% vs -30% target); old /groom stays canonical,
new experimental /groom-playbook skill drives the core groom playbook.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… dirs

Each jinja body now renders with its own ChoiceLoader chain: the body
itself (by basename) -> step dir -> playbook dir -> local/global/core
playbook roots -> src/templates. A PlaybookEnvironment.join_path
override resolves ./ and ../ against the including file's own directory
at any nesting depth; bare names fall through to the chain unchanged.

src/templates stays last so _partials/ keeps resolving plugin-root
relative, at the cost of a playbook-local _partials/ shadowing it. The
graph and step chrome templates render through a separate plugin-only
env so a playbook cannot shadow them.

Also drop the "no playbook.md, skipping" warning: a directory without a
manifest is now skipped silently.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…amed states in loader (M1)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… transition report (M2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…or (M3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ll-run integration test (M4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iving protocol, docs (M5)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ybook scan + name clash (M1)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ons.j2 + step append + clash STOP + --no-lessons (M2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rker + driving lessons binding (M3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s reference, stale shadowing refs removed (M4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tch file target + {instance} interpolation, plan-transition rejection, report prefix (M1)
…vocabulary docs across playbook.md, CLAUDE.md, driving partials (M2)
…ites

Rebuild core groom playbook: playbook.yaml with states/graph, new steps
(draft-plan, decompose-work, verify-references), _scripts status hooks,
_specs design docs. Each step ships promptfoo eval suite (tests.yaml,
fixtures, model variants).

Add eval tooling: justfile recipes (eval, eval-md, smoke, regress),
bin/eval-md.sh + bin/report-md.jq markdown reporter. Ignore repo-root
_booping/ runtime log.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- frontmatter-update on a file without a frontmatter block now prepends
  one instead of aborting; existing content becomes the body unchanged
- groom steps stop authoring `reviewed_at: null` — run hooks own the
  artifact frontmatter, files open at their H1
- run slugs take their timestamp from the local clock
  (`date +%Y%m%d-%H-%M`), never from model memory

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A and others added 28 commits August 8, 2026 13:11
…ansition

An absolute --target ending in the machine's declared artifact: now implies
the workdir, so hooks run beside the artifact without a separate --workdir.
Relative targets, non-matching paths, and machines without artifact: keep cwd.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A workdir inside home_dir/{project}/ now assembles the same context as a
repo workdir; repo_directory becomes optional and hook resolution falls
back to the process cwd when the containment-resolved project has none.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eview to awaiting-approval

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…or release — M1 snapshots + mdcheck as Python scripts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…or release — M2 eval tooling moves to scripts/

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…or release — M3 dead code deleted

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…or release — M4 CLAUDE.md layout + commands sweep

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nting — M2 session-stats subcommand, session-time retired
…nting — M3 metrics_ key rename, migration 006, config surfacing and docs
The vault lived under home_dir at ~/Dev/@A/notes/projects/claude-booping,
tracked in the private notes repo. Move it to vault/ here so plans, retros
and lessons version alongside the code they describe.

- .booping gains vault_path: vault
- _core_playbooks becomes a relative symlink (../playbooks), keeping the
  absolute home path out of a public repo
- vault/notes/ and .booping.log are gitignored: local scratchpad and
  operational log, not part of the published vault
- drop _booping/.booping.log, dead since migration 004
Migration 004 converted _booping/agent_*.md into targeted _lessons/ files;
nothing has read that path since. The developer agent description still
pointed at it. Lessons are discovered automatically, so the sentence is
removed rather than repointed.
…ss cases

Both judged a freshly generated artifact whose shape varies run to run — the
fixtures corpus rubrics and the llm-tests row-quality rubrics went red on roughly
half the runs without any source change. The deterministic smoke cases stay.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The suites judge freshly generated artifacts, so a full run lands on a different
red set each time — a per-sha gate blocked merges on judge variance rather than on
source drift. The sticky PR comment stays as the advisory record of a run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Six incremental migrations described a history no 1.0 vault will ever walk
step by step. Fold them into three that each cover a coherent layout change:
vault layout, tracks and lessons, session metrics.

- fixture marker watermark drops 6 -> 3, and the migrate snapshot follows
- README gains a 'What it's for' section, links the checked-in vault/, and
  states the beta-grade maturity of 1.0
@A

A commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #20, which releases the same commits from release/1.0.0 with the v1.0.0 release notes as its description. No commits are lost — release/1.0.0 branches from this branch's tip (cca2142).

@A A closed this Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant