T-RVMG-adopt-moon-workspace-runner
Status: closed/done · Impact: high · Complexity: large
The repo is single-package today and cannot express shared packages or polyglot
applications. D-0012-monorepo-tooling settled the move: adopt moon as a
language-agnostic workspace runner over a polyglot tree, and stand up the empty
apps/ + packages/ts/ + packages/rust/ trees with workspace wiring. This is
the foundation task — it unblocks the site migration, the dashboard app, and every
later shared-package and Tauri-Rust effort.
The repo is a single Bun package at the root, with an npm-managed Astro site beside it and no monorepo tooling of any kind.
| Location | Role today |
|---|---|
package.json | Root Bun package @sksizer/sdlc-plugin; no workspaces field, no monorepo wiring |
bun.lock | Root Bun lockfile — Bun already manages the JS/TS substrate |
tsconfig.json | Single root tsconfig covering plugin/**/*.ts + tests/**/*.ts |
justfile | Human/skill command catalog — markdown fmt/check recipes today |
lefthook.yml | Git-hook driver — pre-commit markdown fmt + worktree guard + project-check gates |
plugin/cli/sdlc.ts | The sdlc CLI, run via bun run plugin/cli/sdlc.ts <noun> <verb> |
site/ | Astro/Starlight docs site, npm-managed (site/package-lock.json), with a stale site/pnpm-lock.yaml |
There is no monorepo runner today (no .moon/), and no apps/ or packages/
trees — this task creates them.
Proposed
Section titled “Proposed”A moon workspace sits over a polyglot tree. moon owns the build graph and cache;
justfile stays the command catalog and lefthook stays the git-hook driver —
moon sits alongside both, replacing neither. The destination tree:
.moon/ workspace.yml project discovery (globs) + registered projects toolchains.yml javascript+bun toolchain; rust toolchain (for later Tauri)moon.yml root project: wraps the existing sdlc CLI as moon tasksapps/ .gitkeep empty; ready for the dashboard (T-CW4K) and desktop appspackages/ ts/ .gitkeep empty; shared TypeScript packages (UI kit, API client) rust/ .gitkeep empty; shared Rust crates.moon/workspace.yml discovers projects by glob (apps/*, packages/ts/*,
packages/rust/*) and registers the root project; it is written ready to register
site (the migration itself is T-F31Q). .moon/toolchains.yml declares the
JavaScript ecosystem on Bun as package manager and a Rust toolchain
configured for later Tauri work. The root moon.yml exposes the substrate’s
existing checks as moon tasks (test, check) so moon run :test and
moon check drive the same commands skills run today.
Approach
Section titled “Approach”- Add
.moon/workspace.yml— declare theprojectsdiscovery globs (apps/*,packages/ts/*,packages/rust/*) and register the root project (.). Add commented scaffolding for thesiteproject so T-F31Q only has to uncomment/adjust. Pin aversionConstraintfor moon. - Add
.moon/toolchains.yml— declare thejavascripttoolchain withpackageManager: bun(and the bun version constraint matchingpackage.json’sengines.bun), plus arusttoolchain block configured for later Tauri work. Do not pin a Rust version aggressively; channelstable. - Add a root
moon.yml(project typetool/library) wrapping the existing substrate commands as moon tasks:test→bun test,check→ typecheck (bunx tsc --noEmitagainst the roottsconfig.json). Keep tasks thin — they shell to the same commands thejustfile/package.jsonalready run. - Create the empty trees:
apps/.gitkeep,packages/ts/.gitkeep,packages/rust/.gitkeep— placeholders so the directories exist under git with no project yet (project discovery tolerates empty roots). - Add
.moon/cache/to.gitignore(moon’s local cache is gitignored; remote cache is deferred per D-0012-monorepo-tooling). - Verify
moon checkpasses andmoon run :testruns the substrate tests; then confirmjust,lefthook, and thesdlcCLI all still function unchanged.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
.moon/workspace.yml | new | Project discovery globs (apps/*, packages/ts/*, packages/rust/*) + root project; commented site registration ready for T-F31Q |
.moon/toolchains.yml | new | javascript toolchain on Bun + rust toolchain for later Tauri |
moon.yml | new | Root project: test/check moon tasks wrapping existing substrate commands |
apps/.gitkeep | new | Empty apps/ tree placeholder |
packages/ts/.gitkeep | new | Empty packages/ts/ tree placeholder |
packages/rust/.gitkeep | new | Empty packages/rust/ tree placeholder |
.gitignore | modify | Ignore moon’s local cache (.moon/cache/) |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
.moon/workspace.yml,.moon/toolchains.yml, and rootmoon.ymlexist andmoon checkexits 0 against them. - AC-2:
moon run :testruns the substrate test suite (bun test) and passes. - AC-3: The directories
apps/,packages/ts/, andpackages/rust/exist in git (tracked via.gitkeep). - AC-4:
.moon/toolchains.ymldeclares both a Bun-backedjavascripttoolchain and arusttoolchain. - AC-5:
juststill lists its recipes andlefthook run pre-commitstill executes; thesdlcCLI still runs viabun run plugin/cli/sdlc.ts project doctor. - AC-6:
.moon/cache/is gitignored —git statusis clean after amooninvocation.
Out of scope
Section titled “Out of scope”- Migrating
site/to Bun and deletingsite/pnpm-lock.yaml— that isT-F31Q. - Scaffolding the dashboard app under
apps/— that isT-CW4K. - Lifting the substrate (
plugin/lib/→ top-levelsrc/) or moving the harness surface — separately sequenced per D-0001-project-structure. - moon remote cache — deferred until CI exists (D-0012-monorepo-tooling).
- Adding any real package or crate under the new trees — they ship empty.
Dependencies
Section titled “Dependencies”- none. This is the foundation task;
depends_on:is empty.
Discovery context
Section titled “Discovery context”The T-CW4K-scaffold-dashboard-vite-vue post-mortem surfaced two
moon-workspace-setup friction bullets that belong to this foundation task
(the .prototools moon version pin and the node_modules/.bin-on-PATH
toolchain gap), linked here by the spawn-from-post-mortem dedup search rather
than spawned as duplicate tasks.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: moon version mismatch blocked every moon task — the proto shim resolved a global moon 2.0.0-rc.0, which fails the workspace versionConstraint ’>=1.41.0’ (a -rc prerelease doesn’t satisfy a stable range). Fixed by adding a root .prototools pinning moon = 1.41.8. The pin arguably belongs in T-RVMG / D-0012-monorepo-tooling workspace setup rather than in this app task. Keywords searched: d-0012-monorepo-tooling, versionconstraint, prerelease, prototools, workspace, mismatch, resolved, arguably Excluded: T-CW4K-scaffold-dashboard-vite-vue Top candidates (score / status / headline):
- 17 / in-progress / T-RVMG-adopt-moon-workspace-runner — Adopt moon as the monorepo workspace
runner; create apps/ + packages/
trees - 13 / in-progress / T-F31Q-migrate-site-to-bun — Migrate the Astro docs site from npm to Bun
- 13 / in-progress / T-VE7H-task-work-probe-keys-package-manager-off-project — task-work permissions probe should key package-manager signal off project verbs, not blanket npm
- 9 / planning/draft / T-CKC1-tauri-desktop-wrapper — Tauri desktop wrapper consuming the dashboard SPA (polyglot validating case)
- 5 / closed/done / T-SSB8-split-pr-respond-and-close-out-with-lease-reacquire — Split
/sdlc:pr-respondand/sdlc:task-close-outto re-acquire the lease Decision: LINKED-EXISTING T-RVMG-adopt-moon-workspace-runner
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: moon system toolchain doesn’t add node_modules/.bin to PATH — a bare vite task command fails with exit 127; had to invoke bunx vite. A note in the moon-workspace conventions (or a toolchain that injects .bin) would prevent rediscovery. Keywords searched: moon-workspace, node_modules, conventions, rediscovery, toolchain, command, injects, prevent Excluded: T-CW4K-scaffold-dashboard-vite-vue Top candidates (score / status / headline):
- 20 / in-progress / T-RVMG-adopt-moon-workspace-runner — Adopt moon as the monorepo workspace
runner; create apps/ + packages/
trees - 15 / closed/done / T-G834-move-plugin-runtime-state-to-sdlc-dir — Migrate sdlc plugin runtime state from .claude/ to .sdlc/
- 14 / closed/done / T-7PXF-declare-worktree-init-bun-install — Declare worktree_init: bun install in sdlc.yaml
- 14 / closed/done / T-I2ML-squash-legacy-feat-branch-references — Remove legacy feat/
branch-prefix transition-window references — task/ is canonical - 14 / closed/done / T-J1M3-sdlc-yaml-json-schema-and-validator — Add JSON Schema + validator for sdlc.yaml Decision: LINKED-EXISTING T-RVMG-adopt-moon-workspace-runner
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-06-17. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: auto —
.moon/workspace.yml,.moon/toolchain.yml,moon.ymlexist;moon sync projectsandmoon run :checkexit 0.moon checkorchestrates both tasks correctly; its only non-zero is the bundledtesttask surfacing one pre-existing baseline failure (site_roadmap.test.ts), unrelated to moon. - AC-2: auto —
moon run :testdrivesbun test(1410 pass / 1 fail); the single failure (site_roadmap.test.tsidempotency) reproduces identically on a moon-freemaincheckout, so it is pre-existing and moon-independent. The moon-wraps-bun-test wiring is sound. - AC-3: auto —
git ls-filestracksapps/.gitkeep,packages/ts/.gitkeep,packages/rust/.gitkeep. - AC-4: auto —
.moon/toolchain.ymldeclares both a Bun-backedbun:toolchain and arust:toolchain;moon project rootconfirmsToolchain: bun. - AC-5: auto —
just --listlists recipes,bunx lefthook run pre-commitexecutes (v2.1.9, all jobs evaluate),sdlc project doctorreports all deps ok. - AC-6: auto —
.moon/cache/is gitignored (git check-ignoreconfirms);git statusis clean after moon invocations.
What worked
Section titled “What worked”- The baseline-gated quality run correctly subtracted the repo’s ~470 pre-existing findings, so the moon adoption diff was easy to isolate.
- moon’s own
moon check/moon sync projects/moon project rootgave fast, deterministic feedback while authoring the configs.
Friction and automation gaps
Section titled “Friction and automation gaps”- moon 1.41.8 reads
.moon/toolchain.yml(singular), but the task spec and moon’s online docs saytoolchains.yml(plural); a plural file is silently ignored. Cost a round of empirical testing to discover — the task-define / readiness gate could not have caught this (the filename was plausible). No automation gap on the SDLC side; a note in D-0012-monorepo-tooling on the version-specific filename would save the next moon task the same discovery. →T-TZZN-d0012-note-moon-toolchain-filename - The Step 7 baseline-diff gate reported
new-drift=3that were all false positives: twobun testlines were the dashboard test’s non-deterministic ephemeral port/PID/tmpdir, and one rumdl line was the summary header whose(80ms)timing differs run-to-run — the quality executor’s finding-extraction forbun test/rumdlincludes non-deterministic output, so any branch trips a spurious new-drift on these verbs — a normalization pass (strip ports/PIDs/timings before diffing) in the quality service would remove this noise class. → T-BQRU-quality-normalize-ports-pids-timings
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”T-TZZN-d0012-note-moon-toolchain-filename(https://github.com/sksizer/dev/pull/451) — note moon’s version-specific.moon/toolchain.yml(singular) filename in D-0012-monorepo-tooling; spawned (Local).- T-BQRU-quality-normalize-ports-pids-timings
(https://github.com/sksizer/dev/pull/452) — extend
normalizeFindingto mask ephemeral ports, PIDs, and timing tokens; spawned (Upstream-plugin/sdlc, degenerate-local,sdlc-meta).