First command over the USER data root (~/.mosaic), per the HARNESS-HOMES
two-root split: ~/.config/mosaic is update-owned system space; ~/.mosaic is
user content that installs/updates never touch. The store is the vetting
boundary for plugins and skills.
- commands/store.ts: store add <kind> <name> <version> --from <dir> --by
<operator> [--notes] — copies real directory content (symlinks refused,
source must be outside the store) into <root>/<kind>s/<name>/<version>/
and writes store-entry.json LAST, so a partial write can never list as a
usable entry (a markerless dir is reclaimed with status
recovered-partial; an existing marker makes add append-only-refusing).
store list [--kind] [--name] — deterministic enumeration with typed
statuses: vetted | incomplete | invalid-metadata | foreign (surfaced,
never mutated).
- Name/version validated before any filesystem call; rich status enum over
booleans; env seam MOSAIC_USER_HOME for tests — modelled on skill.ts,
pointed at the user root instead of the system root.
- constants: DEFAULT_MOSAIC_USER_HOME. cli.ts: registration only.
- store.spec.ts: 45 tests — validation matrix, marker-last/append-only
semantics, symlink refusal (source link and nested), self-copy guard,
partial recovery, listing classification, CLI exit codes.
Gates (worktree, sb-it-1-dt): store spec 45/45; package build+typecheck+lint
green; package pnpm test vitest 87 files/1593 tests green — framework-shell
chain stops at invariant_r (host pi 0.84.2 vs recorded 0.84.1, inherited);
root build 25/25 + typecheck 45/45; prettier clean (diff-scanned).
Deferred to W-F6: activation/symlink-install into agent homes, version
pinning, network acquisition (add is local-path only, by design).