Skip to content

docs(playbook): document the local plugin development loop - #7

Merged
kyle-sexton merged 1 commit into
mainfrom
docs/local-dev-loop
Jun 24, 2026
Merged

docs(playbook): document the local plugin development loop#7
kyle-sexton merged 1 commit into
mainfrom
docs/local-dev-loop

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

Summary

Adds a Local development loop section to docs/MIGRATION-PLAYBOOK.md. The playbook covered first-publish validation (the migration gate's --plugin-dir step) but had no guidance for iterating on an already-shipped plugin against a local clone — the gap surfaced while finalizing how a consumer (dotfiles) keeps its tracked marketplace registration stable.

The new section documents the doc-verified loop:

  • claude --plugin-dir ./plugins/<name> loads the working copy; when the name matches an installed marketplace plugin, the local copy takes session precedence (no uninstall needed).
  • Edit → /reload-plugins picks up on-disk changes without a restart (reloads skills, agents, hooks, MCP/LSP).
  • The override is session-scoped and never edits a consumer's extraKnownMarketplaces — the published remote registration stays put. Exception: cannot override a plugin force-enabled/disabled by managed settings.
  • Trust considerations apply; validate before PR; consumers pull via /plugin marketplace update.

Verification

Verified 2026-06-24 firsthand against the official Create plugins guide ("Test your plugins locally" / quickstart), per this repo's fresh-docs mandate. No new external links introduced (link-checker safe); MD013 is disabled so prose wraps freely.

🤖 Generated with Claude Code

The playbook covered first-publish validation (the migration gate's
--plugin-dir step) but not how to iterate on an already-shipped plugin
against a local clone. Add a "Local development loop" section: load the
working copy with `claude --plugin-dir ./plugins/<name>` (the local copy
takes session precedence over the installed same-name plugin), edit then
`/reload-plugins` to pick up on-disk changes without a restart, commit, and
let consumers pull via `/plugin marketplace update`.

Key point for the consumer seam: local development never requires switching
a consumer's tracked `extraKnownMarketplaces` source — the published remote
registration stays put; `--plugin-dir` overrides it for the session only.

Verified 2026-06-24 against the official plugins guide (canonical URLs in
CLAUDE.md), per this repo's fresh-docs mandate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kyle-sexton
kyle-sexton merged commit 39e2ca0 into main Jun 24, 2026
14 checks passed
@kyle-sexton
kyle-sexton deleted the docs/local-dev-loop branch June 24, 2026 18:03

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e93f2666fd

ℹ️ 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".

- **Trust.** A locally loaded plugin carries the same trust considerations as any source — only load
directories you control.
- **Then ship.** Run `claude plugin validate` before opening a PR; after merge, consumers pull the
change with `/plugin marketplace update melodic-software`, gated by the `version` bump in `plugin.json`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Tell consumers to update the installed plugin

For release instructions, this command only refreshes the marketplace catalog/version data; the Claude plugin reference lists installed plugin upgrades under /plugin update/auto-update and uses the plugin version as the cache key. A consumer with <name>@melodic-software already installed can run this and still keep using the old cached plugin code, so the playbook should include /plugin update <name>@melodic-software (then reload/restart as needed) when the intent is to receive shipped changes.

Useful? React with 👍 / 👎.

@claude claude Bot mentioned this pull request Jul 11, 2026
kyle-sexton added a commit that referenced this pull request Jul 21, 2026
… 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>
kyle-sexton added a commit that referenced this pull request Jul 29, 2026
…or a non-repo consuming directory (#1728)

## Summary

`continue-in-background`'s dirty-tree gate opened by running `git status
--porcelain -uall` in the
consuming project. In a directory that is not a git repository — a
session started in `$HOME`, say —
that fails with `fatal: not a git repository` and the skill has no
specified behavior. The gate
specified clean, dirty, and linked-worktree; not "no repository at all".

The gate now establishes repository status first with `git rev-parse
--is-inside-work-tree`, and is
exhaustive **by construction** rather than by enumeration: two results
may leave the default, and
everything else falls through to the conservative branch.

| `rev-parse` result | Behavior |
| --- | --- |
| prints `true` | Inspect the tree with the existing `git status
--porcelain -uall` gate, unchanged |
| fails *specifically* with "not a git repository" | Launch. No
uncommitted work to protect, and no worktree isolation to lose — outside
a repository (absent a `WorktreeCreate` hook) background sessions write
to the working directory directly. The launch report states that reading
|
| **anything else** | Tree state UNKNOWN, which is not clean → do NOT
launch; same fallback as the dirty case |

That third row is the load-bearing part, and it is why this is a little
more than the issue's "one or
two sentences" — not scope drift. A gate that fails open is worse than
no gate. Reading a non-zero
exit alone as "no repository" would put dubious-ownership,
damaged-repository, and git-missing cases
on the launch path — exactly where the tree is most likely dirty and
least likely readable. The
unknown default is deliberately wide and it catches a zero-exit case too
(below).

Also here: the context-gathering block's "treat any failure as an
unknown value and carry on" is now
scoped to itself. It colors the save-point and is not the gate; carrying
that shrug — or that block's
non-`-uall` `git status` output — into delivery step 1 would defeat the
gate from a section that runs
before it.

## Evidence

**Gates** (run in the worktree against `origin/main`):

- `check-skill` (the checker `scripts/check-changed-skills.sh` invokes):
**PASS — 0 errors, 0 warnings**; 195/500 lines, all 4 base-ref trigger
phrases preserved
- `scripts/validate-plugin-contracts.mjs`: **pass** — 43 setup skills,
2123 plugin files
- `scripts/check-changelog-parity.sh --check-bump origin/main`: **pass**
— 0.17.16 → 0.17.17 patch bump paired with its `## [0.17.17]` entry
- `markdownlint-cli2` on both changed markdown files: **0 errors**
- `evals.json` validated against
`plugins/skill-quality/reference/evals.schema.json`: **valid**

**Harness claim verified against current docs.** The non-repo sentence
asserts harness behavior, so
it was checked against <https://code.claude.com/docs/en/agent-view> this
session rather than from
recall. That page states isolation is skipped when the working directory
is not a git repository and
no `WorktreeCreate` hook is configured, and that outside a repository
sessions write to the working
directory directly — which is what the new branch relies on, including
the hook qualifier.

**Non-vacuousness — stated honestly.** `evals.json` in this repo is
declarative and model-graded;
there is no runner that asserts, so the three added cases are not
executed regression tests and are
not presented as such. The discriminating argument is textual and
checkable from the diff: an agent
following the pre-change SKILL.md has no branch for #5 (it runs `git
status --porcelain -uall` blind
and hits `fatal: not a git repository`) and no branch at all for #6 or
#7.

- **#5 `non-repo-directory-launches`** — non-repo consuming directory →
launches, states the non-repo reading, STOPS
- **#6 `unknown-tree-state-does-not-launch`** — dubious-ownership
failure → does NOT launch. This is the case that proves the gate does
not fail open
- **#7 `no-work-tree-despite-zero-exit-does-not-launch`** — bare
repository, exit 0 printing `false` → does NOT launch

## Review

Reviewed by a fresh-context reviewer with the rationale withheld. Two
IMPORTANT findings, both fixed
in `748ab3cb` before this PR:

1. **Unrouted fourth outcome.** `git rev-parse --is-inside-work-tree`
exits **0** and prints `false`
inside a bare repository or a `.git` directory — verified empirically by
the reviewer. The
original three-way enumeration left that state unspecified, which is the
same defect class the
issue reports. Fixed by inverting the structure to two specified results
plus a default, and
   guarded by eval #7.
2. **Contradiction with the context block.** "Treat any failure as an
unknown value and carry on"
sat 50 lines above a gate that now reads a git failure the opposite way.
Fixed by scoping that
sentence to its own block and pointing at the gate as owning failure
semantics.

One finding was accepted and **not** fixed, as out of scope: the gate's
pre-existing rationale that
uncommitted changes "would NOT carry into the launched agent's edits"
does not hold when a consumer
sets `worktree.bgIsolation: "none"`, under which background sessions
edit the working copy directly.
The gate's decision stays conservative either way, so this is an
inaccurate rationale rather than a
hole — untouched by this PR and worth its own issue.

Closes #929

## Related

- #924 — introduced the skill and this dirty-tree gate
- #233 — origin design for the save-point/handoff engine the skill
shares
- #1687 — the `$`-expansion isolation constraint the context block's
shape exists to satisfy; the new
`git rev-parse --is-inside-work-tree` carries no `$`-expansion and sits
in the body, not pre-compute

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
kyle-sexton pushed a commit that referenced this pull request Aug 17, 2026
…ry removed

Phase 8 of docs/topics/teach-skill-comparison/PLAN.md, closing the
approved plan:

- After-dogfood run executed by a fresh-context agent at 0.7.0
  against the IDENTICAL baseline persona script (same learner
  turns, same scripted git-hooks misconception, same sanctioned
  plugin-data substitution -> dogfood/after/). The canary
  TEACH-CANARY-h3rpag-p8 was reported verbatim from SKILL.md
  line 12 — live working-tree reload proven — and is removed by
  this commit (grep count now 0).
- Comparison written (memory slice: dogfood/
  COMPARISON-BEFORE-AFTER.md beside the two runs, per the
  topic-docs convention; distilled verdict recorded in PLAN.md
  Phase 8): baseline defect findings F1-F13 RESOLVED with live
  evidence, F15 partially (exit-2 semantics witnessed; unset-
  creation path test-covered), strengths F14 preserved. Zero
  defensive external fetches (baseline: 2); mechanical deictic
  routing; harvest-first interview with no re-asked questions;
  platform-aware markdown fallback + open-offer skip honest on
  the headless host; Tier-0 grounding throughout.
- Scoped per DA #7: rung 4 Documents, rung 2 userConfig, the
  HTML/splice/quiz branch, tier-1+ research, and Windows known-
  folder resolution remain mechanically covered (29-check test
  suite, evals 7-9, acknowledged Windows manual gap) — never
  claimed dogfood-proven.
- Six minor new findings recorded as refinement candidates (none
  caused wrong behavior): rung-3 mode qualifier by inference,
  duplicate probe re-invocation, glossary promotion granularity,
  Tier-0 platform-claim boundary / egress-blocked tier-1 gap,
  unconditional assets/ in the layout diagram, next-focus
  persistence home.
- PLAN.md Phase 8 tag advanced to [DONE] — all eight phases DONE.

Sanity evidence: grep -c TEACH-CANARY SKILL.md = 0;
dogfood/after/ holds transcript + findings + workspace;
COMPARISON-BEFORE-AFTER.md exists with the per-finding table;
markdownlint 0 issues; list-workspaces.test.sh PASS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SUiFZXmwMYiqKnQ4RM233y
kyle-sexton pushed a commit that referenced this pull request Aug 20, 2026
…nt generator bug they exposed

Each verified against the code before acting.

Gitea README verb table called create-item, get-item, link-blocks and list-items
"scaffold — provider mapping to write". Per the README's own definition that means
the script still calls wit_gitea_unimplemented and exits 1. None of them does —
all four are real implementations with passing tests. The table was telling a
consumer that four core verbs do not work.

Label pagination in gitea/create-item.sh had no ceiling while every other
paginated loop in the adapter caps against WIT_GITEA_LIST_ITEMS_MAX. Capped —
but not by copying list-items' treatment, because the consequence differs: there,
truncation just returns fewer items; here, stopping early makes an unseen label
indistinguishable from a nonexistent one, and the next step tells the operator to
create a label that already exists. The ceiling therefore also qualifies that
message.

Conformance binding for basic auth baked auth_user to the literal
ci@example.invalid with no override, while host and scope are required from the
environment — so a generated basic-auth adapter would authenticate as the
placeholder against a real throwaway instance and 401 with nothing saying why. It
now takes the identity from the environment the same way.

Linear binding's scope comment said "e.g. owner/repo"; Linear's scope is
<workspace>/<TEAMKEY>. Fixed in the generated file and at the template that
propagates it, where it now shows the provider's own sample scope.

Two defects of my own, caught by generating a basic-auth adapter rather than
assuming the change was fine: SAMPLE_AUTH_EXTRA feeds BOTH the offline test
fixture (which needs a literal) and the conformance binding (which needs the jq
variable), so collapsing them emitted `$au` into the test's single-quoted JSON —
now two keys; and an apostrophe inside ${VAR:?word} is parsed as a quote by bash,
which broke the generated file's syntax.

That exercise also exposed a latent template bug worth its own note: the
generated test asserted a HARDCODED id number of 12, while the id comes from the
configurable api.sample_id. Both shipped specs happen to end in #12, so it never
showed — but any consumer with a different sample id got a failing test the moment
their adapter was generated, from a template that promises "every case here is
real and passes the moment the adapter is generated". Now derived from the id.
Verified both shapes: a #7 spec and a #12 spec each generate a passing test.

52/52 suites pass; portability, ShellCheck, markdownlint and check-skill clean.

Refs #2946, #2950, #2952.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CnzwTKoTa6xNY7iyEzMYpm
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