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
@@ -0,0 +1,349 @@
1
+ """One managed memory push, freshly inspected at dispatch.
2
+
3
+ Ordinary callers cannot publish native history. The optional private record
4
+ owner can supply its typed, single-use in-process permit. This transport never
5
+ fetches, rebases, changes Git configuration, retries a push or writes a queue.
6
+ Manual Git remains outside this boundary. Existing Git configuration owns auth.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ from dataclasses import dataclass, replace
12
+ import hashlib
13
+ import json
14
+ import math
15
+ import os
16
+ from pathlib import Path
17
+ import re
18
+ import subprocess
19
+ import time
20
+ from urllib.parse import urlsplit
21
+
22
+ from . import record_publish as history
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class PushLimits:
27
+ seconds: float = 90
28
+ command_seconds: float = 15
29
+ push_seconds: float = 45
30
+ output_bytes: int = 65536
31
+ history: history.HistoryLimits = history.DEFAULT_LIMITS
32
+
33
+
34
+ DEFAULT_LIMITS = PushLimits()
35
+ EXIT_CODES = {"pushed": 0, "deferred": 2, "rejected": 3, "unknown": 4}
36
+
37
+
38
+ class _Refusal(Exception):
39
+ def __init__(self, cause, *, status="rejected"):
40
+ self.cause, self.status = cause, status
41
+
42
+
43
+ class _Transport(history._Git):
44
+ def __init__(self, root, deadline, limits, allow_local):
45
+ super().__init__(root, deadline)
46
+ # Transport uses normal system/global/local credential configuration.
47
+ # Repository/config/ref redirection from caller environment is removed.
48
+ self.env.pop("GIT_CONFIG_NOSYSTEM", None)
49
+ self.env.pop("GIT_CONFIG_GLOBAL", None)
50
+ for key in ("GIT_ASKPASS", "GIT_SSL_CAINFO", "GIT_SSL_CAPATH"):
51
+ if key in os.environ:
52
+ self.env[key] = os.environ[key]
53
+ self.limits, self.allow_local = limits, allow_local
54
+
55
+ def start(self, args, *, stdin=False):
56
+ return super().start(["-c", "protocol.https.allow=always", "-c",
57
+ "protocol.file.allow=" + ("always" if self.allow_local else "never"),
58
+ "-c", "http.followRedirects=false", "-c", "push.followTags=false",
59
+ "-c", "push.recurseSubmodules=no", "-c", "push.gpgSign=false",
60
+ "-c", "push.autoSetupRemote=false", *args], stdin=stdin)
61
+
62
+ def command(self, *args, seconds=None):
63
+ outer = self.deadline
64
+ self.deadline = min(outer, time.monotonic() + (seconds or self.limits.command_seconds))
65
+ try:
66
+ return self.run(*args, limit=self.limits.output_bytes, allowed=tuple(range(256)))
67
+ finally:
68
+ self.deadline = outer
69
+
70
+
71
+ def _branch(value):
72
+ if not isinstance(value, str):
73
+ raise _Refusal("invalid_destination_branch")
74
+ ref = value if value.startswith("refs/") else "refs/heads/" + value
75
+ if not ref.startswith("refs/heads/") or not history._ref(ref):
76
+ raise _Refusal("invalid_destination_branch")
77
+ return ref
78
+
79
+
80
+ def _safe_ref(git_dir, ref):
81
+ seen = set()
82
+ while True:
83
+ if ref in seen or len(seen) >= 8:
84
+ raise _Refusal("ambiguous_source_ref")
85
+ seen.add(ref)
86
+ if ref != "HEAD" and (not history._ref(ref) or not ref.startswith("refs/heads/")):
87
+ raise _Refusal("invalid_source_ref")
88
+ selected = git_dir
89
+ for part in ref.split("/"):
90
+ selected /= part
91
+ if selected.is_symlink():
92
+ raise _Refusal("unsupported_repository")
93
+ if (git_dir / "packed-refs").is_symlink():
94
+ raise _Refusal("unsupported_repository")
95
+ if not selected.exists():
96
+ return
97
+ raw = history._regular(selected, 1024).strip()
98
+ if not raw.startswith(b"ref: "):
99
+ return
100
+ ref = raw[5:].decode("ascii")
101
+
102
+
103
+ def _url(value, allow_local):
104
+ if not value or len(value) > 4096 or any(ord(char) <= 32 or ord(char) == 127 for char in value):
105
+ raise _Refusal("unsupported_destination")
106
+ parsed = urlsplit(value)
107
+ if (parsed.scheme == "https" and parsed.hostname and parsed.username is None and parsed.password is None
108
+ and not parsed.query and not parsed.fragment and parsed.path.startswith("/")
109
+ and not re.search(r"[^A-Za-z0-9.:-]", parsed.netloc)):
110
+ return value
111
+ if allow_local and not parsed.scheme and value.startswith("/"):
112
+ path = Path(value)
113
+ if path == path.resolve() and path.is_dir():
114
+ return value
115
+ raise _Refusal("unsupported_destination")
116
+
117
+
118
+ def _snapshot(transport, repository, head_ref, branch_ref):
119
+ root, git_dir = history._repository(repository, transport.deadline)
120
+ _safe_ref(git_dir, head_ref)
121
+ config, code = transport.command("config", "--null", "--list", "--includes")
122
+ if code:
123
+ raise _Refusal("configuration_unavailable", status="deferred")
124
+ values = {}
125
+ for entry in config.split(b"\0"):
126
+ if not entry:
127
+ continue
128
+ key, sep, value = entry.partition(b"\n")
129
+ if not sep:
130
+ # A valueless Boolean key is true in Git's own configuration.
131
+ value = b"true"
132
+ name = key.decode("utf-8").lower()
133
+ values.setdefault(name, []).append(value.decode("utf-8"))
134
+ if any(re.fullmatch(r"url\..*\.(?:push)?insteadof", key) for key in values):
135
+ raise _Refusal("destination_rewrite_unsupported")
136
+ if (len(values.get("remote.origin.url", [])) != 1 or len(values.get("remote.origin.pushurl", [])) > 1
137
+ or any(values.get(key) for key in ("remote.origin.push", "remote.origin.pushoption", "push.pushoption",
138
+ "remote.origin.receivepack", "remote.origin.uploadpack", "remote.origin.vcs"))
139
+ or any(value.lower() not in {"false", "no", "off", "0"} for value in values.get("remote.origin.mirror", []))):
140
+ raise _Refusal("ambiguous_destination")
141
+ selected = values.get("remote.origin.pushurl", values["remote.origin.url"])[0]
142
+ selected = _url(selected, transport.allow_local)
143
+ resolved, code = transport.command("remote", "get-url", "--push", "--all", "origin")
144
+ if code or resolved.decode("utf-8").splitlines() != [selected]:
145
+ raise _Refusal("ambiguous_destination")
146
+ raw_head, code = transport.command("rev-parse", "--verify", head_ref)
147
+ head = raw_head.strip().decode("ascii")
148
+ if code or not history.OID.fullmatch(head):
149
+ raise _Refusal("source_unavailable", status="deferred")
150
+ info, git_info = root.stat(), git_dir.stat()
151
+ return {"url": selected, "head_oid": head, "head_ref": head_ref, "branch_ref": branch_ref,
152
+ "repository_identity": [info.st_dev, info.st_ino, git_info.st_dev, git_info.st_ino],
153
+ "repository_fingerprint": history._digest({"repository": str(root), "git_dir": str(git_dir)}),
154
+ "configuration_digest": hashlib.sha256(config).hexdigest(),
155
+ "destination_fingerprint": history._digest({"url": selected, "ref": branch_ref})}
156
+
157
+
158
+ def _remote(transport, selection):
159
+ raw, code = transport.command("ls-remote", "--refs", "--heads", "--", selection["url"], selection["branch_ref"])
160
+ if code:
161
+ raise _Refusal("remote_evidence_unavailable", status="deferred")
162
+ lines = raw.decode("ascii").splitlines()
163
+ if not lines:
164
+ return None
165
+ if len(lines) != 1:
166
+ raise _Refusal("ambiguous_remote_evidence", status="deferred")
167
+ oid, sep, ref = lines[0].partition("\t")
168
+ if not sep or ref != selection["branch_ref"] or not history.OID.fullmatch(oid) or len(oid) != len(selection["head_oid"]):
169
+ raise _Refusal("ambiguous_remote_evidence", status="deferred")
170
+ return oid
171
+
172
+
173
+ def _same(expected, current):
174
+ if expected != current:
175
+ raise _Refusal("source_or_destination_changed", status="deferred")
176
+
177
+
178
+ def inspect_destination(repository, *, branch, head_ref="HEAD", limits=DEFAULT_LIMITS,
179
+ allow_local_transport=False, deadline_monotonic=None):
180
+ """Fresh read-only host selection. This fact carries no publication grant.
181
+
182
+ The native record owner uses the same bounded destination resolver before
183
+ committing and while reconciling an uncertain exact commit. No fetch,
184
+ reconciliation mutation or push occurs here.
185
+ """
186
+ _validate_arguments(limits, allow_local_transport, head_ref)
187
+ branch_ref = _branch(branch)
188
+ deadline = _deadline(limits, deadline_monotonic)
189
+ root, _ = history._repository(repository, deadline)
190
+ transport = _Transport(root, deadline, limits, allow_local_transport)
191
+ selection = _snapshot(transport, root, head_ref, branch_ref)
192
+ base = _remote(transport, selection)
193
+ _same(selection, _snapshot(transport, root, head_ref, branch_ref))
194
+ return selection, base
195
+
196
+
197
+ def _deadline(limits, inherited):
198
+ if inherited is not None and (type(inherited) not in (float, int) or not math.isfinite(inherited)):
199
+ raise ValueError("invalid inherited deadline")
200
+ value = time.monotonic() + limits.seconds
201
+ if inherited is not None:
202
+ value = min(value, inherited)
203
+ if value <= time.monotonic():
204
+ raise ValueError("publication deadline expired")
205
+ return value
206
+
207
+
208
+ def _validate_arguments(limits, allow_local_transport, head_ref):
209
+ if (not isinstance(limits, PushLimits) or type(allow_local_transport) is not bool
210
+ or any(type(getattr(limits, key)) not in (int, float) or not 0 < getattr(limits, key) <= getattr(DEFAULT_LIMITS, key)
211
+ for key in ("seconds", "command_seconds", "push_seconds"))
212
+ or type(limits.output_bytes) is not int or not 1 <= limits.output_bytes <= DEFAULT_LIMITS.output_bytes
213
+ or not isinstance(limits.history, history.HistoryLimits)):
214
+ raise _Refusal("invalid_limits")
215
+ if not isinstance(head_ref, str) or not (head_ref == "HEAD" or head_ref.startswith("refs/heads/") and history._ref(head_ref)):
216
+ raise _Refusal("invalid_source_ref")
217
+
218
+
219
+ def _empty_receipt():
220
+ return {"schema": "egregore.managed-memory-push/v1", "status": "deferred", "cause": "not_started",
221
+ "source_oid": None, "source_ref": None, "base_oid": None, "destination_ref": None,
222
+ "repository_fingerprint": None, "destination_fingerprint": None, "configuration_digest": None,
223
+ "history_digest": None, "history_status": None, "dispatch_attempted": False,
224
+ "reconciled": False, "retry_safe": False, "observed_remote_oid": None, "native_publication_authority": False}
225
+
226
+
227
+ def push_memory(repository, *, branch, head_ref="HEAD", limits=DEFAULT_LIMITS, allow_local_transport=False,
228
+ native_permit=None, deadline_monotonic=None):
229
+ """Inspect and perform at most one exact managed push; no reusable permit.
230
+
231
+ HTTPS is the production transport. The explicit local-transport host option
232
+ retains every history/CAS guard and exists for disposable local receivers.
233
+ Config/source checks detect ordinary concurrent changes, not hostile local
234
+ filesystem mutation after the final check. An explicit remote lease closes
235
+ the destination-ref race; it is used only after proving fast-forward ancestry.
236
+ """
237
+ receipt = _empty_receipt()
238
+ selection, transport = None, None
239
+ try:
240
+ _validate_arguments(limits, allow_local_transport, head_ref)
241
+ branch_ref = _branch(branch)
242
+ if native_permit is not None:
243
+ # The fixed native owner is private. Human-only public bundles do
244
+ # not carry it and must retain the same denied-native boundary.
245
+ try:
246
+ from .record_admission import NativePublicationPermit
247
+ valid_permit = type(native_permit) is NativePublicationPermit
248
+ except ImportError:
249
+ valid_permit = False
250
+ if not valid_permit:
251
+ raise _Refusal("invalid_native_publication_permit")
252
+ deadline = _deadline(limits, deadline_monotonic)
253
+ root, _ = history._repository(repository, deadline)
254
+ transport = _Transport(root, deadline, limits, allow_local_transport)
255
+ selection = _snapshot(transport, root, head_ref, branch_ref)
256
+ receipt.update(source_oid=selection["head_oid"], source_ref=head_ref, destination_ref=branch_ref,
257
+ **{key: selection[key] for key in ("repository_fingerprint", "destination_fingerprint", "configuration_digest")})
258
+ base = _remote(transport, selection)
259
+ receipt.update(base_oid=base, observed_remote_oid=base)
260
+ if base is not None:
261
+ local = history._Git(root, deadline)
262
+ kind, code = local.run("cat-file", "-t", base, limit=32, allowed=(0, 128))
263
+ if code == 128:
264
+ raise _Refusal("remote_base_unavailable_locally", status="deferred")
265
+ if kind.strip() != b"commit":
266
+ raise _Refusal("remote_base_not_commit", status="deferred")
267
+ inspection = history.inspect_outgoing_history(root, base_oid=base, base_ref=None,
268
+ head_oid=selection["head_oid"], head_ref=head_ref,
269
+ limits=replace(limits.history, seconds=min(limits.history.seconds, transport.remaining())))
270
+ receipt.update(history_digest=inspection["digest"], history_status=inspection["status"])
271
+ if inspection["status"] == "present" and native_permit is None:
272
+ raise _Refusal("native_history_requires_admission")
273
+ if inspection["status"] not in {"none", "present"} or not inspection["complete"]:
274
+ raise _Refusal("outgoing_history_unavailable", status="deferred")
275
+ _same(selection, _snapshot(transport, root, head_ref, branch_ref))
276
+ if _remote(transport, selection) != base:
277
+ raise _Refusal("remote_changed", status="deferred")
278
+ # A further source/config check follows the potentially slow remote read.
279
+ _same(selection, _snapshot(transport, root, head_ref, branch_ref))
280
+ if native_permit is not None:
281
+ try:
282
+ native_permit._admit_dispatch(selection, base, inspection)
283
+ except (ValueError, TypeError, AttributeError, OSError, RuntimeError):
284
+ raise _Refusal("native_publication_admission_changed")
285
+ # The fixed owner rechecks source and permissions, potentially over
286
+ # an inherited pipe. Bind HEAD/config once more after that return.
287
+ _same(selection, _snapshot(transport, root, head_ref, branch_ref))
288
+ receipt["native_publication_authority"] = True
289
+ if base == selection["head_oid"]:
290
+ receipt.update(status="pushed", cause="already_current", reconciled=True)
291
+ else:
292
+ receipt["dispatch_attempted"] = True
293
+ push_code = None
294
+ try:
295
+ _, push_code = transport.command("push", "--porcelain", "--no-verify", "--no-follow-tags",
296
+ "--recurse-submodules=no", "--force-with-lease=" + branch_ref + ":" + (base or ""),
297
+ "--", selection["url"], selection["head_oid"] + ":" + branch_ref, seconds=limits.push_seconds)
298
+ except (history._Unknown, OSError, ValueError, subprocess.SubprocessError):
299
+ pass # The only follow-up is a read; never another push.
300
+ try:
301
+ _same(selection, _snapshot(transport, root, head_ref, branch_ref))
302
+ observed = _remote(transport, selection)
303
+ receipt["observed_remote_oid"] = observed
304
+ if observed == selection["head_oid"]:
305
+ receipt.update(status="pushed", cause="acknowledged" if push_code == 0 else "acknowledgement_reconciled", reconciled=True)
306
+ else:
307
+ receipt.update(status="unknown", cause="remote_changed_after_dispatch" if observed != base else "push_acknowledgement_unknown")
308
+ except (history._Unknown, _Refusal, OSError, ValueError, UnicodeError, subprocess.SubprocessError):
309
+ receipt.update(status="unknown", cause="push_acknowledgement_unknown")
310
+ except _Refusal as exc:
311
+ receipt.update(status="unknown" if receipt["dispatch_attempted"] else exc.status,
312
+ cause="push_acknowledgement_unknown" if receipt["dispatch_attempted"] else exc.cause,
313
+ retry_safe=not receipt["dispatch_attempted"] and exc.cause in {
314
+ "source_or_destination_changed", "remote_changed", "remote_base_unavailable_locally"})
315
+ except (history._Unknown, OSError, ValueError, TypeError, UnicodeError, RecursionError, subprocess.SubprocessError):
316
+ receipt.update(status="unknown" if receipt["dispatch_attempted"] else "deferred",
317
+ cause="push_acknowledgement_unknown" if receipt["dispatch_attempted"] else "bounded_evidence_unavailable")
318
+ return {**receipt, "digest": history._digest(receipt)}
319
+
320
+
321
+ def main(argv=None):
322
+ parser = argparse.ArgumentParser(description="Guard one exact managed memory push; native history remains local.")
323
+ parser.add_argument("--repository", required=True)
324
+ parser.add_argument("--branch", required=True)
325
+ parser.add_argument("--head-ref", default="HEAD")
326
+ parser.add_argument("--allow-local-transport", action="store_true", help="explicit local bare fixture transport; all guards remain enabled")
327
+ args = parser.parse_args(argv)
328
+ deadline = time.monotonic() + DEFAULT_LIMITS.seconds
329
+ try:
330
+ # The host selects the memory repository, normally project/memory -> a
331
+ # sibling checkout. Bind that alias once here; the strict history and
332
+ # transport owners receive only its physical path and never reread it.
333
+ repository = Path(args.repository)
334
+ if not repository.is_absolute() or any(ord(c) < 32 or ord(c) == 127 for c in args.repository):
335
+ raise ValueError("invalid repository selection")
336
+ repository = repository.resolve(strict=True)
337
+ except (OSError, ValueError, RuntimeError, UnicodeError):
338
+ receipt = _empty_receipt()
339
+ receipt["cause"] = "bounded_evidence_unavailable"
340
+ receipt["digest"] = history._digest(receipt)
341
+ else:
342
+ receipt = push_memory(repository, branch=args.branch, head_ref=args.head_ref,
343
+ allow_local_transport=args.allow_local_transport, deadline_monotonic=deadline)
344
+ print(json.dumps(receipt, sort_keys=True, separators=(",", ":")))
345
+ return 75 if receipt["retry_safe"] else EXIT_CODES[receipt["status"]]
346
+
347
+
348
+ if __name__ == "__main__":
349
+ raise SystemExit(main())
@@ -2,10 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json
5
6
  import time
6
7
  from dataclasses import dataclass, replace
7
8
  from datetime import UTC, datetime
8
9
  from uuid import uuid4
10
+ from pathlib import Path
9
11
 
10
12
  from .contracts import (
11
13
  ActionAuthorizer,
@@ -14,6 +16,7 @@ from .contracts import (
14
16
  OrgContext,
15
17
  OrgContextCompiler,
16
18
  Permission,
19
+ PolicyDecision,
17
20
  RetrievalHit,
18
21
  RetrievalRequest,
19
22
  Retriever,
@@ -21,10 +24,10 @@ from .contracts import (
21
24
  TelemetrySink,
22
25
  TemporalScope,
23
26
  )
24
- from .admin_gate import AdminGate
25
27
  from .errors import AuthorizationDenied, ContextBudgetError
28
+ from .held import RedactionError, identity, redact
26
29
  from .lifecycle import AuthorityState, CanonicalLifecycleService, LifecycleRecord
27
- from .policy import scope_allows_path
30
+ from .policy import allows, check, narrow, strips
28
31
 
29
32
 
30
33
  def _token_count(content: str) -> int:
@@ -37,13 +40,28 @@ def _truncate_to_budget(content: str, budget: int) -> str:
37
40
  return content[: max(0, budget * 4)]
38
41
 
39
42
 
43
+ def _packaged(decision: PolicyDecision, content: str, root: Path) -> str:
44
+ """``held.redact`` for one passage; a JSON object (discovery's metadata) field by field, keys too, so a
45
+ title that runs into the next field name never breaks it."""
46
+ if not strips(decision):
47
+ return content
48
+ try:
49
+ fields = json.loads(content) if content.startswith("{") else None
50
+ except (ValueError, RecursionError):
51
+ fields = None
52
+ if not isinstance(fields, dict):
53
+ return redact(decision, content, root=root)
54
+ kept = redact(decision, fields, root=root, keys=True)
55
+ return content if kept == fields else json.dumps(kept, ensure_ascii=False)
56
+
57
+
40
58
  @dataclass(slots=True)
41
59
  class DefaultOrgContextCompiler(OrgContextCompiler):
42
60
  authorizer: ActionAuthorizer
43
61
  retriever: Retriever
44
62
  telemetry: TelemetrySink
63
+ memory_root: Path
45
64
  lifecycle: CanonicalLifecycleService | None = None
46
- admin_gate: AdminGate | None = None
47
65
 
48
66
  def observe(
49
67
  self,
@@ -68,12 +86,13 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
68
86
 
69
87
  scopes = tuple(
70
88
  scope
71
- for scope in (request.authorized_scopes or decision.scopes)
72
- if not decision.scopes or scope_allows_path(scope, decision.scopes)
89
+ for scope in (request.authorized_scopes or decision.read_prefixes)
90
+ if allows(decision, scope, "read", root=self.memory_root)
73
91
  )
74
92
  if not scopes:
75
93
  raise AuthorizationDenied("policy produced no authorized retrieval scope")
76
94
 
95
+ narrowed = narrow(decision, "read", scopes)
77
96
  allowed_ids = request.allowed_artifact_ids
78
97
  if decision.resource_ids:
79
98
  allowed_ids = tuple(
@@ -92,33 +111,28 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
92
111
  scoped_retrieve = getattr(self.retriever, "retrieve_authorized", None)
93
112
  result = (
94
113
  scoped_retrieve(authorized_request, actor=actor,
95
- admin_gate=self.admin_gate, lifecycle=self.lifecycle)
114
+ decision=narrowed, lifecycle=self.lifecycle)
96
115
  if callable(scoped_retrieve)
97
116
  else self.retriever.retrieve(authorized_request)
98
117
  )
99
118
 
100
119
  # Defense in depth: an adapter returning an out-of-scope candidate
101
120
  # cannot place it in model context.
102
- authorized_hits = tuple(
103
- hit
104
- for hit in result.hits
105
- if scope_allows_path(hit.canonical_path, scopes)
106
- and (not allowed_ids or hit.artifact_id in allowed_ids)
107
- )
108
-
109
121
  # Egregore-surface admin protection: QMD may match an admin-marked
110
122
  # document internally, but for a non-admin actor it must contribute
111
123
  # nothing to evidence — no title, path, snippet, count detail, or
112
124
  # model context. Only an opaque withheld tally survives.
125
+ visible_hits = []
113
126
  withheld_admin = 0
114
- if self.admin_gate is not None and not self.admin_gate.actor_is_admin(actor):
115
- visible_hits = []
116
- for hit in authorized_hits:
117
- if self.admin_gate.path_is_admin(hit.canonical_path):
118
- withheld_admin += 1
119
- else:
120
- visible_hits.append(hit)
121
- authorized_hits = tuple(visible_hits)
127
+ for hit in result.hits:
128
+ verdict = check(narrowed, hit.canonical_path, "read", root=self.memory_root)
129
+ if allowed_ids and hit.artifact_id not in allowed_ids:
130
+ continue
131
+ if verdict.reason.startswith("held:"):
132
+ withheld_admin += 1
133
+ if verdict.allowed:
134
+ visible_hits.append(hit)
135
+ authorized_hits = tuple(visible_hits)
122
136
 
123
137
  lifecycle_by_path: dict[str, LifecycleRecord] = {}
124
138
  lifecycle_revision = "unavailable"
@@ -128,7 +142,7 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
128
142
  resolved, lifecycle_revision = self.lifecycle.resolve_paths(
129
143
  tuple(hit.canonical_path for hit in authorized_hits),
130
144
  source_revision=result.source_revision,
131
- authorized_scopes=scopes,
145
+ decision=narrowed,
132
146
  allowed_artifact_ids=allowed_ids,
133
147
  )
134
148
  lifecycle_by_path = dict(resolved)
@@ -189,6 +203,7 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
189
203
  request,
190
204
  token_budget,
191
205
  lifecycle_by_path,
206
+ decision=decision, # names are shared or not against all the reader may see
192
207
  )
193
208
  # A rolling-window receipt is reusable only until its oldest delivered
194
209
  # source expires. Omitted/withheld hits must not affect this boundary.
@@ -209,6 +224,20 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
209
224
  for permission in Permission
210
225
  if self.authorizer.authorize_action(actor, permission).allowed
211
226
  )
227
+ # Retrieval and source packaging may outlive the authority that admitted
228
+ # them. Do not deliver a prepared context after revocation or a changed
229
+ # policy: even its omissions may name sources the reader can no longer
230
+ # see. The caller can retry with the current effective decision.
231
+ current_decision = self.authorizer.authorize_observe(actor, request)
232
+ if not current_decision.allowed or current_decision != decision:
233
+ raise AuthorizationDenied("retrieval authority changed; retry the request")
234
+ # Holds can change in canonical files without changing a policy receipt.
235
+ # Recheck every selected path, including sources named only by omissions.
236
+ if any(
237
+ not allows(current_decision, hit.canonical_path, "read", root=self.memory_root)
238
+ for hit in selected_hits
239
+ ):
240
+ raise AuthorizationDenied("retrieval source access changed; retry the request")
212
241
  context = OrgContext(
213
242
  schema_version="egregore-context/v1",
214
243
  context_id=f"ctx_{uuid4().hex}",
@@ -275,6 +304,8 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
275
304
  request: RetrievalRequest,
276
305
  token_budget: int,
277
306
  lifecycle_by_path: dict[str, LifecycleRecord] | None = None,
307
+ *,
308
+ decision: PolicyDecision,
278
309
  ) -> tuple[tuple[EvidenceItem, ...], tuple[str, ...], tuple[str, ...], int]:
279
310
  evidence: list[EvidenceItem] = []
280
311
  opened_ids: list[str] = []
@@ -298,8 +329,16 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
298
329
  omissions.append(f"stale-passage:{hit.canonical_path}")
299
330
  else:
300
331
  content = hit.passage or ""
332
+ # The one packaging, before the budget cuts: names of documents held from this reader leave
333
+ # every excerpt, title, source, revision and id; a text that cannot be redacted is not handed over.
334
+ try:
335
+ content = _packaged(decision, content, self.memory_root)
336
+ revision = redact(decision, hit.revision or "unknown", root=self.memory_root)
337
+ artifact_id = identity(decision, hit.artifact_id, hit.canonical_path, root=self.memory_root)
338
+ except RedactionError:
339
+ continue
301
340
  if not content:
302
- omissions.append(f"empty:{hit.artifact_id}")
341
+ omissions.append(f"empty:{artifact_id}")
303
342
  continue
304
343
 
305
344
  count = _token_count(content)
@@ -310,9 +349,9 @@ class DefaultOrgContextCompiler(OrgContextCompiler):
310
349
  omissions.append(f"truncated:{hit.canonical_path}")
311
350
  evidence.append(
312
351
  EvidenceItem(
313
- artifact_id=hit.artifact_id,
352
+ artifact_id=artifact_id,
314
353
  canonical_path=hit.canonical_path,
315
- revision=hit.revision or "unknown",
354
+ revision=revision,
316
355
  reason=self._evidence_reason(
317
356
  hit,
318
357
  (lifecycle_by_path or {}).get(hit.canonical_path),
@@ -0,0 +1,19 @@
1
+ """Disposable observers for completed, authorized Runtime operations."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Callable
5
+ from .contracts import ExecutionAuthority
6
+
7
+
8
+ @dataclass(frozen=True, slots=True)
9
+ class RuntimeEvent:
10
+ kind: str
11
+ actor_id: str
12
+ session_id: str
13
+ harness: str
14
+ paths: tuple[str, ...]
15
+ execution: ExecutionAuthority | None = None
16
+
17
+
18
+ Observer = Callable[[RuntimeEvent], None]
19
+ MAX_EVENT_PATHS = 40
@@ -0,0 +1,13 @@
1
+ """Load a separately delivered module; failures inside installed code still raise."""
2
+ from importlib import import_module
3
+ from importlib.util import resolve_name
4
+
5
+
6
+ def optional_module(name: str):
7
+ absolute = resolve_name(name, __package__)
8
+ try:
9
+ return import_module(absolute)
10
+ except ModuleNotFoundError as exc:
11
+ if exc.name != absolute:
12
+ raise
13
+ return None