@roulabs/mx 1.10.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roulabs/mx",
3
- "version": "1.10.1",
3
+ "version": "2.0.0",
4
4
  "description": "mx — run several features in parallel across shared repos using git worktrees",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  <!-- Installed by the mx CLI. Don't hand-edit this file in the runtime —
2
- edit templates/CLAUDE.md in the mx source repo and run `mx update`. -->
2
+ edit templates/CLAUDE.md in the mx source repo and run `mx sync`. -->
3
3
 
4
4
  # mx — multiplexed parallel work across repos
5
5
 
@@ -17,38 +17,91 @@ to read or change the work — its repos, branches, ports — you call an `mx` c
17
17
 
18
18
  Every read command takes `--porcelain` for stable JSON; parse that instead of scraping text.
19
19
 
20
+ ## Runtime version gate
21
+
22
+ This runtime carries a layout version in `<runtime>/mx.json` (an integer). The `mx` CLI supports exactly
23
+ one runtime version (CLI major ⇄ runtime version). If the CLI and runtime versions don't match, **every
24
+ runtime command refuses** with error `RUNTIME_VERSION_MISMATCH` — only `mx migrate`, `mx update`,
25
+ `mx help`, and `mx version` are allowed. If you hit that error, **stop and tell the user**: run
26
+ `mx migrate` to upgrade an older runtime, or `mx update` (then a new-major install) to upgrade the CLI for
27
+ a newer runtime. Don't try to work around the gate by editing files by hand.
28
+
20
29
  ## What this runtime is for
21
30
 
22
31
  `mx/` is where **feature work** happens. Sessions launched here implement a feature inside a
23
- `works/<feature>/` folder. mx *itself* — this template, the `mx` CLI — is maintained in a separate
24
- **mx source checkout** (the `github.com/roulabs/mx` repo), outside this tree. If you were opened
25
- here to change how mx works, you're in the wrong place: switch to that repo. Don't edit `repos/`,
26
- `works/`, or the runtime files from here.
32
+ `works/<feature>/` folder. mx *itself* — this template, the `mx` CLI — is maintained in the
33
+ `github.com/roulabs/mx` source repo. There are two valid setups for that source:
34
+
35
+ 1. **It lives elsewhere** (the default): if you were opened here to change how mx works, you're in
36
+ the wrong place — switch to that repo. Don't edit `repos/`, `works/`, or the runtime files from
37
+ here.
38
+
39
+ 2. **It's hosted as a work in this runtime** (self-hosting / dogfooding): someone has run
40
+ `mx repo add git@github.com:roulabs/mx.git` and created one or more `works/<feature>/mx/`
41
+ worktrees for parallel mx development. In that case, working inside one of those worktrees IS
42
+ valid — follow that worktree's own `CLAUDE.md` for the developer rules. The runtime rule that
43
+ still applies here: **never run the worktree's locally-built mx CLI against this runtime**.
44
+ Locally-built mx (`pnpm mx`, `node npm/bin/mx.js`) must be pointed at a sandbox (`$PWD/.mx` or
45
+ `/tmp/...`) for any testing — otherwise it may re-stamp this `CLAUDE.md` with a work-in-progress
46
+ template. The published `mx` on `$PATH` (from `npm i -g @roulabs/mx`) is the safe one against
47
+ this runtime.
27
48
 
28
49
  ## Layout
29
50
 
30
51
  ```
31
52
  mx/
32
- ├── CLAUDE.md # this file (installed by the mx CLI)
33
53
  ├── .mx-root # empty marker: "this is the mx root"
54
+ ├── mx.json # runtime config: { "version": 2 }
55
+ ├── CLAUDE.md # this file (installed by the mx CLI)
34
56
  ├── context/ # shared memory across all features (see § Context registry)
35
57
  │ ├── INDEX.json # single source of truth — metadata for every entry
36
58
  │ └── <path>.md # body-only entries; nested folders allowed
37
- ├── repos/ # PRISTINE reference clones, each on its default branch
38
- │ ├── repo-a/
39
- └── repo-b/
59
+ ├── repos/<repo>/ # per-repo container
60
+ │ ├── git/ # the PRISTINE clone (read-only reference)
61
+ ├── hydrate.sh # runs after worktree add (customizable)
62
+ │ └── health.sh # augments `mx repo health` (customizable)
40
63
  └── works/ # one folder per feature/work
41
64
  └── feature-a/
42
65
  ├── work.json # manifest — owned by `mx`, do not hand-edit
43
- ├── feature-a.code-workspace
44
- ├── sessions/ # session summaries (see § Session summaries)
45
- ├── repo-a/ # worktree of repo-a on this feature's branch
46
- └── repo-b/ # worktree of repo-b on this feature's branch
66
+ ├── feature-a.code-workspace # owned by `mx` (folder paths point at wt/<repo>)
67
+ ├── CLAUDE.md # work-specific rules — stamped once, then yours to edit (mx never overwrites)
68
+ ├── .claude/settings.json # SessionStart hook loads context/INDEX.json
69
+ ├── wt/ # ALL worktrees live here
70
+ │ ├── repo-a/ # worktree of repo-a on this feature's branch
71
+ │ └── repo-b/ # worktree of repo-b on this feature's branch
72
+ ├── scripts/ # ad-hoc per-work scripts
73
+ ├── files/ # artifacts worth keeping (agent/user drop zone)
74
+ ├── tmp/ # throwaway scratch — may be deleted at any time
75
+ └── sessions/ # session summaries (see § Session summaries)
47
76
  ```
48
77
 
49
- - `repos/<repo>` are **source-of-truth clones** — read-only reference. Worktrees fork from them
78
+ - `repos/<repo>/git` are **source-of-truth clones** — read-only reference. Worktrees fork from them
50
79
  and share their `.git` object store. Never edit, commit, or run dev servers in `repos/`.
51
- - `works/<feature>/<repo>` are **worktrees**, each on its own feature branch. All work happens here.
80
+ - `repos/<repo>/hydrate.sh` and `repos/<repo>/health.sh` are mx-owned per-repo hooks you may customize:
81
+ `hydrate.sh` runs automatically after `mx work … worktree add <repo>` (cwd = the new worktree); `health.sh`
82
+ augments `mx repo health`. Edit their bodies if a repo needs custom worktree hydrate or health output.
83
+ - `works/<feature>/wt/<repo>` are **worktrees**, each on its own feature branch. All work happens here.
84
+ - `works/<feature>/CLAUDE.md` is **work-specific guidance** that loads alongside this runtime
85
+ `CLAUDE.md` for any session started in the work folder (Claude Code walks up from the session's cwd).
86
+ mx stamps it once (an explanatory comment, otherwise empty) and then **never touches it** — it's where
87
+ you and the user record rules specific to this work.
88
+ - `works/<feature>/{scripts,files,tmp}/` are the only places to put non-mx files in a work — see
89
+ § The work folder holds mx-native files only.
90
+
91
+ ## The work folder holds mx-native files only
92
+
93
+ **Never create ad-hoc files directly in the work-folder root.** The root is reserved for mx-native
94
+ files (`work.json`, the `.code-workspace`, the work `CLAUDE.md`, `.claude/`) and the mx-owned
95
+ subfolders. When you or the user need to write anything else, use one of these, never the root:
96
+
97
+ - **`files/`** — artifacts worth keeping: notes, exports, scratch docs, downloads you want to survive.
98
+ - **`tmp/`** — throwaway scratch. Its contents may be deleted at **any** time, with no guarantees —
99
+ never rely on anything here persisting.
100
+ - **`scripts/`** — ad-hoc scripts for this work.
101
+
102
+ The one exception: a runtime file a session legitimately needs to create at the work root for tooling
103
+ to work (e.g. an MCP connection file like `.<something>-mcp`) is fine. The rule targets *ad-hoc*
104
+ user/agent files — notes, downloads, temp outputs — not necessary tooling files.
52
105
 
53
106
  ## work.json (per-work manifest, owned by mx)
54
107
 
@@ -72,8 +125,10 @@ mx/
72
125
  1. You are launched from a **work folder** (`works/<feature>/`), not a single repo. There is no "main repo."
73
126
  2. Read the work's state with `mx work -n <feature> info --porcelain` to learn its repos, branches, and ports.
74
127
  3. When you edit a repo's worktree, follow that repo's own `CLAUDE.md`, linters, and conventions —
75
- its instructions live inside the worktree and apply.
76
- 4. The work root is **not** a git repo. Run build/test/git commands from inside the relevant worktree.
128
+ its instructions live inside the worktree and apply. The work's own `CLAUDE.md` (at the work-folder
129
+ root) also loads for sessions started here read it for rules specific to this work.
130
+ 4. The work root is **not** a git repo. Run build/test/git commands from inside the relevant worktree
131
+ (`works/<feature>/wt/<repo>`).
77
132
  5. If several sessions share one work, the user gives each a lane (usually one repo). Stay in your lane.
78
133
 
79
134
  ## Context registry — shared memory across every feature in this runtime
@@ -115,7 +170,7 @@ Example entry:
115
170
 
116
171
  Primary path:
117
172
 
118
- 1. **Read `<runtime>/context/INDEX.json` on every task** — trivial or not, small or large. Skimming a metadata index is cheap; the cost of missing a relevant entry is high. This is a hard rule, not a heuristic.
173
+ 1. **Read `<runtime>/context/INDEX.json` on every task** — trivial or not, small or large. Skimming a metadata index is cheap; the cost of missing a relevant entry is high. This is a hard rule, not a heuristic. (Each work also carries a `.claude/settings.json` `SessionStart` hook that prints this INDEX into the session at launch, so you usually start with it already in context — but re-read it when in doubt.)
119
174
  2. Open files at `<runtime>/context/<path>.md` for entries whose metadata matches the current task.
120
175
 
121
176
  When INDEX descriptions don't surface what you need — and often they won't — fall back to anything that works:
@@ -192,13 +247,16 @@ clarity; dropping it works while you're inside the work.
192
247
  ```
193
248
  mx work -n <feature> worktree add <repo> [--branch <b>] [--base <ref>]
194
249
  ```
195
- This creates the worktree from the pristine clone, registers it in `work.json`, and adds it to the
196
- workspace — all at once. Never run `git worktree add` yourself.
250
+ This creates the worktree from the pristine clone at `works/<feature>/wt/<repo>`, registers it in
251
+ `work.json`, and adds it to the workspace — all at once. Never run `git worktree add` yourself.
197
252
  - `--branch <b>` is the **new** branch to create (defaults to the work name; if it already exists, it's reused).
198
253
  - `--base <ref>` is where to **fork from** — any ref. A bare branch name (e.g. `main`,
199
254
  `migration-to-mt-service-from-cf`) resolves to that local branch or, failing that, `origin/<name>`.
200
255
  Run `mx repo -n <repo> fetch` first if you want the base at its latest upstream commit. Omit
201
256
  `--base` to fork from the pristine clone's current HEAD.
257
+ - After the worktree is created, the repo's `repos/<repo>/hydrate.sh` runs automatically with the new
258
+ worktree as the working directory (copy a `.env`, install deps, etc.). Pass `--no-hydrate` to skip it,
259
+ or re-run it later with `mx work -n <feature> worktree hydrate <repo>`.
202
260
  - **Allocate a port:** `mx work -n <feature> port set <repo> <service>` returns a free port (unique
203
261
  across all works). This only records the port in `work.json` — **you** must then wire that port
204
262
  into the repo's own env/config (`.env`, `PORT=`, etc.) and remap any outbound URL to a sibling
@@ -214,8 +272,13 @@ clarity; dropping it works while you're inside the work.
214
272
  4. **Creating a worktree requires the user in the loop** — only when they explicitly tell you to in this session.
215
273
  5. **Don't destroy anything unless asked.** Worktrees stay until the user confirms the feature is merged.
216
274
  Teardown keeps feature branches; never delete them.
275
+ 6. **Never create ad-hoc files in the work-folder root.** Keepable artifacts go in `files/`, throwaway
276
+ scratch in `tmp/`, scripts in `scripts/`. The root is mx-native only (only exception: a tooling
277
+ file a session genuinely needs there, e.g. an MCP connection file). See § The work folder holds
278
+ mx-native files only.
217
279
 
218
280
  ## The one rule that matters most
219
281
 
220
- `repos/` is read-only reference; real work lives in worktrees under `works/<feature>/`; and `mx`
221
- owns the manifest. If a repo you need has no worktree yet, ask before adding one — then add it with `mx`.
282
+ `repos/` is read-only reference; real work lives in worktrees under `works/<feature>/wt/<repo>`; and
283
+ `mx` owns the manifest. If a repo you need has no worktree yet, ask before adding one — then add it
284
+ with `mx`.
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # mx per-repo health hook.
4
+ #
5
+ # `mx repo -n <repo> health` first runs mx's built-in structured checks (current
6
+ # vs default branch, uncommitted/untracked, ahead/behind origin, last fetched)
7
+ # and then runs this script, capturing its stdout as an extra section. Use it
8
+ # for repo-specific checks mx can't know about — e.g. node_modules present, a
9
+ # dev DB reachable, a required tool installed.
10
+ #
11
+ # Runs with the repo's git clone as the working directory. Context via env:
12
+ # MX_REPO repo name
13
+ # MX_REPO_PATH repo container (repos/<repo>)
14
+ # MX_GIT_DIR the git clone (repos/<repo>/git)
15
+ # MX_RUNTIME runtime root
16
+ #
17
+ # Whatever you echo appears under the health report. No output by default.
18
+ set -euo pipefail
19
+
20
+ # Example:
21
+ # [ -d node_modules ] && echo "node_modules: present" || echo "node_modules: MISSING"
22
+
23
+ exit 0
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # mx per-worktree hydrate hook for this repo.
4
+ #
5
+ # Runs automatically after `mx work -n <work> worktree add <this repo>` creates
6
+ # a worktree (skip with --no-hydrate; re-run with `mx work -n <work> worktree
7
+ # hydrate <this repo>`). Customize it to make a fresh worktree runnable: copy a
8
+ # .env, allocate a port and write it into the worktree, install deps, etc.
9
+ #
10
+ # mx runs this with the new worktree as the working directory and passes context
11
+ # both as positional args and environment variables:
12
+ #
13
+ # $1 / $MX_WORKTREE_PATH absolute path to the new worktree
14
+ # $2 / $MX_BRANCH branch the worktree is on
15
+ # $MX_WORK work name
16
+ # $MX_REPO repo name
17
+ # $MX_BASE base ref it was forked from (may be empty)
18
+ # $MX_WORK_PATH absolute path to the work folder
19
+ # $MX_RUNTIME runtime root
20
+ #
21
+ # Ports stay mx-owned — allocate via mx, then wire the result in yourself, e.g.:
22
+ # port=$(mx work -n "$MX_WORK" port set "$MX_REPO" web --porcelain | jq -r .port)
23
+ # echo "PORT=$port" >> "$MX_WORKTREE_PATH/.env"
24
+ #
25
+ # A non-zero exit is reported as a warning and the worktree is kept.
26
+ set -euo pipefail
27
+
28
+ echo "Hydrate is done"