@agent-native/core 0.44.4 → 0.45.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 (165) hide show
  1. package/dist/action.d.ts +8 -1
  2. package/dist/action.d.ts.map +1 -1
  3. package/dist/action.js +20 -10
  4. package/dist/action.js.map +1 -1
  5. package/dist/cli/app-skill.d.ts +3 -1
  6. package/dist/cli/app-skill.d.ts.map +1 -1
  7. package/dist/cli/app-skill.js +50 -8
  8. package/dist/cli/app-skill.js.map +1 -1
  9. package/dist/cli/connect.d.ts +2 -1
  10. package/dist/cli/connect.d.ts.map +1 -1
  11. package/dist/cli/connect.js +224 -10
  12. package/dist/cli/connect.js.map +1 -1
  13. package/dist/cli/create.d.ts.map +1 -1
  14. package/dist/cli/create.js +9 -7
  15. package/dist/cli/create.js.map +1 -1
  16. package/dist/cli/index.js +69 -10
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cli/mcp-config-writers.d.ts +10 -0
  19. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  20. package/dist/cli/mcp-config-writers.js +60 -6
  21. package/dist/cli/mcp-config-writers.js.map +1 -1
  22. package/dist/cli/mcp.d.ts.map +1 -1
  23. package/dist/cli/mcp.js +4 -6
  24. package/dist/cli/mcp.js.map +1 -1
  25. package/dist/cli/plan-local.d.ts +43 -0
  26. package/dist/cli/plan-local.d.ts.map +1 -0
  27. package/dist/cli/plan-local.js +490 -0
  28. package/dist/cli/plan-local.js.map +1 -0
  29. package/dist/cli/plan-publish-store.d.ts +17 -7
  30. package/dist/cli/plan-publish-store.d.ts.map +1 -1
  31. package/dist/cli/plan-publish-store.js +33 -8
  32. package/dist/cli/plan-publish-store.js.map +1 -1
  33. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  34. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  35. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  36. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  37. package/dist/cli/recap.d.ts +225 -3
  38. package/dist/cli/recap.d.ts.map +1 -1
  39. package/dist/cli/recap.js +1267 -27
  40. package/dist/cli/recap.js.map +1 -1
  41. package/dist/cli/skills.d.ts +26 -11
  42. package/dist/cli/skills.d.ts.map +1 -1
  43. package/dist/cli/skills.js +810 -1365
  44. package/dist/cli/skills.js.map +1 -1
  45. package/dist/cli/templates-meta.d.ts.map +1 -1
  46. package/dist/cli/templates-meta.js +3 -2
  47. package/dist/cli/templates-meta.js.map +1 -1
  48. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  49. package/dist/client/blocks/library/AnnotatedCodeBlock.js +41 -10
  50. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  51. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  52. package/dist/client/blocks/library/DiffBlock.js +54 -23
  53. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  54. package/dist/client/blocks/library/annotation-rail.d.ts +27 -8
  55. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  56. package/dist/client/blocks/library/annotation-rail.js +64 -27
  57. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  58. package/dist/client/blocks/library/code-filename-label.d.ts +8 -0
  59. package/dist/client/blocks/library/code-filename-label.d.ts.map +1 -0
  60. package/dist/client/blocks/library/code-filename-label.js +15 -0
  61. package/dist/client/blocks/library/code-filename-label.js.map +1 -0
  62. package/dist/client/blocks/library/code.d.ts.map +1 -1
  63. package/dist/client/blocks/library/code.js +3 -2
  64. package/dist/client/blocks/library/code.js.map +1 -1
  65. package/dist/client/blocks/library/diff.config.d.ts +1 -1
  66. package/dist/client/blocks/library/diff.config.js.map +1 -1
  67. package/dist/client/blocks/library/html.d.ts.map +1 -1
  68. package/dist/client/blocks/library/html.js +3 -1
  69. package/dist/client/blocks/library/html.js.map +1 -1
  70. package/dist/client/blocks/library/narrow-container.d.ts +4 -4
  71. package/dist/client/blocks/library/narrow-container.d.ts.map +1 -1
  72. package/dist/client/blocks/library/narrow-container.js +10 -10
  73. package/dist/client/blocks/library/narrow-container.js.map +1 -1
  74. package/dist/client/blocks/library/question-form.d.ts.map +1 -1
  75. package/dist/client/blocks/library/question-form.js +4 -1
  76. package/dist/client/blocks/library/question-form.js.map +1 -1
  77. package/dist/client/blocks/library/tabs.d.ts.map +1 -1
  78. package/dist/client/blocks/library/tabs.js +7 -2
  79. package/dist/client/blocks/library/tabs.js.map +1 -1
  80. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  81. package/dist/client/composer/TiptapComposer.js +4 -1
  82. package/dist/client/composer/TiptapComposer.js.map +1 -1
  83. package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
  84. package/dist/client/db-admin/TableEditor.js +3 -1
  85. package/dist/client/db-admin/TableEditor.js.map +1 -1
  86. package/dist/db/client.d.ts +8 -0
  87. package/dist/db/client.d.ts.map +1 -1
  88. package/dist/db/client.js +23 -2
  89. package/dist/db/client.js.map +1 -1
  90. package/dist/db/migrations.d.ts.map +1 -1
  91. package/dist/db/migrations.js +2 -1
  92. package/dist/db/migrations.js.map +1 -1
  93. package/dist/deploy/build.d.ts.map +1 -1
  94. package/dist/deploy/build.js +8 -0
  95. package/dist/deploy/build.js.map +1 -1
  96. package/dist/extensions/html-shell.js +1 -1
  97. package/dist/extensions/html-shell.js.map +1 -1
  98. package/dist/extensions/routes.d.ts +18 -0
  99. package/dist/extensions/routes.d.ts.map +1 -1
  100. package/dist/extensions/routes.js +30 -8
  101. package/dist/extensions/routes.js.map +1 -1
  102. package/dist/jobs/scheduler.d.ts.map +1 -1
  103. package/dist/jobs/scheduler.js +5 -1
  104. package/dist/jobs/scheduler.js.map +1 -1
  105. package/dist/mcp/build-server.d.ts +1 -0
  106. package/dist/mcp/build-server.d.ts.map +1 -1
  107. package/dist/mcp/build-server.js +7 -3
  108. package/dist/mcp/build-server.js.map +1 -1
  109. package/dist/mcp/oauth-route.d.ts.map +1 -1
  110. package/dist/mcp/oauth-route.js +56 -19
  111. package/dist/mcp/oauth-route.js.map +1 -1
  112. package/dist/mcp/oauth-store.d.ts +1 -0
  113. package/dist/mcp/oauth-store.d.ts.map +1 -1
  114. package/dist/mcp/oauth-store.js +9 -0
  115. package/dist/mcp/oauth-store.js.map +1 -1
  116. package/dist/mcp/server.d.ts.map +1 -1
  117. package/dist/mcp/server.js +9 -4
  118. package/dist/mcp/server.js.map +1 -1
  119. package/dist/mcp-client/errors.js +3 -3
  120. package/dist/mcp-client/errors.js.map +1 -1
  121. package/dist/oauth-tokens/store.d.ts.map +1 -1
  122. package/dist/oauth-tokens/store.js +42 -5
  123. package/dist/oauth-tokens/store.js.map +1 -1
  124. package/dist/scripts/db/index.d.ts.map +1 -1
  125. package/dist/scripts/db/index.js +1 -0
  126. package/dist/scripts/db/index.js.map +1 -1
  127. package/dist/scripts/db/migrate-encrypt-oauth-tokens.d.ts +28 -0
  128. package/dist/scripts/db/migrate-encrypt-oauth-tokens.d.ts.map +1 -0
  129. package/dist/scripts/db/migrate-encrypt-oauth-tokens.js +164 -0
  130. package/dist/scripts/db/migrate-encrypt-oauth-tokens.js.map +1 -0
  131. package/dist/scripts/db/scoping.d.ts.map +1 -1
  132. package/dist/scripts/db/scoping.js +7 -5
  133. package/dist/scripts/db/scoping.js.map +1 -1
  134. package/dist/secrets/index.d.ts +1 -0
  135. package/dist/secrets/index.d.ts.map +1 -1
  136. package/dist/secrets/index.js +4 -0
  137. package/dist/secrets/index.js.map +1 -1
  138. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  139. package/dist/server/agent-chat-plugin.js +3 -1
  140. package/dist/server/agent-chat-plugin.js.map +1 -1
  141. package/dist/server/agent-teams.d.ts.map +1 -1
  142. package/dist/server/agent-teams.js +10 -2
  143. package/dist/server/agent-teams.js.map +1 -1
  144. package/dist/server/auth.d.ts.map +1 -1
  145. package/dist/server/auth.js +7 -3
  146. package/dist/server/auth.js.map +1 -1
  147. package/dist/server/recap-image-route.d.ts.map +1 -1
  148. package/dist/server/recap-image-route.js +3 -6
  149. package/dist/server/recap-image-route.js.map +1 -1
  150. package/dist/server/sentry.d.ts.map +1 -1
  151. package/dist/server/sentry.js +12 -5
  152. package/dist/server/sentry.js.map +1 -1
  153. package/dist/server/social-og-image.d.ts.map +1 -1
  154. package/dist/server/social-og-image.js +3 -1
  155. package/dist/server/social-og-image.js.map +1 -1
  156. package/dist/sharing/actions/set-resource-visibility.d.ts.map +1 -1
  157. package/dist/sharing/actions/set-resource-visibility.js +4 -1
  158. package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
  159. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +22 -6
  160. package/docs/content/plan-plugin.md +39 -7
  161. package/docs/content/pr-visual-recap.md +89 -13
  162. package/docs/content/skills-guide.md +13 -0
  163. package/docs/content/template-plan.md +62 -7
  164. package/package.json +5 -1
  165. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +22 -6
@@ -7,6 +7,7 @@ import fs from "node:fs";
7
7
  import os from "node:os";
8
8
  import path from "node:path";
9
9
  import { spawn } from "node:child_process";
10
+ import { createHash } from "node:crypto";
10
11
  import { buildAppSkillPack, ensureAppSkill, loadAppSkillManifest, normalizeAppSkillManifest, } from "./app-skill.js";
11
12
  import { readConnectClientPreferences, resolveClients, runConnect, writeConnectClientPreferences, } from "./connect.js";
12
13
  import { CONTEXT_XRAY_SKILL_MD, installLocalContextXray, } from "./context-xray-local.js";
@@ -16,6 +17,8 @@ const HELP = `agent-native skills
16
17
 
17
18
  Usage:
18
19
  agent-native skills list
20
+ agent-native skills status [assets|design-exploration|visual-plan|visual-recap|context-xray] [--client codex|claude-code|all] [--scope user|project] [--json]
21
+ agent-native skills update [assets|design-exploration|visual-plan|visual-recap|context-xray] [--client codex|claude-code|all] [--scope user|project] [--dry-run] [--json]
19
22
  agent-native skills add assets|design-exploration|visual-plan|visual-recap|context-xray [--client codex|claude-code|claude-code-cli|cowork|all] [--scope user|project] [--mcp-url <url>] [--no-connect] [--with-github-action] [--yes] [--dry-run] [--json]
20
23
  agent-native skills add <manifest-or-app-dir> [--client ...] [--yes]
21
24
 
@@ -24,6 +27,8 @@ Examples:
24
27
  agent-native skills add design-exploration
25
28
  agent-native skills add visual-plan
26
29
  agent-native skills add visual-plan --with-github-action
30
+ agent-native skills status visual-plan
31
+ agent-native skills update visual-plan
27
32
  agent-native skills add visual-plan --no-connect
28
33
  agent-native skills add context-xray --client all
29
34
  agent-native skills add assets --client claude-code
@@ -45,7 +50,15 @@ register the connector without authenticating (leave auth to the host or run
45
50
  a custom origin (an ngrok tunnel, a local dev server, or a self-hosted
46
51
  deployment) instead of the built-in hosted default — a bare origin gets the
47
52
  standard /_agent-native/mcp path appended. Use app-skill pack for marketplace
48
- bundles and custom adapter output.`;
53
+ bundles and custom adapter output.
54
+
55
+ When installing visual-plan interactively, the CLI offers to add the optional PR
56
+ Visual Recap GitHub Action. Pass --with-github-action to write it directly, then
57
+ run "agent-native recap setup" / "agent-native recap doctor" to configure and
58
+ verify GitHub Actions.
59
+
60
+ The status/update commands inspect copied Agent Native skill folders and refresh
61
+ their instruction files from the current @agent-native/core package.`;
49
62
  const ASSETS_SKILL_MD = `---
50
63
  name: assets
51
64
  description: >-
@@ -198,8 +211,7 @@ iteration, or a human-in-the-loop choice among design directions.
198
211
  `;
199
212
  /**
200
213
  * Shared setup/auth block for every Plans skill (`/visual-plan`,
201
- * `/visual-recap`, `/ui-plan`, `/prototype-plan`, `/plan-design`,
202
- * `/visual-questions`). Interpolated into each skill markdown
214
+ * `/visual-recap`). Interpolated into each skill markdown
203
215
  * so the install + one-step authenticate instructions never drift between them.
204
216
  * Keep this in sync with the copies under `templates/plan/.agents/skills/*` and
205
217
  * top-level `skills/*` (this skill's SKILL.md is triplicated with no sync test).
@@ -217,10 +229,12 @@ intended), so the first tool call does not hit an OAuth wall:
217
229
  agent-native skills add visual-plan
218
230
  \`\`\`
219
231
 
220
- After that, \`/visual-plan\` (and \`/visual-recap\`, \`/ui-plan\`,
221
- \`/prototype-plan\`, \`/plan-design\`, \`/visual-questions\`) generate a plan and open
222
- the editor. Pass \`--no-connect\` to
223
- register the connector without authenticating, then run
232
+ After that, \`/visual-plan\` and \`/visual-recap\` are the two installed slash
233
+ commands. Other planning modes — UI-first (\`create-ui-plan\`), prototype-first
234
+ (\`create-prototype-plan\`), design-first (\`create-plan-design\`), and visual
235
+ intake (\`create-visual-questions\`) are MCP tools reachable from \`/visual-plan\`,
236
+ not separate slash commands. Pass \`--no-connect\` to register the connector
237
+ without authenticating, then run
224
238
  \`agent-native connect https://plan.agent-native.com\` whenever you are ready.
225
239
 
226
240
  **Browser (people you share with).** Open the Plans editor and create & edit
@@ -249,13 +263,13 @@ not put shared secrets in skill files.`;
249
263
  // distributed artifact stays a flat string, so distribution is unchanged.
250
264
  //
251
265
  // Consumers:
252
- // WIREFRAME_QUALITY_CORE — visual-plan, ui-plan, visual-recap (surface-agnostic)
253
- // CANVAS_SURFACE_CORE — visual-plan, ui-plan (canvas/artboard mechanics)
254
- // DOCUMENT_QUALITY_CORE — visual-plan, ui-plan
255
- // EXEMPLAR_CORE — visual-plan, ui-plan
266
+ // WIREFRAME_QUALITY_CORE — visual-plan, visual-recap (surface-agnostic)
267
+ // CANVAS_SURFACE_CORE — visual-plan modes (canvas/artboard mechanics)
268
+ // DOCUMENT_QUALITY_CORE — visual-plan
269
+ // EXEMPLAR_CORE — visual-plan
256
270
  // Surface-agnostic HTML wireframe quality rules. Applies equally to a standalone
257
- // WireframeBlock/<Screen> (visual-recap) and to a canvas artboard (visual-plan /
258
- // ui-plan). Do not put canvas/artboard placement mechanics here.
271
+ // WireframeBlock/<Screen> (visual-recap) and to a canvas artboard (visual-plan).
272
+ // Do not put canvas/artboard placement mechanics here.
259
273
  const WIREFRAME_QUALITY_CORE = `<!-- SHARED-CORE:wireframe-quality START -->
260
274
 
261
275
  **A wireframe is an HTML mockup. The renderer owns the look; you write the
@@ -476,7 +490,34 @@ hex colors:
476
490
  \`\`\`
477
491
 
478
492
  <!-- SHARED-CORE:wireframe-quality END -->`;
479
- // Canvas/artboard placement mechanics. Used only by visual-plan and ui-plan
493
+ // Progressive-disclosure reference file. `WIREFRAME_QUALITY_CORE` is the single
494
+ // source of truth for HTML wireframe quality; it is materialized verbatim into a
495
+ // sibling `references/wireframe.md` in EVERY plan skill dir (visual-plan and
496
+ // visual-recap), instead of being interpolated inline into each SKILL.md body.
497
+ // The SKILL.md bodies carry only `WIREFRAME_REFERENCE_POINTER`, which tells the
498
+ // agent to read this file before authoring any wireframe. Keeping the reference
499
+ // body byte-identical to the core (markers included) lets the sync guard assert
500
+ // the on-disk copies never drift from the canonical constant.
501
+ export const WIREFRAME_REFERENCE_MD = `# HTML wireframe quality — single source of truth
502
+
503
+ This file is the canonical quality bar for HTML wireframes / \`<Screen>\` /
504
+ \`WireframeBlock\` content, shared word for word by \`/visual-plan\` and
505
+ \`/visual-recap\`. Read it in full before authoring ANY wireframe; do not
506
+ author wireframes from memory or paraphrase these rules per command.
507
+
508
+ ${WIREFRAME_QUALITY_CORE}
509
+ `;
510
+ // Short pointer that replaces the inline wireframe-quality core in each SKILL.md
511
+ // body. Authoring quality lives in the sibling reference file so the SKILL.md
512
+ // stays lean (progressive disclosure); the agent loads the detail on demand.
513
+ const WIREFRAME_REFERENCE_POINTER = `UI recap/plan wireframes must meet a strict quality bar — full-width chrome,
514
+ pinned bottom bars, real product content, before/after comparability, the right
515
+ \`surface\` preset, \`--wf-*\` tokens instead of hex, and no \`<html>\`/\`<style>\`/font
516
+ tags. Before authoring ANY wireframe / \`<Screen>\` / \`WireframeBlock\`, READ
517
+ \`references/wireframe.md\` in this skill directory — it is the single source of
518
+ truth for HTML wireframe quality, shared word for word with \`/visual-plan\`
519
+ and \`/visual-recap\`. Do not author wireframes from memory.`;
520
+ // Canvas/artboard placement mechanics. Used only by visual-plan modes
480
521
  // (visual-recap renders standalone wireframes, not a canvas).
481
522
  const CANVAS_SURFACE_CORE = `<!-- SHARED-CORE:canvas-surface START -->
482
523
 
@@ -693,7 +734,7 @@ unreadable diagrams before asking for approval.
693
734
  <!-- SHARED-CORE:document-quality END -->`;
694
735
  const EXEMPLAR_CORE = `<!-- SHARED-CORE:exemplar START -->
695
736
 
696
- **GOOD.** A \`/ui-plan\` for a todo app: a canvas with a \`desktop\` artboard whose
737
+ **GOOD.** A UI-first plan for a todo app: a canvas with a \`desktop\` artboard whose
697
738
  \`data.html\` is a real flex layout — a sidebar of links (\`Inbox 12\`, \`Today 4\`,
698
739
  \`Done\`), a main column with an \`<h1>Today</h1>\`, accent \`.wf-pill\`s for the
699
740
  filters, a muted section label \`OVERDUE\`, and \`.wf-card\` task rows carrying real
@@ -733,6 +774,60 @@ labeled boxes with overlapping text, where the actual code evidence and
733
774
  recommendations live elsewhere. Never produce this.
734
775
 
735
776
  <!-- SHARED-CORE:exemplar END -->`;
777
+ // Progressive-disclosure reference files. Like `WIREFRAME_REFERENCE_MD`, each of
778
+ // the canvas / document-quality / exemplar cores is the single source of truth
779
+ // for its topic and is materialized verbatim into a sibling `references/*.md`
780
+ // file in the visual-plan skill dir instead of being interpolated inline into
781
+ // the SKILL.md body. The body carries only the matching `*_REFERENCE_POINTER`.
782
+ // Keeping each reference body byte-identical to its core (markers included) lets
783
+ // the sync guard assert the on-disk copies never drift from the constant.
784
+ export const CANVAS_REFERENCE_MD = `# Canvas & artboard placement — single source of truth
785
+
786
+ This file is the canonical guide for how the visual-plan canvas works: artboard
787
+ placement, lane layout, annotations, patching, and the legacy kit tree. Read it
788
+ in full before authoring or editing any canvas/artboard content; do not author
789
+ canvas layouts from memory or paraphrase these rules per mode.
790
+
791
+ ${CANVAS_SURFACE_CORE}
792
+ `;
793
+ export const DOCUMENT_QUALITY_REFERENCE_MD = `# Plan document quality — single source of truth
794
+
795
+ This file is the canonical quality bar for the plan document below the canvas:
796
+ how it reads, which blocks to use, how open questions are surfaced, and the
797
+ pre-handoff check. Read it in full before authoring the plan document; it is the
798
+ quality bar. Do not write the document from memory or paraphrase these rules per
799
+ mode.
800
+
801
+ ${DOCUMENT_QUALITY_CORE}
802
+ `;
803
+ export const EXEMPLAR_REFERENCE_MD = `# Good vs. bad exemplar — single source of truth
804
+
805
+ This file is the canonical worked example of a great plan (and the anti-patterns
806
+ to avoid). Read it alongside the document-quality and canvas references before
807
+ authoring a plan; it is the bar these plans must clear.
808
+
809
+ ${EXEMPLAR_CORE}
810
+ `;
811
+ // Short pointers that replace the inline canvas / document-quality / exemplar
812
+ // cores in the SKILL.md body. Authoring detail lives in the sibling reference
813
+ // files so the SKILL.md stays lean (progressive disclosure); the agent loads the
814
+ // detail on demand.
815
+ const CANVAS_REFERENCE_POINTER = `The canvas is the single source of truth for static UI mockups: artboard
816
+ placement is locked by the \`surface\` (never coordinates), mixed surfaces lay out
817
+ in lanes, annotations are plain-text designer notes anchored by
818
+ \`targetId\`/\`placement\`, and edits are surgical \`contentPatches\`. Before
819
+ authoring or editing ANY canvas, artboard, or annotation, READ
820
+ \`references/canvas.md\` in this skill directory — it is the single source of truth
821
+ for canvas/artboard mechanics. Do not author canvas layouts from memory.`;
822
+ const DOCUMENT_QUALITY_REFERENCE_POINTER = `The document is a serious technical plan, not marketing: outcome-first,
823
+ prose-first, self-contained, built from the right native blocks, with open
824
+ questions in a single bottom \`question-form\` and a pre-handoff visual check.
825
+ Before authoring the plan document, READ \`references/document-quality.md\` in this
826
+ skill directory — it is the single source of truth for the document quality bar.
827
+ Do not write the document from memory.`;
828
+ const EXEMPLAR_REFERENCE_POINTER = `For a worked example of the bar — a great UI-first plan and \`/visual-plan\`, plus
829
+ the anti-patterns to avoid — READ \`references/exemplar.md\` in this skill
830
+ directory before authoring a plan.`;
736
831
  export const VISUAL_PLANS_SKILL_MD = `---
737
832
  name: visual-plan
738
833
  description: >-
@@ -754,14 +849,14 @@ usually start in the document with local diagrams near each claim. UI and produc
754
849
  plans should still start with the top canvas/prototype when screens or behavior
755
850
  are what the user needs to review.
756
851
 
757
- \`/visual-plan\` is the canonical command and the main entry point. Use \`/ui-plan\`
758
- when the work is primarily product UI and review should start with the screens.
759
- Use \`/prototype-plan\` when review should start with a functional live prototype.
760
- Use \`/plan-design\` when review should start with full-fidelity branded design.
761
- Use \`/visual-questions\` only when the user explicitly wants a visual intake form
762
- before planning. When a Codex, Claude Code, Markdown, or pasted plan already
763
- exists, \`/visual-plan\` uses that source plan as the starting point and builds
764
- the review surface from it instead of starting over.
852
+ \`/visual-plan\` is the packaged command and main entry point. Choose the review
853
+ mode from the task: UI-first when the work is primarily product UI and review
854
+ should start with screens, prototype-first when review should start with a
855
+ functional live prototype, design-first when review needs full-fidelity branded
856
+ screens, or visual-intake when the user explicitly wants a questionnaire before
857
+ planning. When a Codex, Claude Code, Markdown, or pasted plan already exists,
858
+ \`/visual-plan\` uses that source plan as the starting point and builds the review
859
+ surface from it instead of starting over.
765
860
 
766
861
  ## When To Use
767
862
 
@@ -814,6 +909,37 @@ plan needs a richer review surface.
814
909
  update the plan with \`update-visual-plan\` rather than only changing course in
815
910
  chat, and re-read the approved plan before major steps.
816
911
 
912
+ ## Local-Files Privacy Mode
913
+
914
+ Use local-files privacy mode when the user explicitly asks for no DB writes,
915
+ no hosted Plan app, no Plan MCP publish, fully local files, offline/private
916
+ planning, or when \`AGENT_NATIVE_PLANS_MODE=local-files\` is set. In this mode the
917
+ plan data must never be sent to the Plan MCP server or Plan app action surface.
918
+
919
+ The local-files contract is:
920
+
921
+ - Read source context from local files and shell commands only.
922
+ - Write the plan as a local MDX folder under \`plans/<slug>/\`: \`plan.mdx\`,
923
+ optional \`canvas.mdx\`, optional \`prototype.mdx\`, and optional
924
+ \`.plan-state.json\`.
925
+ - Run \`agent-native plan local preview --dir plans/<slug> --kind plan\` after
926
+ writing or updating the folder. Report the returned local URL or the
927
+ \`/local-plans/<slug>\` route if the local Plan app is running with the same
928
+ \`PLAN_LOCAL_DIR\`.
929
+ - Do **not** call \`create-visual-plan\`, \`create-ui-plan\`,
930
+ \`create-prototype-plan\`, \`create-plan-design\`, \`import-visual-plan-source\`,
931
+ \`update-visual-plan\`, \`patch-visual-plan-source\`, \`get-plan-feedback\`,
932
+ \`export-visual-plan\`, or any hosted Plan tool for that plan.
933
+ - Treat feedback as file or chat feedback: update the MDX files directly, rerun
934
+ the local preview command, and summarize the new local URL/path. Hosted
935
+ comments, sharing, history, and publish/export receipts are unavailable until
936
+ the user explicitly opts into publishing.
937
+
938
+ Local-files mode prevents plan content from going to the Agent-Native Plan
939
+ database. It does not by itself make the coding agent's language model local;
940
+ for that stronger privacy boundary, the host agent/model must also be local or
941
+ otherwise approved by the user.
942
+
817
943
  ## Core Workflow
818
944
 
819
945
  1. Follow the host agent's normal planning flow: inspect the codebase, delegate
@@ -908,38 +1034,30 @@ not add visual chrome by default:
908
1034
  needs to operate the behavior. Keep the static wireframes in
909
1035
  \`content.canvas\`, add the aligned functional prototype in
910
1036
  \`content.prototype\`, and rely on the top visual tabs to switch between them.
911
- - **Prototype-first** when the user explicitly asks for \`/prototype-plan\`, asks
912
- to operate the UI, or when interaction is the main question. Use
913
- \`create-prototype-plan\`, which still preserves static mocks where useful.
1037
+ - **Prototype-first** when the user asks to operate the UI or when interaction is
1038
+ the main question. Use \`create-prototype-plan\`, which still preserves static
1039
+ mocks where useful.
914
1040
 
915
1041
  For mixed canvas + prototype plans, reuse the same real labels, app statuses,
916
1042
  and screen ids across both surfaces. The canvas is the inspectable static reference;
917
1043
  the prototype is the interactive version of that same flow, not a separate
918
1044
  design direction.
919
1045
 
920
- ## Wireframe & Canvas Core
1046
+ ## Wireframe quality read \`references/wireframe.md\`
921
1047
 
922
- This section is shared by \`/visual-plan\` and \`/ui-plan\`, and is the single
923
- source of truth for how wireframes and the canvas work. The wireframe-quality
924
- rules below are additionally shared, word for word, with \`/visual-recap\`; the
925
- canvas/artboard mechanics apply only to \`/visual-plan\` and \`/ui-plan\`. Do not
926
- paraphrase any of it per command.
1048
+ ${WIREFRAME_REFERENCE_POINTER}
927
1049
 
928
- ${WIREFRAME_QUALITY_CORE}
1050
+ ## Canvas — read \`references/canvas.md\`
929
1051
 
930
- ${CANVAS_SURFACE_CORE}
1052
+ ${CANVAS_REFERENCE_POINTER}
931
1053
 
932
- ## Document Quality Core
1054
+ ## Document quality — read \`references/document-quality.md\`
933
1055
 
934
- This section is shared, word for word, by \`/visual-plan\` and \`/ui-plan\`. It is
935
- the single source of truth for the document below the canvas. Do not paraphrase
936
- it per command.
1056
+ ${DOCUMENT_QUALITY_REFERENCE_POINTER}
937
1057
 
938
- ${DOCUMENT_QUALITY_CORE}
1058
+ ## Good vs. bad exemplar — read \`references/exemplar.md\`
939
1059
 
940
- ## Good vs. Bad Exemplar
941
-
942
- ${EXEMPLAR_CORE}
1060
+ ${EXEMPLAR_REFERENCE_POINTER}
943
1061
 
944
1062
  ## Tool Guidance
945
1063
 
@@ -953,8 +1071,8 @@ ${EXEMPLAR_CORE}
953
1071
  optional matching Prototype tab.
954
1072
  - \`convert-visual-plan-to-prototype\`: convert an existing HTML wireframe canvas
955
1073
  into a prototype plan.
956
- - \`create-visual-questions\`: use only for the explicit \`/visual-questions\`
957
- command, not as \`/visual-plan\` preflight.
1074
+ - \`create-visual-questions\`: use only when the user explicitly asks for a visual
1075
+ intake questionnaire, not as \`/visual-plan\` preflight.
958
1076
  - \`update-visual-plan\`: revise content, status, or comments; prefer
959
1077
  \`contentPatches\` over regenerating the whole plan.
960
1078
  - \`read-visual-plan-source\`: read the normalized plan as \`plan.mdx\`,
@@ -967,177 +1085,22 @@ ${EXEMPLAR_CORE}
967
1085
  - \`get-plan-feedback\`: read unconsumed human feedback. Use it frequently; it
968
1086
  returns grouped threads, exact anchor details, expected resolver, and recent
969
1087
  review-event payloads so agents can act only on the comments meant for them.
1088
+ - \`get-plan-blocks\`: resolve block tags before authoring — do not memorize tags;
1089
+ call this first to get the authoritative tag names, required fields, and prop
1090
+ shapes from the live block registry.
970
1091
  - \`export-visual-plan\`: export HTML, Markdown fallback, structured JSON, and MDX
971
1092
  files for repo check-in.
972
1093
 
973
1094
  When the user critiques a plan's look or structure, fix the renderer or this
974
1095
  skill — never hand-edit one stored plan. Turn feedback into better guidance.
975
1096
 
976
- ## Setup & Authentication
977
-
978
- There are two ways into Plans.
979
-
980
- **Coding agent (CLI).** Install once with the Agent-Native CLI. The command
981
- installs the Plans skills, registers the hosted Plans MCP connector, and
982
- authenticates it in the same step (a one-time browser sign-in at setup — this is
983
- intended), so the first tool call does not hit an OAuth wall:
984
-
985
- \`\`\`bash
986
- agent-native skills add visual-plan
987
- \`\`\`
988
-
989
- After that, \`/visual-plan\` (and \`/visual-recap\`, \`/ui-plan\`,
990
- \`/prototype-plan\`, \`/plan-design\`, \`/visual-questions\`) generate a plan and open
991
- the editor. Pass \`--no-connect\` to
992
- register the connector without authenticating, then run
993
- \`agent-native connect https://plan.agent-native.com\` whenever you are ready.
994
-
995
- **Browser (people you share with).** Open the Plans editor and create & edit
996
- with no sign-up — you work as a guest. Sign in only when you want to save or
997
- share; signing in claims the plans you made as a guest into your account.
998
-
999
- Sharing and commenting require an account: public/shared plans are viewable by
1000
- anyone with the link, but commenting on them needs an agent-native account.
1001
-
1002
- For fully offline, no-account use, run the Plans app locally and sync plans to
1003
- your repo as MDX. This local mode is a separate advanced path, not the default
1004
- hosted flow.
1005
-
1006
- If a Plans tool returns \`needs auth\`, \`Unauthorized\`, or \`Session terminated\`,
1007
- do not keep retrying the tool. Authenticate the connector with
1008
- \`agent-native connect https://plan.agent-native.com\` (OAuth-capable hosts can
1009
- instead re-run /mcp and choose Authenticate), then continue once the connector
1010
- is available.
1011
-
1012
- Hosted default: connect \`https://plan.agent-native.com/_agent-native/mcp\`. Do
1013
- not put shared secrets in skill files.
1014
- `;
1015
- export const UI_PLAN_SKILL_MD = `---
1016
- name: ui-plan
1017
- description: >-
1018
- Use Agent-Native Plans for UI-first planning with an optional top pan/zoom
1019
- wireframe canvas, a refined Notion-like document, rich tabs, diagrams,
1020
- comments, drawing, and agent handoff.
1021
- metadata:
1022
- visibility: exported
1023
- ---
1024
-
1025
- # UI Plan
1026
-
1027
- Use \`/ui-plan\` when the task is primarily about product UI, user flows,
1028
- interaction details, component layout, or visual direction. The reviewable UI
1029
- comes first; implementation detail comes after the user has something concrete to
1030
- react to.
1031
-
1032
- \`/visual-plan\` remains the general command for architecture, backend, refactors,
1033
- and mixed work. Use \`/prototype-plan\` when the UI review needs a functional live
1034
- prototype instead of static screens. Use \`/plan-design\` when polish, brand, or
1035
- visual fidelity are material to the decision. Use \`/visual-questions\` only when
1036
- the user explicitly wants visual intake before planning. Use \`/visual-plan\` when
1037
- a text plan already exists and should become the source material for the review.
1038
-
1039
- ## Plan Discipline
1040
-
1041
- - **Gate hard.** Use a UI plan when the surface is new, ambiguous, spans several
1042
- screens or states, or the direction needs agreement before coding. Skip it for
1043
- cosmetic one-liners — a color, a label, a spacing tweak — and just make the
1044
- change. Never ship a single-step or filler plan.
1045
- - **Research before you draft.** Read the real components, routes, and design
1046
- tokens first; ground every mockup and the file map in actual files and symbols.
1047
- Delegate wide exploration to a sub-agent when the surface is large.
1048
- - **Planning is read-only.** Make no source edits while building or reviewing.
1049
- Start editing only after the user approves the UI direction.
1050
- - **Clarify vs. assume.** Do not ask how to build the UI — present the direction
1051
- and options as mockups and tabs. Ask a clarifying question only when an
1052
- ambiguity would change the design; use the host agent's normal
1053
- ask-user-question flow and batch 2-4 before finalizing. Do not call
1054
- \`create-visual-questions\` from \`/ui-plan\`; keep answerable follow-up inside
1055
- the same plan as a bottom \`question-form\` Open Questions block. Otherwise
1056
- state the assumption in the plan and proceed.
1057
- - **The plan is the approval gate.** Ask the user to review and approve the UI
1058
- direction before you write code, and name the files/areas the work touches.
1059
-
1060
- ## UI-First Workflow
1061
-
1062
- 1. Follow the host agent's normal planning flow: inspect the codebase, gather
1063
- the UI/component context needed, and ask native clarifying questions as needed
1064
- before generating the plan.
1065
- 2. Call \`create-ui-plan\` with a UI-specific title, brief, source, repo path, and
1066
- structured \`content\`. The canvas comes first, the document second.
1067
- 3. Compose the top canvas from the kit (see the cores below): the key artboards
1068
- with real product content, designer notes, and connectors only for real
1069
- sequences. Skip the canvas when wireframes would not clarify the work.
1070
- 4. Continue below as a concise technical document that stays close to the
1071
- Markdown plan the agent would normally output — not a second copy of the
1072
- canvas — covering concrete files, contracts, phases, risks, and validation.
1073
- 5. Call \`get-plan-feedback\` before implementation, after review, after a long
1074
- pause, and before the final response. Treat \`anchorDetails\`, resolver intent,
1075
- recent review events, and any focused screenshots from browser handoff as the
1076
- source of truth for exactly what changed and exactly what each UI comment
1077
- points at. Apply changes with \`update-visual-plan\`, preferring
1078
- \`contentPatches\` for one frame, annotation, node, tab, or block. When the
1079
- user wants source-control friendly edits, use \`patch-visual-plan-source\`
1080
- against the MDX files instead of regenerating the plan.
1081
-
1082
- ## Agent Handoff
1083
-
1084
- After the canvas and document, add a short handoff that names the chosen UI
1085
- direction, unresolved visual questions, and feedback that must be read before
1086
- code changes. Never claim feedback has been applied until \`get-plan-feedback\` or
1087
- the user has supplied it.
1088
-
1089
- ## Wireframe & Canvas Core
1090
-
1091
- This section is shared by \`/visual-plan\` and \`/ui-plan\`, and is the single
1092
- source of truth for how wireframes and the canvas work. The wireframe-quality
1093
- rules below are additionally shared, word for word, with \`/visual-recap\`; the
1094
- canvas/artboard mechanics apply only to \`/visual-plan\` and \`/ui-plan\`. Do not
1095
- paraphrase any of it per command.
1096
-
1097
- ${WIREFRAME_QUALITY_CORE}
1098
-
1099
- ${CANVAS_SURFACE_CORE}
1100
-
1101
- ## Document Quality Core
1102
-
1103
- This section is shared, word for word, by \`/visual-plan\` and \`/ui-plan\`. It is
1104
- the single source of truth for the document below the canvas. Do not paraphrase
1105
- it per command.
1106
-
1107
- ${DOCUMENT_QUALITY_CORE}
1108
-
1109
- ## Good vs. Bad Exemplar
1110
-
1111
- ${EXEMPLAR_CORE}
1112
-
1113
- ## Tool Guidance
1114
-
1115
- - \`create-ui-plan\`: create the UI-first structured visual plan.
1116
- - \`create-prototype-plan\`: create a prototype-first plan when UI review needs a
1117
- functional live prototype.
1118
- - \`create-plan-design\`: create a full-fidelity branded design plan when polish,
1119
- brand, and detailed visual direction are primary review inputs.
1120
- - \`convert-visual-plan-to-prototype\`: convert an existing HTML wireframe canvas
1121
- into a prototype plan.
1122
- - \`create-visual-questions\`: use only for the explicit \`/visual-questions\`
1123
- command, not as \`/ui-plan\` preflight.
1124
- - \`update-visual-plan\`: revise content, mockups, comments, or handoff notes;
1125
- prefer targeted \`contentPatches\`.
1126
- - \`read-visual-plan-source\`: read the normalized plan as \`plan.mdx\`,
1127
- optional \`canvas.mdx\`, optional \`.plan-state.json\`, and JSON.
1128
- - \`patch-visual-plan-source\`: apply granular MDX AST patches by stable block,
1129
- artboard, annotation, component, or wireframe-node id.
1130
- - \`import-visual-plan-source\`: create or replace a plan from an MDX folder.
1131
- - \`get-visual-plan\`: inspect the current structured plan, exported HTML, and
1132
- annotations; it also returns the MDX folder for source workflows.
1133
- - \`get-plan-feedback\`: read unconsumed reviewer comments before coding; it
1134
- returns grouped threads, exact anchor details, expected resolver, and recent
1135
- review-event payloads so agents can act only on the comments meant for them.
1136
- - \`export-visual-plan\`: export HTML, Markdown fallback, structured JSON, and MDX
1137
- files for repo check-in.
1097
+ ## Visibility & Sharing
1138
1098
 
1139
- When the user critiques a plan's look or structure, fix the renderer or this
1140
- skill never hand-edit one stored plan. Turn feedback into better guidance.
1099
+ Use \`set-resource-visibility\` to change who can see a plan (e.g. public, login,
1100
+ or org-scoped). Use \`share-resource\` to grant specific users or roles access
1101
+ by email or role. Gate visibility before sharing any plan that covers
1102
+ unreleased or private work — default to the narrowest scope that meets the
1103
+ review need.
1141
1104
 
1142
1105
  ## Setup & Authentication
1143
1106
 
@@ -1152,10 +1115,12 @@ intended), so the first tool call does not hit an OAuth wall:
1152
1115
  agent-native skills add visual-plan
1153
1116
  \`\`\`
1154
1117
 
1155
- After that, \`/visual-plan\` (and \`/visual-recap\`, \`/ui-plan\`,
1156
- \`/prototype-plan\`, \`/plan-design\`, \`/visual-questions\`) generate a plan and open
1157
- the editor. Pass \`--no-connect\` to
1158
- register the connector without authenticating, then run
1118
+ After that, \`/visual-plan\` and \`/visual-recap\` are the two installed slash
1119
+ commands. Other planning modes — UI-first (\`create-ui-plan\`), prototype-first
1120
+ (\`create-prototype-plan\`), design-first (\`create-plan-design\`), and visual
1121
+ intake (\`create-visual-questions\`) are MCP tools reachable from \`/visual-plan\`,
1122
+ not separate slash commands. Pass \`--no-connect\` to register the connector
1123
+ without authenticating, then run
1159
1124
  \`agent-native connect https://plan.agent-native.com\` whenever you are ready.
1160
1125
 
1161
1126
  **Browser (people you share with).** Open the Plans editor and create & edit
@@ -1178,273 +1143,6 @@ is available.
1178
1143
  Hosted default: connect \`https://plan.agent-native.com/_agent-native/mcp\`. Do
1179
1144
  not put shared secrets in skill files.
1180
1145
  `;
1181
- export const PROTOTYPE_PLAN_SKILL_MD = `---
1182
- name: prototype-plan
1183
- description: >-
1184
- Use Agent-Native Plans for /prototype-plan when work needs a functional
1185
- prototype-first plan, static mocks, comments, review toggles, or conversion
1186
- from a visual plan.
1187
- metadata:
1188
- visibility: exported
1189
- ---
1190
-
1191
- # Prototype Plan
1192
-
1193
- \`/prototype-plan\` creates a plan whose primary review surface is a live,
1194
- functional prototype above the document. Use it when the user needs to feel a
1195
- flow, operate basic UI state, or comment on interaction before implementation
1196
- hardens the decision.
1197
-
1198
- ## Rule
1199
-
1200
- Make the prototype answer a concrete question. The plan should say what is being
1201
- tested, show the functional prototype first, then keep static mocks and implementation
1202
- notes in the document below.
1203
-
1204
- ## When To Use
1205
-
1206
- Use \`/prototype-plan\` when the user asks for a prototype, wants to click through
1207
- and operate UI states, needs design review before code, wants comments pinned to
1208
- live screens, or asks to move a visual plan into a prototype.
1209
-
1210
- Prefer \`/visual-plan\` for architecture, data flow, or non-interactive planning.
1211
- Prefer \`/ui-plan\` when static screen review is enough. Use \`/visual-plan\` first
1212
- when the user hands you an existing Markdown/Codex/Claude plan that needs a
1213
- visual companion before becoming interactive.
1214
-
1215
- ## Core Workflow
1216
-
1217
- 1. Inspect the real codebase and decide the question the prototype should
1218
- answer. Good examples: "Does this onboarding flow feel short enough?" or
1219
- "Which dashboard density should we implement?"
1220
- 2. Call \`create-prototype-plan\` with a title, brief, and screen HTML. Default to
1221
- one functional prototype screen when local UI behavior is enough; use 2-4
1222
- screens only for true routes, steps, or materially different contexts. The
1223
- returned plan opens with the prototype viewer on top and static mocks, flow
1224
- diagram, implementation map, and verification below.
1225
- 3. Make controls actually work. Use the renderer's safe Alpine-like directives:
1226
- \`x-data\`, \`x-model\`, \`x-for\`, \`x-text\`, \`x-show\`, \`:class\`, \`@click\`, and
1227
- \`@keydown.enter\`. Use safe helper verbs such as \`remove(list, item)\`,
1228
- \`setAll(list, 'done', true)\`, \`removeWhere(list, 'done', true)\`, and counters
1229
- such as \`count(list)\`, \`countWhere(list, 'done', true)\`, and
1230
- \`remaining(list, 'done')\` when they help. Use \`data-goto="screen-id"\` only
1231
- for true screen/route changes, not for every button press.
1232
- 4. Show important app feedback inside the prototype itself: selected filters,
1233
- checked rows, typed drafts, validation messages, permissions, progress, or
1234
- empty states.
1235
- 5. Surface the returned Plans link and ask the user to click through, comment on
1236
- the prototype or static mocks, and approve the direction before code changes.
1237
- 6. Before implementing or revising, call \`get-plan-feedback\`. Treat prototype
1238
- anchors, screenshots, and resolver intent as the source of truth.
1239
- 7. Update with \`update-visual-plan\` content patches. Use
1240
- \`patch-prototype-html\`, \`update-prototype-screen\`, or \`set-prototype\` for
1241
- targeted prototype edits instead of regenerating the whole plan.
1242
-
1243
- ## Converting A Visual Plan
1244
-
1245
- When a visual plan already has HTML canvas wireframes, call
1246
- \`convert-visual-plan-to-prototype\` with the plan id. This derives prototype
1247
- screens from the canvas frames, preserves the canvas/static mocks by default,
1248
- and changes the top review surface to the prototype viewer.
1249
-
1250
- Use \`removeCanvas: true\` only when the user explicitly wants the old canvas
1251
- gone. Otherwise keep static mocks available for source export and detailed
1252
- review.
1253
-
1254
- ## Prototype Screen HTML
1255
-
1256
- Write bounded semantic HTML fragments only:
1257
-
1258
- \`\`\`html
1259
- <div style="display:flex;flex-direction:column;gap:14px;padding:18px;height:100%">
1260
- <header style="display:flex;justify-content:space-between;gap:12px">
1261
- <div>
1262
- <h1>Launch checklist</h1>
1263
- <p class="wf-muted">Reviewer can add, complete, filter, and remove tasks.</p>
1264
- </div>
1265
- <span class="wf-pill accent">Live prototype</span>
1266
- </header>
1267
- <section
1268
- class="wf-card"
1269
- x-data="{ draft: '', filter: 'all', todos: [{ text: 'Check copy', done: false }, { text: 'Confirm owner', done: true }] }"
1270
- style="display:flex;flex-direction:column;gap:10px"
1271
- >
1272
- <div style="display:flex;gap:8px">
1273
- <input x-model="draft" @keydown.enter="draft && todos.push({ text: draft, done: false }); draft = ''" placeholder="Add task" />
1274
- <button class="primary" @click="draft && todos.push({ text: draft, done: false }); draft = ''">Add</button>
1275
- </div>
1276
- <div style="display:flex;gap:8px">
1277
- <button @click="filter = 'all'" :class="{ primary: filter === 'all' }">All</button>
1278
- <button @click="filter = 'done'" :class="{ primary: filter === 'done' }">Done</button>
1279
- <button @click="setAll(todos, 'done', true)">Mark all done</button>
1280
- </div>
1281
- <p class="wf-muted"><span x-text="remaining(todos, 'done')"></span> open / <span x-text="count(todos)"></span> total</p>
1282
- <div
1283
- class="wf-box"
1284
- x-for="todo in todos"
1285
- x-show="filter === 'all' || (filter === 'done' && todo.done)"
1286
- :class="{ 'is-done': todo.done }"
1287
- style="display:flex;justify-content:space-between;gap:10px"
1288
- >
1289
- <label style="display:flex;gap:8px"><input type="checkbox" x-model="todo.done" /><span x-text="todo.text"></span></label>
1290
- <button @click="remove(todos, todo)">Remove</button>
1291
- </div>
1292
- <button @click="removeWhere(todos, 'done', true)">Clear completed</button>
1293
- </section>
1294
- </div>
1295
- \`\`\`
1296
-
1297
- Use real labels, counts, dates, and controls grounded in the target app. Keep
1298
- surfaces honest: \`browser\` for web pages, \`desktop\` for app shells, \`mobile\`
1299
- only for real mobile work, \`panel\` for side panels, and \`popover\` for menus.
1300
-
1301
- Do not include \`<html>\`, \`<body>\`, \`<script>\`, \`<style>\`, browser \`on*\`
1302
- handler attributes such as \`onclick\`, fake APIs, raw secrets, or customer data.
1303
- The renderer owns sketchy/clean mode, theme, surface sizing, rough outlines, and
1304
- comment overlays.
1305
-
1306
- ## Review Surface
1307
-
1308
- Prototype plans support:
1309
-
1310
- - real local controls through safe prototype directives
1311
- - optional screen/route transitions from \`data-goto\`
1312
- - rough vs clean mode through the shared wireframe toggle
1313
- - dark vs light mode through the shared theme toggle
1314
- - comment visibility from the prototype toolbar
1315
- - Figma-style comments pinned directly on live prototype screens
1316
- - a popout URL with \`?prototype=1\` for focused browser review
1317
- - static wireframe mocks in the document body where they help implementation
1318
-
1319
- ## Source Files
1320
-
1321
- Runtime JSON is canonical. Source export uses:
1322
-
1323
- - \`plan.mdx\` for document blocks
1324
- - \`prototype.mdx\` for \`<Prototype>\`, \`<PrototypeScreen>\`, and
1325
- \`<PrototypeTransition>\`
1326
- - \`canvas.mdx\` for static mocks when a canvas is present
1327
- - \`.plan-state.json\` for persisted viewport state
1328
-
1329
- Patch source with \`patch-visual-plan-source\` only when the user wants
1330
- source-control friendly edits. Patch runtime content when the user is simply
1331
- reviewing and iterating.
1332
-
1333
- ## Related Skills
1334
-
1335
- - \`visual-plan\`
1336
- - \`ui-plan\`
1337
- - \`visual-questions\`
1338
- `;
1339
- export const PLAN_DESIGN_SKILL_MD = `---
1340
- name: plan-design
1341
- description: >-
1342
- Use Agent-Native Plans for full-fidelity UI design planning with a Design
1343
- canvas tab and optional interactive Prototype tab before implementation.
1344
- metadata:
1345
- visibility: exported
1346
- ---
1347
-
1348
- # Plan Design
1349
-
1350
- Use \`/plan-design\` when the user needs a high-fidelity product design before
1351
- implementation: polished branded screens, realistic content, visual direction,
1352
- and interaction review. It is the full-fidelity companion to \`/visual-plan\` and
1353
- \`/prototype-plan\`: the top review surface should show \`Design\` and, when the
1354
- flow needs interaction, \`Prototype\`.
1355
-
1356
- ## When To Use
1357
-
1358
- Use this for UI-heavy work where brand, visual hierarchy, polished layout, or
1359
- interaction feel are material to the decision. Skip it for small copy, spacing,
1360
- or obvious component changes.
1361
-
1362
- ## Research First
1363
-
1364
- Before creating the plan:
1365
-
1366
- 1. Inspect the real app shell, routes, components, CSS variables, Tailwind
1367
- tokens, theme files, and any relevant screenshots.
1368
- 2. If \`design.md\` exists, treat it as the primary design brief and pass its
1369
- important content into \`create-plan-design.designMd\`.
1370
- 3. If a \`.fig\` local-copy file or parsed brand kit is available, use the
1371
- Design/brand-kit parsing actions from the app or shared tooling first, then
1372
- pass the extracted token summary into \`brandKit\`.
1373
- 4. Parse existing codebase style info when possible: CSS custom properties,
1374
- Tailwind config, global CSS, font declarations, spacing/radius tokens, and
1375
- component conventions. Pass the compact evidence into \`codebaseStyles\`.
1376
- 5. Ground every screen in actual product content. Avoid lorem ipsum, generic
1377
- marketing filler, and placeholder gray boxes unless designing an explicit
1378
- loading state.
1379
-
1380
- ## Create The Plan
1381
-
1382
- Call \`create-plan-design\` with:
1383
-
1384
- - \`title\`, \`brief\`, \`repoPath\`, and any \`implementationNotes\`.
1385
- - \`designMd\`, \`brandKit\`, \`codebaseStyles\`, or \`designNotes\` when available.
1386
- - \`screens\`: one to six full-fidelity HTML/CSS screen fragments. Each screen
1387
- must include a bounded \`html\` fragment, optional scoped \`css\`, a \`surface\`,
1388
- and stable \`data-design-id\` attributes on elements a reviewer might edit.
1389
- - \`transitions\` only when the Prototype tab should support true screen/step
1390
- navigation. Use \`data-goto="screen-id"\` in the screen HTML for those controls.
1391
-
1392
- The Design tab is the visual source of truth. The Prototype tab is for behavior
1393
- and should reuse the same visual styling where practical. Do not create a
1394
- separate design direction in the prototype.
1395
-
1396
- ## Full-Fidelity HTML Rules
1397
-
1398
- - Write bounded fragments only: no \`<html>\`, \`<head>\`, \`<body>\`, \`<script>\`,
1399
- \`<style>\`, external imports, iframes, SVG, or executable URLs.
1400
- - Put CSS in the screen \`css\` field. The renderer scopes it to the artboard.
1401
- - Use real CSS and CSS variables. Tailwind-like class names are fine only when
1402
- the provided \`css\` defines them or the classes are harmless semantic hooks.
1403
- - Use \`renderMode: "design"\` on design screen data when authoring full
1404
- structured content directly.
1405
- - Add \`data-design-id="meaningful-name"\` to editable elements such as hero
1406
- panels, key buttons, cards, nav items, pricing rows, chart panels, and state
1407
- chips. Keep ids stable and descriptive.
1408
- - Keep the design responsive within the selected surface. Text must not clip,
1409
- overlap, or rely on viewport-sized type.
1410
-
1411
- ## Targeted Style Edits
1412
-
1413
- When a reviewer selects an element in the Design tab or asks for a specific
1414
- style change, avoid regenerating the whole plan. Use:
1415
-
1416
- \`\`\`json
1417
- {
1418
- "op": "update-design-element-style",
1419
- "frameId": "frame-overview",
1420
- "elementId": "primary-cta",
1421
- "styles": {
1422
- "background-color": "#0f766e",
1423
- "border-radius": "10px"
1424
- }
1425
- }
1426
- \`\`\`
1427
-
1428
- Use \`frameId\` for inline canvas designs or \`blockId\` for a referenced wireframe
1429
- block. Set a style value to \`null\` to remove it. Use \`patch-wireframe-html\` or
1430
- \`patch-prototype-html\` for text/content changes inside a fragment.
1431
-
1432
- ## Document Handoff
1433
-
1434
- Below the visual surface, keep the document concise and implementation-oriented:
1435
- actual files and symbols, state/actions/contracts, open questions, risks, and
1436
- verification. The document should not repeat the same screens in prose.
1437
-
1438
- Before implementation, call \`get-plan-feedback\` and treat comments, selected
1439
- element details, and recent review events as the source of truth.
1440
-
1441
- ## Related Skills
1442
-
1443
- - \`visual-plan\`
1444
- - \`ui-plan\`
1445
- - \`prototype-plan\`
1446
- - \`frontend-design\`
1447
- `;
1448
1146
  export const VISUAL_RECAP_SKILL_MD = `---
1449
1147
  name: visual-recap
1450
1148
  description: >-
@@ -1466,25 +1164,64 @@ schema, API, file, and architecture changes become the same \`data-model\`,
1466
1164
  now they summarize work that exists. A reviewer scans the shape of the change
1467
1165
  before spending attention on the literal lines.
1468
1166
 
1167
+ ## Local-Files Privacy Mode Exception
1168
+
1169
+ Use local-files privacy mode when the user explicitly asks for no DB writes,
1170
+ no hosted Plan app, no Plan MCP publish, fully local files, offline/private
1171
+ recaps, or when \`AGENT_NATIVE_PLANS_MODE=local-files\` is set. This is the only
1172
+ exception to the hosted publish rule below.
1173
+
1174
+ In local-files mode:
1175
+
1176
+ - Read the diff/stat/source context from local files and shell commands only.
1177
+ The existing \`agent-native recap collect-diff\`, \`scan\`, and
1178
+ \`build-prompt --local-files\` helpers are safe to use because they operate on
1179
+ local files and do not write to the Plan database.
1180
+ - Write the recap as a local MDX folder under \`plans/<slug>/\`: \`plan.mdx\`,
1181
+ optional \`canvas.mdx\`, optional \`prototype.mdx\`, and optional
1182
+ \`.plan-state.json\`. Set \`kind: "recap"\` and \`localOnly: true\` in
1183
+ frontmatter/state when authoring the source.
1184
+ - Run \`agent-native plan local preview --dir plans/<slug> --kind recap\` after
1185
+ writing or updating the folder. Report the returned local URL or the
1186
+ \`/local-plans/<slug>\` route if the local Plan app is running with the same
1187
+ \`PLAN_LOCAL_DIR\`.
1188
+ - Do **not** call \`create-visual-recap\`, \`create-visual-plan\`,
1189
+ \`import-visual-plan-source\`, \`update-visual-plan\`,
1190
+ \`patch-visual-plan-source\`, \`get-plan-feedback\`, \`export-visual-plan\`,
1191
+ \`set-resource-visibility\`, or any hosted Plan tool for that recap.
1192
+ - Treat review feedback as file or chat feedback: update the MDX files directly,
1193
+ rerun the local preview command, and summarize the new local URL/path.
1194
+ Hosted comments, sharing, screenshots, usage attachment, and PR sticky comment
1195
+ publishing are unavailable until the user explicitly opts into publishing.
1196
+
1197
+ Local-files mode prevents recap content from going to the Agent-Native Plan
1198
+ database. It does not by itself make the coding agent's language model local;
1199
+ for that stronger privacy boundary, the host agent/model must also be local or
1200
+ otherwise approved by the user.
1201
+
1469
1202
  ## Always Publish As An Agent-Native Plan — Never Inline
1470
1203
 
1471
1204
  The deliverable is ALWAYS a published Agent-Native Plan, created with the
1472
- \`create-visual-recap\` tool on the \`plan\` MCP server. NEVER hand the recap to the
1473
- user as inline chat content not Markdown prose, not an ASCII sketch, not a
1474
- table, not a fenced "wireframe", not a "here's the recap" summary. A recap's
1475
- entire value is the hosted, interactive, annotatable plan; an inline summary is
1476
- not a recap, it is the thing a recap replaces. The only supported output is to
1477
- publish the plan and return its absolute URL.
1478
-
1479
- If the \`plan\` MCP server's tools are not available, do NOT improvise an inline
1480
- recap as a fallback. The usual cause is a connector that did not finish
1481
- connecting this session (it registers zero tools), NOT necessarily an auth
1482
- problem so do not assume the user must authenticate. Stop and tell the user
1483
- how to restore it: reconnect the plan MCP server (in Claude Code, run \`/mcp\` and
1484
- reconnect, or restart the session); only if it is genuinely unauthenticated, run
1485
- \`agent-native connect <plan-app-url>\` or re-authenticate via \`/mcp\`. Then publish
1486
- once the tool is reachable. Falling back to inline content is a defect, not a
1487
- degraded mode.
1205
+ \`create-visual-recap\` tool on the Plan MCP connector. The connector is usually
1206
+ exposed as the \`plan\` server, but older installed agents may expose the same
1207
+ hosted connector as \`agent-native-plans\`; both names are valid. NEVER hand the
1208
+ recap to the user as inline chat content not Markdown prose, not an ASCII
1209
+ sketch, not a table, not a fenced "wireframe", not a "here's the recap" summary.
1210
+ A recap's entire value is the hosted, interactive, annotatable plan; an inline
1211
+ summary is not a recap, it is the thing a recap replaces. The only supported
1212
+ output is to publish the plan and return its absolute URL.
1213
+
1214
+ Except for the explicit local-files privacy mode above, if neither the \`plan\`
1215
+ nor legacy \`agent-native-plans\` Plan MCP tools are available, do NOT improvise an
1216
+ inline recap as a fallback. Do not report the connector as disconnected just
1217
+ because it is named \`agent-native-plans\` instead of \`plan\`. The usual cause is a
1218
+ connector that did not finish connecting this session (it registers zero tools),
1219
+ NOT necessarily an auth problem so do not assume the user must authenticate.
1220
+ Stop and tell the user how to restore it: reconnect the Plan MCP connector (in
1221
+ Claude Code, run \`/mcp\` and reconnect, or restart the session); only if it is
1222
+ genuinely unauthenticated, run \`agent-native connect <plan-app-url>\` or
1223
+ re-authenticate via \`/mcp\`. Then publish once the tool is reachable. Falling
1224
+ back to inline content is a defect, not a degraded mode.
1488
1225
 
1489
1226
  ## When To Use
1490
1227
 
@@ -1535,282 +1272,87 @@ them. Alongside the visual/structural headline (wireframes, \`data-model\`,
1535
1272
  \`api-endpoint\`, \`diagram\`), a substantial recap also carries the implementation
1536
1273
  evidence:
1537
1274
 
1275
+ - A short surface/state inventory before authoring: list the changed routes,
1276
+ components, popovers/dialogs, role/access states, empty/error states, and
1277
+ shared abstractions visible in the diff. The final recap must either represent
1278
+ each meaningful item with a block or intentionally omit it because it is tiny,
1279
+ redundant, or not user-visible.
1538
1280
  - A \`file-tree\` of the changed files with each entry's \`change\` flag, so the
1539
- reviewer sees the footprint of the work at a glance.
1540
- - The \`diff\` of the KEY changed files, grouped under a \`## Key changes\`
1541
- \`rich-text\` heading in a single vertical \`tabs\` block (file labels as the left
1542
- rail), with a one-line \`summary\` and a few \`annotations\` on each — so the
1543
- reviewer can drop from the high-altitude shape straight into the load-bearing
1544
- code. Leave \`mode\` unset so each diff renders unified the default — because a
1545
- tab panel is too narrow for split's side-by-side gutters to stay legible.
1546
-
1547
- Skip the diff appendix only for a genuinely tiny change that reviews faster as
1548
- plain diff (see "When To Use"); for any change worth recapping, the file-tree and
1549
- key-change diffs belong in the plan.
1550
-
1551
- ## UI Impact Needs Wireframes
1552
-
1553
- When the diff changes rendered UI, layout, density, visual state, interaction
1554
- affordances, navigation, controls, menus, dialogs, or design tokens, the recap
1555
- MUST include one or more wireframes. Prose and file diffs are not a substitute
1556
- for showing what changed visually.
1557
-
1558
- Choose the smallest visual surface that makes the review clear:
1559
-
1560
- - Use a \`Before\` / \`After\` wireframe pair when the reviewer benefits from direct
1561
- comparison, such as a removed or added control, a changed state, layout
1562
- density, ordering, navigation, or a visible component replacement. The
1563
- Wireframe Quality core below owns how to lay that pair out (columns vs.
1564
- vertical stack by geometry).
1565
- - Use an after-only wireframe when the change is purely additive or the "before"
1566
- state would only show absence without adding review value.
1567
- - Use more than two wireframes when the UI change is flow-dependent, responsive,
1568
- or stateful; show the meaningful states in order instead of forcing a single
1569
- before/after pair.
1570
- - For tiny surfaces like menus, popovers, dialogs, toasts, or panels, use the
1571
- matching \`surface\` (\`popover\`, \`panel\`, etc.) and show the focused sub-surface.
1572
- Do not redraw a full page unless placement in the page is itself part of the
1573
- change.
1574
-
1575
- Ground each wireframe in the changed UI behavior, component names, file paths,
1576
- and diff-visible labels/states. If exact pixels are inferred rather than
1577
- captured, say so in the wireframe caption or a concise annotation. For
1578
- local/manual recaps, import or update the plan source that holds the wireframes
1579
- so the rendered recap opens with the UI visual available.
1580
-
1581
- ## Wireframe Quality
1582
-
1583
- UI recap wireframes must look like the UI surface that changed, not like generic
1584
- architecture boxes. The following bar is shared, word for word, with
1585
- \`/visual-plan\` and \`/ui-plan\`: it is the single source of truth for HTML
1586
- wireframe quality, and applies to a recap's standalone \`wireframe\` /
1587
- \`WireframeBlock\` / \`<Screen>\` exactly as it applies to a plan's canvas artboard.
1588
-
1589
- <!-- SHARED-CORE:wireframe-quality START -->
1590
-
1591
- **A wireframe is an HTML mockup. The renderer owns the look; you write the
1592
- content.** Set \`data.html\` to a self-contained, semantic HTML fragment of the
1593
- screen and set \`data.surface\`. The renderer owns the surface footprint/aspect,
1594
- the dark/light theme, the hand-drawn font, and the rough.js sketch overlay — you
1595
- never write \`<html>\`/\`<body>\`/\`<script>\`/\`<style>\` tags, font-family, hex colors,
1596
- or any width/height/coordinates. You write real HTML layout and real product
1597
- content; the renderer styles and roughens it.
1598
-
1599
- **A wireframe block's data is an HTML screen plus a surface:**
1600
-
1601
- \`\`\`json
1602
- {
1603
- "surface": "browser",
1604
- "html": "<div style=\\"display:flex;flex-direction:column;gap:10px;padding:16px;height:100%\\"><h1>Sign in</h1><p class=\\"wf-muted\\">Use your work email to continue.</p><div class=\\"wf-card\\" style=\\"display:flex;flex-direction:column;gap:10px\\"><label>Email<input value=\\"jane@acme.co\\" /></label><label>Password<input value=\\"••••••••\\" /></label><label style=\\"display:flex;align-items:center;gap:8px\\"><input type=\\"checkbox\\" checked /> Remember me</label><button class=\\"primary\\">Sign in</button></div><a href=\\"#\\">Forgot password?</a></div>"
1605
- }
1606
- \`\`\`
1607
-
1608
- **Write PLAIN semantic HTML and let the renderer style it.** Bare elements
1609
- (\`h1\`/\`h2\`/\`h3\`, \`p\`, \`button\`, \`input\`, \`<input type="checkbox">\`, \`a\`, \`hr\`)
1610
- are auto-themed — no classes needed. Helper classes carry the rest:
1611
-
1612
- - \`.wf-card\` / \`.wf-box\` — a bordered, padded container (a panel, a list item).
1613
- - \`.wf-pill\` / \`.wf-chip\` — a rounded tag or filter; add \`.accent\`
1614
- (\`<span class="wf-pill accent">\`) for the accent-filled variant.
1615
- - \`.wf-muted\` — secondary/muted text (or use \`<small>\`).
1616
- - \`button.primary\` or any element with \`[data-primary]\` — the accent-filled
1617
- primary button.
1618
-
1619
- **Use the \`--wf-*\` tokens for any custom color, never hex.** The renderer flips
1620
- these on light/dark, so reading them is what keeps a mockup correct in both
1621
- themes. For any inline border, background, or text color, reference a token:
1622
- \`style="border:1.4px solid var(--wf-line)"\`. The tokens are \`--wf-ink\` (text),
1623
- \`--wf-muted\` (secondary text), \`--wf-line\` (borders/dividers), \`--wf-paper\`
1624
- (page background), \`--wf-card\` (raised surface), \`--wf-accent\` /
1625
- \`--wf-accent-fg\` / \`--wf-accent-soft\` (brand action), \`--wf-warn\`, \`--wf-ok\`,
1626
- and \`--wf-radius\`. Never hard-code a hex color and never set \`font-family\` — the
1627
- renderer owns the sketch/clean font.
1628
-
1629
- **Lay out with inline \`style\` flex/grid.** You write the real layout —
1630
- \`display:flex; flex-direction:column; gap:10px; padding:16px\` and so on — and the
1631
- renderer never repositions anything. Compose the actual product: reproduce the
1632
- current screen, then show the modification. Real labels, real counts, real dates,
1633
- real button text grounded in the screen you read; not lorem or gray bars.
1634
-
1635
- **Surface presets — match the real footprint, never default to desktop+mobile.**
1636
- Pick the \`surface\` that matches what the user will actually see:
1637
-
1638
- - \`browser\`: a web page that needs a browser chrome frame around it.
1639
- - \`desktop\`: a full desktop app page or app shell.
1640
- - \`mobile\`: a phone screen, only when the work is genuinely mobile.
1641
- - \`popover\`: a small floating menu, dropdown, or inline popover.
1642
- - \`panel\`: a side panel, inspector, or sidebar widget.
1643
-
1644
- A sidebar popover renders as a small surface, not a desktop page and a phone
1645
- frame. Do not emit \`desktop\` + \`mobile\` variants unless responsive behavior
1646
- actually changes the layout. For a component or widget, show one broader
1647
- app-context frame only when placement affects understanding, then the focused
1648
- component states.
1649
-
1650
- **Model the actual component shell for small surfaces.** A rendered UI change
1651
- belongs in a wireframe; reserve \`diagram\` for architecture, dependency, state,
1652
- or data-flow relationships. Popovers, dropdown menus, command palettes, and
1653
- context menus use \`surface: "popover"\` unless the surrounding page placement is
1654
- the point of the change. Dialogs, sheets, inspectors, sidebars, and long
1655
- property panels use the matching \`panel\` / \`desktop\` surface as appropriate.
1656
- Show the real chrome: trigger or anchor when it matters, title/header row,
1657
- top-right actions, separators, fields, options, selected states, body content,
1658
- and footer actions that are visible in the workflow.
1659
-
1660
- **Modify, don't redesign.** When the task changes an existing screen, reproduce
1661
- the current screen's real layout and footprint FIRST, then change only the delta
1662
- and call it out with a single annotation. Do not restack the page into a new
1663
- layout. For net-new surfaces, compose from the real app shell.
1664
-
1665
- **Classify mockup scope before implementation.** Before turning a plan mockup
1666
- into source code, decide whether each artboard represents the whole page/app
1667
- shell, a route body inside an existing shell, or a component/sub-surface. If an
1668
- artboard includes navigation, sidebars, auth banners, or a signup/login form,
1669
- map those pieces to the real shared shell/auth components instead of nesting the
1670
- entire mockup inside the current page. When a mockup references the product's
1671
- standard signup/login page, find and reuse that existing implementation; do not
1672
- approximate it from the wireframe.
1673
-
1674
- **Zoom in on sub-surfaces, don't redraw the page.** For a small sub-surface (a
1675
- popover, menu, dialog, toast), show the full screen once, then add a small
1676
- separate artboard whose \`html\` contains ONLY that sub-surface — do not re-draw
1677
- the whole page around it, and do not scale a duplicate up. Pick the matching
1678
- \`surface\` (e.g. \`popover\`) so the footprint is right; never widen a popover to
1679
- page width.
1680
-
1681
- **Loading / skeleton states.** Set \`data.skeleton: true\` on the wireframe and
1682
- fill the \`html\` with neutral, textless placeholder geometry — boxes and bars
1683
- built as \`<div>\`s with \`background:var(--wf-line)\` and explicit heights/widths,
1684
- no labels or copy. The renderer drops borders, sketch, and color into the
1685
- skeleton register automatically. Never escape to a \`custom-html\` document block
1686
- to fake a loader.
1687
-
1688
- **Editing an existing mockup.** To change one element, text, or color in an
1689
- existing html mockup, do NOT regenerate the frame — call \`update-visual-plan\`
1690
- with \`contentPatches: [{ op: "patch-wireframe-html", blockId, edits: [{ find,
1691
- replace }] }]\`. Each \`find\` is a unique snippet of the current html (read it
1692
- first with \`get-visual-plan\`); set \`all: true\` on an edit to replace every
1693
- occurrence. The result is re-sanitized.
1694
-
1695
- **Treat the wireframe border as part of the visible design.** Always wrap HTML
1696
- wireframe content in a root container with real inner padding before drawing
1697
- cards, fields, pills, labels, or controls. Use at least 14-16px of padding,
1698
- \`box-sizing: border-box\`, \`height: 100%\`, and \`gap\` between child rows so the
1699
- first row never sits flush against the screen border. Keep text away from
1700
- borders: every container, field, button, menu item, and annotation needs enough
1701
- padding and line-height to read cleanly in the rendered Plan view.
1702
-
1703
- **Lay out children safely so they never collide.** Use HTML flex/grid with
1704
- \`gap\`, \`min-width: 0\`, and sensible overflow. Avoid negative margins, absolute
1705
- positioning, or fixed child widths that can collide when the renderer switches
1706
- between light/dark, sketch/clean, or different zoom levels.
1707
-
1708
- **Do not wrap intentionally single-line labels.** For toolbars, tab rails,
1709
- breadcrumbs, chip/filter rows, branch and file names, file chips, and code
1710
- filenames — any deliberately single-line row — do not let long text wrap. Put
1711
- \`white-space: nowrap\` on the row (and \`overflow: hidden; text-overflow: ellipsis\`
1712
- on the individual labels that can grow), so the wireframe demonstrates the actual
1713
- layout behavior instead of producing ugly stacked or vertical text. Use
1714
- horizontally scrollable or clipped rails for overflow.
1715
-
1716
- **Fill the frame; keep labels short.** Each artboard is a fixed-size surface — compose enough realistic HTML to fill it top to bottom with even vertical rhythm; never leave a large empty band. On desktop/app-shell sidebars, let the nav stack flex to fill (\`flex:1\`) and add any persistent bottom action/status after it so the rail reads complete in taller frames. On mobile especially, flow real rows down the whole screen (status bar, header, then list/detail content) rather than a header floating above a gap. Keep every label short enough to sit on one line within its column — shorten the copy rather than relying on the frame to absorb it (long labels wrap or clip).
1717
-
1718
- **Persistent chrome bars span the full frame width.** Top bars, app headers,
1719
- toolbars, and bottom tab/nav bars are full-width chrome, not centered content.
1720
- Lay each one out as a single flex row that fills the frame
1721
- (\`style="display:flex;align-items:center;width:100%"\`) and push trailing actions
1722
- to the right edge with a flex spacer (\`<div style="flex:1"></div>\`) between the
1723
- leading group and the trailing group — never center a bar inside a narrow,
1724
- centered block, and never let it collapse to the width of its contents. In a
1725
- Before/After pair the bar stays full-width in BOTH states even when one state has
1726
- fewer controls; the spacer absorbs the difference so the remaining controls hold
1727
- their edge alignment instead of sliding to the center.
1728
-
1729
- **Pin bottom bars to the bottom of the frame.** For mobile tab bars, footers, and
1730
- any persistent bottom action row, make the frame itself a flex column at
1731
- \`height:100%\` (\`style="display:flex;flex-direction:column;height:100%"\`), give the
1732
- scrolling body \`flex:1\` so it absorbs the slack, and place the bar as the LAST
1733
- child of the frame (or set \`margin-top:auto\` on it). The bar then sits flush at
1734
- the bottom of the surface instead of floating directly under the content with an
1735
- empty band beneath it.
1736
-
1737
- **Before / after must be comparable.** When showing a state change, preserve the
1738
- unchanged controls in both states so the reviewer can see exactly what moved or
1739
- appeared; do not show an added control as a generic box floating elsewhere in
1740
- the surface. Place the new/changed affordance where the implementation puts it —
1741
- for example, a new \`Edit with AI\` action in a popover header belongs in the
1742
- top-right header slot, aligned with the title, not in the body or footer. Use
1743
- the same frame size, scale, outer padding, border radius, and visual density on
1744
- both sides unless the change itself alters those properties, and let the frame
1745
- height fit the content rather than leaving a tall empty lower half.
1746
-
1747
- **Name the states with the column header, never inside the frame.** Put the two
1748
- states in a \`columns\` block and set each column's \`label\` to \`Before\` and
1749
- \`After\` — the renderer draws that label as an \`h4\` heading above each frame. Do
1750
- NOT bake a \`Before\`/\`After\` pill, title, or heading into the wireframe \`html\`: a
1751
- label placed inside reads as part of the product UI, lands in a random corner,
1752
- and clutters the comparison. The column header is the one and only place the
1753
- state name belongs.
1754
-
1755
- **Let the surface choose side-by-side vs. stacked.** The \`columns\` renderer lays
1756
- narrow surfaces (\`mobile\`, \`popover\`, \`panel\`) out side by side, and
1757
- automatically stacks wide surfaces (\`desktop\`, \`browser\`) vertically at full
1758
- document width so a large frame is never crushed into a half-width column and
1759
- cropped. Author both wireframes with the real \`surface\` and the matching
1760
- \`Before\`/\`After\` column labels; do not hand-stack the pair into separate
1761
- top-level wireframes or duplicate the state name as body content.
1762
-
1763
- **Good example — a contacts list, surface \`browser\`.** A small, real screen
1764
- composed from the helper classes and tokens, layout in inline flex, no fonts or
1765
- hex colors:
1766
-
1767
- \`\`\`html
1768
- <div
1769
- style="display:flex;flex-direction:column;gap:12px;padding:16px;height:100%"
1770
- >
1771
- <div style="display:flex;align-items:center;justify-content:space-between">
1772
- <h1>Contacts</h1>
1773
- <button class="primary">New contact</button>
1774
- </div>
1775
- <div style="display:flex;gap:6px">
1776
- <span class="wf-pill accent">All 128</span>
1777
- <span class="wf-pill">Favorites</span>
1778
- <span class="wf-pill">Archived</span>
1779
- </div>
1780
- <div
1781
- class="wf-card"
1782
- style="display:flex;flex-direction:column;gap:0;padding:0"
1783
- >
1784
- <div
1785
- style="display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1.4px solid var(--wf-line)"
1786
- >
1787
- <div
1788
- style="width:32px;height:32px;border-radius:999px;background:var(--wf-accent-soft)"
1789
- ></div>
1790
- <div style="flex:1">
1791
- <strong>Jane Cooper</strong><br /><small>jane@acme.co</small>
1792
- </div>
1793
- <span class="wf-pill">Lead</span>
1794
- </div>
1795
- <div style="display:flex;align-items:center;gap:10px;padding:10px 12px">
1796
- <div
1797
- style="width:32px;height:32px;border-radius:999px;background:var(--wf-accent-soft)"
1798
- ></div>
1799
- <div style="flex:1">
1800
- <strong>Marcus Lee</strong><br /><small>marcus@globex.io</small>
1801
- </div>
1802
- <span class="wf-pill">Customer</span>
1803
- </div>
1804
- </div>
1805
- </div>
1806
- \`\`\`
1281
+ reviewer sees the footprint of the work at a glance.
1282
+ - The split \`diff\` of the KEY changed files, grouped under a \`## Key changes\`
1283
+ \`rich-text\` heading in a single horizontal \`tabs\` block (the default
1284
+ orientation, one file per tab), with a one-line \`summary\` and a few
1285
+ \`annotations\` on each — so the reviewer can drop from the high-altitude shape
1286
+ straight into the load-bearing code. Use horizontal file tabs, not a vertical
1287
+ side rail, so the selected file has enough width for the side-by-side diff.
1288
+
1289
+ Skip the diff appendix only for a genuinely tiny change that reviews faster as
1290
+ plain diff (see "When To Use"); for any change worth recapping, the file-tree and
1291
+ key-change diffs belong in the plan.
1292
+
1293
+ ## UI Impact Needs Wireframes
1294
+
1295
+ When the diff changes rendered UI, layout, density, visual state, interaction
1296
+ affordances, navigation, controls, menus, dialogs, or design tokens, the recap
1297
+ MUST include one or more wireframes. Prose and file diffs are not a substitute
1298
+ for showing what changed visually.
1299
+
1300
+ Before choosing wireframes, make a UI coverage pass from the diff:
1301
+
1302
+ - Identify the entry surface where the change appears, such as a page header,
1303
+ list row, toolbar, route shell, or menu trigger.
1304
+ - Identify the interaction surface that opens or changes, such as a popover,
1305
+ dialog, tab, sheet, dropdown, inline editor, or toast.
1306
+ - Identify the resulting destination or persistent state, such as a public page,
1307
+ read-only view, empty state, error state, loading state, permission-denied
1308
+ state, or saved/shared state.
1309
+ - Identify access or role variants when permissions change. Owner/admin/editor
1310
+ versus viewer/non-manager differences are visual behavior and need a compact
1311
+ matrix, paired wireframes, or clearly labeled state sequence.
1312
+
1313
+ For UI-heavy PRs, a single before/after of the entry surface is not enough.
1314
+ Show the changed entry point, the main changed interaction surface, and the
1315
+ resulting/destination state. Add more states when the diff adds tabs, role-based
1316
+ controls, public/private visibility, invite/manage flows, destructive controls,
1317
+ or empty/error branches.
1318
+
1319
+ Choose the smallest visual surface that makes the review clear:
1320
+
1321
+ - Use a \`Before\` / \`After\` wireframe pair when the reviewer benefits from direct
1322
+ comparison, such as a removed or added control, a changed state, layout
1323
+ density, ordering, navigation, or a visible component replacement. The
1324
+ Wireframe Quality core below owns how to lay that pair out (columns vs.
1325
+ vertical stack by geometry).
1326
+ - Use an after-only wireframe when the change is purely additive or the "before"
1327
+ state would only show absence without adding review value.
1328
+ - Use more than two wireframes when the UI change is flow-dependent, responsive,
1329
+ or stateful; show the meaningful states in order instead of forcing a single
1330
+ before/after pair.
1331
+ - For tiny surfaces like menus, popovers, dialogs, toasts, or panels, use the
1332
+ matching \`surface\` (\`popover\`, \`panel\`, etc.) and show the focused sub-surface.
1333
+ Do not redraw a full page unless placement in the page is itself part of the
1334
+ change.
1335
+
1336
+ Ground each wireframe in the changed UI behavior, component names, file paths,
1337
+ and diff-visible labels/states. If exact pixels are inferred rather than
1338
+ captured, say so in the wireframe caption or a concise annotation. For
1339
+ local/manual recaps, import or update the plan source that holds the wireframes
1340
+ so the rendered recap opens with the UI visual available.
1807
1341
 
1808
- <!-- SHARED-CORE:wireframe-quality END -->
1342
+ ## Wireframe Quality — read \`references/wireframe.md\`
1343
+
1344
+ UI recap/plan wireframes must meet a strict quality bar — full-width chrome,
1345
+ pinned bottom bars, real product content, before/after comparability, the right
1346
+ \`surface\` preset, \`--wf-*\` tokens instead of hex, and no \`<html>\`/\`<style>\`/font
1347
+ tags. Before authoring ANY wireframe / \`<Screen>\` / \`WireframeBlock\`, READ
1348
+ \`references/wireframe.md\` in this skill directory — it is the single source of
1349
+ truth for HTML wireframe quality, shared word for word with \`/visual-plan\`
1350
+ and \`/visual-recap\`. Do not author wireframes from memory.
1809
1351
 
1810
1352
  Use the standard \`WireframeBlock\` / \`<Screen>\` format so the Plan viewer owns the
1811
1353
  surface frame, theme, and sketchy/clean toggle. HTML wireframes are appropriate
1812
1354
  when placement precision matters, especially popovers, menus, dialogs, and dense
1813
- forms; kit-tree wireframes are appropriate for simpler layouts. For HTML
1355
+ forms. For HTML
1814
1356
  wireframes, keep \`renderMode\` unset or \`wireframe\` unless a design-only editable
1815
1357
  mockup is explicitly required, because \`renderMode="design"\` disables the
1816
1358
  sketchy rough overlay.
@@ -1822,6 +1364,11 @@ text-match screenshot is not enough; visually inspect the captured image.
1822
1364
 
1823
1365
  ## Open And Report The Recap
1824
1366
 
1367
+ In local-files privacy mode, report the local preview URL/path from
1368
+ \`agent-native plan local preview\` or the \`/local-plans/<slug>\` route for a local
1369
+ Plan app using the same \`PLAN_LOCAL_DIR\`. Do not invent a hosted URL and do not
1370
+ publish just to get an absolute Plan link.
1371
+
1825
1372
  After creating the recap, link the reviewer to the rendered plan with an
1826
1373
  **absolute URL on the origin whose database actually holds the plan**. That
1827
1374
  origin is the Plan MCP server you just created the recap through — NOT whatever
@@ -1865,7 +1412,9 @@ artifacts, not as the main way to open the recap.
1865
1412
  ## Diff → Block Mapping
1866
1413
 
1867
1414
  Map each kind of change to the block that carries it, derived mechanically from
1868
- the actual diff:
1415
+ the actual diff. The names below are the CONCEPTUAL block types, not the JSX
1416
+ tags — resolve every conceptual name to its exact tag + prop schema with the
1417
+ \`get-plan-blocks\` tool (see "Block reference" below) before authoring.
1869
1418
 
1870
1419
  - **Schema / migration change** → \`data-model\` for the resulting entities,
1871
1420
  fields, and relations. Flag what moved per field/entity with
@@ -1892,42 +1441,36 @@ the actual diff:
1892
1441
  - **Compatibility-sensitive change** → short \`rich-text\` notes beside the
1893
1442
  relevant \`data-model\` / \`api-endpoint\` block. Name the changed field,
1894
1443
  endpoint, or behavior and mark whether it is breaking, risky, or non-breaking;
1895
- pair that note with a \`diff\` for the literal lines.
1896
- - **Any meaningful code hunk** → \`diff\` carrying the real \`before\` / \`after\` text
1897
- and the \`filename\` / \`language\`. Leave \`mode\` unset: unified is the default and
1898
- the right choice for a recap, since recap diffs almost always sit inside a
1899
- width-constrained container (a vertical-tabs panel or a comparison column)
1900
- where split's two line-number gutters cut the code off. Reach for \`mode:
1901
- "split"\` only for a standalone, full-document-width diff where side-by-side
1902
- genuinely helps. Give every \`diff\` a one-line \`summary\` saying what the hunk
1903
- changes and why; it renders as a description above the code so the reviewer
1904
- reads intent first. Never leave a diff unlabeled.
1444
+ pair that note with a split \`diff\` for the literal lines.
1445
+ - **Any meaningful code hunk** → \`diff\` with \`mode: "split"\`, carrying the real
1446
+ \`before\` / \`after\` text and the \`filename\` / \`language\`. Split mode is the
1447
+ default for recap code review because before/after legibility is the point;
1448
+ use \`mode: "unified"\` only for a genuinely narrow standalone hunk where
1449
+ side-by-side would hide the code. Give every \`diff\` a one-line \`summary\`
1450
+ saying what the hunk changes and why; it renders as a description above the
1451
+ code so the reviewer reads intent first. Never leave a diff unlabeled.
1905
1452
  For the KEY changed files, attach \`annotations\` to the \`diff\` so the recap
1906
1453
  calls out what each important hunk does — this is the headline affordance for
1907
- annotating the key files updated. Each annotation is
1908
- \`{ side?: "before" | "after"; lines: "13" | "13-15"; label?: string; note }\`
1909
- and anchors to the AFTER-side line numbers by default (set \`side: "before"\` to
1910
- point at removed lines). Keep it to a few high-signal notes per file, not one
1911
- per line.
1454
+ annotating the key files updated. Each annotation anchors to the AFTER-side
1455
+ line numbers by default (set \`side: "before"\` to point at removed lines). Keep
1456
+ it to a few high-signal notes per file, not one per line.
1912
1457
  When several key files each need a substantial diff, introduce the group with a
1913
1458
  \`rich-text\` heading block whose markdown is \`## Key changes\`, then place the
1914
- \`diff\` blocks under it in a reusable \`tabs\` block with
1915
- \`orientation: "vertical"\` so file labels form a left rail and the selected
1916
- file's diff renders unified on the right. Leave each diff's \`mode\` unset — the
1917
- tab panel is too narrow for split and let the unified default carry it. Let
1918
- that heading label the section — do NOT also set a \`title\` on the \`tabs\` block.
1919
- Keep each tab label to the file path or a short basename plus directory hint.
1459
+ \`diff\` blocks under it in a reusable \`tabs\` block with horizontal orientation
1460
+ (the default — omit \`orientation\`) so the selected file's split diff gets the
1461
+ full document width. Let that heading label the section do NOT also set a
1462
+ \`title\` on the \`tabs\` block. Keep each tab label to the file path or a short
1463
+ basename plus directory hint.
1920
1464
  If the recap ends with more than one supporting diff, that trailing diff
1921
- appendix should be one vertical \`tabs\` block under its own \`## Key changes\`
1465
+ appendix should be one horizontal \`tabs\` block under its own \`## Key changes\`
1922
1466
  heading, not a stack of separate \`diff\` blocks.
1923
1467
  - **Brand-new file or a substantial added block with no meaningful "before"** →
1924
- \`annotated-code\` rather than a one-sided \`diff\`. Carry the real new code
1468
+ \`annotated-code\` rather than a one-sided split \`diff\`. Carry the real new code
1925
1469
  with its \`filename\` / \`language\` and anchor a few high-signal notes to the lines
1926
- that matter (\`{ lines: "12" | "12-18"; label?; note }\`) so the reviewer reads
1927
- what the new code does, not code for code's sake. Keep \`diff\` for true
1928
- before/after hunks where the removed lines still carry meaning, and group
1929
- several annotated walkthroughs in a vertical \`tabs\` block the same way diffs are
1930
- grouped.
1470
+ that matter so the reviewer reads what the new code does, not code for code's
1471
+ sake. Keep split \`diff\` for true before/after hunks where the removed lines
1472
+ still carry meaning, and group several annotated walkthroughs in a horizontal
1473
+ \`tabs\` block the same way diffs are grouped.
1931
1474
  - **Files added / removed / renamed** → \`file-tree\` with each entry's \`change\`
1932
1475
  flag (\`added\`, \`removed\`, \`modified\`, \`renamed\`) and a short \`note\`; attach a
1933
1476
  \`snippet\` only when one tells the reviewer something the path does not.
@@ -1936,15 +1479,17 @@ the actual diff:
1936
1479
  wireframes when the comparison clarifies the change; otherwise use after-only
1937
1480
  or a short state/flow sequence. Use realistic UI surfaces: for a popover
1938
1481
  change, show a popover with its title row, top-right actions, options/fields,
1939
- and any opened prompt/menu anchored to the correct trigger. Keep the body lean:
1940
- the wireframe carries the UI story, while the file tree and \`diff\`
1941
- blocks carry implementation evidence.
1482
+ tabs, selected/disabled states, people/lists/rows, and any opened prompt/menu
1483
+ anchored to the correct trigger. If a route was added, show the route body and
1484
+ the unavailable/empty state when the diff implements one. If permissions
1485
+ changed, show what managers can do and what viewers/non-managers see instead.
1486
+ Keep the body lean: the wireframe carries the UI story, while the file tree
1487
+ and \`diff\` blocks carry implementation evidence.
1942
1488
  - **Architecture or data-flow shift** → \`diagram\` with \`data.html\` / \`data.css\`
1943
1489
  as a two-panel before/after, layered, or swimlane layout, or \`mermaid\` for a
1944
- quick graph. Use the two-dimensional layouts the Document Quality core
1945
- prescribes; do not reduce a structural change to a left-to-right chain.
1946
- Do not use \`diagram\` as a stand-in for rendered UI controls; UI changes need
1947
- \`wireframe\` blocks.
1490
+ quick graph. Use two-dimensional layouts; do not reduce a structural change to
1491
+ a left-to-right chain. Do not use \`diagram\` as a stand-in for rendered UI
1492
+ controls; UI changes need \`wireframe\` blocks.
1948
1493
  Diagram HTML/CSS should use renderer-owned primitives such as
1949
1494
  \`.diagram-panel\`, \`.diagram-card\`, \`.diagram-node\`, \`.diagram-box\`,
1950
1495
  \`.diagram-pill\`, \`.diagram-muted\`, and \`[data-rough]\`; these map to the plan's
@@ -1957,349 +1502,56 @@ the actual diff:
1957
1502
  the objective the diff served, the key decisions visible in it, and the risks a
1958
1503
  reviewer should weigh. This is the only place the model writes freely.
1959
1504
 
1960
- ## Block MDX reference
1961
-
1962
- This is the authoritative tag + prop shape for every importable block. Author the
1963
- recap source against THESE tags and props do not guess from the conceptual
1964
- names above (the conceptual name like \`api-endpoint\` is NOT the JSX tag). A wrong
1965
- tag or prop shape either 500s the import with a ZodError or, for an unrecognized
1966
- capitalized tag, now **fails the import with a clear "Unknown plan block" error**
1967
- (it used to silently render as raw \`<JsonExplorer …>\` text — that footgun is
1968
- fixed). Every block also takes the shared envelope attributes \`id\` (REQUIRED,
1969
- unique across the whole plan), and optional \`title\`, \`summary\`, \`editable\`
1970
- those are omitted from the per-block prop lists below.
1971
-
1972
- The complete set of real block tags is exactly: \`RichText\`, \`FileTree\`,
1973
- \`DataModel\`, \`Endpoint\`, \`Diff\`, \`AnnotatedCode\`, \`WireframeBlock\` (body
1974
- \`<Screen>\` + wireframe-kit children), \`Columns\`/\`Column\`, \`TabsBlock\`, \`Callout\`,
1975
- \`Diagram\`, \`Mermaid\`, \`Json\`, \`HtmlBlock\`, \`Table\`, \`Checklist\`, \`Code\`,
1976
- \`OpenApi\`. Any other capitalized tag at the block level is rejected on import.
1977
-
1978
- Quick tag map (conceptual name real JSX tag):
1979
-
1980
- | Conceptual | Real tag | Conceptual | Real tag |
1981
- | --- | --- | --- | --- |
1982
- | api-endpoint | \`Endpoint\` | diff | \`Diff\` |
1983
- | data-model | \`DataModel\` | annotated-code | \`AnnotatedCode\` |
1984
- | file-tree | \`FileTree\` | code | \`Code\` |
1985
- | mermaid | \`Mermaid\` | rich-text | \`RichText\` |
1986
- | diagram | \`Diagram\` | callout | \`Callout\` |
1987
- | json-explorer | \`Json\` | columns | \`Columns\` (cols are \`Column\`) |
1988
- | openapi-spec | \`OpenApi\` | tabs | \`TabsBlock\` |
1989
- | wireframe | \`WireframeBlock\` (body \`<Screen>\`) | table | \`Table\` |
1990
- | custom-html | \`HtmlBlock\` | checklist | \`Checklist\` |
1991
-
1992
- ### Common mistakes (these now error on import)
1993
-
1994
- These WRONG tags used to be swallowed as raw text. Common synonyms are now
1995
- auto-corrected to the canonical tag on import; anything not in this map is
1996
- rejected with a "did you mean" hint. Always author with the canonical tag —
1997
- do not rely on the aliases.
1998
-
1999
- | WRONG tag | use |
2000
- | --- | --- |
2001
- | \`JsonExplorer\` | \`Json\` |
2002
- | \`Tabs\` (or a nested \`Tab\` child) | \`TabsBlock\` (tabs are ONE JSON \`tabs={[…]}\` prop — there is NO nested \`<Tab>\` element) |
2003
- | \`ApiEndpoint\` | \`Endpoint\` |
2004
- | \`DiffBlock\` | \`Diff\` |
2005
- | \`AnnotatedCodeBlock\` | \`AnnotatedCode\` |
2006
- | \`Wireframe\` | \`WireframeBlock\` |
2007
-
2008
- Lowercase HTML tags inside \`RichText\`/markdown prose (\`<div>\`, \`<span>\`,
2009
- \`<code>\`, \`<br>\`, …) are always fine only capitalized component-style tags at
2010
- the block level are validated.
2011
-
2012
- ### \`Endpoint\` (API / route)
2013
-
2014
- Tag is \`Endpoint\` — NOT \`ApiEndpoint\`. Required attrs: \`method\`, \`path\`. Optional
2015
- attrs: \`summary\` (the short title — NOT \`title\`), \`auth\`, \`deprecated\` (bool),
2016
- \`change\`, \`params\`, \`request\`, \`responses\`. The prose \`description\` is the MDX
2017
- **children** (body between the tags), NOT an attribute.
2018
-
2019
- - \`method\` ∈ \`GET | POST | PUT | PATCH | DELETE | HEAD | OPTIONS\`. For a
2020
- WebSocket upgrade use \`GET\`.
2021
- - \`change\` (and per-param/per-response \`change\`) ∈ \`added | modified | removed | renamed\`.
2022
- - \`params={[{ name, in, type?, required?, description?, change?, was? }]}\` where
2023
- \`in\` ∈ \`path | query | header | body\`.
2024
- - \`request={{ contentType?, example? }}\` — \`example\` is a JSON **string**, not a
2025
- nested object.
2026
- - \`responses={[{ status, description?, example?, change? }]}\` — each \`example\` is
2027
- a JSON **string** (the renderer parses it into the collapsible JsonExplorer).
2028
- Give each distinct message shape (e.g. success vs error, or separate WS frame
2029
- types) its OWN response entry, not one merged body.
2030
-
2031
- \`\`\`mdx
2032
- <Endpoint
2033
- id="ep-create-task"
2034
- method="POST"
2035
- path="/api/tasks"
2036
- summary="Create a task"
2037
- request={{ contentType: "application/json", example: '{"title":"Ship recap"}' }}
2038
- responses={[{ status: "201", description: "Created", example: '{"id":"t_1","title":"Ship recap"}' }]}
2039
- >
2040
-
2041
- Creates a task scoped to the caller's org.
2042
-
2043
- </Endpoint>
2044
- \`\`\`
2045
-
2046
- ### \`DataModel\` (schema / ER)
2047
-
2048
- Tag is \`DataModel\`. Required attr: \`entities\` (>= 1). Optional attr: \`relations\`.
2049
- There is NO top-level \`fields=\` attribute — fields live inside each entity. There
2050
- is NO per-field \`required\` or \`description\` key; fold either into \`note\`.
2051
-
2052
- - \`entities={[{ id, name, note?, change?, fields: [...] }]}\` — \`id\` is referenced
2053
- by relations.
2054
- - each field: \`{ name, type?, pk?, fk?, nullable?, default?, note?, change?, was? }\`.
2055
- \`pk\`/\`nullable\` are booleans; \`fk\` is a string target like \`"User.id"\`;
2056
- \`change\` ∈ \`added | modified | removed | renamed\`; \`was\` is the prior value
2057
- when \`change\` is \`modified\`.
2058
- - \`relations={[{ from, to, kind?, label? }]}\` (optional — the renderer infers
2059
- simple \`1-n\` from \`fk\` when omitted); \`kind\` ∈ \`1-1 | 1-n | n-n\`.
2060
-
2061
- \`\`\`mdx
2062
- <DataModel
2063
- id="dm-tasks"
2064
- entities={[
2065
- {
2066
- id: "task",
2067
- name: "Task",
2068
- fields: [
2069
- { name: "id", type: "uuid", pk: true },
2070
- { name: "title", type: "text" },
2071
- { name: "status", type: "text", change: "added", note: "open|done" }
2072
- ]
2073
- }
2074
- ]}
2075
- />
2076
- \`\`\`
2077
-
2078
- ### \`FileTree\` (changed files)
2079
-
2080
- Tag is \`FileTree\`. Required attr: \`entries\` (>= 1). Optional attr: \`title\`. The
2081
- tree is built from the leaf \`path\`s — do NOT pass an ASCII tree in children; the
2082
- block is self-closing.
2083
-
2084
- - \`entries={[{ path, change?, note?, snippet?, language? }]}\` — \`path\` is
2085
- slash-delimited; \`change\` ∈ \`added | modified | removed | renamed\`. Add a
2086
- \`snippet\` (with optional \`language\`) only when it says something the path does
2087
- not.
2088
-
2089
- \`\`\`mdx
2090
- <FileTree
2091
- id="ft-changed"
2092
- title="Files touched"
2093
- entries={[
2094
- { path: "server/routes/tasks.ts", change: "modified", note: "add POST handler" },
2095
- { path: "server/db/schema.ts", change: "modified" },
2096
- { path: "tests/tasks.test.ts", change: "added" }
2097
- ]}
2098
- />
2099
- \`\`\`
2100
-
2101
- ### \`Mermaid\` (graph)
2102
-
2103
- Tag is \`Mermaid\` — this is its OWN block, separate from \`Diagram\`. Required attr:
2104
- \`source\` (the diagram text). Optional attr: \`caption\`. Do NOT put mermaid text
2105
- inside a \`Diagram\` block, and do NOT use \`<Diagram mermaid={...}>\` — that is not a
2106
- real prop and will not render.
2107
-
2108
- \`\`\`mdx
2109
- <Mermaid
2110
- id="mm-flow"
2111
- source={\`flowchart LR
2112
- Client --> API
2113
- API --> DB\`}
2114
- caption="Request path"
2115
- />
2116
- \`\`\`
2117
-
2118
- ### \`Diagram\` (HTML/SVG or node graph)
2119
-
2120
- Tag is \`Diagram\`. The whole payload is ONE \`data\` attribute:
2121
- \`data={{ html?, css?, caption?, nodes?, edges?, notes? }}\`. It requires either
2122
- \`html\` (an inert HTML/SVG fragment) OR at least one node — a \`Diagram\` with
2123
- neither fails validation. This is for architecture / data-flow / dependency
2124
- relationships, NOT rendered UI (use a wireframe for UI) and NOT mermaid (use
2125
- \`Mermaid\`). Use \`.diagram-*\` primitives + \`--wf-*\` tokens in \`html\`/\`css\`; never
2126
- hex colors or \`font-family\`.
2127
-
2128
- \`\`\`mdx
2129
- <Diagram
2130
- id="dg-arch"
2131
- data={{
2132
- nodes: [
2133
- { id: "ui", label: "UI" },
2134
- { id: "api", label: "API" },
2135
- { id: "db", label: "DB" }
2136
- ],
2137
- edges: [
2138
- { from: "ui", to: "api" },
2139
- { from: "api", to: "db" }
2140
- ]
2141
- }}
2142
- />
2143
- \`\`\`
2144
-
2145
- ### \`Json\` (JSON explorer)
2146
-
2147
- Tag is \`Json\`. Required attr: \`json\` — a **string** containing the JSON.
2148
- Optional attrs: \`title\`, \`collapsedDepth\` (number, default 2).
2149
-
2150
- \`\`\`mdx
2151
- <Json
2152
- id="json-config"
2153
- title="Resolved config"
2154
- json={'{"flags":{"recap":true},"limit":50}'}
2155
- />
2156
- \`\`\`
2157
-
2158
- ### \`Diff\` (before/after)
2159
-
2160
- Tag is \`Diff\`. Required attrs: \`before\`, \`after\` (multiline source strings).
2161
- Optional attrs: \`filename\`, \`language\`, \`mode\` (\`unified | split\`), \`annotations\`.
2162
- Leave \`mode\` unset: it defaults to **unified**, which reads cleanly at any width
2163
- and is what recap diffs want — they almost always live inside a width-constrained
2164
- container (a vertical-tabs panel or a comparison column) where split's two
2165
- line-number gutters cut the code off. Only set \`mode: "split"\` for a standalone,
2166
- full-document-width diff where side-by-side genuinely helps. The reader always
2167
- exposes a Unified/Split toggle (when there is room), so a viewer can switch
2168
- either way regardless of the authored default. Give every diff a \`summary\` (the
2169
- shared envelope attr) so the reviewer reads intent first.
2170
-
2171
- - \`annotations={[{ side?, lines, label?, note }]}\` — \`side\` ∈ \`before | after\`
2172
- (default \`after\`); \`lines\` is a 1-based ref like \`"13"\` or \`"13-15"\`.
2173
-
2174
- \`\`\`mdx
2175
- <Diff
2176
- id="diff-handler"
2177
- filename="server/routes/tasks.ts"
2178
- language="ts"
2179
- summary="Add the POST /api/tasks handler"
2180
- before={\`router.get("/api/tasks", list);\`}
2181
- after={\`router.get("/api/tasks", list);\\nrouter.post("/api/tasks", create);\`}
2182
- annotations={[{ side: "after", lines: "2", label: "New route", note: "Creates a task" }]}
2183
- />
2184
- \`\`\`
2185
-
2186
- ### \`AnnotatedCode\` (new-file walkthrough)
2187
-
2188
- Tag is \`AnnotatedCode\`. Required attr: \`code\` (multiline string). Optional attrs:
2189
- \`filename\`, \`language\`, \`annotations\`. Use this for a brand-new file with no
2190
- meaningful "before".
2191
-
2192
- - \`annotations={[{ lines, label?, note }]}\` — 1-based \`lines\` ref (no \`side\`,
2193
- unlike \`Diff\`).
2194
-
2195
- \`\`\`mdx
2196
- <AnnotatedCode
2197
- id="ac-create"
2198
- filename="server/tasks/create.ts"
2199
- language="ts"
2200
- code={\`export async function create(input: NewTask) {\\n return db.tasks.insert(input);\\n}\`}
2201
- annotations={[{ lines: "1-3", label: "Handler", note: "Inserts and returns the row" }]}
2202
- />
2203
- \`\`\`
2204
-
2205
- ### \`RichText\` (prose)
2206
-
2207
- Tag is \`RichText\`. The markdown is the MDX **children** (body between the tags),
2208
- NOT an attribute. Use \`## Key changes\` here as the heading above a grouped diff
2209
- \`TabsBlock\`.
2210
-
2211
- \`\`\`mdx
2212
- <RichText id="rt-why">
2213
-
2214
- ## Why
2215
-
2216
- Adds a create endpoint so the agent can author tasks directly.
2217
-
2218
- </RichText>
2219
- \`\`\`
2220
-
2221
- ### \`Callout\` (tone note)
2222
-
2223
- Tag is \`Callout\`. Optional attr: \`tone\` ∈ \`info | decision | risk | warning | success\`.
2224
- The body markdown is the MDX **children**, NOT an attribute.
2225
-
2226
- \`\`\`mdx
2227
- <Callout id="co-risk" tone="risk">
2228
-
2229
- The new column is non-nullable with no default — existing rows need a backfill.
2230
-
2231
- </Callout>
2232
- \`\`\`
2233
-
2234
- ### \`Columns\` (side-by-side)
2235
-
2236
- Tag is \`Columns\`; each column is a nested \`<Column label="...">\` whose body is
2237
- markdown and/or block components. 1–4 columns. Use labels \`Before\` / \`After\` for
2238
- structured comparisons.
2239
-
2240
- \`\`\`mdx
2241
- <Columns id="cols-schema">
2242
- <Column label="Before">
2243
-
2244
- \`status\` did not exist.
2245
-
2246
- </Column>
2247
- <Column label="After">
2248
-
2249
- <DataModel id="dm-after" entities={[{ id: "task", name: "Task", fields: [{ name: "status", type: "text", change: "added" }] }]} />
2250
-
2251
- </Column>
2252
- </Columns>
2253
- \`\`\`
2254
-
2255
- ### \`TabsBlock\` (tab rail)
2256
-
2257
- Tag is \`TabsBlock\` — NOT \`Tabs\`, and there is NO nested \`<Tab>\` element. Required
2258
- attr: \`tabs\` (1–12). Optional attr: \`orientation\` (\`horizontal | vertical\`; use
2259
- \`vertical\` for a file rail). The whole \`tabs\` array (including nested child
2260
- blocks) is ONE JSON prop; do NOT nest the tabs or their child blocks as MDX
2261
- elements. Label the section with a preceding \`## Key changes\` \`RichText\` heading
2262
- rather than a \`title\` on the block.
2263
-
2264
- \`\`\`mdx
2265
- <TabsBlock
2266
- id="tabs-key"
2267
- orientation="vertical"
2268
- tabs={[
2269
- { id: "t-route", label: "routes/tasks.ts", blocks: [ /* Diff block objects */ ] },
2270
- { id: "t-schema", label: "db/schema.ts", blocks: [ /* Diff block objects */ ] }
2271
- ]}
2272
- />
2273
- \`\`\`
2274
-
2275
- ### \`WireframeBlock\` + \`<Screen>\` (UI)
2276
-
2277
- Tag is \`WireframeBlock\`; its body is a single \`<Screen surface ... >\` subtree
2278
- (this is nested MDX, not a flat prop). On \`<Screen>\`, \`html\` must be a
2279
- single-quoted string or a static template literal — NEVER a dynamic expression
2280
- (\`html={someVar}\` throws on import). \`surface\` ∈
2281
- \`desktop | mobile | popover | panel | browser\`. Optional \`<Screen>\` attrs:
2282
- \`renderMode\` (\`wireframe | design\`), \`caption\`, \`css\`, \`skeleton\`. See the
2283
- Wireframe Quality core above for the HTML rules.
2284
-
2285
- \`\`\`mdx
2286
- <WireframeBlock id="wf-tasks">
2287
- <Screen surface="browser" html={'<div style="display:flex;flex-direction:column;gap:12px;padding:16px;height:100%"><h1>Tasks</h1><button class="primary">New task</button></div>'} />
2288
- </WireframeBlock>
2289
- \`\`\`
2290
-
2291
- ### Other blocks
2292
-
2293
- - \`HtmlBlock\` (custom-html) — flat attrs \`html\` (required, bounded fragment),
2294
- \`css?\`, \`caption?\`. Prefer a wireframe for UI; this is an escape hatch.
2295
- - \`Table\` — flat attrs \`columns={["A","B"]}\` and \`rows={[["1","2"]]}\` (both arrays
2296
- of strings), optional \`density\` (\`compact | normal | relaxed\`).
2297
- - \`Checklist\` — flat attr \`items={[{ id, label, checked?, note? }]}\`.
2298
- - \`Code\` — flat attrs \`code\` (required string), \`language?\`, \`filename?\`,
2299
- \`caption?\`, \`maxLines?\`. For a multi-file rail use a \`TabsBlock\` of \`Code\`
2300
- blocks.
2301
- - \`OpenApi\` — flat attrs \`spec\` (required JSON string of a whole OpenAPI/Swagger
2302
- doc), \`title?\`. The whole-document counterpart to \`Endpoint\`.
1505
+ ## Block reference — call \`get-plan-blocks\`, do not memorize tags
1506
+
1507
+ The conceptual block names above (\`api-endpoint\`, \`data-model\`, \`json-explorer\`,
1508
+ \`tabs\`, …) are NOT the JSX tags you author with, and the exact tags, required
1509
+ fields, and prop shapes change as the block library evolves. Do not author from
1510
+ memorized tags they drift and silently produce a wrong tag (\`ApiEndpoint\`
1511
+ instead of \`Endpoint\`, \`JsonExplorer\` instead of \`Json\`, \`Tabs\` instead of
1512
+ \`TabsBlock\`) that errors on import.
1513
+
1514
+ **Before writing any structured plan content, call \`get-plan-blocks\` on the Plan
1515
+ MCP connector (\`plan\` or legacy \`agent-native-plans\`).** It returns the
1516
+ authoritative, always-current block
1517
+ vocabulary generated live from the app's own block registry the same config
1518
+ the renderer and MDX round-trip use — so it can never be stale even if this
1519
+ SKILL.md is an old installed copy:
1520
+
1521
+ - \`get-plan-blocks\` (default \`format: "reference"\`) a compact table of every
1522
+ block's runtime \`type\`, exact MDX \`<Tag>\`, placement, and key data fields.
1523
+ This is your map from each conceptual name above to its real tag and props.
1524
+ - \`get-plan-blocks\` with \`format: "schema"\` → the full per-block JSON Schema
1525
+ plus a worked example for each block, when you need exact field types,
1526
+ enums, or nesting (e.g. \`Diff.annotations\`, \`Endpoint.params[].in\`,
1527
+ \`DataModel.entities[].fields[]\`).
1528
+
1529
+ Author the recap source against the tags and schemas that call returns. The
1530
+ complete set of valid block-level tags is whatever \`get-plan-blocks\` lists;
1531
+ any other capitalized tag at the block level is rejected on import with an
1532
+ "Unknown plan block" / "did you mean" error. Lowercase HTML tags inside
1533
+ \`rich-text\`/markdown prose (\`<div>\`, \`<span>\`, \`<code>\`, \`<br>\`, …) are always
1534
+ fine only capitalized component-style block tags are validated.
1535
+
1536
+ A few recap-specific authoring rules the registry table cannot encode:
1537
+
1538
+ - Every block takes a REQUIRED \`id\` (unique across the whole plan) plus the
1539
+ shared optional \`summary\` / \`editable\` envelope; give a block a heading by
1540
+ placing a \`rich-text\` block with a Markdown \`###\` heading directly above it
1541
+ (blocks no longer take a \`title\`).
1542
+ - \`Endpoint\`: prose \`description\` is the MDX **children** (body between the
1543
+ tags), not an attribute; for a WebSocket upgrade use \`method="GET"\`. Each
1544
+ request/response \`example\` is a JSON **string** (the renderer parses it into
1545
+ the JSON explorer), so keep it a single parseable JSON value.
1546
+ - \`TabsBlock\`: the whole \`tabs\` array (including nested child blocks) is ONE
1547
+ JSON \`tabs={[…]}\` prop — there is NO nested \`<Tab>\` element.
1548
+ - \`WireframeBlock\`: its body is a single \`<Screen surface ... html=… />\` subtree
1549
+ (nested MDX, not a flat prop); \`html\` must be a single-quoted string or static
1550
+ template literal, never a dynamic \`html={someVar}\` expression. See the
1551
+ Wireframe Quality core above for the HTML rules.
1552
+ - \`Diagram\`: the whole payload is one \`data={{ html?, css?, nodes?, edges?, … }}\`
1553
+ attribute and requires either \`html\` or at least one node; \`Mermaid\` is its
1554
+ own separate block (\`source\` text), not a \`Diagram\` prop.
2303
1555
 
2304
1556
  ## Before / After Is The Headline
2305
1557
 
@@ -2313,16 +1565,19 @@ comparisons there are two primitives, and they cover the whole need together:
2313
1565
  "the schema went from X to Y" or "the endpoint contract changed like this."
2314
1566
  Do not use \`columns\` simply to compact or group a list of API endpoints.
2315
1567
  - **\`diff\`** — for **code**. It renders the literal removed and added lines. Use
2316
- it for the actual hunks. Leave \`mode\` unset so it renders unified (the default,
2317
- legible at any width); reserve \`mode: "split"\` for a standalone full-width diff
2318
- where side-by-side genuinely helps never inside a tabs panel or column, where
2319
- split's doubled gutters cut the code off.
1568
+ it for the actual hunks. Use split mode by default for recap code review;
1569
+ reserve \`mode: "unified"\` for genuinely narrow standalone hunks where
1570
+ side-by-side would hide the code. Key-file diff groups should use horizontal
1571
+ tabs so split diffs get the full document width.
2320
1572
 
2321
1573
  For UI diffs, wireframes are the visual comparison primitive. Use before/after
2322
1574
  wireframes when the comparison clarifies the change; use after-only or a state
2323
1575
  sequence when that better matches the change. The visual headline must show
2324
1576
  exact placement, realistic chrome, and adequate padding before any abstract
2325
- explanation. The Wireframe Quality core owns the before/after layout choice —
1577
+ explanation. Do not stop at the first visible affordance when the diff adds a
1578
+ flow; show the entry point, the opened surface, and the resulting state or page
1579
+ so the reviewer can trace the actual user path. The Wireframe Quality core owns
1580
+ the before/after layout choice —
2326
1581
  the \`columns\` renderer keeps narrow surfaces side by side and auto-stacks wide
2327
1582
  \`desktop\`/\`browser\` frames vertically; never hand-build a side-by-side
2328
1583
  wireframe layout in \`custom-html\`. For document-body
@@ -2356,15 +1611,19 @@ inferred (not extracted) as inferred in prose.
2356
1611
  hardcoded-secret rule: obviously fake placeholders only, never the real value,
2357
1612
  in any block, caption, or note.
2358
1613
 
2359
- ## Bidirectional Loop (Fast-Follow)
1614
+ ## Bidirectional Loop
2360
1615
 
2361
1616
  Because a recap is a real, editable plan, the same review loop as forward plans
2362
1617
  applies: a reviewer can annotate any block, and the coding agent reads
2363
1618
  \`get-plan-feedback\` to drive fixes back into the code — annotation → agent →
2364
- diff, the same close-the-loop flow forward plans use. In v1, recaps are
2365
- **read-only**: they summarize a merged or proposed change for review, and the
2366
- annotate-to-fix loop is a fast-follow, not yet wired. Build the recap so the
2367
- blocks are anchorable and the loop drops in later without restructuring.
1619
+ diff, the same close-the-loop flow forward plans use. After a reviewer annotates
1620
+ a block, call \`get-plan-feedback\` to read the structured feedback, then either
1621
+ update the recap with \`create-visual-recap\` (passing the existing \`planId\` to
1622
+ replace it in place) or apply targeted changes with \`update-visual-plan\`. The
1623
+ loop is live and wired. The one thing not yet automatic is PR-comment-triggered
1624
+ re-runs: the GitHub Action creates an initial recap per PR, but it does not yet
1625
+ re-run automatically when new review feedback is posted in GitHub — that
1626
+ auto-re-run is the remaining fast-follow.
2368
1627
 
2369
1628
  ## Related Skills
2370
1629
 
@@ -2375,143 +1634,6 @@ blocks are anchorable and the loop drops in later without restructuring.
2375
1634
  recap's redaction and visibility gating mirror.
2376
1635
  - **sharing** — org/login-gated visibility for the plan that holds the recap.
2377
1636
  `;
2378
- export const VISUAL_QUESTIONS_SKILL_MD = `---
2379
- name: visual-questions
2380
- description: >-
2381
- Use Agent-Native Plans to ask rich visual intake questions when
2382
- /visual-questions is explicitly requested before creating a UI plan or visual
2383
- plan.
2384
- metadata:
2385
- visibility: both
2386
- ---
2387
-
2388
- # Visual Questions
2389
-
2390
- Use \`/visual-questions\` when the next best step is not a plan yet, but a
2391
- reviewable visual intake: single-choice option rows, multi-select option rows,
2392
- freeform notes, mockup choices, sketch diagrams, and a generated answer summary
2393
- that feeds the next planning prompt. It composes with \`/visual-plan\`, \`/ui-plan\`,
2394
- \`/prototype-plan\`, and \`/plan-design\`.
2395
-
2396
- ## When To Use
2397
-
2398
- - The user asks to be shown options before the agent writes a plan.
2399
- - UI direction, form factor, layout model, feature set, or visual style is fuzzy
2400
- enough that 2-6 answers would materially change the plan.
2401
- - The user would benefit from choosing between visual mockups or diagrams rather
2402
- than answering text-only prompts.
2403
-
2404
- Gate hard: skip this for tiny, unambiguous changes. If the agent can reasonably
2405
- infer the answer, prefer \`/ui-plan\`, \`/prototype-plan\`, \`/plan-design\`, or
2406
- \`/visual-plan\` directly and put assumptions in the plan.
2407
-
2408
- Visual questions are an explicit intake command, not an automatic preflight for
2409
- \`/visual-plan\`, \`/ui-plan\`, \`/prototype-plan\`, or \`/plan-design\`.
2410
-
2411
- ## Workflow
2412
-
2413
- 1. Call \`create-visual-questions\` with a clear title, brief, source, and repo
2414
- path when known.
2415
- 2. Omit \`questions\` for the default UI intake. Provide a custom \`questions\` array
2416
- only when the task has domain-specific choices.
2417
- 3. Surface the returned Plans link and ask the user to answer visually.
2418
- 4. The generated summary drives the next step: \`create-ui-plan\` for static UI
2419
- review, \`create-prototype-plan\` for click-through UI flows,
2420
- \`create-plan-design\` for high-fidelity branded UI review,
2421
- \`create-visual-plan\` for general plans or when a text plan already exists,
2422
- or \`update-visual-plan\` with targeted \`contentPatches\` to fold answers into
2423
- an active plan.
2424
- 5. If the user leaves comments, call \`get-plan-feedback\` before using the answers.
2425
-
2426
- ## Question Types
2427
-
2428
- Supported \`questions\` entries:
2429
-
2430
- - \`single\`: chip group where one option wins.
2431
- - \`multi\`: chip group where multiple options can be selected.
2432
- - \`freeform\`: textarea for constraints, inspirations, or things to avoid.
2433
- - \`visual\`: visual options with sketch previews — use for layout direction, flow
2434
- depth, surface choice, or diagram choices.
2435
-
2436
- Each option can include \`label\`, \`value\`, \`description\`, \`recommended\`,
2437
- \`preview\`, and \`bullets\`. Valid \`preview\` values match the wireframe surfaces:
2438
- \`desktop\`, \`mobile\`, \`popover\`, \`panel\`, \`component\`, \`split\`, \`flow\`, and
2439
- \`diagram\`. Pick the preview that matches the real footprint — do not offer a
2440
- desktop/mobile pair for a popover, panel, or component.
2441
-
2442
- \`single\`, \`multi\`, and \`visual\` questions always render a write-in field, so a
2443
- reviewer can answer with their own option instead of the listed choices. Do not
2444
- add an explicit "Other" or "Something else" option yourself; set
2445
- \`allowOther: false\` only on the rare question where a free-text answer makes no
2446
- sense.
2447
-
2448
- ## Quality Bar
2449
-
2450
- - Ask only decision-changing questions. A beautiful form with low-value questions
2451
- is still friction.
2452
- - Prefer visible, answerable options over abstract prose.
2453
- - Use visual tabs when users need to compare layout or flow shapes.
2454
- - Keep the output calm and document-like, not a landing page.
2455
- - The generated answer summary is not the final plan; it is the intake prompt for
2456
- the next agent step.
2457
-
2458
- ## Tool Guidance
2459
-
2460
- - \`create-visual-questions\`: create the interactive intake plan.
2461
- - \`get-visual-plan\`: inspect the current visual question plan.
2462
- - \`get-plan-feedback\`: read comments before creating or updating the next plan.
2463
- - \`create-ui-plan\`: create a UI-first plan from the answers.
2464
- - \`create-prototype-plan\`: create a prototype-first plan from the answers when
2465
- interaction feel matters.
2466
- - \`create-plan-design\`: create a high-fidelity branded design plan from the
2467
- answers when visual polish is the primary review input.
2468
- - \`create-visual-plan\`: create a general visual plan from the answers, or pass
2469
- existing plan text as \`planText\` when the answers should shape an imported
2470
- plan.
2471
- - \`export-visual-plan\`: export answer plans as HTML, Markdown fallback,
2472
- structured JSON, and MDX files when the intake needs to be checked into a repo.
2473
- - \`read-visual-plan-source\` / \`patch-visual-plan-source\`: inspect or patch the
2474
- MDX source if another agent is operating from checked-in plan files.
2475
-
2476
- ## Setup & Authentication
2477
-
2478
- There are two ways into Plans.
2479
-
2480
- **Coding agent (CLI).** Install once with the Agent-Native CLI. The command
2481
- installs the Plans skills, registers the hosted Plans MCP connector, and
2482
- authenticates it in the same step (a one-time browser sign-in at setup — this is
2483
- intended), so the first tool call does not hit an OAuth wall:
2484
-
2485
- \`\`\`bash
2486
- agent-native skills add visual-plan
2487
- \`\`\`
2488
-
2489
- After that, \`/visual-plan\` (and \`/visual-recap\`, \`/ui-plan\`,
2490
- \`/prototype-plan\`, \`/plan-design\`, \`/visual-questions\`) generate a plan and open
2491
- the editor. Pass \`--no-connect\` to
2492
- register the connector without authenticating, then run
2493
- \`agent-native connect https://plan.agent-native.com\` whenever you are ready.
2494
-
2495
- **Browser (people you share with).** Open the Plans editor and create & edit
2496
- with no sign-up — you work as a guest. Sign in only when you want to save or
2497
- share; signing in claims the plans you made as a guest into your account.
2498
-
2499
- Sharing and commenting require an account: public/shared plans are viewable by
2500
- anyone with the link, but commenting on them needs an agent-native account.
2501
-
2502
- For fully offline, no-account use, run the Plans app locally and sync plans to
2503
- your repo as MDX. This local mode is a separate advanced path, not the default
2504
- hosted flow.
2505
-
2506
- If a Plans tool returns \`needs auth\`, \`Unauthorized\`, or \`Session terminated\`,
2507
- do not keep retrying the tool. Authenticate the connector with
2508
- \`agent-native connect https://plan.agent-native.com\` (OAuth-capable hosts can
2509
- instead re-run /mcp and choose Authenticate), then continue once the connector
2510
- is available.
2511
-
2512
- Hosted default: connect \`https://plan.agent-native.com/_agent-native/mcp\`. Do
2513
- not put shared secrets in skill files.
2514
- `;
2515
1637
  export const BUILT_IN_APP_SKILLS = {
2516
1638
  assets: {
2517
1639
  skillName: "assets",
@@ -2603,10 +1725,19 @@ export const BUILT_IN_APP_SKILLS = {
2603
1725
  skillName: "visual-plan",
2604
1726
  extraSkills: {
2605
1727
  "visual-recap": VISUAL_RECAP_SKILL_MD,
2606
- "visual-questions": VISUAL_QUESTIONS_SKILL_MD,
2607
- "ui-plan": UI_PLAN_SKILL_MD,
2608
- "prototype-plan": PROTOTYPE_PLAN_SKILL_MD,
2609
- "plan-design": PLAN_DESIGN_SKILL_MD,
1728
+ },
1729
+ // Sibling reference files materialized alongside each skill's SKILL.md
1730
+ // (progressive disclosure). Keyed by skill name -> relative path -> content.
1731
+ // Both plan skills ship the same canonical wireframe-quality reference; the
1732
+ // canvas / document-quality / exemplar references are visual-plan only.
1733
+ extraFiles: {
1734
+ "visual-plan": {
1735
+ "references/wireframe.md": WIREFRAME_REFERENCE_MD,
1736
+ "references/canvas.md": CANVAS_REFERENCE_MD,
1737
+ "references/document-quality.md": DOCUMENT_QUALITY_REFERENCE_MD,
1738
+ "references/exemplar.md": EXEMPLAR_REFERENCE_MD,
1739
+ },
1740
+ "visual-recap": { "references/wireframe.md": WIREFRAME_REFERENCE_MD },
2610
1741
  },
2611
1742
  manifest: normalizeAppSkillManifest({
2612
1743
  schemaVersion: 1,
@@ -2617,10 +1748,10 @@ export const BUILT_IN_APP_SKILLS = {
2617
1748
  url: "https://plan.agent-native.com",
2618
1749
  mcpUrl: "https://plan.agent-native.com/_agent-native/mcp",
2619
1750
  },
2620
- mcp: { serverName: "agent-native-plans" },
1751
+ mcp: { serverName: "plan", aliases: ["agent-native-plans"] },
2621
1752
  auth: {
2622
1753
  mode: "oauth",
2623
- setup: "Install with the Agent-Native CLI to add the /visual-plan, /visual-recap, /ui-plan, /prototype-plan, /plan-design, and /visual-questions skills plus the Plan MCP connector. Authenticate only for hosted/account-backed sharing.",
1754
+ setup: "Install with the Agent-Native CLI to add the /visual-plan and /visual-recap skills plus the Plan MCP connector. Authenticate only for hosted/account-backed sharing.",
2624
1755
  },
2625
1756
  surfaces: [
2626
1757
  {
@@ -2635,30 +1766,6 @@ export const BUILT_IN_APP_SKILLS = {
2635
1766
  path: "/plans",
2636
1767
  description: "Create a visual recap plan from a PR, commit, branch, or git diff for high-altitude review.",
2637
1768
  },
2638
- {
2639
- id: "ui-plan",
2640
- action: "create-ui-plan",
2641
- path: "/plans",
2642
- description: "Create a UI-first Agent-Native plan with an optional top pan/zoom wireframe canvas and a refined rich document below.",
2643
- },
2644
- {
2645
- id: "prototype-plan",
2646
- action: "create-prototype-plan",
2647
- path: "/plans",
2648
- description: "Create a prototype-first Agent-Native plan with a functional live prototype above the document.",
2649
- },
2650
- {
2651
- id: "plan-design",
2652
- action: "create-plan-design",
2653
- path: "/plans",
2654
- description: "Create a full-fidelity Agent-Native design plan with a Design canvas tab and optional matching Prototype tab.",
2655
- },
2656
- {
2657
- id: "visual-questions",
2658
- action: "create-visual-questions",
2659
- path: "/plans",
2660
- description: "Create a rich visual intake questionnaire for explicit /visual-questions workflows.",
2661
- },
2662
1769
  ],
2663
1770
  skills: [
2664
1771
  {
@@ -2671,26 +1778,6 @@ export const BUILT_IN_APP_SKILLS = {
2671
1778
  visibility: "exported",
2672
1779
  exportAs: "visual-recap",
2673
1780
  },
2674
- {
2675
- path: "skills/visual-questions",
2676
- visibility: "exported",
2677
- exportAs: "visual-questions",
2678
- },
2679
- {
2680
- path: "skills/ui-plan",
2681
- visibility: "exported",
2682
- exportAs: "ui-plan",
2683
- },
2684
- {
2685
- path: "skills/prototype-plan",
2686
- visibility: "exported",
2687
- exportAs: "prototype-plan",
2688
- },
2689
- {
2690
- path: "skills/plan-design",
2691
- visibility: "exported",
2692
- exportAs: "plan-design",
2693
- },
2694
1781
  ],
2695
1782
  hostAdapters: [
2696
1783
  "codex-plugin",
@@ -2736,6 +1823,7 @@ export const BUILT_IN_APP_SKILLS = {
2736
1823
  skillMarkdown: CONTEXT_XRAY_SKILL_MD,
2737
1824
  },
2738
1825
  };
1826
+ export const AGENT_NATIVE_SKILL_METADATA_FILE = "agent-native-skill.json";
2739
1827
  const BUILT_IN_APP_SKILL_ALIASES = {
2740
1828
  assets: "assets",
2741
1829
  asset: "assets",
@@ -2758,13 +1846,6 @@ const BUILT_IN_APP_SKILL_ALIASES = {
2758
1846
  "visual-recaps": "visual-plans",
2759
1847
  "code-review-recap": "visual-plans",
2760
1848
  "code-review-recaps": "visual-plans",
2761
- "ui-plan": "visual-plans",
2762
- "prototype-plan": "visual-plans",
2763
- "plan-design": "visual-plans",
2764
- "plan-designs": "visual-plans",
2765
- "design-plan": "visual-plans",
2766
- "design-plans": "visual-plans",
2767
- "visual-questions": "visual-plans",
2768
1849
  "html-plan": "visual-plans",
2769
1850
  "plan-mode": "visual-plans",
2770
1851
  plannotate: "visual-plans",
@@ -2788,10 +1869,6 @@ const BUILT_IN_APP_SKILL_DISPLAY_ALIASES = {
2788
1869
  "visual-plan",
2789
1870
  "visual-recap",
2790
1871
  "code-review-recap",
2791
- "ui-plan",
2792
- "prototype-plan",
2793
- "plan-design",
2794
- "visual-questions",
2795
1872
  "html-plan",
2796
1873
  "plannotate",
2797
1874
  ],
@@ -2824,9 +1901,243 @@ function isLocalOnlyBuiltInSkill(entry) {
2824
1901
  function builtInExtraSkills(entry) {
2825
1902
  return "extraSkills" in entry && entry.extraSkills ? entry.extraSkills : {};
2826
1903
  }
1904
+ /**
1905
+ * Sibling reference files for a skill (skill name -> relative path -> content),
1906
+ * materialized alongside its SKILL.md for progressive disclosure.
1907
+ */
1908
+ function builtInExtraFiles(entry) {
1909
+ return "extraFiles" in entry && entry.extraFiles ? entry.extraFiles : {};
1910
+ }
2827
1911
  function builtInSkillNames(entry) {
2828
1912
  return [entry.skillName, ...Object.keys(builtInExtraSkills(entry))];
2829
1913
  }
1914
+ function stableSkillHash(files) {
1915
+ const hash = createHash("sha256");
1916
+ for (const rel of Object.keys(files).sort()) {
1917
+ if (rel === AGENT_NATIVE_SKILL_METADATA_FILE)
1918
+ continue;
1919
+ hash.update(rel);
1920
+ hash.update("\0");
1921
+ hash.update(files[rel]);
1922
+ hash.update("\0");
1923
+ }
1924
+ return hash.digest("hex").slice(0, 16);
1925
+ }
1926
+ function skillFilesForBuiltIn(appSkillId) {
1927
+ const entry = BUILT_IN_APP_SKILLS[appSkillId];
1928
+ const skills = {
1929
+ [entry.skillName]: entry.skillMarkdown,
1930
+ ...builtInExtraSkills(entry),
1931
+ };
1932
+ const extraFiles = builtInExtraFiles(entry);
1933
+ const out = {};
1934
+ for (const [skillName, skillMarkdown] of Object.entries(skills)) {
1935
+ const files = {
1936
+ "SKILL.md": skillMarkdown,
1937
+ ...(extraFiles[skillName] ?? {}),
1938
+ };
1939
+ out[skillName] = {
1940
+ appSkillId,
1941
+ displayName: entry.manifest.displayName,
1942
+ skillName,
1943
+ mcpUrl: isLocalOnlyBuiltInSkill(entry)
1944
+ ? ""
1945
+ : entry.manifest.hosted.mcpUrl,
1946
+ files,
1947
+ contentHash: stableSkillHash(files),
1948
+ };
1949
+ }
1950
+ return out;
1951
+ }
1952
+ function latestSkillBundlesForTargets(appSkillIds) {
1953
+ const out = {};
1954
+ for (const appSkillId of appSkillIds) {
1955
+ Object.assign(out, skillFilesForBuiltIn(appSkillId));
1956
+ }
1957
+ return out;
1958
+ }
1959
+ function writeSkillFolder(dir, bundle, installedAt = new Date().toISOString()) {
1960
+ fs.rmSync(dir, { recursive: true, force: true });
1961
+ fs.mkdirSync(dir, { recursive: true });
1962
+ for (const [rel, content] of Object.entries(bundle.files)) {
1963
+ const target = path.join(dir, rel);
1964
+ fs.mkdirSync(path.dirname(target), { recursive: true });
1965
+ fs.writeFileSync(target, content, "utf-8");
1966
+ }
1967
+ const metadata = {
1968
+ schemaVersion: 1,
1969
+ source: "agent-native",
1970
+ appSkillId: bundle.appSkillId,
1971
+ displayName: bundle.displayName,
1972
+ skillName: bundle.skillName,
1973
+ contentHash: bundle.contentHash,
1974
+ mcpUrl: bundle.mcpUrl,
1975
+ installedAt,
1976
+ updateCommand: `agent-native skills update ${bundle.skillName}`,
1977
+ };
1978
+ fs.writeFileSync(path.join(dir, AGENT_NATIVE_SKILL_METADATA_FILE), `${JSON.stringify(metadata, null, 2)}\n`, "utf-8");
1979
+ }
1980
+ function listSkillFolderFiles(dir) {
1981
+ const out = {};
1982
+ const walk = (current, prefix = "") => {
1983
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
1984
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
1985
+ const abs = path.join(current, entry.name);
1986
+ if (entry.isDirectory()) {
1987
+ walk(abs, rel);
1988
+ continue;
1989
+ }
1990
+ if (!entry.isFile() || rel === AGENT_NATIVE_SKILL_METADATA_FILE)
1991
+ continue;
1992
+ out[rel] = fs.readFileSync(abs, "utf-8");
1993
+ }
1994
+ };
1995
+ if (fs.existsSync(dir))
1996
+ walk(dir);
1997
+ return out;
1998
+ }
1999
+ function readSkillInstallMetadata(dir) {
2000
+ const file = path.join(dir, AGENT_NATIVE_SKILL_METADATA_FILE);
2001
+ if (!fs.existsSync(file))
2002
+ return undefined;
2003
+ try {
2004
+ const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
2005
+ if (parsed &&
2006
+ parsed.source === "agent-native" &&
2007
+ typeof parsed.skillName === "string" &&
2008
+ typeof parsed.contentHash === "string") {
2009
+ return parsed;
2010
+ }
2011
+ }
2012
+ catch { }
2013
+ return undefined;
2014
+ }
2015
+ function homeDir() {
2016
+ return process.env.HOME || os.homedir();
2017
+ }
2018
+ function skillSearchRoots(input) {
2019
+ const roots = [];
2020
+ const clientSet = new Set(input.clients);
2021
+ const includeAll = input.clients.length === 0;
2022
+ const hasClient = (client) => includeAll || clientSet.has(client);
2023
+ const add = (root, scope, client) => {
2024
+ if (root)
2025
+ roots.push({ root, scope, client });
2026
+ };
2027
+ if (input.scopes.includes("project")) {
2028
+ if (hasClient("codex")) {
2029
+ add(path.join(input.baseDir, ".agents", "skills"), "project", "codex");
2030
+ }
2031
+ if (hasClient("claude-code") || hasClient("claude-code-cli")) {
2032
+ add(path.join(input.baseDir, ".claude", "skills"), "project", "claude-code");
2033
+ }
2034
+ if (includeAll)
2035
+ add(path.join(input.baseDir, "skills"), "project", "repo");
2036
+ }
2037
+ if (input.scopes.includes("user")) {
2038
+ const home = homeDir();
2039
+ if (hasClient("codex")) {
2040
+ add(process.env.CODEX_HOME
2041
+ ? path.join(process.env.CODEX_HOME, "skills")
2042
+ : undefined, "user", "codex");
2043
+ add(home ? path.join(home, ".codex", "skills") : undefined, "user", "codex");
2044
+ }
2045
+ if (hasClient("claude-code") || hasClient("claude-code-cli")) {
2046
+ add(home ? path.join(home, ".claude", "skills") : undefined, "user", "claude-code");
2047
+ }
2048
+ }
2049
+ const seen = new Set();
2050
+ return roots.filter((entry) => {
2051
+ const key = `${entry.scope}:${entry.client}:${path.resolve(entry.root)}`;
2052
+ if (seen.has(key))
2053
+ return false;
2054
+ seen.add(key);
2055
+ return true;
2056
+ });
2057
+ }
2058
+ function targetIdsForStatus(parsed) {
2059
+ if (!parsed.target) {
2060
+ return Object.keys(BUILT_IN_APP_SKILLS).filter((id) => !isLocalOnlyBuiltInSkill(BUILT_IN_APP_SKILLS[id]));
2061
+ }
2062
+ const known = normalizeKnownSkillTarget(parsed.target);
2063
+ if (!known) {
2064
+ throw new Error(`Unknown built-in skill: ${parsed.target}. Run "agent-native skills list".`);
2065
+ }
2066
+ if (isLocalOnlyBuiltInSkill(BUILT_IN_APP_SKILLS[known])) {
2067
+ throw new Error(`${BUILT_IN_APP_SKILLS[known].manifest.displayName} is installed as a local command and cannot be refreshed with skills update yet.`);
2068
+ }
2069
+ return [known];
2070
+ }
2071
+ function scopeFilterForStatus(parsed) {
2072
+ return parsed.scopeExplicit
2073
+ ? [parsed.scope]
2074
+ : ["project", "user"];
2075
+ }
2076
+ function clientFilterForStatus(parsed) {
2077
+ return parsed.clientExplicit ? resolveClients(parsed.client) : [];
2078
+ }
2079
+ function collectSkillInstallStates(parsed, options) {
2080
+ const appSkillIds = targetIdsForStatus(parsed);
2081
+ const latest = latestSkillBundlesForTargets(appSkillIds);
2082
+ const roots = skillSearchRoots({
2083
+ baseDir: options.baseDir ?? process.cwd(),
2084
+ clients: clientFilterForStatus(parsed),
2085
+ scopes: scopeFilterForStatus(parsed),
2086
+ });
2087
+ const states = [];
2088
+ const seenDirs = new Set();
2089
+ for (const root of roots) {
2090
+ for (const bundle of Object.values(latest)) {
2091
+ const dir = path.join(root.root, bundle.skillName);
2092
+ const resolvedDir = path.resolve(dir);
2093
+ if (seenDirs.has(resolvedDir) || !fs.existsSync(dir))
2094
+ continue;
2095
+ if (!fs.existsSync(path.join(dir, "SKILL.md")))
2096
+ continue;
2097
+ seenDirs.add(resolvedDir);
2098
+ const files = listSkillFolderFiles(dir);
2099
+ const installedHash = Object.keys(files).length > 0 ? stableSkillHash(files) : null;
2100
+ const metadata = readSkillInstallMetadata(dir);
2101
+ states.push({
2102
+ appSkillId: bundle.appSkillId,
2103
+ displayName: bundle.displayName,
2104
+ skillName: bundle.skillName,
2105
+ path: dir,
2106
+ root: root.root,
2107
+ scope: root.scope,
2108
+ client: root.client,
2109
+ latestHash: bundle.contentHash,
2110
+ installedHash,
2111
+ metadataHash: metadata?.contentHash,
2112
+ current: installedHash === bundle.contentHash,
2113
+ managed: metadata?.source === "agent-native",
2114
+ });
2115
+ }
2116
+ }
2117
+ return states.sort((a, b) => `${a.skillName}:${a.path}`.localeCompare(`${b.skillName}:${b.path}`));
2118
+ }
2119
+ function updateSkillInstallStates(states, dryRun) {
2120
+ const latest = latestSkillBundlesForTargets([
2121
+ ...new Set(states.map((state) => state.appSkillId)),
2122
+ ]);
2123
+ const updated = [];
2124
+ for (const state of states) {
2125
+ if (state.current && state.managed)
2126
+ continue;
2127
+ const bundle = latest[state.skillName];
2128
+ if (!bundle)
2129
+ continue;
2130
+ if (!dryRun)
2131
+ writeSkillFolder(state.path, bundle);
2132
+ updated.push({
2133
+ ...state,
2134
+ current: !dryRun,
2135
+ installedHash: dryRun ? state.installedHash : bundle.contentHash,
2136
+ metadataHash: dryRun ? state.metadataHash : bundle.contentHash,
2137
+ });
2138
+ }
2139
+ return updated;
2140
+ }
2830
2141
  function normalizeClientIds(values) {
2831
2142
  if (!Array.isArray(values))
2832
2143
  return [];
@@ -2860,6 +2171,31 @@ function skillPromptOptions() {
2860
2171
  hint: entry.manifest.description,
2861
2172
  }));
2862
2173
  }
2174
+ function prVisualRecapWorkflowPath(baseDir) {
2175
+ return path.join(baseDir, ".github", "workflows", "pr-visual-recap.yml");
2176
+ }
2177
+ function prVisualRecapWorkflowDisplayPath() {
2178
+ return path.join(".github", "workflows", "pr-visual-recap.yml");
2179
+ }
2180
+ function prVisualRecapInstallCommand() {
2181
+ return "agent-native skills add visual-plan --with-github-action";
2182
+ }
2183
+ function prVisualRecapSetupCommand() {
2184
+ return "agent-native recap setup";
2185
+ }
2186
+ async function promptForGithubAction(context) {
2187
+ const clack = await import("@clack/prompts");
2188
+ const result = await clack.confirm({
2189
+ message: "Optional: add automatic PR Visual Recaps?\n" +
2190
+ ` This writes ${context.workflowPath}; ${context.setupCommand} can finish GitHub secrets.`,
2191
+ initialValue: false,
2192
+ });
2193
+ if (clack.isCancel(result)) {
2194
+ clack.cancel("Skipped PR Visual Recap workflow.");
2195
+ return null;
2196
+ }
2197
+ return Boolean(result);
2198
+ }
2863
2199
  function shouldPrompt(parsed, options) {
2864
2200
  if (parsed.yes || parsed.printJson)
2865
2201
  return false;
@@ -2944,7 +2280,10 @@ export function parseSkillsArgs(argv) {
2944
2280
  command = "help";
2945
2281
  args = argv.slice(1);
2946
2282
  }
2947
- else if (first === "list" || first === "add") {
2283
+ else if (first === "list" ||
2284
+ first === "add" ||
2285
+ first === "status" ||
2286
+ first === "update") {
2948
2287
  command = first;
2949
2288
  args = argv.slice(1);
2950
2289
  }
@@ -2956,6 +2295,7 @@ export function parseSkillsArgs(argv) {
2956
2295
  client: "codex",
2957
2296
  clientExplicit: false,
2958
2297
  scope: "user",
2298
+ scopeExplicit: false,
2959
2299
  yes: false,
2960
2300
  dryRun: false,
2961
2301
  printJson: false,
@@ -2986,8 +2326,10 @@ export function parseSkillsArgs(argv) {
2986
2326
  out.client = value;
2987
2327
  out.clientExplicit = true;
2988
2328
  }
2989
- else if ((value = eat("--scope")) !== undefined)
2329
+ else if ((value = eat("--scope")) !== undefined) {
2990
2330
  out.scope = value;
2331
+ out.scopeExplicit = true;
2332
+ }
2991
2333
  else if ((value = eat("--mcp-url")) !== undefined)
2992
2334
  out.mcpUrl = value;
2993
2335
  else if (arg === "--yes" || arg === "-y")
@@ -3031,14 +2373,9 @@ function loadSkillTarget(target) {
3031
2373
  },
3032
2374
  skillNames,
3033
2375
  materializeInstructions(outDir) {
3034
- const skills = {
3035
- [builtIn.skillName]: builtIn.skillMarkdown,
3036
- ...builtInExtraSkills(builtIn),
3037
- };
3038
- for (const [skillName, skillMarkdown] of Object.entries(skills)) {
3039
- const skillDir = path.join(outDir, "skills", skillName);
3040
- fs.mkdirSync(skillDir, { recursive: true });
3041
- fs.writeFileSync(path.join(skillDir, "SKILL.md"), skillMarkdown, "utf-8");
2376
+ const bundles = skillFilesForBuiltIn(knownTarget);
2377
+ for (const bundle of Object.values(bundles)) {
2378
+ writeSkillFolder(path.join(outDir, "skills", bundle.skillName), bundle);
3042
2379
  }
3043
2380
  return outDir;
3044
2381
  },
@@ -3136,6 +2473,8 @@ function dryRunInstallCommand(parsed, target) {
3136
2473
  args.push("--mcp-only");
3137
2474
  if (!parsed.connect)
3138
2475
  args.push("--no-connect");
2476
+ if (parsed.withGithubAction)
2477
+ args.push("--with-github-action");
3139
2478
  if (parsed.yes || isKnownSkill(target))
3140
2479
  args.push("--yes");
3141
2480
  return commandString("agent-native", args);
@@ -3292,6 +2631,9 @@ export async function addAgentNativeSkill(parsed, options = {}) {
3292
2631
  const clients = parsed.clients ?? resolveClients(parsed.client);
3293
2632
  const skillsAgents = skillsAgentsForClients(clients);
3294
2633
  if (parsed.dryRun) {
2634
+ const githubActionPath = parsed.withGithubAction && knownTarget === "visual-plans"
2635
+ ? prVisualRecapWorkflowDisplayPath()
2636
+ : undefined;
3295
2637
  return {
3296
2638
  id: knownBuiltIn.manifest.id,
3297
2639
  displayName: knownBuiltIn.manifest.displayName,
@@ -3302,6 +2644,7 @@ export async function addAgentNativeSkill(parsed, options = {}) {
3302
2644
  dryRun: true,
3303
2645
  local: true,
3304
2646
  commands: [dryRunInstallCommand(parsed, target)],
2647
+ githubActionPath,
3305
2648
  };
3306
2649
  }
3307
2650
  const localInstall = installLocalContextXray({
@@ -3333,6 +2676,12 @@ export async function addAgentNativeSkill(parsed, options = {}) {
3333
2676
  const skillsAgents = skillsAgentsForClients(clients);
3334
2677
  if (parsed.dryRun) {
3335
2678
  try {
2679
+ const githubActionPath = parsed.withGithubAction && knownTarget === "visual-plans"
2680
+ ? prVisualRecapWorkflowDisplayPath()
2681
+ : undefined;
2682
+ const githubActionSuggestedCommand = knownTarget === "visual-plans" && !parsed.withGithubAction
2683
+ ? prVisualRecapInstallCommand()
2684
+ : undefined;
3336
2685
  return {
3337
2686
  id: installTarget.id,
3338
2687
  displayName: installTarget.displayName,
@@ -3342,6 +2691,8 @@ export async function addAgentNativeSkill(parsed, options = {}) {
3342
2691
  mcpClients: clients,
3343
2692
  dryRun: true,
3344
2693
  commands: [dryRunInstallCommand(parsed, target)],
2694
+ githubActionPath,
2695
+ githubActionSuggestedCommand,
3345
2696
  };
3346
2697
  }
3347
2698
  finally {
@@ -3409,14 +2760,32 @@ export async function addAgentNativeSkill(parsed, options = {}) {
3409
2760
  }
3410
2761
  // `--with-github-action`: also drop the PR Visual Recap workflow into the
3411
2762
  // repo so PRs get automatic recaps. Only meaningful for the plan family.
2763
+ const baseDir = options.baseDir ?? process.cwd();
2764
+ let withGithubAction = Boolean(parsed.withGithubAction);
3412
2765
  let githubActionPath;
3413
2766
  let githubActionExisted;
3414
- if (parsed.withGithubAction) {
2767
+ let githubActionSuggestedCommand;
2768
+ if (knownTarget === "visual-plans" &&
2769
+ !withGithubAction &&
2770
+ !fs.existsSync(prVisualRecapWorkflowPath(baseDir))) {
2771
+ if (shouldPrompt(parsed, options)) {
2772
+ const prompt = options.promptGithubAction ?? promptForGithubAction;
2773
+ withGithubAction =
2774
+ (await prompt({
2775
+ workflowPath: prVisualRecapWorkflowDisplayPath(),
2776
+ setupCommand: prVisualRecapSetupCommand(),
2777
+ })) === true;
2778
+ }
2779
+ if (!withGithubAction) {
2780
+ githubActionSuggestedCommand = prVisualRecapInstallCommand();
2781
+ }
2782
+ }
2783
+ if (withGithubAction) {
3415
2784
  if (knownTarget !== "visual-plans") {
3416
2785
  options.log?.("--with-github-action only applies to the visual-plan skill; skipping the workflow.");
3417
2786
  }
3418
2787
  else {
3419
- const written = writePrVisualRecapWorkflow(options.baseDir ?? process.cwd());
2788
+ const written = writePrVisualRecapWorkflow(baseDir);
3420
2789
  githubActionPath = written.path;
3421
2790
  githubActionExisted = written.existed;
3422
2791
  commands.push(`write ${written.path}`);
@@ -3436,6 +2805,7 @@ export async function addAgentNativeSkill(parsed, options = {}) {
3436
2805
  connectCommand,
3437
2806
  githubActionPath,
3438
2807
  githubActionExisted,
2808
+ githubActionSuggestedCommand,
3439
2809
  };
3440
2810
  }
3441
2811
  finally {
@@ -3453,6 +2823,68 @@ function listSkills() {
3453
2823
  local: isLocalOnlyBuiltInSkill(entry),
3454
2824
  }));
3455
2825
  }
2826
+ function skillStateJson(state) {
2827
+ return {
2828
+ appSkillId: state.appSkillId,
2829
+ displayName: state.displayName,
2830
+ skillName: state.skillName,
2831
+ path: state.path,
2832
+ scope: state.scope,
2833
+ client: state.client,
2834
+ status: state.current ? "current" : "stale",
2835
+ managed: state.managed,
2836
+ installedHash: state.installedHash,
2837
+ latestHash: state.latestHash,
2838
+ metadataHash: state.metadataHash,
2839
+ };
2840
+ }
2841
+ function formatSkillState(state) {
2842
+ const status = state.current ? "current" : "stale";
2843
+ const managed = state.managed ? "managed" : "unmarked";
2844
+ const hashes = state.installedHash && !state.current
2845
+ ? ` (${state.installedHash} -> ${state.latestHash})`
2846
+ : "";
2847
+ return `${state.skillName.padEnd(22)} ${status.padEnd(7)} ${state.scope}/${state.client} ${managed}${hashes}\n ${state.path}`;
2848
+ }
2849
+ function runSkillsStatusOrUpdate(parsed, options, update) {
2850
+ const before = collectSkillInstallStates(parsed, options);
2851
+ const changed = update ? updateSkillInstallStates(before, parsed.dryRun) : [];
2852
+ const after = update && !parsed.dryRun
2853
+ ? collectSkillInstallStates(parsed, options)
2854
+ : before;
2855
+ if (parsed.printJson) {
2856
+ const outputStates = update && !parsed.dryRun ? after : before;
2857
+ process.stdout.write(`${JSON.stringify({
2858
+ ok: true,
2859
+ command: parsed.command,
2860
+ dryRun: parsed.dryRun,
2861
+ found: before.length,
2862
+ stale: outputStates.filter((state) => !state.current).length,
2863
+ updated: changed.length,
2864
+ skills: outputStates.map(skillStateJson),
2865
+ }, null, 2)}\n`);
2866
+ return;
2867
+ }
2868
+ if (before.length === 0) {
2869
+ const target = parsed.target ? ` for ${parsed.target}` : "";
2870
+ process.stdout.write(`No installed Agent Native skill copies found${target}.\nRun "agent-native skills add ${parsed.target ?? "visual-plan"}" to install one.\n`);
2871
+ return;
2872
+ }
2873
+ if (update) {
2874
+ if (parsed.dryRun) {
2875
+ process.stdout.write(changed.length
2876
+ ? `Would update ${changed.length} skill folder${changed.length === 1 ? "" : "s"}:\n`
2877
+ : "All discovered skill folders are already current.\n");
2878
+ }
2879
+ else {
2880
+ process.stdout.write(changed.length
2881
+ ? `Updated ${changed.length} skill folder${changed.length === 1 ? "" : "s"}.\n`
2882
+ : "All discovered skill folders are already current.\n");
2883
+ }
2884
+ }
2885
+ const rows = (update && parsed.dryRun ? before : after).map(formatSkillState);
2886
+ process.stdout.write(`${rows.join("\n")}\n`);
2887
+ }
3456
2888
  export async function runSkills(argv, options = {}) {
3457
2889
  const parsed = parseSkillsArgs(argv);
3458
2890
  const log = parsed.printJson
@@ -3478,6 +2910,10 @@ export async function runSkills(argv, options = {}) {
3478
2910
  }
3479
2911
  return;
3480
2912
  }
2913
+ if (parsed.command === "status" || parsed.command === "update") {
2914
+ runSkillsStatusOrUpdate(parsed, options, parsed.command === "update");
2915
+ return;
2916
+ }
3481
2917
  const targets = await resolveSkillTargets(parsed, options);
3482
2918
  if (!targets)
3483
2919
  return;
@@ -3536,7 +2972,15 @@ export async function runSkills(argv, options = {}) {
3536
2972
  .filter((p) => Boolean(p))),
3537
2973
  ];
3538
2974
  const githubActionLine = githubActions.length
3539
- ? `PR Visual Recap workflow: wrote ${githubActions.join(", ")}.\nSet these GitHub repo secrets/variables for it to run:\n ${PR_VISUAL_RECAP_SETUP.join("\n ")}`
2975
+ ? `PR Visual Recap workflow: wrote ${githubActions.join(", ")}.\nNext: run ${prVisualRecapSetupCommand()} to configure GitHub secrets/variables, or set them manually:\n ${PR_VISUAL_RECAP_SETUP.join("\n ")}`
2976
+ : "";
2977
+ const githubActionSuggestions = [
2978
+ ...new Set(results
2979
+ .map((result) => result.githubActionSuggestedCommand)
2980
+ .filter((command) => Boolean(command))),
2981
+ ];
2982
+ const githubActionSuggestionLine = githubActionSuggestions.length
2983
+ ? `Optional PR Visual Recap workflow: run ${githubActionSuggestions.join(" && ")} to add automatic recap comments on pull requests.`
3540
2984
  : "";
3541
2985
  process.stdout.write([
3542
2986
  `Installed ${installedNames} skill${results.length === 1 ? "" : "s"}.`,
@@ -3551,6 +2995,7 @@ export async function runSkills(argv, options = {}) {
3551
2995
  : "",
3552
2996
  authLine,
3553
2997
  githubActionLine,
2998
+ githubActionSuggestionLine,
3554
2999
  localCommands.length ? `Local command: ${localCommands.join(", ")}.` : "",
3555
3000
  "Restart or reload selected agent clients if the skill is not visible yet.",
3556
3001
  parsed.clientExplicit