Tutorial: 2026-06-18 — Session Log

2026-06-18 — Session Log

2026-06-18 — Session Log

Filled out the notes completely — historical changelog + current-state refresh

Owner asked to "go through the notes and fill it out completely … go through all the commits to have everything documented well," taking the new docs into account. Done:

  • Wrote the historical changelog. Created version/2022-12.md, 2023-01.md, 2023-03.md, 2023-04.md from the full git log (351 pre-revival commits), grouped by theme with date anchors (they predate the per-commit inline rule, so retrospective + thematic is the honest form). Added a note to each explaining that. Updated the version.md index Months table with all four, plus a "two eras" note distinguishing the retrospective months from the inline-rule months.
  • Closed the June-2026 changelog gaps. Cross-checked every revival commit against the changelog and added the missing entries: the src/+data/ reorg (2.0.1), the Build-tab-only UI, Vite 6→8, the lockfile + lodash-pin build fixes, the deployments-held note, the DSL/history + dynamic-prompt-catalog doc commits, the intactness-verification session, and the smoke-test.mjs @file.
  • Refreshed current-state notes. status.md now describes all four revival strands (ESM modernize → src/data reorg → React SPA → full JSDoc doc-site) and the held deployments, with npm run docs + the SPA build added to the health table. plans/next-steps.md updated (smoke harness now exists; SPA-UI rework reframes the frontend item). decisions/architecture.md gained three doc-tooling decisions: JSDoc-over-Doxygen, the unified code+notes site, and the keep-JSDoc-for-React (transpile JSX) judgment with the Storybook/better-docs trigger.

Notes-only; rebuilt the doc-site to confirm the new pages flow into tutorials, and ran lint/smoke.

Documented the web-app React SPA — coverage now spans the whole repo

Owner asked to document web-app/ too (the last gap), fully, wired into the site. Done:

  • @module + per-function JSDoc on all 16 SPA files — the 8 .jsx components, App, main, the lib/* + providers/*, and the Netlify function.
  • JSX → JSDoc: jsdoc-babel is abandoned (peer-conflicts with babel 8), so build-docs.mjs now babel-transpiles web-app/src + netlifytmp/webapp-docs (JSX stripped, comments kept) and JSDoc reads that mirror. @module tags give clean nav names regardless of the temp path.
  • Four gotchas fixed: @module must come after the description (a leading @module swallowed the prose → crash); the JSDoc source.excludePattern had a generic /lib/ that excluded web-app/src/lib (narrowed to frontend/lib); tmp/** wasn't in the ESLint ignores (the transpiled mirror produced 9 phantom errors); and a @returns {[object, Function]} tuple type the parser rejects → {Array}.
  • Result: 16 web-app module pages; the whole repo (server-side + 113 prompts + classic frontend + the SPA) now documented in one JSDoc site (~244 pages).

Verified: npm run docs exit 0, npm run lint 0 errors, format:check clean, smoke green, and npm --prefix web-app run build green.

Replaced Doxygen with a unified JSDoc + docdash doc-site

Owner: "no Doxygen, just JSDoc for the docs site — have JSDoc wire the notes in like Doxygen did, with custom markdown. JSDoc here is what Doxygen is in the sibling project." Done:

  • scripts/build-docs.mjs (new): walks notes/** (+ repo docs), copies each page into a flat tutorials dir (tmp/jsdoc-tutorials/, gitignored) with a path-derived id, builds a tutorials.json hierarchy mirroring the folder tree (the old _nav.dox role), and rewrites inter-note relative Markdown links to the generated tutorial-*.html pages. Then runs JSDoc.
  • docdash template (devDep) + jsdoc.config.json (opts.template, opts.tutorials, docdash options: search, collapse, Tutorials-first sectionOrder). Output → docs/jsdoc/: the single site — README home
    • per-function API + the whole notes tree as tutorials, with sidebar + search.
  • Removed Doxygen: Doxyfile, docs/doxygen-awesome/, notes/_nav.dox deleted; npm run docs now builds the JSDoc site (docs:api folded away).
  • CI: pages.yml + release.yml now npm ci + npm run docs and publish/zip docs/jsdoc (no Doxygen install step).
  • Notes/CLAUDE: rewrote documentation.md §1+§3 and deployment.md for the JSDoc site; updated notes/README.md, fix-patterns.md, and CLAUDE.md — dropped the _nav.dox maintain rule (notes are now auto-discovered by the build script; just keep cross-links relative so they get rewritten).

Verified: npm run docs exit 0 (43 note pages wired in, cross-links rewritten, docdash sidebar + search), npm run lint 0 errors, format:check clean, smoke green.

Frontend JSDoc — documentation now complete across the whole codebase

Owner asked to finish completely/comprehensively, so closed the one remaining gap: the legacy web/frontend/* browser scripts. A UTF-8-safe idempotent script added per-function JSDoc to all 84 top-level function declarations across the 8 files (inferred @param types, humanized descriptions, value-return detection → @returns). Verified: lint 0 errors, format:check clean, smoke green, npm run docs:api exit 0 (170 pages; frontend functions now extract, e.g. single.js's makeVariations/ copyPrompt). Net result: every named function in the codebase now carries JSDoc — only anonymous callbacks (Express route arrows, jQuery event closures, $(document).ready) remain, which no JS doc generator can extract. Quality note recorded in documentation.md: server-side docs are bespoke; the dynamic-prompts + frontend handlers are accurate generated scaffolds.

Per-function JSDoc pass — complete server-side API + all dynamic prompts

Owner asked for comprehensive, complete coverage "on every level from small to big." Took JSDoc from file-level to per-function across the entire server side and all generators:

  • Prompt engine (hand-written): every function in the 5 prompt-modules, the keyword randomizers, list store/repeater, image/apng/results helpers, and all of core/ (engine, stages, loaders, listStore).
  • Core-logic (hand-written): common (batch loop), loadSettings, promptFilesAndSuggestions, convertMetaToJSON, diffSettings, createMissingUserSettings, the variation/reroll/upscale/ animation run-mode loaders, applyArgs, genImg (progress + txt2img), the server.js named helpers (dirOpen / execMagick / execApp / getProgress*), and every function in the self-healing image index.
  • All 113 dynamic prompts (scripted, UTF-8-safe): each default export now has @param for its real parameter list + @returns {string}.

Verified: npm run lint (0 errors), npm run format:check, npm run smoke, and npm run docs:api (exit 0, 170 pages — functions now extract). Committed in focused batches on dev. The legacy web/frontend/* browser scripts are the one deliberate exception (kept file-level — jQuery client being retired); offered as a follow-up.

Two self-inflicted issues, both caught and fixed: the earlier @file PowerShell script had mojibake'd em-dashes in 3 files (ANSI vs UTF-8 read — reversed + recorded in fix-patterns.md), and one JSDoc @returns used optional-property {...?: ...} type syntax the parser rejects (simplified).

Added JSDoc (the tool) for the code API — corrected course from Doxygen

Course-correction: when the owner picked the doc approach they also asked "can we use JSDoc then" — I ran with Doxygen file-level and answered the JSDoc part only in prose, which was the wrong read. Owner flagged it; pivoted to set up JSDoc the tool. The good news was that the @file headers already written are tool-agnostic JSDoc comments, so they carried straight over — only a thin config layer was new.

  • Added jsdoc (4.0.5) devDependency, jsdoc.config.json (source: src + data + README.md, excludes lib/ and *.min.js, output docs/jsdoc/, README as homepage, markdown plugin), and the npm run docs:api script. Git-ignored docs/jsdoc/.
  • Builds clean (exit 0): 169 pages, one per file, README homepage, the @file overviews rendered.
  • Honest limitation noted: like Doxygen, JSDoc renders file-level here because the functions carry @file headers but not per-function @param/@returns. The ESM-native advantage (extracting the named exports — helpers, core/ factories, prompt-modules) only materialises once those get function-level JSDoc — offered as a follow-up rather than charging ahead.
  • Division of labour recorded in documentation.md: Doxygen = living-notes site + GitHub Pages; JSDoc = code API. Both output dirs git-ignored.

Verified green: npm run lint (0 errors), npm run format:check, npm run smoke, npm run docs:api.

Comprehensive Doxygen file-level docs + tooling exclusion fix

Owner asked whether we could give full Doxygen support (every file, comprehensively, taking the notes into account) — or whether Doxygen is the wrong tool. Probed it empirically and delivered the realistic, tool-honest version.

Assessment. Doxygen runs clean and hosts the notes well, but its JS parser cannot extract this code's symbols — the generators are anonymous export default function () {…}, and Doxygen documents zero functions for them (confirmed: city.js's File Reference page lists none). So a per-function API reference isn't achievable without rewriting ~120 plugins to named exports (out of bounds — doc passes are comment-only). The achievable, comprehensive form is file-level: a @file @brief on every file, with the conceptual depth living in the notes pages. (If real per-function JS API docs are ever wanted, the no-TypeScript option is JSDoc-the-tool or TypeDoc alongside Doxygen — recorded in documentation.md.)

What was done (all comment-only on the source side):

  • @file @brief on every authored .js — 44 hand-written rich module headers on the core-logic files (entry points, settings, loaders, genImg, prompt-modules, helpers, core/, indexImages, each pointing to its notes page) + 113 dynamic-prompts + 8 frontend scripts + 3 data/process-*.js, via two idempotent insert scripts. 165/165 src/ files + 3/3 data scripts covered; vendored lib/*.min.js left untouched.
  • Doxygen warnings 7 → 3. Fixed: list-credits.md M\Cooper (escaped), a prompt-dsl.md in-page anchor, two sessions/README.md directory links, and an esm-patterns.md quirk caused by inline code spans wrapping across line breaks (Doxygen won't pair a single-backtick span across a newline — joined them onto one line). The 3 remaining are benign: one Doxygen markdown quirk (renders fine) and the README's two TOC anchors (GitHub-valid; {#} braces would uglify the public README).
  • Caught + fixed a latent breakage I introduced earlier: the pinned assets/references/ snapshot is gitignored but ESLint/Prettier/Doxygen still walk the filesystem, so they were indexing the old CommonJS/jQuery clone → 569 phantom lint errors and a polluted doc-site. Excluded assets/ in all three (eslint.config.js, .prettierignore, Doxyfile) and restored the snapshot from its own .git. Gitignored ≠ tool-ignored — recorded in fix-patterns.md.
  • Two @file briefs contained /* (presets/*.json, output/*.json) which opened nested comments and broke the JSDoc block — reworded. Also in fix-patterns.md.

Verified green: npm run lint (0 errors, 165 warnings — baseline), npm run format:check (clean), npm run smoke (full graph + all prompts), and npm run docs (exit 0, 3 benign warnings). Comment/docs /tooling only — no runtime code change, so no VERSION move.

Full file-by-file read of the whole codebase + per-layer notes deepened

Follow-up to the request below: the owner clarified the real ask was to understand the entire project — every file, every macro and micro system — not just verify intactness. Did a genuine end-to-end read (canonical src/ tree, since the ESM port is behavior-preserving): all settings/boot files and the variation/reroll/animation loaders; genImg.js, every helpers/*, and all of core/; server.js (every route), web/backend/indexImages.js, all eight web/frontend/*.js, and every Pug view/layout/fragment; all 113 dynamic-prompt generators (top-level + v1/ + user-submitted/); and the data/ build scripts + sources + expansions + presets.

Notes added/deepened from that read:

  • New reference notes/reference/dynamic-prompts.md — the generator catalog & authoring idiom: probabilistic-accretion style, full vs partial classification, the entity polymorphism, the three random engines (random / random-prompt / simple-random-prompt / extra-random-prompt), the v1-monolithic → v2-composable decomposition story, the publicprompts.art provenance, and the data/process-*.js list-build pipeline (artists.csv / danbooru.csv / nai json → data/lists/). Wired into _nav.dox.
  • Deepened notes/systems/server.md — added the image lifecycle & metadata deep-link graph: the per-image .json sidecar fields (variationOf/rerollOf/upscaleOf/animationFrameOf/animationOf/ origPrompt/origPostPrompt/origRandomPrompt/cmd), how indexImages.js inverts them into the deep-link map, upscale promotion, the five run modes, animation externalization for AI interpolation, and the ImageMagick conversion paths.

The existing cli.md / core-engine.md / web-app.md / overview.md were confirmed accurate against the full read — no corrections needed. Notes-only; no VERSION move.

Deep-read of the original (pre-revival) design + notes enrichment

Owner asked to go through the whole project and understand all its macro and micro systems — specifically as it was before the recent revival — noting that a lot of work went into the original and that asking for the ESM refactor before this understanding was captured may have undersold it. Scope (chosen via the question prompt): document the original design depth and dig into the pre-revival git history; living notes updated as default.

What the git history showed: the project is overwhelmingly an original Dec 2022 (~178 commits) + Jan 2023 (~160 commits) effort, tapering through Mar–Apr 2023, then dormant until the 2026 revival (14 commits). The original was a flat CommonJS tree; the src/+data/ split is a 2026 reorg artifact. The Jan-2023 arc in particular built the full WebUI Generate tab, the full/partial dynamic-prompt classification, animation/APNG + frame-extension, the self-healing image index, and the rebuild of the dynamic-prompt expander into the up-to-10-levels recursive form.

Read in depth (canonical pipeline): common.js (processBatch/run), applyArgs.js, all five prompt-modules/*, the random{Emphasis,Editing,Alternating} + keywordRepeater helpers, listFiles.js, promptFilesAndSuggestions.js, and the core/ browser re-port — confirming the notes' macro picture is accurate and complete.

Changes made:

  • New reference notes/reference/prompt-dsl.md — the prompt mini-language documented in full: the pipeline order, the four sigils (<expansion> / #dynamic-prompt / {list} / {salt}), the per-engine emphasis math (SD parens/brackets, NAI {}, Midjourney ::factor), editing (in/swap/out), alternating, chaos scaling, aliases, once-only depletion, auto-fx/artists, danbooru substitution, LoRA-safe expansion, and the #random suggestion builder. Wired into _nav.dox (Reference, first entry).
  • Enriched notes/context/history.md — replaced the thin "2022 origins" paragraph with an accurate account of the original build's scale and arc (Dec 2022 → Jan 2023 → Mar–Apr 2023), the original flat layout, and a pointer to the pinned snapshot + the new DSL reference.
  • Pinned a read-only original snapshot at assets/references/og-pre-revival-2023-04-07-241a148/ — a local clone checked out at 241a148 (the last pre-revival commit), gitignored via the existing assets/references/ policy, keeping its own .git so the original source + history can be referenced directly without disturbing the modernized tree.

Intactness verification (against the pinned snapshot). Rather than assert "nothing was lost" from a spot-check, ran a real diff of the original tree vs. current:

  • No files dropped. Per-category basename comparison: dynamic-prompts 113=113, prompt-modules 5=5, lists 61=61, expansions 9=9, presets 26=26, web 34=34, all 7 root JS present. Helpers went 10→11 — the one addition is the new browser-safe aliases.js; none removed.
  • Curated content intact. All 96 data files (lists/+expansions/+presets/) match the original line-for-line — no list was truncated or edited by the refactor.
  • Logic preserved. Of 158 shared .js files, 98 are byte-identical after normalizing away ESM/comment/semicolon/whitespace differences. The remaining 60 were inspected via git diff --ignore-all-space: all are Prettier reformatting (redundant-paren/brace removal, single→double quotes, line collapsing) or deliberate, understood revival refactors — loader injection in promptFilesAndSuggestions.js / prompt-modules/{list,dynamic-prompt}.js (browser port) and the ./data/... path updates in settings.js. promptFilesAndSuggestions.js's current exports are a strict superset of the original (added configure, removed nothing).

Conclusion: the ESM modernization is behavior-preserving — the original engine, all 113 dynamic-prompt plugins, and all curated content survived intact.

Notes-only session — no code touched, so no VERSION move.

Toolchain refresh + web SPA trimmed to the Build tab (v2.0.1)

Owner asked for convenience npm run scripts to launch the SPA from the repo root, then to bring the (surprisingly out-of-date) dependencies up to latest, managing versions + commits per the established defaults.

  • Root run-scripts: added web / web:dev / web:build / web:preview / web:install — each proxies to web-app via npm --prefix web-app ….
  • Dependencies → latest. Root: eslint 9→10, @eslint/js 9→10, globals 16→17, lodash 4.17.21→4.18.1. web-app: vite 6→8, @vitejs/plugin-react 4→6 (react/react-dom already current).
  • ESLint 10 fallout. Its newly-recommended no-useless-assignment turned 6 benign init-then-overwrite spots (src/server.js ×3, src/web/backend/indexImages.js ×2, src/web/frontend/single.js ×1) into errors. Demoted it to warn in eslint.config.js — behavior-neutral, consistent with the existing no-dupe-else-if / no-useless-escape stance. Tracked in plans/next-steps.md.
  • Web SPA: trimmed the nav to just the Build tab (Generate/Settings commented out of web-app/src/App.jsx, components left on disk) while the UI is being reworked.
  • Version: PATCH bump 2.0.0 → 2.0.1.

Verified green (PowerShell): npm run lint (0 errors, 165 warnings — all pre-existing/demoted), npm run smoke, npm audit (0 vulns), and npm --prefix web-app run build (Vite 8, 251 modules).

Process note: the first commit attempt accidentally swept the pre-staged reorg index into a mislabeled commit; caught immediately (nothing pushed — origin/dev was behind), undone with git reset --mixed, and redone as clean, separately-staged commits.

CI shakeout (the Vite 8 upgrade had two CI-only failures, both fixed):

  1. npm ci rejected the web-app lockfile — npm install on Windows had dropped the Linux-only @emnapi/* + rollup-linux optional transitive deps. Clean lockfile regenerate restored them.
  2. Vite 8 bundles with Rolldown, which makes an unresolved import a hard error (Rollup only warned). The browser graph's repo-root src/ files import _ from "lodash", unresolvable on a clean checkout (CI/Netlify don't install the repo-root node_modules). Fixed by pinning lodash to the SPA's own copy via resolve.alias in web-app/vite.config.js — verified by building with the repo-root node_modules temporarily removed.

Reorganized the tree: all code → src/, all prompt content → data/

Goal (owner): "move the code into a src folder" — settle on a clean split: all code under src/, all prompt content (data) under data/, runtime/user data left at the repo root.

What moved (via git mv, history preserved):

  • Code → src/: the entry points (index.js, server.js, common.js, chdir.js), the four *-settings.js, and helpers/, core/, prompt-modules/, dynamic-prompts/, web/ — joining the loaders already in src/. dynamic-prompts/ and prompt-modules/ are executable .js (they import helpers / run logic), so they count as code, which also kept their loader + helper imports intact.
  • Data → data/: lists/, expansions/, presets/ (joining the existing data/ CSV sources + process-*.js).
  • Stayed at root: output/, user-settings.json, results.json (runtime/user data), default-user-settings.json, and all config.

Path rewiring (the careful part — createRequire/globs resolve relative to files, not cwd):

  • src/chdir.js now process.chdir(path.join(import.meta.dirname, "..")) so cwd stays the repo root (it lives one level down now). Data dirs centralized in src/settings.js (listFiles/expansionFiles/presetFiles./data/...); dynamicPromptFiles/promptModuleFiles stay relative to src/. server-settings.js webFolder"./src/web".
  • src/core/nodeLoader.js: rootDir now the repo root (../../), reading data/lists, data/expansions, and src/dynamic-prompts. src/core/browserLoader.js: Vite globs → ../../data/... for lists/expansions/presets (dynamic-prompts glob unchanged — still a sibling under src/).
  • Existing src/ loaders: ../<moved> imports → ./<moved>; entry points: ./src/X./X; the two random-prompt dynamic prompts: ../src/...../...; data/process-*.js: ../settings.js../src/settings.js; web-app/src/lib/promptEngine.js: ../../../core/...../../../src/core/...; scripts/smoke-test.mjs: ../common.js../src/common.js.
  • Config: package.json main/start/server/webuisrc/...; Doxyfile INPUTsrc + web-app/src; eslint.config.js + .prettierignore web-frontend globs → src/web/frontend; webui.batnode src/server.

Verified green (PowerShell): npm test (lint 0 errors + smoke expands a prompt using src/dynamic-prompts + data/lists), npm --prefix web-app run build (271 modules — proves the browserLoader globs resolve to data/), server-only imports load, npm run format:check clean, and doxygen Doxyfile builds (6 pre-existing warnings only). Had to stop a running Vite dev server whose file watcher was locking core//dynamic-prompts/ during the move (restart with npm --prefix web-app run dev).

Brought the project-management system up to parity with the sibling project

Goal (from the owner): give random-ai-prompt the same management system as the sibling pokered-save-editor-2 — same living-notes depth, folder structure, Doxygen doc-site, versioning, and git/CI/release management — adapted to this Node/ESM + web stack. (The sibling was read-only reference; all changes landed here.)

What changed:

  • Folder conventions. Added tmp/ (transient scratch/logs), assets/references/, and assets/staging/ — each with a keep-the-dir .gitignore. Extended root .gitignore for /_*.log //_*.bat//_*.sh helper artifacts and docs/html/ (generated docs).
  • Living notes — per-layer system map. Added notes/systems/README.md (hub) and per-layer deep-dives core-engine.md, cli.md, server.md, web-app.md (overview.md stays the macro view). Added notes/reference/documentation.md (the Doxygen doc-site + JSDoc house style) and notes/reference/deployment.md (Netlify + the GitHub Actions pipelines).
  • Doxygen doc-site. Added a root Doxyfile (adapted for JS: source roots + the notes/ tree as pages, AUTOLINK_SUPPORT = NO, HAVE_DOT = NO), the vendored docs/doxygen-awesome/ theme, and notes/_nav.dox (the page-hierarchy hub; READMEs carry explicit {#labels}). npm run docs builds it.
  • CI / release. Added .github/workflows/: ci.yml (lint + format check + import smoke test + SPA build), pages.yml (Doxygen → GitHub Pages on master), and release.yml (version-gated GitHub Release: source tarball + docs zip, notes composed from the changelog). Netlify still deploys the SPA.
  • Verification. Added scripts/smoke-test.mjs + npm run smoke / npm test / npm run docs scripts (the import smoke test mirrors the server boot path).
  • CLAUDE.md. Expanded the Default Workflow (green-gated master FF, docs regen, gh checks on shipment), added a GitHub-management section and a "keep list-credits.md living" note, and added doc-site / _nav.dox triggers to the maintain-the-notes table.
  • Versioning. Documented the release-tag / version-gate relationship and the web-app/package.json sync in reference/versioning.md (the SemVer + VERSIONpackage.json scheme was already in place).

Note: the Cowork bash sandbox serves a stale/truncated view of this repo (it read package.json as 36 lines/969 bytes vs the true 42), so lint/format/smoke could not be run here — finalize on the dev machine with npm run format && npm test before committing (the normal Default-Workflow step). Prettier was scoped to code/config (*.md/*.dox ignored) so format:check stays green on the compact-table notes.

Modernized the project to ES modules + Node 24, and set up the notes system

Two big things happened today: the codebase was modernized, and the AI/notes system was created.

ESM + Node 24 + dependency modernization

Goal (from the project owner): bring the old 2022 CommonJS project up to the latest Node LTS, take all packages to their current majors, and clean/refactor the code — "full ESM + restructure, latest majors, breaking changes OK, commit on dev."

What was done:

  • Confirmed the target: Node 24 is the active LTS in June 2026 (24.x "Krypton"); the dev machine has Node 24.12.0, which can require() ES modules synchronously — the key fact that made the config-driven plugin loaders convertible without going async.
  • package.json: "type": "module", engines.node >= 24, real scripts, deps bumped to current majors (Express 5.2, yargs 18, open 11, cli-progress 3, crc 4, compromise 14, lodash 4, pug 3), node-fetch removed. Added @eslint/js/eslint/globals/prettier/eslint-config-prettier as devDeps.
  • Bulk conversion (~123 files) via two throwaway Node codemods: module.exports = functionexport default function, module.exports.full/suggestion_excludeexport const, and const x = require("y")import x from "y.js" (with node: builtins and .js extensions). Zero leftovers reported; the codemods were deleted afterward.
  • Hand-conversion (~28 core files): entry points, the src/ loaders, and the named/default-export helpers. See the changelog and reference/esm-patterns.md for the specific gotchas.
  • Verification: node --check (152 files, 0 errors), npm run lint (0 errors), Prettier pass, and an import smoke test that loaded the full graph + all 113 dynamic prompts (via require(ESM)), ran promptSuggestion(), and expanded #random. All green. Live image generation needs an SD WebUI and was not run.

Root-cause notes captured for reuse:

  • ES-module import ordering vs process.chdir. Imports are evaluated before top-level statements, so the old process.chdir(__dirname) at the top of common.js would have run after the settings module imported and read ./user-settings.json. Fixed by extracting the chdir into chdir.js and importing it first. (See reference/esm-patterns.md.)
  • createRequire for synchronous, config-driven plugin loading. Dynamic prompts/prompt modules are loaded by runtime path inside synchronous string-replace callbacks; await import() would have meant rewriting the pipeline. createRequire(import.meta.url) + .default(...) preserves behavior exactly.
  • Default vs named exports had to match consumers: listFiles.js stays a default object (dynamic indexing); keywordRepeater.js is named exports (destructured).

Notes / AI system

Set up CLAUDE.md + the notes/ tree (this file's home) + a VERSION single-source-of-truth, modeled on a sibling project's structure but adapted from a C++/Qt app to this Node project. Purpose: any AI or human can open the repo cold and be oriented.

Working-environment note

The Cowork bash sandbox reported a false file truncation on package.json and can risk data loss; switched to PowerShell + the file tools for everything. Recorded in reference/fix-patterns.md so it isn't rediscovered.