feat: markdown-formatter plugin (pilot migration)#3
Conversation
Add .editorconfig (LF, 2-space, shfmt shell keys) and .shellcheckrc (external-sources, source-path=SCRIPTDIR, selective optional checks), mirroring the standards/medley drop-in configs. Governs authoring and linting of this repo's own shell sources only; not shipped to plugin consumers. Long-term these should be consumed from the standards repo. Co-Authored-By: Claude <noreply@anthropic.com>
PostToolUse hook that auto-formats and lints Markdown on edit via markdownlint-cli2 --fix, using the consuming repo's own markdownlint config (ships none). Lifted and genericized from melodic-software/medley's in-repo markdown-format hook: telemetry/observability coupling removed, medley-policy wrapper prose dropped, file-anchored repo-root cd preserved for config discovery, kill switch HOOK_MARKDOWN_FORMAT_ENABLED retained. No userConfig. Bundles a trimmed hook-utils subset and a black-box contract test (12 cases). Verified: claude plugin validate --strict; --plugin-dir load in a clean non-medley repo; source-repo parity vs the in-repo hook (byte-identical --fix output, MD024 finding-line identity, zero plugin telemetry). Co-Authored-By: Claude <noreply@anthropic.com>
Add the markdown-formatter entry to .claude-plugin/marketplace.json so the already-committed plugin is installable, and surface it in the README catalog. Drop metadata.pluginRoot: claude plugin validate --strict rejects the bare plugin source it is meant to enable (plugins.N.source: Invalid input), despite the marketplaces-doc example. Entries use the explicit ./plugins/<name> form. Playbook step 10 now records the ./-prefixed-source requirement and the need to validate the catalog manifest itself (the entry error surfaces only there). Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b970d0c306
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| local norm_file norm_project | ||
| norm_file=$(hook::normalize_path "$file") | ||
| norm_project=$(hook::normalize_path "${CLAUDE_PROJECT_DIR}") | ||
| if [[ "$norm_file" != "$norm_project"* ]]; then |
There was a problem hiding this comment.
Require a path boundary for project membership
When CLAUDE_PROJECT_DIR is /repo/app, this raw prefix check also accepts /repo/app-backup/file.md. The guard is supposed to skip files outside the current project, but with similarly named sibling directories a Write/Edit to that path will still run markdownlint-cli2 --fix outside the project; compare against $norm_project/ or use a relative-path check with a real boundary.
Useful? React with 👍 / 👎.
| elif command -v npx >/dev/null 2>&1; then | ||
| MDLINT=(npx markdownlint-cli2) |
There was a problem hiding this comment.
Avoid treating npx alone as an available formatter
In repos where npx exists but markdownlint-cli2 is not installed locally/globally and the npm registry is unavailable or blocked, this branch still runs npx markdownlint-cli2; npx --help describes it as running from a “local or remote npm package”, so the hook captures npm fetch failures and reports them as markdownlint findings on every Markdown edit instead of being a no-op. Check for an actually local/resolvable package or suppress this fallback when the package cannot be executed without fetching.
Useful? React with 👍 / 👎.
…r self-contained Address three more Codex P2 findings: - teach topic case (#1): topic is start-or-resume, so a fresh-workspace expectation flakes on a machine with prior data. Assert the start-or-resume contract — mission interview for a new workspace, resume for an existing one. - teach primer case (#3): the primer intakes the user's starting point with one question before building the ladder, so a single-turn run may correctly open with the intake. Make the expectation intake-first. - diagnose cleanup case (#6): a broad grep -r "[DEBUG-" already matches the diagnose docs and this fixture in the checkout. Scope the assertion to the specific [DEBUG-a4f2] tag across the changed source.
… hardening (#138) Applies the resolved `planning/setup` hardening to `knowledge/setup`'s `library_dir` seam (same single-directory `userConfig` shape, same latent issues). ## Changes **`plugins/knowledge/skills/setup/SKILL.md`** - **Precedence** — step 1 now resolves the full documented order (Managed > `--settings` > Local > Project > User), warns when higher layers are unreadable instead of declaring a lower value authoritative, and surfaces layer shadowing before the project write. - **Portability** — step 5 guards the tracked project write: never propagate a machine-specific personal-layer value into team settings; route personal-only overrides to `.claude/settings.local.json` (portability required only for the shared project write). - **Declared-convention alignment** — inspect the repo's declared working-notes/artifacts convention even when a value is set; surface divergence and offer to reconcile. **`plugins/codebase-audit/skills/setup/SKILL.md`** (partial match — writes a tracked `.md`, not settings) - Applied only the precedence/shadowing subset: step 1 reports the *effective additively-merged* config across user-global → team → local layers (and warns on unreadable layers), instead of summarizing the team file alone. Settings-write portability specifics do not apply. ## Deviations (own-flagged) 1. **Fix #3 premise softened for knowledge.** The issue's fix #3 parenthetical assumed knowledge "honors that convention over the config at write time" (true for planning). Verified via `skills/youtube/extraction/lib/work-root.js` and the youtube pipeline that **knowledge resolves `library_dir` directly at write time — no skill overrides it with a repo convention at runtime.** Documenting that behavior would be false, so I softened the imported write-time-override claim: `library_dir` is runtime-authoritative, and setup's job is to keep it *aligned* with any declared convention. Fixes #1 and #2 are unaffected. 2. **`codebase-audit` version bump not in issue scope.** Patch-bumped `0.1.0 → 0.1.1` because its SKILL behavior changed; the issue only specified the `knowledge` minor bump. ## Verification - `knowledge` `plugin.json` minor bump `0.2.0 → 0.3.0`; `codebase-audit` `0.1.0 → 0.1.1`. - `claude plugin validate` clean on both plugins. - markdownlint clean on both edited files. Refs melodic-software/medley#1463 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Changes are limited to plugin skill documentation and version metadata; no application runtime or security-sensitive code paths are modified. > > **Overview** > **Hardens setup skills** for the `knowledge` and `codebase-audit` plugins so interactive setup reflects layered config reality instead of treating a single team file as authoritative. > > For **`knowledge/setup`**, step 1 now follows the full Claude Code precedence chain (Managed → `--settings` → Local → Project → User), warns when higher layers are unreadable, and calls out when a project write would stay shadowed. A new step reconciles `library_dir` with repo-declared working-notes conventions even when a value is already set. Persistence (step 5) blocks copying machine-specific personal paths into tracked project settings, routes personal-only overrides to `.claude/settings.local.json`, and the output section documents honest pipeline behavior (`book-distill` ignores `library_dir`; YouTube does not yet honor it). **`knowledge`** bumps **0.2.0 → 0.3.0**. > > For **`codebase-audit/setup`**, step 1 is expanded to summarize the **effective merged** config across user-global → team → local layers (including dimension opt-outs via empty source lists), explain that only the team file is written, and warn when overlays block re-enabling dimensions. **`codebase-audit`** patch-bumps **0.1.0 → 0.1.1**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f13139a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
… follow-ups) (#205) ## Summary The three follow-ups deliberately deferred out of #204 (recorded in its PR body), each decision-gated with the maintainer before editing. Net **−341 lines**; no plugin manifest, schema, or skill behavior touched. ## #1 — Retire the audit snapshots Delete `docs/evals-coverage.md` and `docs/extensibility-contract-grading.md`. They were hand-stamped, point-in-time records that drift the moment a plugin changes (the reorg already forced a two-layer temporal re-stamp). **Retire over generate.** The durable policy already lives in `docs/MIGRATION-PLAYBOOK.md` — the warrant rule + consumer-verify recipe ("Evals — warrant policy and consumer-verify recipe") and the four-seams contract ("Extensibility contract v2.1"). A generator could derive only eval *presence* (a live glob) — the minority of one doc and none of the other; class, contract grades, and medley program state stay irreducibly hand-graded or externally-owned. Generating only the presence slice yields a half-generated hybrid that still drifts on its biggest surface. Retire is the clean fit. **Gaps captured first.** Two warranted-but-unowned eval gaps were recorded *only* in the retired snapshot (verified still live against the tree): `context7/setup` and `planning/wayfind`. Filed durably before deletion: - `melodic-software/medley#1537` — evals(context7/setup) - `melodic-software/medley#1538` — evals(planning/wayfind) Inbound pointers updated: README doc-index (2 bullets removed) and the playbook's evals section (now states on-demand verification instead of pointing at a deleted snapshot). No dangling references remain (repo-wide grep clean). ## #2 — Reclassify the depth-variant convention tension The playbook stated a depth/intensity variant "takes an argument, never a sibling," yet `discovery`'s `explore-deep` / `research-deep` ship as sibling skills. Inspection shows they are **structural, not depth**: - `explore-deep` — `context: fork` + `agent: general-purpose`: a distinct execution *topology* (isolated forked subagent), declared in frontmatter, not expressible as a runtime argument. - `research-deep` — a dispatcher to the heaviest isolated tier (workflow engine, forked subagent, or inline fallback), with its own body and auto-invocation description. The convention needed no exception — it needed a sharper structural/depth test. Amended to classify **execution tier as a structural axis** (sibling) and bind the `-deep` suffix to that axis, so the naming no longer reads as a violation and a future reader does not re-flag it. A true effort knob on one execution path still takes an argument. No skills renamed. ## #3 — README revisit-condition dedup Assessed, closed **no-op**. The coupling flagged in #204 is a documented, directional SSOT+index: `docs/CATALOG-TAXONOMY.md` (L71–73) declares plugin-scoped revisit conditions are *owned by each plugin's README* and the taxonomy "Trigger register" lists them "only as pointers." The READMEs are the single owners of genuine plugin-specific rationale; the register summarizes them. Nothing to dedup. Confirmed none of the three sections cross-names the taxonomy doc. ## Verification - `scripts/validate-plugins.sh`: pass (all manifests + strict catalog sync) - `scripts/run-plugin-tests.sh`: 7 passed, 0 failed - `markdownlint-cli2`: 0 errors on both touched markdown files - Repo-wide grep for the retired doc names: no remaining references ## Note (not in this PR) `docs/hook-migration-audit.md` is the same "point-in-time audit" genus as the two retired here. Left untouched; flagged for a consistency decision in a later pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0163dXPBdRYFpx4wTtS648tE Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#218) ## Summary `code-tidying:tidy`'s Phase H ("Ship") told the agent to create the PR by calling `gh pr create` directly — a bare bypass of `source-control:pull-request`'s canonical create flow, which resolves issue-linkage (with an issue-existence check before shipping a `Closes #N` keyword), assembles the PR body injection-safely (quoted heredoc + parameter-expansion concat, a defense against shell injection through prompt-derived text), and gates PR creation on a valid closing keyword or explicit opt-out before calling `gh pr create` itself. Closes decisions **#3** and **#42** of the melodic-software issue/PR consistency initiative's Decisions Log (`https://claude.ai/code/artifact/232ecdce-8316-4880-8c0a-dc3c7dcf3a63`): - **#3 (formatting-tidy-canonical-pr-gate-bypass)** — "YES, fix — but not via direct skill-to-skill coupling... minimize coupling between `code-tidying:tidy` and `source-control:pull-request`... Likely shape: a shared script/check both skills call, or a convention-level requirement enforced by a common gate." This PR fixes the bypass without a hard cross-plugin dependency (below). - **#42 (crosscut-skill-content-sync-mechanism)** — "Single shared reference doc, all authoring skills import it." Applied here for its first concrete instance (see Design rationale). ## What changed Phase H now applies the same optional-plugin graceful-degrade pattern `tidy` already uses elsewhere in its own SKILL.md (Phase C for `discovery`, Phase D for `work-items`): - **If `source-control` is installed:** invoke `/pull-request create`, supplying tidy's own title/body-section content. Its stage-and-commit step (§2.3) is a no-op here since Phase E already committed the tidyings atomically — the call goes straight to rebase-check, issue-linkage resolution, and gated PR creation. - **If `source-control` isn't installed:** the same invariants apply inline — verify an issue exists before writing `Closes #N`, assemble the body via quoted heredoc + concat (never an unquoted `<<EOF`), and refuse `gh pr create` until the body carries a valid closing keyword or an explicit `Refs #N` / `No related issue:` opt-out. ## Design rationale (decision #42, recorded as an assumption — no user available to confirm interactively this session) Considered extracting the safety invariants into a new shared reference doc (mirroring the `docs/PLUGIN-ARTIFACT-PROTOCOL.md` → per-plugin `reference/artifact-protocol.md` precedent, drift-checked by `validate-plugin-contracts.mjs` and this session's new `scripts/check-cross-plugin-source-drift.sh`). Rejected for now: every invariant worth stating is already authoritative in `pull-request/reference/create.md`, so a copied doc would be pure duplication with drift risk — and with exactly one non-`source-control` consumer today, it wouldn't even register as a cluster for the new drift checker (which requires 2+ plugin copies). A prose convention pointer is lighter, carries no duplication to drift, and degrades gracefully if `source-control` is absent — which a hard-copied doc wouldn't buy any safety over. This is decision #42's design choice for its *first application*, not a retrofit of every authoring skill in the marketplace — no other skill is touched by this PR. Rolling the same pattern out to other PR-creating skills (if any surface a similar bypass) is deferred, unscoped follow-up work, tracked in the Decisions Log rather than guessed at here. ## Test plan - `bash scripts/validate-plugins.sh` — all plugin manifests + strict catalog validation pass. - `node scripts/validate-plugin-contracts.mjs` — 16 setup skills + 1342 plugin files checked, clean. - `npx markdownlint-cli2 plugins/code-tidying/skills/tidy/SKILL.md` — 0 errors. - Confirmed no other stale bare-`gh pr create` references remain under `plugins/code-tidying/`. - No existing test file exercises `tidy`'s `SKILL.md` prose directly (only `open-pr-count.test.sh`, unrelated to Phase H) — nothing to update there.
…verb (#709) ## Summary The work-item-tracker seam reserves `work-map` **containers** as a first-class use case, but its read side was repo-global only — there was no way to operate one container within scope (#498). Concretely: `list-frontier` had no container scoping, its rows drop parent linkage (GitHub's list surface omits it), an unassigned/unblocked container surfaced as **its own** frontier item, and no verb enumerated a container's children (needed for a closed-children invariant check). Surfaced by the #416 wayfind-routing planning pass. ## Fix - **`list-sub-items <parent-id> [--state open|closed|all]`** — new seam + adapter verb. Returns a container's **direct** children as full normalized item objects (same `{items:[…]}` envelope as `list-items`), each re-parented to the container. Raw enumeration — closed and nested-container children are kept (the closed-children invariant check and sub-map traversal need them). `--state` defaults to `all`. Both adapters implement it: GitHub resolves children via the native `subIssues` link and intersects with `list-items` output (its list surface omits parent linkage, so the child set can't be derived from rows); the offline `local-markdown` adapter matches on the stored `parent` frontmatter. - **`list-frontier --parent <container-id>`** — container-scoped frontier. Core reads `list-sub-items` for that container instead of the repo-global `list-items`, then applies the identical filter. The scoped verb is chosen **before** the capability gate, so an adapter with `list-items` but not `list-sub-items` degrades explicitly (exit 6) rather than passing the gate then failing mid-call. - **Container exclusion (obs #3).** `list-frontier` now excludes any item carrying the container label (`work-map`) **unconditionally** — global and `--parent`-scoped, and under `--autonomous`. Justification: the CONTRACT already states containers are never claimable by workers, so this is a correctness fix, not a policy toggle — deliberately not behind a flag. Design notes for the reviewer: - The container label is a named constant (`WIT_CONTAINER_LABEL`, default `work-map`) matching the CONTRACT term — not a new binding key. Per-repo remapping is **deferred** to the existing `config.role_labels` convention, keyed off the first consumer that needs a non-`work-map` marker. - Obs #2 (global rows drop parent linkage) is addressed by the `--parent` scoping path, **not** by enriching global `list-items` rows — GitHub's bulk list surface genuinely omits `parent`, and `get-item` remains authoritative for a single item's parentage (unchanged CONTRACT stance). - Container exclusion lives only in the core frontier filter; `list-sub-items` stays a raw enumeration (nested sub-maps and closed children must survive it). Version `0.15.0` → `0.16.0` (additive); CHANGELOG entry added. ## Verification All commands run in the worktree on the rebased branch (tip of `origin/main` + this commit). New behavioral test — `local-markdown list-sub-items` end-to-end through the core CLI (offline, CI-runnable): ``` $ bash plugins/work-items/tools/work-item-tracker/adapters/local-markdown/list-sub-items.test.sh PASS: [1] list-sub-items holds open child C1 PASS: [2] list-sub-items holds closed child C2 PASS: [3] list-sub-items excludes the container itself PASS: [4] list-sub-items excludes an unrelated leaf PASS: [5] list-sub-items excludes a grandchild (direct children only) PASS: [6] list-sub-items (default all) child count PASS: [7] children carry parent_id PASS: [8] list-sub-items --state open keeps only C1 PASS: [9] list-sub-items --state closed keeps only C2 PASS: [10] list-sub-items on a leaf is empty PASS: [11] scoped frontier holds the open child C1 PASS: [12] scoped frontier drops the closed child C2 PASS: [13] scoped frontier drops the grandchild (not a direct child) PASS: [14] scoped frontier never holds the container PASS: [15] global frontier excludes the unassigned/unblocked container PASS: [16] global frontier still holds the workable leaf ``` Core frontier filter unit test (container exclusion added): ``` $ bash plugins/work-items/tools/work-item-tracker/lib/frontier.test.sh PASS: [7] default frontier excludes the container (work-map) PASS: [8] autonomous frontier also excludes the container PASS: [9] explicit container label excludes the remap, not the stale default ... (9 cases, 0 failed) ``` Abstract conformance suite through the core CLI (exercises `list-sub-items` + `list-frontier --parent` for the adapter — CI runs this offline binding): ``` $ bash plugins/work-items/tools/work-item-tracker/conformance/run-conformance.sh --binding local-markdown PASS: [43] list-sub-items A (exit code) PASS: [46] A's children hold B PASS: [47] enumerated child B is re-parented to A PASS: [50] list-frontier --parent A (exit code) PASS: [53] scoped frontier drops blocked child B Conformance (local-markdown): 72 cases, 0 failed ``` Full `work-items` plugin test suite + shellcheck (`0.11.0`, repo `.shellcheckrc`) over all changed/new shell files — both clean: ``` $ find plugins/work-items -name '*.test.sh' | while read t; do bash "$t"; done # all pass, 0 failures $ shellcheck -x <changed .sh + .test.sh> # rc=0, no findings $ bash scripts/check-changelog-parity.sh --check-bump origin/main # Every changed plugin has its CHANGELOG entry. ``` The GitHub `subIssues`+intersect path runs only under the on-demand `e2e-probe` (needs a live sandbox repo), which was **not** executed here; its `subIssues` node shape (`id/number/title/url/state/repository.nameWithOwner` — no `assignees/labels/blockedBy`, hence the intersect-with-`list-items` design) was verified against gh's own source (`cli/cli api/queries_issue.go`, `LinkedIssue` struct). e2e-probe was extended with container-exclusion and `list-sub-items`/`--parent` assertions for when it is next run against a sandbox. Closes #498 ## Related - #498 — the seam's own read-verb coverage for containers (this PR). - #416 — routes `planning:wayfind` through the seam (the consumer that surfaced this gap); related but distinct, unblocked by this change. - #379 — Jira adapter (a different backend); related but distinct. --------- Co-authored-by: Claude <noreply@anthropic.com>
) ## Summary Closes the three deferred, independently-corroborated (Codex + claude[bot]) review findings from PR #248's review cycle against `plugins/claude-ops/skills/plugins/scripts/fleet-state.sh`. Each was verified VALID but deferred out of #248 to bound an already-long (6+ round) fix/review loop. All fixed here with TDD regression tests (red-then-green). Version bumped `0.15.4` → `0.16.0` (minor: adds a new consumable output field). ## Fix **1 — user-scope install completeness (additive, no behavior change to the existing field).** `fleet-state.sh` now emits a new field `missing_from_user_install` = catalog minus *user-scope*-installed minus opted-out, alongside the untouched all-scope `missing_from_install`. A plugin installed only at `project`/`local` scope was present all-scope (absent from `missing_from_install`) and so was never offered a `user`-scope install by `sync` Step 4 — silently breaking the "usable from any directory" guarantee for it. `sync.md` Step 4 now keys its user-scope install offer off the new field. The existing `missing_from_install` field and its all-scope semantics are unchanged. Chosen approach: the additive option from the issue (new field), not the redefinition option — no behavior change to any existing consumer. Beyond the literal instruction: `SKILL.md`'s report template ("Action needed") reference was also switched to `missing_from_user_install`, so the report and Step 4 name the same signal (safe — `missing_from_user_install` ⊇ `missing_from_install` always, since user-installed ⊆ all-installed). `scope-semantics.md`'s reference was deliberately left on `missing_from_install` — it documents the preserved all-scope field's rename-coverage semantics. **2 — per-plugin shape validation.** The shape check validated `.plugins` is an object but not that each entry is an array. A drifted non-array entry passed the check, then failed inside the installed-flatten `jq` pipeline in a command substitution; with `set -uo pipefail` but no `set -e` the failure was swallowed and the script exited **0** with `installed: []` instead of failing loud per its stated design. The check now also asserts `(.plugins | to_entries | all(.value | type == "array"))` and exits 2 on drift. **3 — `--marketplace` with no name.** `fleet-state.sh --marketplace` (no following arg) set `TARGET=""`, then `shift 2` failed silently (only one positional param left, no `set -e`), leaving `$1` unchanged so the arg loop re-read `--marketplace` forever; the post-loop `-z "$TARGET"` guard was never reached. The empty check now runs inside the `--marketplace` branch before `shift`, exiting 2. The now-dead post-loop guard was removed. ## Verification TDD: three regression cases were added and run **against the unfixed script first** to prove each bug, then the fixes were applied. Before (unfixed script — the three new cases red, proving each bug): ``` FAIL: user-scope: project-only + never-installed both surface, user-scope install excluded FAIL: user-scope: opt-out excluded from missing_from_user_install too FAIL: non-array plugin entry: exit 2 detail: expected exit 2, got 0 # #2: swallowed failure — exited 0 with installed:[] FAIL: --marketplace no arg: exit 2, not an infinite loop detail: expected exit 2, got 124 # #3: 124 = timeout killed the infinite loop FAIL: --marketplace no arg: actionable error ``` After (fixed script — full suite green): ``` PASS: --marketplace no arg: exit 2, not an infinite loop PASS: --marketplace no arg: actionable error 23 cases, 0 failed ``` `shellcheck` (both scripts) and `markdownlint-cli2` (all changed markdown) report clean: ``` SHELLCHECK CLEAN Summary: 0 error(s) ``` Closes #254 ## Related - Closes #254 — the tracking issue enumerating all three findings. - Follow-up from PR #248 (`feat/claude-ops-plugins-skill`), the origin review cycle where these three were verified VALID and deliberately deferred. - #797 — follow-up: `FLEET_STATE_HOOK_UTILS`'s test-only override isn't gated to test contexts at runtime. Pre-existing (unchanged by this PR), out of scope here — filed post-green per the lane's review-deferral rule. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Work item #3 body and the stress-test reversal summary still named --max-turns for the per-run mechanical bound, contradicting this note's own recorded deviation (--max-turns absent from the installed CLI; --max-budget-usd is the actual flag). Update both to --max-budget-usd so the active Phase 1 build path can't wire the nonexistent flag. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fgx6EDAL4cGAFwTNgLpsus
… recording tier, routines provenance (#845) ## Summary Absorbs the vetted ideas from the "4 Levels of Agentic Coding" video digest (Boris Cherny "Steps of AI Adoption" walkthrough) into the plugin estate, per the approved plan at `docs/topics/boris-video-absorption/PLAN.md`. - **testing 0.3.0 (minor):** `/testing:run-e2e` gains the consumer config surface `.claude/testing/e2e.md` (`recording: video|gif|off` default `off`; `browser_mode: headed|headless` default `headless`) with explicit read path, per-key merge + provenance reporting, and plumbing to the playwright executor; keys owned by new `context/e2e-config.md` (policy-vs-mechanics boundary; prompt > config precedence). Prerequisite hard-fail keeps STOP and adds a structured verification-environment gap report. Drive loop subagent-isolated; presence-gated `/verify`-first delegation (CC >=2.1.145). Evidence contract adds optional recording tier + session artifacts. Eval #1 updated. - **verification 0.3.2 (patch):** `/verification:confirm` delegation wording acknowledges the enriched run-e2e; stages/verdict machinery untouched. - **autonomy 0.8.0 (minor):** `reference/routines.md` gains the instruction-provenance clause — routine instruction content lives in a version-controlled artifact, stored prompt is a thin pointer; surface mappings are illustrative deployment-owned bindings. - Implementers-table row added in `docs/conventions/consumer-config-layering/README.md`. Coordination: zero file overlap with the ignition/enforcement lanes (#778 comment posted; ignition Phases 2–3 merged via #810). Defaults preserve current consumer behavior. ## Related No linked issue: this PR closes no GitHub issue. Related, not closed: - #778 — ignition lane coordination (comment posted; zero file overlap) - #810 — ignition Phases 2-3 (merged; separate lane) ## Verification - markdownlint: 0 errors on all touched files; typos gate exit 0 - `check-skill.sh`: run-e2e PASS, confirm PASS (pre-existing advisory warnings only) - run-e2e `evals/evals.json`: valid against bundled schema (ajv, draft2020) - Sanity greps per PLAN phase checks: all pass - Stage-structure invariant on confirm SKILL.md: 16 before/after <details> <summary>PLAN.md</summary> # PLAN — boris-video-absorption ## Brief Absorb the vetted ideas from the Ray Amjad "4 Levels of Agentic Coding" video digest (research base: `~/.work/youtube-watch/the-4-levels-of-agentic-coding-how-to-sh-XLA-sTSJ-Wc/`) into the plugin estate. Interview-locked contracts (this session): - Extend existing seams, no new skill: `testing:run-e2e` (driver) + `verification:confirm` (judge) keep their division of labor. - run-e2e gains: subagent-isolated surface runs; native-/verify-first delegation (presence-gated, CC ≥2.1.145); structured missing-environment gap report on prerequisite failure (hard-fail stays, plus actionable report); video/session-artifact evidence tier. - Recording format (video | gif | off) and browser mode (headed | headless) are layered config knobs per `docs/conventions/consumer-config-layering/` — NOT hardcodes. - `plugins/autonomy/reference/routines.md` gains a thin-pointer clause: routine/scheduled-task prompts on any surface point to version-controlled files; pasted prose non-compliant. - `~/.claude/scheduled-tasks/` (exists, live task) proposed for dotfiles tracking via the dotfiles repo's add-dotfile flow. - Deferred-with-trigger (recorded in digest slice, NO tracker issues): verification self-improvement loop (trigger: accumulated recorded runs); bounded build→review→fix loop (trigger: post-Phase-II enforcement rail); Claude Tag enablement (trigger: post-8/3 cutover + Enterprise admin check). - Out of scope: presenter-custom harness (Percy), chat-surface wiring, Chronicle adoption, lifecycle reordering. - Boris doc capture re-verified NO-DRIFT 2026-07-21; all adopted items trace to the doc's step 1→2/2→3 recipes or native CC features. Success: PRs merged with skill-quality + markdownlint green; every adopted behavior traceable to research findings; zero collision with the primary session's lanes (ignition Phases 2–3 merged via #810; no pending branch touches target files — verified). ## Standards grounding - `docs/conventions/consumer-config-layering/README.md` — three layers (user-global / team / local overlay), additive-preferred merge; new config surface must declare keys in the owning plugin's docs and point at the convention for layering. - `docs/CATALOG-TAXONOMY.md` + `docs/PLUGIN-PHILOSOPHY.md` — extend-over- add, seam cooperation presence-gated, fresh-eyes delegation. - Repo commit/PR conventions (conventional commits, codex thread resolution before merge, `--body-file -` for PR bodies). ## Plan ### Phase 1: Lane setup [DONE] - Create worktree off `origin/main`, branch `feat/boris-video-absorption` (sibling-worktree convention). - Materialize `docs/topics/boris-video-absorption/PLAN.md` (this file) + `design/design-resolution.md` (Tier B early-exit: no new types; one new config surface whose shape is resolved here — see Decisions). - Post coordination comment on #778: secondary session lane, files touched, no overlap with ignition/enforcement lanes. - **Sanity Check:** `git worktree list` shows the new worktree on the new branch; `gh issue view 778` shows the comment; PLAN.md exists in the worktree at `docs/topics/boris-video-absorption/PLAN.md`. ### Phase 2: run-e2e enrichment [DONE] Files: `plugins/testing/skills/run-e2e/SKILL.md`, `plugins/testing/skills/run-e2e/context/e2e.md`, `plugins/testing/README.md`, new `plugins/testing/skills/run-e2e/context/e2e-config.md` (key owner doc), `plugins/testing/skills/run-e2e/evals/evals.json` (eval #1 asserts the prerequisite-failure behavior this phase changes — update unconditionally), `plugins/testing/CHANGELOG.md` (Keep a Changelog entry; **minor** bump — new behaviors), `docs/conventions/consumer-config-layering/README.md` (Implementers-table row for the new surface — the convention tracks conformance, not assumes it). - Declare config surface `.claude/testing/e2e.md` (folder-form name per convention: surface identity = whole path relative to `.claude/`). Keys: `recording: video | gif | off` (default `off` — evidence contract screenshots stay the floor), `browser_mode: headed | headless` (default headless, operator overrides for visibility). Per-key override semantics. Layering resolution cites the convention doc — no restatement. - **Read path (reviewer gap #3 — mandatory):** SKILL.md gains explicit resolution instructions — anchor at repo root, read all three layers (user-global → team → local overlay), merge per-key, report which layer supplied each effective value. **Plumbing:** resolved `browser_mode` and `recording` are passed to the executor (`/playwright:playwright` invocation args / gif_creator choice) — keys without plumbing are the documented ai-briefing deviation; not repeating it. - **Key-ownership framing (reviewer risk #6):** e2e-config.md states the boundary — run-e2e owns capture POLICY (what evidence, which format, visibility preference); playwright owns MECHANICS (how the browser runs). Keys are policy inputs run-e2e resolves and passes through. - **Precedence (operator-locked):** config keys are DEFAULTS only; an explicit session prompt always wins ("run this headed" overrides `browser_mode: headless`). e2e-config.md states this: prompt > local overlay > team > user-global > bundled default. - SKILL.md: subagent-isolated run guidance (delegate the drive loop to a subagent; orchestrator consumes evidence paths only); /verify-first delegation note (presence-gated on bundled /verify, CC ≥2.1.145, with existing orchestrator fallback unchanged). - Prerequisite failure path: keep hard-fail STOP; add a structured verification-environment gap report (what's missing, what the operator must provide — keys/CLIs/environments; the "what do you need to verify this e2e" elicitation) written to the run's evidence output. - context/e2e.md evidence contract: add optional recording tier (video via playwright CLI preferred for long flows; GIF via gif_creator for short demos — driven by the `recording` key) + session artifacts row (recording path, session ID, transcript pointer) in the evidence table. - **Sanity Check:** `rg -c "e2e-config|\.claude/testing/e2e\.md" plugins/testing/skills/run-e2e/SKILL.md` ≥ 1; `rg -c "gap report" plugins/testing/skills/run-e2e/SKILL.md` ≥ 1; `rg -c "recording" plugins/testing/skills/run-e2e/context/e2e.md` ≥ 2; **read-path present:** `rg -c "layer" plugins/testing/skills/run-e2e/SKILL.md` ≥ 2 AND `rg -c "browser_mode" plugins/testing/skills/run-e2e/SKILL.md` ≥ 2 (resolution + plumbing sites); Implementers-table row: `rg -c "testing/e2e" docs/conventions/consumer-config-layering/README.md` ≥ 1; CHANGELOG entry present; eval #1 updated (`rg -c "gap" plugins/testing/skills/run-e2e/evals/evals.json` ≥ 1); markdownlint exit 0 on changed files; `/skill-quality:check run-e2e` PASS. ### Phase 3: confirm delegation touch-up [DONE] Files: `plugins/verification/skills/confirm/SKILL.md`, `plugins/verification/README.md` (only if wording drifts), `plugins/verification/CHANGELOG.md` (**patch** bump — wording touch-up). - Delegation section: acknowledge enriched run-e2e (subagent isolation + recording/session evidence tier + gap report); /verify stays named as the supplementary live-run path with unchanged presence gate. No structural change to stages or verdict machinery. - **Sanity Check:** `rg -c "gap report|recording" plugins/verification/skills/confirm/SKILL.md` ≥ 1; stage structure unchanged (`rg -c "Stage" plugins/verification/skills/confirm/SKILL.md` equal before/after); markdownlint exit 0. ### Phase 4: routines.md thin-pointer clause [DONE] Files: `plugins/autonomy/reference/routines.md`, `plugins/autonomy/CHANGELOG.md` (**minor** bump — new normative clause). - New subsection, phrased to honor the doc's hosting-agnosticism (reviewer risk #7): the NORMATIVE clause is surface-agnostic — "a routine's instruction content lives in a version-controlled, reviewable artifact; the stored prompt is a thin pointer to it; pasted-prose prompts are non-compliant (no history, invisible drift)". The surface-specific mappings (cloud routines → committed `.claude/skills/`, documented transfer path; Desktop scheduled tasks → `~/.claude/scheduled-tasks/<task>/SKILL.md` under dotfiles) appear only as ILLUSTRATIVE binding examples, marked as deployment-owned bindings per the doc's own Hosting stance. Cite research (`routines-versioning-deep-dive.md`: native prompt versioning documented-absent). If the clause reads better in `wiring-vs-advisor.md` at build time, the builder flags it back to the main thread rather than deciding — placement objection is the known review risk. - **Sanity Check:** `rg -c "thin pointer|version-controlled" plugins/autonomy/reference/routines.md` ≥ 2; agnosticism preserved: `rg -c "deployment-owned" plugins/autonomy/reference/routines.md` count increases by ≥1; markdownlint exit 0; CHANGELOG entry present. ### Phase 5: digest-slice deferred items + through-line [DONE] Files (home slice, not repo): `~/.work/youtube-watch/the-4-levels-of-agentic-coding-how-to-sh-XLA-sTSJ-Wc/recommendations/menu.md`, `README.md` (same slice). - Update menu items to final dispositions (adopted → PR refs; deferred → named triggers; no-go unchanged). Add through-line note: Boris doc → interview locks → PLAN → PRs. - **Sanity Check:** `rg -c "deferred" menu.md` ≥ 3; each adopted item carries a PR/branch reference. ### Phase 6: dotfiles tracking proposal [TODO — user gate] - Run the dotfiles repo's `add-dotfile` flow for `~/.claude/scheduled-tasks/` (dir exists with live `autonomy-demo-hourly-drain/`). Flow owns chezmoi mechanics; never `chezmoi apply` from agent context. - **Sanity Check:** dotfiles repo PR/branch exists containing the scheduled-tasks source state, or an explicit operator decline recorded in PLAN. - **User gate:** surfaces before executing (cross-repo write). ### Phase 7: verify + ship [TODO] - Empirical verification in worktree: markdownlint sweep, typos gate, `/skill-quality:check` per touched skill, eval validation. - Version bumps via Edit on the version line (biome retab gotcha). - Conventional commits; PR(s) with PLAN.md in `<details>`; codex threads resolved before merge; close-out per `/planning:plan close-out` (slice prune + pointer). - **Sanity Check:** CI green on PR; `gh pr view` shows mergeable; all phase tags [DONE]. ### Phase 8: trial run (post-merge validation) [TODO] - After plugins update, run the enriched flow end-to-end on a real UI change in a consumer repo: config surface resolved + reported, recording produced per key, gap report exercised (remove a prereq deliberately), evidence table carries session artifacts. - **Sanity Check:** recording artifact exists on disk; gap report emitted on induced prereq failure; operator reviews the recording. ## Blast radius LOW-MEDIUM. Markdown skill/contract text + one new additive config surface; zero runtime code; three plugins touched; consumers unaffected by default (recording defaults off, browser_mode default preserves current behavior). Cross-repo edge: dotfiles proposal (user-gated). ## Stress-test summary Fresh-context plan-reviewer ran against live repo. 3 CONFIRMED-GAPs folded: (1) phantom config surface — read-path resolution + executor plumbing now mandated in P2 with sanity greps; (2) Implementers-table row added to P2 files; (3) CHANGELOG entries added to P2/P3/P4 with SemVer magnitudes (testing minor, verification patch, autonomy minor). Risks addressed: key-ownership boundary framed policy-vs-mechanics in e2e-config.md; routines.md clause re-phrased surface-agnostic with bindings as illustrative examples; eval #1 update made unconditional. Collision re-verified clean (no open PR overlap). Formal /devils-advocate skipped: blast radius LOW-MEDIUM, no infra/CI/dependency triggers. ## Execution shape Wave A (parallel, file-disjoint, one worktree, agents never touch git): | Phase | Surface | Basis | |---|---|---| | 2 run-e2e | Opus builder subagent | mechanical doc edits, largest item | | 3 confirm | Opus builder subagent | small disjoint edit | | 4 routines | Opus builder subagent | small disjoint edit | Wave B (sequential, main thread): 5 (home slice), 6 (user-gated cross-repo), 7 (verify + ship — main thread only, empirical checks + git). Phase 1 precedes all. Scope fences: each builder gets an ALLOWED list = its phase's files; FORBIDDEN = PLAN.md, other phases' files, any git command. Cost: 3 builders vs sequential saves modest wall-clock; fallback = run 2→3→4 sequentially in main thread on any fence violation. ## Open questions None blocking — all interview-locked. ## Handoff to implementation ### User-approval gates - Phase 6 dotfiles add-dotfile run (cross-repo write). - Any mid-flight scope change to config-surface shape. ### Execution shape ([EXEC-SHAPE] tagged) - [EXEC-SHAPE] PLAN drafted in `.work/` first; materialized to `docs/topics/` inside the worktree at Phase 1 (avoids writing to the canonical checkout the primary session owns). - [EXEC-SHAPE] Wave A 3-builder parallel shape with scope fences as above; sequential fallback documented. - [EXEC-SHAPE] Single PR for phases 2–4 (one review surface, shared rationale) unless review load argues for a split at ship time. ### Mechanical work - Commit boundaries: Phase 1 (PLAN + design-resolution), one commit per phase 2–4, Phase 5 lives outside the repo (no commit), Phase 7 ship. - Verification checkpoints: markdownlint + typos + skill-quality per phase before its commit; empirical greps per Sanity Checks. - Sequential fallback: any fence violation → abandon parallel, re-run remaining phases in main thread. </details> 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01QdCmaHa15bwUTh9sy7Rfdz --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
) ## What Sharpens the `orchestrate` skill's per-worker tiering (imperative 7) into an explicit **volume-based default**, and broadens "tier" from model-only to model **and** reasoning effort. ## Why Carried from the re-anchor round-2 ledger (task #3), observed in production: an `/orchestrate` run fanned out ~100–200 agents, all on the top-tier model. PR #340 (0.9.1) fixed the root spawn-inherit bug — SPEC EVERY SPAWN + CALIBRATE now carry a per-worker tier — but the residual enhancement (making the tier *default* flip on volume) was never built. The prior text stated the direction as a gradient ("the wider the fan-out, the cheaper the default per-worker tier") without wiring the verify/judge carve-out as the standing exception, and never named reasoning effort as a tiering lever. ## Change `plugins/session-flow/skills/orchestrate/SKILL.md` — imperative 7: - Past a wide fan-out, the cheaper tier is now the **DEFAULT the whole fleet inherits** (volume multiplies every notch of over-provisioning). - The **standing exception** is an explicitly hard stage — verify, judge/adjudicate, judgment-heavy synthesis — which keeps the parent tier. A premium fan-out outside those stages is a per-stage decision to justify, never a default to inherit. - **Tier is model AND effort**: match reasoning depth (effort), not just the model, to the subtask. `context/sources.md` — three new verbatim citations grounding the change in current official docs: the per-worker `effort` frontmatter lever, the workflow fleet-model inherit mechanism, and the platform's own wide-run threshold (its `Large workflow` warning + `/config` size guideline). Per the skill's model-/tool-agnostic construction, these version-pinned specifics stay in `sources.md`, never the imperatives or export brief. ## Grounding (fresh docs, this session) - Subagent `model` precedence + `inherit` default, `effort` field, cost-routing guidance — <https://code.claude.com/docs/en/sub-agents> - Workflow fleet-model inheritance, per-stage routing, `Large workflow` threshold + size guideline — <https://code.claude.com/docs/en/workflows> ## Gates - `check-skill.sh orchestrate`: PASS (7/7 trigger phrases preserved, 125/500 lines, markdownlint clean) - `check-changelog-parity.sh --check` and `--check-bump origin/main`: PASS - `validate-plugin-contracts.mjs`, `generate-catalog.mjs --check`, `claude plugin validate .`: PASS - Version bumped 0.12.2 → 0.12.3 with CHANGELOG entry in the same diff. ## Related - PR #340 — the session-flow 0.9.1 spawn-inherit fix this builds on (SPEC EVERY SPAWN + CALIBRATE carrying a per-worker tier); not closed by this PR. - The re-anchor round-2 ledger task #3 production observation that motivated the residual enhancement. Closes #863. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
First plugin migrated from medley into this marketplace — the pilot proving the end-to-end lift-and-shift pipeline.
What's in this PR
plugins/markdown-formatter/**— ported PostToolUse hook (markdownlint-cli2 on Write/Edit), bundledhook-utils.shsubset, black-box contract test (12/12), README (16faf60)..editorconfig+.shellcheckrc— platform drop-in configs (5bb2e77)..claude-plugin/marketplace.json— catalog entry making the plugin installable (was empty).README.md— catalog section listing the plugin.docs/MIGRATION-PLAYBOOK.md— step 10 records the./-prefixed source requirement + catalog-manifest validation.Verified
claude plugin validate --strict✔ on both the plugin and the marketplace manifest.--plugin-dirload smoke + source-repo parity (fresh-context) PASS.--plugin-dirand strict-validate do not exercise what a real marketplace install does: relative-source resolution (./plugins/markdown-formatter) and hook firing from the cache copy (~/.claude/plugins/cache). Prove both from this branch ref before merging:/plugin marketplace add https://github.com/melodic-software/claude-code-plugins.git#feat/markdown-formatter-plugin /plugin install markdown-formatter@melodic-software /reload-plugins # edit a .md with a fixable issue → confirm markdownlint-cli2 auto-fixesThis closes the recorded open gap (live in-session PostToolUse fire via an installed plugin). Merge → final user/global install from
main.Note: dropped
metadata.pluginRoot—claude plugin validate --strictrejects the bare source it is meant to enable, despite the marketplaces-doc example.