@roulabs/mx 1.0.2 → 1.1.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/bin/mx.js CHANGED
@@ -78,6 +78,15 @@ function removeStaleRuntimeReadme(targetDir) {
78
78
  }
79
79
  return false;
80
80
  }
81
+ function stampContextIndex(targetDir, templatesDir2) {
82
+ const dest = path2.join(targetDir, "context", "INDEX.json");
83
+ if (exists(dest)) return null;
84
+ const src = path2.join(templatesDir2, "context", "INDEX.json");
85
+ if (!exists(src)) throw new MxError(`missing template: ${src}`, "NO_TEMPLATE");
86
+ fs3.mkdirSync(path2.dirname(dest), { recursive: true });
87
+ fs3.copyFileSync(src, dest);
88
+ return dest;
89
+ }
81
90
 
82
91
  // ../../packages/core/src/runtime.ts
83
92
  var DEFAULT_RUNTIME = path3.join(os.homedir(), "mx");
@@ -153,13 +162,18 @@ function initRuntime(target0, templatesDir2) {
153
162
  created.push(marker);
154
163
  }
155
164
  created.push(stampClaudeMd(target, templatesDir2));
165
+ const ctxIndex = stampContextIndex(target, templatesDir2);
166
+ if (ctxIndex) created.push(ctxIndex);
156
167
  removeStaleRuntimeReadme(target);
157
168
  return { runtime: target, created };
158
169
  }
159
170
  function updateRuntime(root, templatesDir2) {
160
171
  const dest = stampClaudeMd(root, templatesDir2);
172
+ const updated = [dest];
173
+ const ctxIndex = stampContextIndex(root, templatesDir2);
174
+ if (ctxIndex) updated.push(ctxIndex);
161
175
  removeStaleRuntimeReadme(root);
162
- return { runtime: root, updated: [dest] };
176
+ return { runtime: root, updated };
163
177
  }
164
178
 
165
179
  // ../../packages/core/src/repos.ts
@@ -619,7 +633,10 @@ works (${data.works.length}):`);
619
633
  case "update": {
620
634
  const root = requireRuntime({ runtime: flags.runtime });
621
635
  const res = updateRuntime(root, templatesDir());
622
- emit(() => console.log(`Re-stamped CLAUDE.md into ${res.runtime}`), res);
636
+ emit(() => {
637
+ console.log(`Updated runtime at ${res.runtime}`);
638
+ for (const p of res.updated) console.log(` + ${p}`);
639
+ }, res);
623
640
  return;
624
641
  }
625
642
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roulabs/mx",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "mx — run several features in parallel across shared repos using git worktrees",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,6 +31,9 @@ here to change how mx works, you're in the wrong place: switch to that repo. Don
31
31
  mx/
32
32
  ├── CLAUDE.md # this file (installed by the mx CLI)
33
33
  ├── .mx-root # empty marker: "this is the mx root"
34
+ ├── context/ # shared memory across all features (see § Context registry)
35
+ │ ├── INDEX.json # single source of truth — metadata for every entry
36
+ │ └── <path>.md # body-only entries; nested folders allowed
34
37
  ├── repos/ # PRISTINE reference clones, each on its default branch
35
38
  │ ├── repo-a/
36
39
  │ └── repo-b/
@@ -72,6 +75,63 @@ mx/
72
75
  4. The work root is **not** a git repo. Run build/test/git commands from inside the relevant worktree.
73
76
  5. If several sessions share one work, the user gives each a lane (usually one repo). Stay in your lane.
74
77
 
78
+ ## Context registry — shared memory across every feature in this runtime
79
+
80
+ `<runtime>/context/` is mx-owned institutional memory for this runtime — findings, decisions, runbooks, notes, debugging journeys, RCAs, session summaries, project-local procedures, imported reference material, anything worth carrying across sessions. mx stamps a starter `INDEX.json` at init; everything after that is yours to shape.
81
+
82
+ ### Two-file design
83
+
84
+ - **`INDEX.json`** — the **single source of truth** for all entry metadata. JSON array.
85
+ - **Body files** at `<runtime>/context/<path>.md` — **only the prose**. No frontmatter, no in-file header. To know what an entry is about, look up its `path` in INDEX.
86
+
87
+ ### INDEX.json schema
88
+
89
+ Top-level JSON array of entry objects. The schema is **closed** — these fields, these types, nothing else. Adding ad-hoc fields will drift across sessions; don't.
90
+
91
+ | field | type | required | notes |
92
+ |---|---|---|---|
93
+ | `path` | `string` | yes | **The unique identifier.** Kebab-case segments separated by `/`. No `.md` extension. Regex: `^[a-z0-9-]+(/[a-z0-9-]+)*$`. File lives at `<runtime>/context/<path>.md`. |
94
+ | `description` | `string` | yes | 1–3 sentences covering (a) the gist / key claim, (b) where in the system it applies, (c) when this entry is relevant — enough to decide *whether to open the body* without actually opening it. |
95
+ | `type` | `string` | no | Free-form label. Suggested vocabulary: `fact`, `decision`, `runbook`, `note`, `skill`. |
96
+ | `tags` | `string[]` | no | Free-form tag strings. |
97
+ | `related` | `string[]` | no | Each item is another entry's `path`. |
98
+ | `last_verified` | `string` | no | ISO date `YYYY-MM-DD`. Use for entries where freshness matters. |
99
+
100
+ Example entry:
101
+
102
+ ```json
103
+ {
104
+ "path": "auth/tokens",
105
+ "description": "Session tokens are namespaced by tenant_id, 30-day expiry, rotated on password or role change. Validation happens at the edge in middleware/auth.go before any handler runs. Read when touching multi-tenant request handling, session lifecycle, or token storage.",
106
+ "type": "fact",
107
+ "tags": ["auth", "security"],
108
+ "related": ["auth/tenant-isolation"],
109
+ "last_verified": "2026-06-05"
110
+ }
111
+ ```
112
+
113
+ ### Reading
114
+
115
+ 1. Read `<runtime>/context/INDEX.json` — every entry's metadata in one Read.
116
+ 2. Open files at `<runtime>/context/<path>.md` for entries whose metadata matches the current task.
117
+ 3. Grep `<runtime>/context/` for keywords when INDEX doesn't surface a match.
118
+
119
+ A 30-second skim of INDEX is free; do it before any non-trivial task. Skip only for typo-fix-level work.
120
+
121
+ ### Maintain INDEX.json as you go
122
+
123
+ When you add, rename, remove, or restructure an entry, update INDEX in the same change. Drift means orphan files (invisible to future sessions) or stale entries (false positives). After editing INDEX, sanity-check it parses as valid JSON.
124
+
125
+ ### Organize as much as you can
126
+
127
+ - **Nest by subject** — `infra/cell/guide`, `auth/tokens`, `payments/stripe/webhook-quirks`. Match the domain's natural divisions.
128
+ - **One concept per file.** If you can't fit the gist + scope + when-relevant into a 1–3 sentence `description`, the file is doing too much — split it. Aim for ≤ ~200 lines per body file; line count is just a tripwire that flags "look closer." When in doubt, factor the shared concept out into its own entry and `related`-link from the children.
129
+ - **Cross-link via `related` in INDEX**, not in body content.
130
+
131
+ ### Write whatever's worth carrying forward
132
+
133
+ Rationale, history, gotchas, cross-system invariants, debugging journeys, RCAs, session summaries, project-local procedures, imported docs — your call. When in doubt, save it; prune later.
134
+
75
135
  ## How to do things (always via mx)
76
136
 
77
137
  You are launched from the work folder, so you can **omit `-n <feature>`** — mx infers the work from
@@ -0,0 +1 @@
1
+ []