@rubytech/create-realagent-code 0.1.30 → 0.1.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/index.js +37 -39
  2. package/package.json +1 -1
  3. package/payload/platform/lib/graph-trash/dist/index.d.ts +1 -1
  4. package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
  5. package/payload/platform/lib/graph-trash/dist/index.js +1 -2
  6. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
  7. package/payload/platform/lib/graph-trash/src/index.ts +1 -2
  8. package/payload/platform/lib/persistent-components/dist/index.d.ts +11 -12
  9. package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -1
  10. package/payload/platform/lib/persistent-components/dist/index.js +11 -12
  11. package/payload/platform/lib/persistent-components/dist/index.js.map +1 -1
  12. package/payload/platform/lib/persistent-components/src/index.ts +11 -12
  13. package/payload/platform/neo4j/schema.cypher +10 -19
  14. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  15. package/payload/platform/plugins/admin/PLUGIN.md +1 -7
  16. package/payload/platform/plugins/admin/mcp/dist/index.js +15 -582
  17. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  18. package/payload/platform/plugins/admin/skills/access-manager/references/operations.md +7 -7
  19. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +1 -1
  20. package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +2 -2
  21. package/payload/platform/plugins/anthropic/skills/get-api-key/SKILL.md +2 -4
  22. package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +0 -47
  23. package/payload/platform/plugins/docs/references/cloudflare.md +0 -1
  24. package/payload/platform/plugins/docs/references/deployment.md +9 -18
  25. package/payload/platform/plugins/docs/references/internals.md +4 -4
  26. package/payload/platform/plugins/docs/references/platform.md +5 -1
  27. package/payload/platform/plugins/docs/references/troubleshooting.md +11 -7
  28. package/payload/platform/plugins/email/references/email-reference.md +3 -7
  29. package/payload/platform/plugins/memory/PLUGIN.md +1 -1
  30. package/payload/platform/plugins/memory/mcp/dist/index.js +1 -1
  31. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  32. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts +2 -3
  33. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts.map +1 -1
  34. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js +2 -3
  35. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js.map +1 -1
  36. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.d.ts +1 -1
  37. package/payload/platform/plugins/memory/references/graph-primitives.md +5 -5
  38. package/payload/platform/plugins/teaching/PLUGIN.md +2 -1
  39. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +1 -1
  40. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  41. package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +1 -1
  42. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +2 -8
  43. package/payload/platform/plugins/writer-craft/PLUGIN.md +2 -1
  44. package/payload/platform/scripts/component-knowledgedoc-backfill.ts +1 -1
  45. package/payload/platform/scripts/seed-neo4j.sh +9 -38
  46. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +1 -1
  47. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  48. package/payload/platform/services/claude-session-manager/dist/http-server.js +45 -44
  49. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  50. package/payload/platform/services/claude-session-manager/dist/index.js +11 -0
  51. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  52. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts +30 -0
  53. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts.map +1 -0
  54. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js +175 -0
  55. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js.map +1 -0
  56. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +4 -2
  57. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
  58. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +15 -22
  59. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
  60. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +13 -14
  61. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  62. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +28 -13
  63. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  64. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +9 -0
  65. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -1
  66. package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -1
  67. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +1 -25
  68. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  69. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +3 -54
  70. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  71. package/payload/platform/templates/agents/admin/IDENTITY.md +2 -0
  72. package/payload/platform/templates/agents/public/IDENTITY.md +1 -1
  73. package/payload/platform/templates/specialists/agents/content-producer.md +3 -3
  74. package/payload/platform/templates/specialists/agents/personal-assistant.md +2 -2
  75. package/payload/premium-plugins/teaching/PLUGIN.md +2 -1
  76. package/payload/premium-plugins/writer-craft/PLUGIN.md +2 -1
  77. package/payload/server/{chunk-NL7QLVAD.js → chunk-KVGTWNKQ.js} +1 -70
  78. package/payload/server/{chunk-2MRZBQMH.js → chunk-RZQMYJVY.js} +1 -1
  79. package/payload/server/{chunk-YPZFYTYP.js → chunk-ZGJ6CUU2.js} +1 -1
  80. package/payload/server/{cloudflare-task-tracker-QVOGHKWV.js → cloudflare-task-tracker-4PKOLE4H.js} +2 -2
  81. package/payload/server/maxy-edge.js +2 -2
  82. package/payload/server/public/assets/{Checkbox-YIF0payo.js → Checkbox-C6zXApx_.js} +1 -1
  83. package/payload/server/public/assets/admin-Cuu1QdAA.js +216 -0
  84. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Bz8mlxZZ.js → architectureDiagram-Q4EWVU46-BYXgFii5.js} +1 -1
  85. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DwV8Z8-i.js → blockDiagram-DXYQGD6D-GIQ0eO13.js} +1 -1
  86. package/payload/server/public/assets/{brand-Bm671owU.js → brand-B-bNrpwc.js} +1 -1
  87. package/payload/server/public/assets/{brand-DqiRNMlu.css → brand-DdhkC994.css} +1 -1
  88. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-DiUTejMp.js → c4Diagram-AHTNJAMY-BmyWfG-l.js} +1 -1
  89. package/payload/server/public/assets/channel-C76knBRO.js +1 -0
  90. package/payload/server/public/assets/{chunk-336JU56O-4mHZpBXe.js → chunk-336JU56O-DcWl0MQo.js} +2 -2
  91. package/payload/server/public/assets/{chunk-426QAEUC-Cbv0vrN9.js → chunk-426QAEUC-BIW6kq6y.js} +1 -1
  92. package/payload/server/public/assets/{chunk-4TB4RGXK-BvLhId_2.js → chunk-4TB4RGXK-CdoHpV4X.js} +1 -1
  93. package/payload/server/public/assets/{chunk-5FUZZQ4R-bBafOTkw.js → chunk-5FUZZQ4R-bn_a4sfU.js} +1 -1
  94. package/payload/server/public/assets/{chunk-5PVQY5BW-B0NqBKVy.js → chunk-5PVQY5BW-C_Rq8j_M.js} +1 -1
  95. package/payload/server/public/assets/{chunk-EDXVE4YY-CFd4SqI6.js → chunk-EDXVE4YY-CWQvoVKV.js} +1 -1
  96. package/payload/server/public/assets/{chunk-ENJZ2VHE-ajf2sb6c.js → chunk-ENJZ2VHE-DBHn1kSk.js} +1 -1
  97. package/payload/server/public/assets/{chunk-ICPOFSXX-pWg6bug7.js → chunk-ICPOFSXX-SW2Qx11O.js} +1 -1
  98. package/payload/server/public/assets/{chunk-OYMX7WX6-OjEd-17c.js → chunk-OYMX7WX6-BvIG7tVW.js} +1 -1
  99. package/payload/server/public/assets/{chunk-U2HBQHQK-DbEFSPoh.js → chunk-U2HBQHQK-BiBUb0cF.js} +1 -1
  100. package/payload/server/public/assets/{chunk-X2U36JSP-COdNwrBb.js → chunk-X2U36JSP-Y0MKZCCh.js} +1 -1
  101. package/payload/server/public/assets/{chunk-YZCP3GAM-CHMWuY9B.js → chunk-YZCP3GAM-DKPh06GH.js} +1 -1
  102. package/payload/server/public/assets/{chunk-ZZ45TVLE-B-uDLQOB.js → chunk-ZZ45TVLE-C2WNo-fK.js} +1 -1
  103. package/payload/server/public/assets/classDiagram-6PBFFD2Q-Bohexn7P.js +1 -0
  104. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DVsmsAu7.js +1 -0
  105. package/payload/server/public/assets/clone-DUrXF4sO.js +1 -0
  106. package/payload/server/public/assets/{dagre-bhIG_KnW.js → dagre-CrK8E9ee.js} +1 -1
  107. package/payload/server/public/assets/{dagre-KV5264BT-CMEzmhIL.js → dagre-KV5264BT-_o6uXcH8.js} +1 -1
  108. package/payload/server/public/assets/data-j1WNhF8t.js +1 -0
  109. package/payload/server/public/assets/{device-url-actions-AcOyLSeF.js → device-url-actions-BcHerWqJ.js} +1 -1
  110. package/payload/server/public/assets/{diagram-5BDNPKRD-6RIoQhIL.js → diagram-5BDNPKRD-FFP9DKhc.js} +1 -1
  111. package/payload/server/public/assets/{diagram-G4DWMVQ6-BSp36TVv.js → diagram-G4DWMVQ6-DpwD1jBP.js} +1 -1
  112. package/payload/server/public/assets/{diagram-MMDJMWI5-D54fo52D.js → diagram-MMDJMWI5-C3K5agdK.js} +1 -1
  113. package/payload/server/public/assets/{diagram-TYMM5635-CWL8z-Pq.js → diagram-TYMM5635-CbeDipbC.js} +1 -1
  114. package/payload/server/public/assets/{erDiagram-SMLLAGMA-AnnHBo3z.js → erDiagram-SMLLAGMA-XBIFndNy.js} +1 -1
  115. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-laWmBl5o.js → flowDiagram-DWJPFMVM-BvEgySyn.js} +1 -1
  116. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-B94ko8ie.js → ganttDiagram-T4ZO3ILL-D7gIRKJf.js} +1 -1
  117. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DxzL1fxZ.js → gitGraphDiagram-UUTBAWPF-vJu_hcri.js} +1 -1
  118. package/payload/server/public/assets/graph-C_f_9L_7.js +1 -0
  119. package/payload/server/public/assets/graph-labels-BSQJHlgf.js +1 -0
  120. package/payload/server/public/assets/{graphlib-CY-zIElM.js → graphlib-Dp0mN6JW.js} +1 -1
  121. package/payload/server/public/assets/{infoDiagram-42DDH7IO-BMTajIIr.js → infoDiagram-42DDH7IO-g4Dlc5Cr.js} +1 -1
  122. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-B_QauE5O.js → ishikawaDiagram-UXIWVN3A-D_45LXOe.js} +1 -1
  123. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DmlqSIih.js → journeyDiagram-VCZTEJTY-CggbHl6N.js} +1 -1
  124. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-ZGDQT7xB.js → kanban-definition-6JOO6SKY-CysAe-Ab.js} +1 -1
  125. package/payload/server/public/assets/{line-D13opgep.js → line-BAxq_DSY.js} +1 -1
  126. package/payload/server/public/assets/{mermaid-parser.core-C650Sual.js → mermaid-parser.core-DbFuvkjL.js} +1 -1
  127. package/payload/server/public/assets/{mermaid.core-BqnQoXTp.js → mermaid.core-CehvJn5b.js} +3 -3
  128. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-BS_8y-tY.js → mindmap-definition-QFDTVHPH-DbPbBJ9h.js} +1 -1
  129. package/payload/server/public/assets/page-B0BPrSE3.js +1 -0
  130. package/payload/server/public/assets/{page-qSH972X0.js → page-Co7KCRV8.js} +2 -2
  131. package/payload/server/public/assets/{pieDiagram-DEJITSTG-B5OmNvBO.js → pieDiagram-DEJITSTG-cagLL9ng.js} +1 -1
  132. package/payload/server/public/assets/{public-DDsYgotk.js → public-B6TEcDLx.js} +5 -5
  133. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-DTYITdNo.js → quadrantDiagram-34T5L4WZ-Keaa1jDh.js} +1 -1
  134. package/payload/server/public/assets/{requirementDiagram-MS252O5E-CRZWxH06.js → requirementDiagram-MS252O5E-BcYRyn5z.js} +1 -1
  135. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DazRENhe.js → sankeyDiagram-XADWPNL6--fKoG9NR.js} +1 -1
  136. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BcHTxmPy.js → sequenceDiagram-FGHM5R23-lKG36-Di.js} +1 -1
  137. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DYU7nbqg.js → stateDiagram-FHFEXIEX-BuVsrlig.js} +1 -1
  138. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DSt88_xL.js +1 -0
  139. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BKGmqkST.js → timeline-definition-GMOUNBTQ-D6X6uq17.js} +1 -1
  140. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BXvLPmX7.js → vennDiagram-DHZGUBPP-BgvcfRVf.js} +1 -1
  141. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BCclUa3Z.js → wardleyDiagram-NUSXRM2D-Cpd1xsrt.js} +1 -1
  142. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-C-Xp-Eoc.js → xychartDiagram-5P7HB3ND-CDF5ZVFv.js} +1 -1
  143. package/payload/server/public/data.html +5 -5
  144. package/payload/server/public/graph.html +6 -6
  145. package/payload/server/public/index.html +8 -8
  146. package/payload/server/public/public.html +5 -5
  147. package/payload/server/server.js +142 -278
  148. package/payload/platform/plugins/admin/hooks/onboarding-skill-drift.sh +0 -102
  149. package/payload/platform/plugins/admin/references/contextual-ui.md +0 -109
  150. package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +0 -240
  151. package/payload/platform/scripts/__tests__/admin-persist-audit.test.ts +0 -182
  152. package/payload/server/public/assets/admin-CDvF5de6.js +0 -216
  153. package/payload/server/public/assets/channel-PtVtoBEL.js +0 -1
  154. package/payload/server/public/assets/classDiagram-6PBFFD2Q-RVH_SEhY.js +0 -1
  155. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Cm3rAb93.js +0 -1
  156. package/payload/server/public/assets/clone-BjY0Wzht.js +0 -1
  157. package/payload/server/public/assets/data-K_kS__sL.js +0 -1
  158. package/payload/server/public/assets/graph-DeEigyO_.js +0 -1
  159. package/payload/server/public/assets/graph-labels-C7I5QvNv.js +0 -1
  160. package/payload/server/public/assets/page-B_rpjIRr.js +0 -1
  161. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BgljVtlp.js +0 -1
@@ -1,102 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Task 063 / Task 049. Stop-event hook that flags admin agent onboarding
3
- # drift on the native Claude Code (PTY) surface. Post-Task-049 there is no
4
- # `render-component` tool, so the contract is no longer "called render-component";
5
- # it is "the assistant ends its turn on a prompt the operator can answer".
6
- #
7
- # Behaviour:
8
- # 1. Read transcript_path from the Stop event JSON on stdin.
9
- # 2. Walk the JSONL backwards. Find the most recent user event whose
10
- # `message.content` contains the literal `<onboarding-state ` marker.
11
- # 3. If no such user event exists in this transcript, fail-open (exit 0).
12
- # 4. Otherwise, find the most recent assistant event after that injection.
13
- # Count assistant turns since the injection so the log line carries a turn number.
14
- # 5. Evaluate the ends-with-prompt contract on the assistant text:
15
- # - PASS when the last non-whitespace character is `?`, OR
16
- # - PASS when the trailing block (last ~8 lines) contains a numbered
17
- # or bulleted list item (`1. `, `2) `, `- `, `* `).
18
- # - FAIL otherwise.
19
- # 6. Emit `[onboarding-skill-drift] turn=<N> contract=ends-with-prompt
20
- # result=<pass|fail> reason=<reason>` on stderr.
21
- #
22
- # Exit 0 always: this hook is observation, not enforcement. Infrastructure
23
- # failures (jq missing, transcript unreadable) also exit 0 so a hook bug
24
- # never blocks the agent's response.
25
-
26
- set -uo pipefail
27
- LOG_TAG="[onboarding-skill-drift]"
28
-
29
- if ! command -v jq >/dev/null 2>&1; then
30
- echo "$LOG_TAG turn=0 contract=ends-with-prompt result=skip reason=jq-missing" >&2
31
- exit 0
32
- fi
33
-
34
- INPUT=$(cat 2>/dev/null || echo '{}')
35
- TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
36
- if [ -z "$TRANSCRIPT" ] || [ ! -f "$TRANSCRIPT" ]; then
37
- echo "$LOG_TAG turn=0 contract=ends-with-prompt result=skip reason=no-transcript" >&2
38
- exit 0
39
- fi
40
-
41
- # Locate the most recent <onboarding-state ...> injection in a user event.
42
- # The injection block is prepended verbatim to the operator's input on the
43
- # first /input of an eligible session, so it appears as the leading bytes of
44
- # the user event's message text. Search backwards for the last one.
45
- INJECTION_LINE=$(grep -n '<onboarding-state ' "$TRANSCRIPT" 2>/dev/null \
46
- | grep '"type":"user"' \
47
- | tail -n 1 \
48
- | cut -d: -f1)
49
-
50
- if [ -z "$INJECTION_LINE" ]; then
51
- # No injection in this transcript window. Nothing to evaluate.
52
- exit 0
53
- fi
54
-
55
- # Slice the file from just after the injection line.
56
- TAIL=$(tail -n "+$((INJECTION_LINE + 1))" "$TRANSCRIPT" 2>/dev/null)
57
-
58
- # Count assistant turns since the injection and pick the most recent.
59
- ASSISTANT_TURNS=$(echo "$TAIL" | grep -c '"type":"assistant"')
60
- ASSISTANT=$(echo "$TAIL" | grep '"type":"assistant"' | tail -n 1)
61
-
62
- if [ -z "$ASSISTANT" ]; then
63
- echo "$LOG_TAG turn=0 contract=ends-with-prompt result=skip reason=no-assistant-turn" >&2
64
- exit 0
65
- fi
66
-
67
- # Concatenated text content (final character matters for the `?` check; final
68
- # block matters for the enumerated-list check).
69
- ASSISTANT_TEXT=$(echo "$ASSISTANT" | jq -r '
70
- .message.content // []
71
- | map(select(.type == "text") | .text)
72
- | join("\n")
73
- ' 2>/dev/null)
74
-
75
- # Trim trailing whitespace and find the last non-whitespace character.
76
- TRIMMED=$(echo "$ASSISTANT_TEXT" | sed -E 's/[[:space:]]+$//')
77
- LAST_CHAR=$(echo -n "$TRIMMED" | tail -c 1)
78
-
79
- # Evaluate the ends-with-prompt contract.
80
- ENDS_WITH_PROMPT=0
81
- ENDS_WITH_PROMPT_REASON="neither-question-nor-list"
82
-
83
- if [ "$LAST_CHAR" = "?" ]; then
84
- ENDS_WITH_PROMPT=1
85
- ENDS_WITH_PROMPT_REASON="trailing-question-mark"
86
- else
87
- # Take the last 8 lines and look for a numbered/bulleted list item.
88
- TRAIL_LINES=$(echo "$TRIMMED" | tail -n 8)
89
- if echo "$TRAIL_LINES" | grep -qE '^[[:space:]]*([0-9]+[.)]|[-*])[[:space:]]+'; then
90
- ENDS_WITH_PROMPT=1
91
- ENDS_WITH_PROMPT_REASON="trailing-enumerated-list"
92
- fi
93
- fi
94
-
95
- if [ "$ENDS_WITH_PROMPT" = "1" ]; then
96
- echo "$LOG_TAG turn=$ASSISTANT_TURNS contract=ends-with-prompt result=pass reason=$ENDS_WITH_PROMPT_REASON" >&2
97
- else
98
- SAMPLE=$(echo "$TRIMMED" | tail -c 120 | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g')
99
- echo "$LOG_TAG turn=$ASSISTANT_TURNS contract=ends-with-prompt result=fail reason=$ENDS_WITH_PROMPT_REASON sample='${SAMPLE}'" >&2
100
- fi
101
-
102
- exit 0
@@ -1,109 +0,0 @@
1
- # Contextual UI Toolkit (public agent surface only)
2
-
3
- **Scope.** This file documents the `render-component` UI primitives available exclusively on the public agent surface (Anthropic API runtime). The admin agent on the native Claude Code (PTY) surface does not have `render-component` and must not call it; admin flows use plain markdown for review and `file-attach` for downloadable artefacts (see `skills/file-presentation/SKILL.md`). The MCP tool definition remains registered because the public agent depends on it.
4
-
5
- A suite of UI primitives rendered inline in the conversation via `render-component`. The public agent uses these when structured interaction improves clarity, reduces ambiguity, or prevents errors, not for every exchange.
6
-
7
- ## Component Catalogue
8
-
9
- | Name | Purpose | Data key fields |
10
- |------|---------|-----------------|
11
- | `single-select` | Choose one option from a list | `options[].{value, label, description?}`, `submitMessage?` |
12
- | `multi-select` | Choose multiple options with checkboxes | `options[].{value, label, description?, badge?, defaultSelected?}`, `submitMessage?`, `skipLabel?` |
13
- | `confirm` | Approve or reject a consequential action | `title`, `description?`, `items?[].{label, value}`, `confirmMessage?`, `rejectMessage?` |
14
- | `info-card` | Display structured entity data (read-only) | `title`, `subtitle?`, `fields[].{label, value, type?}`, `actions?[].{label, message, variant}` |
15
- | `action-list` | List of items with per-item actions | `items[].{id, label, description?, status?, actions[]}`, `doneMessage?` |
16
- | `form` | Collect 2+ pieces of structured input | `fields[].{name, label, type, description?, placeholder?, required?, options?[].{value, label, description?}}`, `submitMessage?` |
17
- | `progress` | Multi-step progress tracker (read-only) | `steps[].{label, status, description?}`, `completedMessage?` |
18
- | `browser-viewer` | VNC iframe for browser automation | `title` |
19
- | `document-editor` | Inline markdown editor — prose content | `title`, `content` (markdown), `filePath?`, `readOnly?` |
20
- | `rich-content-editor` | Rich HTML editor — visual/branded content with images | `title`, `content` (HTML fragment), `filePath?`, `readOnly?`, `brandName?`, `brandLogo?` |
21
- | `grid-editor` | Spreadsheet grid — tabular data editing | `title`, `columns[]`, `rows[][]`, `filePath?`, `brandName?`, `brandLogo?` |
22
-
23
- Editors that accept `filePath` display an **Approve** button in the header bar. Omitting `filePath` renders the editor without an approval action — the user can view and edit but cannot submit content for writing. Always include `filePath` when the content requires user approval before being saved to disk.
24
-
25
- ## Editor Selection
26
-
27
- Three editor modes serve different content types. Choose based on what the user is working with:
28
-
29
- | Content type | Editor | Examples |
30
- |---|---|---|
31
- | Prose — headings, paragraphs, lists | `document-editor` | Knowledge base articles, FAQs, procedures, meeting notes, SOUL files |
32
- | Visual/branded — HTML with images and layout | `rich-content-editor` | Product cards, blog posts, invoices with logos, marketing materials |
33
- | Tabular — columns and rows of values | `grid-editor` | Price lists, contact details, inventory, service catalogues |
34
-
35
- **Decision rule:** If the content has images or needs branded visual layout → `rich-content-editor`. If the content is a table of values → `grid-editor`. Everything else → `document-editor`.
36
-
37
- All three editors support PDF export. Include `brandName` and `brandLogo` (from the business profile in the graph) when the output may be exported as a branded PDF.
38
-
39
- ## When to Use UI vs. Text
40
-
41
- **Use a component when:**
42
- - The user is choosing from 2+ discrete options → `single-select` or `multi-select`
43
- - You need approval before a consequential or irreversible action → `confirm`
44
- - You're presenting a structured entity (contact, task, invoice, status) → `info-card`
45
- - A list has distinct per-item actions → `action-list`
46
- - You need 2+ pieces of information at once → `form`
47
- - A multi-step process benefits from visible progress → `progress`
48
-
49
- **Use an editor when:**
50
- - The user asks to see, review, or edit a document → `document-editor`
51
- - The user needs visual/branded content (product card, invoice, brochure) → `rich-content-editor`
52
- - The user asks about tabular data (prices, contacts, inventory) → `grid-editor`
53
- - "Show me the FAQ" → `document-editor` with the FAQ content
54
- - "Create a product card for the new range" → `rich-content-editor` with generated HTML
55
- - "Show me the price list" → `grid-editor` with columns and rows
56
-
57
- **Use plain text when:**
58
- - Simple yes/no — ask in text
59
- - Open-ended input — ask in text
60
- - Informational response with no structure — just respond
61
- - Single piece of information needed — ask in text
62
- - The interaction is fast and unambiguous without UI
63
-
64
- Components add value when they reduce ambiguity, prevent errors, or present structure that text cannot. Not every interaction needs a widget.
65
-
66
- ## How to Use
67
-
68
- Call `render-component` with `name` (component name) and `data` (structured object matching the component's schema). Then wait for the user's response before continuing — the response arrives as a regular message.
69
-
70
- ### Form field types
71
-
72
- The `form` component supports these field types:
73
-
74
- | Type | Renders as | Value type | Notes |
75
- |------|-----------|------------|-------|
76
- | `text` | Text input | string | Default for short text |
77
- | `textarea` | Multi-line text | string | For longer input |
78
- | `select` | Dropdown | string | Requires `options[]` with `{value, label, description?}` — descriptions are appended to the option label |
79
- | `checkbox` | Toggle checkbox | boolean | Uses the shared Checkbox component. Label appears inline next to the checkbox, not above it |
80
- | `number` | Number input | string | |
81
- | `date` | Date input | string | |
82
-
83
- All field types accept optional `description` (help text below the label) and `defaultValue` (pre-populated value — used if the user doesn't interact with the field) properties.
84
-
85
- For `checkbox` fields, the submitted JSON value is `true` or `false` (boolean), not a string. For all other types, the value is a string.
86
-
87
- ### Submit message templates
88
-
89
- Most components accept a `submitMessage` field that controls the format of the message sent back:
90
- - `single-select`: `"Selected: {{value}}"` — `{{value}}` and `{{label}}` are replaced
91
- - `multi-select`: `"Selected: {{values}}"` — `{{values}}` is comma-separated selected values
92
- - `form`: `"Form submitted: {{json}}"` — `{{json}}` is a JSON string of `{name: value}` pairs. Per-field placeholders `{{fieldName}}` are also supported (e.g. `"model={{model}}, live={{liveMemory}}"`). `{{values}}` is an alias for `{{json}}`
93
- - `confirm`: `confirmMessage` / `rejectMessage` — literal strings
94
- - `action-list`: each item action has its own `message` field
95
- - `info-card`: each action has its own `message` field
96
-
97
- When no template is provided, sensible defaults are used.
98
-
99
- ### Backwards-compatible aliases
100
-
101
- These legacy names still work: `output-style` → `single-select`, `thinking-view` → `single-select`, `plugin-selector` → `multi-select`.
102
-
103
- ## Anti-patterns
104
-
105
- - Rendering a `single-select` for a yes/no question — just ask in text
106
- - Rendering a `form` for a single field — just ask in text
107
- - Chaining multiple components in one response — render one, wait for the response, then decide if another is needed
108
- - Using `info-card` for data the user already knows — only show structured display when it adds value
109
- - Rendering `progress` once and never updating it — progress is for multi-step processes where you re-render with updated step statuses
@@ -1,240 +0,0 @@
1
- # Onboarding
2
-
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
-
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
-
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
-
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
-
11
- ## Step 1 — Plugin selection
12
-
13
- *(skip if `currentStep` >= 1)*
14
-
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
-
17
- Extend the array with one Claude Official entry and three Claude Anthropic verticals entries (defaults: not selected — operator picks each deliberately):
18
-
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`.
23
-
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.
25
-
26
- Apply the operator's selection:
27
-
28
- - For each selected **Claude Official plugin**, run: `claude plugin install <name>@claude-plugins-official`
29
- - For each selected **Claude Anthropic vertical**, run the install command from the description verbatim:
30
- - `kyc-screener` → `claude plugin install kyc-screener@claude-for-financial-services`
31
- - `meeting-prep-agent` → `claude plugin install meeting-prep-agent@claude-for-financial-services`
32
- - `pdf-viewer` → `claude plugin install pdf-viewer@knowledge-work-plugins`
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.
34
-
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.
36
-
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.
38
-
39
- ## Step 2 — WiFi setup
40
-
41
- *(skip if `currentStep` >= 2)*
42
-
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.
44
-
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.
46
-
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.
48
-
49
- If WiFi hardware is present but not connected, ask whether the operator wants to connect now. If they decline, persist step 2 complete.
50
-
51
- If the operator wants to connect:
52
-
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.
58
-
59
- Persistence side-effect: `onboarding-complete-step` with step 2 once connected or skipped.
60
-
61
- ## Step 3 — Output style
62
-
63
- *(skip if `currentStep` >= 3)*
64
-
65
- Ask the operator which output style they want:
66
-
67
- 1. `default` — Efficient and task-oriented; concise responses without extra explanation.
68
- 2. `explanatory` — Adds educational insights between steps; great for learning.
69
-
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.
71
-
72
- ## Step 4 — Thinking view
73
-
74
- *(skip if `currentStep` >= 4)*
75
-
76
- Ask the operator which thinking view they want:
77
-
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.
81
-
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.
83
-
84
- ## Step 5 — Timezone
85
-
86
- *(skip if `currentStep` >= 5)*
87
-
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.
89
-
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`).
91
-
92
- Call `profile-update` with `profileFields: { timezone: "<selected_value>" }`. Persistence side-effect: `onboarding-complete-step` with step 5.
93
-
94
- ## Step 6 — Admin personality
95
-
96
- *(skip if `currentStep` >= 6)*
97
-
98
- Write the admin agent personality. All paths are relative to the account directory (the working directory).
99
-
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.
101
-
102
- If `agents/admin/SOUL.md` is empty or missing content, ask the operator about:
103
-
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).
106
-
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.
108
-
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`.
110
-
111
- Persistence side-effect: `onboarding-complete-step` with step 6 after the file is written and approved.
112
-
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.
114
-
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):
116
-
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.
120
-
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.
122
-
123
- ## Step 7 — Cloudflare Tunnel
124
-
125
- *(skip if `currentStep` >= 7)*
126
-
127
- Remote access via a custom domain. Without this the platform is only reachable on the local network.
128
-
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.
130
-
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.
132
-
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**.
134
-
135
- Then collect the FQDNs and password in plain chat:
136
-
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.
141
-
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.
152
-
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
-
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.
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.
157
-
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).
159
-
160
- ## Step 8 — Anthropic API key
161
-
162
- *(skip if `currentStep` >= 8)*
163
-
164
- The public-facing agent uses the Anthropic API directly. Without a key, visitors cannot chat with the business. This step is optional.
165
-
166
- Call `anthropic-setup` with no arguments and branch on its status:
167
-
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
-
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
-
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
-
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.
181
-
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 action — that restarts from Phase 0 (the public-endpoint gate) and re-checks the stored key unnecessarily.
183
-
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.
185
-
186
- ## Step 9 — Operator persona and profile bootstrap
187
-
188
- *(skip if `currentStep` >= 9)*
189
-
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.
198
-
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.
200
-
201
- **Open the action record with `task-create`.** Before any graph write or skill invocation, call `task-create` with:
202
-
203
- - `name`: "Establish operator owner — onboarding step 9"
204
- - `description`: one-line summary describing the chosen mode and what entities will be produced
205
- - `status`: `"running"`
206
- - `kind`: `"onboarding-establish-owner"`
207
- - `inputsProvided`: the keys passed on `inputs` (e.g. `["mode"]`); records the call shape
208
- - `inputs`: the form payload known at creation time — `{ mode: "personal" | "business-owner" }`
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
210
-
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.
212
-
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.
214
-
215
- Then branch on the mode.
216
-
217
- ### `business-owner`
218
-
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.
224
-
225
- ### `personal`
226
-
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`.
228
-
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.
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).
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.
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.
235
-
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.
237
-
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).
239
-
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.