Fixesmosaicstack/stack#457. ~/.config/mosaic/TOOLS.md was never created during a bootstrap install even though AGENTS.md declares it as mandatory reading at position 5 of the load order. A fresh 0.0.29 install left the file missing and the agent contract pointing at nothing.
Root cause
packages/mosaic/framework/install.sh lines 228-236 explicitly seed AGENTS.md STANDARDS.md from defaults/ — TOOLS.md was listed in PRESERVE_PATHS but never seeded in the first place.
While investigating I also found:
The TS wizard's FileConfigAdapter.syncFramework (packages/mosaic/src/config/file-adapter.ts) was iterating every file under framework/defaults/, which meant on a fresh install it would silently seed defaults/SOUL.md (hardcoded "Jarvis") and defaults/USER.md (placeholder) into the user's mosaic home before the wizard's own identity stages ran.
packages/mosaic/framework/templates/TOOLS.md.template still referenced ~/.config/mosaic/rails/git/... and ~/.config/mosaic/rails/codex/.... The rails/ tree was renamed to tools/ in the v1→v2 framework migration — so any user who did run mosaic init would end up with a TOOLS.md full of broken paths.
preservePaths drift: install.sh preserves 8 paths across upgrades; file-adapter.ts was only preserving 4. This has been masked in production because the framework source tree has no root-level contract files — but the two code paths should agree regardless.
Fix
packages/mosaic/framework/install.sh — extend the explicit defaults-seed loop from AGENTS.md STANDARDS.md to AGENTS.md STANDARDS.md TOOLS.md.
packages/mosaic/src/config/file-adapter.ts — replace the greedy readdirSync(defaultsDir) loop with an exported DEFAULT_SEED_FILES = ['AGENTS.md', 'STANDARDS.md', 'TOOLS.md'] whitelist. Align preservePaths with the bash PRESERVE_PATHS list so both install paths have the same upgrade-preservation semantics.
packages/mosaic/framework/templates/TOOLS.md.template — replace rails/ with tools/.
Tests
Adds packages/mosaic/src/config/file-adapter.test.ts (5 tests, all green):
Seeds the three framework-contract files on a fresh mosaic home.
Does NOT seed SOUL.md/USER.md from defaults/ — wizard stages own those.
Does NOT seed README.md / AUDIT-*.md (framework-internal).
Preserves existing user contract files under keep mode, including AGENTS.md — this test plants a root-level AGENTS.md in the fixture's sourceDir to actually exercise syncDirectory's preserve path, not just the seed loop.
No-op when defaults/ directory is absent.
Test plan
Unit tests added and green (5/5)
pnpm --filter @mosaicstack/mosaic run typecheck green
pnpm --filter @mosaicstack/mosaic run lint green
pnpm --filter @mosaicstack/mosaic exec vitest run → 275/276 pass (the one failure, src/commands/uninstall.spec.ts:138, is a pre-existing EACCES issue on main and is unrelated to this change)
Repo-wide pnpm typecheck / pnpm lint / pnpm format:check green
Live smoke of bash framework/install.sh against a tmp MOSAIC_HOME — prints "Seeded TOOLS.md from defaults" and the file lands
Independent code review (no blockers; one must-fix on test fixture incorporated before commit)
CI green on PR
Merged and verified on main
Affected version
Ships in @mosaicstack/mosaic 0.0.30.
## Summary
Fixes mosaicstack/stack#457. `~/.config/mosaic/TOOLS.md` was never created during a bootstrap install even though `AGENTS.md` declares it as mandatory reading at position 5 of the load order. A fresh 0.0.29 install left the file missing and the agent contract pointing at nothing.
## Root cause
`packages/mosaic/framework/install.sh` lines 228-236 explicitly seed `AGENTS.md STANDARDS.md` from `defaults/` — `TOOLS.md` was listed in `PRESERVE_PATHS` but never seeded in the first place.
While investigating I also found:
1. The TS wizard's `FileConfigAdapter.syncFramework` (packages/mosaic/src/config/file-adapter.ts) was iterating *every* file under `framework/defaults/`, which meant on a fresh install it would silently seed `defaults/SOUL.md` (hardcoded "Jarvis") and `defaults/USER.md` (placeholder) into the user's mosaic home before the wizard's own identity stages ran.
2. `packages/mosaic/framework/templates/TOOLS.md.template` still referenced `~/.config/mosaic/rails/git/...` and `~/.config/mosaic/rails/codex/...`. The `rails/` tree was renamed to `tools/` in the v1→v2 framework migration — so any user who did run `mosaic init` would end up with a `TOOLS.md` full of broken paths.
3. `preservePaths` drift: `install.sh` preserves 8 paths across upgrades; `file-adapter.ts` was only preserving 4. This has been masked in production because the framework source tree has no root-level contract files — but the two code paths should agree regardless.
## Fix
- `packages/mosaic/framework/install.sh` — extend the explicit defaults-seed loop from `AGENTS.md STANDARDS.md` to `AGENTS.md STANDARDS.md TOOLS.md`.
- `packages/mosaic/src/config/file-adapter.ts` — replace the greedy `readdirSync(defaultsDir)` loop with an exported `DEFAULT_SEED_FILES = ['AGENTS.md', 'STANDARDS.md', 'TOOLS.md']` whitelist. Align `preservePaths` with the bash `PRESERVE_PATHS` list so both install paths have the same upgrade-preservation semantics.
- `packages/mosaic/framework/templates/TOOLS.md.template` — replace `rails/` with `tools/`.
## Tests
Adds `packages/mosaic/src/config/file-adapter.test.ts` (5 tests, all green):
- Seeds the three framework-contract files on a fresh mosaic home.
- Does NOT seed `SOUL.md`/`USER.md` from `defaults/` — wizard stages own those.
- Does NOT seed `README.md` / `AUDIT-*.md` (framework-internal).
- Preserves existing user contract files under `keep` mode, including `AGENTS.md` — this test plants a root-level `AGENTS.md` in the fixture's `sourceDir` to actually exercise `syncDirectory`'s preserve path, not just the seed loop.
- No-op when `defaults/` directory is absent.
## Test plan
- [x] Unit tests added and green (5/5)
- [x] `pnpm --filter @mosaicstack/mosaic run typecheck` green
- [x] `pnpm --filter @mosaicstack/mosaic run lint` green
- [x] `pnpm --filter @mosaicstack/mosaic exec vitest run` → 275/276 pass (the one failure, `src/commands/uninstall.spec.ts:138`, is a pre-existing EACCES issue on main and is unrelated to this change)
- [x] Repo-wide `pnpm typecheck` / `pnpm lint` / `pnpm format:check` green
- [x] Live smoke of `bash framework/install.sh` against a tmp MOSAIC_HOME — prints "Seeded TOOLS.md from defaults" and the file lands
- [x] Independent code review (no blockers; one must-fix on test fixture incorporated before commit)
- [ ] CI green on PR
- [ ] Merged and verified on main
## Affected version
Ships in `@mosaicstack/mosaic` 0.0.30.
Closes#457.
The bash framework installer only seeded AGENTS.md and STANDARDS.md from
defaults/, even though TOOLS.md is listed in PRESERVE_PATHS and AGENTS.md
declares it as mandatory reading at position 5 of the load order. A fresh
bootstrap install therefore left ~/.config/mosaic/TOOLS.md missing and the
agent contract pointing at a non-existent file.
Fixes:
- packages/mosaic/framework/install.sh — extend the explicit defaults-seed
loop from "AGENTS.md STANDARDS.md" to "AGENTS.md STANDARDS.md TOOLS.md".
- packages/mosaic/src/config/file-adapter.ts — replace the greedy
readdirSync loop in syncFramework with an exported DEFAULT_SEED_FILES
whitelist, so the TS wizard no longer silently seeds the Jarvis-flavored
defaults/SOUL.md, placeholder defaults/USER.md, or internal
README.md/AUDIT-*.md into the mosaic home. Also align preservePaths with
the bash PRESERVE_PATHS list (AGENTS.md, STANDARDS.md, sources, and
credentials were previously missing) so both install paths have the
same upgrade-preservation semantics.
- packages/mosaic/framework/templates/TOOLS.md.template — replace stale
~/.config/mosaic/rails/ references with ~/.config/mosaic/tools/. The
rails/ tree was renamed to tools/ in the v1→v2 framework migration.
Tests:
- packages/mosaic/src/config/file-adapter.test.ts (new, 5 tests): pins
the whitelist, asserts SOUL.md/USER.md/README.md/AUDIT-*.md are not
seeded, verifies existing user contract files (including AGENTS.md)
survive a keep-mode sync, and asserts a no-op when defaults/ is absent.
Baselines: mosaic typecheck / lint green. Full mosaic vitest 275/276 —
the one failure (src/commands/uninstall.spec.ts:138) is a pre-existing
EACCES issue on main and is unrelated to this change. Repo-wide
typecheck / lint / format:check green. Live smoke of
`bash framework/install.sh` against a tmp MOSAIC_HOME confirms the
installer now prints "Seeded TOOLS.md from defaults" and the file lands.
Ships in @mosaicstack/mosaic 0.0.30.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Fixes mosaicstack/stack#457.
~/.config/mosaic/TOOLS.mdwas never created during a bootstrap install even thoughAGENTS.mddeclares it as mandatory reading at position 5 of the load order. A fresh 0.0.29 install left the file missing and the agent contract pointing at nothing.Root cause
packages/mosaic/framework/install.shlines 228-236 explicitly seedAGENTS.md STANDARDS.mdfromdefaults/—TOOLS.mdwas listed inPRESERVE_PATHSbut never seeded in the first place.While investigating I also found:
FileConfigAdapter.syncFramework(packages/mosaic/src/config/file-adapter.ts) was iterating every file underframework/defaults/, which meant on a fresh install it would silently seeddefaults/SOUL.md(hardcoded "Jarvis") anddefaults/USER.md(placeholder) into the user's mosaic home before the wizard's own identity stages ran.packages/mosaic/framework/templates/TOOLS.md.templatestill referenced~/.config/mosaic/rails/git/...and~/.config/mosaic/rails/codex/.... Therails/tree was renamed totools/in the v1→v2 framework migration — so any user who did runmosaic initwould end up with aTOOLS.mdfull of broken paths.preservePathsdrift:install.shpreserves 8 paths across upgrades;file-adapter.tswas only preserving 4. This has been masked in production because the framework source tree has no root-level contract files — but the two code paths should agree regardless.Fix
packages/mosaic/framework/install.sh— extend the explicit defaults-seed loop fromAGENTS.md STANDARDS.mdtoAGENTS.md STANDARDS.md TOOLS.md.packages/mosaic/src/config/file-adapter.ts— replace the greedyreaddirSync(defaultsDir)loop with an exportedDEFAULT_SEED_FILES = ['AGENTS.md', 'STANDARDS.md', 'TOOLS.md']whitelist. AlignpreservePathswith the bashPRESERVE_PATHSlist so both install paths have the same upgrade-preservation semantics.packages/mosaic/framework/templates/TOOLS.md.template— replacerails/withtools/.Tests
Adds
packages/mosaic/src/config/file-adapter.test.ts(5 tests, all green):SOUL.md/USER.mdfromdefaults/— wizard stages own those.README.md/AUDIT-*.md(framework-internal).keepmode, includingAGENTS.md— this test plants a root-levelAGENTS.mdin the fixture'ssourceDirto actually exercisesyncDirectory's preserve path, not just the seed loop.defaults/directory is absent.Test plan
pnpm --filter @mosaicstack/mosaic run typecheckgreenpnpm --filter @mosaicstack/mosaic run lintgreenpnpm --filter @mosaicstack/mosaic exec vitest run→ 275/276 pass (the one failure,src/commands/uninstall.spec.ts:138, is a pre-existing EACCES issue on main and is unrelated to this change)pnpm typecheck/pnpm lint/pnpm format:checkgreenbash framework/install.shagainst a tmp MOSAIC_HOME — prints "Seeded TOOLS.md from defaults" and the file landsAffected version
Ships in
@mosaicstack/mosaic0.0.30.