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
@@ -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
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env bash
2
+ # Reflex (show): a session inside a sandbox says what runs degraded and
3
+ # what will not work.
4
+ #
5
+ # Positive markers only, the predicate bin/lib/secret_entry.py and
6
+ # egregore_runtime/sandbox.py use: CODEX_SANDBOX set to anything but empty,
7
+ # none, false or 0, or APP_SANDBOX_CONTAINER_ID set. No marker, no line, on
8
+ # every harness; a missing DISPLAY or a failing write never names a sandbox.
9
+ # With a marker, one file is created and removed where the runtime keeps its
10
+ # per-user state (search and telemetry, resolved as egregore_runtime does).
11
+ # The line follows the result: writable state, and search and browser checks
12
+ # will not work; refused state, and search runs degraded on the workspace
13
+ # copy, with a second line saying that state is read-only here.
14
+ set -u
15
+
16
+ marker="$(printf '%s' "${CODEX_SANDBOX:-}" | tr '[:upper:]' '[:lower:]')"
17
+ case "$marker" in
18
+ ""|none|false|0) [ -n "${APP_SANDBOX_CONTAINER_ID:-}" ] || exit 0 ;;
19
+ esac
20
+
21
+ # Create and remove one file in the nearest existing ancestor of a directory;
22
+ # fails when that location refuses the write or keeps the file. A probe file
23
+ # that outlives its test is removed again on the way out, and that retry
24
+ # never fails the probe, even under an inherited errexit.
25
+ probe_file=""
26
+ trap 'if [ -n "$probe_file" ]; then rm -f "$probe_file" 2>/dev/null || true; fi' EXIT
27
+ writable() {
28
+ local dir="$1" parent
29
+ case "$dir" in \~/*) dir="${HOME:-}/${dir#\~/}" ;; esac
30
+ # A relative override is relative to the current directory, as the runtime
31
+ # resolves it; the walk must reach that directory, never stop short of it.
32
+ case "$dir" in /*) ;; *) dir="$PWD/$dir" ;; esac
33
+ while [ ! -e "$dir" ]; do
34
+ parent="${dir%/*}"
35
+ [ -n "$parent" ] || parent=/
36
+ [ "$parent" != "$dir" ] || break
37
+ dir="$parent"
38
+ done
39
+ [ -d "$dir" ] || return 0
40
+ probe_file="$(mktemp "$dir/.egregore-write-probe.XXXXXX" 2>/dev/null)" || { probe_file=""; return 1; }
41
+ rm -f "$probe_file" 2>/dev/null || return 1
42
+ probe_file=""
43
+ }
44
+
45
+ # Both stores key their per-user directory by the resolved memory checkout
46
+ # (QmdLocalRetriever._instance_hash, LocalTelemetrySink's namespace).
47
+ root="${EGREGORE_ROOT:-.}"
48
+ memory="$(cd "$root/memory" 2>/dev/null && pwd -P)" \
49
+ || memory="$(cd "$root" 2>/dev/null && pwd -P)/memory"
50
+ digest=""
51
+ if command -v shasum >/dev/null 2>&1; then
52
+ digest="$(printf '%s' "$memory" | LC_ALL=C shasum -a 256 2>/dev/null)"
53
+ elif command -v sha256sum >/dev/null 2>&1; then
54
+ digest="$(printf '%s' "$memory" | sha256sum 2>/dev/null)"
55
+ fi
56
+ digest="${digest%% *}"
57
+
58
+ search_state="${EGREGORE_QMD_RUNTIME_DIR:-}"
59
+ telemetry_state="${EGREGORE_TELEMETRY_DIR:-}"
60
+ if [ -n "${HOME:-}" ]; then
61
+ [ -n "$search_state" ] || search_state="$HOME/.egregore/runtime/qmd${digest:+/${digest:0:16}}"
62
+ [ -n "$telemetry_state" ] || telemetry_state="$HOME/.egregore/telemetry${digest:+/${digest:0:20}}"
63
+ fi
64
+
65
+ refused=""
66
+ for state in "$search_state" "$telemetry_state"; do
67
+ [ -n "$state" ] || continue
68
+ if ! writable "$state"; then
69
+ refused=1
70
+ break
71
+ fi
72
+ done
73
+
74
+ # shellcheck disable=SC2016 # the backticks are part of each line
75
+ if [ -n "$refused" ]; then
76
+ # The runtime falls back to the workspace copy: lexical search, telemetry
77
+ # kept there. The read-only fact gets its own line, because this one uses
78
+ # 157 of the runner's 160 characters.
79
+ printf '%s\n' 'this session runs in a sandbox: search runs degraded, telemetry stays in the workspace and browser checks will not work · start through `egregore` to lift it'
80
+ printf '%s\n' 'per-user state is read-only here'
81
+ else
82
+ # Per-user state stays in use, but the sandbox refuses the loopback port
83
+ # of the query worker, so search fails instead of degrading.
84
+ printf '%s\n' 'this session runs in a sandbox: search and browser checks will not work · start through `egregore` to lift it'
85
+ fi
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python3
2
+ """Reflex: your session cost over seven days. Show tier.
3
+
4
+ Reads the current person's session records from the last seven days, today
5
+ included, and only the files whose names fall in that window. A priced record
6
+ counts under its harness (a record priced at list price is a Codex session);
7
+ an unpriced record counts apart, with the input tokens from its Cost section.
8
+ Prints one line, leaving out the parts that are zero, and nothing without
9
+ records. Numbers only: no topic, branch or prompt text.
10
+ """
11
+ import datetime
12
+ import json
13
+ import math
14
+ import os
15
+ import re
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ DAYS = 7
20
+ READ_LIMIT = 256 * 1024
21
+ PRICED = ("ledger", "estimate", "list price")
22
+ LABELS = {"claude": "Claude", "codex": "Codex", "pi": "Pi", "prime": "Prime", "other": "Other"}
23
+ TOKENS = re.compile(r"^- tokens: (\d+) input\b", re.M)
24
+
25
+
26
+ def front_matter(text):
27
+ if not text.startswith("---\n"):
28
+ return {}
29
+ block = text[4:].partition("\n---")[0]
30
+ fields = {}
31
+ for line in block.splitlines():
32
+ key, sep, value = line.partition(":")
33
+ if not sep:
34
+ continue
35
+ value = value.strip()
36
+ try:
37
+ value = json.loads(value)
38
+ except ValueError:
39
+ pass
40
+ fields[key.strip()] = value
41
+ return fields
42
+
43
+
44
+ def amount(value):
45
+ try:
46
+ number = float(value)
47
+ except (TypeError, ValueError):
48
+ return 0.0
49
+ return number if math.isfinite(number) and number > 0 else 0.0
50
+
51
+
52
+ def compact(count):
53
+ value, unit = float(count), ""
54
+ for name in ("K", "M", "B"):
55
+ if round(value, 1) < 1000:
56
+ break
57
+ value, unit = value / 1000, name
58
+ return (f"{value:.1f}".removesuffix(".0") if unit else str(count)) + unit
59
+
60
+
61
+ def main():
62
+ memory = os.environ.get("EGREGORE_MEMORY", "")
63
+ author = re.sub(r"[^a-z0-9_-]", "", os.environ.get("EGREGORE_AUTHOR", "").strip().lower())
64
+ sessions = Path(memory) / "sessions" if memory else None
65
+ if not author or sessions is None or not sessions.is_dir():
66
+ return 0
67
+ today = datetime.date.today()
68
+ priced = dict.fromkeys(LABELS.values(), 0.0)
69
+ unpriced, tokens, seen = 0, 0, set()
70
+ for offset in range(DAYS):
71
+ day = today - datetime.timedelta(days=offset)
72
+ try:
73
+ paths = sorted((sessions / day.strftime("%Y-%m")).glob(day.strftime("%d-") + author + "-*.md"))
74
+ except OSError:
75
+ continue
76
+ for path in paths:
77
+ try:
78
+ with path.open("rb") as stream:
79
+ text = stream.read(READ_LIMIT).decode("utf-8", errors="replace")
80
+ except OSError:
81
+ continue
82
+ meta = front_matter(text)
83
+ owner = str(meta.get("from", "")).strip().lower()
84
+ # Producer-bearing records are never a person's session, including
85
+ # malformed metadata and records copied without a private adapter.
86
+ if any(key.strip().strip("\"'").casefold() in
87
+ {"producer", "producer_principal_id", "producer_identity", "record_owner_actor_id", "subject_kind"}
88
+ and (key != "subject_kind" or value != "human-session") for key, value in meta.items()):
89
+ continue
90
+ session = str(meta.get("session", path.name))
91
+ if meta.get("kind") != "session-record" or owner != author or session in seen:
92
+ continue
93
+ seen.add(session)
94
+ source = meta.get("cost_source", "estimate")
95
+ if source in PRICED:
96
+ harness = "codex" if source == "list price" else str(meta.get("harness") or "claude").lower()
97
+ priced[LABELS.get(harness, "Other")] += amount(meta.get("cost_usd"))
98
+ continue
99
+ unpriced += 1
100
+ match = TOKENS.search(text.partition("\n## Cost\n")[2])
101
+ tokens += int(match.group(1)) if match else 0
102
+ parts = []
103
+ total = sum(priced.values())
104
+ if round(total, 2) > 0:
105
+ split = ", ".join(f"{label} ${value:,.2f}" for label, value in priced.items() if round(value, 2) > 0)
106
+ parts.append(f"${total:,.2f} priced ({split})")
107
+ if unpriced:
108
+ part = f"{unpriced} unpriced session" + ("" if unpriced == 1 else "s")
109
+ parts.append(part + (f", {compact(tokens)} input tokens" if tokens else ""))
110
+ if parts:
111
+ print("7 days: " + " · ".join(parts))
112
+ return 0
113
+
114
+
115
+ if __name__ == "__main__":
116
+ sys.exit(main())
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env python3
2
+ """Reflex: refused shell shapes. Show tier.
3
+
4
+ Reads yesterday's session records of the current person and sums the
5
+ `worktree-guard refusals` counter from their Friction sections. Three or
6
+ more prints one line with the count and the pointer to the plain forms.
7
+ """
8
+ import datetime
9
+ import os
10
+ import re
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ COUNTER = re.compile(r"^- worktree-guard refusals: (\d+)\s*$", re.M)
15
+ FROM = re.compile(r"^from:\s*(.+?)\s*$", re.M)
16
+
17
+
18
+ def main():
19
+ memory = os.environ.get("EGREGORE_MEMORY", "")
20
+ author = os.environ.get("EGREGORE_AUTHOR", "").strip().casefold()
21
+ sessions = Path(memory) / "sessions" if memory else None
22
+ if sessions is None or not sessions.is_dir():
23
+ return 0
24
+ yesterday = datetime.date.today() - datetime.timedelta(days=1)
25
+ folder = sessions / yesterday.strftime("%Y-%m")
26
+ total, files = 0, 0
27
+ try:
28
+ paths = sorted(folder.glob(yesterday.strftime("%d-") + "*.md"))
29
+ except OSError:
30
+ return 0
31
+ for path in paths:
32
+ try:
33
+ text = path.read_text(encoding="utf-8", errors="replace")[:200000]
34
+ except OSError:
35
+ continue
36
+ head = text.partition("\n---")[0]
37
+ owner = FROM.search(head)
38
+ if author and owner and owner.group(1).strip("\"'").casefold() != author:
39
+ continue
40
+ match = COUNTER.search(text)
41
+ if match:
42
+ total += int(match.group(1))
43
+ files += 1
44
+ if total >= 3:
45
+ noun = "session" if files == 1 else "sessions"
46
+ print(f"{total} refused shell commands yesterday across {files} {noun} · plain forms: .claude/context/plain-shell.md")
47
+ return 0
48
+
49
+
50
+ if __name__ == "__main__":
51
+ sys.exit(main())