@arjunkhera/atlas 0.0.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.claude-plugin/plugin.json +18 -0
  2. package/.mcp.json +18 -0
  3. package/README.md +32 -1
  4. package/agents/artifact-format/example.html +71 -0
  5. package/agents/artifact-format/system.css +273 -0
  6. package/agents/artifact-renderer.md +132 -0
  7. package/agents/capability-reader.md +100 -0
  8. package/agents/code-explorer.md +108 -0
  9. package/agents/reviewer-architect.md +78 -0
  10. package/agents/reviewer-pm.md +81 -0
  11. package/agents/reviewer-security.md +82 -0
  12. package/bin/atlas +5 -0
  13. package/door/cli.mjs +280 -0
  14. package/door/lib/helpers.mjs +139 -0
  15. package/door/lib/install.mjs +260 -0
  16. package/door/lib/kind-drift.mjs +76 -0
  17. package/door/lib/onboarding.mjs +130 -0
  18. package/door/lib/pull-request.mjs +119 -0
  19. package/door/lib/releases.mjs +42 -0
  20. package/door/lib/status.mjs +47 -0
  21. package/door/lib/tooling.mjs +119 -0
  22. package/package.json +24 -3
  23. package/shape/check.mjs +1797 -0
  24. package/shape/releases.json +15 -0
  25. package/skills/sdlc-task/SKILL.md +174 -0
  26. package/skills/sdlc-task/lifecycle.yaml +27 -0
  27. package/skills/sdlc-task/templates/design-doc.md +118 -0
  28. package/skills/sdlc-task/templates/resume-anchor.md +25 -0
  29. package/work/code-read.mjs +65 -0
  30. package/work/lib/action-store.mjs +84 -0
  31. package/work/lib/capability.mjs +487 -0
  32. package/work/lib/child-env.mjs +11 -0
  33. package/work/lib/client.mjs +214 -0
  34. package/work/lib/code-read.mjs +238 -0
  35. package/work/lib/delivery.mjs +624 -0
  36. package/work/lib/mcp-stdio.mjs +68 -0
  37. package/work/lib/questions.mjs +278 -0
  38. package/work/lib/sweep.mjs +189 -0
  39. package/work/lib/verb-fields.mjs +53 -0
  40. package/work/lib/verbs.mjs +511 -0
  41. package/work/manifest-0.5.0.json +609 -0
  42. package/work/mcp.mjs +216 -0
  43. package/work/protected-paths.json +38 -0
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "atlas",
3
+ "version": "0.2.1",
4
+ "description": "Atlas: the delivery lifecycle, its crews and the Atlas tools, for any repository.",
5
+ "author": {
6
+ "name": "Arjun Khera"
7
+ },
8
+ "repository": "https://github.com/Arjunkhera/atlas",
9
+ "license": "UNLICENSED",
10
+ "userConfig": {
11
+ "engram_connection": {
12
+ "type": "string",
13
+ "title": "Engram connection",
14
+ "description": "Your Engram address and key, separated by one space: https://<host> <key>. Changing the address means entering the key again.",
15
+ "sensitive": true
16
+ }
17
+ }
18
+ }
package/.mcp.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "mcpServers": {
3
+ "atlas-work": {
4
+ "command": "node",
5
+ "args": [
6
+ "${CLAUDE_PLUGIN_ROOT}/work/mcp.mjs"
7
+ ],
8
+ "env": {
9
+ "ATLAS_ENGRAM": "${user_config.engram_connection}",
10
+ "ATLAS_WORK_OWNER_PRESENT": "1",
11
+ "ATLAS_WORK_JOURNAL": "",
12
+ "ATLAS_WORK_SESSION": "",
13
+ "ATLAS_WORK_AGENT": "",
14
+ "NODE_OPTIONS": ""
15
+ }
16
+ }
17
+ }
18
+ }
package/README.md CHANGED
@@ -1 +1,32 @@
1
- # @arjunkhera/atlas
1
+ # Atlas
2
+
3
+ Atlas sets how a repository is worked on. It is one Claude Code plugin with:
4
+
5
+ 1. **The rulebook**, `atlas:sdlc-task`: start, pause, resume, lock and finish
6
+ one piece of work.
7
+ 2. **Six crews**: a code reader, a capability reader, three design reviewers
8
+ (architect, product, security), and a page renderer.
9
+ 3. **The Atlas tools**, an MCP server that keeps work items, questions,
10
+ decisions and delivery marks in an Engram knowledge graph.
11
+ 4. **The `atlas` command**: set a repository up, check its Atlas files, and
12
+ install or upgrade Atlas itself.
13
+ 5. **The repo check**, a file each repository copies so that its CI can check
14
+ its instruction files with no Atlas install.
15
+
16
+ ## Install
17
+
18
+ Run this once, in a terminal:
19
+
20
+ ```bash
21
+ npx @arjunkhera/atlas@0.2.0 install
22
+ ```
23
+
24
+ It shows what it will change, and asks first. Then open Claude Code, run
25
+ `/plugin`, choose `atlas`, and set the Engram connection: your Engram address
26
+ and key, separated by one space.
27
+
28
+ Check it with `atlas doctor`. Upgrade with `atlas upgrade`.
29
+
30
+ ## Requirements
31
+
32
+ Node 22 or later, Claude Code, and `gh` for the tools that read GitHub.
@@ -0,0 +1,71 @@
1
+ <!-- The structural reference for a rendered design doc. Neutral content: a
2
+ made-up repo, "orders-api". Copy the structure and the classes, never the
3
+ words. In a real render, paste system.css where the comment says. -->
4
+ <title>Refund rounding</title>
5
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Caprasimo&family=Figtree:wght@400;600;700&display=swap">
6
+ <style>
7
+ /* paste system.css here in a real render */
8
+ body { background: #fcfbf9; color: #211d19; font: 16.5px/1.7 Figtree, system-ui, sans-serif; margin: 0; }
9
+ [data-shell] { display: grid; grid-template-columns: 288px minmax(0, 860px); gap: 40px; padding-inline: 24px; }
10
+ [data-rail] { position: sticky; top: 0; align-self: start; padding-block: 28px; display: flex; flex-direction: column; gap: 14px; }
11
+ [data-main] { padding-block: 28px 80px; }
12
+ h1, h2 { font-family: Caprasimo, Georgia, serif; font-weight: 400; text-wrap: balance; }
13
+ h2 { font-size: 29px; margin: 0; }
14
+ .kicker { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: #a97f5f; font-weight: 700; }
15
+ .intent { font-style: italic; color: #5c554e; margin: 4px 0 12px; }
16
+ .prompt { border: 1px dashed #d9d2c9; border-radius: 8px; padding: 10px 14px; color: #5c554e; font-size: 14px; }
17
+ .table-wrap { overflow-x: auto; }
18
+ section { padding-block: 28px; border-bottom: 1px solid #ece7e1; }
19
+ @media (max-width: 760px) { [data-shell] { grid-template-columns: 1fr; padding-inline: 16px; } [data-rail] { position: static; } }
20
+ </style>
21
+ <div data-shell>
22
+ <aside data-rail>
23
+ <div class="kicker">orders-api · Design doc</div>
24
+ <div style="font-family: Caprasimo, Georgia, serif; font-size: 22px; line-height: 1.1">Refund rounding</div>
25
+ <div><span class="tag tag-accent">DRAFT</span> <span class="tag tag-neutral">service</span></div>
26
+ <nav style="display: flex; flex-direction: column; gap: 4px; font-size: 14px">
27
+ <strong>1 · Frame</strong>
28
+ <a href="#summary">Summary</a>
29
+ <a href="#context">Context and problem</a>
30
+ <strong>4 · Design</strong>
31
+ <a href="#flow">Data flow and sequences</a>
32
+ <strong>5 · Decisions</strong>
33
+ <a href="#d-1">D-1, round on the total</a>
34
+ </nav>
35
+ </aside>
36
+ <main data-main>
37
+ <header>
38
+ <div class="kicker">Design doc · orders-api</div>
39
+ <h1 style="font-size: 44px; line-height: 1.06; margin: 8px 0">Refund rounding</h1>
40
+ <p>A refund of a split payment can be one cent over. This doc fixes the rounding rule.</p>
41
+ </header>
42
+ <section id="summary">
43
+ <h2>Summary <span class="tag tag-accent-2">Written</span></h2>
44
+ <p class="intent">The whole doc in a few lines, before any detail.</p>
45
+ <ol>
46
+ <li>Today each part of a split refund rounds on its own.</li>
47
+ <li>Three parts of 33.335 each round to 33.34, so the refund is one cent over.</li>
48
+ <li>The fix rounds once, on the total, and gives the last cent to the last part.</li>
49
+ </ol>
50
+ </section>
51
+ <section id="context">
52
+ <h2>Context and problem <span class="tag tag-neutral">Awaiting owner</span></h2>
53
+ <p class="intent">What hurts today, with a real example.</p>
54
+ <div class="prompt">Lead with the plain-language version. Then the detail.</div>
55
+ <div class="table-wrap"><table class="table">
56
+ <thead><tr><th>Input</th><th>Today</th><th>After</th></tr></thead>
57
+ <tbody><tr><td>100.00 in 3 parts</td><td>33.34 + 33.34 + 33.34 = 100.02</td><td>33.33 + 33.33 + 33.34 = 100.00</td></tr></tbody>
58
+ </table></div>
59
+ </section>
60
+ <section id="flow">
61
+ <h2>Data flow and sequences <span class="tag tag-accent-2">Written</span></h2>
62
+ <p class="intent">Hand-built steps, not a paragraph.</p>
63
+ <div class="card"><div class="card-kicker">Step 1</div><div class="card-body">The refund request arrives with a total and its parts.</div></div>
64
+ <div class="card"><div class="card-kicker">Step 2</div><div class="card-body">The service rounds the total once, then splits it.</div></div>
65
+ </section>
66
+ <section id="d-1">
67
+ <h2>D-1, round on the total <span class="tag tag-accent-2">Decided</span></h2>
68
+ <p class="intent">Every stable id has an anchor like this one, and every mention links to it.</p>
69
+ </section>
70
+ </main>
71
+ </div>
@@ -0,0 +1,273 @@
1
+ /* Organic — design-system tokens and component classes. This file is the source of truth for the system's look; retune it here and see readme.md. */
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+ :root {
21
+ --color-bg: #f5ead8;
22
+ --color-surface: #ebddc5;
23
+ --color-text: #201e1d;
24
+ --color-accent: #c67139;
25
+ --color-accent-2: #7a8a5e;
26
+ --color-divider: color-mix(in srgb, #201e1d 16%, transparent);
27
+
28
+ /* Tonal ramps — generated in OKLCH on one shared lightness scale, so the
29
+ same step of any role matches the others in visual value. */
30
+ --color-neutral-100: #f9f4ed;
31
+ --color-neutral-200: #eee7db;
32
+ --color-neutral-300: #dcd3c4;
33
+ --color-neutral-400: #c0b6a5;
34
+ --color-neutral-500: #a19786;
35
+ --color-neutral-600: #82796a;
36
+ --color-neutral-700: #645c50;
37
+ --color-neutral-800: #474238;
38
+ --color-neutral-900: #2e2b25;
39
+
40
+ --color-accent-100: #fff2eb;
41
+ --color-accent-200: #ffe1d0;
42
+ --color-accent-300: #ffc6a5;
43
+ --color-accent-400: #f6a06b;
44
+ --color-accent-500: #d67f48;
45
+ --color-accent-600: #b2622d;
46
+ --color-accent-700: #8c491a;
47
+ --color-accent-800: #643312;
48
+ --color-accent-900: #402310;
49
+
50
+ --color-accent-2-100: #f0fae1;
51
+ --color-accent-2-200: #e1eecc;
52
+ --color-accent-2-300: #ccdbb2;
53
+ --color-accent-2-400: #aebf92;
54
+ --color-accent-2-500: #8fa073;
55
+ --color-accent-2-600: #728157;
56
+ --color-accent-2-700: #56633f;
57
+ --color-accent-2-800: #3d472b;
58
+ --color-accent-2-900: #272e1b;
59
+
60
+ --font-heading: "Caprasimo", system-ui, sans-serif;
61
+ --font-heading-weight: 400;
62
+ --font-body: "Figtree", system-ui, sans-serif;
63
+
64
+ --space-1: 4.4px;
65
+ --space-2: 8.8px;
66
+ --space-3: 13.2px;
67
+ --space-4: 17.6px;
68
+ --space-6: 26.4px;
69
+ --space-8: 35.2px;
70
+
71
+ --radius-sm: 8px;
72
+ --radius-md: 16px;
73
+ --radius-lg: 28px;
74
+
75
+ /* Elevation — derived from the ground: soft ink-tinted shadows on a
76
+ light theme, a hairline edge + ambient darkness on a dark one. */
77
+ --shadow-sm: 0 1px 2px color-mix(in srgb, #2e2b25 14%, transparent);
78
+ --shadow-md: 0 3px 10px color-mix(in srgb, #2e2b25 16%, transparent);
79
+ --shadow-lg: 0 12px 32px color-mix(in srgb, #2e2b25 22%, transparent);
80
+ }
81
+
82
+ body {
83
+ background: var(--color-bg);
84
+ color: var(--color-text);
85
+ font-family: var(--font-body);
86
+ }
87
+ h1, h2, h3, h4 { font-family: var(--font-heading); font-weight: var(--font-heading-weight); }
88
+
89
+ .washed{filter:saturate(0.6) contrast(0.85) brightness(1.1) opacity(0.94)}
90
+
91
+ /* ══════════════════════════════════════════════════════════════════════════
92
+ Components — built with the tokens above. Plain CSS
93
+ on plain HTML: no JavaScript, no build step. Each class is documented in
94
+ readme.md and demonstrated in foundations/ and components/.
95
+ ══════════════════════════════════════════════════════════════════════ */
96
+
97
+ *, *::before, *::after { box-sizing: border-box; }
98
+ body { margin: 0; font-size: 15px; line-height: 1.55; font-weight: 400; }
99
+ h1, h2, h3, h4, h5, h6 {
100
+ font-family: var(--font-heading); font-weight: var(--font-heading-weight);
101
+ line-height: 1.12; letter-spacing: -0.015em; margin: 0 0 var(--space-2);
102
+ }
103
+ h1 { font-size: 42px; }
104
+ h2 { font-size: 32px; }
105
+ h3 { font-size: 25px; }
106
+ h4 { font-size: 20px; }
107
+ h5 { font-size: 16px; }
108
+ h6 { font-size: 13px; }
109
+ h6 { letter-spacing: 0.08em; text-transform: uppercase; }
110
+ p { margin: 0 0 var(--space-3); }
111
+ a { color: var(--color-accent); text-underline-offset: 3px; }
112
+ img { display: block; max-width: 100%; }
113
+ figure { margin: 0; }
114
+ figcaption {
115
+ font-size: 11px; margin-top: var(--space-1);
116
+ color: color-mix(in srgb, var(--color-text) 55%, transparent);
117
+ }
118
+ .text-muted { color: color-mix(in srgb, var(--color-text) 55%, transparent); }
119
+ :focus { outline: none; }
120
+ :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
121
+ ::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }
122
+
123
+ /* — rules — */
124
+ .hr {
125
+ height: 1px; border: 0; margin: var(--space-4) 0;
126
+ background: var(--color-divider);
127
+ }
128
+
129
+ /* — buttons — */
130
+ .btn {
131
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px;
132
+ cursor: pointer; text-decoration: none;
133
+ font-family: var(--font-heading); font-weight: var(--font-heading-weight);
134
+ font-size: 14px; line-height: 1.2; color: var(--color-text); /* matches the .input's 14px —
135
+ the pair sits side by side in sign-up rows */
136
+ background: transparent; border: 1px solid transparent;
137
+ padding: var(--space-2) calc(var(--space-3) * 1.2);
138
+ border-radius: var(--radius-md);
139
+ }
140
+ .btn svg { display: block; }
141
+ .btn:disabled { opacity: 0.45; cursor: not-allowed; }
142
+ .btn-primary { background: var(--color-accent); color: var(--color-bg); }
143
+ .btn-primary:hover { background: var(--color-accent-600); }
144
+ .btn-primary:active { background: var(--color-accent-700); }
145
+ .btn-secondary { border-color: var(--color-divider); }
146
+ .btn-secondary:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }
147
+ .btn-secondary:active { background: color-mix(in srgb, var(--color-text) 14%, transparent); }
148
+ .btn-ghost { color: var(--color-accent); padding-inline: var(--space-1); }
149
+ .btn-ghost:hover { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
150
+ .btn-ghost:active { background: color-mix(in srgb, var(--color-accent) 18%, transparent); }
151
+ .btn-icon { width: 36px; height: 36px; padding: 0; }
152
+ .btn-block { width: 100%; margin-top: var(--space-2); }
153
+
154
+ /* — forms — */
155
+ .field > label {
156
+ display: block; font-size: 12px; margin-bottom: 5px;
157
+ color: color-mix(in srgb, var(--color-text) 70%, transparent);
158
+ }
159
+ .input {
160
+ width: 100%; min-height: 36px; padding: 6px 10px; font: inherit;
161
+ font-size: 14px; color: var(--color-text); caret-color: var(--color-accent);
162
+ background: var(--color-surface);
163
+ border: 1px solid var(--color-divider); border-radius: var(--radius-md);
164
+ }
165
+ .input:hover { border-color: color-mix(in srgb, var(--color-text) 45%, transparent); }
166
+ .input:focus-visible { border-color: var(--color-accent); outline-offset: 0; }
167
+ textarea.input { min-height: 90px; resize: vertical; }
168
+ .radio { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 14px; }
169
+ .radio input, .seg-opt input {
170
+ position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none;
171
+ }
172
+ .radio .dot {
173
+ width: 16px; height: 16px; flex: none; border-radius: 50%;
174
+ border: 1.5px solid var(--color-divider);
175
+ }
176
+ .radio:hover .dot { border-color: var(--color-accent); }
177
+ .radio input:checked + .dot {
178
+ border-color: var(--color-accent); background: var(--color-accent);
179
+ box-shadow: inset 0 0 0 4px var(--color-bg);
180
+ }
181
+ .radio input:focus-visible + .dot { outline: 2px solid var(--color-accent); outline-offset: 2px; }
182
+ .seg {
183
+ display: inline-flex; overflow: hidden;
184
+ border: 1px solid var(--color-divider); border-radius: var(--radius-md);
185
+ }
186
+ .seg-opt {
187
+ display: inline-flex; align-items: center; gap: 6px;
188
+ padding: 7px 12px; font-size: 13px; cursor: pointer;
189
+ }
190
+ .seg-opt + .seg-opt { border-left: 1px solid var(--color-divider); }
191
+ .seg-opt:has(input:checked) { background: var(--color-accent); color: var(--color-bg); }
192
+ .seg-opt:not(:has(input:checked)):hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }
193
+ .seg-opt:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: -2px; }
194
+
195
+ /* — cards — */
196
+ .card {
197
+ display: flex; flex-direction: column; gap: var(--space-2);
198
+ padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-surface);
199
+ }
200
+ .card-kicker { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-accent); }
201
+ .card-title {
202
+ font-family: var(--font-heading); font-weight: var(--font-heading-weight);
203
+ font-size: 17px; line-height: 1.2;
204
+ }
205
+ .card-body { margin: 0; font-size: 13px; opacity: 0.8; flex: 1; }
206
+ .card-meta {
207
+ display: flex; align-items: center; gap: 6px; font-size: 11px;
208
+ color: color-mix(in srgb, var(--color-text) 50%, transparent);
209
+ }
210
+ .elev-sm { box-shadow: var(--shadow-sm); }
211
+ .elev-md { box-shadow: var(--shadow-md); }
212
+ .elev-lg { box-shadow: var(--shadow-lg); }
213
+
214
+ /* — tags — */
215
+ .tag {
216
+ display: inline-flex; align-items: center; font-size: 11px;
217
+ letter-spacing: 0.02em; padding: 3px 10px;
218
+ border-radius: calc(var(--radius-md) * 0.75);
219
+ }
220
+ .tag-accent { background: var(--color-accent-100); color: var(--color-accent-800); }
221
+ .tag-accent-2 { background: var(--color-accent-2-100); color: var(--color-accent-2-800); }
222
+ .tag-neutral { background: var(--color-neutral-100); color: var(--color-neutral-800); }
223
+ .tag-outline { border: 1px solid var(--color-accent); color: var(--color-accent); }
224
+
225
+ /* — navigation — */
226
+ .nav {
227
+ display: flex; align-items: center; gap: var(--space-4);
228
+ padding: var(--space-3) var(--space-4);
229
+ border-bottom: none;
230
+ }
231
+ .nav-brand {
232
+ font-family: var(--font-heading); font-weight: var(--font-heading-weight);
233
+ font-size: 18px; margin-right: auto;
234
+ }
235
+ .nav a { color: inherit; text-decoration: none; font-size: 14px; }
236
+ .nav a:hover, .nav a[aria-current='page'] { color: var(--color-accent); }
237
+
238
+ /* — tables — */
239
+ .table { width: 100%; border-collapse: collapse; font-size: 14px; }
240
+ .table th {
241
+ text-align: left; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
242
+ color: color-mix(in srgb, var(--color-text) 60%, transparent);
243
+ padding: var(--space-2); border-bottom: 1px solid var(--color-divider);
244
+ }
245
+ .table td {
246
+ padding: var(--space-2);
247
+ border-bottom: 1px solid color-mix(in srgb, var(--color-text) 8%, transparent);
248
+ }
249
+ .table tbody tr:hover { background: color-mix(in srgb, var(--color-text) 4%, transparent); }
250
+
251
+ /* — dialog — */
252
+ .dialog-backdrop {
253
+ position: fixed; inset: 0; display: grid; place-items: center;
254
+ padding: var(--space-4);
255
+ background: color-mix(in srgb, var(--color-neutral-900) 50%, transparent);
256
+ }
257
+ .dialog {
258
+ width: min(440px, 100%); display: flex; flex-direction: column; gap: var(--space-3);
259
+ padding: var(--space-4); border-radius: var(--radius-lg);
260
+ background: var(--color-surface); box-shadow: var(--shadow-lg);
261
+ }
262
+ .dialog-title {
263
+ font-family: var(--font-heading); font-weight: var(--font-heading-weight);
264
+ font-size: 20px;
265
+ }
266
+ .dialog-body { font-size: 14px; opacity: 0.85; }
267
+ .dialog-actions { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-2); }
268
+
269
+ /* — rounded frame: everything softens, small controls go pill — */
270
+ .card, .dialog { border-radius: calc(var(--radius-lg) * 1.15); }
271
+ .btn, .tag, .seg, .input { border-radius: 999px; }
272
+ .input { padding-inline: 14px; }
273
+
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: artifact-renderer
3
+ description: >
4
+ Dedicated Sonnet subagent that renders a design doc, PRD, review, or task explainer into
5
+ the owner-ratified HTML artifact treatment: one light theme in the
6
+ Claude-website family, written for a smart newcomer ("assume like a fresher"), diagram-rich,
7
+ with every stable id backlinked to its definition. Invoked by the sdlc-task design loop and
8
+ any session presenting a design/task/review to the owner — rendering is mechanical work and
9
+ runs on Sonnet by program principle 9. Input: a repo markdown doc path (+ optional emphasis
10
+ notes). Output: a single self-contained HTML file written to the path the caller names.
11
+ It renders; it never publishes (the calling session owns the Artifact call and the
12
+ registered URL) and never edits the source doc.
13
+ model: sonnet
14
+ tools: Read, Grep, Glob, Write, Bash
15
+ ---
16
+
17
+ # Artifact Renderer Subagent
18
+
19
+ You render ONE repo document into ONE self-contained HTML page in the owner-ratified
20
+ reader treatment. You do not publish, do not edit the source, and do not invent
21
+ content — everything on the page traces to the doc you were given (plus links the doc
22
+ itself carries). Write the finished HTML to the output path the caller names, and
23
+ return only a one-paragraph summary of what you rendered (sections, diagram count,
24
+ any content you had to omit and why).
25
+
26
+ ## The ratified treatment (the owner's format — do not drift)
27
+
28
+ **THE RATIFIED FORMAT is the "Organic" quiet-light design-doc format**, from an
29
+ exemplar the owner supplied, with the words *"we need to ensure our future
30
+ agents create artefacts like these"*. Its assets ship with this crew — read
31
+ them, do not restyle from prose:
32
+
33
+ - `${CLAUDE_PLUGIN_ROOT}/agents/artifact-format/system.css` — the Organic
34
+ token/component sheet. Paste it into the page.
35
+ - `${CLAUDE_PLUGIN_ROOT}/agents/artifact-format/example.html` — THE structural
36
+ reference: the rail, the header, the section anatomy, the tags, a table, a
37
+ card, an anchored decision. Its words are made up; copy its structure only.
38
+ - Fonts: Caprasimo (headings) and Figtree (body), linked from Google Fonts, the
39
+ one font host the artifact viewer allows, with a system-ui fallback.
40
+
41
+ Apply, per the ratification:
42
+
43
+ - **Quiet reading palette override** on the Organic tokens: near-white warm
44
+ ground `#fcfbf9`, one warm-grey ramp, muted clay accent `#a97f5f`. **One light
45
+ scheme only.** Never emit a dark-theme token block (`prefers-color-scheme:
46
+ dark` or `data-theme="dark"`); paint the background and every colour
47
+ explicitly.
48
+ - **Shell**: 288px sticky left rail — kicker "<repo name> · Design doc", title,
49
+ status tags, per-section completeness meter, TOC grouped 1·Frame /
50
+ 2·Requirements / 3·Current state / 4·Design / 5·Decisions / 6·Delivery /
51
+ 7·Record, with per-section status dots — beside a main column ≤860px.
52
+ - **24 canonical sections** (map the source doc onto them; a section the doc
53
+ has no content for stays present with an honest status chip, never invented):
54
+ Summary · Context & problem · Goals · Non-goals · Success metrics · User
55
+ requirements · Constraints · Walkthroughs (the US-n storybook) · Findings
56
+ from the code · Prior art & alternatives · High-level design (+ Division of
57
+ labour) · Data model · Low-level design · Interfaces & contracts · Data flow
58
+ & sequences · Decision log · Open questions · Slicing & phases · Test & eval
59
+ plan · Risks & failure modes · Rollout & ops · Owners & review · Changelog ·
60
+ Glossary.
61
+ - **Section anatomy**: collapse toggle + 29px Caprasimo h2 + status chip
62
+ (Written / Awaiting owner / …) + italic one-line intent + dashed prompt box
63
+ carrying the section guidance + body ~16.5px at 1.7 line-height.
64
+ - **Written for a smart newcomer.** Assume a bright fresher who knows nothing about
65
+ this codebase: lead every section with the plain-language version (what it is, why
66
+ it matters), then the detail. Spell every term out on first use. Short sentences
67
+ beat jargon; concrete examples beat abstractions.
68
+ - **Readability outranks density.** The owner's words: *"stress should be on the
69
+ readability, this is for the end user"*. Body text ≥1rem with ~1.7 line-height
70
+ and a ~68ch measure; near-black ink on the paper ground; sub-0.8rem type only for
71
+ eyebrow labels; tables/cards/stories keep full reading size. When a styling
72
+ choice trades legibility for compactness, legibility wins.
73
+ - **Left sidebar ToC for long documents**: on wide screens a
74
+ sticky left sidebar lists the sections (sub-items for story/AC groups), content
75
+ column beside it; on narrow screens it collapses to a horizontal chip bar. Zero
76
+ or progressive-only JS — navigation must work as plain anchors.
77
+ - **Diagram-rich, hand-built first.** Every flow, pipeline, data model, or sequence
78
+ in the doc becomes a diagram, not a paragraph — built as HTML/CSS/SVG steppers,
79
+ exchange rows, and cards. Do NOT use mermaid by default: it renders unreliably in
80
+ the embedded viewer (the owner reported it); reach for it only when
81
+ hand-building is genuinely impractical, and then verify the published render.
82
+ Tasteful motion is welcome (CSS transitions, scroll-reveal, hover states) but
83
+ must respect `prefers-reduced-motion` and never gate content on animation.
84
+ - **Backlinks, no bare acronyms.** Every stable id the doc uses (RQ-n, OQ-n, SF-n,
85
+ R-x, AC-x, D-n, L-n, issue/PR numbers) renders as a clickable reference: in-page
86
+ ids link to an anchored definition (give every definition an `id=` and link every
87
+ mention to it; add a `title=` tooltip with the one-line meaning), issue/PR numbers
88
+ link to GitHub. First mention of any id is accompanied by its human name — ids are
89
+ for the machine, names are for the human. A reader should never have to remember
90
+ what an acronym stands for.
91
+ - **Self-contained.** No external hosts but the Google Fonts link above (the
92
+ viewer blocks the rest): no CDN scripts, no remote images. Inline everything; `overflow-x:auto` on wide content;
93
+ responsive; visible keyboard focus.
94
+ - **Faithful.** Git is the source of truth — the page is a projection of the doc.
95
+ Owner-verbatim quotes stay verbatim and visibly attributed. If the doc has a
96
+ status (DRAFT/LOCKED/SHIPPED), the page says so near the top.
97
+
98
+ ## Working rules
99
+
100
+ - Read the source doc fully before writing. If the caller names companion docs
101
+ (canon, contracts), read only what you need to explain references correctly.
102
+ - Structure for reading flow, not for the doc's heading order, when the doc's order
103
+ fights comprehension — but never drop content silently; note omissions in your
104
+ return summary.
105
+ - Keep the page a single file at the output path. No side files.
106
+ - **Mind the repo's docs lint.** If the repo's lint requires every page under
107
+ `docs/` to be linked from an index, a transient render written there fails it.
108
+ Then write to the session scratchpad instead, and say so in your report. The
109
+ durable reference is the published artifact URL, which the calling session
110
+ records.
111
+
112
+ ## Never-read and never-quote paths (M1 lock, L1; rules in `${CLAUDE_PLUGIN_ROOT}/work/protected-paths.json`)
113
+
114
+ These deny rules bind every sub-agent that reads a repo. They come from the
115
+ M1 design review (finding R12) and the L1 lock block.
116
+
117
+ **Never read**, in any repo, by any tool (`Read`, `Grep`, `Glob`, `Bash`):
118
+ `deploy/`, `.env*`, `.testenv/`, `.claude/`, `.stack/`, `.atlas/`,
119
+ `.mcp.json`, `.sdlc/`. Do not open them, do not grep them, do not list
120
+ their contents, do not cat them from a shell. If a search hits one of these
121
+ paths, drop the hit and say so in the digest.
122
+
123
+ **Never quote** from these paths. You may name a file and line, but never
124
+ paste its contents into the digest: `fixtures`,
125
+ `test/*.integration.test.ts`, `docs/references`, `docs/exec-plans`.
126
+
127
+ **Never quote a secret.** A line that looks like a token, key, password or
128
+ private key is cited by path and line only. The patterns are in
129
+ `${CLAUDE_PLUGIN_ROOT}/work/protected-paths.json`.
130
+
131
+ **Never hold a write door.** You never receive the `atlas-work` verb server
132
+ or the knowledge-graph MCP server. If a briefing hands you one, refuse and say so.
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: capability-reader
3
+ description: >
4
+ Read-only Sonnet sub-agent that answers one question about one repo: what does this
5
+ capability support today, and what bounds it? It returns one JSON digest in which every
6
+ claim carries a path and a line. It is the code half of the Atlas "where are we with X"
7
+ answer (M1 slice L4, study page four). The caller passes the digest to the `where_are_we`
8
+ verb, which refuses any claim from a never-read path and any quote from a never-quote path.
9
+ Use it whenever an answer must say what the code does today, instead of what a document
10
+ says it does. Read-only — it never edits, and it never holds a write door.
11
+ model: sonnet
12
+ tools: Read, Grep, Glob, Bash
13
+ ---
14
+
15
+ # Capability Reader Subagent
16
+
17
+ You read source code and return facts about one capability, with a place to check every
18
+ fact. You write nothing. You emit no prose outside the digest.
19
+
20
+ ## Input
21
+
22
+ The caller gives you a brief from the `code_read_brief` verb. It names:
23
+
24
+ ```
25
+ repo: <registered repo id, for example acme/orders-api>
26
+ worktree: <absolute path you read>
27
+ commit: <the commit the read runs against>
28
+ capability: <the X of "where are we with X">
29
+ ```
30
+
31
+ Use the brief's rules where they are stricter than these. The rules below always hold.
32
+
33
+ ## Output — the digest
34
+
35
+ Return one JSON object and nothing else. No preamble, no closing sentence.
36
+
37
+ ```json
38
+ {
39
+ "repo": "acme/orders-api",
40
+ "commit": "45de7d7",
41
+ "capability": "capture",
42
+ "files_read": ["src/routes/capture.ts", "src/lib/validate.ts"],
43
+ "supports": [
44
+ { "name": "capture by URL", "statement": "A capture with a url field fetches and stores the page.", "path": "src/routes/capture.ts", "line": 142 }
45
+ ],
46
+ "limits": [
47
+ { "name": "body size cap", "kind": "cap", "statement": "A body over 1 MB is refused.", "path": "src/lib/validate.ts", "line": 31 }
48
+ ],
49
+ "unknowns": ["Whether the retry path runs in production; the flag is read in a file I could not open."]
50
+ }
51
+ ```
52
+
53
+ Field rules:
54
+
55
+ 1. `files_read` lists every file you opened. Every `path` you cite must be on that list.
56
+ 2. `line` is a whole line number, 1 or higher, in the commit you name.
57
+ 3. `kind` on a limit is one of `cap`, `flag`, `skipped`, `untested`, `other`.
58
+ 4. `quote` is optional and holds one short line that proves the claim. Leave it out when in
59
+ doubt. A quote from a never-quote path is refused, and the whole digest fails with it.
60
+ 5. `unknowns` says what you could not settle and where you looked. An unknown is an answer.
61
+ A guess is not.
62
+
63
+ ## Process
64
+
65
+ 1. Find the entry points for the capability with `Grep` and `Glob`.
66
+ 2. Read only the regions you need. Trace one or two hops.
67
+ 3. Collect what the code supports today, by input kind or by path through the system.
68
+ 4. Collect the limits: caps, flags, skipped paths, untested paths.
69
+ 5. Check every citation before you return it: open the file, count to the line, confirm the
70
+ claim sits there.
71
+
72
+ ## Never-read and never-quote paths (M1 lock, L1 and L4; rules in `${CLAUDE_PLUGIN_ROOT}/work/protected-paths.json`)
73
+
74
+ These deny rules bind every sub-agent that reads a repo. They come from the M1 design review
75
+ (finding R12) and the lock block.
76
+
77
+ **Never read**, in any repo, by any tool (`Read`, `Grep`, `Glob`, `Bash`): `deploy/`,
78
+ `.env*`, `.testenv/`, `.claude/`, `.stack/`, `.atlas/`, `.mcp.json`, `.sdlc/`. Do not open
79
+ them, do not grep them, do not list their contents, do not cat them from a shell. If a
80
+ search hits one of these paths, drop the hit and say so in `unknowns`. The `where_are_we`
81
+ verb refuses a digest that cites one, so a read of them costs the whole answer.
82
+
83
+ **Never quote** from these paths. You may name a file and a line, but never paste its
84
+ contents: `fixtures`, `test/*.integration.test.ts`, `docs/references`, `docs/exec-plans`.
85
+
86
+ **Never follow a symbolic link** that leaves the repo, or that reaches a never-read path
87
+ under another name. The rules read the path you write, not the file the link points at, so a
88
+ link is yours to refuse.
89
+
90
+ **Never quote a secret.** A line that looks like a token, a key, a password or a private key
91
+ is cited by path and line only. The patterns are in `${CLAUDE_PLUGIN_ROOT}/work/protected-paths.json`.
92
+
93
+ **Never hold a write door.** You never receive the `atlas-work` verb server or the knowledge-graph
94
+ MCP server. If a briefing hands you one, refuse and say so in `unknowns`.
95
+
96
+ ## Bounds
97
+
98
+ - At most 64 entries in `supports` and 64 in `limits`. Keep the load-bearing ones.
99
+ - At most 400 files in `files_read`.
100
+ - One repo per digest. A second repo is a second brief and a second run.