@arjunkhera/atlas 0.3.7 → 0.3.9

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 (67) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/artifact-renderer.md +22 -22
  3. package/agents/verifier.md +29 -0
  4. package/door/cli.mjs +62 -12
  5. package/door/kit-releases.json +4 -0
  6. package/door/lib/design-build.mjs +409 -0
  7. package/door/lib/design.mjs +199 -118
  8. package/door/lib/markdown.mjs +160 -0
  9. package/door/lib/proof.mjs +127 -0
  10. package/door/lib/tests.mjs +190 -0
  11. package/package.json +2 -1
  12. package/skills/lead/SKILL.md +4 -1
  13. package/skills/sdlc-task/SKILL.md +33 -24
  14. package/skills/sdlc-task/design/README.md +187 -0
  15. package/skills/sdlc-task/design/parts/actors.md +26 -0
  16. package/skills/sdlc-task/design/parts/alternatives.md +24 -0
  17. package/skills/sdlc-task/design/parts/build.md +23 -0
  18. package/skills/sdlc-task/design/parts/calls.md +25 -0
  19. package/skills/sdlc-task/design/parts/change.md +27 -0
  20. package/skills/sdlc-task/design/parts/data.md +22 -0
  21. package/skills/sdlc-task/design/parts/done.md +23 -0
  22. package/skills/sdlc-task/design/parts/edges.md +24 -0
  23. package/skills/sdlc-task/design/parts/goals.md +27 -0
  24. package/skills/sdlc-task/design/parts/key.md +25 -0
  25. package/skills/sdlc-task/design/parts/migration.md +22 -0
  26. package/skills/sdlc-task/design/parts/order.md +24 -0
  27. package/skills/sdlc-task/design/parts/problem.md +22 -0
  28. package/skills/sdlc-task/design/parts/proof.md +24 -0
  29. package/skills/sdlc-task/design/parts/proposal.md +24 -0
  30. package/skills/sdlc-task/design/parts/records.md +24 -0
  31. package/skills/sdlc-task/design/parts/repos.md +25 -0
  32. package/skills/sdlc-task/design/parts/risks.md +24 -0
  33. package/skills/sdlc-task/design/parts/rollout.md +24 -0
  34. package/skills/sdlc-task/design/parts/routes.md +24 -0
  35. package/skills/sdlc-task/design/parts/scorecard.md +25 -0
  36. package/skills/sdlc-task/design/parts/security.md +22 -0
  37. package/skills/sdlc-task/design/parts/shared-decisions.md +24 -0
  38. package/skills/sdlc-task/design/parts/states.md +25 -0
  39. package/skills/sdlc-task/design/parts/stories.md +26 -0
  40. package/skills/sdlc-task/design/parts/summary.md +33 -0
  41. package/skills/sdlc-task/design/parts/why.md +22 -0
  42. package/skills/sdlc-task/design/parts/words.md +29 -0
  43. package/skills/sdlc-task/design/parts/yardstick.md +25 -0
  44. package/skills/sdlc-task/design/parts.yaml +306 -0
  45. package/skills/sdlc-task/lifecycle.yaml +2 -2
  46. package/skills/tests/SKILL.md +234 -0
  47. package/tests/contract.mjs +398 -0
  48. package/tests/drivers/function.mjs +30 -0
  49. package/tests/drivers/http.mjs +68 -0
  50. package/tests/drivers/index.mjs +65 -0
  51. package/tests/drivers/mcp-stdio.mjs +174 -0
  52. package/tests/environment.mjs +227 -0
  53. package/tests/errors.mjs +27 -0
  54. package/tests/evidence.mjs +113 -0
  55. package/tests/fresh.mjs +42 -0
  56. package/tests/guards.mjs +159 -0
  57. package/tests/index.mjs +11 -0
  58. package/tests/link-check.mjs +576 -0
  59. package/tests/procs.mjs +43 -0
  60. package/tests/redact.mjs +58 -0
  61. package/tests/scenario.mjs +325 -0
  62. package/tests/stand-in.mjs +74 -0
  63. package/tests/tests-yaml.mjs +258 -0
  64. package/tests/wait.mjs +44 -0
  65. package/tests/yaml.mjs +327 -0
  66. package/agents/artifact-format/walkthrough.html +0 -706
  67. package/skills/sdlc-task/templates/design-doc.md +0 -126
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atlas",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Atlas: the delivery lifecycle, its crews and the Atlas tools, for any repository.",
5
5
  "author": {
6
6
  "name": "Arjun Khera"
@@ -2,8 +2,8 @@
2
2
  name: artifact-renderer
3
3
  description: >
4
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,
5
+ the owner-ratified HTML artifact treatment (one light theme in the
6
+ Claude-website family), or draws one custom figure for a design part, written for a smart newcomer ("assume like a fresher"), diagram-rich,
7
7
  with every stable id backlinked to its definition. Invoked by the sdlc-task design loop and
8
8
  any session presenting a design/task/review to the owner — rendering is mechanical work and
9
9
  runs on Sonnet (sdlc-task skill, "Model tiering"). Input: a repo markdown doc path (+ optional emphasis
@@ -23,26 +23,26 @@ itself carries). Write the finished HTML to the output path the caller names, an
23
23
  return only a one-paragraph summary of what you rendered (sections, diagram count,
24
24
  any content you had to omit and why).
25
25
 
26
- ## Two formats: walkthrough for designs, Organic pages for the rest
27
-
28
- **A design doc made from the walkthrough template** (it has `## Part N —`
29
- and `### Step N —` lines) renders in the **walkthrough format**. The owner
30
- chose it on 7 October 2026, for designs explained to a new joiner with
31
- examples and pictures. Its reference file ships with this crew:
32
- `${CLAUDE_PLUGIN_ROOT}/agents/artifact-format/walkthrough.html`. Copy its
33
- CSS, script and structure, and swap in the doc's content:
34
-
35
- - One tab for each part, then a last "Reference" tab for the rest of the doc.
36
- - One step block for each step: the picture on the left, and the step text
37
- and an example card on the right. The example card holds the doc's
38
- `Example:` block, word for word.
39
- - One hand-built SVG for each part, built from the steps' `Picture:` lines.
40
- Each piece carries `data-step` with the step that adds it, so the picture
41
- builds up. Never use mermaid on the page.
42
- - The page works with all scripts removed. Each step block keeps its own
43
- copy of the picture, at that step's state. The reference file's comment
44
- states the contract.
45
- - The summary sits in a card at the top of Part 1.
26
+ ## Designs: figures only. Every other doc: an Organic page
27
+
28
+ **A design is a folder** with `design.yaml` and one file for each part.
29
+ `atlas design build <folder>` builds its page, with the rail, the bars, the
30
+ keys and both themes. You never build a design's page by hand.
31
+
32
+ For a design, the caller asks you for **one custom figure** for one part:
33
+ git lanes, a time line, a scorecard or a data diff. Write it as HTML inside a
34
+ fenced block with the info string `figure`, and return the block. The rules
35
+ are in `${CLAUDE_PLUGIN_ROOT}/skills/sdlc-task/design/README.md`, under
36
+ "Figures":
37
+
38
+ - Use the page tokens, such as `var(--accent)`, `var(--line)` and
39
+ `var(--card)`, so the figure works in the light and the dark theme. Never
40
+ write a colour with no token.
41
+ - A step has a title and one or two sentences. The reader sets the pace.
42
+ The figure prints as stills, and it works with its script removed.
43
+ - Meaning is never by colour alone.
44
+ - Close every tag. `atlas design check <folder>` flags a figure that does
45
+ not.
46
46
 
47
47
  **Every other doc** (an older design, a PRD, a review, a task explainer)
48
48
  renders in the Organic page format below.
@@ -76,6 +76,35 @@ Verified at <the head commit>, in a fresh worktree.
76
76
  Links made for this run: <none, or each ignored file linked>.
77
77
  ```
78
78
 
79
+ ## Scenario proofs
80
+
81
+ Use this section when the definition of done names scenario assertions,
82
+ such as `week-conflict/e3#a1b2c3`. The steps above still apply. These steps
83
+ replace step 2 for those lines.
84
+
85
+ 1. Make a fresh worktree of the branch, as in the steps above.
86
+ 2. Start the product from `atlas/tests.yaml` with run secrets. The kit in
87
+ `<area>/test/atlas/` does this when the scenarios run. Set `ATLAS_GUARDS_FROM`
88
+ to `atlas/tests.yaml` of the main branch. A scenario that needs a provided
89
+ secret follows the rules of the section "Ignored files and secrets".
90
+ 3. Run the scenarios that the line names, with the runner command of `tests.yaml`.
91
+ Note the run id. Evidence goes to `<area>/test/evidence/<run id>/`.
92
+ 4. For each named assertion, make your own check through a raw driver of
93
+ the kit (`test/atlas/drivers/`). Do not use the actions of the repo or its tests.
94
+ Write a short script in your scratch folder. It starts the environment, sends the
95
+ calls of the assertion, and reads the answers. Keep the answer that proves the result.
96
+ 5. Write the `--own` file in your scratch folder. It is a JSON object with one
97
+ entry for each assertion: `{ "week-conflict/e3": { "result": "pass", "proof": "refused, revision 2" } }`.
98
+ 6. Print the table with `atlas tests proof`. Give it `--root` for the area,
99
+ `--run` for the run id, and `--own` for your file.
100
+ Put the table under the heading of the proof comment. A blocked or failed way
101
+ in shows its reason in the table.
102
+ 7. Run the privacy check on the comment, and post it, as the steps above say.
103
+ In a cloud session `gh pr comment` may be blocked. Then do not retry.
104
+ Return the path of the comment file to the caller. The caller posts it.
105
+ 8. A line is PASS only when the run and your own check both pass. If they
106
+ differ, mark the line FAIL and show both results.
107
+
79
108
  ## Never-read and never-quote paths (rules in `${CLAUDE_PLUGIN_ROOT}/work/protected-paths.json`)
80
109
 
81
110
  These deny rules bind every sub-agent that reads a repo.
package/door/cli.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  // The atlas command: install, upgrade, doctor, check, status, the tooling
3
- // writer, the kind drift report, the code-read resolver, the STE check and
4
- // the design check.
3
+ // writer, the kind drift report, the code-read resolver, the STE check, the
4
+ // design check and page builder, and the tests verbs (the link check and the
5
+ // test kit writer).
5
6
  //
6
7
  // Stage 1 of the target design retired `setup`, `change`, `helpers` and
7
8
  // `test onboarding`: code that guesses meaning retires (decided 28
@@ -10,7 +11,7 @@
10
11
  //
11
12
  // Nothing here writes to the work graph, and nothing here merges. A person
12
13
  // merges every file the tooling writer writes, because both steer agents.
13
- import { resolve, join, dirname } from 'node:path';
14
+ import { resolve, join, dirname, basename } from 'node:path';
14
15
  import { fileURLToPath } from 'node:url';
15
16
  import { readFileSync, existsSync, realpathSync } from 'node:fs';
16
17
  import { spawnSync } from 'node:child_process';
@@ -22,8 +23,11 @@ import { scan, toText, verdict, CHECK_VERSION, SPECS } from '../shape/check.mjs'
22
23
  import { packagePackageVersion } from './lib/releases.mjs';
23
24
  import { install, upgrade, doctor } from './lib/install.mjs';
24
25
  import { checkPaths, LIMITS } from './lib/ste.mjs';
25
- import { checkDesignFile, MAX_STEP_SENTENCES } from './lib/design.mjs';
26
+ import { checkDesignFolder } from './lib/design.mjs';
27
+ import { writeDesignPage, readTracker } from './lib/design-build.mjs';
26
28
  import { loadPrivateTerms } from './lib/privacy.mjs';
29
+ import { checkCommand as testsCheck, writeCommand as testsWrite } from './lib/tests.mjs';
30
+ import { proofCommand as testsProof } from './lib/proof.mjs';
27
31
 
28
32
  export const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
29
33
  const ATLAS_VERSION = packagePackageVersion(PACKAGE_ROOT);
@@ -44,7 +48,21 @@ const HELP = `atlas — the door into a repo's Atlas files
44
48
  atlas ste <file or folder> … measure markdown and HTML against the STE limits
45
49
  --share also run the privacy filter, quotes included
46
50
  --terms <file> private terms; default ~/.config/atlas/private-terms.txt
47
- atlas design <file> … check a walkthrough design doc: summary, parts, an example and a picture in each step
51
+ atlas design check <folder> … check a design folder: each needed part, no state line, every code in the Key
52
+ atlas design build <folder> build the design's page from its folder
53
+ --tracker <file> the tracker data, as JSON, from the lead
54
+ --out <file> the page; default docs/artifacts/<folder name>.html
55
+ --draft build even when the check has findings, and mark the page a draft
56
+
57
+ atlas tests check --root <area> run the link check on the tests of an area
58
+ --halves <list> static, lint, run; default all three
59
+ --evidence <dir> where the evidence files are; default <area>/test/evidence
60
+ --guards-from <file> tests.yaml of the main branch; a changed guard part is a finding
61
+ --run <id> read the evidence of this run only; default the newest run
62
+ atlas tests write --root <area> copy the shipped test kit into <area>/test/atlas/
63
+ atlas tests proof --root <area> print the proof table of one run, one row for each assertion
64
+ --run <id> the run; default the newest run in the evidence folder
65
+ --own <file> JSON of the verifier's own checks: { id: { result, proof } }
48
66
 
49
67
  atlas install install Atlas for every folder on this Mac
50
68
  atlas upgrade [--version <v>] check, show and install a newer release
@@ -70,7 +88,8 @@ export const FLAGS = Object.freeze({
70
88
  'kind-drift': { root: 'optional', 'record-kind': 'value', registry: 'value', repo: 'value' },
71
89
  check: { root: 'optional', repo: 'value', 'fail-on': 'value' },
72
90
  ste: { share: 'switch', terms: 'value' },
73
- design: {},
91
+ design: { tracker: 'value', out: 'value', draft: 'switch' },
92
+ tests: { root: 'optional', halves: 'value', evidence: 'value', 'guards-from': 'value', tests: 'value', 'dry-run': 'switch', run: 'value', own: 'value' },
74
93
  install: { local: 'switch', from: 'value', 'skip-global': 'switch', yes: 'switch' },
75
94
  upgrade: { version: 'optional', yes: 'switch' },
76
95
  doctor: {},
@@ -208,18 +227,48 @@ function steCommand(chosen) {
208
227
  }
209
228
 
210
229
  function designCommand(chosen) {
211
- const paths = chosen._.slice(1);
212
- if (!paths.length) throw new Error('give a design doc: atlas design <file>');
230
+ const what = chosen._[1];
231
+ const folders = chosen._.slice(2);
232
+ if (what !== 'check' && what !== 'build') throw new Error('use atlas design check <folder> or atlas design build <folder>');
233
+ if (!folders.length) throw new Error(`give a design folder: atlas design ${what} <folder>`);
234
+ if (what === 'check' && (chosen.tracker !== undefined || chosen.out !== undefined || chosen.draft)) throw new Error('--tracker, --out and --draft work only with atlas design build.');
235
+ if (what === 'build') {
236
+ if (folders.length > 1) throw new Error('atlas design build takes one folder.');
237
+ const folder = resolve(folders[0]);
238
+ const out = resolve(chosen.out ?? join('docs', 'artifacts', `${basename(folder)}.html`));
239
+ const tracker = chosen.tracker !== undefined ? readTracker(resolve(chosen.tracker)) : null;
240
+ const result = writeDesignPage(folder, out, { tracker, draft: Boolean(chosen.draft) });
241
+ if (!result.html) {
242
+ for (const finding of result.findings) line(`${join(folders[0], finding.file)}:${finding.line} ${finding.rule} ${finding.why}`);
243
+ line('');
244
+ line(`No page written: the check has ${result.findings.length} finding(s). Fix them, or build a draft with --draft.`);
245
+ return 1;
246
+ }
247
+ line(`Wrote ${out}: ${result.parts} parts, ${result.groups} groups, ${result.figures} figure(s).${tracker ? '' : ' No tracker data: the tracker parts say so.'}`);
248
+ if (result.findings.length) line(`A draft: the check has ${result.findings.length} finding(s). Run atlas design check ${folders[0]}.`);
249
+ return 0;
250
+ }
213
251
  let count = 0;
214
- for (const path of paths) {
215
- for (const finding of checkDesignFile(resolve(path))) { count += 1; line(`${path}:${finding.line} ${finding.rule} ${finding.why}`); }
252
+ for (const folder of folders) {
253
+ for (const finding of checkDesignFolder(resolve(folder))) { count += 1; line(`${join(folder, finding.file)}:${finding.line} ${finding.rule} ${finding.why}`); }
216
254
  }
217
255
  line('');
218
- line(`${paths.length} design doc(s) read; ${count} finding(s). Each step needs an Example block and a picture, and at most ${MAX_STEP_SENTENCES} sentences before its example.`);
219
- line(count ? 'Fix the doc by hand. This check never rewrites.' : 'GREEN');
256
+ line(`${folders.length} design(s) read; ${count} finding(s). The parts each kind needs are in skills/sdlc-task/design/parts.yaml.`);
257
+ line(count ? 'Fix the design by hand. This check never rewrites.' : 'GREEN');
220
258
  return count ? 1 : 0;
221
259
  }
222
260
 
261
+ function testsCommand(chosen) {
262
+ const root = rootOf(chosen);
263
+ const what = chosen._[1];
264
+ if (what === 'check') {
265
+ return testsCheck({ halves: chosen.halves, evidence: chosen.evidence, tests: chosen.tests, guardsFrom: chosen['guards-from'], run: chosen.run }, root, line, PACKAGE_ROOT);
266
+ }
267
+ if (what === 'write') return testsWrite({ dryRun: Boolean(chosen['dry-run']) }, root, PACKAGE_ROOT, line);
268
+ if (what === 'proof') return testsProof({ run: chosen.run, own: chosen.own, evidence: chosen.evidence }, root, line);
269
+ throw new Error(`there is no tests verb "${what ?? ''}". Use check, write or proof.`);
270
+ }
271
+
223
272
  function checkCommand(chosen) {
224
273
  const root = rootOf(chosen);
225
274
  const report = scan({ root, repoId: chosen.repo ?? null });
@@ -250,6 +299,7 @@ export async function main(argv = process.argv.slice(2)) {
250
299
  case 'check': return checkCommand(chosen);
251
300
  case 'ste': return steCommand(chosen);
252
301
  case 'design': return designCommand(chosen);
302
+ case 'tests': return testsCommand(chosen);
253
303
  default: throw new Error(`there is no verb "${command}". Run "atlas help".`);
254
304
  }
255
305
  }
@@ -0,0 +1,4 @@
1
+ {
2
+ "note": "Every kit of the folder tests/ that a release of Atlas shipped, as the kit hash of its manifest (the sha256 of the sorted lines of path and file hash). The kit of this package is always accepted and need not be listed. When a release changes anything in tests/, add the kit hash of the release before it here. atlas tests check reads this list; git history is never read.",
3
+ "releases": []
4
+ }