create-egregore 0.21.6 → 0.22.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 (719) hide show
  1. package/assets/egregore-launcher.js +58 -6
  2. package/assets/egregore-launcher.sh +15 -2
  3. package/lib/claude-runtime.js +2 -0
  4. package/lib/codex-runtime.js +2 -0
  5. package/lib/setup.js +20 -3
  6. package/package.json +2 -2
  7. package/runtime/claude/.claude/context/commit-format.md +7 -4
  8. package/runtime/claude/.claude/context/handoff-claiming.md +32 -0
  9. package/runtime/claude/.claude/context/notification-consent.md +12 -9
  10. package/runtime/claude/.claude/hooks/boundary-check.sh +14 -331
  11. package/runtime/claude/.claude/hooks/memory-read-guard.sh +9 -1
  12. package/runtime/claude/.claude/rules/voice-bedrock.md +6 -2
  13. package/runtime/claude/.claude/settings.json +1 -1
  14. package/runtime/claude/.claude/skills/commit/SKILL.md +5 -3
  15. package/runtime/claude/.claude/skills/dark-mode/SKILL.md +48 -369
  16. package/runtime/claude/.claude/skills/records/SKILL.md +158 -0
  17. package/runtime/claude/.claude/skills/reflect/SKILL.md +50 -21
  18. package/runtime/claude/.claude/skills/review-pr/SKILL.md +4 -2
  19. package/runtime/claude/.claude/skills/save/SKILL.md +9 -3
  20. package/runtime/claude/.claude/skills/summon/SKILL.md +138 -207
  21. package/runtime/claude/.claude/skills/tui-design/SKILL.md +1 -1
  22. package/runtime/claude/.claude/skills/update/SKILL.md +1 -1
  23. package/runtime/claude/.claude/skills/view/SKILL.md +52 -16
  24. package/runtime/claude/.claude/skills/view/compose-scaffold.html +19 -13
  25. package/runtime/claude/CLAUDE.md +59 -95
  26. package/runtime/claude/bin/agent.sh +231 -7
  27. package/runtime/claude/bin/api-call.sh +44 -23
  28. package/runtime/claude/bin/artifact-register.sh +7 -1
  29. package/runtime/claude/bin/artifact-writeback.sh +1 -1
  30. package/runtime/claude/bin/artifacts.sh +66 -265
  31. package/runtime/claude/bin/attendant.sh +4 -1
  32. package/runtime/claude/bin/boundary-guard.cjs +1848 -0
  33. package/runtime/claude/bin/boundary-hook.sh +41 -0
  34. package/runtime/claude/bin/boundary.sh +15 -155
  35. package/runtime/claude/bin/capture-run.sh +32 -2
  36. package/runtime/claude/bin/codex-render-spec.mjs +24 -46
  37. package/runtime/claude/bin/codex-session-start.sh +19 -0
  38. package/runtime/claude/bin/codex-skill-render.mjs +18 -0
  39. package/runtime/claude/bin/config-get.sh +10 -1
  40. package/runtime/claude/bin/connect-refresh.sh +16 -0
  41. package/runtime/claude/bin/corpus_map.py +5 -0
  42. package/runtime/claude/bin/data/capabilities/claude.json +1480 -0
  43. package/runtime/claude/bin/genui.sh +19 -0
  44. package/runtime/claude/bin/graph-batch.sh +1 -1
  45. package/runtime/claude/bin/graph-op.sh +14 -0
  46. package/runtime/claude/bin/graph.sh +1 -1
  47. package/runtime/claude/bin/handoff-pr-backfill.sh +1 -1
  48. package/runtime/claude/bin/handoff-run.sh +11 -6
  49. package/runtime/claude/bin/ingest-item.sh +1 -1
  50. package/runtime/claude/bin/ingest-surface.html +22 -4
  51. package/runtime/claude/bin/issue.sh +1 -1
  52. package/runtime/claude/bin/knowledge.sh +1 -1
  53. package/runtime/claude/bin/lib/card-delivery.sh +329 -0
  54. package/runtime/claude/bin/lib/config.sh +148 -3
  55. package/runtime/claude/bin/lib/context.sh +38 -67
  56. package/runtime/claude/bin/lib/genui-entry.py +36 -0
  57. package/runtime/claude/bin/lib/git-message.sh +25 -6
  58. package/runtime/claude/bin/lib/git-sync.sh +12 -4
  59. package/runtime/claude/bin/lib/greeting.sh +255 -28
  60. package/runtime/claude/bin/lib/handoff_meta.py +294 -0
  61. package/runtime/claude/bin/lib/health-footer.sh +83 -2
  62. package/runtime/claude/bin/lib/identity.sh +31 -10
  63. package/runtime/claude/bin/lib/instance-registry.sh +71 -0
  64. package/runtime/claude/bin/lib/local_ci_receipt.py +249 -0
  65. package/runtime/claude/bin/lib/metrics.sh +121 -8
  66. package/runtime/claude/bin/lib/notices.sh +36 -0
  67. package/runtime/claude/bin/lib/record_outcomes.py +729 -0
  68. package/runtime/claude/bin/lib/reflexes.py +267 -0
  69. package/runtime/claude/bin/lib/retrieval_scorecard.py +624 -0
  70. package/runtime/claude/bin/lib/session-record-prompt.txt +18 -0
  71. package/runtime/claude/bin/lib/session_record.py +3747 -0
  72. package/runtime/claude/bin/lib/session_trail.py +1983 -0
  73. package/runtime/claude/bin/lib/settings-drift.sh +8 -5
  74. package/runtime/claude/bin/lib/startup-restart.sh +41 -0
  75. package/runtime/claude/bin/lib/worktree-links.sh +92 -0
  76. package/runtime/claude/bin/memory-push.sh +6 -0
  77. package/runtime/claude/bin/merge-gate.sh +498 -0
  78. package/runtime/claude/bin/notify.sh +5 -2
  79. package/runtime/claude/bin/page-access.sh +103 -0
  80. package/runtime/claude/bin/person.sh +13 -2
  81. package/runtime/claude/bin/pi-render-spec.mjs +0 -1
  82. package/runtime/claude/bin/pi-spirit-discovery.mjs +34 -0
  83. package/runtime/claude/bin/post-update.sh +181 -0
  84. package/runtime/claude/bin/prime-render-spec.mjs +0 -1
  85. package/runtime/claude/bin/publish-artifact.sh +89 -42
  86. package/runtime/claude/bin/qa-inventory.sh +2 -2
  87. package/runtime/claude/bin/quest.sh +1 -1
  88. package/runtime/claude/bin/records.sh +11 -0
  89. package/runtime/claude/bin/reflexes/05-vitals.sh +9 -0
  90. package/runtime/claude/bin/reflexes/10-open-items.sh +12 -0
  91. package/runtime/claude/bin/reflexes/15-retrieval.sh +8 -0
  92. package/runtime/claude/bin/reflexes/20-nightly.sh +100 -0
  93. package/runtime/claude/bin/reflexes/20-sandbox.sh +85 -0
  94. package/runtime/claude/bin/reflexes/30-cost.py +116 -0
  95. package/runtime/claude/bin/reflexes/40-shells.py +51 -0
  96. package/runtime/claude/bin/reflexes/README.md +61 -0
  97. package/runtime/claude/bin/reflexes.sh +7 -0
  98. package/runtime/claude/bin/runtime-identity.sh +140 -42
  99. package/runtime/claude/bin/screenshot.sh +77 -0
  100. package/runtime/claude/bin/scroll.sh +1 -1
  101. package/runtime/claude/bin/search.sh +31 -5
  102. package/runtime/claude/bin/session-autosave.sh +6 -3
  103. package/runtime/claude/bin/session-id.sh +147 -0
  104. package/runtime/claude/bin/session-log.sh +19 -0
  105. package/runtime/claude/bin/session-record.sh +26 -0
  106. package/runtime/claude/bin/session-start.sh +121 -151
  107. package/runtime/claude/bin/settings.sh +13 -8
  108. package/runtime/claude/bin/spirit-discovery-claude.sh +4 -0
  109. package/runtime/claude/bin/spirit-discovery-codex.sh +4 -0
  110. package/runtime/claude/bin/spirit-discovery-pi.sh +4 -0
  111. package/runtime/claude/bin/spirit-discovery-prime.sh +4 -0
  112. package/runtime/claude/bin/spirit-discovery.sh +4 -0
  113. package/runtime/claude/bin/startup-check.sh +1 -1
  114. package/runtime/claude/bin/telemetry.sh +11 -4
  115. package/runtime/claude/bin/test-baseline.sh +33 -5
  116. package/runtime/claude/bin/todo.sh +1 -1
  117. package/runtime/claude/bin/worktree-create.sh +15 -45
  118. package/runtime/claude/bin/worktree.sh +6 -0
  119. package/runtime/claude/docs/spirit-discovery.md +96 -0
  120. package/runtime/claude/egregore_runtime/__init__.py +18 -12
  121. package/runtime/claude/egregore_runtime/access.py +608 -0
  122. package/runtime/claude/egregore_runtime/access_cli.py +190 -0
  123. package/runtime/claude/egregore_runtime/adapters/invitation.py +5 -3
  124. package/runtime/claude/egregore_runtime/adapters/qmd.py +521 -47
  125. package/runtime/claude/egregore_runtime/admin_entry.py +56 -0
  126. package/runtime/claude/egregore_runtime/artifacts.py +222 -16
  127. package/runtime/claude/egregore_runtime/contracts.py +27 -0
  128. package/runtime/claude/egregore_runtime/eligibility.py +5 -12
  129. package/runtime/claude/egregore_runtime/episode_binding.py +16 -5
  130. package/runtime/claude/egregore_runtime/github_issues.py +2 -2
  131. package/runtime/claude/egregore_runtime/handoff_lookup.py +9 -20
  132. package/runtime/claude/egregore_runtime/harness_cli.py +674 -149
  133. package/runtime/claude/egregore_runtime/held.py +2436 -0
  134. package/runtime/claude/egregore_runtime/hosted_api.py +137 -0
  135. package/runtime/claude/egregore_runtime/identity.py +196 -65
  136. package/runtime/claude/egregore_runtime/identity_transfer.py +6 -2
  137. package/runtime/claude/egregore_runtime/ingest_cli.py +2 -2
  138. package/runtime/claude/egregore_runtime/ingest_index_cli.py +4 -16
  139. package/runtime/claude/egregore_runtime/installation.py +119 -0
  140. package/runtime/claude/egregore_runtime/investigation.py +64 -41
  141. package/runtime/claude/egregore_runtime/investigation_guidance.py +16 -11
  142. package/runtime/claude/egregore_runtime/issue_cli.py +51 -32
  143. package/runtime/claude/egregore_runtime/issue_reporting.py +4 -3
  144. package/runtime/claude/egregore_runtime/issue_triage_service.py +2 -2
  145. package/runtime/claude/egregore_runtime/issues.py +12 -6
  146. package/runtime/claude/egregore_runtime/knowledge.py +331 -5
  147. package/runtime/claude/egregore_runtime/knowledge_cli.py +57 -17
  148. package/runtime/claude/egregore_runtime/lifecycle.py +88 -22
  149. package/runtime/claude/egregore_runtime/lifecycle_cli.py +21 -13
  150. package/runtime/claude/egregore_runtime/line_ids.py +10 -0
  151. package/runtime/claude/egregore_runtime/memory_push.py +349 -0
  152. package/runtime/claude/egregore_runtime/observe.py +64 -25
  153. package/runtime/claude/egregore_runtime/observers.py +19 -0
  154. package/runtime/claude/egregore_runtime/optional_modules.py +13 -0
  155. package/runtime/claude/egregore_runtime/outputs_cli.py +321 -0
  156. package/runtime/claude/egregore_runtime/policy.py +651 -24
  157. package/runtime/claude/egregore_runtime/private_result.py +2 -1
  158. package/runtime/claude/egregore_runtime/projection.py +946 -0
  159. package/runtime/claude/egregore_runtime/quest_cli.py +20 -23
  160. package/runtime/claude/egregore_runtime/question_cli.py +15 -11
  161. package/runtime/claude/egregore_runtime/questions.py +10 -10
  162. package/runtime/claude/egregore_runtime/quests.py +10 -10
  163. package/runtime/claude/egregore_runtime/record_publish.py +548 -0
  164. package/runtime/claude/egregore_runtime/record_subject.py +564 -0
  165. package/runtime/claude/egregore_runtime/research_ingest.py +2 -4
  166. package/runtime/claude/egregore_runtime/runtime.py +169 -60
  167. package/runtime/claude/egregore_runtime/sandbox.py +194 -0
  168. package/runtime/claude/egregore_runtime/scroll_cli.py +22 -32
  169. package/runtime/claude/egregore_runtime/scrolls.py +23 -15
  170. package/runtime/claude/egregore_runtime/shadow.py +262 -0
  171. package/runtime/claude/egregore_runtime/spirit_discovery.py +487 -0
  172. package/runtime/claude/egregore_runtime/spirit_discovery_cli.py +25 -0
  173. package/runtime/claude/egregore_runtime/spirit_discovery_transport.py +18 -0
  174. package/runtime/claude/egregore_runtime/status.py +101 -44
  175. package/runtime/claude/egregore_runtime/status_cli.py +13 -5
  176. package/runtime/claude/egregore_runtime/sync.py +39 -21
  177. package/runtime/claude/egregore_runtime/taste.py +934 -0
  178. package/runtime/claude/egregore_runtime/taste_cli.py +242 -0
  179. package/runtime/claude/egregore_runtime/taste_rules.py +91 -0
  180. package/runtime/claude/egregore_runtime/telemetry.py +26 -3
  181. package/runtime/claude/egregore_runtime/todo_cli.py +15 -12
  182. package/runtime/claude/egregore_runtime/todos.py +3 -2
  183. package/runtime/claude/egregore_runtime/upgrade.py +85 -58
  184. package/runtime/claude/egregore_runtime/writeback.py +330 -24
  185. package/runtime/claude/manifest.json +65 -5
  186. package/runtime/codex/.claude/context/handoff-claiming.md +32 -0
  187. package/runtime/codex/.claude/context/notification-consent.md +12 -9
  188. package/runtime/codex/.claude/skills/view/SKILL.md +438 -0
  189. package/runtime/codex/.codex/hooks.json +11 -0
  190. package/runtime/codex/.codex/skills/dark-mode/SKILL.md +1 -1
  191. package/runtime/codex/.codex/skills/records/SKILL.md +29 -0
  192. package/runtime/codex/.codex/skills/summon/SKILL.md +1 -1
  193. package/runtime/codex/.codex/skills/view/assets/compose-scaffold.html +19 -13
  194. package/runtime/codex/.codex/spec-manifest.json +13 -19
  195. package/runtime/codex/AGENTS.md +54 -105
  196. package/runtime/codex/bin/agent.sh +231 -7
  197. package/runtime/codex/bin/api-call.sh +44 -23
  198. package/runtime/codex/bin/artifact-register.sh +7 -1
  199. package/runtime/codex/bin/artifact-writeback.sh +1 -1
  200. package/runtime/codex/bin/artifacts.sh +66 -265
  201. package/runtime/codex/bin/attendant.sh +4 -1
  202. package/runtime/codex/bin/boundary-guard.cjs +1848 -0
  203. package/runtime/codex/bin/boundary-hook.sh +41 -0
  204. package/runtime/codex/bin/capture-run.sh +32 -2
  205. package/runtime/codex/bin/codex-render-spec.mjs +24 -46
  206. package/runtime/codex/bin/codex-session-start.sh +19 -0
  207. package/runtime/codex/bin/codex-skill-render.mjs +18 -0
  208. package/runtime/codex/bin/config-get.sh +10 -1
  209. package/runtime/codex/bin/connect-refresh.sh +16 -0
  210. package/runtime/codex/bin/corpus_map.py +5 -0
  211. package/runtime/codex/bin/data/capabilities/codex.json +1458 -0
  212. package/runtime/codex/bin/genui.sh +19 -0
  213. package/runtime/codex/bin/graph-batch.sh +1 -1
  214. package/runtime/codex/bin/graph-op.sh +14 -0
  215. package/runtime/codex/bin/graph.sh +1 -1
  216. package/runtime/codex/bin/handoff-pr-backfill.sh +1 -1
  217. package/runtime/codex/bin/handoff-run.sh +11 -6
  218. package/runtime/codex/bin/ingest-item.sh +1 -1
  219. package/runtime/codex/bin/ingest-surface.html +22 -4
  220. package/runtime/codex/bin/issue.sh +1 -1
  221. package/runtime/codex/bin/knowledge.sh +1 -1
  222. package/runtime/codex/bin/lib/card-delivery.sh +329 -0
  223. package/runtime/codex/bin/lib/config.sh +148 -3
  224. package/runtime/codex/bin/lib/context.sh +38 -67
  225. package/runtime/codex/bin/lib/genui-entry.py +36 -0
  226. package/runtime/codex/bin/lib/git-message.sh +25 -6
  227. package/runtime/codex/bin/lib/git-sync.sh +12 -4
  228. package/runtime/codex/bin/lib/greeting.sh +255 -28
  229. package/runtime/codex/bin/lib/handoff_meta.py +294 -0
  230. package/runtime/codex/bin/lib/health-footer.sh +83 -2
  231. package/runtime/codex/bin/lib/identity.sh +31 -10
  232. package/runtime/codex/bin/lib/instance-registry.sh +71 -0
  233. package/runtime/codex/bin/lib/local_ci_receipt.py +249 -0
  234. package/runtime/codex/bin/lib/metrics.sh +121 -8
  235. package/runtime/codex/bin/lib/notices.sh +36 -0
  236. package/runtime/codex/bin/lib/record_outcomes.py +729 -0
  237. package/runtime/codex/bin/lib/reflexes.py +267 -0
  238. package/runtime/codex/bin/lib/retrieval_scorecard.py +624 -0
  239. package/runtime/codex/bin/lib/session-record-prompt.txt +18 -0
  240. package/runtime/codex/bin/lib/session_record.py +3747 -0
  241. package/runtime/codex/bin/lib/session_trail.py +1983 -0
  242. package/runtime/codex/bin/lib/settings-drift.sh +8 -5
  243. package/runtime/codex/bin/lib/startup-restart.sh +41 -0
  244. package/runtime/codex/bin/lib/worktree-links.sh +92 -0
  245. package/runtime/codex/bin/memory-push.sh +6 -0
  246. package/runtime/codex/bin/merge-gate.sh +498 -0
  247. package/runtime/codex/bin/notify.sh +5 -2
  248. package/runtime/codex/bin/page-access.sh +103 -0
  249. package/runtime/codex/bin/person.sh +13 -2
  250. package/runtime/codex/bin/pi-render-spec.mjs +0 -1
  251. package/runtime/codex/bin/pi-spirit-discovery.mjs +34 -0
  252. package/runtime/codex/bin/post-update.sh +181 -0
  253. package/runtime/codex/bin/prime-render-spec.mjs +0 -1
  254. package/runtime/codex/bin/publish-artifact.sh +89 -42
  255. package/runtime/codex/bin/qa-inventory.sh +2 -2
  256. package/runtime/codex/bin/quest.sh +1 -1
  257. package/runtime/codex/bin/records.sh +11 -0
  258. package/runtime/codex/bin/reflexes/05-vitals.sh +9 -0
  259. package/runtime/codex/bin/reflexes/10-open-items.sh +12 -0
  260. package/runtime/codex/bin/reflexes/15-retrieval.sh +8 -0
  261. package/runtime/codex/bin/reflexes/20-nightly.sh +100 -0
  262. package/runtime/codex/bin/reflexes/20-sandbox.sh +85 -0
  263. package/runtime/codex/bin/reflexes/30-cost.py +116 -0
  264. package/runtime/codex/bin/reflexes/40-shells.py +51 -0
  265. package/runtime/codex/bin/reflexes/README.md +61 -0
  266. package/runtime/codex/bin/reflexes.sh +7 -0
  267. package/runtime/codex/bin/runtime-identity.sh +140 -42
  268. package/runtime/codex/bin/screenshot.sh +77 -0
  269. package/runtime/codex/bin/scroll.sh +1 -1
  270. package/runtime/codex/bin/search.sh +31 -5
  271. package/runtime/codex/bin/session-autosave.sh +6 -3
  272. package/runtime/codex/bin/session-id.sh +147 -0
  273. package/runtime/codex/bin/session-log.sh +19 -0
  274. package/runtime/codex/bin/session-record.sh +26 -0
  275. package/runtime/codex/bin/settings.sh +13 -8
  276. package/runtime/codex/bin/spirit-discovery-claude.sh +4 -0
  277. package/runtime/codex/bin/spirit-discovery-codex.sh +4 -0
  278. package/runtime/codex/bin/spirit-discovery-pi.sh +4 -0
  279. package/runtime/codex/bin/spirit-discovery-prime.sh +4 -0
  280. package/runtime/codex/bin/spirit-discovery.sh +4 -0
  281. package/runtime/codex/bin/startup-check.sh +1 -1
  282. package/runtime/codex/bin/telemetry.sh +11 -4
  283. package/runtime/codex/bin/test-baseline.sh +33 -5
  284. package/runtime/codex/bin/todo.sh +1 -1
  285. package/runtime/codex/bin/worktree-create.sh +15 -45
  286. package/runtime/codex/bin/worktree.sh +6 -0
  287. package/runtime/codex/docs/spirit-discovery.md +96 -0
  288. package/runtime/codex/egregore_runtime/__init__.py +18 -12
  289. package/runtime/codex/egregore_runtime/access.py +608 -0
  290. package/runtime/codex/egregore_runtime/access_cli.py +190 -0
  291. package/runtime/codex/egregore_runtime/adapters/invitation.py +5 -3
  292. package/runtime/codex/egregore_runtime/adapters/qmd.py +521 -47
  293. package/runtime/codex/egregore_runtime/admin_entry.py +56 -0
  294. package/runtime/codex/egregore_runtime/artifacts.py +222 -16
  295. package/runtime/codex/egregore_runtime/contracts.py +27 -0
  296. package/runtime/codex/egregore_runtime/eligibility.py +5 -12
  297. package/runtime/codex/egregore_runtime/episode_binding.py +16 -5
  298. package/runtime/codex/egregore_runtime/github_issues.py +2 -2
  299. package/runtime/codex/egregore_runtime/handoff_lookup.py +9 -20
  300. package/runtime/codex/egregore_runtime/harness_cli.py +674 -149
  301. package/runtime/codex/egregore_runtime/held.py +2436 -0
  302. package/runtime/codex/egregore_runtime/hosted_api.py +137 -0
  303. package/runtime/codex/egregore_runtime/identity.py +196 -65
  304. package/runtime/codex/egregore_runtime/identity_transfer.py +6 -2
  305. package/runtime/codex/egregore_runtime/ingest_cli.py +2 -2
  306. package/runtime/codex/egregore_runtime/ingest_index_cli.py +4 -16
  307. package/runtime/codex/egregore_runtime/installation.py +119 -0
  308. package/runtime/codex/egregore_runtime/investigation.py +64 -41
  309. package/runtime/codex/egregore_runtime/investigation_guidance.py +16 -11
  310. package/runtime/codex/egregore_runtime/issue_cli.py +51 -32
  311. package/runtime/codex/egregore_runtime/issue_reporting.py +4 -3
  312. package/runtime/codex/egregore_runtime/issue_triage_service.py +2 -2
  313. package/runtime/codex/egregore_runtime/issues.py +12 -6
  314. package/runtime/codex/egregore_runtime/knowledge.py +331 -5
  315. package/runtime/codex/egregore_runtime/knowledge_cli.py +57 -17
  316. package/runtime/codex/egregore_runtime/lifecycle.py +88 -22
  317. package/runtime/codex/egregore_runtime/lifecycle_cli.py +21 -13
  318. package/runtime/codex/egregore_runtime/line_ids.py +10 -0
  319. package/runtime/codex/egregore_runtime/memory_push.py +349 -0
  320. package/runtime/codex/egregore_runtime/observe.py +64 -25
  321. package/runtime/codex/egregore_runtime/observers.py +19 -0
  322. package/runtime/codex/egregore_runtime/optional_modules.py +13 -0
  323. package/runtime/codex/egregore_runtime/outputs_cli.py +321 -0
  324. package/runtime/codex/egregore_runtime/policy.py +651 -24
  325. package/runtime/codex/egregore_runtime/private_result.py +2 -1
  326. package/runtime/codex/egregore_runtime/projection.py +946 -0
  327. package/runtime/codex/egregore_runtime/quest_cli.py +20 -23
  328. package/runtime/codex/egregore_runtime/question_cli.py +15 -11
  329. package/runtime/codex/egregore_runtime/questions.py +10 -10
  330. package/runtime/codex/egregore_runtime/quests.py +10 -10
  331. package/runtime/codex/egregore_runtime/record_publish.py +548 -0
  332. package/runtime/codex/egregore_runtime/record_subject.py +564 -0
  333. package/runtime/codex/egregore_runtime/research_ingest.py +2 -4
  334. package/runtime/codex/egregore_runtime/runtime.py +169 -60
  335. package/runtime/codex/egregore_runtime/sandbox.py +194 -0
  336. package/runtime/codex/egregore_runtime/scroll_cli.py +22 -32
  337. package/runtime/codex/egregore_runtime/scrolls.py +23 -15
  338. package/runtime/codex/egregore_runtime/shadow.py +262 -0
  339. package/runtime/codex/egregore_runtime/spirit_discovery.py +487 -0
  340. package/runtime/codex/egregore_runtime/spirit_discovery_cli.py +25 -0
  341. package/runtime/codex/egregore_runtime/spirit_discovery_transport.py +18 -0
  342. package/runtime/codex/egregore_runtime/status.py +101 -44
  343. package/runtime/codex/egregore_runtime/status_cli.py +13 -5
  344. package/runtime/codex/egregore_runtime/sync.py +39 -21
  345. package/runtime/codex/egregore_runtime/taste.py +934 -0
  346. package/runtime/codex/egregore_runtime/taste_cli.py +242 -0
  347. package/runtime/codex/egregore_runtime/taste_rules.py +91 -0
  348. package/runtime/codex/egregore_runtime/telemetry.py +26 -3
  349. package/runtime/codex/egregore_runtime/todo_cli.py +15 -12
  350. package/runtime/codex/egregore_runtime/todos.py +3 -2
  351. package/runtime/codex/egregore_runtime/upgrade.py +85 -58
  352. package/runtime/codex/egregore_runtime/writeback.py +330 -24
  353. package/runtime/codex/manifest.json +66 -5
  354. package/runtime/pi/.claude/context/handoff-claiming.md +32 -0
  355. package/runtime/pi/.claude/context/notification-consent.md +12 -9
  356. package/runtime/pi/.claude/skills/view/SKILL.md +438 -0
  357. package/runtime/pi/.codex/hooks.json +11 -0
  358. package/runtime/pi/.codex/skills/dark-mode/SKILL.md +1 -1
  359. package/runtime/pi/.codex/skills/records/SKILL.md +29 -0
  360. package/runtime/pi/.codex/skills/summon/SKILL.md +1 -1
  361. package/runtime/pi/.codex/skills/view/assets/compose-scaffold.html +19 -13
  362. package/runtime/pi/.codex/spec-manifest.json +13 -19
  363. package/runtime/pi/.pi/APPEND_SYSTEM.md +53 -99
  364. package/runtime/pi/.pi/extensions/egregore.ts +13 -1
  365. package/runtime/pi/.pi/spec-manifest.json +2 -2
  366. package/runtime/pi/AGENTS.md +54 -105
  367. package/runtime/pi/bin/agent.sh +231 -7
  368. package/runtime/pi/bin/api-call.sh +44 -23
  369. package/runtime/pi/bin/artifact-register.sh +7 -1
  370. package/runtime/pi/bin/artifact-writeback.sh +1 -1
  371. package/runtime/pi/bin/artifacts.sh +66 -265
  372. package/runtime/pi/bin/attendant.sh +4 -1
  373. package/runtime/pi/bin/boundary-guard.cjs +1848 -0
  374. package/runtime/pi/bin/boundary-hook.sh +41 -0
  375. package/runtime/pi/bin/capture-run.sh +32 -2
  376. package/runtime/pi/bin/codex-render-spec.mjs +24 -46
  377. package/runtime/pi/bin/codex-session-start.sh +19 -0
  378. package/runtime/pi/bin/codex-skill-render.mjs +18 -0
  379. package/runtime/pi/bin/config-get.sh +10 -1
  380. package/runtime/pi/bin/connect-refresh.sh +16 -0
  381. package/runtime/pi/bin/corpus_map.py +5 -0
  382. package/runtime/pi/bin/data/capabilities/pi.json +1458 -0
  383. package/runtime/pi/bin/genui.sh +19 -0
  384. package/runtime/pi/bin/graph-batch.sh +1 -1
  385. package/runtime/pi/bin/graph-op.sh +14 -0
  386. package/runtime/pi/bin/graph.sh +1 -1
  387. package/runtime/pi/bin/handoff-pr-backfill.sh +1 -1
  388. package/runtime/pi/bin/handoff-run.sh +11 -6
  389. package/runtime/pi/bin/ingest-item.sh +1 -1
  390. package/runtime/pi/bin/ingest-surface.html +22 -4
  391. package/runtime/pi/bin/issue.sh +1 -1
  392. package/runtime/pi/bin/knowledge.sh +1 -1
  393. package/runtime/pi/bin/lib/card-delivery.sh +329 -0
  394. package/runtime/pi/bin/lib/config.sh +148 -3
  395. package/runtime/pi/bin/lib/context.sh +38 -67
  396. package/runtime/pi/bin/lib/genui-entry.py +36 -0
  397. package/runtime/pi/bin/lib/git-message.sh +25 -6
  398. package/runtime/pi/bin/lib/git-sync.sh +12 -4
  399. package/runtime/pi/bin/lib/greeting.sh +255 -28
  400. package/runtime/pi/bin/lib/handoff_meta.py +294 -0
  401. package/runtime/pi/bin/lib/health-footer.sh +83 -2
  402. package/runtime/pi/bin/lib/identity.sh +31 -10
  403. package/runtime/pi/bin/lib/instance-registry.sh +71 -0
  404. package/runtime/pi/bin/lib/local_ci_receipt.py +249 -0
  405. package/runtime/pi/bin/lib/metrics.sh +121 -8
  406. package/runtime/pi/bin/lib/notices.sh +36 -0
  407. package/runtime/pi/bin/lib/record_outcomes.py +729 -0
  408. package/runtime/pi/bin/lib/reflexes.py +267 -0
  409. package/runtime/pi/bin/lib/retrieval_scorecard.py +624 -0
  410. package/runtime/pi/bin/lib/session-record-prompt.txt +18 -0
  411. package/runtime/pi/bin/lib/session_record.py +3747 -0
  412. package/runtime/pi/bin/lib/session_trail.py +1983 -0
  413. package/runtime/pi/bin/lib/settings-drift.sh +8 -5
  414. package/runtime/pi/bin/lib/startup-restart.sh +41 -0
  415. package/runtime/pi/bin/lib/worktree-links.sh +92 -0
  416. package/runtime/pi/bin/memory-push.sh +6 -0
  417. package/runtime/pi/bin/merge-gate.sh +498 -0
  418. package/runtime/pi/bin/notify.sh +5 -2
  419. package/runtime/pi/bin/page-access.sh +103 -0
  420. package/runtime/pi/bin/person.sh +13 -2
  421. package/runtime/pi/bin/pi-branch-policy.mjs +37 -0
  422. package/runtime/pi/bin/pi-observe-context.mjs +97 -4
  423. package/runtime/pi/bin/pi-render-spec.mjs +0 -1
  424. package/runtime/pi/bin/pi-session-start.sh +4 -1
  425. package/runtime/pi/bin/pi-spirit-discovery.mjs +34 -0
  426. package/runtime/pi/bin/post-update.sh +181 -0
  427. package/runtime/pi/bin/prime-render-spec.mjs +0 -1
  428. package/runtime/pi/bin/publish-artifact.sh +89 -42
  429. package/runtime/pi/bin/qa-inventory.sh +2 -2
  430. package/runtime/pi/bin/quest.sh +1 -1
  431. package/runtime/pi/bin/records.sh +11 -0
  432. package/runtime/pi/bin/reflexes/05-vitals.sh +9 -0
  433. package/runtime/pi/bin/reflexes/10-open-items.sh +12 -0
  434. package/runtime/pi/bin/reflexes/15-retrieval.sh +8 -0
  435. package/runtime/pi/bin/reflexes/20-nightly.sh +100 -0
  436. package/runtime/pi/bin/reflexes/20-sandbox.sh +85 -0
  437. package/runtime/pi/bin/reflexes/30-cost.py +116 -0
  438. package/runtime/pi/bin/reflexes/40-shells.py +51 -0
  439. package/runtime/pi/bin/reflexes/README.md +61 -0
  440. package/runtime/pi/bin/reflexes.sh +7 -0
  441. package/runtime/pi/bin/runtime-identity.sh +140 -42
  442. package/runtime/pi/bin/screenshot.sh +77 -0
  443. package/runtime/pi/bin/scroll.sh +1 -1
  444. package/runtime/pi/bin/search.sh +31 -5
  445. package/runtime/pi/bin/session-autosave.sh +6 -3
  446. package/runtime/pi/bin/session-id.sh +147 -0
  447. package/runtime/pi/bin/session-log.sh +19 -0
  448. package/runtime/pi/bin/session-record.sh +26 -0
  449. package/runtime/pi/bin/settings.sh +13 -8
  450. package/runtime/pi/bin/spirit-discovery-claude.sh +4 -0
  451. package/runtime/pi/bin/spirit-discovery-codex.sh +4 -0
  452. package/runtime/pi/bin/spirit-discovery-pi.sh +4 -0
  453. package/runtime/pi/bin/spirit-discovery-prime.sh +4 -0
  454. package/runtime/pi/bin/spirit-discovery.sh +4 -0
  455. package/runtime/pi/bin/startup-check.sh +1 -1
  456. package/runtime/pi/bin/telemetry.sh +11 -4
  457. package/runtime/pi/bin/test-baseline.sh +33 -5
  458. package/runtime/pi/bin/todo.sh +1 -1
  459. package/runtime/pi/bin/worktree-create.sh +15 -45
  460. package/runtime/pi/bin/worktree.sh +6 -0
  461. package/runtime/pi/docs/spirit-discovery.md +96 -0
  462. package/runtime/pi/egregore_runtime/__init__.py +18 -12
  463. package/runtime/pi/egregore_runtime/access.py +608 -0
  464. package/runtime/pi/egregore_runtime/access_cli.py +190 -0
  465. package/runtime/pi/egregore_runtime/adapters/invitation.py +5 -3
  466. package/runtime/pi/egregore_runtime/adapters/qmd.py +521 -47
  467. package/runtime/pi/egregore_runtime/admin_entry.py +56 -0
  468. package/runtime/pi/egregore_runtime/artifacts.py +222 -16
  469. package/runtime/pi/egregore_runtime/contracts.py +27 -0
  470. package/runtime/pi/egregore_runtime/eligibility.py +5 -12
  471. package/runtime/pi/egregore_runtime/episode_binding.py +16 -5
  472. package/runtime/pi/egregore_runtime/github_issues.py +2 -2
  473. package/runtime/pi/egregore_runtime/handoff_lookup.py +9 -20
  474. package/runtime/pi/egregore_runtime/harness_cli.py +674 -149
  475. package/runtime/pi/egregore_runtime/held.py +2436 -0
  476. package/runtime/pi/egregore_runtime/hosted_api.py +137 -0
  477. package/runtime/pi/egregore_runtime/identity.py +196 -65
  478. package/runtime/pi/egregore_runtime/identity_transfer.py +6 -2
  479. package/runtime/pi/egregore_runtime/ingest_cli.py +2 -2
  480. package/runtime/pi/egregore_runtime/ingest_index_cli.py +4 -16
  481. package/runtime/pi/egregore_runtime/installation.py +119 -0
  482. package/runtime/pi/egregore_runtime/investigation.py +64 -41
  483. package/runtime/pi/egregore_runtime/investigation_guidance.py +16 -11
  484. package/runtime/pi/egregore_runtime/issue_cli.py +51 -32
  485. package/runtime/pi/egregore_runtime/issue_reporting.py +4 -3
  486. package/runtime/pi/egregore_runtime/issue_triage_service.py +2 -2
  487. package/runtime/pi/egregore_runtime/issues.py +12 -6
  488. package/runtime/pi/egregore_runtime/knowledge.py +331 -5
  489. package/runtime/pi/egregore_runtime/knowledge_cli.py +57 -17
  490. package/runtime/pi/egregore_runtime/lifecycle.py +88 -22
  491. package/runtime/pi/egregore_runtime/lifecycle_cli.py +21 -13
  492. package/runtime/pi/egregore_runtime/line_ids.py +10 -0
  493. package/runtime/pi/egregore_runtime/memory_push.py +349 -0
  494. package/runtime/pi/egregore_runtime/observe.py +64 -25
  495. package/runtime/pi/egregore_runtime/observers.py +19 -0
  496. package/runtime/pi/egregore_runtime/optional_modules.py +13 -0
  497. package/runtime/pi/egregore_runtime/outputs_cli.py +321 -0
  498. package/runtime/pi/egregore_runtime/policy.py +651 -24
  499. package/runtime/pi/egregore_runtime/private_result.py +2 -1
  500. package/runtime/pi/egregore_runtime/projection.py +946 -0
  501. package/runtime/pi/egregore_runtime/quest_cli.py +20 -23
  502. package/runtime/pi/egregore_runtime/question_cli.py +15 -11
  503. package/runtime/pi/egregore_runtime/questions.py +10 -10
  504. package/runtime/pi/egregore_runtime/quests.py +10 -10
  505. package/runtime/pi/egregore_runtime/record_publish.py +548 -0
  506. package/runtime/pi/egregore_runtime/record_subject.py +564 -0
  507. package/runtime/pi/egregore_runtime/research_ingest.py +2 -4
  508. package/runtime/pi/egregore_runtime/runtime.py +169 -60
  509. package/runtime/pi/egregore_runtime/sandbox.py +194 -0
  510. package/runtime/pi/egregore_runtime/scroll_cli.py +22 -32
  511. package/runtime/pi/egregore_runtime/scrolls.py +23 -15
  512. package/runtime/pi/egregore_runtime/shadow.py +262 -0
  513. package/runtime/pi/egregore_runtime/spirit_discovery.py +487 -0
  514. package/runtime/pi/egregore_runtime/spirit_discovery_cli.py +25 -0
  515. package/runtime/pi/egregore_runtime/spirit_discovery_transport.py +18 -0
  516. package/runtime/pi/egregore_runtime/status.py +101 -44
  517. package/runtime/pi/egregore_runtime/status_cli.py +13 -5
  518. package/runtime/pi/egregore_runtime/sync.py +39 -21
  519. package/runtime/pi/egregore_runtime/taste.py +934 -0
  520. package/runtime/pi/egregore_runtime/taste_cli.py +242 -0
  521. package/runtime/pi/egregore_runtime/taste_rules.py +91 -0
  522. package/runtime/pi/egregore_runtime/telemetry.py +26 -3
  523. package/runtime/pi/egregore_runtime/todo_cli.py +15 -12
  524. package/runtime/pi/egregore_runtime/todos.py +3 -2
  525. package/runtime/pi/egregore_runtime/upgrade.py +85 -58
  526. package/runtime/pi/egregore_runtime/writeback.py +330 -24
  527. package/runtime/pi/manifest.json +66 -5
  528. package/runtime/prime/.claude/context/handoff-claiming.md +32 -0
  529. package/runtime/prime/.claude/context/notification-consent.md +12 -9
  530. package/runtime/prime/.claude/skills/view/SKILL.md +438 -0
  531. package/runtime/prime/.codex/hooks.json +11 -0
  532. package/runtime/prime/.codex/skills/dark-mode/SKILL.md +1 -1
  533. package/runtime/prime/.codex/skills/records/SKILL.md +29 -0
  534. package/runtime/prime/.codex/skills/summon/SKILL.md +1 -1
  535. package/runtime/prime/.codex/skills/view/assets/compose-scaffold.html +19 -13
  536. package/runtime/prime/.codex/spec-manifest.json +13 -19
  537. package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +53 -99
  538. package/runtime/prime/.prime/agent/extensions/egregore.ts +14 -1
  539. package/runtime/prime/.prime/agent/skills/egregore/SKILL.md +14 -6
  540. package/runtime/prime/.prime/agent/skills/egregore/src/egregore/__init__.py +66 -1
  541. package/runtime/prime/.prime/agent/spec-manifest.json +2 -2
  542. package/runtime/prime/AGENTS.md +54 -105
  543. package/runtime/prime/bin/agent.sh +231 -7
  544. package/runtime/prime/bin/api-call.sh +44 -23
  545. package/runtime/prime/bin/artifact-register.sh +7 -1
  546. package/runtime/prime/bin/artifact-writeback.sh +1 -1
  547. package/runtime/prime/bin/artifacts.sh +66 -265
  548. package/runtime/prime/bin/attendant.sh +4 -1
  549. package/runtime/prime/bin/boundary-guard.cjs +1848 -0
  550. package/runtime/prime/bin/boundary-hook.sh +41 -0
  551. package/runtime/prime/bin/capture-run.sh +32 -2
  552. package/runtime/prime/bin/codex-render-spec.mjs +24 -46
  553. package/runtime/prime/bin/codex-session-start.sh +19 -0
  554. package/runtime/prime/bin/codex-skill-render.mjs +18 -0
  555. package/runtime/prime/bin/config-get.sh +10 -1
  556. package/runtime/prime/bin/connect-refresh.sh +16 -0
  557. package/runtime/prime/bin/corpus_map.py +5 -0
  558. package/runtime/prime/bin/data/capabilities/prime.json +1458 -0
  559. package/runtime/prime/bin/genui.sh +19 -0
  560. package/runtime/prime/bin/graph-batch.sh +1 -1
  561. package/runtime/prime/bin/graph-op.sh +14 -0
  562. package/runtime/prime/bin/graph.sh +1 -1
  563. package/runtime/prime/bin/handoff-pr-backfill.sh +1 -1
  564. package/runtime/prime/bin/handoff-run.sh +11 -6
  565. package/runtime/prime/bin/ingest-item.sh +1 -1
  566. package/runtime/prime/bin/ingest-surface.html +22 -4
  567. package/runtime/prime/bin/issue.sh +1 -1
  568. package/runtime/prime/bin/knowledge.sh +1 -1
  569. package/runtime/prime/bin/lib/card-delivery.sh +329 -0
  570. package/runtime/prime/bin/lib/config.sh +148 -3
  571. package/runtime/prime/bin/lib/context.sh +38 -67
  572. package/runtime/prime/bin/lib/genui-entry.py +36 -0
  573. package/runtime/prime/bin/lib/git-message.sh +25 -6
  574. package/runtime/prime/bin/lib/git-sync.sh +12 -4
  575. package/runtime/prime/bin/lib/greeting.sh +255 -28
  576. package/runtime/prime/bin/lib/handoff_meta.py +294 -0
  577. package/runtime/prime/bin/lib/health-footer.sh +83 -2
  578. package/runtime/prime/bin/lib/identity.sh +31 -10
  579. package/runtime/prime/bin/lib/instance-registry.sh +71 -0
  580. package/runtime/prime/bin/lib/local_ci_receipt.py +249 -0
  581. package/runtime/prime/bin/lib/metrics.sh +121 -8
  582. package/runtime/prime/bin/lib/notices.sh +36 -0
  583. package/runtime/prime/bin/lib/record_outcomes.py +729 -0
  584. package/runtime/prime/bin/lib/reflexes.py +267 -0
  585. package/runtime/prime/bin/lib/retrieval_scorecard.py +624 -0
  586. package/runtime/prime/bin/lib/session-record-prompt.txt +18 -0
  587. package/runtime/prime/bin/lib/session_record.py +3747 -0
  588. package/runtime/prime/bin/lib/session_trail.py +1983 -0
  589. package/runtime/prime/bin/lib/settings-drift.sh +8 -5
  590. package/runtime/prime/bin/lib/startup-restart.sh +41 -0
  591. package/runtime/prime/bin/lib/worktree-links.sh +92 -0
  592. package/runtime/prime/bin/memory-push.sh +6 -0
  593. package/runtime/prime/bin/merge-gate.sh +498 -0
  594. package/runtime/prime/bin/notify.sh +5 -2
  595. package/runtime/prime/bin/page-access.sh +103 -0
  596. package/runtime/prime/bin/person.sh +13 -2
  597. package/runtime/prime/bin/pi-branch-policy.mjs +37 -0
  598. package/runtime/prime/bin/pi-observe-context.mjs +97 -4
  599. package/runtime/prime/bin/pi-render-spec.mjs +0 -1
  600. package/runtime/prime/bin/pi-spirit-discovery.mjs +34 -0
  601. package/runtime/prime/bin/post-update.sh +181 -0
  602. package/runtime/prime/bin/prime-render-spec.mjs +0 -1
  603. package/runtime/prime/bin/prime-session-start.sh +3 -1
  604. package/runtime/prime/bin/publish-artifact.sh +89 -42
  605. package/runtime/prime/bin/qa-inventory.sh +2 -2
  606. package/runtime/prime/bin/quest.sh +1 -1
  607. package/runtime/prime/bin/records.sh +11 -0
  608. package/runtime/prime/bin/reflexes/05-vitals.sh +9 -0
  609. package/runtime/prime/bin/reflexes/10-open-items.sh +12 -0
  610. package/runtime/prime/bin/reflexes/15-retrieval.sh +8 -0
  611. package/runtime/prime/bin/reflexes/20-nightly.sh +100 -0
  612. package/runtime/prime/bin/reflexes/20-sandbox.sh +85 -0
  613. package/runtime/prime/bin/reflexes/30-cost.py +116 -0
  614. package/runtime/prime/bin/reflexes/40-shells.py +51 -0
  615. package/runtime/prime/bin/reflexes/README.md +61 -0
  616. package/runtime/prime/bin/reflexes.sh +7 -0
  617. package/runtime/prime/bin/runtime-identity.sh +140 -42
  618. package/runtime/prime/bin/screenshot.sh +77 -0
  619. package/runtime/prime/bin/scroll.sh +1 -1
  620. package/runtime/prime/bin/search.sh +31 -5
  621. package/runtime/prime/bin/session-autosave.sh +6 -3
  622. package/runtime/prime/bin/session-id.sh +147 -0
  623. package/runtime/prime/bin/session-log.sh +19 -0
  624. package/runtime/prime/bin/session-record.sh +26 -0
  625. package/runtime/prime/bin/settings.sh +13 -8
  626. package/runtime/prime/bin/spirit-discovery-claude.sh +4 -0
  627. package/runtime/prime/bin/spirit-discovery-codex.sh +4 -0
  628. package/runtime/prime/bin/spirit-discovery-pi.sh +4 -0
  629. package/runtime/prime/bin/spirit-discovery-prime.sh +4 -0
  630. package/runtime/prime/bin/spirit-discovery.sh +4 -0
  631. package/runtime/prime/bin/startup-check.sh +1 -1
  632. package/runtime/prime/bin/telemetry.sh +11 -4
  633. package/runtime/prime/bin/test-baseline.sh +33 -5
  634. package/runtime/prime/bin/todo.sh +1 -1
  635. package/runtime/prime/bin/worktree-create.sh +15 -45
  636. package/runtime/prime/bin/worktree.sh +6 -0
  637. package/runtime/prime/docs/spirit-discovery.md +96 -0
  638. package/runtime/prime/egregore_runtime/__init__.py +18 -12
  639. package/runtime/prime/egregore_runtime/access.py +608 -0
  640. package/runtime/prime/egregore_runtime/access_cli.py +190 -0
  641. package/runtime/prime/egregore_runtime/adapters/invitation.py +5 -3
  642. package/runtime/prime/egregore_runtime/adapters/qmd.py +521 -47
  643. package/runtime/prime/egregore_runtime/admin_entry.py +56 -0
  644. package/runtime/prime/egregore_runtime/artifacts.py +222 -16
  645. package/runtime/prime/egregore_runtime/contracts.py +27 -0
  646. package/runtime/prime/egregore_runtime/eligibility.py +5 -12
  647. package/runtime/prime/egregore_runtime/episode_binding.py +16 -5
  648. package/runtime/prime/egregore_runtime/github_issues.py +2 -2
  649. package/runtime/prime/egregore_runtime/handoff_lookup.py +9 -20
  650. package/runtime/prime/egregore_runtime/harness_cli.py +674 -149
  651. package/runtime/prime/egregore_runtime/held.py +2436 -0
  652. package/runtime/prime/egregore_runtime/hosted_api.py +137 -0
  653. package/runtime/prime/egregore_runtime/identity.py +196 -65
  654. package/runtime/prime/egregore_runtime/identity_transfer.py +6 -2
  655. package/runtime/prime/egregore_runtime/ingest_cli.py +2 -2
  656. package/runtime/prime/egregore_runtime/ingest_index_cli.py +4 -16
  657. package/runtime/prime/egregore_runtime/installation.py +119 -0
  658. package/runtime/prime/egregore_runtime/investigation.py +64 -41
  659. package/runtime/prime/egregore_runtime/investigation_guidance.py +16 -11
  660. package/runtime/prime/egregore_runtime/issue_cli.py +51 -32
  661. package/runtime/prime/egregore_runtime/issue_reporting.py +4 -3
  662. package/runtime/prime/egregore_runtime/issue_triage_service.py +2 -2
  663. package/runtime/prime/egregore_runtime/issues.py +12 -6
  664. package/runtime/prime/egregore_runtime/knowledge.py +331 -5
  665. package/runtime/prime/egregore_runtime/knowledge_cli.py +57 -17
  666. package/runtime/prime/egregore_runtime/lifecycle.py +88 -22
  667. package/runtime/prime/egregore_runtime/lifecycle_cli.py +21 -13
  668. package/runtime/prime/egregore_runtime/line_ids.py +10 -0
  669. package/runtime/prime/egregore_runtime/memory_push.py +349 -0
  670. package/runtime/prime/egregore_runtime/observe.py +64 -25
  671. package/runtime/prime/egregore_runtime/observers.py +19 -0
  672. package/runtime/prime/egregore_runtime/optional_modules.py +13 -0
  673. package/runtime/prime/egregore_runtime/outputs_cli.py +321 -0
  674. package/runtime/prime/egregore_runtime/policy.py +651 -24
  675. package/runtime/prime/egregore_runtime/private_result.py +2 -1
  676. package/runtime/prime/egregore_runtime/projection.py +946 -0
  677. package/runtime/prime/egregore_runtime/quest_cli.py +20 -23
  678. package/runtime/prime/egregore_runtime/question_cli.py +15 -11
  679. package/runtime/prime/egregore_runtime/questions.py +10 -10
  680. package/runtime/prime/egregore_runtime/quests.py +10 -10
  681. package/runtime/prime/egregore_runtime/record_publish.py +548 -0
  682. package/runtime/prime/egregore_runtime/record_subject.py +564 -0
  683. package/runtime/prime/egregore_runtime/research_ingest.py +2 -4
  684. package/runtime/prime/egregore_runtime/runtime.py +169 -60
  685. package/runtime/prime/egregore_runtime/sandbox.py +194 -0
  686. package/runtime/prime/egregore_runtime/scroll_cli.py +22 -32
  687. package/runtime/prime/egregore_runtime/scrolls.py +23 -15
  688. package/runtime/prime/egregore_runtime/shadow.py +262 -0
  689. package/runtime/prime/egregore_runtime/spirit_discovery.py +487 -0
  690. package/runtime/prime/egregore_runtime/spirit_discovery_cli.py +25 -0
  691. package/runtime/prime/egregore_runtime/spirit_discovery_transport.py +18 -0
  692. package/runtime/prime/egregore_runtime/status.py +101 -44
  693. package/runtime/prime/egregore_runtime/status_cli.py +13 -5
  694. package/runtime/prime/egregore_runtime/sync.py +39 -21
  695. package/runtime/prime/egregore_runtime/taste.py +934 -0
  696. package/runtime/prime/egregore_runtime/taste_cli.py +242 -0
  697. package/runtime/prime/egregore_runtime/taste_rules.py +91 -0
  698. package/runtime/prime/egregore_runtime/telemetry.py +26 -3
  699. package/runtime/prime/egregore_runtime/todo_cli.py +15 -12
  700. package/runtime/prime/egregore_runtime/todos.py +3 -2
  701. package/runtime/prime/egregore_runtime/upgrade.py +85 -58
  702. package/runtime/prime/egregore_runtime/writeback.py +330 -24
  703. package/runtime/prime/manifest.json +66 -5
  704. package/runtime/claude/bin/thread.sh +0 -9
  705. package/runtime/claude/egregore_runtime/admin_gate.py +0 -102
  706. package/runtime/claude/egregore_runtime/thread_cli.py +0 -173
  707. package/runtime/claude/egregore_runtime/threads.py +0 -521
  708. package/runtime/codex/bin/thread.sh +0 -9
  709. package/runtime/codex/egregore_runtime/admin_gate.py +0 -102
  710. package/runtime/codex/egregore_runtime/thread_cli.py +0 -173
  711. package/runtime/codex/egregore_runtime/threads.py +0 -521
  712. package/runtime/pi/bin/thread.sh +0 -9
  713. package/runtime/pi/egregore_runtime/admin_gate.py +0 -102
  714. package/runtime/pi/egregore_runtime/thread_cli.py +0 -173
  715. package/runtime/pi/egregore_runtime/threads.py +0 -521
  716. package/runtime/prime/bin/thread.sh +0 -9
  717. package/runtime/prime/egregore_runtime/admin_gate.py +0 -102
  718. package/runtime/prime/egregore_runtime/thread_cli.py +0 -173
  719. package/runtime/prime/egregore_runtime/threads.py +0 -521
@@ -75,7 +75,6 @@ function adapt(sourceSpec) {
75
75
  ["Egregore on Codex", "Egregore on Pi"],
76
76
  ["Codex-native", "Pi-native"],
77
77
  ["Codex sessions", "Pi sessions"],
78
- ["On Codex", "On Pi"],
79
78
  ["bin/codex-session-start.sh", "bin/pi-session-start.sh"],
80
79
  [".codex/hooks/branch-guard.js", ".pi/extensions/egregore.ts"],
81
80
  ["PreToolUse hook (launcher `--enable hooks`)", "`tool_call` gate (loaded after Pi project trust)"],
@@ -0,0 +1,34 @@
1
+ // Pi and Prime share this thin adapter; the reader owns all evidence semantics.
2
+ import { join } from 'node:path';
3
+ export function registerSpiritDiscovery(pi, { root, runtime, Type }) {
4
+ if (!['pi', 'prime'].includes(runtime)) throw new Error('invalid discovery adapter');
5
+ pi.registerTool({
6
+ name: 'egregore_discover_capabilities', label: 'Egregore capabilities',
7
+ description: 'Inspect local installed-file evidence and separately authenticated spirit capabilities. Read-only; does not grant or execute work.',
8
+ parameters: Type.Object({ operation: Type.Union(['capabilities.list','capabilities.find','capabilities.describe','capabilities.explain','system.explain'].map(Type.Literal)),
9
+ query: Type.Optional(Type.String({ maxLength: 200 })), id: Type.Optional(Type.String({ maxLength: 160 })) }, { additionalProperties: false }),
10
+ async execute(_id, params) {
11
+ // JSON is argv data; the fixed adapter never accepts a root or runtime selector.
12
+ if (!params || typeof params !== 'object' || Array.isArray(params)
13
+ || !['capabilities.list','capabilities.find','capabilities.describe','capabilities.explain','system.explain'].includes(params.operation)) throw new Error('invalid discovery query');
14
+ const args = [join(root, 'bin', `spirit-discovery-${runtime}.sh`), params.operation];
15
+ const allowed = params.operation === 'capabilities.find' ? ['operation','query']
16
+ : ['capabilities.describe','capabilities.explain'].includes(params.operation) ? ['operation','id']
17
+ : params.operation === 'system.explain' && Object.hasOwn(params,'id') ? ['operation','id'] : ['operation'];
18
+ if (Object.keys(params).sort().join() !== allowed.sort().join()) throw new Error('invalid discovery query');
19
+ for (const [field, limit] of [['query', 200], ['id', 160]]) {
20
+ if (Object.hasOwn(params, field) && (typeof params[field] !== 'string' || !params[field].trim()
21
+ || Buffer.from(params[field], 'utf8').toString('utf8') !== params[field]
22
+ || Buffer.byteLength(params[field]) > limit || /[\x00-\x1f\x7f]/.test(params[field]))) throw new Error('invalid discovery query');
23
+ }
24
+ if (Object.hasOwn(params,'query')) args.push(params.query);
25
+ if (Object.hasOwn(params,'id')) args.push(params.id);
26
+ const response = await pi.exec('bash', args, { timeout: 15000 });
27
+ if (Number(response.code ?? response.status ?? 0) !== 0) throw new Error('discovery is unavailable');
28
+ let value;
29
+ try { value = JSON.parse(response.stdout); } catch { throw new Error('discovery is unavailable'); }
30
+ if (value.schema !== 'egregore.capability-query/v1') throw new Error('discovery is unavailable');
31
+ return { content: [{ type: 'text', text: JSON.stringify(value) }], details: value };
32
+ },
33
+ });
34
+ }
@@ -43,6 +43,187 @@ if [ ! -e "$SCRIPT_DIR/egregore_runtime" ] && \
43
43
  MIGRATED=1
44
44
  fi
45
45
 
46
+ # --- Migration: saved hosted address after the October 2026 security reset ---
47
+ # Connected setups before 22 Oct 2026 saved the hosted API's old Railway origin
48
+ # in egregore.json. That origin is retired; requests already resolve it to the
49
+ # hosted API (bin/lib/config.sh), and this rewrites the saved value once so the
50
+ # committed file says where requests go. Only that origin, without a path,
51
+ # changes; other keys, custom origins and Local configs are left alone.
52
+ #
53
+ # The working file and the index copy are handled separately, so /update
54
+ # commits this change and never an unrelated edit someone left in the file.
55
+ # Only the api_url string itself is replaced, byte for byte: formatting, key
56
+ # order, line endings, a byte-order mark and the file mode all stay as they
57
+ # were. An api_url written any other way (escaped, repeated) is left for the
58
+ # person to change by hand. Nothing is rewritten when either copy is Local,
59
+ # when egregore.json is a link (its target may belong to something else; the
60
+ # warning says to change it there), or when the working file is missing or
61
+ # unreadable. Nothing is staged for an untracked, sparse or assume-unchanged
62
+ # file. The index copy is staged first and the working file written second; a
63
+ # failed write restores the index, so the two never disagree about the
64
+ # address. A skip warns on stderr and never stops /update: the resolver
65
+ # already sends every request to the hosted API. Never at session start, where
66
+ # a modified tracked file would stop the startup sync. A source instance
67
+ # (upstream_url "none") skips the update commit, so it is left to the
68
+ # resolver.
69
+ # shellcheck source=bin/lib/config.sh
70
+ source "$SCRIPT_DIR/bin/lib/config.sh"
71
+ address_warn() { echo " ! $*" >&2; }
72
+ # saved_api_url TEXT — the api_url string jq reads from TEXT, if any.
73
+ saved_api_url() { jq -r '.api_url | strings' 2>/dev/null <<< "$1" || true; }
74
+ # other_keys TEXT — everything jq reads from TEXT apart from api_url.
75
+ other_keys() { jq -cS 'del(.api_url)' 2>/dev/null <<< "$1"; }
76
+ # address_state TEXT — "retired" for a Connected config (the _detect_mode
77
+ # test) whose saved address is the retired origin, "local" for a Local one,
78
+ # "keep" for anything else, including text that is not a JSON object.
79
+ address_state() {
80
+ local text="$1" saved
81
+ if ! jq -e 'type == "object"' >/dev/null 2>&1 <<< "$text"; then echo keep; return 0; fi
82
+ if ! jq -e "$EGREGORE_CONNECTED_JQ" >/dev/null 2>&1 <<< "$text"; then echo local; return 0; fi
83
+ saved="$(saved_api_url "$text")"
84
+ if [ "$(jq -r '.upstream_url | strings' 2>/dev/null <<< "$text" || true)" != none ] \
85
+ && _retired_api_url "$saved" \
86
+ && [ "$(_hosted_api_url "$saved" 2>/dev/null || true)" = "$EGREGORE_HOSTED_API_ORIGIN" ]; then
87
+ echo retired
88
+ else
89
+ echo keep
90
+ fi
91
+ }
92
+ # hosted_address_text TEXT — sets ADDRESS_TEXT to TEXT with only its api_url
93
+ # string replaced by the hosted address. Fails, leaving it empty, unless TEXT
94
+ # holds "api_url" exactly once, as a string without escapes that is the value
95
+ # jq reads, and the replacement changes nothing else jq can see.
96
+ hosted_address_text() {
97
+ local LC_ALL=C
98
+ local text="$1" key='"api_url"' value_re='^([[:space:]]*:[[:space:]]*")([^"\\]*)"' after updated before_keys after_keys
99
+ ADDRESS_TEXT=""
100
+ case "$text" in *"$key"*) ;; *) return 1 ;; esac
101
+ after="${text#*"$key"}"
102
+ case "$after" in *"$key"*) return 1 ;; esac
103
+ [[ "$after" =~ $value_re ]] || return 1
104
+ [ "${BASH_REMATCH[2]}" = "$(saved_api_url "$text")" ] || return 1
105
+ updated="${text%%"$key"*}$key${BASH_REMATCH[1]}$EGREGORE_HOSTED_API_ORIGIN\"${after#"${BASH_REMATCH[0]}"}"
106
+ [ "$(saved_api_url "$updated")" = "$EGREGORE_HOSTED_API_ORIGIN" ] || return 1
107
+ before_keys="$(other_keys "$text")" && after_keys="$(other_keys "$updated")" \
108
+ && [ "$before_keys" = "$after_keys" ] || return 1
109
+ ADDRESS_TEXT="$updated"
110
+ }
111
+ # read_exact FILE — sets EXACT_TEXT to FILE's bytes, trailing newlines kept.
112
+ read_exact() {
113
+ local text
114
+ text="$(cat -- "$1" 2>/dev/null && printf .)" || return 1
115
+ EXACT_TEXT="${text%.}"
116
+ }
117
+ config_path="$SCRIPT_DIR/egregore.json"
118
+ worktree_state=absent
119
+ worktree_text=""
120
+ if [ -L "$config_path" ]; then
121
+ worktree_state=link
122
+ elif [ -f "$config_path" ]; then
123
+ if [ -r "$config_path" ] && read_exact "$config_path"; then
124
+ worktree_text="$EXACT_TEXT"
125
+ worktree_state="$(address_state "$worktree_text")"
126
+ else
127
+ worktree_state=unreadable
128
+ fi
129
+ fi
130
+ index_state=untracked
131
+ index_stageable=false
132
+ index_entry="$(git -C "$SCRIPT_DIR" ls-files -s -- egregore.json 2>/dev/null || true)"
133
+ index_mode="${index_entry%% *}"
134
+ index_sha="${index_entry#* }"
135
+ index_sha="${index_sha%% *}"
136
+ index_text=""
137
+ case "$index_entry" in
138
+ 100644\ *\ 0$'\t'egregore.json|100755\ *\ 0$'\t'egregore.json)
139
+ index_text="$(git -C "$SCRIPT_DIR" cat-file blob "$index_sha" 2>/dev/null && printf .)" || index_text=""
140
+ if [ -n "$index_text" ]; then
141
+ index_text="${index_text%.}"
142
+ index_state="$(address_state "$index_text")"
143
+ # Only a normal entry ("H"): skip-worktree and assume-unchanged files
144
+ # are set aside from this checkout, so their commits are not ours to make.
145
+ index_tag="$(git -C "$SCRIPT_DIR" ls-files -v -- egregore.json 2>/dev/null || true)"
146
+ [ "${index_tag%% *}" = H ] && index_stageable=true
147
+ else
148
+ index_state=other
149
+ fi
150
+ ;;
151
+ '') ;;
152
+ *) index_state=other ;;
153
+ esac
154
+ address_updated=false
155
+ by_hand="set api_url to $EGREGORE_HOSTED_API_ORIGIN by hand"
156
+ if [ "$worktree_state" = link ]; then
157
+ if read_exact "$config_path" && [ "$(address_state "$EXACT_TEXT")" = retired ]; then
158
+ address_warn "egregore.json is a link, so its saved hosted address was left as is; requests still use $EGREGORE_HOSTED_API_ORIGIN. Set api_url to it in the file the link points to."
159
+ fi
160
+ elif [ "$worktree_state" = unreadable ]; then
161
+ address_warn "egregore.json can't be read, so its saved hosted address wasn't checked. If it names the retired address, $by_hand."
162
+ elif [ "$worktree_state" = local ] || [ "$index_state" = local ]; then
163
+ if [ "$worktree_state" = retired ] || [ "$index_state" = retired ]; then
164
+ address_warn "egregore.json is Local in one copy and Connected in the other, so its saved hosted address was left as is; requests still use $EGREGORE_HOSTED_API_ORIGIN."
165
+ fi
166
+ else
167
+ stage_index=false
168
+ write_worktree=false
169
+ if [ "$index_state" = retired ]; then
170
+ if [ "$worktree_state" = absent ]; then
171
+ address_warn "egregore.json is missing from this checkout, so its committed hosted address was left as is."
172
+ elif [ "$index_stageable" != true ]; then
173
+ address_warn "egregore.json is set aside from this checkout (sparse or assume-unchanged), so its committed hosted address was left as is."
174
+ else
175
+ stage_index=true
176
+ fi
177
+ fi
178
+ [ "$worktree_state" != retired ] || write_worktree=true
179
+ index_new=""
180
+ worktree_new=""
181
+ plan_ok=true
182
+ if [ "$stage_index" = true ]; then
183
+ if hosted_address_text "$index_text"; then index_new="$ADDRESS_TEXT"; else plan_ok=false; fi
184
+ fi
185
+ if [ "$write_worktree" = true ]; then
186
+ if hosted_address_text "$worktree_text"; then worktree_new="$ADDRESS_TEXT"; else plan_ok=false; fi
187
+ fi
188
+ if [ "$plan_ok" != true ]; then
189
+ address_warn "egregore.json's api_url is written in a way this update can't change safely, so it was left as is; requests still use $EGREGORE_HOSTED_API_ORIGIN. Please $by_hand."
190
+ elif [ "$stage_index" = true ] || [ "$write_worktree" = true ]; then
191
+ landed=true
192
+ index_staged=false
193
+ if [ "$stage_index" = true ]; then
194
+ if index_blob="$(printf '%s' "$index_new" | git -C "$SCRIPT_DIR" hash-object -w --no-filters --stdin 2>/dev/null)" \
195
+ && git -C "$SCRIPT_DIR" update-index --cacheinfo "$index_mode,$index_blob,egregore.json" 2>/dev/null; then
196
+ index_staged=true
197
+ else
198
+ landed=false
199
+ address_warn "Could not stage the hosted services address, so egregore.json was left as is; requests still use $EGREGORE_HOSTED_API_ORIGIN. Run /update again, or $by_hand."
200
+ fi
201
+ fi
202
+ if [ "$landed" = true ] && [ "$write_worktree" = true ]; then
203
+ config_mode="$(stat -c '%a' "$config_path" 2>/dev/null || stat -f '%Lp' "$config_path" 2>/dev/null || echo 644)"
204
+ config_tmp="$(mktemp "$config_path.XXXXXX" 2>/dev/null || true)"
205
+ if [ -n "$config_tmp" ] && printf '%s' "$worktree_new" > "$config_tmp" \
206
+ && chmod "$config_mode" "$config_tmp" && mv -f "$config_tmp" "$config_path"; then
207
+ :
208
+ else
209
+ landed=false
210
+ [ -z "$config_tmp" ] || rm -f "$config_tmp"
211
+ if [ "$index_staged" = true ] \
212
+ && ! git -C "$SCRIPT_DIR" update-index --cacheinfo "$index_mode,$index_sha,egregore.json" 2>/dev/null; then
213
+ address_warn "Could not update the hosted services address in egregore.json, and its staged copy could not be put back; run git restore --staged egregore.json, then $by_hand."
214
+ else
215
+ address_warn "Could not update the hosted services address in egregore.json; it is unchanged, and requests still use $EGREGORE_HOSTED_API_ORIGIN."
216
+ fi
217
+ fi
218
+ fi
219
+ [ "$landed" != true ] || address_updated=true
220
+ fi
221
+ fi
222
+ if [ "$address_updated" = true ]; then
223
+ echo " ✓ Hosted services address updated after the October security reset"
224
+ MIGRATED=1
225
+ fi
226
+
46
227
  # --- Future migrations go here ---
47
228
  # Each migration should:
48
229
  # 1. Check if it needs to run (idempotent guard)
@@ -74,7 +74,6 @@ function adapt(sourceSpec) {
74
74
  ["Egregore on Codex", "Egregore on Prime Agent"],
75
75
  ["Codex-native", "Prime-native"],
76
76
  ["Codex sessions", "Prime Agent sessions"],
77
- ["On Codex", "On Prime Agent"],
78
77
  ["bin/codex-session-start.sh", "bin/prime-session-start.sh"],
79
78
  [".codex/hooks/branch-guard.js", ".prime/agent/extensions/egregore.ts"],
80
79
  ["PreToolUse hook (launcher `--enable hooks`)", "`tool_call` gate (loaded from the project-local extension)"],
@@ -25,6 +25,15 @@ set -euo pipefail
25
25
  # Set automatically when publish-references.sh invokes us for a child,
26
26
  # preventing recursion.
27
27
  #
28
+ # --expires <days|never>: close the page's link that many days from now (1-365),
29
+ # or keep it open with never. Left out, a republish keeps the
30
+ # link's current closing date. Org pages only; close, reopen and
31
+ # see opens with bin/artifacts.sh close|reopen|opens <id>.
32
+ #
33
+ # --visible-to <@handle|email,...|public>: open the page only to these signed-in
34
+ # people (Connected only; refused in Local). public reopens it to
35
+ # anyone with the link; left out, a republish keeps the list.
36
+ #
28
37
  # Outputs artifact URL on success, exits silently on soft failure (the server
29
38
  # could not be reached).
30
39
  # Designed for fire-and-forget use: `bash bin/publish-artifact.sh handoff file.md &`
@@ -40,6 +49,8 @@ set -euo pipefail
40
49
 
41
50
  SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
42
51
  CONFIG="$SCRIPT_DIR/egregore.json"
52
+ # shellcheck source=bin/lib/config.sh
53
+ source "$SCRIPT_DIR/bin/lib/config.sh"
43
54
 
44
55
  # --- Parse arguments ---
45
56
  TYPE=""
@@ -69,6 +80,8 @@ while [[ $# -gt 0 ]]; do
69
80
  --raw-html) RAW_HTML=1; shift ;;
70
81
  --allow-admin) ALLOW_ADMIN=1; shift ;;
71
82
  --no-references) SKIP_REFERENCES=1; shift ;;
83
+ --expires) EXPIRES="$2"; shift 2 ;;
84
+ --visible-to) VISIBLE_TO="$2"; shift 2 ;;
72
85
  *)
73
86
  if [ -z "$TYPE" ]; then
74
87
  TYPE="$1"
@@ -89,6 +102,14 @@ if [ -n "$ARTIFACT_ID" ] && ! [[ "$ARTIFACT_ID" =~ ^[a-zA-Z0-9_-]{1,50}$ ]]; the
89
102
  echo "--id must be 1-50 chars, alphanumeric/hyphen/underscore only" >&2
90
103
  exit 1
91
104
  fi
105
+ if [ -n "${EXPIRES:-}" ] && ! [[ "$EXPIRES" =~ ^([1-9][0-9]{0,2}|never)$ && ( "$EXPIRES" == never || "$EXPIRES" -le 365 ) ]]; then
106
+ echo "--expires takes a number of days from 1 to 365, or never" >&2
107
+ exit 1
108
+ fi
109
+ if [ -n "${VISIBLE_TO:-}" ] && ! [[ "$VISIBLE_TO" =~ ^(public|[^,[:space:]]+(,[^,[:space:]]+){0,49})$ ]]; then
110
+ echo "--visible-to takes @handles or emails separated by commas, or public" >&2
111
+ exit 1
112
+ fi
92
113
  if [ -n "$CANONICAL_ID" ] && ! [[ "$CANONICAL_ID" =~ ^[mh]-[0-9a-f]{12}$ ]]; then
93
114
  echo "--canonical-id must be a memory file id (m- or h- and 12 hex characters)" >&2
94
115
  exit 1
@@ -115,11 +136,24 @@ if [ ! -f "$CONFIG" ] || ! jq -e 'type == "object"' "$CONFIG" >/dev/null 2>&1; t
115
136
  exit 4
116
137
  fi
117
138
 
118
- API_URL="${EGREGORE_API_URL:-$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null)}"
139
+ # A refused address stops here: a Connected org's page must never fall back
140
+ # to the public relay because its saved address is not plain.
141
+ if ! API_URL="$(_hosted_api_url "${EGREGORE_API_URL:-$(jq -r '.api_url // empty' "$CONFIG" 2>/dev/null)}")"; then
142
+ echo "Not published — nothing left this machine." >&2
143
+ exit 4
144
+ fi
119
145
  API_KEY="${EGREGORE_API_KEY:-}"
120
146
  ORG_SLUG="$(jq -r '.slug // empty' "$CONFIG" 2>/dev/null)"
121
147
  VIEW_BASE="https://egregore.xyz/view"
122
148
 
149
+ # A page opened by identity needs the hosted sign-in, so it is org-only. The
150
+ # public relay would show it to anyone with the link: refuse, upload nothing.
151
+ if [ -n "${VISIBLE_TO:-}" ] && { [ -z "$API_URL" ] || [ -z "$API_KEY" ]; }; then
152
+ echo "Not published — nothing left this machine." >&2
153
+ echo "--visible-to opens a page by identity, which needs Connected mode. In Local mode, hand over the password-protected file instead." >&2
154
+ exit 4
155
+ fi
156
+
123
157
  # Resolve "use published renderer" from env first, then egregore.json. The
124
158
  # env var lets individuals override per-shell; egregore.json lets an
125
159
  # instance (e.g. the upstream dev repo) opt in for every teammate.
@@ -132,7 +166,7 @@ fi
132
166
 
133
167
  # Public relay for OSS share endpoint. Unauthenticated: anything posted here is
134
168
  # readable by anyone holding the URL, for 7 days, with nothing in front of it.
135
- RELAY_URL="https://api.egregore.xyz"
169
+ RELAY_URL="$EGREGORE_HOSTED_API_ORIGIN"
136
170
 
137
171
  # --- Artifact hosting off-switch (compliance / privacy) ---
138
172
  # An instance can disable ALL egregore.xyz publishing via `bin/settings.sh hosting off`
@@ -166,48 +200,40 @@ if [ -z "$API_URL" ] || [ -z "$API_KEY" ]; then
166
200
  fi
167
201
  fi
168
202
 
169
- # --- Admin-content gate (the refusal documented in bin/lib/permissions.sh) --
170
- # `admin: true` sources — including backtick-referenced memory files — are
171
- # refused before any render or upload. An authorized admin (stable identity,
172
- # github.username alias against egregore.json admins) may proceed only with
173
- # the explicit --allow-admin confirmation, which is separate from and never
174
- # replaces normal publication approval. This protects the Egregore surface;
175
- # repository members can still read raw Git files.
176
- # shellcheck source=bin/lib/permissions.sh
177
- source "$SCRIPT_DIR/bin/lib/permissions.sh"
178
- ADMIN_MARKED=()
179
- if _is_admin_only_file "$FILE"; then
180
- ADMIN_MARKED+=("$FILE")
203
+ # --- Held-content gate: a publish is a hand-over -----------------------------
204
+ # The source and every backtick-referenced memory file go through one
205
+ # `access check --hand-over`: every held class is refused to a non-admin,
206
+ # under every policy, and a failed check refuses too. An admin may publish
207
+ # held material only with the explicit --allow-admin confirmation, which is
208
+ # separate from and never replaces normal publication approval.
209
+ MEMORY_REAL="$(cd "$SCRIPT_DIR/memory" 2>/dev/null && pwd -P || true)"
210
+ SOURCE_REAL="$(cd "$(dirname "$FILE")" && pwd -P)/$(basename "$FILE")"
211
+ if [ -n "$MEMORY_REAL" ] && [[ "$SOURCE_REAL" == "$MEMORY_REAL"/* ]]; then
212
+ SOURCES=("memory/${SOURCE_REAL#"$MEMORY_REAL"/}")
213
+ else
214
+ SOURCES=("$SOURCE_REAL")
181
215
  fi
182
216
  if [ "$RAW_HTML" -eq 0 ]; then
183
217
  while IFS= read -r ref; do
184
- [ -z "$ref" ] && continue
185
- rel="${ref#\`}"
186
- rel="${rel%\`}"
187
- if [ -f "$SCRIPT_DIR/$rel" ] && _is_admin_only_file "$SCRIPT_DIR/$rel"; then
188
- ADMIN_MARKED+=("$rel")
189
- fi
218
+ rel="${ref//\`/}"
219
+ [ -f "$SCRIPT_DIR/$rel" ] && SOURCES+=("$rel")
190
220
  done < <(grep -Eo '`memory/[^`[:space:]]+\.(md|html)`' "$FILE" 2>/dev/null | sort -u)
191
221
  fi
192
- if [ "${#ADMIN_MARKED[@]}" -gt 0 ]; then
193
- IS_ADMIN="false"
194
- ADMIN_JSON=$(cd "$SCRIPT_DIR" && EGREGORE_ROOT="$SCRIPT_DIR" \
195
- PYTHONSAFEPATH=1 PYTHONPATH="$SCRIPT_DIR${PYTHONPATH:+:$PYTHONPATH}" \
196
- python3 -m egregore_runtime.harness_cli admin-status 2>/dev/null) || true
197
- IS_ADMIN=$(printf '%s' "$ADMIN_JSON" | jq -r '.admin // false' 2>/dev/null || echo "false")
198
- if [ "$IS_ADMIN" != "true" ]; then
199
- echo "publish refused: admin-marked content cannot be published by a non-admin member:" >&2
200
- printf ' %s\n' "${ADMIN_MARKED[@]}" >&2
201
- echo "(--allow-admin is available to organization admins only)" >&2
202
- exit 5
203
- fi
204
- if [ "$ALLOW_ADMIN" -ne 1 ]; then
205
- echo "publish refused: this content is admin-marked:" >&2
206
- printf ' %s\n' "${ADMIN_MARKED[@]}" >&2
207
- echo "re-run with --allow-admin to confirm publishing admin-marked content" >&2
208
- echo "(this confirmation is separate from normal publication approval)" >&2
209
- exit 5
210
- fi
222
+ HELD_CHECK=0
223
+ CHECKED="$(cd "$SCRIPT_DIR" && EGREGORE_ROOT="$SCRIPT_DIR" PYTHONSAFEPATH=1 \
224
+ PYTHONPATH="$SCRIPT_DIR${PYTHONPATH:+:$PYTHONPATH}" \
225
+ python3 -m egregore_runtime.harness_cli access check --hand-over "${SOURCES[@]}" 2>/dev/null)" || HELD_CHECK=$?
226
+ if [ "$HELD_CHECK" -ne 0 ] || [ -z "$CHECKED" ]; then
227
+ echo "publish refused: a non-admin cannot publish held material, or access could not be checked:" >&2
228
+ printf '%s\n' "$CHECKED" | awk -F '\t' '$3 != "allowed" && NF { print " " $1 }' >&2
229
+ exit 5
230
+ fi
231
+ if [ "$ALLOW_ADMIN" -ne 1 ] && printf '%s\n' "$CHECKED" | grep -q ' for everyone else$'; then
232
+ echo "publish refused: this content is held from everyone but admins:" >&2
233
+ printf '%s\n' "$CHECKED" | awk -F '\t' '/ for everyone else$/ { print " " $1 " (" $4 ")" }' >&2
234
+ echo "re-run with --allow-admin to confirm publishing it" >&2
235
+ echo "(this confirmation is separate from normal publication approval)" >&2
236
+ exit 5
211
237
  fi
212
238
 
213
239
  # --- Prepare HTML ---
@@ -291,8 +317,12 @@ fi
291
317
  RESPONSE=""
292
318
 
293
319
  if [ -n "$API_URL" ] && [ -n "$API_KEY" ]; then
294
- # Connected mode: permanent, org-scoped
295
- RESPONSE=$(curl -s -X POST "${API_URL}/api/artifacts/publish" \
320
+ # Connected mode: permanent, org-scoped. A list goes to publish-restricted,
321
+ # which a server that cannot open pages by identity does not have: it
322
+ # refuses there instead of ignoring the list and opening the page to all.
323
+ PUBLISH_PATH="/api/artifacts/publish"
324
+ [ -z "${VISIBLE_TO:-}" ] || PUBLISH_PATH="/api/artifacts/publish-restricted"
325
+ RESPONSE=$(curl -s -X POST "${API_URL}${PUBLISH_PATH}" \
296
326
  -H "Authorization: Bearer $API_KEY" \
297
327
  -F "file=@${TMP_HTML}" \
298
328
  -F "artifact_type=${TYPE}" \
@@ -300,9 +330,14 @@ if [ -n "$API_URL" ] && [ -n "$API_KEY" ]; then
300
330
  -F "author=${AUTHOR}" \
301
331
  -F "description=${DESCRIPTION}" \
302
332
  -F "artifact_id=${ARTIFACT_ID}" \
333
+ -F "expires_in_days=${EXPIRES:-}" \
334
+ --form-string "visible_to=${VISIBLE_TO:-}" \
303
335
  --max-time 15 2>/dev/null) || true
304
336
  else
305
337
  # OSS mode: ephemeral, 7-day TTL
338
+ if [ -n "${EXPIRES:-}" ]; then
339
+ echo "Note: --expires applies to organization pages; this public copy closes after 7 days." >&2
340
+ fi
306
341
  RESPONSE=$(curl -s -X POST "${RELAY_URL}/api/artifacts/share" \
307
342
  -F "file=@${TMP_HTML}" \
308
343
  -F "artifact_type=${TYPE}" \
@@ -334,6 +369,9 @@ if [ -n "$RESPONSE" ]; then
334
369
  # The server refused (409 for an id another org holds, 400, 413, 503…).
335
370
  # A distinct exit code lets callers that report stderr on failure show why.
336
371
  DETAIL=$(echo "$RESPONSE" | jq -r 'if (.detail | type) == "string" then .detail else empty end' 2>/dev/null || true)
372
+ if [ -n "${VISIBLE_TO:-}" ] && { [ "$DETAIL" = "Not Found" ] || [ "$DETAIL" = "Method Not Allowed" ]; }; then
373
+ DETAIL="the hosted service cannot open pages by identity yet, so nothing was stored."
374
+ fi
337
375
  echo "Not published: ${DETAIL:-the server answered without a URL.}" >&2
338
376
  exit 6
339
377
  fi
@@ -345,7 +383,16 @@ fi
345
383
  # - parent publish failed (no URL),
346
384
  # - --raw-html (HTML attachments don't embed markdown refs we'd parse),
347
385
  # - --no-references (caller explicitly opts out / recursion guard).
348
- if [ -n "$URL" ] && [ "$RAW_HTML" -eq 0 ] && [ "$SKIP_REFERENCES" -eq 0 ]; then
386
+ # - the page opens by identity (its stored list, so a republish that keeps
387
+ # the list counts): the files it links to would open to anyone.
388
+ RESTRICTED=0
389
+ if [ -n "$URL" ] && [ "$(echo "$RESPONSE" | jq -r '.visible_to | type' 2>/dev/null || true)" = "array" ]; then
390
+ RESTRICTED=1
391
+ if [ -n "$REF_IDS" ] && [ "$SKIP_REFERENCES" -eq 0 ]; then
392
+ echo "Note: the files this page links to were not published; it opens only for the people it is shared with." >&2
393
+ fi
394
+ fi
395
+ if [ -n "$URL" ] && [ "$RESTRICTED" -eq 0 ] && [ "$RAW_HTML" -eq 0 ] && [ "$SKIP_REFERENCES" -eq 0 ]; then
349
396
  EGREGORE_REF_IDS="$REF_IDS" bash "$SCRIPT_DIR/bin/publish-references.sh" "$FILE" >/dev/null 2>&1 &
350
397
  disown 2>/dev/null || true
351
398
  fi
@@ -236,7 +236,7 @@ if $requested_tree; then
236
236
  ($path | split("/")[-1]) as $basename | .[$basename] += [$path])' \
237
237
  "$scratch/head-paths" > "$scratch/head-basenames.json"
238
238
  else
239
- for suite in "$SCRIPT_DIR"/tests/*.sh "$SCRIPT_DIR"/tests/*.py "$SCRIPT_DIR"/bin/tests/*.sh "$SCRIPT_DIR"/bin/tests/*.mjs; do
239
+ for suite in "$SCRIPT_DIR"/tests/*.sh "$SCRIPT_DIR"/tests/*.py "$SCRIPT_DIR"/tests/*.mjs "$SCRIPT_DIR"/bin/tests/*.sh "$SCRIPT_DIR"/bin/tests/*.mjs; do
240
240
  if [ -L "$suite" ]; then
241
241
  suite_paths_skipped=$((suite_paths_skipped + 1))
242
242
  continue
@@ -286,7 +286,7 @@ while IFS= read -r -d '' file; do
286
286
  code=0
287
287
  if $requested_tree; then
288
288
  git -C "$SCRIPT_DIR" grep -l -z -F "${patterns[@]}" "$head_oid" -- \
289
- ':(top,glob)tests/*.sh' ':(top,glob)tests/*.py' \
289
+ ':(top,glob)tests/*.sh' ':(top,glob)tests/*.py' ':(top,glob)tests/*.mjs' \
290
290
  ':(top,glob)bin/tests/*.sh' ':(top,glob)bin/tests/*.mjs' > "$scratch/hits" || code=$?
291
291
  while IFS= read -r -d '' suite; do
292
292
  jq -cn --arg suite "${suite#"$head_oid":}" --arg match "$file" \
@@ -3,7 +3,7 @@ set -euo pipefail
3
3
 
4
4
  ROOT="$(cd "$(dirname "$0")/.." && pwd)"
5
5
  export EGREGORE_ROOT="$ROOT"
6
- export EGREGORE_SESSION_ID="${EGREGORE_SESSION_ID:-$(cat "$ROOT/.egregore-session-id" 2>/dev/null || true)}"
6
+ export EGREGORE_SESSION_ID="${EGREGORE_SESSION_ID:-$(bash "$ROOT/bin/session-id.sh" --root "$ROOT" 2>/dev/null || cat "$ROOT/.egregore-session-id" 2>/dev/null || true)}"
7
7
  export PYTHONSAFEPATH=1 PYTHONPATH="$ROOT${PYTHONPATH:+:$PYTHONPATH}"
8
8
 
9
9
  exec python3 -m egregore_runtime.quest_cli "$@"
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ # Personal controls and batch actions for session records.
3
+ set -uo pipefail
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" || exit 0
5
+ command -v jq >/dev/null 2>&1 || exit 0
6
+ command -v python3 >/dev/null 2>&1 || exit 0
7
+ [ -n "${HOME:-}" ] || exit 0
8
+ # The organization's vitals read the records and the gate ledger only.
9
+ [ "${1:-}" = vitals ] && shift && exec python3 "$SCRIPT_DIR/bin/lib/session_record.py" vitals --root "$SCRIPT_DIR" "$@"
10
+ [ "${1:-}" = retrieval ] && shift && exec python3 "$SCRIPT_DIR/bin/lib/retrieval_scorecard.py" --root "$SCRIPT_DIR" "$@"
11
+ exec python3 "$SCRIPT_DIR/bin/lib/session_record.py" records --root "$SCRIPT_DIR" "$@"
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ # The organization's pulse: sessions by harness, cost, friction and the merge
3
+ # gate's decisions over the last seven days beside the seven before, from the
4
+ # session records and memory/sessions/gate.jsonl. Silent under two sessions.
5
+ # Writes nothing. Contract: bin/reflexes/README.md.
6
+ set -uo pipefail
7
+ root="${EGREGORE_ROOT:-}"
8
+ [ -n "$root" ] && [ -f "$root/bin/lib/session_record.py" ] && command -v python3 >/dev/null 2>&1 || exit 0
9
+ exec python3 "$root/bin/lib/session_record.py" vitals-line --root "$root" --memory "${EGREGORE_MEMORY:-$root/memory}"
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+ # Open items carried from the session records: how many, and the oldest. An
3
+ # ownerless item past three days adds the count and the oldest's age; past
4
+ # seven days the line ends with the command that drafts an issue for it.
5
+ # Reads the records of the last fourteen days and the open-items ledger;
6
+ # writes nothing. Contract: bin/reflexes/README.md.
7
+ set -uo pipefail
8
+ root="${EGREGORE_ROOT:-}"
9
+ [ -n "$root" ] && [ -f "$root/bin/lib/session_record.py" ] || exit 0
10
+ command -v python3 >/dev/null 2>&1 || exit 0
11
+ exec python3 "$root/bin/lib/session_record.py" open-items-line --root "$root" \
12
+ --memory "${EGREGORE_MEMORY:-$root/memory}"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ # Show: this installation's memory lookups and the organization's session reach
3
+ # over seven days. Silent below two lookups or when organization records are off.
4
+ # One line, at most 160 characters; writes nothing. Contract: README.md.
5
+ set -uo pipefail
6
+ root="${EGREGORE_ROOT:-}"
7
+ [ -n "$root" ] && [ -f "$root/bin/lib/retrieval_scorecard.py" ] && command -v python3 >/dev/null 2>&1 || exit 0
8
+ exec python3 "$root/bin/lib/retrieval_scorecard.py" line --root "$root" --memory "${EGREGORE_MEMORY:-$root/memory}"
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env bash
2
+ # Reflex, show then propose: the runs of ci.yml on develop, the push run
3
+ # each merge starts and the workflow_dispatch run the nightly dispatcher
4
+ # requests. A run cancelled because a newer merge superseded it is no verdict
5
+ # and is skipped.
6
+ #
7
+ # Silent while the latest finished run is green, or red once. Two or more red
8
+ # runs running name the failing jobs of the latest run; three end with a
9
+ # proposal to give the failure an owner.
10
+ #
11
+ # The answer is cached for six hours in tmp/reflexes/nightly.json, so a warm
12
+ # card makes no gh call. A cold one makes one request, and a second for the
13
+ # failing jobs only when the line will print; both go through gh's own
14
+ # six-hour response cache, which outlives the sweep of tmp/ at session end.
15
+ # Silent when gh or jq is missing, gh is signed out or offline, or the
16
+ # request outlasts the runner's one-second budget.
17
+ set -uo pipefail
18
+
19
+ ROOT="${EGREGORE_ROOT:-$(cd "$(dirname "$0")/../.." 2>/dev/null && pwd)}"
20
+ [ -n "$ROOT" ] && [ -d "$ROOT" ] || exit 0
21
+ CACHE="$ROOT/tmp/reflexes/nightly.json"
22
+ TTL=21600
23
+ BRANCH=develop
24
+
25
+ command -v jq >/dev/null 2>&1 || exit 0
26
+ now="$(date +%s)"
27
+
28
+ fresh() {
29
+ local at
30
+ at="$(jq -r '.fetched_at // 0 | floor' "$CACHE" 2>/dev/null)" || return 1
31
+ case "$at" in ''|*[!0-9]*) return 1 ;; esac
32
+ [ $((at + TTL)) -gt "$now" ]
33
+ }
34
+
35
+ # Reads run conclusions, latest first; prints how many in a row are red.
36
+ red_streak() {
37
+ local conclusion count=0 open=1
38
+ while IFS= read -r conclusion; do
39
+ [ "$open" -eq 1 ] || continue
40
+ case "$conclusion" in
41
+ failure|timed_out|action_required|startup_failure) count=$((count + 1)) ;;
42
+ *) open=0 ;;
43
+ esac
44
+ done
45
+ printf '%s\n' "$count"
46
+ }
47
+
48
+ refresh() {
49
+ local runs jobs='[]' streak latest tmp
50
+ command -v gh >/dev/null 2>&1 || return 1
51
+ [ -f "$ROOT/.github/workflows/ci.yml" ] || return 1
52
+ runs="$(cd "$ROOT" && gh api --cache 6h \
53
+ "repos/{owner}/{repo}/actions/workflows/ci.yml/runs?branch=$BRANCH&per_page=10" 2>/dev/null \
54
+ | jq -c '[.workflow_runs[]? | select(.status == "completed" and .conclusion != "cancelled")
55
+ | {conclusion, createdAt: .created_at, databaseId: .id}] | .[:3]')" || return 1
56
+ streak="$(jq -r '.[].conclusion' <<<"$runs" | red_streak)"
57
+ if [ "$streak" -ge 2 ]; then
58
+ latest="$(jq -r '.[0].databaseId' <<<"$runs")"
59
+ case "$latest" in ''|*[!0-9]*) return 1 ;; esac
60
+ jobs="$(cd "$ROOT" && gh api --cache 6h "repos/{owner}/{repo}/actions/runs/$latest/jobs?per_page=100" 2>/dev/null \
61
+ | jq -c '[.jobs[]? | select(.conclusion == "failure" or .conclusion == "timed_out"
62
+ or .conclusion == "startup_failure" or .conclusion == "action_required")
63
+ | .name | gsub("\\s*[—–-]*\\s*[0-9a-f]{40}"; "")]')" || return 1
64
+ fi
65
+ mkdir -p "${CACHE%/*}" 2>/dev/null || return 1
66
+ tmp="$(mktemp "${CACHE%/*}/.nightly.XXXXXX" 2>/dev/null)" || return 1
67
+ if jq -n --argjson at "$now" --arg branch "$BRANCH" --argjson runs "$runs" --argjson jobs "$jobs" \
68
+ '{fetched_at: $at, branch: $branch, runs: $runs, failing_jobs: $jobs}' >"$tmp" 2>/dev/null; then
69
+ mv -f "$tmp" "$CACHE" || { rm -f "$tmp"; return 1; }
70
+ else
71
+ rm -f "$tmp"
72
+ return 1
73
+ fi
74
+ }
75
+
76
+ render() {
77
+ local streak prefix suffix="" names="" name budget extra=0
78
+ streak="$(jq -r '.runs[]?.conclusion' "$CACHE" 2>/dev/null | red_streak)"
79
+ [ "$streak" -ge 2 ] || return 0
80
+ [ "$streak" -lt 3 ] || suffix=" · propose an owner: /issue"
81
+ prefix="$(jq -r '.branch // "develop"' "$CACHE") red $streak runs running: "
82
+ # The runner cuts a line at 160 characters; keep the proposal inside it.
83
+ budget=$((160 - ${#prefix} - ${#suffix} - 12))
84
+ while IFS= read -r name; do
85
+ [ -n "$name" ] || continue
86
+ if [ -z "$names" ]; then
87
+ names="$name"
88
+ elif [ $((${#names} + 2 + ${#name})) -le "$budget" ]; then
89
+ names="$names, $name"
90
+ else
91
+ extra=$((extra + 1))
92
+ fi
93
+ done < <(jq -r '.failing_jobs[]?' "$CACHE" 2>/dev/null)
94
+ [ "$extra" -eq 0 ] || names="$names and $extra more"
95
+ [ -n "$names" ] || names="$(jq -r '.runs[0].conclusion // "failure"' "$CACHE")"
96
+ printf '%s%s%s\n' "$prefix" "$names" "$suffix"
97
+ }
98
+
99
+ fresh || refresh || exit 0
100
+ render