-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathtoolkit-guide.html
More file actions
497 lines (458 loc) · 47.3 KB
/
Copy pathtoolkit-guide.html
File metadata and controls
497 lines (458 loc) · 47.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mxcli Project Toolkit — How This Works</title>
<style>
/* ── Shared shell tokens ─────────────────────────────────────────────
Every stage HTML surface (triage.html, architecture/blueprint.html, build-plan.html,
test-report.html, index.html …) copies this :root block + base styles as its
shell, so all project artifacts read as one system. These are the neutral
bootstrap tokens; once Stage 3 produces design/design-system.html, THAT file's
tokens supersede these for everything generated afterwards. */
:root {
--bg: #f8fafc;
--surface: #ffffff;
--ink: #1e293b;
--ink-soft: #64748b;
--ink-faint: #94a3b8;
--line: #e2e8f0;
--accent: #0f4c81;
--pass-bg: #dcfce7; --pass-ink: #166534;
--fail-bg: #fee2e2; --fail-ink: #991b1b;
--warn-bg: #fef3c7; --warn-ink: #92400e;
--radius: 10px;
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--mono: ui-monospace, 'SF Mono', Menlo, monospace;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: var(--font); background: var(--bg); color: var(--ink); line-height: 1.55; padding: 40px 20px 80px; }
.wrap { max-width: 880px; margin: 0 auto; }
h1 { font-size: 28px; letter-spacing: -0.02em; }
h2 { font-size: 19px; margin: 48px 0 14px; letter-spacing: -0.01em; }
h3 { font-size: 15px; margin: 18px 0 6px; }
p { margin: 8px 0; }
.lede { color: var(--ink-soft); font-size: 15px; max-width: 640px; margin-top: 10px; }
code { font-family: var(--mono); font-size: 0.88em; background: #eef2f7; border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; }
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 20px; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }
.card h3 { margin-top: 0; }
.card .stages { font-family: var(--mono); font-size: 12px; color: var(--accent); font-weight: 600; }
.card p { font-size: 13.5px; color: var(--ink-soft); }
.badge { display: inline-block; font-size: 11px; font-weight: 700; padding: 2px 10px; border-radius: 999px; vertical-align: 2px; }
.badge.gate { background: var(--fail-bg); color: var(--fail-ink); }
.badge.soft { background: var(--pass-bg); color: var(--pass-ink); }
.badge.mig { background: var(--warn-bg); color: var(--warn-ink); }
.badge.prop { background: var(--warn-bg); color: var(--warn-ink); border: 1px dashed var(--warn-ink); }
/* timeline */
.timeline { list-style: none; margin-top: 18px; }
.timeline li { position: relative; padding: 0 0 26px 56px; }
.timeline li::before { content: ""; position: absolute; left: 19px; top: 34px; bottom: -4px; width: 2px; background: var(--line); }
.timeline li:last-child::before { display: none; }
.stage-no { position: absolute; left: 0; top: 0; width: 40px; height: 40px; border-radius: 50%;
background: var(--surface); border: 2px solid var(--accent); color: var(--accent);
font-weight: 700; font-size: 14px; display: flex; align-items: center; justify-content: center; }
.timeline .stage-title { font-weight: 700; font-size: 15px; padding-top: 8px; }
.yougive, .youget { font-size: 13.5px; margin-top: 4px; }
.yougive strong, .youget strong { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; }
.yougive strong { color: var(--accent); }
.youget strong { color: var(--ink-faint); }
ol.protocol { margin: 12px 0 0 20px; }
ol.protocol li { margin-bottom: 8px; font-size: 14px; }
pre.tree { font-family: var(--mono); font-size: 12.5px; background: var(--surface); border: 1px solid var(--line);
border-radius: var(--radius); padding: 16px 20px; overflow-x: auto; line-height: 1.7; }
pre.tree .c { color: var(--ink-faint); }
.panic { border-left: 4px solid var(--warn-ink); }
.panic h3 { color: var(--warn-ink); }
.kbd { font-family: var(--mono); background: var(--ink); color: #e2e8f0; padding: 2px 8px; border-radius: 4px; font-size: 12px; }
.footer { margin-top: 56px; font-size: 12px; color: var(--ink-faint); border-top: 1px solid var(--line); padding-top: 14px; }
table { border-collapse: collapse; width: 100%; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; font-size: 13.5px; }
th, td { text-align: left; padding: 9px 13px; border-bottom: 1px solid var(--line); }
th { background: var(--ink); color: #e2e8f0; font-weight: 600; font-size: 12.5px; }
tr:last-child td { border-bottom: none; }
</style>
</head>
<body>
<div class="wrap">
<h1>mxcli Project Toolkit — how this works</h1>
<p class="lede">You point this toolkit at legacy source code <em>or</em> a stack of requirements, and it interviews you through to a running Mendix app. Every stage produces an artifact you can show a customer, and every decision you make is recorded — nothing is silently decided for you.</p>
<h2>1 · Five ways in — pick what you're starting from</h2>
<div class="cards">
<div class="card">
<h3>Migration</h3>
<div class="stages">Stages P, 0–7</div>
<p>You have legacy source code (OutSystems, Java/Angular, Node/React, …). Extractors read it, BRDs are generated from it, and the app is rebuilt in Mendix — with an optional data cutover at the end.</p>
</div>
<div class="card">
<h3>Requirements-driven</h3>
<div class="stages">Stages P, 1–6</div>
<p>No legacy code — you have specs, BRDs, workshop outputs, wireframes, or an expert to interview. Document extraction and SME interviews replace the code extractors; everything after that is identical.</p>
</div>
<div class="card">
<h3>Greenfield</h3>
<div class="stages">Stages P, 5–6</div>
<p>You already know what to build. Skip straight to the Mendix build discipline: gated module-by-module construction, then end-to-end testing.</p>
</div>
<div class="card">
<h3>Change an existing app</h3>
<div class="stages">Stages P, 0–6 per slice</div>
<p>You have a live Mendix app and are adding to or altering one slice of it. The knowledge base is queried from the model itself, a regression net goes under the app before anything changes, stages 2–4 run over the slice only, and every build gate is also a regression gate. No cutover — the app never stops being live.</p>
</div>
<div class="card">
<h3>Just the tools</h3>
<div class="stages">No pipeline</div>
<p>You have an existing Mendix app and only want an audit, a lint pass, or a regression/e2e test net under it. Skip everything above — no intake, no stages, no gates. The agent grabs exactly the tools needed and hands you a findings report or a green test suite.</p>
</div>
</div>
<h2>2 · The journey</h2>
<p class="lede"><span class="badge gate">✋ HARD GATE</span> means the pipeline stops until you explicitly confirm a decision. <span class="badge soft">SOFT GATE</span> means unknowns get a recommended default, recorded as <code>ASSUMED</code>, and the run keeps moving.</p>
<ul class="timeline">
<li><span class="stage-no">P</span>
<div class="stage-title">Kickoff <span class="badge soft">SOFT GATE</span></div>
<div class="yougive"><strong>You're asked</strong> — where the source/requirements live, any licence constraints, whether an expert (SME) is available.</div>
<div class="youget"><strong>You get</strong> — a scaffolded workspace: <code>intake.md</code>, <code>PROJECT.md</code> (your decision register), <code>index.html</code> (your live dashboard).</div>
</li>
<li><span class="stage-no">0</span>
<div class="stage-title">Triage <span class="badge gate">✋ HARD GATE</span> <span class="badge mig">MIGRATION ONLY</span></div>
<div class="yougive"><strong>You're asked</strong> — reuse an existing extraction pipeline or build a new one (with a coverage matrix as evidence); what to do about each missing dependency; what order to tackle a large source in.</div>
<div class="youget"><strong>You get</strong> — <code>assessment.md</code> + <code>triage.md</code>: what's in your source, the risks, and a signed-off plan of attack.</div>
</li>
<li><span class="stage-no">1</span>
<div class="stage-title">Analysis <span class="badge soft">SOFT GATE</span></div>
<div class="yougive"><strong>You're asked</strong> — do documents exist beyond the source folder? DB schema? Sample data? Who can answer what the code can't?</div>
<div class="youget"><strong>You get</strong> — a knowledge base extracted three ways: from code, from documents, from the expert interview. Each path is done or explicitly declared unavailable — never silently skipped.</div>
</li>
<li><span class="stage-no">2</span>
<div class="stage-title">Requirements <span class="badge soft">SOFT GATE</span></div>
<div class="yougive"><strong>You're asked</strong> — to confirm business rules the code or documents imply. Narrative is never invented.</div>
<div class="youget"><strong>You get</strong> — validated BRDs (business requirements documents), one per module, checked clean.</div>
</li>
<li><span class="stage-no">3</span>
<div class="stage-title">Architecture & Design <span class="badge gate">✋ HARD GATE</span></div>
<div class="yougive"><strong>You're asked</strong> — module boundaries, buy-vs-build per gap, target security roles, data volumes, integration contracts, branding (logo/palette/type).</div>
<div class="youget"><strong>You get</strong> — architecture diagrams, fit-gap analysis, a versioned design system, annotated wireframes.</div>
</li>
<li><span class="stage-no">4</span>
<div class="stage-title">Build Plan <span class="badge gate">✋ HARD GATE</span></div>
<div class="yougive"><strong>You're asked</strong> — acceptance criteria per module (what "done" means), target environments, iteration size.</div>
<div class="youget"><strong>You get</strong> — a numbered, dependency-ordered build plan. Nothing gets built before you approve it.</div>
</li>
<li><span class="stage-no">5</span>
<div class="stage-title">Build <span class="badge soft">SOFT GATE</span></div>
<div class="yougive"><strong>You're asked</strong> — to confirm each module's business-rule coverage checklist: the real definition of done, beyond "no errors".</div>
<div class="youget"><strong>You get</strong> — working modules, one at a time, each passing an automatic snapshot → execute → verify → restore-on-failure loop. A bad write costs one batch, never the project.</div>
</li>
<li><span class="stage-no">6</span>
<div class="stage-title">Test <span class="badge soft">SOFT GATE</span></div>
<div class="yougive"><strong>You're asked</strong> — which edge cases matter beyond the golden path.</div>
<div class="youget"><strong>You get</strong> — Playwright walking your app as a real user, plus database assertions catching what the UI can't. Results reported verbatim.</div>
</li>
<li><span class="stage-no">7</span>
<div class="stage-title">Cutover <span class="badge gate">✋ HARD GATE</span> <span class="badge mig">MIGRATION ONLY</span></div>
<div class="yougive"><strong>You're asked</strong> — migrate legacy data, seed fresh, or drop it? Who flips the switch, when, and what's the rollback?</div>
<div class="youget"><strong>You get</strong> — migration scripts and a cutover checklist. Runs only after testing passes — never before.</div>
</li>
</ul>
<h2>3 · How a gate works — you correct, you don't fill in forms</h2>
<div class="card">
<ol class="protocol">
<li><strong>The agent does its homework first.</strong> It never asks what it can derive from your source, the extraction, or the Mendix model itself.</li>
<li><strong>It proposes, with evidence.</strong> 2–4 concrete options, a recommendation, and why — citing your actual source (“your app has 4 auth roles, 3 are never checked; I recommend collapsing to 2”).</li>
<li><strong>It states its assumptions out loud</strong> so you can correct the premise, not just the conclusion.</li>
<li><strong>You answer in the terminal</strong> — multiple choice, “other” always available.</li>
<li><strong>The decision is written down twice</strong>: in that stage's HTML report and in <code>PROJECT.md</code>, marked <code>CONFIRMED</code>.</li>
<li><strong>Don't know? That's fine.</strong> The recommendation is applied and marked <code>ASSUMED</code> with the risk if wrong. A solo run never stalls — except at a ✋ gate, which waits for you.</li>
</ol>
</div>
<h2>4 · Three ways your app gets written — CLI, MCP+MDL, hand-rolled MCP</h2>
<p class="lede">From Stage 5 on, the agent writes to your Mendix project (<code>.mpr</code>) through one of three routes. You don't have to pick — the agent checks a safety table (the "STOP table") before every write — but knowing the difference explains why it sometimes asks you to close or open Studio Pro.</p>
<div class="cards">
<div class="card">
<h3>CLI <span class="badge soft">STUDIO PRO CLOSED</span></h3>
<p><strong>The bulk builder.</strong> <code>mxcli exec script.mdl</code> writes a whole reviewable script — entities, associations, microflows, security, navigation — to disk in one shot. Scaffolds an entire module at once, auto-snapshots before every run. Tradeoff: Studio Pro must be closed and reopened afterwards.</p>
</div>
<div class="card">
<h3>MCP + MDL <span class="badge mig">STUDIO PRO OPEN</span></h3>
<p><strong>The live editor.</strong> <code>mxcli --mcp exec</code> routes the same MDL through Studio Pro's own engine while it's running — changes appear immediately, no restart. This is the mode for UI iteration: page layouts, widget wiring, visibility tweaks. It also sidesteps a class of disk-writer bugs.</p>
</div>
<div class="card">
<h3>Hand-rolled MCP <span class="badge mig">STUDIO PRO OPEN</span></h3>
<p><strong>The precision tool.</strong> Raw JSON patches against Studio Pro's model API (<code>pg_patch_page</code>), for the few widget shapes MDL has no syntax for yet — complex datagrid columns, dropdown filters. Used only when the other two genuinely can't express the change.</p>
</div>
</div>
<p style="font-size:13.5px; color:var(--ink-soft); margin-top:10px;"><strong>In practice:</strong> CLI to build, MCP to refine. A typical module: one CLI exec scaffolds the domain model and logic → MCP+MDL polishes the pages → hand-rolled MCP only for the exceptions. Two operations never go through any of these — project settings and dropping secured attributes go to <strong>you, in the Studio Pro GUI</strong>, because they corrupt on every automated route. The agent will tell you when, with the exact click path.</p>
<h2>5 · Where you run this — detected, never asked, and you can move</h2>
<p class="lede">There is no "which setup do you want?" question. <code>bin/doctor.sh</code> looks at where your chat started and records it once in <code>PROJECT.md</code>. All three places work on the <em>same</em> project folder, git repo and <code>.mpr</code> — you switch between them whenever one is more convenient. The only rule: one writer on the <code>.mpr</code> at a time.</p>
<svg viewBox="0 0 840 540" width="100%" role="img" aria-labelledby="lanes-title" style="display:block; margin:16px 0; font-family:var(--font);">
<title id="lanes-title">Three places to run the toolkit, all working on one shared project</title>
<defs>
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0,0 L10,5 L0,10 z" fill="var(--ink-faint)"/>
</marker>
<marker id="arr-accent" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0,0 L10,5 L0,10 z" fill="var(--accent)"/>
</marker>
</defs>
<!-- lane: cloud -->
<rect x="15" y="16" width="250" height="150" rx="10" fill="var(--surface)" stroke="var(--line)"/>
<text x="30" y="42" font-size="15" font-weight="700" fill="var(--ink)">☁︎ Cloud</text>
<text x="30" y="60" font-size="11.5" fill="var(--ink-soft)">Claude Code on the web / mobile</text>
<text x="30" y="84" font-size="12" fill="var(--ink)">• nothing to install</text>
<text x="30" y="102" font-size="12" fill="var(--ink)">• headless: CLI writes, mxbuild gate</text>
<text x="30" y="120" font-size="12" fill="var(--ink)">• see the app via a preview URL</text>
<text x="30" y="138" font-size="12" fill="var(--warn-ink)">• ephemeral → push at every gate</text>
<text x="30" y="156" font-size="11" font-family="var(--mono)" fill="var(--accent)">Environment: cloud</text>
<!-- lane: devcontainer -->
<rect x="295" y="16" width="250" height="150" rx="10" fill="var(--surface)" stroke="var(--line)"/>
<text x="310" y="42" font-size="15" font-weight="700" fill="var(--ink)">▣ Dev Container</text>
<text x="310" y="60" font-size="11.5" fill="var(--ink-soft)">VS Code + Docker Desktop, or Codespaces</text>
<text x="310" y="84" font-size="12" fill="var(--ink)">• toolchain pinned in the container</text>
<text x="310" y="102" font-size="12" fill="var(--ink)">• headless: CLI writes, mxbuild gate</text>
<text x="310" y="120" font-size="12" fill="var(--ink)">• see the app on localhost</text>
<text x="310" y="138" font-size="12" fill="var(--pass-ink)">• on your disk, nothing ephemeral</text>
<text x="310" y="156" font-size="11" font-family="var(--mono)" fill="var(--accent)">Environment: devcontainer</text>
<!-- lane: local -->
<rect x="575" y="16" width="250" height="150" rx="10" fill="var(--surface)" stroke="var(--accent)" stroke-width="1.5"/>
<text x="590" y="42" font-size="15" font-weight="700" fill="var(--ink)">⌂ Local + Studio Pro</text>
<text x="590" y="60" font-size="11.5" fill="var(--ink-soft)">Mac terminal, or Git Bash on Windows</text>
<text x="590" y="84" font-size="12" fill="var(--ink)">• everything the other two do, plus:</text>
<text x="590" y="102" font-size="12" fill="var(--ink)">• MCP + MDL live edits, hand-rolled MCP</text>
<text x="590" y="120" font-size="12" fill="var(--ink)">• Studio-Pro-only ops (settings, security)</text>
<text x="590" y="138" font-size="12" fill="var(--ink)">• UI polish with the app in front of you</text>
<text x="590" y="156" font-size="11" font-family="var(--mono)" fill="var(--accent)">Environment: local</text>
<!-- arrows to shared -->
<path d="M140,166 L140,205 Q140,215 150,215 L400,215" fill="none" stroke="var(--ink-faint)" stroke-width="1.5" marker-start="url(#arr)"/>
<path d="M420,166 L420,225" fill="none" stroke="var(--ink-faint)" stroke-width="1.5" marker-start="url(#arr)" marker-end="url(#arr)"/>
<path d="M700,166 L700,205 Q700,215 690,215 L440,215" fill="none" stroke="var(--ink-faint)" stroke-width="1.5" marker-start="url(#arr)"/>
<text x="420" y="205" font-size="11" fill="var(--ink-faint)" text-anchor="middle">switch any time — same files</text>
<!-- shared -->
<rect x="190" y="228" width="460" height="64" rx="10" fill="var(--ink)"/>
<text x="420" y="254" font-size="14" font-weight="700" fill="#e2e8f0" text-anchor="middle">ONE project folder · one git repo · one .mpr</text>
<text x="420" y="276" font-size="11.5" fill="#cbd5e1" text-anchor="middle">PROJECT.md, gates, dashboard and toolkit clone are identical in every lane</text>
<!-- windows inset -->
<rect x="15" y="320" width="400" height="204" rx="10" fill="var(--surface)" stroke="var(--line)"/>
<text x="30" y="346" font-size="14" font-weight="700" fill="var(--ink)">Windows, specifically</text>
<text x="30" y="364" font-size="11.5" fill="var(--ink-soft)">Two different things both say "WSL". They don't conflict.</text>
<rect x="30" y="378" width="370" height="58" rx="6" fill="var(--pass-bg)"/>
<text x="42" y="397" font-size="12" font-weight="700" fill="var(--pass-ink)">✓ Docker Desktop runs on a WSL2 backend</text>
<text x="42" y="413" font-size="11.5" fill="var(--pass-ink)">VS Code asks "install Docker on WSL?" when you reopen an</text>
<text x="42" y="428" font-size="11.5" fill="var(--pass-ink)">mxcli new project in its Dev Container → say Yes. That's the ▣ lane.</text>
<rect x="30" y="444" width="370" height="66" rx="6" fill="var(--fail-bg)"/>
<text x="42" y="463" font-size="12" font-weight="700" fill="var(--fail-ink)">✗ A WSL prompt as YOUR shell, next to Studio Pro</text>
<text x="42" y="479" font-size="11.5" fill="var(--fail-ink)">WSL is a separate Linux machine: it can't see Studio Pro or the</text>
<text x="42" y="494" font-size="11.5" fill="var(--fail-ink)">process holding your .mpr. For the ⌂ lane, type in Git Bash —</text>
<text x="42" y="507" font-size="11.5" fill="var(--fail-ink)">same filesystem and process space as Studio Pro and mxcli.</text>
<!-- rhythm inset -->
<rect x="435" y="320" width="390" height="204" rx="10" fill="var(--surface)" stroke="var(--line)"/>
<text x="450" y="346" font-size="14" font-weight="700" fill="var(--ink)">A typical rhythm</text>
<text x="450" y="364" font-size="11.5" fill="var(--ink-soft)">Build where it's reproducible, polish where you can see it.</text>
<rect x="450" y="380" width="150" height="54" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="525" y="400" font-size="12" font-weight="700" fill="var(--ink)" text-anchor="middle">☁︎ / ▣ build</text>
<text x="525" y="416" font-size="11" fill="var(--ink-soft)" text-anchor="middle">stages 1–6, CLI scaffolds,</text>
<text x="525" y="428" font-size="11" fill="var(--ink-soft)" text-anchor="middle">mxbuild gate, commit</text>
<rect x="660" y="380" width="150" height="54" rx="6" fill="var(--bg)" stroke="var(--accent)"/>
<text x="735" y="400" font-size="12" font-weight="700" fill="var(--ink)" text-anchor="middle">⌂ polish</text>
<text x="735" y="416" font-size="11" fill="var(--ink-soft)" text-anchor="middle">open the same .mpr in SP,</text>
<text x="735" y="428" font-size="11" fill="var(--ink-soft)" text-anchor="middle">MCP edits, settings, UI</text>
<path d="M600,392 L660,392" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr-accent)"/>
<path d="M660,424 L600,424" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr-accent)"/>
<text x="630" y="375" font-size="10" fill="var(--accent)" text-anchor="middle">push, then open</text>
<text x="630" y="446" font-size="10" fill="var(--accent)" text-anchor="middle">close SP, then pull</text>
<rect x="450" y="456" width="360" height="38" rx="8" fill="var(--warn-bg)"/>
<text x="630" y="472" font-size="11.5" font-weight="700" fill="var(--warn-ink)" text-anchor="middle">ONE WRITER AT A TIME</text>
<text x="630" y="487" font-size="11" fill="var(--warn-ink)" text-anchor="middle">never build in the container while Studio Pro holds the .mpr</text>
<text x="450" y="510" font-size="11" fill="var(--ink-soft)">Switching lanes: skills/handoff-to-studio-pro.md (warns before an .mpr upgrade).</text>
</svg>
<h3>"Why a Dev Container instead of just working locally?"</h3>
<table>
<tr><th></th><th>☁︎ Cloud</th><th>▣ Dev Container</th><th>⌂ Local + Studio Pro</th></tr>
<tr><td><strong>You install</strong></td><td>nothing</td><td>Docker Desktop + VS Code (Windows: Docker's WSL2 backend — say Yes)</td><td>Java, mxcli, Studio Pro (Windows: Git for Windows too)</td></tr>
<tr><td><strong>Toolchain</strong></td><td>pinned per session</td><td>pinned in <code>.devcontainer/</code> — same Java, Node, mxcli for everyone on the team</td><td>whatever is on your machine; you keep it aligned</td></tr>
<tr><td><strong>Write modes</strong></td><td>CLI</td><td>CLI</td><td>CLI + MCP + hand-rolled MCP</td></tr>
<tr><td><strong>Studio Pro</strong></td><td>no</td><td>no — open the same <code>.mpr</code> locally when you need it</td><td>yes</td></tr>
<tr><td><strong>See the app</strong></td><td>preview URL (<code>--hub</code>)</td><td>localhost</td><td>localhost, or from Studio Pro</td></tr>
<tr><td><strong>Survives a closed laptop</strong></td><td>only what you pushed</td><td>yes, it's your disk</td><td>yes</td></tr>
<tr><td><strong>Reach for it when</strong></td><td>you have nothing set up, or want a stakeholder preview link</td><td>you want a reproducible headless build, a clean machine, or a Mac/Linux without Studio Pro</td><td>UI polish, live MCP edits, Studio-Pro-only settings, the final look</td></tr>
</table>
<p style="font-size:13.5px; color:var(--ink-soft); margin-top:10px;"><strong>Short answer:</strong> the Dev Container is where the build is <em>reproducible</em> — a colleague clones and gets the identical toolchain. Local is where the build is <em>visible</em> — Studio Pro open, MCP live. Most projects use both, and nothing about the project changes when you switch.</p>
<h2>6 · Where everything lands</h2>
<pre class="tree"><project-root>/ <span class="c">← ONE folder per project — everything lives inside it</span>
PROJECT.md <span class="c">← every decision, assumption, and open question</span>
intake.md · assessment.md · triage.md
index.html <span class="c">← your dashboard — open this anytime to see where you are</span>
source/ <span class="c">← your original source or requirements docs, read-only</span>
analysis/<source-name>/
knowledge-base/ <span class="c">← extraction JSON + BRDs</span>
architecture/ · design/ <span class="c">← diagrams, fit-gap, design system, build plan</span>
<Project>.mpr <span class="c">← the target Mendix app</span>
<span class="c">The toolkit clone (~/Mendix/mxcli-project-toolkit) stays elsewhere and stays clean —
nothing of yours ever lands in it. And analysis/ is INSIDE your project folder,
never a sibling next to it.</span></pre>
<p style="font-size:13.5px; color:var(--ink-soft);">The dashboard regenerates from real project files every time a gate check runs (<code>bin/gate-check.sh</code>) — it can't drift from reality, because it's derived from it.</p>
<h2>7 · Something looks broken? Don't panic — it's designed for this</h2>
<div class="cards">
<div class="card panic">
<h3>“Studio Pro won't open / the project fails to load”</h3>
<p>A bad write happened — and the toolkit snapshotted automatically before it. Tell the agent: <span class="kbd">The project won't load — restore the last snapshot.</span> It runs <code>bin/restore-mpr.sh</code>, which restores both halves of the project together. You've lost at most one batch of changes.</p>
</div>
<div class="card panic">
<h3>“Studio Pro won't start / hangs on launch”</h3>
<p>Almost always a stale background process from the last session. Tell the agent: <span class="kbd">SP won't start — kill any stale Studio Pro processes.</span> That's the entire problem 95% of the time; a leftover <code>.mpr.lock</code> file is the other 5%.</p>
</div>
</div>
<p style="font-size:13.5px; color:var(--ink-soft); margin-top:10px;">Nothing here requires reinstalling anything or starting over. Git commits at every phase gate are the real safety history.</p>
<h2>8 · For agents: this page is also the shared HTML shell</h2>
<p style="font-size:14px;">Every stage HTML surface (<code>triage.html</code>, <code>architecture/blueprint.html</code>, <code>build-plan.html</code>, <code>test-report.html</code>, …) copies this file's <code>:root</code> token block and base styles, so all project artifacts look like one system. Once Stage 3 produces <code>design/design-system.html</code>, that file's tokens supersede these for artifacts generated afterwards. Copying the tokens does <em>not</em> mean opening this page: opening is governed by the first-touch rule in <code>CLAUDE.md</code> — only when <code><project-root>/.claude/.guide-shown</code> is absent, and <code>touch</code> it immediately after.</p>
<h2>9 · First session on your harness — flip one setting</h2>
<p style="font-size:13.5px; color:var(--ink-soft);">The AGENT-side default (whether it asks before a listed write) is one knob, <code>bin/exec-approval.sh</code> — rule text lives once, in <code>bin/lib/wiring-item3.sh</code>, not here. This page covers the other half: the HARNESS you're running in also prompts before it will even run <code>bin/exec.sh</code>, separately, unless you tell it not to. <code>bin/init-project.sh</code> and <code>bin/sync-project.sh</code> both call <code>bin/install-harness-permissions.sh</code>, which does this automatically for the harnesses that have a project-level setting for it — this table is what to check or flip by hand if that didn't run, or on a harness that has no project-level setting at all.</p>
<table>
<tr><th>Harness</th><th>The one setting</th><th>Where it lives</th></tr>
<tr><td><strong>Claude Code</strong></td><td>permission mode <code>acceptEdits</code>, plus the allow-list in <code>.claude/settings.json</code> / <code>.claude/settings.local.json</code></td><td>installed automatically; <code>acceptEdits</code> you set yourself (<code>/permissions</code> or <code>--permission-mode acceptEdits</code>) — the allow-list alone doesn't cover file edits, and auto mode's own classifier still blocks a raw model write regardless of allow rules</td></tr>
<tr><td><strong>GitHub Copilot</strong></td><td><code>chat.tools.terminal.autoApprove</code></td><td><code>.vscode/settings.json</code> — installed automatically</td></tr>
<tr><td><strong>Aider</strong></td><td><code>yes-always: true</code></td><td><code>.aider.conf.yml</code> — installed automatically</td></tr>
<tr><td><strong>Cursor</strong></td><td>auto-run / YOLO mode allow-list</td><td>user-level IDE settings — not a project file this toolkit can commit; flip it once per machine</td></tr>
<tr><td><strong>Continue</strong></td><td>tool-approval ("don't ask again")</td><td><code>~/.continue/permissions.yaml</code> — user-level, same as Cursor; flip it once per machine</td></tr>
<tr><td><strong>Windsurf</strong></td><td>Cascade auto-execution allow-list</td><td>user-level IDE settings — same as Cursor, flip it once per machine</td></tr>
</table>
<p style="font-size:13.5px; color:var(--ink-soft); margin-top:10px;">On any harness without a snapshot-and-classify step of its own, <code>bin/exec.sh</code> <em>is</em> the safety net — snapshot first, mxbuild-validate after, auto-restore on failure. Whatever you allow-list, allow-list the wrapper, never a bare <code>./mxcli exec</code>.</p>
<h2 id="wiring">10 · How the assets wire together — what a session reads, in which order</h2>
<p class="lede">Nothing is remembered between sessions. Every fact a session acts on is a file, read in a fixed order, and each file is written by exactly one owner. This is the map of those files. Boxes marked <span class="badge prop">PROPOSED</span> are ideas queued in <code>contrib/inbox/</code> or open PRs — not shipped, do not go looking for them. The company brain shipped as a template on 2026-09-19 (<code>skills/company-brain.md</code>).</p>
<svg viewBox="0 0 880 620" width="100%" style="max-width:880px; display:block; margin:14px 0; font-family:var(--font);" role="img" aria-label="Four layers: toolkit, company brain, project registers, stage chain">
<defs>
<marker id="arr9" markerWidth="10" markerHeight="10" refX="9" refY="5" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L10,5 L0,10 z" fill="var(--accent)"/>
</marker>
<marker id="arr9g" markerWidth="10" markerHeight="10" refX="9" refY="5" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L10,5 L0,10 z" fill="var(--ink-faint)"/>
</marker>
</defs>
<!-- Layer 1: toolkit -->
<text x="0" y="14" font-size="10.5" font-weight="700" fill="var(--ink-faint)" letter-spacing="1">LAYER 1 · THE TOOLKIT — the process, shared, never holds your data</text>
<rect x="0" y="22" width="880" height="64" rx="10" fill="var(--surface)" stroke="var(--line)"/>
<rect x="14" y="34" width="200" height="40" rx="6" fill="var(--bg)" stroke="var(--accent)"/>
<text x="114" y="51" font-size="11.5" font-family="var(--mono)" font-weight="700" fill="var(--accent)" text-anchor="middle">skills/conversion-runbook.md</text>
<text x="114" y="66" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">the spine: stages, gates, entry modes</text>
<rect x="228" y="34" width="200" height="40" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="328" y="51" font-size="11.5" font-family="var(--mono)" font-weight="700" fill="var(--ink)" text-anchor="middle">bin/lib/skill-routing.tsv</text>
<text x="328" y="66" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">rendered into every CLAUDE.local.md</text>
<rect x="442" y="34" width="200" height="40" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="542" y="51" font-size="11.5" font-family="var(--mono)" font-weight="700" fill="var(--ink)" text-anchor="middle">bin/gate-check.sh · status.sh</text>
<text x="542" y="66" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">read the registers, never write them</text>
<rect x="656" y="34" width="210" height="40" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="761" y="51" font-size="11.5" font-family="var(--mono)" font-weight="700" fill="var(--ink)" text-anchor="middle">skills/learned-*.md · bug-logs/</text>
<text x="761" y="66" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">what transfers between any two apps</text>
<!-- Layer 2: company brain -->
<text x="0" y="112" font-size="10.5" font-weight="700" fill="var(--ink-faint)" letter-spacing="1">LAYER 2 · THE COMPANY BRAIN — yours, private, same shape as the toolkit</text>
<rect x="0" y="120" width="880" height="64" rx="10" fill="var(--surface)" stroke="var(--pass-ink)"/>
<rect x="700" y="126" width="168" height="18" rx="9" fill="var(--pass-bg)"/>
<text x="784" y="139" font-size="10" font-weight="700" fill="var(--pass-ink)" text-anchor="middle">TEMPLATE SHIPPED · 2026-09-19</text>
<text x="14" y="142" font-size="12" font-weight="700" fill="var(--ink)">own skills · naming conventions · lint rules · MDL snippets · design system · approved MPK catalog</text>
<text x="14" y="158" font-size="11" fill="var(--ink-soft)">Wired by one ~40-word pointer row in CLAUDE.local.md; its own routing table loads on demand. Curated by the company, by hand,</text>
<text x="14" y="173" font-size="11" fill="var(--ink-soft)">from each project's outbox. Client names are allowed here; personal data, credentials and local paths never.</text>
<!-- Layer 3: project registers -->
<text x="0" y="210" font-size="10.5" font-weight="700" fill="var(--ink-faint)" letter-spacing="1">LAYER 3 · PROJECT REGISTERS — read by every stage, written by no stage alone</text>
<rect x="0" y="218" width="880" height="96" rx="10" fill="var(--surface)" stroke="var(--line)"/>
<rect x="14" y="230" width="200" height="72" rx="6" fill="var(--bg)" stroke="var(--accent)" stroke-width="1.5"/>
<text x="114" y="248" font-size="12" font-family="var(--mono)" font-weight="700" fill="var(--accent)" text-anchor="middle">PROJECT.md</text>
<text x="114" y="264" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">every gate answer: stage, entry mode,</text>
<text x="114" y="278" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">CONFIRMED / ASSUMED, waivers</text>
<text x="114" y="294" font-size="10" fill="var(--accent)" text-anchor="middle">gate-check reads it — the only register it parses</text>
<rect x="228" y="230" width="200" height="72" rx="6" fill="var(--bg)" stroke="var(--accent)" stroke-width="1.5"/>
<text x="328" y="248" font-size="12" font-family="var(--mono)" font-weight="700" fill="var(--accent)" text-anchor="middle">docs/brain/ (mxcli brain)</text>
<text x="328" y="264" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">what a session learned: a pattern and its</text>
<text x="328" y="278" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">why, anchored to @Module.Element</text>
<text x="328" y="294" font-size="10" fill="var(--accent)" text-anchor="middle">brain check fails when the anchor dies</text>
<rect x="442" y="230" width="200" height="72" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="542" y="248" font-size="12" font-family="var(--mono)" font-weight="700" fill="var(--ink)" text-anchor="middle">coverage ledger</text>
<text x="542" y="264" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">every BRD leaf claimed by a build-plan</text>
<text x="542" y="278" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">row, or catalogued as not built</text>
<text x="542" y="294" font-size="10" fill="var(--warn-ink)" text-anchor="middle">brain plan may replace it — research, PR #93</text>
<rect x="656" y="230" width="210" height="72" rx="6" fill="var(--bg)" stroke="var(--fail-ink)"/>
<text x="761" y="248" font-size="12" font-family="var(--mono)" font-weight="700" fill="var(--fail-ink)" text-anchor="middle">docs/open-questions.html</text>
<text x="761" y="264" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">anything the pipeline could not settle,</text>
<text x="761" y="278" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">batched per gate by bin/open-questions.sh</text>
<text x="761" y="294" font-size="10" fill="var(--fail-ink)" text-anchor="middle">blocks the gate while anything is unanswered</text>
<!-- arrows registers -> chain -->
<path d="M114,314 L114,352" fill="none" stroke="var(--ink-faint)" stroke-width="1.2" stroke-dasharray="3 3" marker-end="url(#arr9g)"/>
<path d="M328,314 L328,352" fill="none" stroke="var(--ink-faint)" stroke-width="1.2" stroke-dasharray="3 3" marker-end="url(#arr9g)"/>
<path d="M542,314 L542,352" fill="none" stroke="var(--ink-faint)" stroke-width="1.2" stroke-dasharray="3 3" marker-end="url(#arr9g)"/>
<path d="M761,314 L761,352" fill="none" stroke="var(--ink-faint)" stroke-width="1.2" stroke-dasharray="3 3" marker-end="url(#arr9g)"/>
<!-- Layer 4: stage chain -->
<rect x="0" y="336" width="470" height="15" fill="var(--bg)"/>
<text x="0" y="346" font-size="10.5" font-weight="700" fill="var(--ink-faint)" letter-spacing="1">LAYER 4 · THE STAGE CHAIN — each stage reads only the one before it, on disk</text>
<rect x="0" y="354" width="880" height="80" rx="10" fill="var(--surface)" stroke="var(--line)"/>
<g font-size="11" font-family="var(--mono)" font-weight="700" text-anchor="middle">
<rect x="10" y="366" width="128" height="56" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="74" y="386" fill="var(--ink)">source/</text>
<text x="74" y="402" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">read only, never edited</text>
<path d="M138,394 L154,394" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="156" y="366" width="128" height="56" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="220" y="386" fill="var(--ink)">knowledge-base/</text>
<text x="220" y="402" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">the extraction · stage 1</text>
<path d="M284,394 L300,394" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="302" y="366" width="128" height="56" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="366" y="386" fill="var(--ink)">brd/*.brd.json</text>
<text x="366" y="402" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">requirements · stage 2</text>
<path d="M430,394 L446,394" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="448" y="366" width="128" height="56" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="512" y="386" fill="var(--ink)">architecture/ design/</text>
<text x="512" y="402" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">blueprint, wireframes · stage 3</text>
<path d="M576,394 L592,394" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="594" y="366" width="128" height="56" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="658" y="386" fill="var(--ink)">build-plan.md</text>
<text x="658" y="402" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">the ordered work · stage 4</text>
<path d="M722,394 L738,394" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="740" y="366" width="128" height="56" rx="6" fill="var(--bg)" stroke="var(--accent)" stroke-width="1.5"/>
<text x="804" y="386" fill="var(--accent)"><Module>-brief.md</text>
<text x="804" y="402" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">the ONE file the build opens</text>
</g>
<text x="440" y="448" font-size="10.5" fill="var(--ink-soft)" text-anchor="middle">The brief is assembled per module from BRD + wireframes + blueprint + build plan. It points at those files rather than copying them, so a changed wireframe never means a rewritten brief.</text>
<!-- Layer 5: build & prove -->
<text x="0" y="482" font-size="10.5" font-weight="700" fill="var(--ink-faint)" letter-spacing="1">THEN · BUILD AND PROVE — stage 5 and 6, per module, every result back into a file</text>
<rect x="0" y="490" width="880" height="64" rx="10" fill="var(--surface)" stroke="var(--line)"/>
<g font-size="11" font-family="var(--mono)" font-weight="700" text-anchor="middle">
<rect x="10" y="500" width="160" height="44" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="90" y="518" fill="var(--ink)">mdlsource/*.mdl</text>
<text x="90" y="534" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">via bin/exec.sh: snapshot first</text>
<path d="M170,522 L186,522" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="188" y="500" width="160" height="44" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="268" y="518" fill="var(--ink)"><App>.mpr</text>
<text x="268" y="534" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">mxbuild validates after</text>
<path d="M348,522 L364,522" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="366" y="500" width="160" height="44" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="446" y="518" fill="var(--ink)">docs/BUILD-LOG.md</text>
<text x="446" y="534" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">append-only, one row per exec</text>
<path d="M526,522 L542,522" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="544" y="500" width="160" height="44" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="624" y="518" fill="var(--ink)">docs/report.json</text>
<text x="624" y="534" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">every instrument appends here</text>
<path d="M704,522 L720,522" fill="none" stroke="var(--accent)" stroke-width="1.5" marker-end="url(#arr9)"/>
<rect x="722" y="500" width="146" height="44" rx="6" fill="var(--bg)" stroke="var(--line)"/>
<text x="795" y="518" fill="var(--ink)">index.html</text>
<text x="795" y="534" font-size="10" font-family="var(--font)" font-weight="400" fill="var(--ink-soft)">regenerated by gate-check</text>
</g>
<!-- Prerequisites gate -->
<rect x="0" y="572" width="880" height="42" rx="10" fill="var(--surface)" stroke="var(--warn-ink)" stroke-dasharray="5 4"/>
<rect x="740" y="578" width="128" height="18" rx="9" fill="var(--warn-bg)"/>
<text x="804" y="591" font-size="10" font-weight="700" fill="var(--warn-ink)" text-anchor="middle">PROPOSED · inbox</text>
<text x="14" y="590" font-size="12" font-weight="700" fill="var(--ink)">Prerequisites card — before any "full X" task outside the pipeline (full e2e, full UI loop, full audit)</text>
<text x="14" y="606" font-size="10.5" fill="var(--ink-soft)">App reachable, a credential per persona, seed data, a denominator, a pass bar — checked or asked once, answers kept in docs/brain/, before a single token is spent on the run.</text>
</svg>
<h3>Who writes what — one owner per file</h3>
<table>
<tr><th>File</th><th>Written by</th><th>Read by</th><th>What breaks if it's stale</th></tr>
<tr><td><code>PROJECT.md</code></td><td>the agent at a gate, after asking you</td><td><code>gate-check.sh</code>, <code>checkpoint.sh</code>, every stage</td><td>a stage runs on a decision you never saw; gates block on <code>UNSYNCED</code></td></tr>
<tr><td><code>docs/brain/</code></td><td><code>mxcli brain capture</code> when a session learns something</td><td>the next session, <code>brain check</code> before every commit</td><td>the next session reasonably decides the opposite</td></tr>
<tr><td>coverage ledger</td><td>Stage 4, from build-plan <code>claims</code></td><td>Stage 4 gate, Stage 5 build rows</td><td>a requirement is silently neither built nor descoped</td></tr>
<tr><td><code>docs/open-questions.html</code></td><td><code>bin/open-questions.sh</code>, from BRD <code>openQuestions</code> + SME notes</td><td>you, at every gate</td><td>a product decision gets taken in a file nobody opens</td></tr>
<tr><td><code>brd/*.brd.json</code></td><td>Stage 2 (extractor, KB, interview or by hand)</td><td>Stage 3, 4, the brief, the ledger</td><td>the build drifts from the requirement — see the drift-sync rule</td></tr>
<tr><td><code><Module>-brief.md</code></td><td>ba-agent (roles, screens, rules) + architect (entities, dependencies, stubs)</td><td>the build agent, first, for that module only</td><td>the build agent improvises what nobody wrote down</td></tr>
<tr><td><code>docs/BUILD-LOG.md</code> · <code>docs/report.json</code></td><td><code>bin/exec.sh</code> and every instrument</td><td><code>status.sh</code>, <code>index.html</code>, the test-result audit</td><td>"done" becomes a claim instead of a record</td></tr>
<tr><td>company brain (<code>templates/company-brain/</code>)</td><td>the company, by hand, from each project's outbox</td><td>ba-agent and architect before writing a brief; any session, on demand</td><td>each project re-invents the convention</td></tr>
</table>
<p style="font-size:13.5px; color:var(--ink-soft); margin-top:10px;"><strong>The rule under all of it:</strong> a session starts by reading, in this order — the toolkit's runbook, then the project registers, then the one stage artifact before it — and starts a new session at each stage boundary instead of running one all day. Memory is never a source; if it isn't on disk, it didn't happen.</p>
<div class="footer">mxcli-project-toolkit · toolkit-guide.html · The detailed, executable version of this page is <code>skills/conversion-runbook.md</code>; the thin text pointer is <code>CONVERSION-RUNBOOK.md</code>.</div>
</div>
</body>
</html>