@zigrivers/scaffold 3.29.0 → 3.31.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.
Files changed (86) hide show
  1. package/content/guides/AUTHORING.md +146 -0
  2. package/content/guides/cli/index.html +1855 -0
  3. package/content/guides/cli/index.md +206 -0
  4. package/content/guides/concepts/index.html +1970 -0
  5. package/content/guides/concepts/index.md +347 -0
  6. package/content/guides/dashboard/index.html +1913 -0
  7. package/content/guides/dashboard/index.md +264 -0
  8. package/content/guides/index.html +368 -15
  9. package/content/guides/install/.diagrams/diagram-0.svg +1 -0
  10. package/content/guides/install/.diagrams/manifest.json +3 -0
  11. package/content/guides/install/index.html +1653 -0
  12. package/content/guides/install/index.md +186 -0
  13. package/content/guides/knowledge/.diagrams/diagram-0.svg +1 -0
  14. package/content/guides/knowledge/.diagrams/manifest.json +3 -0
  15. package/content/guides/knowledge/index.html +1765 -0
  16. package/content/guides/knowledge/index.md +209 -0
  17. package/content/guides/knowledge-freshness/.diagrams/diagram-0.svg +1 -0
  18. package/content/guides/knowledge-freshness/.diagrams/manifest.json +3 -0
  19. package/content/guides/knowledge-freshness/index.html +2795 -0
  20. package/content/guides/knowledge-freshness/index.md +893 -0
  21. package/content/guides/mmr/index.html +407 -36
  22. package/content/guides/mmr/index.md +39 -16
  23. package/content/guides/multi-agent/.diagrams/diagram-0.svg +1 -0
  24. package/content/guides/multi-agent/.diagrams/manifest.json +3 -0
  25. package/content/guides/multi-agent/index.html +1715 -0
  26. package/content/guides/multi-agent/index.md +243 -0
  27. package/content/guides/observability/.diagrams/diagram-0.svg +1 -0
  28. package/content/guides/observability/.diagrams/diagram-1.svg +1 -0
  29. package/content/guides/observability/.diagrams/diagram-2.svg +1 -0
  30. package/content/guides/observability/.diagrams/diagram-3.svg +1 -0
  31. package/content/guides/observability/.diagrams/manifest.json +6 -0
  32. package/content/guides/observability/index.html +3257 -0
  33. package/content/guides/observability/index.md +1097 -0
  34. package/content/guides/pipeline/.diagrams/diagram-0.svg +1 -0
  35. package/content/guides/pipeline/.diagrams/diagram-1.svg +1 -0
  36. package/content/guides/pipeline/.diagrams/manifest.json +4 -0
  37. package/content/guides/pipeline/index.html +1973 -0
  38. package/content/guides/pipeline/index.md +387 -0
  39. package/content/guides/review-workflow/.diagrams/diagram-0.svg +1 -0
  40. package/content/guides/review-workflow/.diagrams/diagram-1.svg +1 -0
  41. package/content/guides/review-workflow/.diagrams/manifest.json +4 -0
  42. package/content/guides/review-workflow/index.html +1790 -0
  43. package/content/guides/review-workflow/index.md +248 -0
  44. package/dist/guides/build.d.ts +1 -1
  45. package/dist/guides/build.d.ts.map +1 -1
  46. package/dist/guides/build.js +21 -9
  47. package/dist/guides/build.js.map +1 -1
  48. package/dist/guides/build.test.js +47 -0
  49. package/dist/guides/build.test.js.map +1 -1
  50. package/dist/guides/chrome.d.ts.map +1 -1
  51. package/dist/guides/chrome.js +83 -12
  52. package/dist/guides/chrome.js.map +1 -1
  53. package/dist/guides/dashboard-theme.css +8 -0
  54. package/dist/guides/directives-cite.test.d.ts +2 -0
  55. package/dist/guides/directives-cite.test.d.ts.map +1 -0
  56. package/dist/guides/directives-cite.test.js +26 -0
  57. package/dist/guides/directives-cite.test.js.map +1 -0
  58. package/dist/guides/directives-tabs.test.js +47 -0
  59. package/dist/guides/directives-tabs.test.js.map +1 -1
  60. package/dist/guides/directives.d.ts +1 -0
  61. package/dist/guides/directives.d.ts.map +1 -1
  62. package/dist/guides/directives.js +38 -0
  63. package/dist/guides/directives.js.map +1 -1
  64. package/dist/guides/guides.css +268 -0
  65. package/dist/guides/index-page.d.ts.map +1 -1
  66. package/dist/guides/index-page.js +41 -8
  67. package/dist/guides/index-page.js.map +1 -1
  68. package/dist/guides/links.d.ts +14 -0
  69. package/dist/guides/links.d.ts.map +1 -0
  70. package/dist/guides/links.js +56 -0
  71. package/dist/guides/links.js.map +1 -0
  72. package/dist/guides/links.test.d.ts +2 -0
  73. package/dist/guides/links.test.d.ts.map +1 -0
  74. package/dist/guides/links.test.js +72 -0
  75. package/dist/guides/links.test.js.map +1 -0
  76. package/dist/guides/render.d.ts +1 -0
  77. package/dist/guides/render.d.ts.map +1 -1
  78. package/dist/guides/render.js +1 -1
  79. package/dist/guides/render.js.map +1 -1
  80. package/dist/guides/sanitize.d.ts.map +1 -1
  81. package/dist/guides/sanitize.js +5 -0
  82. package/dist/guides/sanitize.js.map +1 -1
  83. package/dist/guides/template.d.ts.map +1 -1
  84. package/dist/guides/template.js +7 -2
  85. package/dist/guides/template.js.map +1 -1
  86. package/package.json +2 -2
@@ -0,0 +1,1715 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-chrome-version="1">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Parallel Agents &amp; Worktrees</title>
7
+ <!-- scaffold:chrome v1 -->
8
+ <style>/* Scaffold Dashboard Theme
9
+ * All CSS for the generated pipeline dashboard.
10
+ * Embedded into HTML by scripts/generate-dashboard.sh.
11
+ * Design system reference: docs/design-system.md
12
+ *
13
+ * Aesthetic: "Precision Industrial" — Swiss-typographic control room.
14
+ * Deep navy dark mode with indigo accents, clean cool-white light mode.
15
+ */
16
+
17
+ /* ─── Design Tokens (Light Mode) ──────────────── */
18
+ :root {
19
+ /* Surface */
20
+ --bg: #f5f6fa;
21
+ --bg-card: #ffffff;
22
+ --bg-hover: #eef0f6;
23
+ --bg-inset: #e8eaf2;
24
+
25
+ /* Text */
26
+ --text: #1a1d2e;
27
+ --text-muted: #6b7294;
28
+ --text-faint: #9ba1c0;
29
+
30
+ /* Borders & Structure */
31
+ --border: #dde0ed;
32
+ --border-light: #eceef5;
33
+ --radius: 10px;
34
+ --radius-sm: 6px;
35
+
36
+ /* Accent */
37
+ --accent: #4f46e5;
38
+ --accent-hover: #4338ca;
39
+ --accent-glow: rgba(79, 70, 229, 0.10);
40
+
41
+ /* Semantic: Status */
42
+ --green: #059669;
43
+ --green-bg: #ecfdf5;
44
+ --green-border: #a7f3d0;
45
+ --blue: #2563eb;
46
+ --blue-bg: #eff6ff;
47
+ --blue-border: #bfdbfe;
48
+ --yellow: #d97706;
49
+ --yellow-bg: #fffbeb;
50
+ --yellow-border:#fde68a;
51
+ --red: #dc2626;
52
+ --red-bg: #fef2f2;
53
+ --red-border: #fecaca;
54
+ --gray: #9ca3af;
55
+ --gray-bg: #f3f4f6;
56
+ --gray-border: #e5e7eb;
57
+ --scrim: rgba(15, 17, 23, 0.45);
58
+
59
+ /* Semantic: Next Banner */
60
+ --next-bg: #eef2ff;
61
+ --next-border: #4f46e5;
62
+ --next-glow: rgba(79, 70, 229, 0.06);
63
+
64
+ /* Semantic: Progress */
65
+ --progress-bg: #e5e7eb;
66
+ --progress-h: 10px;
67
+
68
+ /* Depth */
69
+ --shadow-sm: 0 1px 2px rgba(30, 34, 60, 0.04);
70
+ --shadow: 0 1px 3px rgba(30, 34, 60, 0.07), 0 1px 2px rgba(30, 34, 60, 0.04);
71
+ --shadow-md: 0 4px 12px rgba(30, 34, 60, 0.08), 0 1px 3px rgba(30, 34, 60, 0.05);
72
+ --shadow-lg: 0 8px 24px rgba(30, 34, 60, 0.10), 0 2px 6px rgba(30, 34, 60, 0.04);
73
+
74
+ /* Spacing scale (4px base) */
75
+ --sp-1: 4px;
76
+ --sp-2: 8px;
77
+ --sp-3: 12px;
78
+ --sp-4: 16px;
79
+ --sp-5: 20px;
80
+ --sp-6: 24px;
81
+ --sp-8: 32px;
82
+ --sp-10: 40px;
83
+
84
+ /* Typography */
85
+ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
86
+ --font-mono: "SF Mono", "Cascadia Code", "Fira Code", "JetBrains Mono", Menlo, Consolas, monospace;
87
+ --text-xs: 0.75rem;
88
+ --text-sm: 0.8125rem;
89
+ --text-base: 0.9375rem;
90
+ --text-lg: 1.125rem;
91
+ --text-xl: 1.375rem;
92
+ --text-2xl: 1.75rem;
93
+ --lh-tight: 1.25;
94
+ --lh-normal: 1.5;
95
+ --lh-relaxed: 1.625;
96
+ --ls-tight: -0.01em;
97
+ --ls-wide: 0.025em;
98
+ --fw-normal: 400;
99
+ --fw-medium: 500;
100
+ --fw-semi: 600;
101
+ --fw-bold: 700;
102
+
103
+ /* Layout */
104
+ --max-w: 960px;
105
+ --page-pad: 24px;
106
+ }
107
+
108
+ /* ─── Design Tokens (Dark Mode) ───────────────── */
109
+ [data-theme="dark"] {
110
+ /* Surface */
111
+ --bg: #0f1117;
112
+ --bg-card: #1a1d2e;
113
+ --bg-hover: #252940;
114
+ --bg-inset: #141724;
115
+
116
+ /* Text */
117
+ --text: #e2e5f0;
118
+ --text-muted: #7c82a8;
119
+ --text-faint: #555c80;
120
+
121
+ /* Borders & Structure */
122
+ --border: #2a2f45;
123
+ --border-light: #21253a;
124
+
125
+ /* Accent */
126
+ --accent: #818cf8;
127
+ --accent-hover: #a5b4fc;
128
+ --accent-glow: rgba(129, 140, 248, 0.12);
129
+
130
+ /* Semantic: Status */
131
+ --green: #34d399;
132
+ --green-bg: rgba(6, 78, 59, 0.25);
133
+ --green-border: rgba(52, 211, 153, 0.25);
134
+ --blue: #60a5fa;
135
+ --blue-bg: rgba(30, 58, 95, 0.30);
136
+ --blue-border: rgba(96, 165, 250, 0.25);
137
+ --yellow: #fbbf24;
138
+ --yellow-bg: rgba(120, 53, 15, 0.25);
139
+ --yellow-border:rgba(251, 191, 36, 0.20);
140
+ --red: #f87171;
141
+ --red-bg: rgba(127, 29, 29, 0.25);
142
+ --red-border: rgba(248, 113, 113, 0.22);
143
+ --gray: #6b7294;
144
+ --gray-bg: #252940;
145
+ --gray-border: #363c58;
146
+ --scrim: rgba(0, 0, 0, 0.6);
147
+
148
+ /* Semantic: Next Banner */
149
+ --next-bg: rgba(30, 27, 75, 0.50);
150
+ --next-border: #818cf8;
151
+ --next-glow: rgba(129, 140, 248, 0.08);
152
+
153
+ /* Semantic: Progress */
154
+ --progress-bg: #1f2337;
155
+
156
+ /* Depth */
157
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.20);
158
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.30), 0 1px 2px rgba(0, 0, 0, 0.15);
159
+ --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.20);
160
+ --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.40), 0 2px 6px rgba(0, 0, 0, 0.20);
161
+ }
162
+
163
+ /* ─── Theme Toggle ───────────────────────────── */
164
+ .theme-toggle {
165
+ background: var(--bg-inset);
166
+ border: 1px solid var(--border);
167
+ border-radius: var(--radius-sm);
168
+ padding: var(--sp-1) var(--sp-2);
169
+ cursor: pointer;
170
+ font-size: var(--text-base);
171
+ line-height: 1;
172
+ color: var(--text-muted);
173
+ transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
174
+ display: flex;
175
+ align-items: center;
176
+ margin-left: auto;
177
+ }
178
+
179
+ .theme-toggle:hover {
180
+ border-color: var(--accent);
181
+ color: var(--accent);
182
+ background: var(--accent-glow);
183
+ }
184
+
185
+ /* ─── Base ────────────────────────────────────── */
186
+ *, *::before, *::after {
187
+ margin: 0;
188
+ padding: 0;
189
+ box-sizing: border-box;
190
+ }
191
+
192
+ body {
193
+ font-family: var(--font-sans);
194
+ font-size: var(--text-base);
195
+ line-height: var(--lh-normal);
196
+ color: var(--text);
197
+ background: var(--bg);
198
+ -webkit-font-smoothing: antialiased;
199
+ -moz-osx-font-smoothing: grayscale;
200
+ }
201
+
202
+ /* ─── Layout ──────────────────────────────────── */
203
+ .wrap {
204
+ max-width: var(--max-w);
205
+ margin: 0 auto;
206
+ padding: var(--sp-8) var(--page-pad);
207
+ }
208
+
209
+ /* ─── Header ──────────────────────────────────── */
210
+ .header {
211
+ display: flex;
212
+ align-items: baseline;
213
+ gap: var(--sp-3);
214
+ margin-bottom: var(--sp-2);
215
+ flex-wrap: wrap;
216
+ }
217
+
218
+ h1 {
219
+ font-size: var(--text-2xl);
220
+ font-weight: var(--fw-bold);
221
+ letter-spacing: var(--ls-tight);
222
+ line-height: var(--lh-tight);
223
+ }
224
+
225
+ h2 {
226
+ font-size: var(--text-lg);
227
+ font-weight: var(--fw-semi);
228
+ letter-spacing: var(--ls-tight);
229
+ line-height: var(--lh-tight);
230
+ margin-bottom: var(--sp-3);
231
+ }
232
+
233
+ .header-meta {
234
+ font-size: var(--text-xs);
235
+ color: var(--text-faint);
236
+ margin-bottom: var(--sp-6);
237
+ letter-spacing: var(--ls-wide);
238
+ text-transform: uppercase;
239
+ }
240
+
241
+ /* ─── Badge ───────────────────────────────────── */
242
+ .badge {
243
+ display: inline-block;
244
+ padding: 2px var(--sp-2);
245
+ border-radius: 99px;
246
+ font-size: var(--text-xs);
247
+ font-weight: var(--fw-semi);
248
+ letter-spacing: var(--ls-wide);
249
+ background: var(--accent);
250
+ color: #fff;
251
+ text-transform: uppercase;
252
+ }
253
+
254
+ .badge-optional {
255
+ background: var(--yellow-bg);
256
+ color: var(--yellow);
257
+ border: 1px solid var(--yellow-border);
258
+ }
259
+
260
+ /* ─── Progress Bar ────────────────────────────── */
261
+ .progress-bar {
262
+ width: 100%;
263
+ height: var(--progress-h);
264
+ background: var(--progress-bg);
265
+ border-radius: 99px;
266
+ overflow: hidden;
267
+ margin-bottom: var(--sp-6);
268
+ display: flex;
269
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.06);
270
+ }
271
+
272
+ .progress-bar .seg-done {
273
+ background: linear-gradient(135deg, var(--green), #10b981);
274
+ box-shadow: 0 0 8px rgba(5, 150, 105, 0.3);
275
+ }
276
+
277
+ .progress-bar .seg-likely {
278
+ background: linear-gradient(135deg, var(--blue), #3b82f6);
279
+ box-shadow: 0 0 8px rgba(37, 99, 235, 0.25);
280
+ }
281
+
282
+ .progress-bar .seg-skip {
283
+ background: var(--gray);
284
+ opacity: 0.7;
285
+ }
286
+
287
+ /* ─── Summary Cards ───────────────────────────── */
288
+ .cards {
289
+ display: grid;
290
+ grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
291
+ gap: var(--sp-3);
292
+ margin-bottom: var(--sp-6);
293
+ }
294
+
295
+ .card {
296
+ background: var(--bg-card);
297
+ border: 1px solid var(--border);
298
+ border-radius: var(--radius);
299
+ padding: var(--sp-4) var(--sp-5);
300
+ box-shadow: var(--shadow);
301
+ transition: box-shadow 0.15s ease, transform 0.15s ease;
302
+ }
303
+
304
+ .card:hover {
305
+ box-shadow: var(--shadow-md);
306
+ transform: translateY(-1px);
307
+ }
308
+
309
+ .card-num {
310
+ font-size: var(--text-2xl);
311
+ font-weight: var(--fw-bold);
312
+ font-family: var(--font-mono);
313
+ letter-spacing: var(--ls-tight);
314
+ line-height: 1;
315
+ }
316
+
317
+ .card-lbl {
318
+ font-size: var(--text-xs);
319
+ color: var(--text-muted);
320
+ margin-top: var(--sp-1);
321
+ letter-spacing: var(--ls-wide);
322
+ text-transform: uppercase;
323
+ font-weight: var(--fw-medium);
324
+ }
325
+
326
+ /* ─── What's Next Banner ──────────────────────── */
327
+ .next-banner {
328
+ background: var(--next-bg);
329
+ border: 1px solid var(--next-border);
330
+ border-left: 4px solid var(--next-border);
331
+ border-radius: var(--radius);
332
+ padding: var(--sp-5) var(--sp-6);
333
+ margin-bottom: var(--sp-6);
334
+ box-shadow: 0 0 0 1px var(--next-glow), var(--shadow);
335
+ position: relative;
336
+ overflow: hidden;
337
+ }
338
+
339
+ .next-banner::before {
340
+ content: "";
341
+ position: absolute;
342
+ top: 0;
343
+ left: 0;
344
+ width: 4px;
345
+ height: 100%;
346
+ background: var(--next-border);
347
+ animation: pulse-border 2.5s ease-in-out infinite;
348
+ }
349
+
350
+ @keyframes pulse-border {
351
+ 0%, 100% { opacity: 1; }
352
+ 50% { opacity: 0.5; }
353
+ }
354
+
355
+ .next-banner h2 {
356
+ color: var(--accent);
357
+ margin-bottom: var(--sp-1);
358
+ font-size: var(--text-base);
359
+ font-weight: var(--fw-semi);
360
+ letter-spacing: var(--ls-wide);
361
+ text-transform: uppercase;
362
+ }
363
+
364
+ .next-banner p {
365
+ color: var(--text);
366
+ font-size: var(--text-base);
367
+ }
368
+
369
+ .next-cmd {
370
+ font-family: var(--font-mono);
371
+ background: var(--bg-card);
372
+ padding: var(--sp-1) var(--sp-3);
373
+ border-radius: var(--radius-sm);
374
+ font-size: var(--text-sm);
375
+ display: inline-flex;
376
+ align-items: center;
377
+ gap: var(--sp-2);
378
+ margin-top: var(--sp-3);
379
+ border: 1px solid var(--border);
380
+ }
381
+
382
+ /* ─── Phase Headers (Collapsible) ─────────────── */
383
+ .phase {
384
+ margin-bottom: var(--sp-6);
385
+ }
386
+
387
+ .phase-hdr {
388
+ display: flex;
389
+ align-items: center;
390
+ gap: var(--sp-2);
391
+ cursor: pointer;
392
+ padding: var(--sp-2) 0;
393
+ user-select: none;
394
+ border-bottom: 2px solid var(--border);
395
+ margin-bottom: var(--sp-3);
396
+ transition: border-color 0.15s ease;
397
+ }
398
+
399
+ .phase-hdr:hover {
400
+ border-bottom-color: var(--accent);
401
+ }
402
+
403
+ .phase-hdr:hover h2 {
404
+ color: var(--accent);
405
+ }
406
+
407
+ .phase-hdr h2 {
408
+ transition: color 0.15s ease;
409
+ }
410
+
411
+ .phase-hdr .arr {
412
+ transition: transform 0.2s ease;
413
+ font-size: var(--text-xs);
414
+ color: var(--text-muted);
415
+ }
416
+
417
+ .phase-hdr.closed .arr {
418
+ transform: rotate(-90deg);
419
+ }
420
+
421
+ .phase-cnt {
422
+ font-size: var(--text-xs);
423
+ font-family: var(--font-mono);
424
+ color: var(--text-faint);
425
+ margin-left: auto;
426
+ letter-spacing: var(--ls-wide);
427
+ }
428
+
429
+ /* ─── Prompt List ─────────────────────────────── */
430
+ .plist {
431
+ display: flex;
432
+ flex-direction: column;
433
+ gap: var(--sp-2);
434
+ }
435
+
436
+ /* ─── Prompt Cards ────────────────────────────── */
437
+ .pcard {
438
+ background: var(--bg-card);
439
+ border: 1px solid var(--border);
440
+ border-radius: var(--radius);
441
+ padding: var(--sp-3) var(--sp-4);
442
+ box-shadow: var(--shadow-sm);
443
+ display: grid;
444
+ grid-template-columns: auto 1fr auto;
445
+ gap: var(--sp-2) var(--sp-3);
446
+ align-items: start;
447
+ transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
448
+ }
449
+
450
+ .pcard:hover {
451
+ box-shadow: var(--shadow);
452
+ transform: translateY(-1px);
453
+ border-color: var(--accent-glow);
454
+ }
455
+
456
+ /* ─── Status Badges ──────────────────────────── */
457
+ .status-badge {
458
+ display: inline-flex;
459
+ align-items: center;
460
+ gap: var(--sp-1);
461
+ font-size: var(--text-xs);
462
+ font-weight: var(--fw-medium);
463
+ padding: 2px var(--sp-2);
464
+ border-radius: 99px;
465
+ white-space: nowrap;
466
+ flex-shrink: 0;
467
+ letter-spacing: var(--ls-wide);
468
+ line-height: var(--lh-tight);
469
+ }
470
+
471
+ .st-completed {
472
+ background: var(--green-bg);
473
+ color: var(--green);
474
+ border: 1px solid var(--green-border);
475
+ }
476
+
477
+ .st-likely-completed {
478
+ background: var(--blue-bg);
479
+ color: var(--blue);
480
+ border: 1px solid var(--blue-border);
481
+ }
482
+
483
+ .st-skipped {
484
+ background: var(--gray-bg);
485
+ color: var(--gray);
486
+ border: 1px solid var(--gray-border);
487
+ }
488
+
489
+ .st-pending {
490
+ background: var(--bg-inset);
491
+ color: var(--text-faint);
492
+ border: 1px solid var(--border);
493
+ }
494
+
495
+ /* ─── Status Legend ──────────────────────────── */
496
+ .status-legend {
497
+ display: flex;
498
+ flex-wrap: wrap;
499
+ gap: var(--sp-2);
500
+ margin-bottom: var(--sp-4);
501
+ padding: var(--sp-2) 0;
502
+ }
503
+
504
+ .status-legend .status-badge {
505
+ cursor: default;
506
+ }
507
+
508
+ /* ─── Prompt Card Inner ───────────────────────── */
509
+ .pinfo {
510
+ min-width: 0;
511
+ }
512
+
513
+ .pname {
514
+ font-weight: var(--fw-semi);
515
+ font-size: var(--text-base);
516
+ }
517
+
518
+ .pstep {
519
+ font-size: var(--text-xs);
520
+ font-family: var(--font-mono);
521
+ color: var(--text-faint);
522
+ letter-spacing: var(--ls-wide);
523
+ }
524
+
525
+ .pdesc {
526
+ font-size: var(--text-sm);
527
+ color: var(--text-muted);
528
+ margin-top: 2px;
529
+ line-height: var(--lh-relaxed);
530
+ }
531
+
532
+ .pdesc-long {
533
+ font-size: var(--text-xs);
534
+ color: var(--text-faint);
535
+ margin-top: 2px;
536
+ }
537
+
538
+ .pdeps {
539
+ font-size: var(--text-xs);
540
+ color: var(--yellow);
541
+ margin-top: var(--sp-1);
542
+ font-weight: var(--fw-medium);
543
+ }
544
+
545
+ /* ─── Copy Command Button ─────────────────────── */
546
+ .pcmd {
547
+ font-family: var(--font-mono);
548
+ font-size: var(--text-xs);
549
+ background: var(--bg-inset);
550
+ padding: 3px var(--sp-2);
551
+ border-radius: var(--radius-sm);
552
+ cursor: pointer;
553
+ border: 1px solid var(--border);
554
+ white-space: nowrap;
555
+ align-self: center;
556
+ color: var(--text-muted);
557
+ transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
558
+ letter-spacing: var(--ls-wide);
559
+ }
560
+
561
+ .pcmd:hover {
562
+ border-color: var(--accent);
563
+ color: var(--accent);
564
+ background: var(--accent-glow);
565
+ }
566
+
567
+ .pcmd.copied {
568
+ border-color: var(--green);
569
+ color: var(--green);
570
+ background: var(--green-bg);
571
+ }
572
+
573
+ /* ─── Prompt Modal ────────────────────────────── */
574
+ .modal-overlay {
575
+ position: fixed;
576
+ inset: 0;
577
+ background: rgba(0, 0, 0, 0.6);
578
+ display: flex;
579
+ align-items: center;
580
+ justify-content: center;
581
+ z-index: 1000;
582
+ padding: var(--sp-4);
583
+ }
584
+
585
+ .modal {
586
+ background: var(--bg-card);
587
+ border: 1px solid var(--border);
588
+ border-radius: var(--radius);
589
+ box-shadow: var(--shadow-lg);
590
+ max-width: 720px;
591
+ width: 100%;
592
+ max-height: 85vh;
593
+ display: flex;
594
+ flex-direction: column;
595
+ }
596
+
597
+ .modal-header {
598
+ display: flex;
599
+ align-items: center;
600
+ gap: var(--sp-3);
601
+ padding: var(--sp-4) var(--sp-5);
602
+ border-bottom: 1px solid var(--border);
603
+ flex-shrink: 0;
604
+ }
605
+
606
+ .modal-header h3 {
607
+ font-size: var(--text-lg);
608
+ font-weight: var(--fw-semi);
609
+ flex: 1;
610
+ min-width: 0;
611
+ }
612
+
613
+ .modal-close {
614
+ background: var(--bg-inset);
615
+ border: 1px solid var(--border);
616
+ border-radius: var(--radius-sm);
617
+ padding: var(--sp-1) var(--sp-2);
618
+ cursor: pointer;
619
+ font-size: var(--text-base);
620
+ color: var(--text-muted);
621
+ line-height: 1;
622
+ transition: border-color 0.15s ease, color 0.15s ease;
623
+ }
624
+
625
+ .modal-close:hover {
626
+ border-color: var(--accent);
627
+ color: var(--accent);
628
+ }
629
+
630
+ .modal-body {
631
+ padding: var(--sp-5);
632
+ overflow-y: auto;
633
+ flex: 1;
634
+ }
635
+
636
+ .modal-body pre {
637
+ font-family: var(--font-mono);
638
+ font-size: var(--text-sm);
639
+ line-height: var(--lh-relaxed);
640
+ white-space: pre-wrap;
641
+ word-break: break-word;
642
+ color: var(--text);
643
+ }
644
+
645
+ .modal-body pre .md-heading {
646
+ font-weight: var(--fw-bold);
647
+ color: var(--accent);
648
+ }
649
+
650
+ .modal-body pre .md-code {
651
+ background: var(--bg-inset);
652
+ padding: 1px 4px;
653
+ border-radius: 3px;
654
+ font-size: var(--text-xs);
655
+ }
656
+
657
+ .modal-footer {
658
+ display: flex;
659
+ gap: var(--sp-2);
660
+ padding: var(--sp-3) var(--sp-5);
661
+ border-top: 1px solid var(--border);
662
+ flex-shrink: 0;
663
+ }
664
+
665
+ .modal-copy-btn {
666
+ background: var(--accent);
667
+ color: #fff;
668
+ border: none;
669
+ border-radius: var(--radius-sm);
670
+ padding: var(--sp-2) var(--sp-4);
671
+ font-size: var(--text-sm);
672
+ font-weight: var(--fw-medium);
673
+ cursor: pointer;
674
+ transition: background 0.15s ease;
675
+ }
676
+
677
+ .modal-copy-btn:hover {
678
+ background: var(--accent-hover);
679
+ }
680
+
681
+ .modal-copy-btn.copied {
682
+ background: var(--green);
683
+ }
684
+
685
+ /* ─── Beads Task Section ─────────────────────── */
686
+ .beads-section {
687
+ margin-top: var(--sp-8);
688
+ margin-bottom: var(--sp-6);
689
+ }
690
+
691
+ .beads-filters {
692
+ display: flex;
693
+ gap: var(--sp-2);
694
+ margin-bottom: var(--sp-3);
695
+ }
696
+
697
+ .beads-filter {
698
+ background: var(--bg-inset);
699
+ border: 1px solid var(--border);
700
+ border-radius: 99px;
701
+ padding: var(--sp-1) var(--sp-3);
702
+ font-size: var(--text-xs);
703
+ font-weight: var(--fw-medium);
704
+ color: var(--text-muted);
705
+ cursor: pointer;
706
+ transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
707
+ letter-spacing: var(--ls-wide);
708
+ }
709
+
710
+ .beads-filter:hover {
711
+ border-color: var(--accent);
712
+ color: var(--accent);
713
+ }
714
+
715
+ .beads-filter.active {
716
+ background: var(--accent);
717
+ color: #fff;
718
+ border-color: var(--accent);
719
+ }
720
+
721
+ /* ─── Beads Status Badges ────────────────────── */
722
+ .st-bead-open {
723
+ background: var(--accent-glow);
724
+ color: var(--accent);
725
+ border: 1px solid var(--accent);
726
+ }
727
+
728
+ .st-bead-progress {
729
+ background: var(--blue-bg);
730
+ color: var(--blue);
731
+ border: 1px solid var(--blue-border);
732
+ }
733
+
734
+ .st-bead-blocked {
735
+ background: var(--yellow-bg);
736
+ color: var(--yellow);
737
+ border: 1px solid var(--yellow-border);
738
+ }
739
+
740
+ .st-bead-deferred {
741
+ background: var(--gray-bg);
742
+ color: var(--gray);
743
+ border: 1px solid var(--gray-border);
744
+ }
745
+
746
+ .st-bead-closed {
747
+ background: var(--green-bg);
748
+ color: var(--green);
749
+ border: 1px solid var(--green-border);
750
+ }
751
+
752
+ /* ─── Beads Filter Separator ─────────────────── */
753
+ .beads-filter-sep {
754
+ width: 1px;
755
+ background: var(--border);
756
+ align-self: stretch;
757
+ margin: 0 var(--sp-1);
758
+ }
759
+
760
+ /* ─── Beads Priority Filter ──────────────────── */
761
+ .beads-prio-filter {
762
+ background: var(--bg-inset);
763
+ border: 1px solid var(--border);
764
+ border-radius: 99px;
765
+ padding: var(--sp-1) var(--sp-3);
766
+ font-size: var(--text-xs);
767
+ font-weight: var(--fw-medium);
768
+ color: var(--text-muted);
769
+ cursor: pointer;
770
+ transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
771
+ letter-spacing: var(--ls-wide);
772
+ }
773
+
774
+ .beads-prio-filter:hover {
775
+ border-color: var(--accent);
776
+ color: var(--accent);
777
+ }
778
+
779
+ .beads-prio-filter.active {
780
+ background: var(--accent);
781
+ color: #fff;
782
+ border-color: var(--accent);
783
+ }
784
+
785
+ /* ─── Beads Task Detail Modal ────────────────── */
786
+ .bead-meta-grid {
787
+ display: grid;
788
+ grid-template-columns: 1fr 1fr;
789
+ gap: var(--sp-3);
790
+ padding: var(--sp-4) 0;
791
+ border-bottom: 1px solid var(--border-light);
792
+ }
793
+
794
+ .bead-meta-item {
795
+ display: flex;
796
+ flex-direction: column;
797
+ gap: 2px;
798
+ }
799
+
800
+ .bead-meta-label {
801
+ font-size: var(--text-xs);
802
+ color: var(--text-faint);
803
+ text-transform: uppercase;
804
+ letter-spacing: var(--ls-wide);
805
+ font-weight: var(--fw-medium);
806
+ }
807
+
808
+ .bead-meta-value {
809
+ font-size: var(--text-sm);
810
+ font-weight: var(--fw-medium);
811
+ color: var(--text);
812
+ }
813
+
814
+ .bead-description {
815
+ padding: var(--sp-4) 0;
816
+ border-bottom: 1px solid var(--border-light);
817
+ white-space: pre-wrap;
818
+ font-size: var(--text-sm);
819
+ line-height: var(--lh-relaxed);
820
+ color: var(--text-muted);
821
+ }
822
+
823
+ .bead-deps {
824
+ padding: var(--sp-4) 0;
825
+ border-bottom: 1px solid var(--border-light);
826
+ }
827
+
828
+ .bead-dep-group {
829
+ display: flex;
830
+ flex-wrap: wrap;
831
+ align-items: center;
832
+ gap: var(--sp-2);
833
+ margin-bottom: var(--sp-2);
834
+ }
835
+
836
+ .bead-dep-group:last-child {
837
+ margin-bottom: 0;
838
+ }
839
+
840
+ .bead-dep-label {
841
+ font-size: var(--text-xs);
842
+ color: var(--text-faint);
843
+ text-transform: uppercase;
844
+ letter-spacing: var(--ls-wide);
845
+ font-weight: var(--fw-medium);
846
+ min-width: 80px;
847
+ }
848
+
849
+ .bead-dep-link {
850
+ display: inline-block;
851
+ font-family: var(--font-mono);
852
+ font-size: var(--text-xs);
853
+ padding: 2px var(--sp-2);
854
+ border-radius: 99px;
855
+ background: var(--accent-glow);
856
+ color: var(--accent);
857
+ border: 1px solid var(--accent);
858
+ cursor: pointer;
859
+ transition: background 0.15s ease, color 0.15s ease;
860
+ text-decoration: none;
861
+ }
862
+
863
+ .bead-dep-link:hover {
864
+ background: var(--accent);
865
+ color: #fff;
866
+ }
867
+
868
+ .bead-timestamps {
869
+ display: flex;
870
+ flex-wrap: wrap;
871
+ gap: var(--sp-4);
872
+ padding: var(--sp-4) 0;
873
+ }
874
+
875
+ .bead-ts-item {
876
+ display: flex;
877
+ flex-direction: column;
878
+ gap: 2px;
879
+ }
880
+
881
+ .bead-ts-label {
882
+ font-size: var(--text-xs);
883
+ color: var(--text-faint);
884
+ text-transform: uppercase;
885
+ letter-spacing: var(--ls-wide);
886
+ font-weight: var(--fw-medium);
887
+ }
888
+
889
+ .bead-ts-value {
890
+ font-size: var(--text-sm);
891
+ color: var(--text-muted);
892
+ }
893
+
894
+ .bead-ts-value[title] {
895
+ border-bottom: 1px dotted var(--text-faint);
896
+ cursor: help;
897
+ }
898
+
899
+ /* ─── Standalone Commands Section ─────────────── */
900
+ .ongoing {
901
+ margin-top: var(--sp-10);
902
+ }
903
+
904
+ .ongoing h2 {
905
+ letter-spacing: var(--ls-wide);
906
+ text-transform: uppercase;
907
+ font-size: var(--text-sm);
908
+ color: var(--text-muted);
909
+ margin-bottom: var(--sp-4);
910
+ border-bottom: 2px solid var(--border);
911
+ padding-bottom: var(--sp-2);
912
+ }
913
+
914
+ /* ─── Footer ──────────────────────────────────── */
915
+ .footer {
916
+ text-align: center;
917
+ font-size: var(--text-xs);
918
+ color: var(--text-faint);
919
+ margin-top: var(--sp-10);
920
+ padding-top: var(--sp-4);
921
+ border-top: 1px solid var(--border-light);
922
+ letter-spacing: var(--ls-wide);
923
+ }
924
+
925
+ /* ─── Utilities ───────────────────────────────── */
926
+ .hidden {
927
+ display: none;
928
+ }
929
+
930
+ /* Build-observability severity + verdict tokens (Plan 4) */
931
+ :root {
932
+ --sev-p0: #dc2626; /* red 600 */
933
+ --sev-p1: #ea580c; /* orange 600 */
934
+ --sev-p2: #ca8a04; /* yellow 600 */
935
+ --sev-p3: #2563eb; /* blue 600 */
936
+ --sev-pass: #16a34a; /* green 600 */
937
+ }
938
+ [data-theme="dark"] {
939
+ --sev-p0: #f87171;
940
+ --sev-p1: #fb923c;
941
+ --sev-p2: #facc15;
942
+ --sev-p3: #60a5fa;
943
+ --sev-pass: #4ade80;
944
+ }
945
+
946
+ /* Build-observability panel layout */
947
+ .panel {
948
+ background: var(--bg-card);
949
+ border: 1px solid var(--border);
950
+ border-radius: var(--radius);
951
+ padding: var(--sp-4) var(--sp-6);
952
+ margin-bottom: var(--sp-6);
953
+ }
954
+ .panel > header {
955
+ display: flex;
956
+ align-items: center;
957
+ gap: var(--sp-3);
958
+ margin-bottom: var(--sp-4);
959
+ flex-wrap: wrap;
960
+ }
961
+ .panel > header h2 {
962
+ margin: 0;
963
+ font-size: var(--text-base);
964
+ font-weight: var(--fw-semi);
965
+ }
966
+ .panel .meta {
967
+ color: var(--text-muted);
968
+ font-size: var(--text-sm);
969
+ }
970
+ .grid { display: grid; gap: var(--sp-4); }
971
+ .grid-2 { grid-template-columns: repeat(2, 1fr); }
972
+ @media (max-width: 640px) { .grid-2 { grid-template-columns: 1fr; } }
973
+
974
+ /* Finding filters */
975
+ .finding-filters {
976
+ display: flex;
977
+ gap: var(--sp-2);
978
+ flex-wrap: wrap;
979
+ margin-bottom: var(--sp-4);
980
+ }
981
+ .finding-filters button {
982
+ padding: var(--sp-1) var(--sp-3);
983
+ border: 1px solid var(--border);
984
+ border-radius: var(--radius-sm);
985
+ background: var(--bg-inset);
986
+ color: var(--text);
987
+ font-size: var(--text-sm);
988
+ cursor: pointer;
989
+ }
990
+ .finding-filters button:hover,
991
+ .finding-filters button.active {
992
+ background: var(--accent);
993
+ border-color: var(--accent);
994
+ color: #fff;
995
+ }
996
+
997
+ /* Findings list */
998
+ .findings {
999
+ list-style: none;
1000
+ padding: 0;
1001
+ margin: 0;
1002
+ display: flex;
1003
+ flex-direction: column;
1004
+ gap: var(--sp-3);
1005
+ }
1006
+ .finding {
1007
+ background: var(--bg-inset);
1008
+ border: 1px solid var(--border-light);
1009
+ border-radius: var(--radius-sm);
1010
+ padding: var(--sp-3) var(--sp-4);
1011
+ }
1012
+ .finding header {
1013
+ display: flex;
1014
+ align-items: center;
1015
+ gap: var(--sp-2);
1016
+ flex-wrap: wrap;
1017
+ margin-bottom: var(--sp-2);
1018
+ }
1019
+ .finding-id {
1020
+ font-family: var(--font-mono, monospace);
1021
+ font-size: var(--text-xs);
1022
+ color: var(--text-muted);
1023
+ background: var(--bg-card);
1024
+ border: 1px solid var(--border);
1025
+ border-radius: 4px;
1026
+ padding: 1px var(--sp-1);
1027
+ }
1028
+ .finding .lens {
1029
+ font-size: var(--text-xs);
1030
+ color: var(--text-muted);
1031
+ }
1032
+ .finding .title {
1033
+ font-size: var(--text-sm);
1034
+ font-weight: var(--fw-semi);
1035
+ flex: 1;
1036
+ }
1037
+ .finding p { margin: 0; font-size: var(--text-sm); color: var(--text-muted); }
1038
+ .empty { color: var(--text-muted); font-size: var(--text-sm); text-align: center; padding: var(--sp-4); }
1039
+
1040
+ /* ── Mermaid diagrams ─────────────────────────────────────────────────────────
1041
+ The build renders mermaid to inline SVG via mmdc, then sanitizeSvg() +
1042
+ rehype-sanitize strip the SVG's own <script>, <foreignObject>, AND <style>
1043
+ for security. Stripping <style> means the diagram arrives unstyled (nodes
1044
+ default to a black fill). These theme-token rules restyle the SVG so nodes,
1045
+ edges, arrowheads, and labels render correctly — and follow light/dark mode.
1046
+ Authors must render with htmlLabels:false (the generator forces this) so node
1047
+ labels are native <text>/<tspan> rather than stripped <foreignObject> HTML. */
1048
+ figure.mermaid { margin: var(--sp-5) 0; text-align: center; }
1049
+ figure.mermaid svg { max-width: 100%; height: auto; }
1050
+ /* Node shapes */
1051
+ figure.mermaid svg .node rect,
1052
+ figure.mermaid svg .node circle,
1053
+ figure.mermaid svg .node ellipse,
1054
+ figure.mermaid svg .node polygon,
1055
+ figure.mermaid svg .node path {
1056
+ fill: var(--bg-inset);
1057
+ stroke: var(--border);
1058
+ stroke-width: 1px;
1059
+ }
1060
+ /* Background helper rects mermaid emits behind labels */
1061
+ figure.mermaid svg .node .label-container { fill: var(--bg-inset); stroke: var(--border); }
1062
+ figure.mermaid svg rect.background { fill: none; stroke: none; }
1063
+ /* Labels (rendered as <text>/<tspan> when htmlLabels:false) */
1064
+ figure.mermaid svg .nodeLabel,
1065
+ figure.mermaid svg .node text,
1066
+ figure.mermaid svg text.nodeLabel,
1067
+ figure.mermaid svg .label text,
1068
+ figure.mermaid svg span.nodeLabel {
1069
+ fill: var(--text);
1070
+ color: var(--text);
1071
+ font-family: var(--font-sans);
1072
+ }
1073
+ /* Edges: thin strokes, not filled blobs */
1074
+ figure.mermaid svg .edgePath path,
1075
+ figure.mermaid svg path.flowchart-link,
1076
+ figure.mermaid svg .flowchart-link {
1077
+ fill: none;
1078
+ stroke: var(--text-faint);
1079
+ stroke-width: 1.5px;
1080
+ }
1081
+ /* Arrowheads */
1082
+ figure.mermaid svg marker path,
1083
+ figure.mermaid svg .marker {
1084
+ fill: var(--text-faint);
1085
+ stroke: var(--text-faint);
1086
+ }
1087
+ figure.mermaid svg .edgeLabel,
1088
+ figure.mermaid svg .edgeLabel text { fill: var(--text-muted); color: var(--text-muted); }
1089
+
1090
+ /* ============================================================================
1091
+ * guides.css — component + layout styles for `scaffold guides` reference pages.
1092
+ *
1093
+ * Pairs with lib/dashboard-theme.css (the token source) and src/guides/chrome.ts
1094
+ * (the behavior). Styles the guide CHROME (.topbar, .layout, .rail, nav.toc,
1095
+ * .content) and the markdown DIRECTIVES (callouts, sev chips, filter-tables,
1096
+ * charts, tabs, citations) plus base prose typography.
1097
+ *
1098
+ * DESIGN SYSTEM: all COLORS come from dashboard-theme.css tokens, and spacing
1099
+ * uses the --sp-* scale wherever it maps. The few structural layout constants
1100
+ * (topbar height, rail/drawer width, chart label column, card min) are declared
1101
+ * as local custom properties below; a handful of sub-scale UI values (chip/bar
1102
+ * sizing, em-based inline-code padding) and the responsive breakpoint are
1103
+ * literal because no token expresses them. Both themes are covered because every
1104
+ * color is a token.
1105
+ * ==========================================================================*/
1106
+
1107
+ :root {
1108
+ --topbar-h: 52px; /* sticky topbar height; rail sticky offset keys off it */
1109
+ --rail-w: 260px; /* desktop TOC sidebar column */
1110
+ --drawer-w: 280px; /* mobile off-canvas TOC drawer */
1111
+ --card-min: 260px; /* index card min track width */
1112
+ --chart-label-w: 90px; /* chart row label column min */
1113
+ }
1114
+
1115
+ /* ── Base / reset on top of the token base in dashboard-theme.css ─────────── */
1116
+ .content a { color: var(--accent); text-decoration: none; }
1117
+ .content a:hover { text-decoration: underline; }
1118
+ .content strong { font-weight: var(--fw-semi); }
1119
+ .content hr { border: 0; border-top: 1px solid var(--border-light); margin: var(--sp-6) 0; }
1120
+
1121
+ /* Consistent keyboard focus for every interactive control (a11y). */
1122
+ .topbar button:focus-visible,
1123
+ .copy-btn:focus-visible,
1124
+ .tab-btn:focus-visible,
1125
+ .filter-input:focus-visible,
1126
+ nav.toc a:focus-visible,
1127
+ .guide-card:focus-visible,
1128
+ .content a:focus-visible {
1129
+ outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm);
1130
+ }
1131
+
1132
+ /* ── Topbar ────────────────────────────────────────────────────────────────*/
1133
+ .topbar {
1134
+ position: sticky; top: 0; z-index: 60; height: var(--topbar-h);
1135
+ display: flex; align-items: center; gap: var(--sp-3);
1136
+ padding: 0 var(--page-pad);
1137
+ background: var(--bg-card); border-bottom: 1px solid var(--border);
1138
+ }
1139
+ .topbar h1 {
1140
+ flex: 1; min-width: 0; margin: 0;
1141
+ font-size: var(--text-lg); font-weight: var(--fw-bold);
1142
+ letter-spacing: var(--ls-tight);
1143
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
1144
+ }
1145
+ .topbar button {
1146
+ background: var(--bg-card); border: 1px solid var(--border); color: var(--text);
1147
+ border-radius: var(--radius-sm); padding: var(--sp-1) var(--sp-3); font-size: var(--text-base);
1148
+ line-height: 1; cursor: pointer; font-family: inherit;
1149
+ }
1150
+ .topbar button:hover { background: var(--bg-hover); border-color: var(--accent); }
1151
+ .nav-toggle { display: none; }
1152
+
1153
+ /* ── Layout: sticky sidebar TOC + reading-width content ──────────────────── */
1154
+ .layout {
1155
+ max-width: var(--max-w); margin: 0 auto;
1156
+ display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr);
1157
+ gap: var(--sp-8); padding: 0 var(--page-pad);
1158
+ }
1159
+ .rail {
1160
+ position: sticky; top: var(--topbar-h); align-self: start;
1161
+ height: calc(100vh - var(--topbar-h)); overflow-y: auto;
1162
+ padding: var(--sp-5) 0; border-right: 1px solid var(--border-light);
1163
+ }
1164
+ .content { min-width: 0; padding: var(--sp-6) 0 var(--sp-10); }
1165
+
1166
+ /* Backdrop behind the mobile drawer (toggled with the rail via chrome.ts). */
1167
+ .rail-backdrop { display: none; }
1168
+ /* In-drawer close button — hidden on desktop (the rail is a static sidebar). */
1169
+ .rail-close { display: none; }
1170
+
1171
+ /* ── Table of contents (scrollspy marks a.active) ────────────────────────── */
1172
+ nav.toc ul { list-style: none; margin: 0; padding: 0; }
1173
+ nav.toc li { margin: 0; }
1174
+ nav.toc a {
1175
+ display: block; padding: var(--sp-1) var(--sp-3); line-height: 1.35;
1176
+ color: var(--text-muted); font-size: var(--text-sm);
1177
+ text-decoration: none; border-left: 2px solid transparent;
1178
+ border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
1179
+ }
1180
+ nav.toc a:hover { color: var(--text); background: var(--bg-hover); }
1181
+ nav.toc a.active {
1182
+ color: var(--accent); border-left-color: var(--accent);
1183
+ background: var(--accent-glow); font-weight: var(--fw-medium);
1184
+ }
1185
+ nav.toc li.toc-3 a { padding-left: var(--sp-6); font-size: var(--text-xs); }
1186
+
1187
+ /* ── Prose typography ──────────────────────────────────────────────────────*/
1188
+ .content h2 {
1189
+ font-size: var(--text-xl); letter-spacing: var(--ls-tight);
1190
+ margin: var(--sp-8) 0 var(--sp-3); padding-bottom: var(--sp-2);
1191
+ border-bottom: 1px solid var(--border-light); scroll-margin-top: calc(var(--topbar-h) + var(--sp-3));
1192
+ }
1193
+ .content h3 {
1194
+ font-size: var(--text-lg); margin: var(--sp-5) 0 var(--sp-2);
1195
+ scroll-margin-top: calc(var(--topbar-h) + var(--sp-3));
1196
+ }
1197
+ .content p { margin: var(--sp-3) 0; line-height: var(--lh-relaxed); }
1198
+ .content ul, .content ol { margin: var(--sp-3) 0; padding-left: var(--sp-6); }
1199
+ .content li { margin: var(--sp-1) 0; line-height: var(--lh-relaxed); }
1200
+ .content blockquote {
1201
+ margin: var(--sp-3) 0; padding: var(--sp-1) var(--sp-4);
1202
+ border-left: 3px solid var(--border); color: var(--text-muted);
1203
+ }
1204
+
1205
+ /* ── Inline code + code blocks (chrome.ts wraps <pre> in .code + .copy-btn) ──*/
1206
+ .content code {
1207
+ font-family: var(--font-mono); font-size: 0.85em;
1208
+ background: var(--bg-inset); padding: 0.12em 0.4em; border-radius: var(--radius-sm);
1209
+ }
1210
+ .content .code { position: relative; margin: var(--sp-3) 0; }
1211
+ .content .code pre {
1212
+ margin: 0; padding: var(--sp-3) var(--sp-4); overflow-x: auto;
1213
+ background: var(--bg-inset); border: 1px solid var(--border-light);
1214
+ border-radius: var(--radius-sm); font-family: var(--font-mono);
1215
+ font-size: var(--text-sm); line-height: var(--lh-relaxed);
1216
+ }
1217
+ .content .code pre code { background: none; padding: 0; font-size: inherit; }
1218
+ .copy-btn {
1219
+ position: absolute; top: var(--sp-1); right: var(--sp-1);
1220
+ background: var(--bg-card); border: 1px solid var(--border); color: var(--text-muted);
1221
+ border-radius: var(--radius-sm); font-size: var(--text-xs); padding: var(--sp-1) var(--sp-2);
1222
+ cursor: pointer; opacity: 0.85; font-family: inherit;
1223
+ }
1224
+ .copy-btn:hover { color: var(--accent); border-color: var(--accent); opacity: 1; }
1225
+
1226
+ /* ── Callouts ─ (border-color BEFORE border-left-color so the accent wins) ── */
1227
+ .callout {
1228
+ margin: var(--sp-4) 0; padding: var(--sp-3) var(--sp-4);
1229
+ border: 1px solid var(--border); border-left-width: 3px;
1230
+ border-radius: var(--radius-sm); background: var(--bg-card);
1231
+ }
1232
+ .callout > :first-child { margin-top: 0; }
1233
+ .callout > :last-child { margin-bottom: 0; }
1234
+ .callout-note, .callout-info { background: var(--blue-bg); border-color: var(--blue-border); border-left-color: var(--blue); }
1235
+ .callout-tip { background: var(--green-bg); border-color: var(--green-border); border-left-color: var(--green); }
1236
+ .callout-warning { background: var(--yellow-bg); border-color: var(--yellow-border); border-left-color: var(--yellow); }
1237
+ .callout-danger { background: var(--red-bg); border-color: var(--red-border); border-left-color: var(--red); }
1238
+
1239
+ /* ── Severity chips (:sev) — tight pill, sub-scale vertical padding ───────── */
1240
+ .sev {
1241
+ display: inline-block; font-size: var(--text-xs); font-weight: var(--fw-semi);
1242
+ padding: 1px var(--sp-2); border-radius: 999px; line-height: 1.5;
1243
+ border: 1px solid var(--border); background: var(--bg-inset); color: var(--text-muted);
1244
+ white-space: nowrap;
1245
+ }
1246
+ .sev-p0 { color: var(--sev-p0); border-color: var(--sev-p0); }
1247
+ .sev-p1 { color: var(--sev-p1); border-color: var(--sev-p1); }
1248
+ .sev-p2 { color: var(--sev-p2); border-color: var(--sev-p2); }
1249
+ .sev-p3 { color: var(--sev-p3); border-color: var(--sev-p3); }
1250
+ .sev-pass { color: var(--sev-pass); border-color: var(--sev-pass); }
1251
+
1252
+ /* ── Citations (:cite) — inline provenance refs ──────────────────────────── */
1253
+ .fp, .cite-advisory {
1254
+ font-family: var(--font-mono); font-size: 0.82em;
1255
+ padding: 0.05em 0.35em; border-radius: var(--radius-sm);
1256
+ background: var(--bg-inset); border: 1px solid var(--border-light);
1257
+ }
1258
+ .fp { color: var(--accent); }
1259
+ .cite-advisory { color: var(--text-faint); border-style: dashed; }
1260
+
1261
+ /* ── Tables + filter-tables ──────────────────────────────────────────────── */
1262
+ .content table { width: 100%; border-collapse: collapse; margin: var(--sp-3) 0; font-size: var(--text-sm); }
1263
+ .content th, .content td { text-align: left; padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border-light); vertical-align: top; }
1264
+ .content th {
1265
+ color: var(--text-muted); font-weight: var(--fw-semi); font-size: var(--text-xs);
1266
+ text-transform: uppercase; letter-spacing: var(--ls-wide); border-bottom-color: var(--border);
1267
+ }
1268
+ .content tbody tr:hover { background: var(--bg-hover); }
1269
+ .content td code { white-space: nowrap; }
1270
+ .filter-table { margin: var(--sp-4) 0; }
1271
+ .filter-input {
1272
+ width: 100%; max-width: 320px; margin-bottom: var(--sp-2);
1273
+ padding: var(--sp-2) var(--sp-3); font-family: inherit; font-size: var(--text-sm);
1274
+ color: var(--text); background: var(--bg-card);
1275
+ border: 1px solid var(--border); border-radius: var(--radius-sm);
1276
+ }
1277
+ .filter-input:focus { border-color: var(--accent); }
1278
+
1279
+ /* ── Charts (:::chart) — label + proportional bar (fill carries inline width%) */
1280
+ .chart-block { margin: var(--sp-4) 0; }
1281
+ .chart-row {
1282
+ display: grid; grid-template-columns: minmax(var(--chart-label-w), 24%) 1fr;
1283
+ align-items: center; gap: var(--sp-3); margin: var(--sp-1) 0;
1284
+ }
1285
+ .chart-label {
1286
+ font-size: var(--text-sm); color: var(--text-muted); text-align: right;
1287
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
1288
+ }
1289
+ .chart-row .chart-bar {
1290
+ height: 0.9em; min-width: 2px; background: var(--accent);
1291
+ border-radius: var(--radius-sm);
1292
+ }
1293
+
1294
+ /* ── Tabs (::::tabs / :::tab) ─────────────────────────────────────────────── */
1295
+ .tabs { margin: var(--sp-4) 0; }
1296
+ .tablist { display: flex; flex-wrap: wrap; gap: var(--sp-1); border-bottom: 1px solid var(--border); margin-bottom: var(--sp-3); }
1297
+ .tab-btn {
1298
+ background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
1299
+ padding: var(--sp-2) var(--sp-3); color: var(--text-muted);
1300
+ font-family: inherit; font-size: var(--text-sm); font-weight: var(--fw-medium); cursor: pointer;
1301
+ }
1302
+ .tab-btn:hover { color: var(--text); }
1303
+ .tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }
1304
+ .tabpane { display: none; }
1305
+ .tabpane.active { display: block; }
1306
+
1307
+ /* ── Mermaid diagrams ────────────────────────────────────────────────────── */
1308
+ .content figure { margin: var(--sp-4) 0; text-align: center; }
1309
+ .content figure svg, .content > svg, .content .mermaid svg { max-width: 100%; height: auto; }
1310
+
1311
+ /* ── Index page: category card grid ──────────────────────────────────────── */
1312
+ .content .lead { color: var(--text-muted); font-size: var(--text-base); max-width: 60ch; margin-top: var(--sp-2); }
1313
+ .guide-cards {
1314
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(min(var(--card-min), 100%), 1fr));
1315
+ gap: var(--sp-4); margin: var(--sp-4) 0 var(--sp-6);
1316
+ }
1317
+ .guide-card {
1318
+ display: flex; flex-direction: column; gap: var(--sp-2);
1319
+ padding: var(--sp-4); background: var(--bg-card);
1320
+ border: 1px solid var(--border); border-radius: var(--radius);
1321
+ color: inherit; text-decoration: none;
1322
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
1323
+ }
1324
+ .guide-card:hover { border-color: var(--accent); box-shadow: var(--shadow-md); text-decoration: none; }
1325
+ .guide-card-title { font-weight: var(--fw-semi); color: var(--accent); font-size: var(--text-base); }
1326
+ .guide-card-desc { color: var(--text-muted); font-size: var(--text-sm); line-height: var(--lh-normal); }
1327
+
1328
+ /* ── Responsive: TOC becomes an off-canvas drawer (chrome.ts toggles .open) ──*/
1329
+ /* 860px is literal — media queries cannot read custom properties. Revisit it if
1330
+ --topbar-h / --rail-w / --drawer-w change (the drawer sticky offsets key off them). */
1331
+ @media (max-width: 860px) {
1332
+ .nav-toggle { display: inline-flex; align-items: center; }
1333
+ .layout { grid-template-columns: 1fr; gap: 0; }
1334
+ .rail {
1335
+ position: fixed; top: var(--topbar-h); left: 0; bottom: 0; width: var(--drawer-w); z-index: 50;
1336
+ height: auto; background: var(--bg-card); border-right: 1px solid var(--border);
1337
+ padding: var(--sp-4); box-shadow: var(--shadow-lg);
1338
+ transform: translateX(-100%); transition: transform 0.2s ease, visibility 0.2s ease;
1339
+ /* Closed drawer is off-screen AND removed from tab order / pointer events. */
1340
+ visibility: hidden; pointer-events: none;
1341
+ }
1342
+ .rail.open { transform: translateX(0); visibility: visible; pointer-events: auto; }
1343
+ .rail-close {
1344
+ display: block; margin-left: auto; margin-bottom: var(--sp-2);
1345
+ background: var(--bg-card); border: 1px solid var(--border); color: var(--text);
1346
+ border-radius: var(--radius-sm); padding: var(--sp-1) var(--sp-3); font-size: var(--text-base);
1347
+ line-height: 1; cursor: pointer; font-family: inherit;
1348
+ }
1349
+ .rail-close:hover { background: var(--bg-hover); border-color: var(--accent); }
1350
+ .rail-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1351
+ .rail-backdrop {
1352
+ display: block; position: fixed; inset: var(--topbar-h) 0 0 0;
1353
+ background: var(--scrim); z-index: 49;
1354
+ opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
1355
+ }
1356
+ .rail.open ~ .rail-backdrop { opacity: 1; pointer-events: auto; }
1357
+ }
1358
+ </style>
1359
+ <script>(function(){try{var t=localStorage.getItem('guide-theme');if(!t&&window.matchMedia&&matchMedia('(prefers-color-scheme: dark)').matches)t='dark';if(t)document.documentElement.setAttribute('data-theme',t);}catch(e){}})();</script>
1360
+ </head>
1361
+ <body>
1362
+ <header class="topbar">
1363
+ <button data-action="nav" class="nav-toggle" aria-label="Toggle navigation"
1364
+ aria-expanded="false" aria-controls="guide-toc">☰</button>
1365
+ <h1>Parallel Agents &amp; Worktrees</h1>
1366
+ <button data-action="theme" class="theme-toggle" aria-label="Toggle theme">◐</button>
1367
+ </header>
1368
+ <div class="layout">
1369
+ <aside class="rail" id="guide-toc">
1370
+ <button class="rail-close" data-action="nav" aria-label="Close navigation">✕</button>
1371
+ <nav class="toc" aria-label="Table of contents"><ul><li class="toc-2"><a href="#why-worktrees-not-just-branches">Why worktrees, not just branches</a></li><li class="toc-2"><a href="#setup-setup-agent-worktreesh">Setup — setup-agent-worktree.sh</a></li><li class="toc-2"><a href="#which-build-phase-entry-point">Which build-phase entry point?</a></li><li class="toc-2"><a href="#working-in-parallel">Working in parallel</a></li><li class="toc-2"><a href="#teardown-harvest">Teardown &amp; harvest</a></li><li class="toc-3"><a href="#the-branch-deletion-guards">The branch-deletion guards</a></li><li class="toc-3"><a href="#recovering-orphaned-ledgers---recover">Recovering orphaned ledgers — --recover</a></li><li class="toc-2"><a href="#resuming-after-a-break">Resuming after a break</a></li><li class="toc-2"><a href="#see-also">See also</a></li></ul></nav>
1372
+ </aside>
1373
+ <main class="content"><h2 id="why-worktrees-not-just-branches">Why worktrees, not just branches</h2>
1374
+ <p>Several agents implementing the same project at once need two things: a clean
1375
+ checkout each can build and test in, and a shared history they all merge back
1376
+ into. A branch alone gives you the second but not the first — switching
1377
+ branches mutates one working directory, so two agents on two branches in the
1378
+ same checkout collide on every uncommitted file, every <code>node_modules</code>, every
1379
+ test run.</p>
1380
+ <p>A <strong>git worktree</strong> solves this: it is an independent working directory backed by
1381
+ the <em>same</em> <code>.git</code> repository. Each agent gets its own files and its own checked-out
1382
+ branch, but commits, refs and history are shared. The layout is one primary
1383
+ checkout plus one sibling directory per agent:</p>
1384
+ <pre><code class="language-text">~/projects/
1385
+ ├── scaffold/ # primary checkout (you work here)
1386
+ ├── scaffold-alpha/ # worktree for agent "alpha"
1387
+ └── scaffold-beta/ # worktree for agent "beta"
1388
+ </code></pre>
1389
+ <p>So worktrees give you <strong>filesystem isolation with a shared object store</strong>:
1390
+ agents never overwrite each other's working files, but a PR merged from one
1391
+ worktree is immediately visible (after a fetch/rebase) to all the others.</p>
1392
+ <div class="callout callout-note"><p><strong>One worktree, one branch, one agent.</strong> A branch that is checked out in a
1393
+ worktree cannot also be checked out in the primary repo — git enforces this.
1394
+ That constraint is a feature here: it keeps each agent's work pinned to its own
1395
+ branch.</p></div>
1396
+ <h2 id="setup-setup-agent-worktreesh">Setup — <code>setup-agent-worktree.sh</code></h2>
1397
+ <p><code>scripts/setup-agent-worktree.sh &#x3C;agent-name></code> creates a permanent worktree for
1398
+ one parallel agent. Given a name like <code>alpha</code>, it:</p>
1399
+ <ol>
1400
+ <li><strong>Normalizes the name</strong> to a lowercase, hyphenated, alphanumeric slug (so
1401
+ <code>Agent_1</code> becomes <code>agent-1</code>), then derives the worktree directory as a
1402
+ <em>sibling</em> of the primary repo: <code>../&#x3C;repo-name>-&#x3C;slug></code>.</li>
1403
+ <li><strong>Creates the workspace branch</strong> <code>&#x3C;slug>-workspace</code> if it does not already
1404
+ exist <span class="fp" data-path="scripts/setup-agent-worktree.sh:40">scripts/setup-agent-worktree.sh:40</span>, then adds the worktree on
1405
+ that branch <span class="fp" data-path="scripts/setup-agent-worktree.sh:44">scripts/setup-agent-worktree.sh:44</span>. Re-running for an
1406
+ existing worktree is a safe no-op.</li>
1407
+ <li><strong>Writes <code>.scaffold/identity.json</code></strong> — the stable identity that build
1408
+ observability stamps onto every event this worktree records. The script
1409
+ creates <code>.scaffold/</code> <span class="fp" data-path="scripts/setup-agent-worktree.sh:52">scripts/setup-agent-worktree.sh:52</span> and, only if no
1410
+ identity file exists yet, writes <code>worktree_id</code> (a UUID), <code>worktree_label</code>
1411
+ (the agent slug), and <code>created_at</code>
1412
+ <span class="fp" data-path="scripts/setup-agent-worktree.sh:71">scripts/setup-agent-worktree.sh:71</span>.</li>
1413
+ <li><strong>Re-syncs Beads</strong> with a fail-soft <code>bd doctor --fix</code> when a <code>.beads/</code>
1414
+ directory is present <span class="fp" data-path="scripts/setup-agent-worktree.sh:88">scripts/setup-agent-worktree.sh:88</span>, reconciling the
1415
+ worktree's Beads git hooks and project config against the installed <code>bd</code>
1416
+ version. (Beads DB sharing is automatic — worktrees discover the main repo's
1417
+ task DB via git's common directory, so there is nothing for <code>bd doctor</code> to
1418
+ register.)</li>
1419
+ </ol>
1420
+ <p>The <code>worktree_id</code> is what later lets the harvester tell one worktree's ledger
1421
+ from another's — see the <a href="../observability/index.md">observability guide</a> for
1422
+ how identity flows into events.</p>
1423
+ <div class="callout callout-tip"><p><strong>The identity write is idempotent.</strong> The script only writes
1424
+ <code>identity.json</code> when one is absent, so re-running setup never clobbers an
1425
+ established worktree id. If you want a fresh id, delete the file first.</p></div>
1426
+ <h2 id="which-build-phase-entry-point">Which build-phase entry point?</h2>
1427
+ <p>Six build-phase commands start or resume implementation work. Pick by two
1428
+ questions: <em>is the work already in the plan?</em> and <em>is one agent or several
1429
+ working?</em></p>
1430
+ <figure class="mermaid"><svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 1139.59px; background-color: transparent;" viewBox="0 0 1139.589111328125 987.3843994140625" role="graphics-document document">#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#666;stroke:#666;}#my-svg .marker.cross{stroke:#666;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#my-svg .cluster-label text{fill:#333;}#my-svg .cluster-label span{color:#333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#000000;color:#000000;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#eee;stroke:#999;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#666!important;stroke-width:0;stroke:#666;}#my-svg .arrowheadPath{fill:#333333;}#my-svg .edgePath .path{stroke:#666;stroke-width:1px;}#my-svg .flowchart-link{stroke:#666;fill:none;}#my-svg .edgeLabel{background-color:white;text-align:center;}#my-svg .edgeLabel p{background-color:white;}#my-svg .edgeLabel rect{opacity:0.5;background-color:white;fill:white;}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:hsl(0, 0%, 98.9215686275%);stroke:#707070;stroke-width:1px;}#my-svg .cluster text{fill:#333;}#my-svg .cluster span{color:#333;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(-160, 0%, 93.3333333333%);border:1px solid #707070;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:white;text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:white;padding:2px;}#my-svg .icon-shape .label rect,#my-svg .image-shape .label rect{opacity:0.5;background-color:white;fill:white;}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg .node .neo-node{stroke:#999;}#my-svg [data-look="neo"].node rect,#my-svg [data-look="neo"].cluster rect,#my-svg [data-look="neo"].node polygon{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].node path{stroke:url(#my-svg-gradient);stroke-width:1px;}#my-svg [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].node .neo-line path{stroke:#999;filter:none;}#my-svg [data-look="neo"].node circle{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].node circle .state-start{fill:#000000;}#my-svg [data-look="neo"].icon-shape .icon{fill:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].icon-shape .icon-neo path{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}<g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path></marker><marker id="my-svg_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"></path></marker><marker id="my-svg_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"></polygon></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></circle></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></circle></marker><marker id="my-svg_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"></circle></marker><marker id="my-svg_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"></circle></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"></path></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"></path></marker><marker id="my-svg_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"></path></marker><marker id="my-svg_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1, 0;"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"><path d="M378.359,57L378.359,61.167C378.359,65.333,378.359,73.667,378.359,81.333C378.359,89,378.359,96,378.359,99.5L378.359,103" id="my-svg-L_Start_InPlan_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M306.247,256.909L272.687,275.011C239.128,293.113,172.009,329.318,138.45,364.067C104.891,398.816,104.891,432.11,104.891,448.758L104.891,465.405" id="my-svg-L_InPlan_Quick_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M378.359,329.022L378.359,335.105C378.359,341.189,378.359,353.355,378.359,376.086C378.359,398.816,378.359,432.11,378.359,448.758L378.359,465.405" id="my-svg-L_InPlan_Enh_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M451.002,256.38L485.441,274.57C519.88,292.76,588.758,329.141,623.197,352.748C657.636,376.355,657.636,387.189,657.636,392.605L657.636,398.022" id="my-svg-L_InPlan_HowMany_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M592.634,538.385L561.814,555.302C530.995,572.219,469.357,606.053,438.537,628.387C407.718,650.721,407.718,661.554,407.718,666.971L407.718,672.388" id="my-svg-L_HowMany_Single_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M722.51,538.513L753.12,555.409C783.729,572.305,844.948,606.096,875.558,628.409C906.167,650.721,906.167,661.554,906.167,666.971L906.167,672.388" id="my-svg-L_HowMany_Multi_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M366.035,798.102L352.462,811.132C338.889,824.163,311.743,850.224,298.17,870.137C284.597,890.051,284.597,903.818,284.597,910.701L284.597,917.584" id="my-svg-L_Single_SS_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M449.4,798.102L462.974,811.132C476.547,824.163,503.693,850.224,517.266,870.137C530.839,890.051,530.839,903.818,530.839,910.701L530.839,917.584" id="my-svg-L_Single_SR_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M864.256,797.873L850.49,810.942C836.724,824.01,809.192,850.147,795.425,868.633C781.659,887.118,781.659,897.951,781.659,903.368L781.659,908.784" id="my-svg-L_Multi_MS_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path><path d="M948.078,797.873L961.844,810.942C975.611,824.01,1003.143,850.147,1016.909,868.633C1030.675,887.118,1030.675,897.951,1030.675,903.368L1030.675,908.784" id="my-svg-L_Multi_MR_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" marker-end="url(#my-svg_flowchart-v2-pointEnd)"></path></g><g class="edgeLabels"><g class="edgeLabel"><g class="label" transform="translate(0, 0)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"></tspan></text></g></g><g><rect class="background" style="stroke: none"></rect></g><g class="edgeLabel" transform="translate(104.890625, 365.5218811035156)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-96.890625" y="-1" width="193.78125" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">No</tspan><tspan class="text-inner-tspan"> —</tspan><tspan class="text-inner-tspan"> one-off</tspan><tspan class="text-inner-tspan"> bug/refactor</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(378.359375, 365.5218811035156)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-96.109375" y="-1" width="192.21875" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">No</tspan><tspan class="text-inner-tspan"> —</tspan><tspan class="text-inner-tspan"> a</tspan><tspan class="text-inner-tspan"> whole</tspan><tspan class="text-inner-tspan"> new</tspan><tspan class="text-inner-tspan"> feature</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(657.6359405517578, 365.5218811035156)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-72.90625" y="-1" width="145.8125" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">Yes</tspan><tspan class="text-inner-tspan"> —</tspan><tspan class="text-inner-tspan"> planned</tspan><tspan class="text-inner-tspan"> tasks</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(407.7179718017578, 639.8875122070312)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-38.6640625" y="-1" width="77.328125" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">One</tspan><tspan class="text-inner-tspan"> agent</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(906.1671905517578, 639.8875122070312)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-53.9375" y="-1" width="107.875" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">Several</tspan><tspan class="text-inner-tspan"> agents</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(284.5968780517578, 876.2843933105469)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-21.28125" y="-1" width="42.5625" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">Fresh</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(530.8390655517578, 876.2843933105469)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-35.6171875" y="-1" width="71.234375" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">Resuming</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(781.6593780517578, 876.2843933105469)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-21.28125" y="-1" width="42.5625" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">Fresh</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1030.6750030517578, 876.2843933105469)"><g class="label" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-35.6171875" y="-1" width="71.234375" height="23"></rect><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" text-anchor="middle"><tspan class="text-inner-tspan">Resuming</tspan></tspan></text></g></g></g></g><g class="nodes"><g class="node default" id="my-svg-flowchart-Start-0" transform="translate(378.359375, 32.5)"><rect class="basic label-container" style="" x="-112.4140625" y="-24.5" width="224.828125" height="49"></rect><g class="label" style="" transform="translate(0, -9.5)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">Build-phase</tspan><tspan class="text-inner-tspan"> work</tspan><tspan class="text-inner-tspan"> to</tspan><tspan class="text-inner-tspan"> do</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-InPlan-1" transform="translate(378.359375, 218.0109405517578)"><polygon points="111.01093673706055,0 222.0218734741211,-111.01093673706055 111.01093673706055,-222.0218734741211 0,-111.01093673706055" class="label-container" transform="translate(-110.51093673706055, 111.01093673706055)"></polygon><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">Already</tspan><tspan class="text-inner-tspan"> in</tspan><tspan class="text-inner-tspan"> the</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em"><tspan class="text-inner-tspan">implementation</tspan><tspan class="text-inner-tspan"> plan?</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-Quick-3" transform="translate(104.890625, 502.70469665527344)"><rect class="basic label-container" style="" x="-94.875" y="-33.29999923706055" width="189.75" height="66.5999984741211"></rect><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">quick-task</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em"><tspan class="text-inner-tspan">single</tspan><tspan class="text-inner-tspan"> scoped</tspan><tspan class="text-inner-tspan"> task</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-Enh-5" transform="translate(378.359375, 502.70469665527344)"><rect class="basic label-container" style="" x="-128.59375" y="-33.29999923706055" width="257.1875" height="66.5999984741211"></rect><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">new-enhancement</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em"><tspan class="text-inner-tspan">update</tspan><tspan class="text-inner-tspan"> PRD</tspan><tspan class="text-inner-tspan"> +</tspan><tspan class="text-inner-tspan"> stories</tspan><tspan class="text-inner-tspan"> +</tspan><tspan class="text-inner-tspan"> plan</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-HowMany-7" transform="translate(657.6359405517578, 502.70469665527344)"><polygon points="100.68281173706055,0 201.3656234741211,-100.68281173706055 100.68281173706055,-201.3656234741211 0,-100.68281173706055" class="label-container" transform="translate(-100.18281173706055, 100.68281173706055)"></polygon><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">One</tspan><tspan class="text-inner-tspan"> agent</tspan><tspan class="text-inner-tspan"> or</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em"><tspan class="text-inner-tspan">several</tspan><tspan class="text-inner-tspan"> in</tspan><tspan class="text-inner-tspan"> parallel?</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-Single-9" transform="translate(407.7179718017578, 758.0859527587891)"><polygon points="81.69843673706055,0 163.3968734741211,-81.69843673706055 81.69843673706055,-163.3968734741211 0,-81.69843673706055" class="label-container" transform="translate(-81.19843673706055, 81.69843673706055)"></polygon><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">Fresh</tspan><tspan class="text-inner-tspan"> start</tspan><tspan class="text-inner-tspan"> or</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em"><tspan class="text-inner-tspan">resuming?</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-Multi-11" transform="translate(906.1671905517578, 758.0859527587891)"><polygon points="81.69843673706055,0 163.3968734741211,-81.69843673706055 81.69843673706055,-163.3968734741211 0,-81.69843673706055" class="label-container" transform="translate(-81.19843673706055, 81.69843673706055)"></polygon><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">Fresh</tspan><tspan class="text-inner-tspan"> start</tspan><tspan class="text-inner-tspan"> or</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em"><tspan class="text-inner-tspan">resuming?</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-SS-13" transform="translate(284.5968780517578, 946.0843925476074)"><rect class="basic label-container" style="" x="-93.5234375" y="-24.5" width="187.046875" height="49"></rect><g class="label" style="" transform="translate(0, -9.5)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">single-agent-start</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-SR-15" transform="translate(530.8390655517578, 946.0843925476074)"><rect class="basic label-container" style="" x="-102.71875" y="-24.5" width="205.4375" height="49"></rect><g class="label" style="" transform="translate(0, -9.5)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">single-agent-resume</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-MS-17" transform="translate(781.6593780517578, 946.0843925476074)"><rect class="basic label-container" style="" x="-98.1015625" y="-33.29999923706055" width="196.203125" height="66.5999984741211"></rect><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">multi-agent-start</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em"><tspan class="text-inner-tspan">(needs</tspan><tspan class="text-inner-tspan"> a</tspan><tspan class="text-inner-tspan"> worktree)</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-MR-19" transform="translate(1030.6750030517578, 946.0843925476074)"><rect class="basic label-container" style="" x="-100.9140625" y="-33.29999923706055" width="201.828125" height="66.5999984741211"></rect><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect></rect><g><rect class="background" style="stroke: none"></rect><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em"><tspan class="text-inner-tspan">multi-agent-resume</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em"><tspan class="text-inner-tspan">(in</tspan><tspan class="text-inner-tspan"> the</tspan><tspan class="text-inner-tspan"> worktree)</tspan></tspan></text></g></g></g></g></g></g><defs></defs><defs></defs></svg></figure>
1431
+ <div class="tabs"><div class="tablist" role="tablist"><button id="tab-0-0" class="tab-btn active" role="tab" data-tab="0" aria-controls="tabpane-0-0" aria-selected="true" tabindex="0">Planned work</button><button id="tab-0-1" class="tab-btn" role="tab" data-tab="1" aria-controls="tabpane-0-1" aria-selected="false" tabindex="-1">Unplanned work</button></div><div id="tabpane-0-0" class="tabpane active" role="tabpanel" data-tab="0" aria-labelledby="tab-0-0" tabindex="0"><p><strong><code>single-agent-start</code></strong> — one agent claims the next planned task, runs the
1432
+ red-green-refactor loop, opens a PR, repeats. The default entry point when one
1433
+ agent works the plan sequentially.</p><p><strong><code>multi-agent-start &#x3C;agent-name></code></strong> — establishes a <em>named</em> agent inside a git
1434
+ worktree so several agents run the same loop simultaneously without file
1435
+ conflicts. Run <code>setup-agent-worktree.sh &#x3C;name></code> first; this command verifies the
1436
+ worktree environment before claiming tasks.</p><p><strong><code>single-agent-resume</code></strong> / <strong><code>multi-agent-resume &#x3C;agent-name></code></strong> — pick these
1437
+ after a break (context reset, paused session, next day). They recover context —
1438
+ git state, in-progress work, merged PRs — and continue the loop. The
1439
+ multi-agent variant additionally verifies the worktree and syncs with main
1440
+ before resuming.</p></div><div id="tabpane-0-1" class="tabpane" role="tabpanel" data-tab="1" aria-labelledby="tab-0-1" tabindex="0"><p><strong><code>quick-task &#x3C;description></code></strong> — a single, well-scoped task for a bug fix,
1441
+ refactor, perf tweak, or small refinement that is <em>not</em> in the plan. Produces
1442
+ one task with acceptance criteria and a TDD test plan; a complexity gate
1443
+ redirects to <code>new-enhancement</code> if the scope turns out to be too large.</p><p><strong><code>new-enhancement &#x3C;description></code></strong> — the full-weight path for a genuinely new
1444
+ feature: impact analysis, then updates to the PRD and user stories, an
1445
+ innovation pass, and new implementation tasks that integrate with the existing
1446
+ plan. Use this when the work deserves stories and acceptance criteria, not just
1447
+ a task.</p></div></div>
1448
+ <p>Both unplanned entry points feed back into the planned loop: once <code>quick-task</code>
1449
+ or <code>new-enhancement</code> has created tasks, an agent picks them up with one of the
1450
+ <code>*-start</code> / <code>*-resume</code> commands.</p>
1451
+ <h2 id="working-in-parallel">Working in parallel</h2>
1452
+ <p>Several agents merging to <code>main</code> at once is fine if every agent keeps its
1453
+ footprint small and its branches short. The conflict-prevention rules from
1454
+ <code>docs/git-workflow.md</code> apply directly:</p>
1455
+ <ul>
1456
+ <li><strong>Keep branches short-lived</strong> — merge within hours, not days
1457
+ <span class="cite-advisory" data-path="docs/git-workflow.md:131">docs/git-workflow.md:131</span>. The longer a branch lives, the
1458
+ more <code>main</code> drifts underneath it.</li>
1459
+ <li><strong>Rebase frequently</strong> — other agents are merging while you work
1460
+ <span class="cite-advisory" data-path="docs/git-workflow.md:173">docs/git-workflow.md:173</span>. Rebase before you touch a file,
1461
+ and again before you open the PR.</li>
1462
+ <li><strong>Avoid high-contention files in parallel.</strong> <code>CLAUDE.md</code> and shared libraries
1463
+ are read or edited by every agent; serialize work on them and rebase first
1464
+ rather than editing concurrently <span class="cite-advisory" data-path="docs/git-workflow.md:126">docs/git-workflow.md:126</span>.</li>
1465
+ <li><strong>Don't reformat files you aren't otherwise changing</strong> — gratuitous diffs turn
1466
+ into needless conflicts.</li>
1467
+ </ul>
1468
+ <p>Each agent otherwise follows the standard PR workflow from its own worktree:
1469
+ branch, commit, push, <code>gh pr create</code>, wait for CI, squash-merge. The shared
1470
+ object store means a merge from <code>scaffold-alpha</code> is on <code>main</code> for everyone the
1471
+ moment it lands.</p>
1472
+ <h2 id="teardown-harvest">Teardown &#x26; harvest</h2>
1473
+ <p>When an agent's work is merged, retire its worktree. The single command for this
1474
+ is <code>scripts/teardown-agent-worktree.sh &#x3C;worktree-path></code>, and the <strong>order of
1475
+ operations is the whole point</strong>.</p>
1476
+ <div class="callout callout-danger"><p><strong>Harvest the ledger BEFORE removing the worktree — or lose the build record.</strong>
1477
+ A worktree's <code>.scaffold/activity.jsonl</code> lives <em>inside</em> that worktree. Once
1478
+ <code>git worktree remove</code> deletes the directory, the ledger goes with it — every
1479
+ decision, blocker, and task event that worktree recorded is gone, and they were
1480
+ never on <code>main</code> to begin with. The teardown script harvests the ledger into the
1481
+ primary repo's archive <em>first</em> <span class="fp" data-path="scripts/teardown-agent-worktree.sh:42">scripts/teardown-agent-worktree.sh:42</span> and
1482
+ only then runs <code>git worktree remove</code>
1483
+ <span class="fp" data-path="scripts/teardown-agent-worktree.sh:50">scripts/teardown-agent-worktree.sh:50</span>. <strong>Never</strong> call <code>git worktree remove</code> by hand on an agent worktree before harvesting — use the script, which
1484
+ enforces the ordering.</p></div>
1485
+ <p>The script's full sequence:</p>
1486
+ <ol>
1487
+ <li><strong>Resolve the primary repo</strong> from the worktree path via
1488
+ <code>git -C &#x3C;path> rev-parse --git-common-dir</code>
1489
+ <span class="fp" data-path="scripts/teardown-agent-worktree.sh:27">scripts/teardown-agent-worktree.sh:27</span>, so it works run from anywhere.</li>
1490
+ <li><strong>Read the worktree's branch name</strong> before anything is removed
1491
+ <span class="fp" data-path="scripts/teardown-agent-worktree.sh:37">scripts/teardown-agent-worktree.sh:37</span>.</li>
1492
+ <li><strong>Harvest the ledger</strong> (fail-soft — a harvest failure prints a warning but
1493
+ does not abort the removal) <span class="fp" data-path="scripts/teardown-agent-worktree.sh:42">scripts/teardown-agent-worktree.sh:42</span>.</li>
1494
+ <li><strong>Remove the worktree</strong> <span class="fp" data-path="scripts/teardown-agent-worktree.sh:50">scripts/teardown-agent-worktree.sh:50</span>.</li>
1495
+ <li><strong>Delete the workspace branch — with guards.</strong></li>
1496
+ </ol>
1497
+ <h3 id="the-branch-deletion-guards">The branch-deletion guards</h3>
1498
+ <p>The script refuses to delete a branch that would harm the primary repo:</p>
1499
+ <ul>
1500
+ <li>It never deletes the branch the <strong>primary repo currently has checked out</strong>
1501
+ <span class="fp" data-path="scripts/teardown-agent-worktree.sh:72">scripts/teardown-agent-worktree.sh:72</span>.</li>
1502
+ <li>It never deletes the repo's <strong>default branch</strong> (<code>main</code>/<code>master</code>, or whatever
1503
+ <code>origin/HEAD</code> points at) <span class="fp" data-path="scripts/teardown-agent-worktree.sh:74">scripts/teardown-agent-worktree.sh:74</span>. This
1504
+ matters because <code>gh pr merge --delete-branch</code> often leaves the merged worktree
1505
+ sitting on the default branch — deleting it here would nuke local <code>main</code>.</li>
1506
+ <li>Otherwise it runs <code>git branch -D &#x3C;branch></code>
1507
+ <span class="fp" data-path="scripts/teardown-agent-worktree.sh:77">scripts/teardown-agent-worktree.sh:77</span>, and if that fails (checked out
1508
+ elsewhere, already gone) it just notes it and exits cleanly.</li>
1509
+ </ul>
1510
+ <h3 id="recovering-orphaned-ledgers---recover">Recovering orphaned ledgers — <code>--recover</code></h3>
1511
+ <p><code>scaffold observe harvest --recover</code> only <strong>finalizes already-harvested</strong>
1512
+ active-archive entries whose worktree is no longer live. Run it from the primary
1513
+ repo: it lists the live worktrees, then rotates any active-archive entry whose
1514
+ worktree has gone away into the monthly archive. It does <strong>not</strong> recover a ledger
1515
+ that was never harvested — if a worktree's <code>.scaffold/activity.jsonl</code> was deleted
1516
+ with the worktree before any harvest ran (<code>git worktree remove</code> by hand, a deleted
1517
+ directory, a crashed machine), that ledger is gone and cannot be recovered. This
1518
+ is why teardown must always harvest first. See the
1519
+ <a href="../observability/index.md">observability guide</a> for the active-vs-monthly
1520
+ archive mechanics.</p>
1521
+ <p><code>scaffold observe harvest</code> must run from the <strong>primary</strong> repo, not from inside a
1522
+ worktree — the CLI rejects a worktree primary root
1523
+ <span class="fp" data-path="src/cli/commands/observe.ts:191">src/cli/commands/observe.ts:191</span> and warns when the target worktree has no
1524
+ <code>identity.json</code> to key the archive on <span class="fp" data-path="src/cli/commands/observe.ts:194">src/cli/commands/observe.ts:194</span>.</p>
1525
+ <div class="callout callout-note"><p><strong>Empty ledgers are fine.</strong> A worktree that never recorded an event has no
1526
+ <code>activity.jsonl</code>; harvest is a clean no-op and teardown proceeds normally.</p></div>
1527
+ <h2 id="resuming-after-a-break">Resuming after a break</h2>
1528
+ <p>Coming back to parallel work — a context reset, a paused session, the next
1529
+ morning — does <strong>not</strong> mean re-running setup. The worktree and its
1530
+ <code>identity.json</code> persist on disk. Instead:</p>
1531
+ <ol>
1532
+ <li>Return to the agent's worktree directory (<code>../&#x3C;repo>-&#x3C;agent></code>).</li>
1533
+ <li>Run <strong><code>multi-agent-resume &#x3C;agent-name></code></strong> (or <code>single-agent-resume</code> for the
1534
+ non-worktree case). It verifies the worktree environment, syncs with <code>main</code>,
1535
+ reconciles task status against any PRs merged while you were away, and
1536
+ resumes the TDD loop from wherever the previous session stopped.</li>
1537
+ </ol>
1538
+ <p>Only run <code>setup-agent-worktree.sh</code> again if the worktree itself was torn down.
1539
+ Re-running it on a live worktree is harmless — the identity write is skipped
1540
+ when <code>identity.json</code> already exists — but it does no useful work.</p>
1541
+ <h2 id="see-also">See also</h2>
1542
+ <ul>
1543
+ <li><a href="../observability/index.md">Build Observability</a> — the ledger, harvest, and
1544
+ <code>--recover</code> archive mechanics this guide defers to.</li>
1545
+ <li><code>docs/git-workflow.md</code> §7 — the canonical worktree commands and conflict
1546
+ rules <span class="cite-advisory" data-path="docs/git-workflow.md:150">docs/git-workflow.md:150</span>.</li>
1547
+ </ul></main>
1548
+ <div class="rail-backdrop" data-action="nav" aria-hidden="true"></div>
1549
+ </div>
1550
+ <script>(function(){
1551
+ var LS_KEY = 'guide-theme';
1552
+ function applyTheme(t) {
1553
+ document.documentElement.setAttribute('data-theme', t);
1554
+ }
1555
+
1556
+ document.addEventListener('DOMContentLoaded', function() {
1557
+ // ─── Theme toggle ────────────────────────────────────────────────────────
1558
+ document.querySelectorAll('[data-action="theme"]').forEach(function(btn) {
1559
+ btn.addEventListener('click', function() {
1560
+ var current = document.documentElement.getAttribute('data-theme');
1561
+ var next = current === 'dark' ? 'light' : 'dark';
1562
+ applyTheme(next);
1563
+ try { localStorage.setItem(LS_KEY, next); } catch(e) {}
1564
+ });
1565
+ });
1566
+
1567
+ // ─── Mobile nav (drawer + backdrop; aria-expanded + Escape-to-close) ──────
1568
+ function setNav(open) {
1569
+ var rail = document.querySelector('.rail');
1570
+ if (rail) rail.classList.toggle('open', open);
1571
+ var toggle = document.querySelector('.nav-toggle');
1572
+ if (toggle) toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
1573
+ // Modal-drawer focus containment: while open, make the page content inert
1574
+ // (out of tab order + a11y tree) and move focus into the drawer; on close,
1575
+ // restore content and return focus to the toggle.
1576
+ var main = document.querySelector('.content');
1577
+ if (main) main.inert = open;
1578
+ if (open) {
1579
+ var first = rail && rail.querySelector('a, button, [tabindex]:not([tabindex="-1"])');
1580
+ if (first) first.focus();
1581
+ else if (rail) { rail.setAttribute('tabindex', '-1'); rail.focus(); }
1582
+ } else if (toggle) {
1583
+ toggle.focus();
1584
+ }
1585
+ }
1586
+ // If the viewport grows past the mobile breakpoint while the drawer is open,
1587
+ // the rail becomes the desktop sidebar and the toggle hides — clear the open
1588
+ // state so .content doesn't stay inert with no way to close it.
1589
+ if (window.matchMedia) {
1590
+ var mq = window.matchMedia('(max-width: 860px)');
1591
+ var onMq = function() {
1592
+ if (mq.matches) return;
1593
+ var rail = document.querySelector('.rail');
1594
+ if (rail) rail.classList.remove('open');
1595
+ var toggle = document.querySelector('.nav-toggle');
1596
+ if (toggle) toggle.setAttribute('aria-expanded', 'false');
1597
+ var main = document.querySelector('.content');
1598
+ if (main) main.inert = false;
1599
+ };
1600
+ if (mq.addEventListener) mq.addEventListener('change', onMq);
1601
+ else if (mq.addListener) mq.addListener(onMq);
1602
+ }
1603
+ document.querySelectorAll('[data-action="nav"]').forEach(function(btn) {
1604
+ btn.addEventListener('click', function() {
1605
+ var rail = document.querySelector('.rail');
1606
+ setNav(!(rail && rail.classList.contains('open')));
1607
+ });
1608
+ });
1609
+ // Selecting a TOC link closes the drawer (so the now-active content isn't
1610
+ // left inert behind the panel) before the anchor navigation scrolls.
1611
+ var drawerRail = document.querySelector('.rail');
1612
+ if (drawerRail) {
1613
+ drawerRail.querySelectorAll('a').forEach(function(a) {
1614
+ a.addEventListener('click', function() {
1615
+ if (drawerRail.classList.contains('open')) setNav(false);
1616
+ });
1617
+ });
1618
+ }
1619
+ document.addEventListener('keydown', function(e) {
1620
+ var rail = document.querySelector('.rail');
1621
+ if (!rail || !rail.classList.contains('open')) return;
1622
+ if (e.key === 'Escape') { setNav(false); return; } // setNav restores focus to the toggle
1623
+ // Trap Tab within the open drawer (modal pattern).
1624
+ if (e.key !== 'Tab') return;
1625
+ var f = rail.querySelectorAll('a[href], button, [tabindex]:not([tabindex="-1"])');
1626
+ if (!f.length) return;
1627
+ var first = f[0], last = f[f.length - 1];
1628
+ if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
1629
+ else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
1630
+ });
1631
+
1632
+ // ─── Copy buttons ─────────────────────────────────────────────────────────
1633
+ document.querySelectorAll('pre').forEach(function(pre) {
1634
+ if (!pre.parentNode) return;
1635
+ var wrapper = document.createElement('div');
1636
+ wrapper.className = 'code';
1637
+ pre.parentNode.insertBefore(wrapper, pre);
1638
+ wrapper.appendChild(pre);
1639
+ var btn = document.createElement('button');
1640
+ btn.className = 'copy-btn';
1641
+ btn.textContent = 'Copy';
1642
+ btn.addEventListener('click', function() {
1643
+ var text = pre.textContent || '';
1644
+ if (navigator.clipboard && navigator.clipboard.writeText) {
1645
+ navigator.clipboard.writeText(text).then(function() {
1646
+ btn.textContent = 'Copied';
1647
+ setTimeout(function() { btn.textContent = 'Copy'; }, 1200);
1648
+ }, function() {
1649
+ btn.textContent = 'Copy';
1650
+ });
1651
+ }
1652
+ });
1653
+ wrapper.insertBefore(btn, pre);
1654
+ });
1655
+
1656
+ // ─── Tabs (ARIA pattern: aria-selected + roving tabindex + arrow keys) ────
1657
+ function activateTab(group, btn, focus) {
1658
+ var idx = btn.getAttribute('data-tab');
1659
+ group.querySelectorAll('.tab-btn').forEach(function(b) {
1660
+ var on = b === btn;
1661
+ b.classList.toggle('active', on);
1662
+ b.setAttribute('aria-selected', on ? 'true' : 'false');
1663
+ b.setAttribute('tabindex', on ? '0' : '-1');
1664
+ });
1665
+ group.querySelectorAll('.tabpane').forEach(function(pane) {
1666
+ pane.classList.toggle('active', pane.getAttribute('data-tab') === idx);
1667
+ });
1668
+ if (focus) btn.focus();
1669
+ }
1670
+ document.querySelectorAll('.tabs').forEach(function(group) {
1671
+ var btns = [].slice.call(group.querySelectorAll('.tab-btn'));
1672
+ btns.forEach(function(btn, i) {
1673
+ btn.addEventListener('click', function() { activateTab(group, btn, false); });
1674
+ btn.addEventListener('keydown', function(e) {
1675
+ var ni = -1;
1676
+ if (e.key === 'ArrowRight' || e.key === 'ArrowDown') ni = (i + 1) % btns.length;
1677
+ else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') ni = (i - 1 + btns.length) % btns.length;
1678
+ else if (e.key === 'Home') ni = 0;
1679
+ else if (e.key === 'End') ni = btns.length - 1;
1680
+ if (ni >= 0) { e.preventDefault(); activateTab(group, btns[ni], true); }
1681
+ });
1682
+ });
1683
+ });
1684
+
1685
+ // ─── Filter tables ────────────────────────────────────────────────────────
1686
+ document.querySelectorAll('.filter-input').forEach(function(input) {
1687
+ input.addEventListener('input', function() {
1688
+ var q = input.value.toLowerCase();
1689
+ var container = input.closest('.filter-table');
1690
+ if (!container) return;
1691
+ container.querySelectorAll('tbody tr').forEach(function(row) {
1692
+ var text = (row.textContent || '').toLowerCase();
1693
+ row.style.display = text.includes(q) ? '' : 'none';
1694
+ });
1695
+ });
1696
+ });
1697
+
1698
+ // ─── Scrollspy ────────────────────────────────────────────────────────────
1699
+ if (typeof IntersectionObserver === 'undefined') return;
1700
+ var headings = document.querySelectorAll('h2[id],h3[id]');
1701
+ if (!headings.length) return;
1702
+ var observer = new IntersectionObserver(function(entries) {
1703
+ entries.forEach(function(entry) {
1704
+ if (!entry.isIntersecting) return;
1705
+ var id = entry.target.getAttribute('id');
1706
+ document.querySelectorAll('.toc a').forEach(function(a) {
1707
+ a.classList.toggle('active', a.getAttribute('href') === '#' + id);
1708
+ });
1709
+ });
1710
+ }, { rootMargin: '0px 0px -70% 0px', threshold: 0 });
1711
+ headings.forEach(function(h) { observer.observe(h); });
1712
+ });
1713
+ })();</script>
1714
+ </body>
1715
+ </html>