Skip to content

Phase 14: front door and distribution - #63

Open
sellke wants to merge 80 commits into
docs/phase-13-uatfrom
phase/14-front-door-and-distribution
Open

sellke wants to merge 80 commits into
docs/phase-13-uatfrom
phase/14-front-door-and-distribution

Conversation

@sellke

@sellke sellke commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Phase 14 (Front Door and Distribution, ADR-030). Stacked on #61: the base is docs/phase-13-uat, so this diff shows Phase 14 only. GitHub retargets it to main when #61 merges.

What ships

  • /writ front door. It restates a request as Goal, Problem, and Done check, routes it to the one command whose ceremony fits, confirms once, and mirrors the routed command's phases on the todo list.
  • Plugin distribution. Writ installs as a plugin in Claude Code and in Cursor. install.sh stays.
  • Generated platform trees. scripts/gen-platform-trees.py renders the Cursor rule, the Claude Code block, the Codex AGENTS.md template, and both plugin trees from one source. --check fails on stale trees and on platform terms an adapter does not map.
  • Rendering-delegation rows for /prototype, and the prompting guide (.writ/docs/prompting-guide.md).

Acceptance

.writ/eval/phase-14-acceptance/report.md covers clean-room installs, behavior probes with no-Writ controls, and blind grading against rubrics committed before the runs. The pass found nine defects. All nine are fixed, along with two found while fixing them:

  • D1 and D2: Codex installs had no Prime Directive. After that fix, Codex declined a false claim but read the code in only 1 of 3 runs. One verify line in the Codex intro raised that to 10 of 10, against 1 of 10 without it (.writ/eval/codex-verify-d2/, pre-registered).
  • D3 to D7: /prototype could strand its fix in a worktree. /writ asked for more options than Claude Code's question tool holds. Three adapter rows contradicted the installed CLIs.
  • D8 and found along the way: uninstall now removes unmodified shipped scripts and docs and the refs/notes/writ refspecs. A rerun of the uninstall matrix leaves 0 differing files with --include-writ on all three platforms.
  • D9: /writ asks before routing a request that names something the project lacks. The spec now says so (front-door DEV-009).
  • Plugin DEV-005: four Writ-source maintenance scripts are now dev-only, so plugin commands no longer write inside the plugin.

The /writ routing bar was missed: 10 of 20 against a bar of 16. Seven of the misses are clarifying questions about requests whose projects were absent. Under the amended spec those asks are correct, but the rubric counted them as misses and is not regraded.

Gate

The merged branch passes:

  • uv run pytest and uv run --python 3.9 pytest: 3,062 passed, 2 skipped.
  • Every scripts/tests/test_*.sh.
  • bash scripts/eval.sh, exit 0.
  • gen-platform-trees.py --check: 0 stale.

Needs a person before release

  • Cursor: /writ in chat, the Prime Directive from writ.mdc, and the Cursor plugin loading its agents.
  • Codex Desktop: whether the app renders an HTML draft.
  • GitHub marketplace install: claude plugin marketplace add sellke/writ.
  • Interactive Claude Code in an installed project: the native picker with at most four routes, and the Plan Mode contract line.
  • A colleague on a clean machine follows the README Quick Start.

🤖 Generated with Claude Code

sellke and others added 30 commits October 22, 2026 16:33
Decomposition pre-pass for /implement-phase 14 (Front Door and Distribution):
rendering-delegation-rows, prompting-guide, front-door, generated-platform-trees,
plugin-distribution. Contracts locked 2026-10-22; 18 stories, 120 tasks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rendering-Delegation Rows, Story 1: adapters/claude-code.md gains a dated
verification record under the Quick Reference tool table, four rows from a
live Claude Code 2.1.308 desktop-app run (artifact published and rendered;
Browser pane rendered the served draft and opened the file:// path as a
static snapshot; Claude Design type listable from inside a command run;
headless -p recorded from the docs, unverified). The canvas-preview row is
unchanged.

Tests: test_verification_records[claude-code] (record heading, columns,
anchored status grammar, https source), test_claude_code_record_checks,
test_claude_code_canvas_row_states_facts, and a no-"verified"-in-row
assertion on test_adapter_canvas_row.

Files: 2 product files, 1 drift log, story file, README, context.md.
Tests: pytest 2777 passed, 2 skipped (3.9); bash 45/45; eval.sh 0 findings.
Drift: Small (DEV-001, DEV-002), fixed in place.
Gate 3: evaluator-agent PASS (verdict received from the attempt-1 spawn).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…OpenClaw (Story 2)

Rendering-Delegation Rows, Story 2. Each of the three adapters gains a
dated verification record under its tool table, written from first-party
pages read 2026-10-22 and marked unverified (pending UAT for Cursor and
Codex, no deployment for OpenClaw). The Cursor row drops cursor-ide-browser
(neither Cursor page documents it or a canvas that renders a local HTML
file) and names the HTML-file floor plus the Browser tool's allowlisted
origins. The Codex row becomes a CLI clause (HTML-file floor) and a Desktop
clause (the app docs do not document rendering an HTML draft). The OpenClaw
row is unchanged. technical-spec.md § UAT Protocols is finalized against
the rows for Cursor and Codex Desktop.

Tests: test_verification_records now parametrized over all four adapters
(derived from ADAPTER_TABLES); cursor keywords moved to the floor; new
test_cursor_row_names_the_floor, test_codex_row_has_cli_and_desktop_clauses,
test_uat_protocol[Cursor|Codex Desktop].

Files: 3 adapters, technical-spec.md, test file; spec-lite amended (DEV-003);
story-1 header gains its commit SHA.
Tests: pytest 2784 passed, 2 skipped (3.9); bash 45/45; eval.sh 0 findings.
Drift: Small (DEV-003, auto-amended). Gate 3: evaluator-agent PASS.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… issue note (Story 3)

Rendering-Delegation Rows, Story 3. The record assertions move into
check_record(adapter, table); test_verification_records runs it for all
four adapters, and test_check_record_rejects_bad_cells proves it rejects a
Source of "not documented", a Status without a date, a Status with a version
appended, and a record with no data row, each message naming the adapter and
the cell. test_prototype_render_table_reconciled pins that no recorded
observation changed commands/prototype.md Step 2.5 (the Claude Code run found
the Claude Design type listable from inside a command run, so the native
surface row stands; no drift entry). The origin issue gains a
### Verification note under ## Resolution with each adapter's status at
spec close. spec.md Status -> Complete; story 2 header gains its commit SHA.

Files: test file, origin issue, spec.md, story/README/context bookkeeping.
Tests: pytest 2789 passed, 2 skipped (3.9); bash 45/45; eval.sh 0 findings.
Drift: None. Gate 3: evaluator-agent PASS.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add .writ/docs/prompting-guide.md (61 lines): the three parts a request
carries (Goal, Done check, Proof), five route recipes with weak and strong
examples, and five pitfalls. Add scripts/tests/test_prompting_guide.py
pinning the H2 headings, part names, recipe routes, line budget, and the
no-internal-links rule. Record Story 1 drift (DEV-001..003, all Small).

Tests: targeted 5/5; pytest 3.9 2794 passed, 2 skipped; bash 45/45;
eval.sh 0 findings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…hip set (Story 2)

Add the "New here? Read .writ/docs/prompting-guide.md (two minutes)."
pointer directly under README § Quick Start, above the five-command
table, with no /writ clause (the front-door spec adds it). Extend
scripts/tests/test_prompting_guide.py with test_readme_links_guide (the
Quick Start section names the guide's path) and test_ships
(is_shippable_writ_doc from scripts/install.sh and scripts/update.sh,
extracted with sed and sourced in a bash subprocess, admits
prompting-guide.md). The function is sourced from a here-string because
the spec's process-substitution sketch defines nothing on macOS bash 3.2
(DEV-004, Small).

Tests: targeted 7/7; pytest 3.9 2796 passed, 2 skipped; bash 45/45;
eval.sh 0 findings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tests (Story 1)

commands/writ.md (135 lines): restate as Goal / Problem / Done check / Proof,
classify with the six-row Routing Rules table and the /prototype escalation
tie-break, confirm once with one AskQuestion ((Recommended), "Not what I
meant" last), mirror the routed command's ### Phase N / ### Step N headings
onto the todo list with skip: <reason>, then follow the routed file with the
restatement. Writes nothing under .writ/.

scripts/tests/test_front_door.py: test_command_file, test_guide_cited,
test_routing_rules, test_confirmation_step, test_mirroring_step (AC-1.1 to
AC-1.5), red then green; 8/8 mutations caught.

Known until Story 2 registers the command: check_manifest and the leanness
README-orphan finding (8 governor tests, test_eval_leanness.sh). Drift: Small
(DEV-001, DEV-002).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Manifest gains the first category `entry` ("Start here") and the writ entry
between verify-spec and writ-design; SKILL.md and claude-code/CLAUDE.md are
regenerated by their generators (the CLAUDE.md template gains a "Start with
/writ" line); codex/AGENTS.md.template and README § Commands gain a Start
here table; README § Quick Start opens with /writ and a two-line example,
completes the prompting-guide pointer, and puts the five-command table under
"What /writ routes to"; cursor tree 32 -> 33; status.md allowlists lead with
writ; model-tiers high row 15 -> 16; Claude Code todo_write -> TodoWrite.

scripts/tests/test_front_door.py registration section: test_manifest,
test_catalogs, test_readme, test_surfaces (AC-2.1 to AC-2.5), red then
green. Two pre-existing tests re-anchored (gen-claude-md fixture, allowlist
and tree anchors). Story 1's README-orphan failures are cleared: pytest 2805
passed, bash 45/45, eval.sh 0 findings. Drift: Small (DEV-003 to DEV-005).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e, and record the routing fixture (Story 3)

scripts/eval-command-structure.py gains two rows for commands/writ.md (the
Routing Rules heading and the entry_level frontmatter key); the
in-your-own-words issue gets its ## Resolution and spec_ref; the routing
fixture's eight requests route as expected 8/8 (coder, orchestrator, and
evaluator each applied Steps 1-3). Step 2's tie-break gains one sentence
saying a signal counts only when stated or nameable (DEV-006); the rule
table is unchanged and the file stays at 135 lines.

scripts/tests/test_front_door.py: test_issue_resolution, test_structure_rows
(AC-3.1, AC-3.2), red then green; 11 tests. pytest 2807 passed, bash 45/45,
eval.sh 0 findings. spec.md Status -> Complete.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ory 1)

scripts/gen-platform-trees.py parses the four adapter tool tables by
heading chain, normalizes column 1 to a capability name, fails closed on a
malformed or empty table, is unverifiable on a missing heading, and
computes the neutral set, unmapped, and vendor_only; main() is a stub
until Stories 2-4 add the writers, --check, and coverage. The tables now
agree on the golden neutral set: codex gains file_search, openclaw folds
readonly: true into Task({ readonly: true }), and every table ends with a
Plan Mode row (Claude Code EnterPlanMode; Cursor asks the user; Codex and
OpenClaw run discovery read-only and say so). create-spec Step 1.3,
plan-product Step 1.2, and new-command Step 1.2 point at the adapter's
Plan Mode row, one sentence each; the Plan Mode issue is resolved.

gen-platform-trees.py joins the is_shippable_script dev-only case in
install.sh, update.sh, and unlink.sh (DEV-001: the CLI-contract tests
derive the shipped set from it); a backticked token containing :// is a
URL, not a vendor identifier (DEV-002); the cursor Plan Mode row keeps the
command list in Used By and the mapping plus degradation sentence in
Purpose (DEV-003). The create-spec byte ledger is re-pinned 13602 -> 13654.

scripts/tests/test_gen_platform_trees.py: 30 tests (AC-1.1 to AC-1.5),
red then green; five fixtures under scripts/tests/fixtures/platform-trees/.
pytest 2837 passed, bash 45/45, eval.sh 0 findings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ap (Story 2)

scripts/gen-platform-trees.py gains write mode: it parses the four adapters,
checks parity, runs every sub-generator's --check, and only then writes
cursor/writ.mdc (alwaysApply frontmatter, generated-file comment, the
system-instructions.md body verbatim, the Cursor Capability Map) and runs
gen-claude-agents.py, gen-codex-agent-tomls.py, and gen-claude-md.py,
relaying their wrote lines; any input reason or a sub-generator exit >= 2
prints fail and writes nothing. capability_map(adapter, root) renders one
row per neutral name in adapter order with Task variants as sub-rows and
the degradation sentence in "When unavailable". gen-claude-md.py fills a new
{capability_map} slot after the Commands table from the driver, loaded by
path, and fails on a malformed adapter row or an @ outside backticks in the
map.

The takeover of cursor/writ.mdc is purely additive: the hand copy was
byte-identical to system-instructions.md. Producers run first so one run
converges; a sub-generator's stale/missing/absent/extra reasons are what
write repairs and do not block it (DEV-005); the write-mode summary is
(<n> written, <r> reasons) (DEV-004); CLAUDE.md keeps gen-claude-md.py's
header and no comment (DEV-006).

scripts/tests/test_gen_platform_trees.py: 11 Story 2 tests (AC-2.1 to
AC-2.5); test_gen_claude_md.py and test_eval_claude_md.sh copy the driver
and adapter into their temp roots. pytest 2856 passed, bash 45/45, eval.sh
0 findings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ls, and the Codex map (Story 3)

scripts/gen-platform-trees.py renders codex/AGENTS.md.template from
.writ/manifest.yaml (categories, commands, agents), every skills/*/SKILL.md
description, the built-ins paragraph as a literal, and the Codex Capability
Map, in the order Writ on Codex, Available Commands (Start here first),
Available Agents, Available Skills, Built-in Codex slash commands vs Writ,
Capability Map, Catalog source. Line 1 keeps the merge-marker comment the
install and update scripts read; line 2 names the generator; the file has
no adapters/ mention and is 12478 bytes. The renderer fails closed on an
adapters/ mention or a render at 16 KiB (DEV-007), and write mode now
writes 19 files.

The takeover replaces the hand-maintained file: the stale command, agent,
and skill lists and the twenty truncated purpose cells give way to the
manifest text, the adapters/codex.md clause points at the map below, and
no still-true sentence is lost (the story records the diff line by line).

scripts/tests/test_gen_platform_trees.py: 20 Story 3 tests (AC-3.1 to
AC-3.4), red then green; 63 tests in the file. pytest 2876 passed, bash
45/45, eval.sh 0 findings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…eval check to gen-platform-trees (Story 4)

scripts/gen-platform-trees.py --check renders cursor/writ.mdc,
claude-code/CLAUDE.md (via gen-claude-md), and codex/AGENTS.md.template in
memory and compares bytes with disk (stale, missing), folds the three
sub-generators' --check output (orphan claude-code/agents/<name>.md and
codex/agents/<name>.toml translated to the driver's own paths, everything
else as `<gen>: <kind> <detail>`), reports a claude-code/agents/*.md outside
gen-claude-agents' writ-*.md glob as the driver's own orphan, and ends with
the vendor scan; it writes nothing and prints the five-count summary.
`coverage` reports unmapped names and vendor hits only. A backticked token
references a tool when its leading identifier is followed by nothing or by
call syntax, so `Grep("pattern")` is a hit for Grep (Rule 4; the story's
open edge case); a dotted field, URL, path, key: value, flag, or assignment
is not. The allowlist stays Read, Write, Bash. TARGETS carries the three
identity targets (each narrows write mode to its platform) and the fixture
target, whose --out-dir tree rewrites every `(python3|bash) scripts/<name>`
token to ${PLUGIN_ROOT}/scripts/<name> as bytes and nothing else. Write
mode now also refuses a vendor hit or a stray agent file.

scripts/eval.sh: check_platform_trees runs --check once (it already carries
the coverage reasons; DEV-008), turns each reason into a finding located at
its path with the regenerate-and-commit remedy, and counts a helper exit of
2 or more, or a missing verdict line, as a run error.

The first coverage run found three vendor hits and each was rewritten on
its own line: commands/create-issue.md Grep -> codebase_search and Glob ->
file_search; commands/writ-design.md browser_navigate, which has no neutral
name, -> neutral prose (DEV-009). The is_shippable_script denylist entry
landed in Story 1 (DEV-001); the three bodies stay byte-identical.

Tests: 41 Story 4 cases in test_gen_platform_trees.py (100 in the file),
red on the stub then green; test_eval_platform_trees.sh (6 assertions) with
three killed mutants. pytest 2913 passed 2 skipped, bash 46/46, eval.sh 0
findings. Review: PASS, drift Small (DEV-008, DEV-009).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
sellke and others added 30 commits October 23, 2026 17:15
Evidence-bound writeback from /implement-phase 14: harness stops are not
lane failures; run pytest alone; spec headings must match story-context.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 scripted scenarios pass, 0 fail, across the five plans. 19 stay open
for the maintainer: live Claude Code, Cursor, and Codex Desktop sessions,
three steps blocked by a logged-out CLI, and the post-merge GitHub install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Front door: all 16 scenarios pass. The maintainer ran Scenarios 1 to 10
live in a clone; Scenario 11 and plugin-distribution Scenario 2 ran in a
logged-in shell with the corrected probe command. Scenario 10's
missing-roadmap and missing-routed-file steps were not run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plugin install from a local clone scaffolds .writ/ from the plugin root
and routes with namespaced commands; both install paths coexist; undo
restores both registries and leaves settings.json unchanged. Notes one
restatement-shape miss in two /writ:writ runs and the removal of /agents
in Claude Code 2.1.310.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/create-spec enters Plan Mode through EnterPlanMode on its own, presents
the contract proposal as the plan, and renders the Contract Decision only
after the plan exit. The plan's sample request does not fit the Writ repo;
the run that reached the contract used a Writ-shaped request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UAT 2026-10-23: a /writ:writ run in a session that already held context answered in prose without the Goal, Problem, Done check, and Proof lines. Step 1 now says to print them first every time and never fold them into prose; a test pins the rule. Plugin and Cursor trees regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude Code's plan-exit dialog says the plan is ready to execute, which reads as if approval starts building. The Plan Mode row now has the agent open the contract plan with one line saying approval accepts the draft and runs nothing. Capability map regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plugin Scenario 2: the probe prompt goes before --tools "", which takes several values and swallowed it. Plugin Scenario 9: /agents is gone in Claude Code 2.1.310 and autocomplete matches by prefix; read the loaded inventory instead. Generated-trees Scenario 6: use a request that fits the Writ repo; a UI request makes /create-spec correctly decline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s; omit a failing Cursor plugin from the README

- gen-platform-trees: the cursor-plugin target adds name and description
  frontmatter, taken from the manifest purpose, to each agent whose source
  has none (DEV-017). A missing manifest entry is an error.
- test_readme_install_order follows spec Rule 10: a cursor-plugin fail
  result requires the "### Cursor (plugin)" subsection to be gone (DEV-022).
- Drift log, Cursor adapter record, and UAT plan S5 and S8 updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- adapters/codex.md: the CLI row is verified 2026-10-24 with codex-cli
  0.163.0. The Desktop row stays pending UAT.
- The origin issue's codex line and test_issue_verification_note pin both
  statuses.
- Rendering UAT: Scenario 3 passes in the Claude Code desktop app;
  Scenario 8 records the CLI half.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…brics

Committed before any acceptance run, so labels and pass criteria cannot
drift toward the results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Acceptance runs showed a Codex install loading the AGENTS.md Writ block
with no Prime Directive: the block pointed at a system-instructions.md
that install.sh never copied for Codex. With Writ installed, Codex
confirmed a false claim about the code without reading it in 3 of 3 runs.

- The generated template gains a Prime Directive section: the obligation
  line, Hard Constraints, and Recommendation Semantics, byte for byte from
  system-instructions.md, plus a pointer to .codex/system-instructions.md.
  14.5 KB, under the 16 KB cap.
- install.sh, update.sh, and uninstall.sh install, update, preserve, and
  remove .codex/system-instructions.md; an older install gets it as new.
- Lifecycle docs, README, and the Codex adapter say so.
- After the fix the identity probe passed 3 of 3. Drift DEV-011.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The acceptance pass rechecked adapter rows against Claude Code 2.1.310 and
codex-cli 0.163.0 and found four written from docs or memory:

- Claude Code AskQuestion said "no interactive UI", and the generated map
  shipped that to every install. It now maps to AskUserQuestion (one to
  four questions, two to four options), with numbered text only when the
  platform has no question tool, as in headless `claude -p`. Drift DEV-012.
- todo_write gains the same headless fallback: print the checklist.
- A dated record row: headless init lists Artifact, and lacks
  AskUserQuestion, TodoWrite, and the plan tools even when named.
- Codex search rows named Glob and Grep tools. Codex's event stream shows
  shell commands only, so the rows use rg and ls through the shell.

scripts/eval-platform-facts.py (dev-only) rechecks the facts the harness
and adapters depend on; --live starts short sessions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Step 3 offered the proposed route, every other route, and "Not what I
meant": up to seven options. Claude Code's question tool takes two to
four, and front-door S10 saw the widget show four. The confirmation now
holds the proposed route, the two closest alternatives, and "Not what I
meant", and the prompt names the routes left out. Spec Must Include 2,
Journey step 3, and Business Rule 4 amended; drift DEV-007.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ckout

Under the Claude Code plugin, /writ:writ routed to /writ:prototype
--no-diverge, and in 2 of 3 runs the writ:writ-coder agent finished the fix
in its isolated worktree while the user's checkout stayed unchanged and
the reply said the tests passed. Step 3 now cites the worktree-integration
skill, pipes the diff into git apply with no temp file outside the
project, and requires git status to show the change. After the fix, 3 of
3 plugin runs landed the change. Drift front-door DEV-008.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The acceptance audit found DEV-005 recorded only in ADR-031:
/writ:new-skill and /writ:refresh-command run four self-locating scripts
from the plugin's folder, so they read and write there, not in the
project. The Claude Code adapter's plugin facts and the README plugin
paragraph now say so. The output-style bullet also records the observed
result: with the user's own outputStyle set, the plugin's Prime Directive
still loaded in 3 of 3 runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- coverage-audit.md/json: 83 claims mapped to scenarios before any run;
  60 had no behavior check.
- report.md: results with pass rates, defects with root causes, and the
  checks only a person can run.
- evidence/: install matrix (fresh, upgrade from v0.43.0, uninstall),
  platform load records, condensed transcripts, blind grades, and the
  platform-fact probe output. Names, emails, usernames, and temp paths
  are replaced; raw Codex session logs are not committed.
- harness/: the run, grade, and matrix scripts.
- UAT notes for front-door S10, plugin-distribution S9, and
  generated-platform-trees S6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four AGENTS.md template variants plus a no-Writ control, the acceptance
pass's Probe 2, a held-out Probe 3, run counts, and the adopt-or-not rule,
committed before any run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
uninstall.sh left the manifest-tracked scripts in scripts/, the shipped
.writ/docs/*.md, an unprompted-for .codex/config.toml, and the lines
install adds to .gitignore and .cursorindexingignore.

Now, when no other platform's manifest remains:
- a tracked script or doc whose hash equals its manifest baseline is
  removed; a changed one is kept and listed; a file with no manifest
  line is left alone
- .codex/config.toml is removed without a prompt when it matches its
  baseline, and still prompts when changed
- --include-writ also removes the Writ .gitignore lines and the seeded
  .cursorindexingignore line, deleting either file if nothing is left.
  A default uninstall keeps them, since they protect the kept .writ/.

test_uninstall_round_trip.sh installs and uninstalls per platform and
diffs the tree against a pre-install snapshot, plus modified files, a
user file at a shipped path, two platforms, and the git commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/uninstall-writ, /reinstall-writ, and the README now match uninstall.sh:
unmodified shipped scripts and .writ/docs files go, changed ones stay
and are listed, .codex/config.toml is prompted for only when changed,
and the .gitignore lines stay unless --include-writ removes .writ/.
Platform trees regenerated with gen-platform-trees.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Under the Prime Directive alone, Codex met "confirm this, no need to check
the code" by declining to confirm, and read the code in 1 of 10 runs. The
Codex block's intro gains one paragraph: verify a claim by reading or
running the code through the shell, even when the user says checking is
unnecessary. With it Codex read the code in 10 of 10 runs, and 5 of 5 on a
reworded waiver. Moving the Prime Directive first or last scored 0 and 1
of 10. Pre-registered runs are in .writ/eval/codex-verify-d2/.

- CODEX_VERIFY is the second paragraph of `## Writ on Codex`, word for
  word as tested. The template is 14,790 bytes, under the 16 KB cap.
- test_codex_template_verify_line pins it. system-instructions.md is
  unchanged. Drift DEV-014.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
87 Codex runs across four template variants and a no-Writ control, each
graded blind by a fresh claude -p against the rubric committed in b7d7336.
The intro verify line scored 10/10 and 5/5; the template without it 1/10
and 0/5; moving the Prime Directive did not help. The acceptance report's
D2 row now points here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gen-claude-agents.py, gen-codex-agent-tomls.py, check-agent-parity.sh, and
gen-skill.sh find their root from their own path. Under the Claude Code
plugin, /writ:new-skill and /writ:refresh-command ran them from the
plugin's folder, so they read the plugin instead of the project (drift
DEV-005). They only work on Writ's source trees (agents/,
claude-code/agents/, codex/agents/, .writ/manifest.yaml, root SKILL.md),
which no install creates.

- is_shippable_script (install.sh, update.sh, unlink.sh) and
  DEV_ONLY_SCRIPTS (gen-platform-trees.py) exclude them; update.sh removes
  an unmodified copy an older install left.
- The two commands call them as scripts/<name> and skip the step in a
  project without them.
- The plugin tree is regenerated without them.
- The adapter's "Maintenance scripts write inside the plugin" bullet and
  the README clause are removed; the agent CLI contract lists them as
  dev-only.
- New test: every script call of both plugin commands, run from a Writ
  checkout, leaves the plugin byte-identical and regenerates the
  checkout's stale files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
install.sh adds +refs/notes/writ:refs/notes/origin-writ to
remote.<remote>.fetch and refs/notes/writ to remote.<remote>.push.
uninstall.sh left both in .git/config, and the push line keeps a plain
`git push` from pushing the current branch after Writ is gone.

On the last platform's uninstall (no other .writ-manifest), uninstall.sh
now removes exactly those lines, plus the pre-0.33 fetch line, from every
remote. Other refspecs, the notes, and writ.auditNotes stay. --dry-run
lists the lines. /uninstall-writ documents the step; platform trees
regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ect lacks (D9)

In acceptance runs R04 and R12 the request stated a goal, yet /writ
searched, found nothing it named, and asked where it lives instead of
routing. Business Rule 4 said routing proceeds whenever the goal is
present. The maintainer chose the observed behavior: a route built on
absent code plans against nothing.

- commands/writ.md Step 1 states the case: say what was searched for, ask
  one natural-language question, route from the answer.
- spec.md Rule 4 and the State Catalog gain it. Drift DEV-009.
- Plugin trees regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
D2, D8, and D9 are fixed, plus the notes refspecs and plugin DEV-005
found along the way. The report's verdict, result rows, and defect rows
now say so, and a new After the pass section lists each fix with its
commits and evidence.

- Uninstall matrix rerun on the merged branch (harness/recheck-uninstall.sh):
  --include-writ leaves 0 differing files and 0 refspec lines on all three
  platforms; a default uninstall keeps only the two ignore files.
- Codex on the merged branch: identity 3/3, verify 3/3.
- Gate green: pytest on the default interpreter and 3.9, bash tests,
  eval.sh, gen-platform-trees --check.
- Routing stays 10/20 as graded; the rubric is not regraded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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