@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 +19 -2
- package/package.json +1 -1
- package/templates/CLAUDE.md +60 -0
- package/templates/context/INDEX.json +1 -0
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
|
|
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(() =>
|
|
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
package/templates/CLAUDE.md
CHANGED
|
@@ -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
|
+
[]
|