Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
5.9 KiB
Hotfix Scratchpad — install.sh does not seed TOOLS.md
- Issue: install.sh does not seed TOOLS.md — breaks AGENTS.md mandatory load order (mosaicstack/stack#457)
- Branch:
fix/tools-md-seeding - Type: Out-of-mission hotfix (not part of Install UX v2 mission)
- Started: 2026-04-11
- Ships in:
@mosaicstack/mosaic0.0.30
Objective
Ensure ~/.config/mosaic/TOOLS.md is created on every supported install path so the mandatory AGENTS.md load order actually resolves. The load order lists TOOLS.md at position 5 but the bash installer never seeds it.
Root cause
packages/mosaic/framework/install.sh:228-236 — the post-sync "Seed defaults" loop explicitly lists AGENTS.md STANDARDS.md:
DEFAULTS_DIR="$TARGET_DIR/defaults"
if [[ -d "$DEFAULTS_DIR" ]]; then
for default_file in AGENTS.md STANDARDS.md; do # ← missing TOOLS.md
if [[ -f "$DEFAULTS_DIR/$default_file" ]] && [[ ! -f "$TARGET_DIR/$default_file" ]]; then
cp "$DEFAULTS_DIR/$default_file" "$TARGET_DIR/$default_file"
ok "Seeded $default_file from defaults"
fi
done
fi
TOOLS.md is listed in PRESERVE_PATHS (line 24) but never created in the first place. A fresh bootstrap install via tools/install.sh → framework/install.sh leaves ~/.config/mosaic/TOOLS.md absent, and the agent load order then points at a missing file.
Secondary: TypeScript syncFramework is too greedy
packages/mosaic/src/config/file-adapter.ts:133-160 — FileConfigAdapter.syncFramework correctly seeds TOOLS.md, but it does so by iterating every file in framework/defaults/:
for (const entry of readdirSync(defaultsDir)) {
const dest = join(this.mosaicHome, entry);
if (!existsSync(dest)) {
copyFileSync(join(defaultsDir, entry), dest);
}
}
framework/defaults/ contains:
AGENTS.md
AUDIT-2026-02-17-framework-consistency.md
README.md
SOUL.md ← hardcoded "Jarvis"
STANDARDS.md
TOOLS.md
USER.md
So on a fresh install the TS wizard would silently copy the Jarvis-flavored SOUL.md + placeholder USER.md + internal AUDIT-*.md and README.md into the user's mosaic home before mosaic init ever prompts them. That's a latent identity bug as well as a root-clutter bug — the wizard's own stages are responsible for generating SOUL.md/USER.md via templates.
Tertiary: stale TOOLS.md.template
packages/mosaic/framework/templates/TOOLS.md.template still references ~/.config/mosaic/rails/git/… and ~/.config/mosaic/rails/codex/…. The rails/ tree was renamed to tools/ in the v1→v2 migration (see run_migrations in install.sh, which removes the old rails/ symlink). Any user who does run mosaic init ends up with a TOOLS.md that points to paths that no longer exist.
Scope of this fix
packages/mosaic/framework/install.sh— extend the explicit seed list to includeTOOLS.md.packages/mosaic/src/config/file-adapter.ts— restrictsyncFrameworkdefaults-seeding to an explicit whitelist (AGENTS.md,STANDARDS.md,TOOLS.md) so the TS wizard never accidentally seedsSOUL.md/USER.md/README.md/AUDIT-*.mdinto the mosaic home.packages/mosaic/framework/templates/TOOLS.md.template— replacerails/withtools/in the wrapper-path examples (minimal surgical fix; full template modernization is out of scope for a 0.0.30 hotfix).- Regression test — unit test around
FileConfigAdapter.syncFrameworkthat runs against a tmpdir fixture asserting:TOOLS.mdis seeded when absentAGENTS.md/STANDARDS.mdare still seeded when absentSOUL.md/USER.mdare not seeded fromdefaults/(the wizard stages own those)- Existing root files are not clobbered.
Out of scope (tracked separately / future work):
- Regenerating
defaults/SOUL.mdanddefaults/USER.mdso they no longer contain Jarvis-specific content. - Fully modernizing
TOOLS.md.templateto match the rich canonicaldefaults/TOOLS.mdreference. issue-create.sh/pr-create.shevalbugs (already captured to OpenBrain from the prior hotfix).
Plan / checklist
- Branch
fix/tools-md-seedingfrommain(atb2cbf89) - File Gitea issue (direct API; wrappers broken for bodies with backticks)
- Scratchpad created (this file)
install.shseed loop extended toAGENTS.md STANDARDS.md TOOLS.mdfile-adapter.tsseeding restricted to explicit whitelistTOOLS.md.templaterails/→tools/- Regression test added (
file-adapter.test.ts) — failing first, then green pnpm --filter @mosaicstack/mosaic run typecheckgreenpnpm --filter @mosaicstack/mosaic run lintgreenpnpm --filter @mosaicstack/mosaic exec vitest run— new test green, no new failures beyond the known pre-existinguninstall.spec.ts:138- Repo baselines:
pnpm typecheck/pnpm lint/pnpm format:check - Independent code review (
feature-dev:code-reviewer, sonnet tier) - Commit + push
- PR opened via Gitea API
- CI queue guard cleared (bypass local
ci-queue-wait.shif stale origin URL breaks it; query Gitea API directly) - CI green on PR
- PR merged (squash)
- CI green on main
- Issue closed with link to merge commit
chore/release-mosaic-0.0.30branch bumpspackages/mosaic/package.json0.0.29 → 0.0.30- Release PR opened + merged
.woodpecker/publish.ymlauto-publishes to Gitea npm registry- Publish verified (
npm view @mosaicstack/mosaic versionor registry check)
Risks / blockers
ci-queue-wait.shwrapper may still crash on staleoriginURL (captured in OpenBrain from prior hotfix). Workaround: query Gitea API directly for running/queued pipelines.issue-create.sh/pr-create.shevalbugs. Workaround: Gitea API direct call.uninstall.spec.ts:138is a pre-existing failure on main; not this change's problem.- Publish flow is fire-and-forget on main push — if
publish.ymlfails, rollback means republishing a follow-up patch, not reverting the version bump.