@open-agent-toolkit/cli 0.2.30 → 0.2.32

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 (107) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/configuration.md +41 -0
  3. package/assets/docs/contributing/code.md +19 -7
  4. package/assets/docs/contributing/explainer-kit-verification.md +9 -1
  5. package/assets/docs/contributing/skills.md +9 -0
  6. package/assets/docs/provider-sync/commands.md +15 -10
  7. package/assets/docs/provider-sync/manifest-and-drift.md +23 -0
  8. package/assets/docs/provider-sync/providers.md +8 -2
  9. package/assets/docs/provider-sync/scope-and-surface.md +3 -1
  10. package/assets/docs/reference/file-locations.md +5 -0
  11. package/assets/docs/reference/troubleshooting.md +18 -0
  12. package/assets/docs/workflows/skills/explainer-kit-providers.md +16 -5
  13. package/assets/docs/workflows/skills/explainer-kit.md +98 -38
  14. package/assets/public-package-versions.json +4 -4
  15. package/assets/skills/create-agnostic-skill/references/docs/skills-guide.md +34 -22
  16. package/assets/skills/explainer-kit/SKILL.md +33 -8
  17. package/assets/skills/explainer-kit/briefs/project-recap.md +25 -7
  18. package/assets/skills/explainer-kit/recipes/project-recap.v2.json +72 -0
  19. package/assets/skills/explainer-kit/references/contracts.md +49 -17
  20. package/assets/skills/explainer-kit/references/destination-contract.md +141 -25
  21. package/assets/skills/explainer-kit/references/extension-contract.md +19 -10
  22. package/assets/skills/explainer-kit/references/visual-authoring.md +24 -0
  23. package/assets/skills/explainer-kit/references/visual-review.md +19 -5
  24. package/assets/skills/explainer-kit/schemas/author-request.v3.schema.json +241 -0
  25. package/assets/skills/explainer-kit/schemas/publish-receipt.v2.schema.json +215 -0
  26. package/assets/skills/explainer-kit/schemas/publish-request.v2.schema.json +34 -0
  27. package/assets/skills/explainer-kit/schemas/run-request.schema.json +4 -1
  28. package/assets/skills/explainer-kit/schemas/terminal-evidence.v1.schema.json +81 -0
  29. package/assets/skills/explainer-kit/schemas/visual-review-evidence.v1.schema.json +66 -0
  30. package/assets/skills/explainer-kit/scripts/lib/catalog.mjs +109 -3
  31. package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +550 -17
  32. package/assets/skills/explainer-kit/scripts/lib/durability.mjs +90 -8
  33. package/assets/skills/explainer-kit/scripts/lib/fs-safe.mjs +5 -0
  34. package/assets/skills/explainer-kit/scripts/lib/internal-references.mjs +538 -0
  35. package/assets/skills/explainer-kit/scripts/lib/package-coverage.mjs +129 -11
  36. package/assets/skills/explainer-kit/scripts/lib/publication-policy.mjs +54 -0
  37. package/assets/skills/explainer-kit/scripts/lib/recipes.mjs +2 -1
  38. package/assets/skills/explainer-kit/scripts/lib/records.mjs +139 -22
  39. package/assets/skills/explainer-kit/scripts/lib/s3-roots.mjs +353 -0
  40. package/assets/skills/explainer-kit/scripts/lib/s3-static.mjs +237 -107
  41. package/assets/skills/explainer-kit/scripts/lib/set-plan.mjs +1 -0
  42. package/assets/skills/explainer-kit/scripts/lib/terminal-evidence.mjs +157 -0
  43. package/assets/skills/explainer-kit/scripts/lib/visual-review.mjs +26 -6
  44. package/assets/skills/explainer-kit/scripts/run.mjs +1006 -144
  45. package/assets/skills/oat-agent-instructions-analyze/references/docs/provider-reference.md +14 -2
  46. package/assets/skills/oat-agent-instructions-apply/references/docs/provider-reference.md +14 -2
  47. package/assets/skills/oat-explainer-kit/SKILL.md +16 -3
  48. package/assets/skills/oat-explainer-kit/references/config-contract.md +13 -8
  49. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +50 -6
  50. package/assets/skills/oat-explainer-kit/references/migration.md +2 -1
  51. package/assets/skills/oat-explainer-kit/references/visual-review-callback.md +11 -0
  52. package/assets/skills/oat-explainer-kit/scripts/bind-project-sources.mjs +37 -15
  53. package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +83 -0
  54. package/assets/skills/oat-explainer-kit/scripts/derive-destination.mjs +91 -0
  55. package/assets/skills/oat-explainer-kit/scripts/finalize-tracked-run.mjs +66 -10
  56. package/assets/skills/oat-explainer-kit/scripts/resolve-config.mjs +60 -21
  57. package/assets/skills/oat-explainer-kit/scripts/resolve-paths.mjs +52 -8
  58. package/assets/skills/oat-explainer-kit/scripts/run.mjs +271 -36
  59. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +2 -2
  60. package/assets/skills/oat-project-complete/SKILL.md +19 -3
  61. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +2 -2
  62. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +8 -0
  63. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +2 -2
  64. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +2 -2
  65. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +2 -2
  66. package/dist/commands/config/index.d.ts.map +1 -1
  67. package/dist/commands/config/index.js +18 -0
  68. package/dist/commands/init/index.d.ts +2 -2
  69. package/dist/commands/init/index.d.ts.map +1 -1
  70. package/dist/commands/init/index.js +22 -13
  71. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  72. package/dist/commands/project/archive/archive-utils.js +57 -7
  73. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts +29 -0
  74. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts.map +1 -0
  75. package/dist/commands/project/archive/explainer-terminal-evidence.js +37 -0
  76. package/dist/commands/remove/skill/remove-skill.d.ts +4 -1
  77. package/dist/commands/remove/skill/remove-skill.d.ts.map +1 -1
  78. package/dist/commands/remove/skill/remove-skill.js +44 -5
  79. package/dist/commands/shared/adopt-stray.d.ts +5 -0
  80. package/dist/commands/shared/adopt-stray.d.ts.map +1 -1
  81. package/dist/commands/shared/adopt-stray.js +25 -4
  82. package/dist/commands/shared/native-skill-disposition.d.ts +22 -0
  83. package/dist/commands/shared/native-skill-disposition.d.ts.map +1 -0
  84. package/dist/commands/shared/native-skill-disposition.js +60 -0
  85. package/dist/commands/status/index.d.ts +2 -2
  86. package/dist/commands/status/index.d.ts.map +1 -1
  87. package/dist/commands/status/index.js +22 -13
  88. package/dist/config/oat-config.d.ts +2 -0
  89. package/dist/config/oat-config.d.ts.map +1 -1
  90. package/dist/config/oat-config.js +4 -0
  91. package/dist/config/resolve.d.ts.map +1 -1
  92. package/dist/config/resolve.js +1 -0
  93. package/dist/engine/compute-plan.d.ts +3 -2
  94. package/dist/engine/compute-plan.d.ts.map +1 -1
  95. package/dist/engine/compute-plan.js +1 -1
  96. package/dist/engine/index.d.ts +1 -1
  97. package/dist/engine/index.d.ts.map +1 -1
  98. package/dist/engine/index.js +1 -1
  99. package/dist/providers/copilot/paths.d.ts.map +1 -1
  100. package/dist/providers/copilot/paths.js +6 -4
  101. package/package.json +2 -2
  102. package/dist/commands/shared/cursor-skill-disposition.d.ts +0 -17
  103. package/dist/commands/shared/cursor-skill-disposition.d.ts.map +0 -1
  104. package/dist/commands/shared/cursor-skill-disposition.js +0 -41
  105. /package/assets/skills/explainer-kit/recipes/{project-recap.json → project-recap.v1.json} +0 -0
  106. /package/assets/skills/explainer-kit/schemas/{publish-receipt.schema.json → publish-receipt.v1.schema.json} +0 -0
  107. /package/assets/skills/explainer-kit/schemas/{publish-request.schema.json → publish-request.v1.schema.json} +0 -0
@@ -279,13 +279,24 @@ supported home for Cursor-only skills. Cursor also reads `.claude/skills/` and
279
279
  **Skill locations:**
280
280
 
281
281
  - Project:
282
- - `.github/skills/<skill-name>/SKILL.md`
282
+ - `.agents/skills/<skill-name>/SKILL.md` (**native canonical path**)
283
+ - `.github/skills/<skill-name>/SKILL.md` (**legacy/adoption path**)
283
284
  - `.claude/skills/<skill-name>/SKILL.md` (**Claude compatibility**)
284
285
  - Personal:
285
- - `~/.copilot/skills/<skill-name>/SKILL.md` (Copilot coding agent and GitHub Copilot CLI only)
286
+ - `~/.agents/skills/<skill-name>/SKILL.md` (**native canonical path**)
287
+ - `~/.copilot/skills/<skill-name>/SKILL.md` (**legacy/adoption path**)
286
288
  - `~/.claude/skills/<skill-name>/SKILL.md` (**Claude compatibility**; Copilot coding agent and GitHub Copilot CLI only)
287
289
 
288
- **Notable:** Like Cursor, Copilot reads from `.claude/skills/` for cross-tool compatibility at both project and personal scopes. Organization-level and enterprise-level skill support is coming soon.
290
+ **Notable:** Like Cursor, Copilot reads canonical `.agents/skills/` at project
291
+ and personal scope. OAT does not generate `.github/skills` or
292
+ `~/.copilot/skills` views; existing packages there remain adoption inputs.
293
+ Copilot agents and project rules still use `.github/agents`,
294
+ `~/.copilot/agents`, and `.github/instructions`.
295
+
296
+ OAT asks whether to adopt each unresolved legacy Copilot skill into canonical
297
+ storage or keep it Copilot-only as an exact known stray. Same-name canonical
298
+ collisions block keep-local. Legacy cleanup removes only verified clean managed
299
+ views and preserves changed or unverifiable content.
289
300
 
290
301
  **Notes:** The `license` field may be required in practice even though the spec marks it optional (see https://github.com/github/copilot-cli/issues/894).
291
302
 
@@ -343,16 +354,14 @@ Installs skills from GitHub repos, local paths, or GitLab URLs to any supported
343
354
 
344
355
  ### Symlink Approach (Recommended)
345
356
 
346
- Author skills in `.agents/skills/` (canonical) and distribute to provider-specific directories:
357
+ Author skills in `.agents/skills/` (canonical) and distribute only to providers
358
+ that require a provider-specific directory:
347
359
 
348
360
  ```bash
349
361
  # Claude Code
350
362
  ln -s ../../.agents/skills/my-skill .claude/skills/my-skill
351
363
 
352
- # GitHub Copilot
353
- ln -s ../../.agents/skills/my-skill .github/skills/my-skill
354
-
355
- # Cursor, Codex, and Gemini read .agents/skills/ natively — no symlink needed
364
+ # Cursor, Copilot, Codex, and Gemini read .agents/skills/ natively — no symlink needed
356
365
  ```
357
366
 
358
367
  For automated distribution, use **OAT sync** (for local/internal skills) or **`npx skills add`** (for remote/community skills):
@@ -365,11 +374,12 @@ oat sync --scope all
365
374
  npx skills add github-user/skill-repo -a claude-code -a github-copilot
366
375
  ```
367
376
 
368
- **Result: one canonical source, two symlinks, five tools.**
377
+ **Result: one canonical source, one symlink, five tools.**
369
378
 
370
- **Note:** Cursor, Codex, and Gemini read `.agents/skills/` directly at project
371
- and user scope. Keep `.cursor/skills/` for intentionally Cursor-only skills,
372
- not as a generated mirror of canonical content.
379
+ **Note:** Cursor, Copilot, Codex, and Gemini read `.agents/skills/` directly at
380
+ project and user scope. Keep `.cursor/skills/` for intentionally Cursor-only
381
+ skills, not as a generated mirror of canonical content. Treat `.github/skills/`
382
+ and `~/.copilot/skills/` as legacy Copilot adoption inputs, not mirrors.
373
383
 
374
384
  ---
375
385
 
@@ -523,31 +533,33 @@ The proposal has community interest but no official timeline or maintainer respo
523
533
 
524
534
  **Source:** https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices, https://github.com/agentskills/agentskills/tree/main/skills-ref
525
535
 
526
- ### Q: Does Cursor's native `.agents/skills/` support eliminate all provider views?
536
+ ### Q: Do native `.agents/skills/` mappings eliminate all provider views?
527
537
 
528
- **Answer:** No. Cursor, Codex, and Gemini need no skill mirror, but Claude Code
529
- and GitHub Copilot still use provider-specific paths:
538
+ **Answer:** No. Cursor, Copilot, Codex, and Gemini need no skill mirror, but
539
+ Claude Code still uses a provider-specific path. Provider-specific agent and
540
+ rule views also remain where those runtimes require them:
530
541
 
531
542
  | Tool | Native Path | Reads `.claude/skills/`? | Reads `.agents/skills/`? |
532
543
  | -------------- | ----------------- | ------------------------ | ------------------------ |
533
544
  | Claude Code | `.claude/skills/` | ✅ (native) | ❌ |
534
545
  | Cursor | `.agents/skills/` | ✅ (compatibility) | ✅ (native) |
535
546
  | Codex CLI | `.agents/skills/` | ❌ | ✅ (native) |
536
- | GitHub Copilot | `.github/skills/` | ✅ (compatibility) | |
547
+ | GitHub Copilot | `.agents/skills/` | ✅ (compatibility) | ✅ (native) |
537
548
  | Gemini CLI | `.agents/skills/` | ❌ | ✅ (native alias) |
538
549
 
539
- **Recommended approach:** Author skills in `.agents/skills/` (tool-agnostic canonical source), then symlink only where needed:
550
+ **Recommended approach:** Author skills in `.agents/skills/` (tool-agnostic
551
+ canonical source), then symlink only where needed:
540
552
 
541
553
  ```bash
542
- # Two symlinks needed:
554
+ # One symlink needed:
543
555
  ln -s ../../.agents/skills/my-skill .claude/skills/my-skill # Claude Code + Copilot compatibility
544
- ln -s ../../.agents/skills/my-skill .github/skills/my-skill # GitHub Copilot (native path)
545
- # Cursor, Codex, and Gemini read .agents/skills/ natively — no symlink needed
556
+ # Cursor, Copilot, Codex, and Gemini read .agents/skills/ natively no symlink needed
546
557
  ```
547
558
 
548
- **One canonical source, two symlinks, five tools.** (Copilot reads `.claude/skills/` cross-compat, so the `.github/skills` symlink is optional but recommended for explicitness.)
559
+ **One canonical source, one symlink, five tools.** Legacy `.github/skills` and
560
+ `~/.copilot/skills` entries are migration candidates, not recommended mirrors.
549
561
 
550
- **Note (updated July 2026):** Cursor, Codex, and Gemini read
562
+ **Note (updated August 2026):** Cursor, Copilot, Codex, and Gemini read
551
563
  `.agents/skills/` natively at project and user scope. No skill symlinks are
552
564
  needed for those providers.
553
565
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: explainer-kit
3
- version: 2.0.3
3
+ version: 2.1.0
4
4
  description: Use when building destination-neutral visual explainer artifacts from explicit, versioned inputs.
5
5
  user-invocable: true
6
6
  allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Agent, mcp__*
@@ -74,11 +74,13 @@ request.
74
74
  The recipe — never the author — selects each artifact's authoring path. Floor
75
75
  entries and expansion profiles declare `authoring: markdown` for the narrative
76
76
  path or `authoring: html` for the artistic path. The core invokes the author
77
- once per artifact with an `explainer-kit.author-request/v2` payload carrying the
77
+ once per artifact with an `explainer-kit.author-request/v3` payload carrying the
78
78
  artifact identity and type, its authoring path, the inlined brief from
79
79
  `briefs/`, the reconciled fact base, the resolved theme, the shell source for
80
- artistic artifacts, and the required narrative sections for narrative floor
81
- artifacts. It accepts only a schema-valid
80
+ artistic artifacts, the required narrative sections for narrative floor
81
+ artifacts, and canonical `artifactLinks` with explicit `index.html` site paths
82
+ and receiver-relative hrefs. Version 2 requests remain readable for replay. It
83
+ accepts only a schema-valid
82
84
  `explainer-kit.author-result/v2` with exactly one of `content.markdown` or
83
85
  `content.html` plus non-secret provenance, rejects excessive verbatim source
84
86
  overlap, retains each validated result under `source/author/` and its content
@@ -107,11 +109,28 @@ continues. Accepted expansion artifacts render to
107
109
  `site/{directory}/{slug}/{artifactId}/index.html` and are linked from the floor
108
110
  hub; floor artifacts keep their existing paths.
109
111
 
112
+ `project-recap@2` requires one complete navigational hub and makes diagrams,
113
+ decks, and deep dives adaptive expansions. The planner proposes one only when
114
+ it can name a distinct reader question, the supporting source evidence, and why
115
+ that medium improves on adding more hub prose. The prose brief governs
116
+ typographic roles, hierarchy, slide archetypes, diagram semantics,
117
+ fit-to-content composition, density, repetition, and medium choice. These are
118
+ editorial judgments, not new request fields or renderer rules.
119
+ `project-recap@1` remains readable for replay with its historical three-artifact
120
+ floor.
121
+
110
122
  ## Review, Approval, and Warnings
111
123
 
112
- Approval runs after theme, render, safety validation, the guideline checker, and
113
- render QA, immediately before publish and durability — so a reviewer approves
114
- rendered artifacts and the complete warning set, not raw prose.
124
+ Approval runs after theme, render, hard internal-reference validation, safety
125
+ validation, the guideline checker, and render QA, immediately before publish and
126
+ durability — so a reviewer approves rendered artifacts and the complete warning
127
+ set, not raw prose. The reference gate resolves `href`, `src`, `srcset`,
128
+ fragments, and safe embedded references against explicit manifest/site-tree
129
+ files. It may invoke the existing correction author once, then rerenders and
130
+ revalidates before any browser or visual review. A later visual correction also
131
+ rerenders and passes through the validation-only reference gate without
132
+ receiving another correction attempt. An exhausted `E_INTERNAL_REFERENCE`
133
+ finding fails closed and cannot reach durability.
115
134
 
116
135
  Interactive runs stop with an `incomplete` outcome once artifacts are built and
117
136
  checked. Review the rendered `site/` tree, the sources under `source/content/`,
@@ -144,7 +163,13 @@ succeed.
144
163
 
145
164
  Visual critics use the independent whole-set rubric in
146
165
  `references/visual-review.md`, which separates review judgment from
147
- medium-specific authoring rules.
166
+ medium-specific authoring rules. They assess typography, hierarchy,
167
+ composition, density, medium leverage, template repetition, diagram semantics,
168
+ and cross-artifact cohesion from rendered browser evidence. The rubric keeps
169
+ the existing provider-neutral result contract: `pass` means no required
170
+ correction remains, while `correct` carries concrete artifact-scoped actions
171
+ into the one bounded correction round. It does not assign design scores or
172
+ encode geometry thresholds.
148
173
 
149
174
  Render QA is opt-in. It runs only against an injected `browserProbe`, and the
150
175
  core never launches a browser of its own — reviewing the rendered output in a
@@ -34,14 +34,32 @@ Use the same terms, statuses, and numbers throughout.
34
34
 
35
35
  ## Floor
36
36
 
37
- Produce one rich narrative hub covering all six sections above. It must contain
38
- at least one high-level architecture diagram, structured lists where useful,
39
- and evidence tables for implementation and validation. The page should remain
40
- useful without any expansion artifact.
37
+ Produce one rich navigational hub covering all six sections above. It must
38
+ orient the reader, expose the project state and outcome in the first viewport,
39
+ and link every selected artifact with descriptive labels. The hub should remain
40
+ complete and useful without an expansion artifact.
41
+
42
+ Establish deliberate typographic roles for the title, framing statement,
43
+ section headings, labels, body text, and evidence annotations. Build hierarchy
44
+ through scale, spacing, contrast, and grouping instead of applying one repeated
45
+ card or section treatment everywhere. Keep density fit to the material: shorten
46
+ or restructure crowded passages, but do not pad sparse evidence with decorative
47
+ filler. Choose tables, lists, diagrams, and prose only when each medium makes
48
+ the evidence easier to understand.
41
49
 
42
50
  ## Expansion license
43
51
 
44
- Propose additional diagrams, a deep-dive, or a walkthrough deck when complexity
45
- earns it. Expansion should clarify a real boundary, flow, trade-off, or
46
- operational handoff that would overload the hub. Do not expand to repeat the
52
+ Propose a supporting diagram, walkthrough deck, or deep-dive only when it
53
+ answers a distinct reader question that the hub cannot answer cleanly. For
54
+ every proposal, identify the reader question, the source evidence that supports
55
+ it, and the rationale for choosing that medium. Do not expand to repeat the
47
56
  same story in another format.
57
+
58
+ Use a diagram when topology, direction, ownership, or flow carries meaning.
59
+ Preserve branches, fan-in, cycles, labels, and explicit relationships, and fit
60
+ the frame to the content rather than leaving a tiny graph in a large canvas.
61
+ Use a deck only when pacing adds value; choose slide archetypes to match the
62
+ story, such as an outcome opener, comparison, system view, decision, evidence,
63
+ or next-action frame. Vary composition to fit each claim instead of repeating
64
+ one template. Use a deep-dive when source-backed mechanics or trade-offs need
65
+ more room than the hub can give them.
@@ -0,0 +1,72 @@
1
+ {
2
+ "schemaVersion": "explainer-kit.recipe/v2",
3
+ "id": "project-recap",
4
+ "version": "2",
5
+ "sourceRoles": [
6
+ {
7
+ "role": "project",
8
+ "required": true,
9
+ "accepts": ["file", "directory", "git", "github"],
10
+ "minBindings": 1,
11
+ "maxBindings": 1
12
+ }
13
+ ],
14
+ "floor": [
15
+ {
16
+ "id": "project-recap",
17
+ "type": "hub",
18
+ "authoring": "html",
19
+ "template": "house-style",
20
+ "required": true,
21
+ "briefRef": "briefs/project-recap.md",
22
+ "requiredNarrative": [
23
+ "original-request",
24
+ "key-agent-decisions",
25
+ "as-built-architecture",
26
+ "implementation-record",
27
+ "validation-evidence",
28
+ "outcome"
29
+ ]
30
+ }
31
+ ],
32
+ "expansion": {
33
+ "profiles": [
34
+ {
35
+ "profileId": "supporting-diagram",
36
+ "type": "diagram",
37
+ "authoring": "html",
38
+ "briefRef": "briefs/supporting-diagram.md",
39
+ "shell": "diagram-shell",
40
+ "maxCount": 1
41
+ },
42
+ {
43
+ "profileId": "walkthrough-deck",
44
+ "type": "deck",
45
+ "authoring": "html",
46
+ "briefRef": "briefs/walkthrough-deck.md",
47
+ "shell": "deck-shell",
48
+ "maxCount": 1
49
+ },
50
+ {
51
+ "profileId": "deep-dive",
52
+ "type": "explainer",
53
+ "authoring": "markdown",
54
+ "briefRef": "briefs/deep-dive.md",
55
+ "maxCount": 3
56
+ }
57
+ ],
58
+ "limits": {
59
+ "maxArtifacts": 5
60
+ }
61
+ },
62
+ "fallback": {
63
+ "mode": "deterministic-markdown",
64
+ "selection": "explicit",
65
+ "authoring": "markdown",
66
+ "scope": "portfolio"
67
+ },
68
+ "discoveryLimits": {
69
+ "consecutiveNoNewFindingsRounds": 2,
70
+ "maxRounds": 8
71
+ }
72
+ }
@@ -34,25 +34,34 @@ Every run, interactive or unattended, also requires a provider-neutral author
34
34
  callback; a run without one fails `E_AUTHOR_REQUIRED`. An in-process caller
35
35
  supplies `options.author(request)`; a JSON-only CLI caller uses
36
36
  `--author-module author.mjs`. The core invokes it once per resolved artifact
37
- with an `explainer-kit.author-request/v2` payload containing the artifact
37
+ with an `explainer-kit.author-request/v3` payload containing the artifact
38
38
  identity and type, the artifact's authoring path, the inlined brief, the bundled
39
39
  `visualAuthoringGuidance`, the reconciled fact base, the resolved theme, the
40
40
  shell source for artistic artifacts, the required narrative sections for
41
- narrative floor artifacts, and bounded-discovery context. The guidance is
41
+ narrative floor artifacts, bounded-discovery context, and `artifactLinks`.
42
+ Each canonical link entry names the planned artifact, its explicit site-relative
43
+ path ending in `index.html`, and the relative `href` from the receiving
44
+ artifact's own location. The guidance is
42
45
  loaded only from the installed skill's `references/visual-authoring.md`; no
43
46
  ambient or home-directory file is consulted. The callback must return an
44
47
  `explainer-kit.author-result/v2` carrying exactly one of `content.markdown` or
45
48
  `content.html`, matching the artifact's declared authoring path, plus non-secret
46
49
  provenance. The executable callback is never persisted in `run-request.json`.
47
50
 
48
- Project recap requests have an explicit `recapMode`. Omitting it selects and
49
- persists `artistic`, which keeps the recipe's rich HTML floor. Selecting
50
- `deterministic-markdown` before the run applies the recipe-owned fallback to
51
- the complete planned portfolio, including optional expansions, while retaining
52
- the same adaptive hub, architecture, and deck identities. The resulting
53
- Markdown author records and `source/content/*.md` paths remain distinct in the
54
- manifest and immutable rebuild package. An artistic author failure fails the
55
- run; the core never silently retries or downgrades it as Markdown.
51
+ New project recap producers select immutable `project-recap@2`. Its
52
+ navigational hub is the only mandatory artifact. A diagram, deck, or deep dive
53
+ is an optional expansion only when its justification states a distinct reader
54
+ question, supporting source evidence, and the rationale for using that medium.
55
+ Project recap requests also have an explicit `recapMode`. Omitting it selects
56
+ and persists `artistic`, which keeps the recipe's rich HTML floor. Selecting
57
+ `deterministic-markdown` before the run applies the recipe-owned fallback to the
58
+ complete planned portfolio the hub plus any accepted expansions — without
59
+ changing its artifact identities. The resulting Markdown author records and
60
+ `source/content/*.md` paths remain distinct in the manifest and immutable
61
+ rebuild package. An artistic author failure fails the run; the core never
62
+ silently retries or downgrades it as Markdown. `project-recap@1` is immutable
63
+ replay guidance only: retained v1 requests remain readable, but current
64
+ producers do not select it.
56
65
 
57
66
  Before artifact authoring, a caller supplies one provider-neutral `planSet`
58
67
  callback. It receives the reconciled fact base and recipe policy and returns
@@ -62,7 +71,7 @@ callback. It receives the reconciled fact base and recipe policy and returns
62
71
  {
63
72
  "schemaVersion": "explainer-kit.set-plan/v1",
64
73
  "planId": "project-recap-set",
65
- "recipe": { "id": "project-recap", "version": "1" },
74
+ "recipe": { "id": "project-recap", "version": "2" },
66
75
  "sourceIds": ["plan"],
67
76
  "ledger": {
68
77
  "terminology": [],
@@ -87,9 +96,11 @@ The set plan owns the shared terminology/status/number ledger, source coverage,
87
96
  adaptive portfolio, per-artifact draft, and visual intent. Optional entries add
88
97
  a source-backed `justification`; undeclared sources, conflicting ledger values,
89
98
  duplicate artifact IDs, and unjustified optional entries are invalid. Each
90
- `author-request/v2` carries the complete immutable `setContext` plus the exact
99
+ `author-request/v3` carries the complete immutable `setContext` plus the exact
91
100
  matching `plannedArtifact`. The planner finalizes floor and expansion entries
92
101
  before authoring; author results cannot add, remove, or replace artifacts.
102
+ Version 2 requests remain valid for deterministic replay; new runs emit only
103
+ the complete v3 request.
93
104
  When a planner draft contains a supported non-linear graph, the request also
94
105
  carries its closed `graphSemantics` (direction, nodes, edges, and topology).
95
106
  Artistic HTML must expose one exact `data-direction`. Each planned node requires
@@ -183,12 +194,33 @@ The core executes:
183
194
  5. author every planned artifact against the same set context
184
195
  6. render typed artifacts through the narrative renderer or validate
185
196
  agent-composed HTML, per each artifact's declared authoring path
186
- 7. run structural and guideline QA, plus required browser and independent
197
+ 7. validate every post-render `href`, `src`, `srcset`, and embedded reference
198
+ against the manifest paths and generated site tree; reject directory links,
199
+ escapes, missing files or fragments, malformed references, and unsafe
200
+ embedded resources
201
+ 8. optionally apply one bounded author correction, then rerender and revalidate
202
+ the complete site before any browser callback
203
+ 9. run structural and guideline QA, plus required browser and independent
187
204
  visual review for unattended project recaps
188
- 8. close any unresolved recap review gate before external persistence
189
- 9. resolve content approval — the interactive gate pauses here, after render and
190
- QA and before anything is published or persisted externally
191
- 10. write the manifest and build record
205
+ 10. close any unresolved recap review gate before external persistence
206
+ 11. resolve content approval — the interactive gate pauses here, after render and
207
+ QA and before anything is published or persisted externally
208
+ 12. write the manifest and build record
209
+
210
+ The internal-reference gate uses a bounded tokenizer/classifier rather than a
211
+ general HTML parser. Relative references resolve from the current explicit file
212
+ with an isolated HTTPS base, then must bind exactly to the manifest/site tree.
213
+ Referenced fragments must resolve to exactly one ID in the target document;
214
+ unused duplicate renderer-generated IDs do not fail indexing. Safe base64 image
215
+ data references and same-document fragments are classified separately. A
216
+ malformed, unresolved, or ambiguous reference fails `E_INTERNAL_REFERENCE`.
217
+ Once the one correction is exhausted, including after visual correction, the run
218
+ fails hard: the QA stage is recorded `failed` with code-only evidence and the
219
+ scrubbed message `The qa stage failed.`, and the run is not durability- or
220
+ publication-eligible. No finding is retained and nothing names the broken
221
+ reference — terminal evidence is code-only by design, and the failure is
222
+ attributed to the `link-validation` evidence stage rather than to
223
+ `browser-review`.
192
224
 
193
225
  An incomplete interactive result includes
194
226
  `approval.resumeToken: "ekrt2:<64 lowercase hex characters>"`. The token is an
@@ -10,15 +10,39 @@ node scripts/publish.mjs \
10
10
  --confirm-publish
11
11
  ```
12
12
 
13
- The request uses `explainer-kit.publish-request/v1`. Credentials come only from
14
- the standard AWS credential chain or the request's optional profile. Never put
15
- access keys, secret keys, session tokens, or SSO tokens in a request.
16
-
17
- ## Corresponding roots
18
-
19
- `s3Uri` and `publicBaseUrl` must identify corresponding roots. Both are
20
- normalized without trailing slashes. For a path `P` relative to `siteRoot`, the
21
- connector writes `<s3Uri>/P` and verifies `<publicBaseUrl>/P`.
13
+ New requests use `explainer-kit.publish-request/v2` and explicitly declare
14
+ `publicAccess` as `public` or `protected`. V1 remains readable as public-mode
15
+ replay. Credentials come only from the standard AWS credential chain or the
16
+ request's optional profile. Never put access keys, secret keys, session tokens,
17
+ or SSO tokens in a request.
18
+
19
+ ## How the two roots compose
20
+
21
+ `s3Uri` and `publicBaseUrl` are each normalized without trailing slashes. For a
22
+ path `P` relative to `siteRoot`, the connector writes `<s3Uri>/P` and verifies
23
+ `<publicBaseUrl>/P`. That composition is the whole of the relationship.
24
+
25
+ **No relational validation is performed between the two roots, by design.** The
26
+ mapping from an S3 key to a public URL is underdetermined by these two strings:
27
+ it lives in CDN configuration the connector cannot read. Both of these are
28
+ legitimate, and they disagree structurally:
29
+
30
+ | Shape | `s3Uri` | `publicBaseUrl` |
31
+ | ----- | ---------------------------- | ----------------------------- |
32
+ | A | `s3://bucket/repositories/x` | `https://host/repositories/x` |
33
+ | B | `s3://bucket/explainers` | `https://host` |
34
+
35
+ B is an ordinary CloudFront **Origin Path** deployment, where a bucket prefix is
36
+ mapped to the distribution root. Requiring the public path to equal the S3 key
37
+ prefix rejects it. Suffix-containment does not rescue the rule either — an empty
38
+ public path is a suffix of everything, so B would pass vacuously while
39
+ path-rewriting deployments (CloudFront Functions, Lambda@Edge, custom origins)
40
+ still produce false rejections.
41
+
42
+ Divergence between the two paths is therefore reported as a **non-blocking
43
+ warning**, never a failure. Correctness of an advertised URL is established by
44
+ verification, not by string shape — which is also why `publicAccess: protected`,
45
+ where no anonymous fetch happens, cannot establish it at all.
22
46
 
23
47
  For example:
24
48
 
@@ -32,7 +56,39 @@ For example:
32
56
  | public URL | `https://cdn.example.com/published/initiatives/demo/index.html` |
33
57
 
34
58
  Use explicit `index.html` URLs. Directory redirects are not portable evidence.
35
- The destination must serve uploaded bytes at the corresponding public path.
59
+ The destination must serve the uploaded bytes at the composed public path. That
60
+ is a requirement on the deployment, not something the connector validates from
61
+ the two root strings; see below.
62
+
63
+ ## The manifest a connector receives is intentionally incomplete
64
+
65
+ The core persists the manifest **before** it invokes the publisher callback, so
66
+ the file at `manifestPath` carries `outcome: "incomplete"` while the `publish`
67
+ stage is still `running`. This is a contractually intended intermediate state,
68
+ not a corrupt or half-written record, and a connector must not reject it on the
69
+ strength of `outcome` alone.
70
+
71
+ Do not decide publishability from the manifest by itself. Read the build record
72
+ named by `manifest.buildRecord.path` (resolved relative to the manifest) and
73
+ require all of:
74
+
75
+ - the manifest carries no `visual-review-required:` warning;
76
+ - the build record's own `outcome` is `incomplete`;
77
+ - its `publish` stage exists and is `running`; and
78
+ - every stage before `publish` is `passed`, `warned`, or `skipped` and carries
79
+ no `visual-review-required:` warning.
80
+
81
+ Only that combination makes an `incomplete` manifest publishable. The one other
82
+ eligible shape is a finalized `built-durable` manifest that is not
83
+ review-flagged. Any other `incomplete` manifest, and every manifest whose run is
84
+ flagged, failed, or superseded, must be refused. The built-in connector performs
85
+ exactly this check before its first network call; third-party connectors are
86
+ required to perform an equivalent one.
87
+
88
+ The published bytes cannot diverge from the finalized manifest: the catalog
89
+ projection omits `outcome` and `warnings`, and both manifest writes share one
90
+ `finalizedAt`. After the callback returns a valid receipt, the core rewrites the
91
+ manifest with its terminal outcome.
36
92
 
37
93
  ## Safety and ordering
38
94
 
@@ -41,16 +97,22 @@ site-relative paths before network access. It then:
41
97
 
42
98
  1. uploads a sentinel whose path contains the run ID and a random 128-bit
43
99
  suffix;
44
- 2. verifies the sentinel with `head-object`;
45
- 3. fetches that exact sentinel through the public root;
100
+ 2. verifies the sentinel with a service-computed SHA-256 checksum or an
101
+ authenticated download hash;
102
+ 3. for public destinations, fetches that exact sentinel anonymously through the
103
+ public root; protected destinations skip this public fetch explicitly;
46
104
  4. deletes only that sentinel;
47
105
  5. uploads or idempotently skips each declared artifact;
48
- 6. verifies object metadata, content type, and SHA-256 of the exact response
49
- bytes from each public artifact URL; and
50
- 7. atomically writes `explainer-kit.publish-receipt/v1`.
106
+ 6. verifies exact object bytes from service-computed SHA-256 evidence or an
107
+ authenticated download hash, then additionally verifies the exact anonymous
108
+ response bytes for public destinations; and
109
+ 7. atomically writes `explainer-kit.publish-receipt/v2` with separate
110
+ authenticated-object and anonymous-public verification facts.
51
111
 
52
- If public sentinel verification fails, no artifact is uploaded. The connector
53
- attempts sentinel cleanup and emits no successful receipt.
112
+ If required sentinel verification fails or its verification capability is
113
+ unavailable, no artifact is uploaded. The connector attempts sentinel cleanup
114
+ and emits no successful receipt. An undeclared `401` or `403` in public mode is
115
+ a verification failure, never evidence that the destination is protected.
54
116
 
55
117
  Publishing is additive. The implementation uses individual `put-object`,
56
118
  `head-object`, and sentinel-only `delete-object` operations. It never performs
@@ -74,10 +136,13 @@ Every upload sets metadata explicitly:
74
136
  | other | manifest media type or `application/octet-stream` |
75
137
 
76
138
  Artifacts use `Cache-Control: public, max-age=300`. The connector stores the
77
- SHA-256 digest as object metadata for idempotency and verifies content type,
78
- cache control, and digest after upload. Public verification hashes response
79
- bytes without text decoding, so binary artifacts and stale wrong-byte 200
80
- responses are covered.
139
+ SHA-256 digest as object metadata for idempotency and supplies
140
+ `--checksum-sha256` on upload. It requests service checksum evidence with
141
+ `--checksum-mode ENABLED`; caller-authored metadata and ETags are never treated
142
+ as object-byte proof. When service SHA-256 evidence is unavailable, the
143
+ connector hashes bytes from an authenticated download. Public verification
144
+ separately hashes response bytes without text decoding, so binary artifacts and
145
+ stale wrong-byte 200 responses are covered.
81
146
 
82
147
  ## Failures and retries
83
148
 
@@ -86,9 +151,60 @@ not run `aws sso login`, retry with another profile, expose AWS diagnostics, or
86
151
  persist credentials. Refresh credentials separately and rerun after approval.
87
152
 
88
153
  Only transient individual object-operation failures receive bounded retries.
89
- Input, authorization, root-correspondence, metadata, and public-verification
90
- failures are not retried. A failed publish preserves the local package.
154
+ Input, authorization, metadata, and public-verification failures are not
155
+ retried. A failed publish preserves the local package.
91
156
 
92
157
  Public roots must be credential-free HTTPS URLs with no username, password,
93
- query, or fragment. Invalid roots fail before AWS or HTTP operations and are
94
- never persisted in receipts.
158
+ query, or fragment. Three further rejections apply, all before any AWS or HTTP
159
+ operation, and none of them are ever persisted in receipts:
160
+
161
+ - **Control characters.** Any codepoint in `0x00`–`0x1f` or `0x7f`–`0x9f`, and
162
+ any backslash, in either root. These otherwise reach S3 object keys, composed
163
+ public URLs, the catalog, the receipt and `aws` argv; `0x9b` is the 8-bit CSI.
164
+ - **Non-public addresses.** Loopback, link-local (`169.254.0.0/16`, `fe80::/10`,
165
+ including the `169.254.169.254` instance-metadata address), unique-local
166
+ (`fc00::/7`) and RFC 1918 private hosts, in both literal IPv4 and IPv6 forms
167
+ including IPv4-mapped spellings. Public verification issues an outbound GET
168
+ against whatever the root names, so an unconstrained root is a request
169
+ primitive aimed at internal addresses. Set
170
+ `EXPLAINER_KIT_ALLOW_PRIVATE_PUBLIC_ROOT=1` to opt back in for a genuinely
171
+ internal mirror. The policy is address-literal only: a hostname that happens
172
+ to resolve inward is not detected.
173
+ - **Redirects.** Public verification uses `redirect: 'error'`. A canonical
174
+ artifact URL is uploaded to a known key and should never legitimately
175
+ redirect, so any redirecting destination is a hard verification failure rather
176
+ than something to follow. A destination that requires redirects is
177
+ incompatible with this connector and will report as such rather than failing
178
+ opaquely later.
179
+
180
+ ## The generated initiative catalog
181
+
182
+ The connector generates one auxiliary artifact the manifest does not declare: an
183
+ initiative catalog at `site/initiatives/<slug>/catalog.json`, uploaded alongside
184
+ the declared artifacts and recorded in the receipt as
185
+ `source: { kind: 'auxiliary', name: 'catalog' }`.
186
+
187
+ A third-party connector must reproduce it **byte for byte**, because
188
+ `recordDurability` rebuilds it from the manifest and compares hashes; a mismatch
189
+ rejects the publication with `cross-record-mismatch`. Build it with
190
+ `catalogFromManifest(manifest, publicBaseUrl, { publicAccess })` and serialize
191
+ with `serializeInitiativeCatalog`, rather than constructing it by hand.
192
+
193
+ Two properties matter most:
194
+
195
+ - The `{ publicAccess }` option is **required**. Omitting it raises a
196
+ `TypeError` rather than defaulting, because the policy selects a field inside
197
+ the serialized bytes and therefore changes the hash. Pass
198
+ `{ publicAccess: undefined }` for `publish-request/v1`, which has no such
199
+ field and is public by definition.
200
+ - `publicVerification` carries **policy, never outcome**: `"required"` for
201
+ public destinations and `"skipped-by-policy"` for protected ones. The catalog
202
+ is serialized and hashed before the first upload and long before any
203
+ per-artifact verification runs, so it cannot carry a verification result
204
+ without invalidating its own hash. The authoritative outcome lives in the
205
+ publish receipt, which the catalog's `runId` identifies. Never write
206
+ `"verified"` into a catalog.
207
+
208
+ Publishability is gated by `assertManifestPublishable`, which raises
209
+ `E_PUBLISH_OUTCOME` for a manifest that is not eligible; see the intermediate
210
+ `incomplete` state described above.