@roulabs/mx 1.0.2 → 1.1.1
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 +78 -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,81 @@ 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
|
+
Primary path:
|
|
116
|
+
|
|
117
|
+
1. Read `<runtime>/context/INDEX.json` — every entry's metadata in one Read.
|
|
118
|
+
2. Open files at `<runtime>/context/<path>.md` for entries whose metadata matches the current task.
|
|
119
|
+
|
|
120
|
+
When INDEX descriptions don't surface what you need — and often they won't — fall back to anything that works:
|
|
121
|
+
|
|
122
|
+
- **Grep `<runtime>/context/`** for keywords. Frequently the term you need lives in a body, not in any description.
|
|
123
|
+
- **`ls` the folder recursively** to spot entries on disk that aren't indexed (orphans), and read them directly when relevant.
|
|
124
|
+
- **Follow `related` chains** outward from a known-relevant entry to find the rest of a cluster.
|
|
125
|
+
- **Read everything** if the registry is small (< ~30 entries) and you're starting unfamiliar work — cheaper than guessing.
|
|
126
|
+
|
|
127
|
+
INDEX is the *primary* discovery surface, not the only one. Use whatever gets you to the right entry fastest — direct grep, full-content scan, recursive read, following links, your judgment.
|
|
128
|
+
|
|
129
|
+
A 30-second skim of INDEX is free; do it before any non-trivial task. Skip only for typo-fix-level work.
|
|
130
|
+
|
|
131
|
+
### Maintain INDEX.json as you go
|
|
132
|
+
|
|
133
|
+
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.
|
|
134
|
+
|
|
135
|
+
### Organize as much as you can
|
|
136
|
+
|
|
137
|
+
- **Nest by subject** — `infra/cell/guide`, `auth/tokens`, `payments/stripe/webhook-quirks`. Match the domain's natural divisions.
|
|
138
|
+
- **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.
|
|
139
|
+
- **Cross-link via `related` in INDEX**, not in body content.
|
|
140
|
+
|
|
141
|
+
### When and what to write
|
|
142
|
+
|
|
143
|
+
Three triggers for new entries:
|
|
144
|
+
|
|
145
|
+
1. **When the user asks.** "Save this," "remember this," "add to context" — write the entry immediately and update INDEX.
|
|
146
|
+
2. **When you make a non-obvious discovery during the session.** A root cause you traced, a system invariant you confirmed, a decision reached together, a gotcha that tripped you up — propose inline: *"This seems worth saving — add it as `<path>` with this description? OK?"* Write only after the user confirms.
|
|
147
|
+
3. **Before ending a substantial session.** Review what was learned and propose 1–3 entries the user can approve. Catches durable findings you didn't surface mid-stream.
|
|
148
|
+
|
|
149
|
+
For ephemeral scratch (a debugging journey in progress, a hypothesis you're testing) — write without asking. It's notes; promote or delete later.
|
|
150
|
+
|
|
151
|
+
**What's worth writing:** rationale, history, gotchas, cross-system invariants, debugging journeys, RCAs, session summaries, project-local procedures, imported reference material — your call. When in doubt, save it; prune later.
|
|
152
|
+
|
|
75
153
|
## How to do things (always via mx)
|
|
76
154
|
|
|
77
155
|
You are launched from the work folder, so you can **omit `-n <feature>`** — mx infers the work from
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|