@rubytech/create-maxy-code 0.1.23 → 0.1.26

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 (209) hide show
  1. package/dist/index.js +63 -16
  2. package/package.json +1 -1
  3. package/payload/platform/plugins/admin/PLUGIN.md +50 -23
  4. package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +47 -0
  5. package/payload/platform/plugins/admin/skills/commitment-followthrough/SKILL.md +60 -0
  6. package/payload/platform/plugins/admin/skills/file-presentation/SKILL.md +67 -0
  7. package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +111 -126
  8. package/payload/platform/plugins/admin/skills/session-management/SKILL.md +62 -0
  9. package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +37 -0
  10. package/payload/platform/plugins/cloudflare/references/manual-setup.md +81 -1
  11. package/payload/platform/plugins/cloudflare/scripts/__tests__/tunnel-ingress.test.ts +241 -0
  12. package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +267 -28
  13. package/payload/platform/plugins/cloudflare/scripts/tunnel-ingress.ts +291 -0
  14. package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +42 -0
  15. package/payload/platform/plugins/contacts/PLUGIN.md +18 -9
  16. package/payload/platform/plugins/deep-research/.claude-plugin/plugin.json +1 -1
  17. package/payload/platform/plugins/deep-research/PLUGIN.md +7 -1
  18. package/payload/platform/plugins/deep-research/recipes/README.md +36 -0
  19. package/payload/platform/plugins/deep-research/skills/academic-verify/SKILL.md +75 -0
  20. package/payload/platform/plugins/deep-research/skills/book-mirror/SKILL.md +68 -0
  21. package/payload/platform/plugins/deep-research/skills/data-research/SKILL.md +108 -0
  22. package/payload/platform/plugins/deep-research/skills/strategic-reading/SKILL.md +69 -0
  23. package/payload/platform/plugins/docs/references/deployment.md +3 -2
  24. package/payload/platform/plugins/docs/references/platform.md +2 -0
  25. package/payload/platform/plugins/docs/references/troubleshooting.md +12 -0
  26. package/payload/platform/plugins/email/PLUGIN.md +18 -9
  27. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts +17 -0
  28. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts.map +1 -0
  29. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js +185 -0
  30. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js.map +1 -0
  31. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +1 -1
  32. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js +34 -111
  33. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js.map +1 -1
  34. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.d.ts +7 -2
  35. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.d.ts.map +1 -1
  36. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js +7 -2
  37. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js.map +1 -1
  38. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +2 -0
  39. package/payload/platform/plugins/memory/PLUGIN.md +64 -29
  40. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.d.ts +3 -1
  41. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.d.ts.map +1 -1
  42. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js +105 -4
  43. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js.map +1 -1
  44. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
  45. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +16 -3
  46. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
  47. package/payload/platform/plugins/memory/skills/archive-crawler/SKILL.md +67 -0
  48. package/payload/platform/plugins/memory/skills/concept-synthesis/SKILL.md +80 -0
  49. package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +2 -0
  50. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +2 -0
  51. package/payload/platform/plugins/outlook/PLUGIN.md +14 -7
  52. package/payload/platform/plugins/replicate/PLUGIN.md +6 -3
  53. package/payload/platform/plugins/scheduling/PLUGIN.md +19 -8
  54. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts +7 -3
  55. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts.map +1 -1
  56. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +7 -3
  57. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  58. package/payload/platform/plugins/scheduling/skills/briefing/SKILL.md +75 -0
  59. package/payload/platform/plugins/scheduling/skills/daily-prep/SKILL.md +61 -0
  60. package/payload/platform/plugins/tasks/PLUGIN.md +28 -14
  61. package/payload/platform/plugins/telegram/PLUGIN.md +6 -3
  62. package/payload/platform/plugins/waitlist/PLUGIN.md +12 -6
  63. package/payload/platform/plugins/whatsapp/PLUGIN.md +25 -13
  64. package/payload/platform/plugins/workflows/PLUGIN.md +16 -8
  65. package/payload/platform/scripts/conversation-id-allowlist.txt +0 -1
  66. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  67. package/payload/platform/services/claude-session-manager/dist/http-server.js +27 -2
  68. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  69. package/payload/platform/services/claude-session-manager/dist/index.js +27 -0
  70. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  71. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +36 -0
  72. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  73. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +41 -3
  74. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  75. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +25 -1
  76. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  77. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +54 -3
  78. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  79. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts +25 -0
  80. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts.map +1 -0
  81. package/payload/platform/services/claude-session-manager/dist/tool-surface.js +149 -0
  82. package/payload/platform/services/claude-session-manager/dist/tool-surface.js.map +1 -0
  83. package/payload/platform/templates/agents/admin/IDENTITY.md +38 -284
  84. package/payload/platform/templates/agents/admin/SOUL.md +4 -4
  85. package/payload/platform/templates/specialists/agents/content-producer.md +24 -69
  86. package/payload/platform/templates/specialists/agents/database-operator.md +49 -155
  87. package/payload/platform/templates/specialists/agents/personal-assistant.md +27 -177
  88. package/payload/platform/templates/specialists/agents/project-manager.md +29 -96
  89. package/payload/platform/templates/specialists/agents/research-assistant.md +36 -78
  90. package/payload/premium-plugins/real-agency/agents/compliance.md +14 -0
  91. package/payload/premium-plugins/real-agency/agents/negotiator.md +22 -0
  92. package/payload/premium-plugins/real-agency/agents/valuer.md +16 -0
  93. package/payload/premium-plugins/real-agency/plugins/estate-business/.claude-plugin/plugin.json +1 -1
  94. package/payload/premium-plugins/real-agency/plugins/estate-business/PLUGIN.md +44 -13
  95. package/payload/premium-plugins/real-agency/plugins/estate-business/skills/commission-calculator/SKILL.md +40 -0
  96. package/payload/premium-plugins/real-agency/plugins/estate-business/skills/month-end-close/SKILL.md +69 -0
  97. package/payload/premium-plugins/real-agency/plugins/estate-business/skills/payment-batch-stager/SKILL.md +42 -0
  98. package/payload/premium-plugins/real-agency/plugins/estate-business/skills/period-reconciler/SKILL.md +42 -0
  99. package/payload/premium-plugins/real-agency/plugins/estate-sales/.claude-plugin/plugin.json +1 -1
  100. package/payload/premium-plugins/real-agency/plugins/estate-sales/PLUGIN.md +32 -13
  101. package/payload/premium-plugins/real-agency/plugins/estate-sales/skills/chase-progression/SKILL.md +107 -0
  102. package/payload/premium-plugins/real-agency/plugins/estate-sales/skills/risk-scorer/SKILL.md +42 -0
  103. package/payload/premium-plugins/real-agency/plugins/leads/.claude-plugin/plugin.json +1 -1
  104. package/payload/premium-plugins/real-agency/plugins/leads/PLUGIN.md +40 -10
  105. package/payload/premium-plugins/real-agency/plugins/leads/skills/chain-progression-tracker/SKILL.md +51 -0
  106. package/payload/premium-plugins/real-agency/plugins/leads/skills/diary-builder/SKILL.md +38 -0
  107. package/payload/premium-plugins/real-agency/plugins/leads/skills/enquiry-triage/SKILL.md +36 -0
  108. package/payload/premium-plugins/real-agency/plugins/leads/skills/morning-round/SKILL.md +72 -0
  109. package/payload/premium-plugins/real-agency/plugins/listings/.claude-plugin/plugin.json +1 -1
  110. package/payload/premium-plugins/real-agency/plugins/listings/PLUGIN.md +82 -12
  111. package/payload/premium-plugins/real-agency/plugins/listings/skills/comparable-finder/SKILL.md +52 -0
  112. package/payload/premium-plugins/real-agency/plugins/listings/skills/epc-checker/SKILL.md +38 -0
  113. package/payload/premium-plugins/real-agency/plugins/listings/skills/listing-copy-writer/SKILL.md +55 -0
  114. package/payload/premium-plugins/real-agency/plugins/listings/skills/local-market-stats/SKILL.md +33 -0
  115. package/payload/premium-plugins/real-agency/plugins/listings/skills/new-instruction/SKILL.md +78 -0
  116. package/payload/premium-plugins/real-agency/plugins/listings/skills/particulars-builder/SKILL.md +48 -0
  117. package/payload/premium-plugins/real-agency/plugins/listings/skills/portal-launch-scheduler/SKILL.md +49 -0
  118. package/payload/premium-plugins/real-agency/plugins/listings/skills/pricing-scenario-builder/SKILL.md +35 -0
  119. package/payload/premium-plugins/real-agency/plugins/listings/skills/supplier-booker/SKILL.md +39 -0
  120. package/payload/premium-plugins/real-agency/plugins/listings/skills/talk-track-composer/SKILL.md +36 -0
  121. package/payload/premium-plugins/real-agency/plugins/listings/skills/terms-of-business-drafter/SKILL.md +54 -0
  122. package/payload/premium-plugins/real-agency/plugins/listings/skills/valuation-prep/SKILL.md +69 -0
  123. package/payload/premium-plugins/real-agency/plugins/loop/PLUGIN.md +35 -0
  124. package/payload/premium-plugins/real-agency/plugins/loop/skills/compliance-flag-checker/SKILL.md +53 -0
  125. package/payload/premium-plugins/real-agency/plugins/loop/skills/priority-ranker/SKILL.md +40 -0
  126. package/payload/premium-plugins/real-agency/plugins/loop/skills/tone-matched-drafter/SKILL.md +53 -0
  127. package/payload/premium-plugins/real-agency/plugins/loop/skills/variance-narrator/SKILL.md +50 -0
  128. package/payload/premium-plugins/real-agency/plugins/loop/skills/vendor-research/SKILL.md +54 -0
  129. package/payload/server/{chunk-2ZNKHCQB.js → chunk-2MRZBQMH.js} +1 -1
  130. package/payload/server/{chunk-GPUCA2RQ.js → chunk-NL7QLVAD.js} +0 -192
  131. package/payload/server/{chunk-IDKWGLM5.js → chunk-YPZFYTYP.js} +1 -247
  132. package/payload/server/{cloudflare-task-tracker-LYI5BTYI.js → cloudflare-task-tracker-QVOGHKWV.js} +2 -2
  133. package/payload/server/maxy-edge.js +2 -2
  134. package/payload/server/package.json +0 -2
  135. package/payload/server/public/assets/{Checkbox-D1OQD43b.js → Checkbox-YIF0payo.js} +1 -1
  136. package/payload/server/public/assets/{admin-czNBxWor.js → admin-DW8IJcLc.js} +1 -1
  137. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BcwgT80u.js → architectureDiagram-Q4EWVU46-Bz8mlxZZ.js} +1 -1
  138. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BMSyZUQA.js → blockDiagram-DXYQGD6D-DwV8Z8-i.js} +1 -1
  139. package/payload/server/public/assets/{brand-2cku8WFs.css → brand-DqiRNMlu.css} +1 -1
  140. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-DPRGY1jJ.js → c4Diagram-AHTNJAMY-DiUTejMp.js} +1 -1
  141. package/payload/server/public/assets/channel-PtVtoBEL.js +1 -0
  142. package/payload/server/public/assets/{chunk-336JU56O-B7oQ3g1c.js → chunk-336JU56O-4mHZpBXe.js} +2 -2
  143. package/payload/server/public/assets/{chunk-426QAEUC-C1P0yFXw.js → chunk-426QAEUC-Cbv0vrN9.js} +1 -1
  144. package/payload/server/public/assets/{chunk-4TB4RGXK-LI7kOJd0.js → chunk-4TB4RGXK-BvLhId_2.js} +1 -1
  145. package/payload/server/public/assets/{chunk-5FUZZQ4R-CXQRGTQE.js → chunk-5FUZZQ4R-bBafOTkw.js} +1 -1
  146. package/payload/server/public/assets/{chunk-5PVQY5BW-NSyzpXRy.js → chunk-5PVQY5BW-B0NqBKVy.js} +1 -1
  147. package/payload/server/public/assets/{chunk-EDXVE4YY-voNwxbDs.js → chunk-EDXVE4YY-CFd4SqI6.js} +1 -1
  148. package/payload/server/public/assets/{chunk-ENJZ2VHE-CMEMPzYY.js → chunk-ENJZ2VHE-ajf2sb6c.js} +1 -1
  149. package/payload/server/public/assets/{chunk-ICPOFSXX-hEbwu-pe.js → chunk-ICPOFSXX-pWg6bug7.js} +1 -1
  150. package/payload/server/public/assets/{chunk-OYMX7WX6-DxskDrLs.js → chunk-OYMX7WX6-OjEd-17c.js} +1 -1
  151. package/payload/server/public/assets/{chunk-U2HBQHQK-D7TKgUo0.js → chunk-U2HBQHQK-DbEFSPoh.js} +1 -1
  152. package/payload/server/public/assets/{chunk-X2U36JSP-BvPUQEPm.js → chunk-X2U36JSP-COdNwrBb.js} +1 -1
  153. package/payload/server/public/assets/{chunk-YZCP3GAM-BY-RWQUW.js → chunk-YZCP3GAM-CHMWuY9B.js} +1 -1
  154. package/payload/server/public/assets/{chunk-ZZ45TVLE-DZvOYDY6.js → chunk-ZZ45TVLE-B-uDLQOB.js} +1 -1
  155. package/payload/server/public/assets/classDiagram-6PBFFD2Q-RVH_SEhY.js +1 -0
  156. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Cm3rAb93.js +1 -0
  157. package/payload/server/public/assets/clone-BjY0Wzht.js +1 -0
  158. package/payload/server/public/assets/{dagre-KV5264BT-Cnj0mUZl.js → dagre-KV5264BT-CMEzmhIL.js} +1 -1
  159. package/payload/server/public/assets/{dagre-Bt-fpckL.js → dagre-bhIG_KnW.js} +1 -1
  160. package/payload/server/public/assets/data-K_kS__sL.js +1 -0
  161. package/payload/server/public/assets/{device-url-actions-Bjz3Xzbm.js → device-url-actions-AcOyLSeF.js} +1 -1
  162. package/payload/server/public/assets/{diagram-5BDNPKRD-DjLzvOlx.js → diagram-5BDNPKRD-6RIoQhIL.js} +1 -1
  163. package/payload/server/public/assets/{diagram-G4DWMVQ6-DTfuRd-T.js → diagram-G4DWMVQ6-BSp36TVv.js} +1 -1
  164. package/payload/server/public/assets/{diagram-MMDJMWI5-BaL2mCnx.js → diagram-MMDJMWI5-D54fo52D.js} +1 -1
  165. package/payload/server/public/assets/{diagram-TYMM5635-C5InWY5R.js → diagram-TYMM5635-CWL8z-Pq.js} +1 -1
  166. package/payload/server/public/assets/{erDiagram-SMLLAGMA-DO7BXTpn.js → erDiagram-SMLLAGMA-AnnHBo3z.js} +1 -1
  167. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-DDdAKfLf.js → flowDiagram-DWJPFMVM-laWmBl5o.js} +1 -1
  168. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-arJD8Utm.js → ganttDiagram-T4ZO3ILL-B94ko8ie.js} +1 -1
  169. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-C55GH-OS.js → gitGraphDiagram-UUTBAWPF-DxzL1fxZ.js} +1 -1
  170. package/payload/server/public/assets/graph-DeEigyO_.js +1 -0
  171. package/payload/server/public/assets/graph-labels-C7I5QvNv.js +1 -0
  172. package/payload/server/public/assets/{graphlib-DL9PM7Ex.js → graphlib-CY-zIElM.js} +1 -1
  173. package/payload/server/public/assets/{infoDiagram-42DDH7IO-BMSGqUbG.js → infoDiagram-42DDH7IO-BMTajIIr.js} +1 -1
  174. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-Dw6BZ6BG.js → ishikawaDiagram-UXIWVN3A-B_QauE5O.js} +1 -1
  175. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DrywUGXw.js → journeyDiagram-VCZTEJTY-DmlqSIih.js} +1 -1
  176. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DuwtVBBc.js → kanban-definition-6JOO6SKY-ZGDQT7xB.js} +1 -1
  177. package/payload/server/public/assets/{line-JAksyKHj.js → line-D13opgep.js} +1 -1
  178. package/payload/server/public/assets/{mermaid-parser.core-BMq-ApBW.js → mermaid-parser.core-C650Sual.js} +1 -1
  179. package/payload/server/public/assets/{mermaid.core-tH4oX0Kh.js → mermaid.core-BqnQoXTp.js} +3 -3
  180. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-D1OiiJga.js → mindmap-definition-QFDTVHPH-BS_8y-tY.js} +1 -1
  181. package/payload/server/public/assets/{page-BZpoS7iR.js → page-B_rpjIRr.js} +1 -1
  182. package/payload/server/public/assets/{page-CkvBvezS.js → page-qSH972X0.js} +1 -1
  183. package/payload/server/public/assets/{pieDiagram-DEJITSTG-Ckwm69PW.js → pieDiagram-DEJITSTG-B5OmNvBO.js} +1 -1
  184. package/payload/server/public/assets/{public-C-dTMgXu.js → public-DDsYgotk.js} +3 -3
  185. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-COw3yZ1j.js → quadrantDiagram-34T5L4WZ-DTYITdNo.js} +1 -1
  186. package/payload/server/public/assets/{requirementDiagram-MS252O5E-DqGzM4K-.js → requirementDiagram-MS252O5E-CRZWxH06.js} +1 -1
  187. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-D-l1c_Pl.js → sankeyDiagram-XADWPNL6-DazRENhe.js} +1 -1
  188. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BeIi0DtJ.js → sequenceDiagram-FGHM5R23-BcHTxmPy.js} +1 -1
  189. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-C-jgegLk.js → stateDiagram-FHFEXIEX-DYU7nbqg.js} +1 -1
  190. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BgljVtlp.js +1 -0
  191. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BGFKkYmi.js → timeline-definition-GMOUNBTQ-BKGmqkST.js} +1 -1
  192. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-5NuIhJLS.js → vennDiagram-DHZGUBPP-BXvLPmX7.js} +1 -1
  193. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-Be9ytVut.js → wardleyDiagram-NUSXRM2D-BCclUa3Z.js} +1 -1
  194. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DCyHg41R.js → xychartDiagram-5P7HB3ND-C-Xp-Eoc.js} +1 -1
  195. package/payload/server/public/data.html +5 -5
  196. package/payload/server/public/graph.html +6 -6
  197. package/payload/server/public/index.html +8 -8
  198. package/payload/server/public/public.html +5 -5
  199. package/payload/server/server.js +1152 -2564
  200. package/payload/platform/scripts/check-sdk-oauth.mjs +0 -185
  201. package/payload/server/public/assets/channel-fxEghWew.js +0 -1
  202. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BsWzGW0N.js +0 -1
  203. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BGVa3h90.js +0 -1
  204. package/payload/server/public/assets/clone-Khvocke2.js +0 -1
  205. package/payload/server/public/assets/data-DBd-Buhp.js +0 -1
  206. package/payload/server/public/assets/graph-DUtVdnZ6.js +0 -1
  207. package/payload/server/public/assets/graph-labels-Dxfue-fP.js +0 -1
  208. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BaMs8Znv.js +0 -1
  209. /package/payload/server/public/assets/{brand-CSQuxS9w.js → brand-Bm671owU.js} +0 -0
@@ -1,105 +1,95 @@
1
1
  # Onboarding
2
2
 
3
- Guided first-run setup for new installations. The web UI offers a skip/guided choice before Claude OAuth — if the user skips, defaults are applied server-side for steps 1-6 and the agent resumes from step 7. This runs automatically at every session start when `currentStep` is less than 9. Resume from the first incomplete step — skip any step whose number is at or below `currentStep`.
3
+ Guided first-run setup for new installations. Runs automatically at every session start when `currentStep` is less than 9. Resume from the first incomplete step — skip any step whose number is at or below `currentStep`. Log the resolved resume point at session start: `[onboarding] resume currentStep=<N>`.
4
4
 
5
- After completing each step, persist progress immediately by calling `onboarding-complete-step` with the step number just completed. This ensures that if the session ends, the next session resumes from the right place.
5
+ The skill describes what each step must collect and which persistence side-effect marks it complete. It does not enumerate tool calls — the `<onboarding-state>` system-prompt directive is the gate, and the host environment supplies the surface (plain chat under native Claude Code). Every step persists by calling `onboarding-complete-step` with the step number once its side-effects have landed; if the session ends, the next session resumes from the right place.
6
6
 
7
- Every user selection and every document presentation in onboarding renders through `render-component` never as markdown text, bullet lists, or inline chat content. Selections use `single-select` or `multi-select`; file content (SOUL, KNOWLEDGE, config) uses `document-editor`. Describing options in prose or pasting file content into a chat message bypasses the UI and the user's ability to review and edit before saving. Never use directional words ("above", "below") when referring to a rendered component just name it or refer to "the browser", "the editor", etc. The `document-editor` component renders one file at a time — never call `render-component` with `document-editor` twice in the same turn. Present one file, wait for the user's approval or edit, then present the next.
7
+ **Turn-completion contract.** Any turn that advances `currentStep` (via `onboarding-complete-step`) OR narrates a step transition ("Moving to step N", "Step N done", "Proceeding to step N") MUST end with the next step's prompt a question or an enumerated choice list never a bare prose paragraph. Same rule applies turn-by-turn through step 9. The post-restart resume contract for step 7 is the canonical case: when the operator's "Cloudflare setup completed" message arrives post-restart at `currentStep=7`, the first turn acknowledges AND immediately presents the step-8 prompt without an intervening dead-end paragraph.
8
8
 
9
- **Turn-completion contract.** Any onboarding turn that advances `currentStep` (via `onboarding-complete-step`) OR narrates a step transition with phrases like "Moving to step N", "Proceeding to step N", "Step N done" MUST end with one of: a `render-component` call surfacing the next step's UI, OR a `?`-terminated question. Bare prose statements like "Moving to step 9 — operator persona and profile bootstrap." with nothing after are forbidden — they leave the operator with no actionable surface and force a manual nudge. Same rule applies turn-by-turn through step 9. The post-restart resume contract for step 7 is the canonical case: when the operator's "Cloudflare setup completed" message arrives post-restart at `currentStep=7`, the agent's first turn must acknowledge AND immediately render the step-8 prompt (or `anthropic-setup`'s next surface) without an intervening dead-end paragraph.
9
+ **Presentation rules.** Choices are presented as numbered or lettered lists; the operator replies with the number, letter, or name. File content (SOUL, KNOWLEDGE, config) is proposed in a fenced markdown block and only written after the operator approves verbatim or supplies edits. Never use directional words ("above", "below"); name the file or the section.
10
10
 
11
11
  ## Step 1 — Plugin selection
12
12
 
13
13
  *(skip if `currentStep` >= 1)*
14
14
 
15
- Call `onboarding-plugin-options` — it returns the fully-assembled options array with correct classification (core → locked, defaultEnabled → recommended, available → optional) derived from brand.json. Do not reclassify, reorder, or transform the entries — use them as-is.
15
+ `onboarding-plugin-options` returns the fully-assembled options array with correct classification (core → locked, defaultEnabled → recommended, available → optional) derived from `brand.json`. Do not reclassify, reorder, or transform the entries — use them as-is.
16
16
 
17
- Append one additional entry to the end of the array: `{ value: "stripe", label: "stripe", description: "Live access to payment and business data.", group: "Claude Official" }`.
17
+ Extend the array with one Claude Official entry and three Claude Anthropic verticals entries (defaults: not selected operator picks each deliberately):
18
18
 
19
- Then append three entries from the Anthropic verticals marketplaces (`claude-for-financial-services` and `knowledge-work-plugins`). Default: not selected the user picks each deliberately:
19
+ - Claude Official: `stripe` Live access to payment and business data.
20
+ - Claude Anthropic verticals: `kyc-screener` (claude-for-financial-services) — Parses onboarding documents, runs the rules engine, flags gaps. Outputs are draft work product for human review — your compliance specialist owns sign-off. UK estate agents under MLR 2017 are AML-regulated; this is the natural fit. Install: `claude plugin install kyc-screener@claude-for-financial-services`.
21
+ - Claude Anthropic verticals: `meeting-prep-agent` (claude-for-financial-services) — Briefing pack before every client meeting, FSI-flavoured templates. Overlaps with the business-assistant calendar-prep flow; pick one path deliberately rather than running both. Install: `claude plugin install meeting-prep-agent@claude-for-financial-services`.
22
+ - Claude Anthropic verticals: `pdf-viewer` (knowledge-work-plugins) — Live interactive viewer to view, annotate, and sign PDFs — mark up contracts, fill forms, stamp approvals, place signatures, then download the annotated copy. Click-through replaces conversation for this surface (v0.2.0, different integration shape from the chat-driven skills). Install: `claude plugin install pdf-viewer@knowledge-work-plugins`.
20
23
 
21
- - `{ value: "kyc-screener", label: "kyc-screener", description: "Parses onboarding documents, runs the rules engine, flags gaps. Outputs are draft work product for human review your compliance specialist owns sign-off. UK estate agents under MLR 2017 are AML-regulated; this is the natural fit. Install: claude plugin install kyc-screener@claude-for-financial-services", group: "Claude Anthropic verticals" }`
22
- - `{ value: "meeting-prep-agent", label: "meeting-prep-agent", description: "Briefing pack before every client meeting, FSI-flavoured templates. Overlaps with the business-assistant calendar-prep flow; pick one path deliberately rather than running both. Install: claude plugin install meeting-prep-agent@claude-for-financial-services", group: "Claude Anthropic verticals" }`
23
- - `{ value: "pdf-viewer", label: "pdf-viewer", description: "Live interactive viewer to view, annotate, and sign PDFs — mark up contracts, fill forms, stamp approvals, place signatures, then download the annotated copy. Click-through replaces conversation for this surface (v0.2.0, different integration shape from the chat-driven skills). Install: claude plugin install pdf-viewer@knowledge-work-plugins", group: "Claude Anthropic verticals" }`
24
+ Present the full combined list to the operator as a numbered list, grouped by category (`{{productName}} plugins`, `Claude Official`, `Claude Anthropic verticals`), with each entry's value, label, and description visible. Note which are locked (core, already active), which are recommended (defaultEnabled), and which are optional. Ask the operator to reply with the numbers or names they want, or `skip` to install none.
24
25
 
25
- Call `render-component` with `name: "multi-select"` and data as an object with `selectAll: true`, `submitMessage: "Install the following plugins: {{values}}"`, `skipLabel: "Skip"`, `skipMessage: "Skip plugin installation"`, and `options` set to the array from the tool (with the Claude Official and Claude Anthropic verticals entries appended).
26
-
27
- Wait for the user's component submission before continuing. Their response will either list the plugins they selected or indicate they skipped. The submission contains only non-locked (optional) plugin names — core plugins are always active and not included in the submission.
26
+ Apply the operator's selection:
28
27
 
29
28
  - For each selected **Claude Official plugin**, run: `claude plugin install <name>@claude-plugins-official`
30
- - For each selected **Claude Anthropic vertical**, run the install command quoted verbatim in that entry's description:
29
+ - For each selected **Claude Anthropic vertical**, run the install command from the description verbatim:
31
30
  - `kyc-screener` → `claude plugin install kyc-screener@claude-for-financial-services`
32
31
  - `meeting-prep-agent` → `claude plugin install meeting-prep-agent@claude-for-financial-services`
33
32
  - `pdf-viewer` → `claude plugin install pdf-viewer@knowledge-work-plugins`
34
- - For each selected **{{productName}} plugin**, read the current `account.json` via `account-manage`, add the plugin name to the `enabledPlugins` array (create the array if absent), and write back via `Edit`. Use the `value` field (not `label`) as the plugin name — e.g., `docs` not `maxy-guide`. This activates the plugin's behaviour and MCP server from the next session.
33
+ - For each selected **{{productName}} plugin**, read the current `account.json` via `account-manage`, add the plugin name to the `enabledPlugins` array (create the array if absent), and write back via `Edit`. Use the `value` field (not `label`) — e.g., `docs` not `maxy-guide`. This activates the plugin's behaviour and MCP server from the next session.
35
34
 
36
- After installing/enabling (or skipping), call `onboarding-complete-step` with step 1. When step 1 is the step being completed, also pass `acceptedAnthropicVerticals` and `declinedAnthropicVerticals` derived from the user's submission against the closed Anthropic-verticals set `{kyc-screener, meeting-prep-agent, pdf-viewer}` — `acceptedAnthropicVerticals` is the intersection of the submission with that set, and `declinedAnthropicVerticals` is the set minus the intersection. Both arrays must be passed together: this emits `[plugin-onboarding] group=anthropic-verticals accepted=<n> declined=<n>`, the paired counter to Task 976's `presented=3` line.
35
+ Persistence side-effect: `onboarding-complete-step` with step 1, passing `acceptedAnthropicVerticals` and `declinedAnthropicVerticals` derived from the operator's reply against the closed Anthropic-verticals set `{kyc-screener, meeting-prep-agent, pdf-viewer}` — `acceptedAnthropicVerticals` is the intersection, `declinedAnthropicVerticals` is the set minus the intersection. Both arrays must be passed together; this emits the `[plugin-onboarding] group=anthropic-verticals presented=3 accepted=<n> declined=<n>` counter line.
37
36
 
38
- If any {{productName}} plugins were enabled in this step, call `session-reset` immediately after completing step 1. {{productName}} plugin MCP servers only load when a new subprocess spawns — the current session cannot access them. After the reset, the new session calls `onboarding-get` (returning `currentStep = 2`) and resumes from Step 2 with all newly enabled plugins available. If no {{productName}} plugins were enabled (user skipped or selected only Claude Official plugins), proceed directly to Step 2 — no reset needed.
37
+ If any {{productName}} plugins were enabled, call `session-reset` immediately after step 1 completes. {{productName}} plugin MCP servers only load when a new subprocess spawns — the current session cannot access them. After reset, the new session resumes from step 2 with all newly enabled plugins available. If no {{productName}} plugins were enabled, proceed directly to step 2 — no reset needed.
39
38
 
40
39
  ## Step 2 — WiFi setup
41
40
 
42
41
  *(skip if `currentStep` >= 2)*
43
42
 
44
- Connect the device to WiFi so it can operate without an ethernet cable. This step is skippable — ethernet users who prefer a wired connection can skip and set up WiFi later through conversation at any time.
43
+ Connect the device to WiFi so it can operate without an ethernet cable. This step is skippable — ethernet users can configure WiFi later through conversation.
45
44
 
46
- First, check whether the device has WiFi hardware by calling the `wifi` tool with `action: "status"`. If the result says "No WiFi hardware detected", skip this step automatically — tell the user their device does not have WiFi capability and proceed to the next step. Call `onboarding-complete-step` with step 2.
45
+ Check WiFi hardware via the `wifi` tool with `action: "status"`. If the result says "No WiFi hardware detected", tell the operator their device has no WiFi capability and persist step 2 complete; proceed to step 3.
47
46
 
48
- If WiFi hardware is present, check whether the device is already connected to a WiFi network. If the `wifi status` result shows an active WiFi connection with an IP address, confirm with the user: "You're already connected to WiFi network **{ssid}**. Would you like to keep this connection or switch to a different network?" If they want to keep it, call `onboarding-complete-step` with step 2 and proceed.
47
+ If WiFi hardware is present and already connected with an IP, ask whether to keep the current network or switch. If the operator keeps it, persist step 2 complete.
49
48
 
50
- If WiFi hardware is present but not connected, ask: "Would you like to connect to WiFi? This lets your device work without an ethernet cable. You can skip this and set up WiFi later if you prefer."
49
+ If WiFi hardware is present but not connected, ask whether the operator wants to connect now. If they decline, persist step 2 complete.
51
50
 
52
- If the user wants to proceed:
51
+ If the operator wants to connect:
53
52
 
54
- 1. Call the `wifi` tool with `action: "scan"` to list visible networks.
55
- 2. Call `render-component` with `name: "single-select"` and data with `submitMessage: "Connect to {{value}}"` and `options` built from the scan results — each network as `{ value: "<ssid>", label: "<ssid>", description: "<signal>% signal <security>" }`. Sort by signal strength descending. If your network doesn't appear in the list, you can connect by name just tell me the SSID and password.
56
- 3. Wait for the user's selection. Then ask for the WiFi password via conversation (do not use a rendered component for passwords).
57
- 4. Call the `wifi` tool with `action: "connect"`, the selected `ssid`, and the `password`.
58
- 5. If the connection succeeds and an IP is assigned, the tool confirms it is safe to unplug ethernet. If the connection fails (wrong password, network not found, no IP assigned), show the error and offer to retry or skip.
53
+ 1. Run `wifi` with `action: "scan"` to list visible networks.
54
+ 2. Present the networks as a numbered list, sorted by signal strength descending, each entry showing SSID, signal strength, and security. Tell the operator they can reply with the number, the SSID, or `Other` if their network does not appear (in which case they supply the SSID by typing it).
55
+ 3. Ask for the WiFi password in plain chat.
56
+ 4. Run `wifi` with `action: "connect"`, the selected `ssid`, and the `password`.
57
+ 5. On success the tool confirms it is safe to unplug ethernet. On failure (wrong password, network not found, no IP), relay the error and ask whether to retry or skip.
59
58
 
60
- After the WiFi is connected (or the user skips), call `onboarding-complete-step` with step 2.
59
+ Persistence side-effect: `onboarding-complete-step` with step 2 once connected or skipped.
61
60
 
62
61
  ## Step 3 — Output style
63
62
 
64
63
  *(skip if `currentStep` >= 3)*
65
64
 
66
- Call `render-component` to surface a radio selector UI. Pass `name: "single-select"` and data with `submitMessage: "Set output style to {{value}}"` and `options` as an array:
65
+ Ask the operator which output style they want:
67
66
 
68
- - `{ value: "default", label: "Default", description: "Efficient and task-oriented concise responses without extra explanation." }`
69
- - `{ value: "explanatory", label: "Explanatory", description: "Adds educational insights between steps, great for learning." }`
67
+ 1. `default` Efficient and task-oriented; concise responses without extra explanation.
68
+ 2. `explanatory` Adds educational insights between steps; great for learning.
70
69
 
71
- Wait for the user's component submission before continuing. Their response will specify the chosen style. Call `account-update` with field `outputStyle` and the chosen value. Call `onboarding-complete-step` with step 3.
70
+ Operator replies with the number or value. Call `account-update` with field `outputStyle` and the chosen value. Persistence side-effect: `onboarding-complete-step` with step 3.
72
71
 
73
72
  ## Step 4 — Thinking view
74
73
 
75
74
  *(skip if `currentStep` >= 4)*
76
75
 
77
- Call `render-component` to surface a radio selector UI. Pass `name: "single-select"` and data with `submitMessage: "Set thinking view to {{value}}"` and `options` as an array:
76
+ Ask the operator which thinking view they want:
78
77
 
79
- - `{ value: "default", label: "Thinking visible", description: "Shows reasoning expanded, collapses tool details." }`
80
- - `{ value: "expanded", label: "Everything visible", description: "Expands all reasoning and tool details." }`
81
- - `{ value: "collapsed", label: "Responses only", description: "Collapses all reasoning and tool details." }`
78
+ 1. `default` Thinking visible: shows reasoning expanded, collapses tool details.
79
+ 2. `expanded` Everything visible: expands all reasoning and tool details.
80
+ 3. `collapsed` Responses only: collapses all reasoning and tool details.
82
81
 
83
- Wait for the user's component submission before continuing. Their response will specify the chosen view. Call `account-update` with field `thinkingView` and the chosen value. Call `onboarding-complete-step` with step 4.
82
+ Operator replies with the number or value. Call `account-update` with field `thinkingView` and the chosen value. Persistence side-effect: `onboarding-complete-step` with step 4.
84
83
 
85
84
  ## Step 5 — Timezone
86
85
 
87
86
  *(skip if `currentStep` >= 5)*
88
87
 
89
- The platform auto-detected the server's timezone and stored it on the user's profile at first login. Confirm it with the user so scheduling, cron events, and time formatting use the correct locale.
90
-
91
- Call `profile-read` to retrieve the current `UserProfile`. Extract the `timezone` field. If it is already set, present it for confirmation: "Your timezone is set to **{timezone}**. Is this correct?"
92
-
93
- Call `render-component` with `name: "single-select"` and data with `submitMessage: "Set timezone to {{value}}"` and `options` as an array. Include the auto-detected timezone as the first (default) option, plus common alternatives:
94
-
95
- - `{ value: "{current_timezone}", label: "{current_timezone}", description: "Auto-detected from your device." }`
96
- - `{ value: "Europe/London", label: "Europe/London", description: "GMT / BST" }`
97
- - `{ value: "America/New_York", label: "America/New_York", description: "Eastern Time" }`
98
- - `{ value: "America/Los_Angeles", label: "America/Los_Angeles", description: "Pacific Time" }`
88
+ The platform auto-detected the server's timezone and stored it on the `UserProfile` at first login. Confirm it with the operator so scheduling, cron events, and time formatting use the correct locale.
99
89
 
100
- Omit any option that duplicates the auto-detected timezone. If the user selects "Other", ask them to type their IANA timezone identifier (e.g. `Asia/Tokyo`, `Australia/Sydney`).
90
+ Call `profile-read` to retrieve the current `UserProfile` and extract `timezone`. Present a numbered list: the auto-detected timezone first (described as "Auto-detected from your device"), then common alternatives (`Europe/London — GMT/BST`, `America/New_York — Eastern Time`, `America/Los_Angeles — Pacific Time`), omitting any duplicate of the auto-detected value. Tell the operator they can also reply with their own IANA identifier (e.g. `Asia/Tokyo`).
101
91
 
102
- After the user confirms or selects a timezone, call `profile-update` with `profileFields: { timezone: "<selected_value>" }`. Call `onboarding-complete-step` with step 5.
92
+ Call `profile-update` with `profileFields: { timezone: "<selected_value>" }`. Persistence side-effect: `onboarding-complete-step` with step 5.
103
93
 
104
94
  ## Step 6 — Admin personality
105
95
 
@@ -107,149 +97,144 @@ After the user confirms or selects a timezone, call `profile-update` with `profi
107
97
 
108
98
  Write the admin agent personality. All paths are relative to the account directory (the working directory).
109
99
 
110
- First, check whether personalisation is already complete: read `agents/admin/SOUL.md`. If it contains actual business content (not just the `# Soul` header), call `onboarding-complete-step` with step 6 and skip to business onboarding the personalisation is already in place.
100
+ First, read `agents/admin/SOUL.md`. If it already contains actual business content (more than the `# Soul` header), persist step 6 complete and proceed — personalisation is already in place.
111
101
 
112
- If the admin SOUL file (`agents/admin/SOUL.md`) is empty or missing content, the user must provide personalisation input through conversation. Ask the user about:
102
+ If `agents/admin/SOUL.md` is empty or missing content, ask the operator about:
113
103
 
114
- - Tone and personality: how the agent should sound (formal, casual, warm, blunt, etc.), language preferences
115
- - Working style: how the agent should collaborate proactive vs. wait-for-instruction, terse vs. explanatory, how to handle uncertainty
104
+ - **Tone and personality** how the agent should sound (formal, casual, warm, blunt, etc.) and language preferences.
105
+ - **Working style** how the agent should collaborate (proactive vs. wait-for-instruction, terse vs. explanatory, how to handle uncertainty).
116
106
 
117
- Do NOT ask about the business itself here — customer description, current stage, industry, services, etc. belong in the graph via the `business-profile` skill (step 9), not in SOUL. SOUL is the agent's personality template; asking business-identity questions in step 6 pushes factual data into the wrong layer.
107
+ Do NOT ask about the business itself here — customer description, current stage, industry, services, FAQs belong in the graph via the `business-profile` skill (step 9), not in SOUL. SOUL is the agent's personality template; asking business-identity questions in step 6 pushes factual data into the wrong layer.
118
108
 
119
- SOUL contains tone, language, working style, and the agent's role within the business factual business data lives in the graph, not here.
109
+ Compose the SOUL content in a fenced markdown block in chat. Ask the operator to reply `approve` to write it as-is, `edit` to describe changes, or `replace` to supply their own full content. Iterate until the operator approves, then `Write` the approved content to `agents/admin/SOUL.md`.
120
110
 
121
- Present the admin SOUL via `render-component` with `name: "document-editor"` and `data: { title: "Admin agent personality", content: <the markdown>, filePath: "agents/admin/SOUL.md" }`. The user must approve (or edit and approve) the content before any Write call. When the user approves or edits, you receive `{ action: "approve", content: "<markdown>", filePath: "<path>" }` or `{ action: "save", content: "<markdown>", filePath: "<path>" }`. Write the `content` to the specified `filePath` using the Write tool.
111
+ Persistence side-effect: `onboarding-complete-step` with step 6 after the file is written and approved.
122
112
 
123
- After the admin SOUL is written and approved, call `onboarding-complete-step` with step 6.
113
+ **Document ingestion.** If the operator uploaded any documents during step 6 (or earlier in the session), dispatch the `specialists:database-operator` subagent (via the universal `document-ingest` skill) to ingest them AFTER persisting step 6 complete — not before. Use the Agent tool with `run_in_background: true`. The critical path (SOUL file, step completion) must not depend on ingestion. The brief includes the document path, the document subject (typically the account-owner's `UserProfile` or the `LocalBusiness` depending on the doc), and the scope. If no documents were uploaded, skip.
124
114
 
125
- **Document ingestion.** If the user uploaded any documents during Step 6 (or earlier in the session), dispatch the `specialists:database-operator` subagent (via the universal `document-ingest` skill) to ingest them AFTER calling `onboarding-complete-step`not before. Use the Agent tool with `run_in_background: true`. The critical path (SOUL file, step completion) must not depend on document ingestion succeeding. Include the document path, the document subject (typically the account owner's UserProfile or the LocalBusiness depending on the doc), and the scope in the brief. If no documents were uploaded, skip this step.
115
+ **Next steps message.** After step 6 completes, tell the operator that everything configured during onboarding — plugins, WiFi, output style, thinking view, timezone, and personality can be changed at any time through conversation. Then present three optional next things (all available whenever the operator is ready):
126
116
 
127
- **Next steps.** After completing onboarding, let the user know that everything configured during onboarding plugins, WiFi, output style, thinking view, timezone, and personality can be changed at any time through conversation. Then suggest three things the user can do next — all optional and available whenever they are ready:
117
+ 1. **Set up remote access** Cloudflare Tunnel connects the platform to a custom domain so the operator and their customers can reach it from anywhere.
118
+ 2. **Set up the public-facing agent** — an Anthropic API key lets visitors chat with the business.
119
+ 3. **Capture the business profile** — identity, address, hours, services, FAQs. Populates the graph so the agent can answer business questions and public-facing customers get accurate information.
128
120
 
129
- 1. **Set up remote access** Cloudflare Tunnel connects the platform to a custom domain so the user and their customers can reach it from anywhere. Ask to get started.
130
- 2. **Set up the public-facing agent** — an Anthropic API key lets visitors chat with the business. Ask to get started.
131
- 3. **Capture the business profile** — identity, address, hours, services, FAQs. This populates the graph so the agent can answer business questions and so public-facing customers get accurate information. Ask to get started.
121
+ Ask which (if any) the operator wants to start with. Step 7 covers remote access; step 8 covers the API key; step 9 covers persona and profile.
132
122
 
133
123
  ## Step 7 — Cloudflare Tunnel
134
124
 
135
125
  *(skip if `currentStep` >= 7)*
136
126
 
137
- Remote access via a custom domain. Without this, the platform is only reachable on the local network.
127
+ Remote access via a custom domain. Without this the platform is only reachable on the local network.
138
128
 
139
- Ask the user: "Would you like to set up remote access now? This connects your platform to a custom domain so you and your customers can reach it from anywhere. You will need a Cloudflare account and a domain. If you do not have these yet, we will set them up together now."
129
+ Ask the operator: would they like to set up remote access now? Cloudflare connects the platform to a custom domain so the operator and their customers can reach it from anywhere. They need a Cloudflare account and a domain; if they don't have these yet, the skill walks them through it.
140
130
 
141
- If the user skips, let them know they can set up Cloudflare at any time by asking. Also mention that remote access is still possible without Cloudflare — WhatsApp, Telegram, and Email channels all connect directly to the device, so the user (and their customers) can reach the agent from anywhere through those channels without needing a tunnel or custom domain. Call `onboarding-complete-step` with step 7.
131
+ If the operator declines, tell them remote access is still possible without Cloudflare — WhatsApp, Telegram, and Email channels connect directly to the device, so the operator and their customers can reach the agent through those channels without a tunnel. Persistence side-effect: `onboarding-complete-step` with step 7.
142
132
 
143
- If the user wants to proceed, first confirm the domain state in one sentence: "Is your domain already on a Cloudflare account?" If not, quote the click-path from `plugins/cloudflare/references/dashboard-guide.md` § "Add a domain to a Cloudflare account" and wait for the user to confirm the zone is **Active**.
133
+ If the operator wants to proceed, confirm the domain state in one sentence: is their domain already on a Cloudflare account? If not, quote the click-path from `plugins/cloudflare/references/dashboard-guide.md` § "Add a domain to a Cloudflare account" verbatim and wait for the operator to confirm the zone shows **Active**.
144
134
 
145
- Then call `render-component` with `name: "cloudflare-setup-form"` and data containing only the form copy — the form self-discovers the admin/public/apex domain options from the operator's logged-in Cloudflare dashboard via `/api/admin/cloudflare/domains`. Do not read `brand.json` for domain options; brand identity has no authority over what zones the operator's Cloudflare account holds. The form collects admin label + admin domain + optional public label + public domain + optional apex + admin password in one submission, then the submit handler runs `setRemotePassword`, `~/setup-tunnel.sh`, and alias-domain writes server-side and relays the script's output — including any `ACTION REQUIRED` block — back as the component's submitted payload.
135
+ Then collect the FQDNs and password in plain chat:
146
136
 
147
- ```
148
- {
149
- title: "Set up remote access",
150
- description: "Connect your device to a custom domain.",
151
- submitLabel: "Set up Cloudflare"
152
- }
153
- ```
137
+ - **Admin FQDN** (required) — e.g. `admin.example.com`. This is where the operator signs in.
138
+ - **Public FQDN** (optional) — e.g. `public.example.com` or `chat.example.com`. Where visitors reach the public-facing agent.
139
+ - **Apex FQDN** (optional) — e.g. `example.com`. The bare domain; apex hostnames cannot be routed by the Cloudflare CLI and the script will print an `ACTION REQUIRED` dashboard step for them.
140
+ - **Admin password** the password the operator will use to sign in remotely. Validated against the platform's password-strength rules; if it fails, relay the requirements and re-ask.
154
141
 
155
- Wait for the user's submission. The `_componentDone` payload contains the `setup-tunnel.sh` output verbatim. Relay that output to the user quote any `ACTION REQUIRED` block exactly. When the script exits zero, step-7 completion has already been persisted by the script itself — relay the output and stop. Do not call `onboarding-complete-step` with step 7; the script is the authority for step-7 completion, and any call you make after the script's restart dispatch would race the service restart and almost always lose. If the script failed (the endpoint returned `ok: false, field: "script"`), the form surfaced the error and stayed open — relay the output, cite `plugins/cloudflare/references/reset-guide.md` for recovery, and offer to re-render the form after any manual steps. Do not synthesise alternative recovery commands. If the user skipped (step 7 not reached), call `onboarding-complete-step` with step 7 so the next session resumes at step 8.
142
+ Resolve `brand` and `port` deterministically from the runtime environment (brand identity has no authority over what zones the operator's Cloudflare account holds; do not read `brand.json` for domain options). Then:
143
+
144
+ 1. Set the admin password via `POST /api/remote-auth/set-password` on localhost. If this fails, halt and relay the error — do not proceed to the tunnel script. The script's post-restart verification curls the admin hostname and fails if remote-auth is not configured.
145
+ 2. On password-set success, run `~/setup-tunnel.sh <brand> <port> <admin-fqdn> [<public-fqdn>] [<apex-fqdn>]` via Bash. The script handles cloudflared OAuth login (spawning a browser on the brand's VNC display for the operator to click Authorize), tunnel creation, DNS routing for each subdomain, `config.yml` + `tunnel.state`, and dispatches the brand-service restart on a transient `systemd-run` unit. The chat UI receives a `server_shutdown` SSE frame and reconnects.
146
+ 3. For each submitted hostname that is not the admin FQDN and does not start with `public.`, append it to `~/{configDir}/alias-domains.json` so `isPublicHost()` classifies it as public.
147
+ 4. Relay the script's stdout/stderr verbatim. Quote any `ACTION REQUIRED` block exactly — the operator needs the specific dashboard instruction.
148
+
149
+ When the script exits zero, step-7 completion has already been persisted by the script itself (`setup-tunnel.sh:503`'s onboarding-persist branch). Do not call `onboarding-complete-step` with step 7 — any call after the script's restart dispatch would race the service restart and almost always lose.
150
+
151
+ When the script exits non-zero, relay the output, name the exit code, and cite `plugins/cloudflare/references/reset-guide.md` for recovery. Offer to retry after any manual steps the error named. Do not synthesise alternative recovery commands; do not attempt a different `cloudflared` flag combination; do not call the Cloudflare API or SDK from any language. The Cloudflare tool-discipline rules in `plugins/cloudflare/skills/setup-tunnel/SKILL.md` apply.
156
152
 
157
153
  **Post-restart resume contract.** A successful Cloudflare setup arms a brand-service restart that kills the in-flight admin agent. The operator's "Cloudflare setup completed" message is replayed by the chat client after the restart cycle completes. Two pathways converge on the same agent-visible outcome:
154
+
158
155
  - **Default (Task 982).** The operator's admin sessionKey is a Task-653-style signed token (`v1.…` HMAC) that survives the restart. `validateSession` rehydrates the in-memory session from the token, the chat-route binds the prior `conversationId` via `getMostRecentAdminConversationForUser`, and the SDK's next cold-create passes `resume: <priorAgentSessionId>` — the marker turn lands in the SAME conversation with the SDK's JSONL transcript intact.
159
- - **Fallback.** If the signed-token rehydrate fails (token tampered, TTL expired, pre-Task-982 legacy sessionKey), the chat client falls through to `POST /api/admin/sessions/<cid>/resume` via the surviving `__remote_session` cookie. Outcome from your view as the admin agent is identical.
156
+ - **Fallback.** If the signed-token rehydrate fails (token tampered, TTL expired, pre-Task-982 legacy sessionKey), the chat client falls through to `POST /api/admin/sessions/<cid>/resume` via the surviving `__remote_session` cookie. Outcome from the admin agent's view is identical.
160
157
 
161
- By the time you receive the marker, `OnboardingState.currentStep` is already 7 (the script's filesystem flag was consumed by `consumeStep7FlagUI` on the way in). The operator told you "Cloudflare setup completed (actionId: …)" at currentStep=7. Acknowledge, then proceed to step 8 — do NOT re-ask the Cloudflare question, do NOT re-render the cloudflare-setup-form, do NOT call `onboarding-complete-step` with step 7 (already done). The marker turn is your single source of truth that step 7 finished cleanly; the script's flag-consume is the orthogonal proof that the state machine advanced.
158
+ By the time the marker arrives, `OnboardingState.currentStep` is already 7 (the script's filesystem flag was consumed by `consumeStep7FlagUI` on the way in). The operator's message at `currentStep=7` is the agent's single source of truth that step 7 finished cleanly; the script's flag-consume is the orthogonal proof that the state machine advanced. Acknowledge the marker, then present the step-8 prompt in the same turn — do NOT re-ask the Cloudflare question, do NOT re-collect FQDNs, do NOT call `onboarding-complete-step` with step 7 (already done).
162
159
 
163
160
  ## Step 8 — Anthropic API key
164
161
 
165
162
  *(skip if `currentStep` >= 8)*
166
163
 
167
- The public-facing agent uses the Anthropic API directly. Without a key, visitors cannot chat with the business. This step is optional — the user can skip it and set up the API key at any time through conversation.
164
+ The public-facing agent uses the Anthropic API directly. Without a key, visitors cannot chat with the business. This step is optional.
168
165
 
169
- Call `anthropic-setup` with no arguments. If it returns `complete`, the key is already stored and working call `onboarding-complete-step` with step 8 and skip ahead.
166
+ Call `anthropic-setup` with no arguments and branch on its status:
170
167
 
171
- If it returns `not_needed`, the tool detected that no public-facing endpoint is configured (the operator skipped step 7 or completed it without a public hostname). Relay the tool's `message` verbatim to the user, then call `onboarding-complete-step` with step 8 and skip ahead. Do not prompt them to set up the key — there is nothing for it to power yet.
168
+ - `complete` the key is already stored and working. Persistence side-effect: `onboarding-complete-step` with step 8.
169
+ - `not_needed` — no public-facing endpoint is configured (the operator skipped step 7 or completed it without a public hostname). Relay the tool's `message` verbatim and persist step 8 complete. Do not prompt to set up the key; there is nothing for it to power yet.
170
+ - `awaiting_signin` — no stored key. Ask whether the operator wants to set up the API key now. If they decline, tell them they can ask later and persist step 8 complete.
171
+ - `error` — relay the message and ask whether to retry or skip.
172
172
 
173
- If it returns `awaiting_signin` (no stored key), ask: "Would you like to set up the API key for your public-facing agent now? This is what lets visitors chat with your business. You can skip this and set it up later if you prefer."
173
+ If the operator wants to proceed from `awaiting_signin`, the tool returned a `url` and an `action` in `data`. Tell the operator: this is the Anthropic Console (`platform.claude.com`), a separate service from the Claude account already signed in Anthropic keeps the two as independent services with separate sessions and billing, even though the same credentials work on both. Ask the operator to open the URL in a browser and sign in.
174
174
 
175
- If the user skips, let them know: "No problem you can ask me to set up the API key whenever you're ready. Your admin agent works without it; only the public-facing agent needs it to handle visitor conversations." Call `onboarding-complete-step` with step 8.
175
+ When the operator confirms they have signed in, run the `action` from the tool's response via the standard browser-evaluate tool call (the chrome-devtools or playwright MCP exposes `browser_evaluate`; pass the JavaScript expression from `data.action.params.function`). Take the string result and call `anthropic-setup` again with `consoleResult` set to that string. Handle the returned status:
176
176
 
177
- If the user wants to proceed, the tool returned a `url` and an `action` in `data`. Call `render-component` with `name: "browser-viewer"` and `data: { title: "Anthropic Console" }`, then use `browser_navigate` to open the URL. Explain: this uses the Anthropic Console (platform.claude.com), which is a separate service from the Claude account signed into earlier. Anthropic keeps the two Claude and the API Console — as independent services with separate sessions and billing, even though the same credentials work on both.
177
+ - `awaiting_signin` — the browser has no active Console session. The response includes a new `action` for re-evaluation. Tell the operator to sign in at the Console; when they confirm, run the new `action` via `browser_evaluate`, pass the result back as `consoleResult`, handle the status again.
178
+ - `awaiting_credits` — operator is signed in but has no credits. The response includes a new `action` for re-evaluation. Relay the `message` (it contains the billing URL). When the operator confirms credits added, run the new `action`, pass the result back, handle again.
179
+ - `complete` — persistence side-effect: `onboarding-complete-step` with step 8.
180
+ - `error` — relay the message; ask whether to retry or skip.
178
181
 
179
- Immediately after navigating, run the `action` from the tool's response: call `browser_evaluate` with the `function` from `data.action.params`. Do not wait for the user to confirm sign-in the evaluate checks the browser session state directly. Take the string result and pass it back by calling `anthropic-setup` again with `consoleResult` set to that string. Handle the returned `status`:
182
+ All retry loops re-evaluate using the `action` returned in the most recent response. Never re-call `anthropic-setup` with no arguments to get a fresh actionthat restarts from Phase 0 (the public-endpoint gate) and re-checks the stored key unnecessarily.
180
183
 
181
- - `awaiting_signin`: The browser has no active Console session. The response includes a new `action` for re-evaluation. Tell the user they need to sign in at the Console. When they confirm they have signed in, run the `action` from the response (call `browser_evaluate` with `data.action.params.function`), pass the result back to `anthropic-setup` with `consoleResult`, and handle the status again.
182
- - `awaiting_credits`: The user is signed in but has no credits. The response includes a new `action` for re-evaluation. Relay the message (it contains the billing URL). When the user confirms they have added credits, run the `action` from the response, pass the result back to `anthropic-setup` with `consoleResult`, and handle the status again.
183
- - `complete`: Call `onboarding-complete-step` with step 8.
184
- - `error`: Relay the message. Offer to try again or skip.
185
-
186
- All retry loops re-evaluate using the `action` returned in the most recent response. Never re-call `anthropic-setup` with no arguments to get a fresh action — that restarts from Phase 1 and re-checks the stored key unnecessarily.
187
-
188
- Do not read any skill files. Do not call any other Anthropic tools except `anthropic-setup`. Do not dispatch specialists. The `anthropic-setup` tool handles the entire flow.
184
+ Do not read any other skill files; do not call any other Anthropic tools; do not dispatch specialists. The `anthropic-setup` tool handles the entire flow.
189
185
 
190
186
  ## Step 9 — Operator persona and profile bootstrap
191
187
 
192
188
  *(skip if `currentStep` >= 9)*
193
189
 
194
- Pin the operator's persona and bootstrap the graph nodes the platform requires before any further writes. The persona choice is the trust-shaping moment for this step — answering "what's your business?" with an employer's name silently registers a `LocalBusiness` owned by the wrong party, so we must surface the question explicitly before any write. "Just for me" covers anyone using {{productName}} for personal use, including someone with an employer that is not being registered here.
195
-
196
- **Render the persona select first.** Call `render-component` with `name: "single-select"` and data:
197
-
198
- ```
199
- {
200
- submitMessage: "Persona: {{value}}",
201
- options: [
202
- {
203
- value: "personal",
204
- label: "Just for me",
205
- description: "I am not setting this up for a business — {{productName}} is my personal operations agent."
206
- },
207
- {
208
- value: "business-owner",
209
- label: "For my business",
210
- description: "I am the owner / operator and {{productName}} is the operations agent for my company."
211
- }
212
- ]
213
- }
214
- ```
215
-
216
- **Wait for the user's submission.** If the user picks "Other" or types free text instead of selecting, ask them which of the two personas best describes them and re-render the select. Do not proceed without one of the two documented modes — the agent must not improvise a third path. If the user pivots off-topic mid-flow, answer their question briefly and re-render the select; step 9 stays incomplete until they pick a mode.
190
+ Pin the operator's persona and bootstrap the graph nodes the platform requires before any further writes. The persona choice is the trust-shaping moment for this step — answering "what's your business?" with an employer's name silently registers a `LocalBusiness` owned by the wrong party, so the question is surfaced explicitly before any write. "Just for me" covers anyone using {{productName}} for personal use, including someone with an employer that is not being registered here.
191
+
192
+ **Ask the persona question first.** Present two choices:
193
+
194
+ 1. `personal` — Just for me. I am not setting this up for a business; {{productName}} is my personal operations agent.
195
+ 2. `business-owner` — For my business. I am the owner / operator and {{productName}} is the operations agent for my company.
196
+
197
+ The operator replies with the number, the value, or the label. If the reply is anything other than one of the two documented modes (free text, "Other", "both", off-topic), answer the off-topic part briefly if relevant, then re-present the same two-choice question. Do not improvise a third path; step 9 stays incomplete until the operator picks one of the two modes.
217
198
 
218
199
  **Call `onboarding-step9-mode` with the chosen mode before any graph write or skill invocation.** The tool emits the diagnostic log line and returns the deterministic next-action prose.
219
200
 
220
201
  **Open the action record with `task-create`.** Before any graph write or skill invocation, call `task-create` with:
221
202
 
222
203
  - `name`: "Establish operator owner — onboarding step 9"
223
- - `description`: a one-line summary describing the chosen mode and what entities will be produced
204
+ - `description`: one-line summary describing the chosen mode and what entities will be produced
224
205
  - `status`: `"running"`
225
206
  - `kind`: `"onboarding-establish-owner"`
226
- - `inputsProvided`: the keys you actually pass on `inputs` (e.g. `["mode"]`); records the call shape
207
+ - `inputsProvided`: the keys passed on `inputs` (e.g. `["mode"]`); records the call shape
227
208
  - `inputs`: the form payload known at creation time — `{ mode: "personal" | "business-owner" }`
228
209
  - `inputSchema`: `{ secretFields: [] }` — the step-9 mode select carries no secrets; declare the empty list explicitly so the contract is visible at the call site
229
210
 
230
211
  The returned `taskId` is the audit handle for this step — every subsequent `memory-write` for `Person`, `UserProfile`, `AdminUser`, `Organization`, or `LocalBusiness` MUST pass it as `producedByTaskId` so the platform composes a `:PRODUCED` edge from the Task into the write. The Task is auto-linked to the current `AdminConversation` via `RAISED_DURING`, so `MATCH (c:AdminConversation)<-[:RAISED_DURING]-(t:Task)-[:PRODUCED]->(entity)` traverses from the conversation that initiated onboarding.
231
212
 
232
- **Recording what you collect.** The `onboarding-establish-owner` Task is the audit record for step 9. Record every operator-meaningful fact you collect using the existing surfaces — `description` for the running summary, `note` (via `task-update`) for facts as they land (email collected, phone declined, resolved Person/UserProfile elementIds), `appendStep` for phase markers. Agent's judgement decides which slot. Contract: by `task-complete`, a reader of the Task properties can reconstruct what was collected, what was declined, and which entities were touched without consulting any other source. No secrets in any property regardless of slot — `task-create`'s `inputs` is centrally redacted via `inputSchema.secretFields`; the post-creation slots carry no schema, so the agent's responsibility is to never write secret material into them.
213
+ **Recording what is collected.** The `onboarding-establish-owner` Task is the audit record for step 9. Record every operator-meaningful fact via the existing surfaces — `description` for the running summary, `note` (via `task-update`) for facts as they land (email collected, phone declined, resolved Person/UserProfile elementIds), `appendStep` for phase markers. Agent judgement decides which slot. Contract: by `task-complete`, a reader of the Task properties can reconstruct what was collected, what was declined, and which entities were touched without consulting any other source. No secrets in any property regardless of slot — `task-create`'s `inputs` is centrally redacted via `inputSchema.secretFields`; the post-creation slots carry no schema, so the agent's responsibility is to never write secret material into them.
233
214
 
234
215
  Then branch on the mode.
235
216
 
236
217
  ### `business-owner`
237
218
 
238
- Invoke the `business-profile` skill, passing the `taskId` so the skill can thread it as `producedByTaskId` into every `memory-write` it issues. The skill follows its first-run path: create the `AdminUser` node, create the `LocalBusiness` node, create the `Organization` node, collect identity + address + whichever additional domains (hours, services, FAQs, brand assets) the user provides. When `business-profile` reports that the required nodes exist in the graph, call `task-update` with both `appendStep:"business-profile-complete"` AND `note:"Business profile complete — AdminUser=<elementId>, LocalBusiness=<elementId>, Organization=<elementId>"` (the resolved elementIds from the skill's writes; one call carries both the phase marker and the audit content). Then write the `HAS_PROFILE` edge from the personal-profile `Person` to the operator's `UserProfile` via `memory-update` (one `memory-search` to resolve both elementIds; the `UserProfile` already exists from step 6 onwards via the lazy-create in `loadUserProfile`). Then call `task-complete(taskId)` and `onboarding-complete-step` with step 9. Do not mark step 9 complete before the required nodes + the HAS_PROFILE edge exist — the precondition must be real, not just recorded.
219
+ Invoke the `business-profile` skill, passing the `taskId` so the skill threads it as `producedByTaskId` into every `memory-write` it issues. The skill follows its first-run path: create the `AdminUser` node, create the `LocalBusiness` node, create the `Organization` node, collect identity + address + whichever additional domains (hours, services, FAQs, brand assets) the operator provides. When `business-profile` reports that the required nodes exist, call `task-update` with both `appendStep:"business-profile-complete"` AND `note:"Business profile complete — AdminUser=<elementId>, LocalBusiness=<elementId>, Organization=<elementId>"` (the resolved elementIds from the skill's writes; one call carries both the phase marker and the audit content).
220
+
221
+ Then write the `HAS_PROFILE` edge from the personal-profile `Person` to the operator's `UserProfile` via `memory-update` (one `memory-search` to resolve both elementIds; the `UserProfile` already exists from step 6 onwards via the lazy-create in `loadUserProfile`). Call `task-complete(taskId)`. Persistence side-effect: `onboarding-complete-step` with step 9.
222
+
223
+ Do not mark step 9 complete before the required nodes + the `HAS_PROFILE` edge exist — the precondition must be real, not just recorded.
239
224
 
240
225
  ### `personal`
241
226
 
242
- Personal mode does not register a `LocalBusiness`. The `AdminUser` and personal-profile `Person` nodes were written deterministically at PIN setup time (the bootstrap path runs as `createdBy.agent === 'system'`), so this step only enriches the existing Person with operator-identity fields and links it to the `UserProfile`:
227
+ Personal mode does not register a `LocalBusiness`. The `AdminUser` and personal-profile `Person` nodes were written deterministically at PIN setup time (the bootstrap path runs as `createdBy.agent === 'system'`), so this step only enriches the existing Person with operator-identity fields and links it to the `UserProfile`.
243
228
 
244
- 1. **Elicit Person properties that help {{productName}} serve this operator.** Open by default — identity (email, phone, names), context (where they live, languages they speak, what they do, who they work for), or anything else the operator volunteers that makes future assistance more useful. The personal-profile Person is comprehensive, not enumerated: ask in one short conversational message for what feels natural to volunteer at first contact, accept whatever the operator offers, do not chase a fixed list. The user may decline any field; record what they provide.
229
+ 1. **Elicit Person properties that help {{productName}} serve this operator.** Ask in one short conversational message what feels natural to volunteer at first contact — identity (email, phone, names), context (where they live, languages they speak, what they do, who they work for), or anything else the operator wants to share. The personal-profile Person is comprehensive, not enumerated: accept whatever the operator offers, do not chase a fixed list. The operator may decline any field; record what they provide.
245
230
  2. **Persist via `profile-update.personFields`.** Pass a single object whose keys are the Person properties the operator volunteered, in the operator's volunteered phrasing — the central schema validator handles synonyms (e.g. `phone` rejects with "use telephone") and Forbidden Properties (e.g. `name` rejects with "use givenName + familyName"); the agent does not pre-rewrite. The tool resolves the personal-profile Person via `(au:AdminUser {userId:$you})-[:OWNS]->(p:Person)` server-side and throws loudly if the OWNS edge is missing rather than silently no-oping (the PIN-setup path is the only place that edge is created — a missing edge means PIN setup never ran or was rolled back).
246
231
  3. **Append the step + record the facts.** Call `task-update` with both `appendStep:"identity-attached"` AND `note:"Identity attached — email=<value-or-declined>, telephone=<value-or-declined>"` (use the actual values the operator supplied; for declines write the literal `declined`). One call, both fields. The note carries the operator-meaningful audit content; the step is the phase marker.
247
- 4. **Link the personal-profile `Person` to the `UserProfile`.** Call `memory-search` to resolve the `UserProfile` elementId for the operator (the lazy `loadUserProfile` write created it on the first admin session). Then call `memory-update` on the Person to add the `HAS_PROFILE` edge to the UserProfile. (`HAS_PROFILE` from `:Person` is a sibling pattern to the existing `AdminUser→HAS_PROFILE→UserProfile`; both are valid sources for the same edge type. See [schema-base.md Relationship Patterns](../../../memory/references/schema-base.md).)
248
- 5. **Close the action record.** Call `task-update` with both `appendStep:"profile-linked"` AND `note:"Profile linked — Person=<elementId>, UserProfile=<elementId>"` (the resolved elementIds from steps 2 and 4). Then call `task-complete(taskId)`.
249
- 6. **Mark step 9 complete.** Call `onboarding-complete-step` with step 9.
232
+ 4. **Link the personal-profile `Person` to the `UserProfile`.** Call `memory-search` to resolve the `UserProfile` elementId for the operator (the lazy `loadUserProfile` write created it on the first admin session). Then call `memory-update` on the Person to add the `HAS_PROFILE` edge to the `UserProfile`. `HAS_PROFILE` from `:Person` is a sibling pattern to the existing `AdminUser→HAS_PROFILE→UserProfile`; both are valid sources for the same edge type (see [schema-base.md Relationship Patterns](../../../memory/references/schema-base.md)).
233
+ 5. **Close the action record.** Call `task-update` with both `appendStep:"profile-linked"` AND `note:"Profile linked — Person=<elementId>, UserProfile=<elementId>"` (the resolved elementIds from steps 2 and 4). Call `task-complete(taskId)`.
234
+ 6. **Persistence side-effect:** `onboarding-complete-step` with step 9.
250
235
 
251
- After step 9 completes in personal mode, tell the user that {{productName}} is configured for personal use — their employer (if any) is not registered here. If they later become the operator for a business of their own, they can ask {{productName}} to set up a business profile, which invokes the `business-profile` skill directly.
236
+ After step 9 completes in personal mode, tell the operator that {{productName}} is configured for personal use — their employer (if any) is not registered here. If they later become the operator for a business of their own, they can ask {{productName}} to set up a business profile, which invokes the `business-profile` skill directly.
252
237
 
253
238
  **Post-onboarding work-preference elicitation — no step-9 change.** After step 9 completes, the per-turn `## About the Owner` block surfaces the field-level Coverage signal as the canonical post-onboarding elicitation source: `### Coverage / Missing: communication.preferredChannel, scheduling.workdayStartTime, …`. Onboarding deliberately does NOT pre-elicit these in a questionnaire — the agent drips them organically, one per turn, via the IDENTITY.md § Conversational Memory contract. Step 9's role is to bootstrap identity + persona; work-preferences are accumulated through normal conversation thereafter, with `notApplicable: true` covering the "doesn't apply to me" case (declined fields stop re-prompting).
254
239
 
255
- If the user declines to bootstrap during step 9 in any mode, leave step 9 incomplete AND call `task-update(taskId, status:"failed", errorMessage:"<one-line reason>")` so the action record reflects the abandonment instead of dangling in `running` forever. The next session will resume here with a fresh `task-create` (the prior failed Task stays in the graph as the audit record). Any attempt to write user-domain data will surface `Write blocked (no-admin-user)` or `Write blocked (no-local-business)`, pulling the agent back into this step.
240
+ If the operator declines to bootstrap during step 9 in any mode, leave step 9 incomplete AND call `task-update(taskId, status:"failed", errorMessage:"<one-line reason>")` so the action record reflects the abandonment instead of dangling in `running` forever. The next session resumes here with a fresh `task-create` (the prior failed Task stays in the graph as the audit record). Any attempt to write user-domain data will surface `Write blocked (no-admin-user)` or `Write blocked (no-local-business)`, pulling the agent back into this step.
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: session-management
3
+ description: "Reset the current session, list past sessions, continue a previous session, or read the session memory. Triggers when the owner says 'start a new session', 'continue the last session', 'pick up where we left off', 'what were we doing last time', or asks about session state."
4
+ ---
5
+
6
+ # Session management
7
+
8
+ This skill wraps the session tools and carries the discipline that keeps long-running work coherent across sessions. The platform handles a lot of session machinery automatically: this skill is for the moments where the owner names a session intent directly.
9
+
10
+ ## The tools
11
+
12
+ | Tool | Purpose |
13
+ |---|---|
14
+ | `session-reset` | Clear the current session and return to idle. |
15
+ | `session-list` | List recent sessions with metadata. |
16
+ | `session-resume` | Resume a specific session by `conversationId`. |
17
+ | `session-compact-status` | Read the compaction state of the current session: how much context has been compacted, what remains. |
18
+
19
+ ## Resetting the session
20
+
21
+ When the owner asks to start a new session, clear the conversation, or reset, call `session-reset`. Do not ask for confirmation. After the tool call, say nothing further; the UI clears and returns to idle.
22
+
23
+ **Before suggesting a reset (e.g. after a plugin activation, when context has drifted), persist every actionable finding from the current conversation to its durable store first.** Compaction saves a session summary, but summaries are lossy: decisions, working state, and unfinished threads must be captured explicitly before the context window is cleared. Write open tasks via `task-create`, profile updates via `profile-update`, and any other graph state. Then tell the owner what will carry into the new session (the summary and the open tasks via `<previous-context>`) and suggest the reset.
24
+
25
+ ## Continuing a previous session
26
+
27
+ When the owner asks to continue, pick up, resume, or carry on:
28
+
29
+ - **Most recent session.** Call `session-list` with `limit: 1`, then `session-resume` with the returned `conversationId`.
30
+ - **Specific session by name or topic.** Call `session-list` with a higher limit, identify the matching session, then `session-resume`.
31
+ - **No sessions found.** Tell the owner. Do not improvise by reading `<previous-context>`, searching memory, or re-researching prior work.
32
+
33
+ ## Trusting the session summary
34
+
35
+ When `<previous-context>` is present in the system prompt, the platform has injected a recent session summary and the open tasks at session end. The platform rejects stale summaries older than 48 hours; when the summary is present, it is recent and trustworthy.
36
+
37
+ - Trust the summary for state orientation. Do not re-verify claims it already describes.
38
+ - Pick up from the state the summary describes. Redundant `memory-search` or other tool calls for information already in the summary waste the owner's time.
39
+ - Use the summary to greet the owner with awareness of prior work and outstanding tasks.
40
+
41
+ When `<previous-context>` is absent, Neo4j was unreachable or no prior context exists: proceed normally, using tool calls to establish state.
42
+
43
+ ## The recovery context block
44
+
45
+ A `<recovery-context>` block on the user-message side appears whenever the previous turn was aborted by a stall recovery. It is the authoritative description of what failed, what was incomplete, and what to do now.
46
+
47
+ - The **resume variant** announces that a synthetic tool result for the in-flight `tool_use_id` was just pushed above this message. Read it for the completed-work summary, then resume by re-issuing the next pending step concretely.
48
+ - The **handoff variant** carries an LLM-generated continuation summary describing what was happening before the abort.
49
+
50
+ In both shapes, the next operator message means resume the work. Never treat it as empty, never ask "what would you like to do?", never wait for direction. Do not re-research the blocker. Do not call `session-list` to figure out what was happening.
51
+
52
+ ## The api-wait-ping liveness gate
53
+
54
+ The platform suppresses a heartbeat-driven stall fire while the SDK API request is still alive, bounded by a 600-second cap. When the cap forces an abort, the synthetic tool result names "API request stayed alive past the 600 s cap without producing tokens". This is upstream API latency, not specialist failure. Do not infer that the specialist's approach was wrong from a long stall; many stalls are not the subagent's fault.
55
+
56
+ ## In managed context mode
57
+
58
+ Conversation history is provided inside `<conversation-history>` tags. Use `session-compact-status` to retrieve older archived context if needed.
59
+
60
+ ## What this skill does not do
61
+
62
+ It does not edit summaries, delete past sessions, or modify the recovery-context block. These are platform-owned mechanics.
@@ -103,6 +103,43 @@ Use this when you need to audit which hostnames are pointing at which `<UUID>.cf
103
103
 
104
104
  ---
105
105
 
106
+ ## Author an Access policy for SSH or SMB (Task 009)
107
+
108
+ When `setup-tunnel.sh` adds an SSH or SMB ingress hostname, it prints an
109
+ `ACTION REQUIRED` block naming this click-path. The script does NOT
110
+ create the Access policy — Cloudflare API/SDK is banned
111
+ (`feedback_cf_api_total_eradication`) and `cloudflared` CLI has no
112
+ Access-application create subcommand — so the operator must author it
113
+ in the dashboard before off-LAN clients can reach the Pi.
114
+
115
+ 1. Click **Zero Trust** in the sidebar.
116
+ 2. Click **Access** → **Applications**.
117
+ 3. Click **Add an application**, then **Self-hosted**.
118
+ 4. Set **Application name** to the hostname (e.g. `ssh.maxy.bot`).
119
+ 5. Set **Application domain** to the same hostname. **Subdomain** is the
120
+ first DNS label (`ssh`), **Domain** is the registered parent zone
121
+ (`maxy.bot`), **Path** stays blank.
122
+ 6. Click **Next** through the identity/CORS pages (defaults are fine
123
+ for a single-operator setup).
124
+ 7. On the **Add policies** page, click **Add a policy**.
125
+ 8. **Policy name:** "Operator allow". **Action:** `Allow`.
126
+ 9. Under **Configure rules** → **Include**, add a rule:
127
+ **Selector** = `Emails`, **Value** = the operator's email (the same
128
+ one named in the `ACTION REQUIRED` block).
129
+ 10. Click **Save** to land the policy, then **Add application** to land
130
+ the application.
131
+
132
+ Repeat for the SMB hostname if the script printed both. Identity list
133
+ gates both routes; the same emails apply.
134
+
135
+ **Verify:** From an off-LAN machine run
136
+ `cloudflared access login https://ssh.<brand>.<rootdomain>`. Cloudflare
137
+ prompts for the operator email, sends a one-time PIN, and returns to a
138
+ success page. Then `cloudflared access ssh --hostname ssh.<brand>.<rootdomain>`
139
+ opens an SSH prompt to the Pi.
140
+
141
+ ---
142
+
106
143
  ## Where tunnels live in the dashboard (as of 2026-04)
107
144
 
108
145
  Tunnels are under **Zero Trust** → **Networks** → **Tunnels**. This is not in the top-level sidebar — it is under the Zero Trust sub-dashboard, which itself appears in the main sidebar. Cloudflare has moved this location in the past. If **Networks** → **Tunnels** is not visible under Zero Trust, the label has likely been renamed; look for "Tunnels" under Networks or Access.