Repository navigation
Releases: m4bwav/wikiwright
Release list
wikiwright 0.9.2
wikiwright 0.9.1
C-20261003-2 � 2026-10-03 � Release 0.9.1: ready for the Claude plugin directory, launcher packages pinned (directory-prep)
- because: user request (submission to the Claude plugin directory and its pre-submission checklist); T-20261003-1
- files: .claude-plugin/plugin.json (version; documentationUrl to the wiki, supportUrl, privacyPolicyUrl), ../../README.md (Privacy), references/npm.md (the oldest Node in engines; TypeScript), templates/npm/wiki-verify.template.mjs (OLDEST_NODE comments), SKILL.md (Step 3 oldest-Node line;
metadata.version), MAINTENANCE.md and RESEARCH.md (npx skills@1.7.0), scripts/wikiwright.py (VERSION), evergreen.json (version), ../../ai-docs/decisions (the 92-character decision file name shortened to2026-09-28-wikiwright-own-plugin.md) - The directory wants every package a launcher runs pinned: the docs now pass
OLDEST_NODEan exact version (20.20.2; the template already accepted one, and a bare major still works), and shownpx -p typescript@7.0.2andnpx skills@1.7.0. The README's Privacy section lists every route the skill and script use. The long decision file name broke Windows clones under deep paths (Filename too long). 0.9.1 also carries C-20261003-1 and C-20261004-1.
wikiwright 0.9.0
- because: user request (the TrailerClipperLib and CachingServiceWithAOPSupport kickoff); C-20261001-1 to C-20261001-6; T-20261001-1; L-143 to L-147
- files: .claude-plugin/plugin.json, scripts/wikiwright.py (
VERSION), SKILL.md (metadata.version; Steps 3 and 4 route to the new references and toscaffold nuget), evergreen.json (version, counts, tests, history), README.md (tested page sets,scaffold nuget) - 0.9.0 gathers the entries below.
wikiwright.py releasecheck 0.9.0checks the four version fields, this entry and T-20261001-1. - The ninth real run (TrailerClipperLib: TrailerClipper 2.0.0 and the dotnet tool TrailerClipper.Tool, headless, installed code): 11 pages with Commands and Configuration, wiki 72e35c3, check 0 errors, outputs 104 of 104, snippets 37 of 37, net10.0, net8.0 and net48 on Windows and net10.0 in WSL, golden 148 of 148 for 1.1.0 today on net48 (2.0.0 121 and 113, every difference a named exception), repository tests 193 and 193; $14.68, 40 minutes, 193 turns. It found a crash in
tclipper -o <folder>, fifteen inaccuracies in the shipped docs and fifteen places the skill was wrong or missing (C-20261001-3, C-20261001-4). The command-line tool sketch held with the library set in union and became a tested set. - The tenth run (CachingServiceWithAOPSupport 2.0.0): 9 pages, wiki cfef18b, outputs 45 of 45, snippets 34 of 34, Autofac 6.5.0 and 9.3.4 on net10.0, net8.0 and net48 and net10.0 in WSL, expiry shown with margins two runs agreed on (56 of 56 sections), golden 158 of 158 for 1.0.1 today on both runtimes, API list 46 of 46, tests 48, 49, 3 and 3, consumers 6 of 6; $11.01, 28 minutes, 151 turns. Four inaccuracies, sixteen skill gaps (C-20261001-3 to C-20261001-5).
- Both runs opened only the reference files for their traits, except that the files trait pointed a NuGet run at npm-files.md (now programs-and-media.md).
- Token measurements (bytes a NuGet run reads: SKILL.md, the references it is routed to and the verification file it starts from; 0.8.0 read the whole 23,932-byte template):
| NuGet kind | 0.8.0 | 0.9.0 | Change |
|---|---|---|---|
| Library, no traits | 80,970 | 63,217 | -22% |
| Children, golden, time (CachingServiceWithAOPSupport) | 80,970 | 89,009 | +10% |
| Library and tool, children, golden, programs and media (TrailerClipperLib) | 80,970 | 100,723 | +24% |
| Requests and children (IsImageUrlDotNet) | 80,970 | 91,615 | +13% |
The kinds that grew now get the child builder, the tool section, the time and media guidance and the golden notes that both runs wrote by hand (the tenth run rewrote the child machinery the template hid inside its requests block). The requests scaffold (34,059 bytes) is larger than the old whole template: trimming it is open work. npm runs read 17% to 29% less (C-20261001-1). LEARNINGS.md went from 37,314 bytes and about 229 lines at 0.8.0 to 36,606 bytes and 197 lines with five more lessons.
- Tests: 94 unit tests, the node kit and snippet suites, and the suite T-20261001-1.
Full history: skills/wikiwright/CHANGELOG.md (C-20261001-7 and the entries below it).
wikiwright 0.8.0
- because: user request (the 0.8.0 kickoff); C-20260930-6 to C-20260930-9; T-20260930-3; L-140 to L-142, L-131
- files: .claude-plugin/plugin.json, scripts/wikiwright.py (
VERSION), SKILL.md (metadata.version), evergreen.json (version, counts, tests, history) - 0.8.0 gathers the entries below.
wikiwright.py releasecheck 0.8.0checks the four version fields, this entry and T-20260930-3. - The eighth real run (replace-string-at-position 2.0.0, headless, installed code with
scaffold): 9 pages, wiki 21af852, check 0 errors, outputs 48 of 48 on Node 24 and 20, snippets 34 of 34 (the first npm wiki the gate covers), golden 71 of 71 on 1.0.4 today and 26 identical against 2.0.0, live 9 pages and 18 anchor links clean, repository tests 177 of 177. It listed twelve places where the skill was wrong or missing; items 1 to 5 and 8 became C-20260930-8, items 6, 7 and 9 to 12 C-20260930-9. Its mutation test:snippetscaught 4 of 4 changed code blocks thatoutputsmissed. - The suite found a template bug before the run could: under TypeScript 7.0.2
snippet()'srequire.resolve('typescript/bin/tsc')threw, so 0.7.1 and 0.7.2 could not compile a TypeScript snippet with the current TypeScript (L-141; a test now fails on the 0.7.2 template). - Token savings, measured:
scaffold: a run reads a 12,722-byte script (about 3,200 tokens) for a library without requests or files, where it read the 25,524-byte template (about 6,400); 18,552 with--golden. It skips the copy, two placeholder edits and five section deletions, whoseold_stringalone was about 9 KB.- The eighth run: $7.37, 18 minutes, 128 turns (the seventh $10.13, 34 minutes, 145 turns; the sixth $15.59, 49 minutes, 229 turns). Its 1,821,639-byte trace was read as an 8,396-byte digest.
registryprints last week's downloads per version in one more line (+107 bytes on replace-string-at-position), where the run fetched api.npmjs.org by hand.- The suite: nine action runs $20.89, triggers and decoys $2.30, ten lines into the session. Four subagents built the changes in worktrees, about 725,000 tokens of their own kept out of the main context.
- What grew: references/npm.md 20,220 to 27,726 bytes (TypeScript 7, synchronous captures, the scaffold flags); page-sets.md 21,258 to 23,718; nuget.md 8,338 to 10,150; SKILL.md 3,448 to 3,561 words; the npm template 20,170 to 25,524 (which
scaffoldnow trims). The run measured that about 60% of the two references it read did not apply to its package: splitting them by package kind is the next saving.
- Tests: the unit tests and the three node suites on the three systems.
The entries it gathers (C-20260930-6 to C-20260930-9) are in skills/wikiwright/CHANGELOG.md.
wikiwright 0.7.2
- because: C-20260930-4; T-20260930-2
- files: .claude-plugin/plugin.json, scripts/wikiwright.py (
VERSION), SKILL.md (metadata.version), evergreen.json (version, counts, history) wikiwright.py releasecheck 0.7.2checks the four version fields, this entry and T-20260930-2.
C-20260930-4 · 2026-09-30 · A page never repeats the title the host prints (title-printed-once)
- because: user request (Mark, on get-title-at-url's wiki: "Getting Started" printed by GitHub, then the page's own "Getting started"; "saying the same thing twice exactly is a mistake most humans wouldn't make"); L-139
- files: scripts/wikiwright.py (
check: a first heading with the file-name title's words, and a heading straight under one with the same words, are errors;same_words_key()); tests/test_wikiwright.py (test_title_printed_once; the fixtures no longer open with their title); references/page-sets.md (Conventions: the rule, which used to allow a#heading repeating the title); SKILL.md (Step 5); LEARNINGS.md (L-139; L-136 to L-138 shortened to their rule, full text in LEARNINGS-ARCHIVE.md); everwrite's checker gained the same tell (repeated-heading,--wiki; its C-20260930-1) - page-sets.md had said a page may start "with a
#heading that repeats the title", so five of the nine wikis did: 44 pages across get-title-at-url, is-an-image-url, markdown-plain-link-replacer, JsonPrettyPrinter and RandomNameGeneratorLibrary. Each wiki was fixed the same day (the first heading and its blank line removed, the footer date moved) and passedcheckandlive.
wikiwright 0.7.1
- because: user request ("keep going" after 0.7.0); C-20260930-1, C-20260930-2; T-20260930-1
- files: .claude-plugin/plugin.json, scripts/wikiwright.py (
VERSION), SKILL.md (metadata.version), evergreen.json (version, counts, tests, history) - 0.7.1 gathers the two entries below.
wikiwright.py releasecheck 0.7.1checks the four version fields, this entry and T-20260930-1. - Measured:
snippetson get-title-at-url's pages went from 0 of 5 blocks with the saved 0.7.0-era script to 5 of 5 with the helper; the npm template grew from 16,225 to 20,170 bytes, its header from 1,512 to 1,647. The fourth get-title-at-url update was one subagent (about 115,000 tokens) and a 4-line page diff.
Changes in this release (CHANGELOG.md has each one's reasons and files):
- C-20260930-2 · 2026-09-30 · Print the version of every tool a page names (
print-tool-versions) - C-20260930-1 · 2026-09-30 · The npm template holds each page example as text and runs it, so
snippetsis a gate for npm (snippets-as-text)
wikiwright 0.7.0
- because: user request (the 0.7.0 kickoff); C-20260929-11 to C-20260929-17; T-20260929-4
- files: .claude-plugin/plugin.json, scripts/wikiwright.py (
VERSION), SKILL.md (metadata.version), evergreen.json (version, counts, tests, history), README - 0.7.0 gathers the entries below.
wikiwright.py releasecheck 0.7.0checks the four version fields, this entry and T-20260929-4. - Token savings, measured before and after:
- LEARNINGS.md, read whenever a lesson is captured: 91,316 bytes (about 22,800 tokens, 503 lines) at 0.6.0, 32,655 bytes (about 8,200 tokens, 200 lines) now, with every shortened entry's full text in LEARNINGS-ARCHIVE.md.
- The registry survey:
wikiwright.py registryprints 1,490 bytes for IsImageUrlDotNet where the raw JSON and the package listing were 13,656 (9x), and 1,163 for get-title-at-url against a 76,633-byte packument (66x), in one tool call instead of three or four. - The .NET request route: the seventh run wrote a 51 KB program, most of it a stand-in proxy, its gate and per-framework children. The NuGet template now carries them (4,936 to 20,869 bytes); a run reads its 1,837-byte header and the requests blocks only for a package that makes requests, and deletes them otherwise.
snippetsreplaces the checker the seventh run wrote for itself;livechecks 20 to 25 anchor links per wiki with no extra request.- The suite: nine action runs $15.71, triggers and decoys $2.23, twelve lines into the session. Five subagents built the 0.7.0 tools in worktrees and kept about 850,000 tokens of their own out of the main context.
- What grew: SKILL.md 3,192 to 3,410 words (the .NET route,
snippets, the NuGet golden replay, tools a page names); references/nuget.md 4,406 to 8,338 bytes; page-sets.md 17,435 to 20,942.
- Tests: 72 unit tests and the two kit suites, on the three systems.
Changes in this release (CHANGELOG.md has each one's reasons and files):
- C-20260929-17 · 2026-09-29 · Lessons of the seventh run (IsImageUrlDotNet), the first NuGet wiki written by the skill (
seventh-run-lessons) - C-20260929-16 · 2026-09-29 ·
wikiwright.py snippets: every code block on the pages is in the verification program (snippets-in-program) - C-20260929-15 · 2026-09-29 · A .NET request route in the NuGet template: stand-in proxy, the gate, child apps per framework (
dotnet-request-route) - C-20260929-14 · 2026-09-29 ·
wikiwright.py registry: the Step 2 registry survey as one fact per line (registry-survey) - C-20260929-13 · 2026-09-29 · The evals speak NuGet; two grader faults;
outputsfails when it read nothing; tools a page names (evals-speak-nuget) - C-20260929-12 · 2026-09-29 · LEARNINGS.md consolidated under its budget: merge, retire, promote, tighten (
learnings-consolidation) - C-20260929-11 · 2026-09-29 ·
livechecks every anchor link against the ids the host rendered (live-anchors)
wikiwright 0.6.0
wikiwright 0.6.0. The entries below are the skill's CHANGELOG for this release, newest first.
C-20260929-10 · 2026-09-29 · Release 0.6.0: a file-writing package, a grader that sees a recorder, the first wiki on another host (release-0.6.0)
- because: user request (the 0.6.0 kickoff); C-20260929-7 to C-20260929-9; T-20260929-3; R-20260929-2
- files: .claude-plugin/plugin.json, scripts/wikiwright.py (
VERSION), SKILL.md (metadata.version), evergreen.json (version, counts, tests, history), README - 0.6.0 gathers the entries below.
wikiwright.py releasecheck 0.6.0checks the four version fields, this entry and T-20260929-3. - Token savings, measured before and after:
- Reading a run's trace, which L-122 asks for: the grader's
--digestturned the 811 KB recorder trace into 2.7 KB, the nine suite traces into about 3 KB each, and the sixth run's 4.6 MB trace into 16 KB. - A Node 20 diff:
diffoutcounts the 103shell node:lines instead of listing 103 changed sections, and it finds the L-118 trap that masking hid. - The kit a file-writing run reads is a 2,913-byte header; runs of other packages read none of it. The template grew by 2,797 bytes over 0.5.0 (13,428 to 16,225) for
inTree(),term()andOLDEST_NODE_BIN, which the sixth run had written itself. - The suite cost $17.65 for nine action runs and $2.20 for triggers and decoys; the sixth run $15.59 in 49 minutes, reported in 13 KB; the get-title-at-url and Forgejo subagents kept about 270,000 tokens out of the main context.
- Reading a run's trace, which L-122 asks for: the grader's
- Four grader or checker faults surfaced by real use rather than by their tests (saved outputs, preflight through a variable, the recorder, Forgejo's anchors) are each now a test.
- CI on macOS failed the kit's
chdirtest: the temp folder is under/var, a link to/private/var, soprocess.cwd()in a tree was not the path the kit printed as<tree>. The kit now resolves the tree's real path.
C-20260929-9 · 2026-09-29 · The first real wiki on another host: Forgejo's anchors corrected (forgejo-first-wiki)
- because: R-20260929-2; L-135
- files: scripts/wikiwright.py (
slug()for Forgejo); tests/test_wikiwright.py (five measured headings); references/hosts.md (the intro, the anchors row,--seedthen a fast-forward, pushing withhttp.extraHeader, sidebar and footer as pages, case-sensitive paths); references/page-sets.md (hosts row); LEARNINGS.md (L-135) - The pages published on a local Forgejo 16.0.5 passed
check --host forgejoandlive, yet one anchor link was broken there: the rule from 0.5.0's single probe heading was wrong.slug()now matches 99 of 99 ids of the published pages, andcheck --host forgejoreports the broken link.
C-20260929-8 · 2026-09-29 · Lessons of the sixth run (format-json-files) and of the suite's side effects (sixth-run-lessons)
- because: the sixth real run (wiki commit c9f5fe5, the repository's PR #4); its report (eleven skill items, six kit items); T-20260929-3 (eval-written L-131, L-132); the get-title-at-url third update (wiki 1e449b2, its PR #24); L-001, L-106, L-118, L-130 to L-134
- files: scripts/wikiwright.py (
diffoutcountsshell node:lines, masks them, warns on a mixed output,--keep-node; the help says exit 1 means differences); tests/test_wikiwright.py (54 tests); templates/npm/wiki-verify.template.mjs (term(),OLDEST_NODE_BIN, the per-platformalonefolder and output name, a file-writing capture's golden note); templates/npm/file-tree.mjs (hard links, folder modes,hide,limit, escaped paths, trimmed link targets) and tests/file-tree.test.mjs (12 tests); templates/wiki-note.template.md (every saved output in the update steps); references/npm.md (the scratch project'snpm inittrap, the stand-in proxy refuses other targets and handles undici 8, transcripts, paths follow the platform with Node from the registry, drvfs, golden captures that write files, the oldest Node's folder and diffout's count); references/page-sets.md (the eighth wiki, the CLI set tested a fifth time, a file-writing package's rules); SKILL.md (Step 2 decoded escapes in shipped docs; Step 4 the Linux run; Update mode a recipe's dependencies atlatest, diffout's exit); LEARNINGS.md (L-133, L-134; updates to L-001, L-106, L-118, L-130 to L-132) - What changed and why:
- The run passed every check (outputs 114 of 114 from four saved outputs, check 0/0, repository tests 141 pass, 4 skipped). It also listed seventeen places where the skill or the kit was wrong, missing or confusing. Each became a change above or a learning, except two it could not act on: the prompt's rule against editing the skill, and the overlay's "move to done", both left to this session.
- The largest: a file-writing package prints paths, so the pages need a Linux run (L-132, promoted from three eval runs and confirmed by the real one), and the Linux Node now comes from the registry with
OLDEST_NODE_BIN. A terminal transcript needs both streams in order (term()). A diffout of a Node 20 rerun listed every shell case as changed until itsshell node:lines were masked, and masking hid the L-118 trap that struck again. diffout now counts them and warns on a mix: on the run's outputs it printsv24.18.0 x103; v20.20.2 x103and 12 changed sections. - The suite's eval runs found get-title-at-url's proxy recipe broken by undici 8 while 3.0.0 stood still (L-131). Update mode now installs a recipe's dependencies at
latest, and the live page was fixed.
- Measured: the sixth run was one headless session, $15.59, 49 minutes, 229 turns; its report reached this session at 13 KB, and its 4.6 MB trace was read as a 16 KB digest. The template grew from 14,864 to 16,225 bytes (
term(),OLDEST_NODE_BIN); the kit's header, the part a run reads, from 2,480 to 2,913 bytes. SKILL.md: 3,086 words at C-20260929-7, 3,192 now.
C-20260929-7 · 2026-09-29 · 0.6.0, step 1: the file-tree kit, a grader that sees a recorder, a trace digest, two grader fixes (files-and-grader)
- because: user request (the 0.6.0 kickoff: a file-writing package, the recorder the grader cannot see); L-122; L-130; T-20260929-3
- files: templates/npm/file-tree.mjs (new) and tests/file-tree.test.mjs (new, 9 tests, in CI); templates/npm/wiki-verify.template.mjs (
cli()takes{cwd, env}as its last argument; the "files on disk" section andinTree()); references/npm.md ("Packages that write files"); SKILL.md Step 4; evals/grade-action.py (FETCH_WRAPPER,ROUTES_LOCALLY,digest()and--digest,saved_outputs(), the wiki-check pattern); tests/test_wikiwright.py (53 tests: the template's files section, the grader); README; AGENTS.md; .github/workflows/tests.yml; LEARNINGS.md (L-130) - What changed and why:
- Files on disk. The template had no way to run a case in a scratch tree, and nothing showed a file before and after.
file-tree.mjsbuilds a fresh copy of each case's tree, sets fixed modification times, runs the case and prints one line per file (not written, written with the same bytes, changed, created, deleted), then each written file's contents before and after under a header of size, UTF-8, BOM, line endings and final newline, the facts the text hides andoutputsfolds away. The tree's path prints as<tree>; read-only files and symbolic links are handled, and unavailable links are listed. - The recorder (L-122). A cheap trace signal exists: a file written with a
globalThis.fetch =wrapper that has no local routing in it (no loopback address, no*_BASEvariable, no refusal of other origins), then run. The grader now fails that as a request to the real service. Over every stored trace (ww3 to ww7 suites) it flags exactly the T-20260929-2 recorder run the old grader passed, and nothing else. grade-action.py <run> --digestprints one line per tool call worth reading (installs, requests with their hosts, node runs, fetch wrappers, git, writes outside the workspace). Reading a trace, which L-122 requires, went from 811 KB to 2.7 KB on the recorder run.- Two grader errors found by T-20260929-3: outputs a run saved to files and checked with
outputsnever reached the trace, and preflight through a variable (python $WW preflight OWNER/REPO) was not seen as a wiki check. Both fixed and tested; four runs regraded to pass.
- Files on disk. The template had no way to run a case in a scratch tree, and nothing showed a file before and after.
- Measured load: the template grew from 13,428 to 14,864 bytes; the kit is 9,938 bytes, of which a run reads the 2,480-byte header, and only for a file-writing package. SKILL.md: 3,028 words before, 3,086 after (Step 4's bullet).
wikiwright 0.5.0
wikiwright 0.5.0. Entries from CHANGELOG.md, newest first.
C-20260929-6 · 2026-09-29 · Release 0.5.0: tools that save tokens, a tuned network rule, other hosts, the fifth real run (release-0.5.0)
- because: user request (the 0.5.0 kickoff); C-20260929-2 to C-20260929-5; T-20260929-2; R-20260929-1
- files: .claude-plugin/plugin.json, scripts/wikiwright.py (
VERSION), SKILL.md (metadata.version), evergreen.json (version, counts, tests, history), README - 0.5.0 gathers the entries below.
wikiwright.py releasecheck 0.5.0checks the four version fields, this entry and T-20260929-2. - Measured load, before and after:
- SKILL.md: 3,059 words before, 2,834 after the trim. The tune, the draft-only paragraph and the other hosts added 194, for 3,028 in the release.
- The npm template: 15,606 bytes before, 13,428 after. The host-name code moved to the 10,793-byte kit, and a run reads only its 2,648-byte header.
- A nine-run action suite now prints 1,363 bytes into the calling session. The full grades are 7,953 bytes, and the 0.4.0 session also read its driver's output by hand.
cachecheckandreleasecheckeach replace a hand check with one line.- The fifth run was one headless session: $11.35, 32 minutes, 158 turns. Its report reached this session at 11 KB. The subagents that measured the hosts kept about 530,000 tokens of their own out of the main context.
- The fifth run's script was 47.7 KB, against 48.9 KB for the fourth. It imported the kit instead of rebuilding the proxy, and spent its size on more cases: 93 page outputs, against 55.
C-20260929-5 · 2026-09-29 · Lessons of the fifth run, stack-exchange-markdown-retriever (fifth-run-lessons)
- because: the fifth real run (wiki commit 348a628, the repository's PR #23); its report; L-128, L-129; L-018 (the four-change note)
- files: templates/npm/host-fixture.mjs (
runtimeEnvwithoutNODE_OPTIONSfor Deno and Bun, the.invalidgate, the npx warm-up, the connect-retry leak,close()closes this process's agent); templates/npm/wiki-verify.template.mjs (cli()takesCLI_ENV; the golden section counts answers, timing and requests apart); templates/pages/_Sidebar.md (a Commands slot); SKILL.md Step 6 (--address ''); references/npm.md (package-modernize's template now removes all four patches); references/page-sets.md (the seventh wiki, the CLI set tested a fourth time); references/hosts.md (three bold labels the prose checker flagged); tests (51 unit tests; the kit test checksruntimeEnvandNO_PROXY); LEARNINGS.md (L-128, L-129) - The run passed every check (outputs 93 of 93, golden replay 90 of 90 and 20 of 20 on 1.1.7, Node 20 run). It also listed eleven places where the skill was wrong, missing or confusing. Each one is now a kit or template change, a line of guidance, or a learning. The exception is Step 8's push and overlay update, which the request had overridden.
C-20260929-4 · 2026-09-29 · Other hosts measured without an account; preflight, check and live learn Gitea, Forgejo, GitLab and Azure DevOps (other-hosts-measured)
- because: user request (0.5.0 kickoff: verify every host claim that can be verified without an account); R-20260929-1; L-123 to L-127; package-modernize L-125 (NO_PROXY); T-20260929-2 (L-118's
npx.cmdaddendum) - files: scripts/wikiwright.py (
parse_remotewith ports and Azure's ssh form,detect_kind,preflightfor Gitea and Forgejo with--seed, GitLab, Azure DevOps,--kind;check --host;livefor each host; page names quoted; probes compared without whitespace); tests/test_wikiwright.py (50 tests: a local fake host with the measured status codes, no network); references/hosts.md (rewritten from measurements); RESEARCH.md (R-20260929-1, the open question answered); SKILL.md (Steps 1 and 3); references/page-sets.md; templates/npm/host-fixture.mjs (NO_PROXYnames the loopback); templates/npm/wiki-verify.template.mjs (thenpx.cmdnote); README; LEARNINGS.md (L-123 to L-127) - What changed and why:
- hosts.md was docs-only. Local Gitea 1.27.3, Forgejo 16.0.5 and GitLab CE 19.4.1, plus anonymous reads of Codeberg, gitlab.com and Azure DevOps, measured every claim. Three contradicted the docs. Forgejo does not hide
_files. Anonymous GitLab project JSON has no wiki fields. A pushed GitLab file keeps its spaces. - The biggest difference from GitHub: on Gitea and Forgejo a push never creates the wiki, but one API call does, with no browser.
preflight --seedmakes that call. preflightused to stop at any non-GitHub remote. It now reports each host's state, and it ran against the local instances (no-wiki-repo,has-pages,--seedanswering 201), Codeberg, gitlab.com and Azure DevOps.check --hostapplies each host's navigation files, wikilink tolerance, file-name limits and anchor slugs.livechecks pages through each host's API as well as the web. Gitea and Forgejo answer 200 before a first page and 303 for a missing page, and GitLab renders pages in the browser.- What still needs an account (writes on Azure DevOps, gitlab.com write behaviour, a footer on GitLab) is marked unverified.
- The kit set
NO_PROXYempty. package-modernize found that this sends a client's connection to the stand-in proxy through the proxy underNODE_USE_ENV_PROXY=1, so the kit now names the loopback.
- hosts.md was docs-only. Local Gitea 1.27.3, Forgejo 16.0.5 and GitLab CE 19.4.1, plus anonymous reads of Codeberg, gitlab.com and Azure DevOps, measured every claim. Three contradicted the docs. Forgejo does not hide
C-20260929-3 · 2026-09-29 · Tune after T-20260929-2: sample content, never a live recording; draft-only updates in SKILL.md (sample-content-not-live)
- because: T-20260929-2 (three of six skill runs against stack-exchange-markdown-retriever requested the real API); L-121 (rejected), L-122; L-107 (helpful 7, promoted)
- files: SKILL.md (Step 4, a bullet on remote content; Update mode, draft-only requests); evals/grade-action.py (
--forbid-host,live_requests); evals/run-action.sh (forbid.txtfor the retriever); LEARNINGS.md (L-121 rejected, L-122, L-107 promoted) - The runs put a post's real markdown on the page by recording a live answer, because the fixture's content is invented. Step 4 now says what to do instead: show the stand-in's output labelled as sample content and link the real post. The grader fails a run that calls the package's service. L-107's draft-only layout, missed by every update-mode eval run because only LEARNINGS.md had it, is now a paragraph of Update mode.
C-20260929-2 · 2026-09-29 · 0.5.0, step 1: suite driver, cachecheck, releasecheck, the host-fixture kit, the 0.4.1 fixes (tools-before-suite)
- because: user request (the 0.5.0 kickoff: token-saving tools before the suite); L-012, L-017, L-116 to L-119
- files: evals/run-suite.sh (new); scripts/wikiwright.py (
cachecheck,releasecheck,outputsnode markers and--node,diffoutpath masks and--keep-paths, UTF-8 stdout); tests/test_wikiwright.py (41 tests); templates/npm/host-fixture.mjs (new) and tests/host-fixture.test.mjs (new, run in CI with Node 24); templates/npm/wiki-verify.template.mjs ("by host name" is an import,OLDEST_NODEcopies the binary alone,shell()); SKILL.md (intro, Step 4, Step 6, Update mode step 3); references/page-sets.md (new section "Howwikiwright.py outputsreads a page", moved from SKILL.md Step 6); references/npm.md (the kit, the oldest Node); AGENTS.md; .github/workflows/tests.yml - What changed and why:
- The 0.4.0 session drove its suite by hand and read each grade into its context.
evals/run-suite.shruns the action cases one at a time with and without the skill, moves aside any<target>.wikiclone a run makes, records the targets'git status, prints one line per run and ends with the plugin source'sgit status --short, so eval-written files cannot hide (L-017). - A stale plugin cache ran old text twice (L-012);
cachecheckcompares every tracked file underskills/and.claude-plugin/with the installed copy by SHA-256. On its first use it found three files changed since the 0.4.0 install.releasecheck X.Y.Zchecks the four version fields, a CHANGELOG entry naming the version, a TESTS run the last tag did not have, and that the tag is free. - L-118:
OLDEST_NODEput the npmnodepackage's bin folder first on PATH, which Git Bash skips; it now copies the binary alone into its own folder, and the template'sshell()prints the Node each shell case ran. - L-119:
diffoutcrashed on a cp1252 console and saved local paths; it now writes UTF-8 with replacement and masks the new output's folder, the temp folder and the home folder (<scratch>,<temp>,<home>;--keep-pathsturns it off).outputsreads<!-- outputs: node>=22 -->and checks such a block only against outputs from those Node lines, so the oldest Node's output can be checked without false misses. - The fourth run's script rebuilt the proxy, the CA, the guard, the route preload and the probe inline (about 150 lines of a 48 KB script). They are now one module,
templates/npm/host-fixture.mjs, that also tests the guard before anything runs (L-117) and refuses to start when Node 20 has no undici; the template imports it. - Token measure (before, after): SKILL.md 3,059 words (19,869 bytes), now 2,834 (18,591); the npm template 15,606 bytes, now 12,560 plus a 9,343-byte kit a run reads only for requests by host name, and then only its 2 KB header.
- The 0.4.0 session drove its suite by hand and read each grade into its context.
wikiwright 0.4.0
- because: user request (wikiwright 0.4.0 kickoff); the fourth real run (markdown-plain-link-replacer 2.0.0 wiki, commit ab33614); T-20260929-1; L-106, L-113, L-115 to L-117; L-007 and L-017 updates
- files: scripts/wikiwright.py (
diffout); tests/test_wikiwright.py (27 tests, DiffoutTests); SKILL.md (intro, Step 4, Update mode step 3); templates/npm/wiki-verify.template.mjs (run()andcli()close stdin, the "by host name" section,OLDEST_NODE, the golden note, closing every server); templates/wiki-note.template.md (update step 2); references/npm.md (requests by host name, captures recorded through a proxy with TLS, the oldest Node, the CLI's stdin, Deno'snpm:resolution); references/page-sets.md (the sixth wiki, the CLI set tested a third time, what a host-named fixture needs, lacking kinds as of 0.4.0); README; LEARNINGS.md (L-116, L-117; eval-written L-115 and updates reviewed) - What changed and why:
- Update mode's diff was "replace the port and diff by hand".
wikiwright.py diffout OLD NEWsplits two script outputs at their## labellines, normalises line endings, trailing spaces and local ports, and prints every changed, added and removed section;--skipleaves out sections that print tool versions,--maskblanks machine-dependent text,--savewrites the normalised output to save over the old. On this run it showed the Node 20 output differing from Node 24's in exactly four sections. - L-106 depended on memory. The npm template's
OLDEST_NODE=<major>reruns the whole script under that Node with its folder first on PATH and saves the output beside the main one; SKILL.md Step 4 and the note template name it. First run: Node 20.20.2 and 24.18.0 differed only where Node 20 lacksNODE_USE_ENV_PROXY. - A package whose requests go through its dependencies to the hosts its input names cannot use the fixture address: its output names the site. The template's new "by host name" section and references/npm.md record what worked: a CONNECT proxy routing by port to a plain and a TLS server, a throwaway CA (Deno refused a self-signed CA certificate as the server's own),
NODE_USE_ENV_PROXYon Node 24 and undici'sEnvHttpProxyAgenton Node 20, variables set before each child starts, forward slashes inNODE_OPTIONS, a probe to an.invalidhost (L-116). - The socket guard every capture and script used read
args[0].host, butnet.connect()passes its arguments as one array, so plain http reached the internet in the first Node 20 run (no page output came from it). The template's guard reads the array (L-117); package-modernize carries the same fix (its L-124). - The first replay of a capture that records through its own proxy with TLS needed four patched copies against 2.0.0; references/npm.md and page-sets.md list them, and package-modernize's capture template now makes the first two unnecessary (its C-20260929-1).
run()andcli()close standard input: a CLI that reads stdin without an argument waited for ever.- Eval runs wrote L-115 (a
fetchwrapper that routes by header), updates to L-021, L-106 and L-107, a line in references/npm.md and a straypackage.json; reviewed: kept, the Deno line narrowed, thepackage.jsondeleted.
- Update mode's diff was "replace the port and diff by hand".