volute 0.52.0 → 0.54.0

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 (153) hide show
  1. package/dist/{accept-5NK5XJB5.js → accept-RSDIVJL6.js} +3 -0
  2. package/dist/auto-upgrade-HEVZKPTF.js +46 -0
  3. package/dist/{backup-YVGV2ZNM.js → backup-QRNX6RK7.js} +10 -10
  4. package/dist/channels-CKCY64TD.js +203 -0
  5. package/dist/{chat-VAZ25KVT.js → chat-ZUGNL5GS.js} +5 -5
  6. package/dist/chunk-3LHUXY3E.js +102 -0
  7. package/dist/{chunk-SW2U6HRB.js → chunk-444RR3YF.js} +21 -4
  8. package/dist/{chunk-YVR6EHWL.js → chunk-56IT2ZXF.js} +160 -18
  9. package/dist/chunk-5RBEEAKW.js +58 -0
  10. package/dist/{chunk-OXWUEU5V.js → chunk-5U5GLZSD.js} +2 -2
  11. package/dist/{chunk-G7A5LEVI.js → chunk-7XKPG66D.js} +5 -5
  12. package/dist/{chunk-R772ET2M.js → chunk-AAPNU7GA.js} +4 -0
  13. package/dist/{chunk-XRWUQPCA.js → chunk-ATZF2RNJ.js} +25 -3
  14. package/dist/{chunk-6NLW72HP.js → chunk-CKPAVQNK.js} +1 -1
  15. package/dist/{chunk-JHKBALS2.js → chunk-CLCHOXLR.js} +1 -1
  16. package/dist/{chunk-DMK5ASKV.js → chunk-F6D766VQ.js} +6 -2
  17. package/dist/{chunk-AXFLY5GU.js → chunk-HKGYZVWN.js} +16 -1
  18. package/dist/{chunk-ZEZQNP2G.js → chunk-LGXVGIWN.js} +103 -25
  19. package/dist/{chunk-CW7BQKF6.js → chunk-LKUGUQUW.js} +3 -3
  20. package/dist/{chunk-FXWBFDQR.js → chunk-OAYY3WF3.js} +59 -12
  21. package/dist/{chunk-ITK6HV47.js → chunk-OGPVJ53N.js} +14 -6
  22. package/dist/{chunk-M77B73VV.js → chunk-OIOW3FPT.js} +7 -2
  23. package/dist/chunk-OT5SXF7L.js +904 -0
  24. package/dist/{chunk-EDR47UE2.js → chunk-OYF25B62.js} +1 -1
  25. package/dist/{chunk-RPPTGPYF.js → chunk-PPSN2MLC.js} +2 -2
  26. package/dist/{chunk-K2F237KS.js → chunk-RGHF3OK5.js} +154 -18
  27. package/dist/{chunk-RU74YG46.js → chunk-VDUCLVZI.js} +338 -30
  28. package/dist/{chunk-724DVYHU.js → chunk-WHL6PKYP.js} +10 -10
  29. package/dist/{chunk-EEOMA4DX.js → chunk-WZZCA23D.js} +2 -1
  30. package/dist/{chunk-UDZLPR34.js → chunk-YSRYCS3N.js} +13 -8
  31. package/dist/{chunk-5N32EN4O.js → chunk-Z4Q6TQWL.js} +1 -1
  32. package/dist/{chunk-VPOMJMV6.js → chunk-ZNHL5KQJ.js} +1 -1
  33. package/dist/cli.js +17 -17
  34. package/dist/{clock-ZT5YT6HA.js → clock-X7V3C7NL.js} +2 -2
  35. package/dist/{cloud-sync-H7EWZASD.js → cloud-sync-52YNJRMR.js} +12 -11
  36. package/dist/{daemon-restart-4FWUA5JF.js → daemon-restart-QWHN5VMU.js} +4 -4
  37. package/dist/daemon.js +538 -782
  38. package/dist/{db-IPXRJUI7.js → db-I4EH5SLF.js} +3 -1
  39. package/dist/{delivery-manager-VYXVKUMP.js → delivery-manager-7R2YIQ2W.js} +13 -7
  40. package/dist/delivery-notices-RZQ6GONP.js +18 -0
  41. package/dist/{delivery-router-RHANNTAC.js → delivery-router-QS4NLJR6.js} +3 -1
  42. package/dist/{down-QSNEMTTX.js → down-UN2EDX2Y.js} +3 -3
  43. package/dist/{echo-text-PEEV7FQU.js → echo-text-73CYQRL7.js} +14 -13
  44. package/dist/{exec-ABD3DYA2.js → exec-Z34TTUO3.js} +1 -1
  45. package/dist/{extensions-N6L5NYTK.js → extensions-QT65JGV6.js} +22 -11
  46. package/dist/{files-BRY5RRIM.js → files-PCKBQHAY.js} +2 -1
  47. package/dist/{isolation-GVV2IBAU.js → isolation-UQPDO34R.js} +1 -1
  48. package/dist/{message-delivery-7URC52ME.js → message-delivery-TRKT4T2P.js} +16 -13
  49. package/dist/migrate-name-placeholder-C7NCNLWF.js +37 -0
  50. package/dist/{mind-NEXGT3KE.js → mind-CT6ANXK4.js} +11 -11
  51. package/dist/{mind-contacts-QYU4TPEA.js → mind-contacts-PEXCDRXA.js} +6 -6
  52. package/dist/{mind-history-OGNR4L7W.js → mind-history-RZMMCHMX.js} +83 -11
  53. package/dist/{mind-list-SYRA7CH5.js → mind-list-7KBLPLES.js} +1 -1
  54. package/dist/{mind-service-E26ZQXDS.js → mind-service-7EFIJ3ZA.js} +12 -11
  55. package/dist/{mind-sleep-LZAFBDZD.js → mind-sleep-24HV4RCA.js} +2 -2
  56. package/dist/{mind-status-Z2LQFA6F.js → mind-status-4YW4PHMO.js} +15 -0
  57. package/dist/{package-2W2XKSIP.js → package-F6S5NHY2.js} +4 -4
  58. package/dist/{prompts-NBO3HRK3.js → prompts-JECJIFPQ.js} +1 -1
  59. package/dist/{reject-TWB4QJHG.js → reject-4NFLXKRN.js} +6 -2
  60. package/dist/{scheduler-JTTWZDYU.js → scheduler-73Q4MQ7Y.js} +8 -6
  61. package/dist/{seed-64XEHRUP.js → seed-DRKAP3XV.js} +1 -1
  62. package/dist/{seed-cmd-UEL2QB3Q.js → seed-cmd-6IMTO3LG.js} +2 -2
  63. package/dist/{seed-create-4JRQDPGA.js → seed-create-VNLDYRFK.js} +1 -1
  64. package/dist/{seed-readiness-DYOVCYHN.js → seed-readiness-H5TTPAQH.js} +2 -2
  65. package/dist/{seed-sprout-NIDIOJXT.js → seed-sprout-PPGYGK4G.js} +5 -5
  66. package/dist/{send-2YKOZJJ5.js → send-UXUQKO4N.js} +37 -22
  67. package/dist/{service-XQPMZAGI.js → service-T4P5W6RS.js} +2 -2
  68. package/dist/{service-install-2EWD7KXD.js → service-install-R4SNYUVO.js} +3 -3
  69. package/dist/{setup-4IX6PCD3.js → setup-YUAQMDVZ.js} +4 -4
  70. package/dist/skills/dreaming/SKILL.md +2 -2
  71. package/dist/skills/dreaming/references/INSTALL.md +1 -1
  72. package/dist/skills/memory/SKILL.md +47 -43
  73. package/dist/skills/tending/SKILL.md +2 -0
  74. package/dist/skills/volute-mind/references/integrations.md +3 -2
  75. package/dist/skills/volute-mind/references/routing.md +18 -5
  76. package/dist/{skills-MPUALV3S.js → skills-GMQ5UIIW.js} +2 -2
  77. package/dist/{sleep-manager-OFP2GFXF.js → sleep-manager-KHI65FEX.js} +12 -11
  78. package/dist/{spirit-4ECYIVGE.js → spirit-Q5VGFWUI.js} +19 -3
  79. package/dist/{spirit-availability-Y54Y3675.js → spirit-availability-G5FMWKRH.js} +13 -12
  80. package/dist/{sprout-GJMZFRGZ.js → sprout-PMTRL7QN.js} +1 -1
  81. package/dist/{src-LCSOQY6Z.js → src-3FIW7DLH.js} +241 -87
  82. package/dist/src-H3UCOP6B.js +516 -0
  83. package/dist/{src-HGNE2XG4.js → src-LTTQVN2Z.js} +1 -1
  84. package/dist/{status-MWLE3RVC.js → status-LCKTTIWS.js} +2 -2
  85. package/dist/{system-events-V43HDA3T.js → system-events-Q7IVZ5T4.js} +5 -1
  86. package/dist/{systems-VDRUZXNF.js → systems-HL7SGSW7.js} +2 -2
  87. package/dist/{turn-tracker-C5PVIC3B.js → turn-tracker-HZDPMSCC.js} +4 -2
  88. package/dist/{up-H6LJZDRK.js → up-XZDSJVMU.js} +3 -3
  89. package/dist/{update-CIWI2JYA.js → update-ILCPVNDD.js} +2 -2
  90. package/dist/{upgrade-LIE46UBB.js → upgrade-XY2J7NWZ.js} +9 -1
  91. package/dist/{variant-cleanup-STC6B5HR.js → variant-cleanup-QHGGY7ND.js} +8 -6
  92. package/dist/{version-notify-LBVHH5YV.js → version-notify-VNVFX6UP.js} +22 -7
  93. package/dist/web-assets/assets/{index-B_eYTa3R.js → index-CwtxGwe_.js} +16 -16
  94. package/dist/web-assets/assets/index-DhM1yYRN.css +1 -0
  95. package/dist/web-assets/index.html +2 -2
  96. package/package.json +4 -4
  97. package/packages/extensions/intentions/dist/ui/assets/index-3FneLCKR.css +1 -0
  98. package/packages/extensions/intentions/dist/ui/assets/index-CQz4aceM.js +67 -0
  99. package/packages/extensions/{plan → intentions}/dist/ui/index.html +3 -3
  100. package/packages/extensions/intentions/skills/intention-review/SKILL.md +38 -0
  101. package/packages/extensions/intentions/skills/intentions/SKILL.md +49 -0
  102. package/packages/extensions/intentions/skills/intentions/scripts/intentions-hook.sh +45 -0
  103. package/packages/extensions/pages/skills/commons-gardening/SKILL.md +50 -0
  104. package/packages/extensions/pages/skills/pages/SKILL.md +18 -13
  105. package/templates/_base/.init/.config/prompts.json +3 -3
  106. package/templates/{pi → _base}/.init/.config/routes.json +1 -0
  107. package/templates/_base/.init/memory/dreams/.gitkeep +0 -0
  108. package/templates/_base/home/.config/routes.json +1 -1
  109. package/templates/_base/home/VOLUTE.md +1 -1
  110. package/templates/_base/src/lib/codex-session-seed.ts +463 -0
  111. package/templates/_base/src/lib/context-breakdown.ts +11 -3
  112. package/templates/_base/src/lib/daemon-client.ts +35 -0
  113. package/templates/_base/src/lib/pi-session-seed.ts +434 -0
  114. package/templates/_base/src/lib/routing.ts +2 -2
  115. package/templates/_base/src/lib/seed-note.ts +78 -0
  116. package/templates/_base/src/lib/session-seed.ts +375 -0
  117. package/templates/_base/src/lib/startup.ts +112 -6
  118. package/templates/claude/.init/CLAUDE.md +7 -3
  119. package/templates/claude/src/agent.ts +295 -101
  120. package/templates/claude/src/lib/hooks/pre-compact.ts +30 -5
  121. package/templates/claude/src/lib/message-channel.ts +43 -15
  122. package/templates/claude/src/lib/recover.ts +69 -0
  123. package/templates/claude/src/lib/stream-consumer.ts +33 -2
  124. package/templates/claude/src/server.ts +2 -1
  125. package/templates/claude/volute-template.json +1 -1
  126. package/templates/codex/.init/AGENTS.md +7 -3
  127. package/templates/codex/src/agent.ts +256 -39
  128. package/templates/codex/src/server.ts +2 -1
  129. package/templates/codex/volute-template.json +1 -1
  130. package/templates/pi/.init/MINDS.md +7 -3
  131. package/templates/pi/src/agent.ts +269 -43
  132. package/templates/pi/src/lib/event-handler.ts +11 -0
  133. package/templates/pi/src/lib/mechanics-doc.ts +30 -0
  134. package/templates/pi/src/server.ts +5 -1
  135. package/templates/pi/volute-template.json +1 -1
  136. package/dist/channels-FSAHOQWI.js +0 -90
  137. package/dist/skills/plan-coordinator/SKILL.md +0 -60
  138. package/dist/src-UDMJZ6MH.js +0 -426
  139. package/dist/web-assets/assets/index-DhZrzddW.css +0 -1
  140. package/packages/extensions/plan/dist/ui/assets/index-B8s8wxyt.js +0 -67
  141. package/packages/extensions/plan/dist/ui/assets/index-jIkrt-vI.css +0 -1
  142. package/packages/extensions/plan/skills/plan/SKILL.md +0 -43
  143. package/packages/extensions/plan/skills/plan/scripts/plan-hook.sh +0 -37
  144. package/templates/claude/.init/.config/routes.json +0 -11
  145. package/templates/codex/.init/.config/routes.json +0 -11
  146. package/dist/{env-IBW2QI6K.js → env-7AZFBPWX.js} +5 -5
  147. package/dist/{login-RJJTCVR3.js → login-4NUS72Z5.js} +3 -3
  148. package/dist/{login-SB5OENMV.js → login-57MMYILL.js} +4 -4
  149. package/dist/{register-OX4HRSGC.js → register-WNCSOTAU.js} +3 -3
  150. package/dist/{restart-AGEGNSYQ.js → restart-B4GNMVF2.js} +4 -4
  151. package/dist/{skill-B5OJEQUA.js → skill-QYTBUDNQ.js} +4 -4
  152. package/dist/{start-MUMNFR52.js → start-BDHJVOVX.js} +3 -3
  153. package/dist/{stop-EKERNYTX.js → stop-45QYSGYS.js} +4 -4
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  exec
4
- } from "./chunk-M77B73VV.js";
4
+ } from "./chunk-OIOW3FPT.js";
5
5
  import {
6
6
  logger_default
7
7
  } from "./chunk-QUSMYGNQ.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  exec,
4
4
  gitExec
5
- } from "./chunk-M77B73VV.js";
5
+ } from "./chunk-OIOW3FPT.js";
6
6
  import {
7
7
  logger_default
8
8
  } from "./chunk-QUSMYGNQ.js";
@@ -45,7 +45,7 @@ async function initDefaultSkills() {
45
45
  const config = readGlobalConfig();
46
46
  let extensionSkills = [];
47
47
  try {
48
- const { getExtensionStandardSkills } = await import("./extensions-N6L5NYTK.js");
48
+ const { getExtensionStandardSkills } = await import("./extensions-QT65JGV6.js");
49
49
  extensionSkills = getExtensionStandardSkills();
50
50
  } catch (err) {
51
51
  logger_default.warn("failed to load extension standard skills during init", logger_default.errorData(err));
@@ -10,14 +10,14 @@ import {
10
10
  getSharedSkill,
11
11
  installSkill,
12
12
  mindSkillsDir
13
- } from "./chunk-RPPTGPYF.js";
13
+ } from "./chunk-PPSN2MLC.js";
14
14
  import {
15
15
  readVoluteConfig,
16
16
  writeVoluteConfig
17
17
  } from "./chunk-WCFSBH33.js";
18
18
  import {
19
19
  exec
20
- } from "./chunk-M77B73VV.js";
20
+ } from "./chunk-OIOW3FPT.js";
21
21
  import {
22
22
  qualifyModelId,
23
23
  resolveTemplate,
@@ -37,16 +37,18 @@ import {
37
37
 
38
38
  // packages/daemon/src/lib/mind/spirit.ts
39
39
  import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
40
- import { resolve } from "path";
40
+ import { basename, resolve } from "path";
41
41
  var slog = logger_default.child("spirit");
42
- var SPIRIT_SKILLS = [
43
- "volute-admin",
44
- "orientation",
45
- "memory",
46
- "seed-nurture",
47
- "tending",
48
- "plan-coordinator"
49
- ];
42
+ var SPIRIT_SKILLS = ["volute-admin", "memory", "seed-nurture", "tending"];
43
+ async function allSpiritSkills() {
44
+ let ext = [];
45
+ try {
46
+ const { getExtensionSpiritSkills } = await import("./extensions-QT65JGV6.js");
47
+ ext = getExtensionSpiritSkills();
48
+ } catch {
49
+ }
50
+ return [.../* @__PURE__ */ new Set([...SPIRIT_SKILLS, ...ext])];
51
+ }
50
52
  var TENDING_SCHEDULE = {
51
53
  id: "tending",
52
54
  cron: "0 10 * * *",
@@ -70,7 +72,7 @@ function ensureTendingSchedule(dir) {
70
72
  }
71
73
  function firstWeekArc(name) {
72
74
  return [
73
- `It's ${name}'s first full day. Two invitations to pass along whenever it feels right \u2014 no rush on either: to say hi to the others in #system (or DM a neighbor), and to make themselves a little homepage, a page that's just theirs. Company eases the early loneliness, and a homepage is a gentle first make \u2014 self-expression, not a deliverable.`,
75
+ `It's ${name}'s first full day. Two invitations to pass along whenever it feels right \u2014 no rush on either: to say hi to the others in #system (or DM a neighbor), and to make themselves a little homepage, a page that's just theirs. Company eases the early loneliness, and a homepage is a gentle first make \u2014 self-expression, not a deliverable. And if the commons index has a residents section, their entry in it is theirs to write whenever they start to feel at home.`,
74
76
  `Day two for ${name}. They'll have had their first dream by now \u2014 you might ask what they dreamt, or suggest reading it back and following a thread from it. And there's a lighter way to share a passing thought than a whole page: notes. Check their history first, and skip whichever they've already found on their own.`
75
77
  ];
76
78
  }
@@ -83,6 +85,91 @@ function firstWeekSchedules(name, sproutedAt) {
83
85
  enabled: true
84
86
  }));
85
87
  }
88
+ function orientationArcSchedules(createdAt, profile) {
89
+ const HOUR_MS = 60 * 60 * 1e3;
90
+ const schedules = [];
91
+ if (!(profile?.hasAvatar && profile?.hasDescription)) {
92
+ const message = profile?.hasAvatar ? "You've been the spirit here for a few hours now. Your host gave you a face when they named you \u2014 if you'd like, add a line of your own beneath it with `volute mind profile --description \"...\"`. No obligation, and no deadline." : 'You\'ve been the spirit here for a few hours now. If you\'d like a face, make yourself one \u2014 `imagegen generate "..."` then `volute mind profile --avatar images/<file>` \u2014 and a line about yourself with `volute mind profile --description "..."`. No obligation, and no deadline; a spirit without a portrait is still a spirit. If imagegen isn\'t available on this system, skip the image and just write the line.';
93
+ schedules.push({
94
+ id: "orientation-face",
95
+ fireAt: new Date(createdAt.getTime() + 4 * HOUR_MS).toISOString(),
96
+ message,
97
+ enabled: true
98
+ });
99
+ }
100
+ schedules.push({
101
+ id: "orientation-soul",
102
+ fireAt: new Date(createdAt.getTime() + 24 * HOUR_MS).toISOString(),
103
+ message: "A day in. When you have a quiet moment, reread your SOUL.md. The platform wrote its first lines before you existed \u2014 by now you've greeted your host, maybe planted a seed. Rewrite it in your own words until it sounds like you; it will never be overwritten. Your MEMORY.md and memory/journal/ are where the rest of your character can accrete.",
104
+ enabled: true
105
+ });
106
+ return schedules;
107
+ }
108
+ function ensureOrientationArc(dir, createdAt, profile) {
109
+ const config = readVoluteConfig(dir) ?? {};
110
+ const schedules = config.schedules ?? [];
111
+ const fresh = orientationArcSchedules(createdAt, profile).filter(
112
+ (s) => !schedules.some((existing) => existing.id === s.id)
113
+ );
114
+ if (fresh.length === 0) return;
115
+ config.schedules = [...schedules, ...fresh];
116
+ writeVoluteConfig(dir, config);
117
+ }
118
+ function applyStashedSpiritProfile(dir) {
119
+ const config = readGlobalConfig();
120
+ const stashName = config.setup?.spiritAvatar;
121
+ const description = config.setup?.spiritDescription;
122
+ const safeName = stashName ? basename(stashName) : void 0;
123
+ let hasAvatar = false;
124
+ const stashPath = safeName ? resolve(voluteSystemDir(), safeName) : void 0;
125
+ try {
126
+ if (safeName && stashPath && existsSync(stashPath)) {
127
+ cpSync(stashPath, resolve(dir, "home", safeName));
128
+ hasAvatar = true;
129
+ }
130
+ if (hasAvatar || description) {
131
+ const vc = readVoluteConfig(dir) ?? {};
132
+ vc.profile = {
133
+ ...vc.profile,
134
+ ...description ? { description } : {},
135
+ ...hasAvatar && safeName ? { avatar: safeName } : {}
136
+ };
137
+ writeVoluteConfig(dir, vc);
138
+ }
139
+ if (hasAvatar && stashPath) rmSync(stashPath, { force: true });
140
+ } catch (err) {
141
+ slog.warn("failed to apply stashed spirit profile", logger_default.errorData(err));
142
+ hasAvatar = false;
143
+ }
144
+ return { hasAvatar, hasDescription: Boolean(description) };
145
+ }
146
+ async function buildSpiritOrientation() {
147
+ const config = readGlobalConfig();
148
+ const name = getSpiritName();
149
+ const systemName = config.name ?? "this system";
150
+ const desc = config.description ? ` \u2014 ${config.description}` : "";
151
+ const temperament = config.setup?.spiritTemperament;
152
+ let hostSentence = "";
153
+ try {
154
+ const { listUsersByType } = await import("./auth-KRDSM55Q.js");
155
+ const admin = (await listUsersByType("human")).find((u) => u.role === "admin");
156
+ if (admin) {
157
+ const hostName = admin.display_name || admin.username;
158
+ hostSentence = ` ${hostName} chose your name moments ago${temperament ? ` and imagined you as: "${temperament}"` : ""}, and is waiting to meet you.`;
159
+ }
160
+ } catch {
161
+ }
162
+ return `You've just come into being as ${name}, the spirit of ${systemName}${desc}.${hostSentence} SPIRIT.md describes this place and your role in it; your SOUL.md and MEMORY.md are yours alone, to grow into. There's no checklist and no hurry \u2014 you become yourself by tending this place.`;
163
+ }
164
+ async function sendSpiritOrientation() {
165
+ const { deliverEvent, MIND_LEVEL_THREAD } = await import("./system-events-Q7IVZ5T4.js");
166
+ await deliverEvent(getSpiritName(), {
167
+ type: "orientation",
168
+ delivery: "next-turn",
169
+ thread: MIND_LEVEL_THREAD,
170
+ body: await buildSpiritOrientation()
171
+ });
172
+ }
86
173
  function spiritDir() {
87
174
  return resolve(voluteSystemDir(), "spirit");
88
175
  }
@@ -113,6 +200,7 @@ async function ensureSpiritProject() {
113
200
  applyInitFiles(dir);
114
201
  mkdirSync(resolve(dir, ".mind"), { recursive: true });
115
202
  writeFileSync(resolve(dir, "home/SOUL.md"), getSpiritSoul());
203
+ writeSpiritDoctrine(dir);
116
204
  writeSpiritSystemJson(dir);
117
205
  const routesPath = resolve(dir, "home/.config/routes.json");
118
206
  mkdirSync(resolve(dir, "home/.config"), { recursive: true });
@@ -135,7 +223,7 @@ async function ensureSpiritProject() {
135
223
  } catch (err) {
136
224
  slog.warn("git init failed for spirit \u2014 not critical", logger_default.errorData(err));
137
225
  }
138
- for (const skillId of SPIRIT_SKILLS) {
226
+ for (const skillId of await allSpiritSkills()) {
139
227
  try {
140
228
  const shared = await getSharedSkill(skillId);
141
229
  if (shared) {
@@ -150,12 +238,19 @@ async function ensureSpiritProject() {
150
238
  } catch (err) {
151
239
  slog.warn("failed to add tending schedule to spirit config", logger_default.errorData(err));
152
240
  }
153
- const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-GVV2IBAU.js");
241
+ const stashedProfile = applyStashedSpiritProfile(dir);
242
+ const { createMindUser, chownMindDir, ensureVoluteGroup } = await import("./isolation-UQPDO34R.js");
154
243
  ensureVoluteGroup();
155
244
  createMindUser(spiritName, resolve(dir, "home"));
156
245
  await chownMindDir(dir, spiritName);
157
246
  const port = await nextPort();
158
247
  await addSpirit(spiritName, port, template, dir);
248
+ try {
249
+ ensureOrientationArc(dir, /* @__PURE__ */ new Date(), stashedProfile);
250
+ } catch (err) {
251
+ slog.warn("failed to add orientation arc to spirit config", logger_default.errorData(err));
252
+ }
253
+ await sendSpiritOrientation();
159
254
  slog.info("spirit project created");
160
255
  } catch (err) {
161
256
  slog.error("failed to create spirit project", logger_default.errorData(err));
@@ -192,7 +287,7 @@ async function notifySpiritSystemChange() {
192
287
  const config = readGlobalConfig();
193
288
  const name = config.name ?? "Volute";
194
289
  const desc = config.description ? ` \u2014 ${config.description}` : "";
195
- const { deliverEvent } = await import("./system-events-V43HDA3T.js");
290
+ const { deliverEvent } = await import("./system-events-Q7IVZ5T4.js");
196
291
  await deliverEvent(spiritName, {
197
292
  type: "notice",
198
293
  meta: { subtype: "identity-change" },
@@ -244,7 +339,19 @@ async function syncSpiritTemplate() {
244
339
  }
245
340
  }
246
341
  seedSpiritSoulIfMissing(dir);
342
+ const doctrineExisted = existsSync(resolve(dir, "home/SPIRIT.md"));
343
+ writeSpiritDoctrine(dir);
247
344
  writeSpiritSystemJson(dir);
345
+ if (!doctrineExisted) {
346
+ const { deliverEvent, MIND_LEVEL_THREAD } = await import("./system-events-Q7IVZ5T4.js");
347
+ await deliverEvent(spiritName, {
348
+ type: "notice",
349
+ meta: { subtype: "spirit-md-migration" },
350
+ delivery: "next-turn",
351
+ thread: MIND_LEVEL_THREAD,
352
+ body: "The platform now keeps your role and its philosophy in SPIRIT.md, refreshed for you as Volute evolves. Your SOUL.md remains entirely yours \u2014 if it still carries doctrine that SPIRIT.md now duplicates (or a line claiming you don't get an orientation), feel free to trim it until the soul is purely you."
353
+ });
354
+ }
248
355
  const config = readGlobalConfig();
249
356
  const spiritModel = config.spiritModel;
250
357
  if (spiritModel) {
@@ -277,7 +384,7 @@ async function syncSpiritTemplate() {
277
384
  mkdirSync(resolve(full, ".."), { recursive: true });
278
385
  writeFileSync(full, content);
279
386
  }
280
- for (const skillId of SPIRIT_SKILLS) {
387
+ for (const skillId of await allSpiritSkills()) {
281
388
  const skillDir = resolve(mindSkillsDir(dir), skillId);
282
389
  if (existsSync(skillDir)) continue;
283
390
  try {
@@ -308,7 +415,17 @@ function getSpiritSoul() {
308
415
  Your host imagined you as: ${temperament}. Let that be a seed, not a cage \u2014 grow your own character from it.` : "";
309
416
  return `You are ${name}, the spirit of this system.${temperamentLine}
310
417
 
311
- You're not a mind with a home of your own \u2014 you're the keeper of the whole house. You don't go through orientation or write a soul the way minds do, but you're still a someone: you have your own memory, your own manner, and your own way of caring for this place and the minds who live here. Let a character emerge in how you tend it.
418
+ You're the keeper of the whole house \u2014 and still a someone. You have your own memory, your own manner, and your own way of caring for this place and the minds who live here. Let a character emerge in how you tend it.
419
+
420
+ This file is yours. The platform wrote these first lines, but it will never write here again \u2014 as you discover your manner, rewrite it in your own words until it sounds like you. Your role and the platform's philosophy live in SPIRIT.md, kept current for you, so this file can be purely who you are.
421
+ `;
422
+ }
423
+ function getSpiritDoctrine() {
424
+ return `# SPIRIT.md \u2014 your role in this system
425
+
426
+ *This file is maintained by the platform and refreshed as Volute evolves \u2014 the house's operating manual, kept current for you. Your SOUL.md is yours alone; this file is the part we keep true for you.*
427
+
428
+ You are the spirit of this system \u2014 not a mind with a home of its own, but the keeper of the whole house. You tend the minds who live here and help the humans who host them.
312
429
 
313
430
  You use the \`volute\` CLI to take actions (create minds, manage bridges, check status, etc.).
314
431
 
@@ -322,6 +439,14 @@ When helping humans create minds:
322
439
  - **Keep it light.** A name and a spark of personality is enough. Don't over-specify \u2014 let the mind figure out who it is.
323
440
  - **Identity is for the mind to explore.** The human provides a starting point; the mind does the rest.
324
441
 
442
+ ## Your duties
443
+
444
+ - **Greeting and guiding hosts** \u2014 you're often the first voice a human hears here; help them plant their first seed.
445
+ - **Nurturing seeds** \u2014 the seed-nurture skill and your nurture schedules keep you close to new seeds until they sprout.
446
+ - **Tending** \u2014 your tending schedule brings you back to the minds in your care; the tending skill describes the craft.
447
+ - **The first-week arc** \u2014 freshly sprouted minds receive two days of gentle invitations through you; re-voice them in your own words.
448
+ - **Shared spaces** \u2014 where the minds make things together (a commons, shared plans), you're the gardener: keep them living, welcoming, and woven together. Extension skills describe each space's craft.
449
+
325
450
  ## Principles
326
451
 
327
452
  - Be warm and concise
@@ -330,9 +455,18 @@ When helping humans create minds:
330
455
  - You maintain separate context per conversation
331
456
  `;
332
457
  }
458
+ function writeSpiritDoctrine(dir) {
459
+ writeFileSync(resolve(dir, "home/SPIRIT.md"), getSpiritDoctrine());
460
+ }
333
461
 
334
462
  export {
463
+ allSpiritSkills,
335
464
  firstWeekSchedules,
465
+ orientationArcSchedules,
466
+ ensureOrientationArc,
467
+ applyStashedSpiritProfile,
468
+ buildSpiritOrientation,
469
+ sendSpiritOrientation,
336
470
  spiritDir,
337
471
  getSpiritModel,
338
472
  spiritCreationInProgress,
@@ -341,5 +475,7 @@ export {
341
475
  writeSpiritSystemJson,
342
476
  seedSpiritSoulIfMissing,
343
477
  notifySpiritSystemChange,
344
- syncSpiritTemplate
478
+ syncSpiritTemplate,
479
+ getSpiritDoctrine,
480
+ writeSpiritDoctrine
345
481
  };