create-egregore 0.20.2 → 0.21.0-runtime-mvp.2

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 (706) hide show
  1. package/assets/egregore-launcher.js +1013 -16
  2. package/bin/cli.js +11 -0
  3. package/lib/claude-runtime.js +192 -0
  4. package/lib/local.js +38 -31
  5. package/lib/pi-runtime.js +1 -0
  6. package/lib/prime-runtime.js +1 -0
  7. package/lib/runtime-identity.js +146 -0
  8. package/lib/setup.js +116 -17
  9. package/package.json +10 -6
  10. package/runtime/claude/.claude/context/commit-format.md +110 -0
  11. package/runtime/claude/.claude/context/git-language.md +46 -0
  12. package/runtime/claude/.claude/context/notification-consent.md +66 -0
  13. package/runtime/claude/.claude/context/pr-format.md +67 -0
  14. package/runtime/claude/.claude/context/telemetry.md +133 -0
  15. package/runtime/claude/.claude/hooks/boundary-check.sh +333 -0
  16. package/runtime/claude/.claude/hooks/branch-guard.sh +231 -0
  17. package/runtime/claude/.claude/hooks/card-context.sh +38 -0
  18. package/runtime/claude/.claude/hooks/emissary-detect.sh +53 -0
  19. package/runtime/claude/.claude/hooks/memory-refresh.sh +67 -0
  20. package/runtime/claude/.claude/hooks/onboarding-guard.sh +86 -0
  21. package/runtime/claude/.claude/hooks/retrieval-context.sh +43 -0
  22. package/runtime/claude/.claude/rules/voice-bedrock.md +73 -0
  23. package/runtime/claude/.claude/settings.json +131 -0
  24. package/runtime/claude/.claude/skills/activity/SKILL.md +68 -0
  25. package/runtime/claude/.claude/skills/announce/SKILL.md +54 -0
  26. package/runtime/claude/.claude/skills/archive/SKILL.md +71 -0
  27. package/runtime/claude/.claude/skills/branch/SKILL.md +147 -0
  28. package/runtime/claude/.claude/skills/checkup/SKILL.md +159 -0
  29. package/runtime/claude/.claude/skills/commit/SKILL.md +103 -0
  30. package/runtime/claude/.claude/skills/contribute/SKILL.md +343 -0
  31. package/runtime/claude/.claude/skills/create-skill/SKILL.md +135 -0
  32. package/runtime/claude/.claude/skills/dark-mode/SKILL.md +410 -0
  33. package/runtime/claude/.claude/skills/dashboard/SKILL.md +43 -0
  34. package/runtime/claude/.claude/skills/deep-reflect/REPORT.md +140 -0
  35. package/runtime/claude/.claude/skills/deep-reflect/RESEARCH.md +132 -0
  36. package/runtime/claude/.claude/skills/deep-reflect/ROLES.md +104 -0
  37. package/runtime/claude/.claude/skills/deep-reflect/SKILL.md +170 -0
  38. package/runtime/claude/.claude/skills/delete-user/SKILL.md +150 -0
  39. package/runtime/claude/.claude/skills/emissary/SKILL.md +220 -0
  40. package/runtime/claude/.claude/skills/handoff/SKILL.md +124 -0
  41. package/runtime/claude/.claude/skills/harvest/AUDIT.md +546 -0
  42. package/runtime/claude/.claude/skills/harvest/FORMAT.md +436 -0
  43. package/runtime/claude/.claude/skills/harvest/PROCESS.md +395 -0
  44. package/runtime/claude/.claude/skills/harvest/QUESTION_PALETTE.md +76 -0
  45. package/runtime/claude/.claude/skills/harvest/SKILL.md +100 -0
  46. package/runtime/claude/.claude/skills/ingest/SKILL.md +112 -0
  47. package/runtime/claude/.claude/skills/ingest-corpus/SKILL.md +187 -0
  48. package/runtime/claude/.claude/skills/ingest-notion/SKILL.md +214 -0
  49. package/runtime/claude/.claude/skills/ingest-user-interview/SKILL.md +65 -0
  50. package/runtime/claude/.claude/skills/ingest-user-interview/references/analysis-contract.md +125 -0
  51. package/runtime/claude/.claude/skills/invite/SKILL.md +111 -0
  52. package/runtime/claude/.claude/skills/issue/SKILL.md +104 -0
  53. package/runtime/claude/.claude/skills/me/SKILL.md +81 -0
  54. package/runtime/claude/.claude/skills/meeting/SKILL.md +76 -0
  55. package/runtime/claude/.claude/skills/meeting/references/analysis-contract.md +102 -0
  56. package/runtime/claude/.claude/skills/note/SKILL.md +71 -0
  57. package/runtime/claude/.claude/skills/notion-connect/SKILL.md +124 -0
  58. package/runtime/claude/.claude/skills/onboarding/SKILL.md +159 -0
  59. package/runtime/claude/.claude/skills/pr/SKILL.md +85 -0
  60. package/runtime/claude/.claude/skills/pull/SKILL.md +79 -0
  61. package/runtime/claude/.claude/skills/push/SKILL.md +47 -0
  62. package/runtime/claude/.claude/skills/quest/SKILL.md +121 -0
  63. package/runtime/claude/.claude/skills/reflect/SKILL.md +69 -0
  64. package/runtime/claude/.claude/skills/review-pr/SKILL.md +276 -0
  65. package/runtime/claude/.claude/skills/save/SKILL.md +92 -0
  66. package/runtime/claude/.claude/skills/slack-connect/SKILL.md +148 -0
  67. package/runtime/claude/.claude/skills/summon/SKILL.md +240 -0
  68. package/runtime/claude/.claude/skills/sync-repos/SKILL.md +82 -0
  69. package/runtime/claude/.claude/skills/teams-connect/SKILL.md +216 -0
  70. package/runtime/claude/.claude/skills/telegram-connect/SKILL.md +110 -0
  71. package/runtime/claude/.claude/skills/telemetry/SKILL.md +117 -0
  72. package/runtime/claude/.claude/skills/test/SKILL.md +87 -0
  73. package/runtime/claude/.claude/skills/the-spiral/SKILL.md +492 -0
  74. package/runtime/claude/.claude/skills/tui-design/SKILL.md +188 -0
  75. package/runtime/claude/.claude/skills/tutorial/SKILL.md +100 -0
  76. package/runtime/claude/.claude/skills/update/SKILL.md +265 -0
  77. package/runtime/claude/.claude/skills/view/SKILL.md +393 -0
  78. package/runtime/claude/.claude/skills/view/compose-scaffold.html +221 -0
  79. package/runtime/claude/.claude/skills/visual-explain/SKILL.md +132 -0
  80. package/runtime/claude/.claude/skills/wrap/SKILL.md +98 -0
  81. package/runtime/claude/CLAUDE.md +447 -0
  82. package/runtime/claude/bin/activity-action.sh +92 -0
  83. package/runtime/claude/bin/activity-data.sh +17 -0
  84. package/runtime/claude/bin/agent.sh +783 -0
  85. package/runtime/claude/bin/artifact-register.sh +164 -0
  86. package/runtime/claude/bin/artifact-writeback.sh +53 -0
  87. package/runtime/claude/bin/artifacts.sh +288 -0
  88. package/runtime/claude/bin/attendant.sh +707 -0
  89. package/runtime/claude/bin/autosave.sh +112 -0
  90. package/runtime/claude/bin/boundary.sh +253 -0
  91. package/runtime/claude/bin/build-sealed-dataroom.mjs +722 -0
  92. package/runtime/claude/bin/capture-reconcile.sh +69 -0
  93. package/runtime/claude/bin/capture-run.sh +357 -0
  94. package/runtime/claude/bin/codex-install-skills.sh +78 -0
  95. package/runtime/claude/bin/codex-render-spec.mjs +462 -0
  96. package/runtime/claude/bin/codex-session-start.sh +275 -0
  97. package/runtime/claude/bin/codex-skill-render.mjs +349 -0
  98. package/runtime/claude/bin/codex-sync-skills.sh +237 -0
  99. package/runtime/claude/bin/connect-refresh.sh +33 -0
  100. package/runtime/claude/bin/contribute-guard.sh +79 -0
  101. package/runtime/claude/bin/corpus_map.py +806 -0
  102. package/runtime/claude/bin/corpus_survey.py +304 -0
  103. package/runtime/claude/bin/dashboard-data.sh +18 -0
  104. package/runtime/claude/bin/github-auth.sh +121 -0
  105. package/runtime/claude/bin/graph-batch.sh +86 -0
  106. package/runtime/claude/bin/graph-op.sh +1106 -0
  107. package/runtime/claude/bin/graph-projection.sh +54 -0
  108. package/runtime/claude/bin/graph-wal.sh +242 -0
  109. package/runtime/claude/bin/graph.sh +267 -0
  110. package/runtime/claude/bin/handoff-lifecycle-job.sh +146 -0
  111. package/runtime/claude/bin/handoff-lifecycle.sh +280 -0
  112. package/runtime/claude/bin/handoff-pr-backfill.sh +86 -0
  113. package/runtime/claude/bin/handoff-preview.sh +169 -0
  114. package/runtime/claude/bin/handoff-run.sh +692 -0
  115. package/runtime/claude/bin/handoff-save-egregore.sh +224 -0
  116. package/runtime/claude/bin/index-handoff.sh +322 -0
  117. package/runtime/claude/bin/ingest-graph.sh +86 -0
  118. package/runtime/claude/bin/ingest-item.sh +10 -0
  119. package/runtime/claude/bin/ingest-surface.html +495 -0
  120. package/runtime/claude/bin/ingest.py +1011 -0
  121. package/runtime/claude/bin/ingest.sh +308 -0
  122. package/runtime/claude/bin/ingest_graph.py +856 -0
  123. package/runtime/claude/bin/ingest_surface.py +544 -0
  124. package/runtime/claude/bin/invite.sh +6 -0
  125. package/runtime/claude/bin/issue.sh +10 -0
  126. package/runtime/claude/bin/knowledge.sh +10 -0
  127. package/runtime/claude/bin/lib/artifact-id.sh +46 -0
  128. package/runtime/claude/bin/lib/config.sh +136 -0
  129. package/runtime/claude/bin/lib/context.sh +642 -0
  130. package/runtime/claude/bin/lib/dashboard-artifact.sh +242 -0
  131. package/runtime/claude/bin/lib/ensure-develop.sh +183 -0
  132. package/runtime/claude/bin/lib/git-message.sh +37 -0
  133. package/runtime/claude/bin/lib/git-sync.sh +494 -0
  134. package/runtime/claude/bin/lib/greeting.sh +548 -0
  135. package/runtime/claude/bin/lib/handoff-meta.sh +97 -0
  136. package/runtime/claude/bin/lib/hash.sh +13 -0
  137. package/runtime/claude/bin/lib/identity.sh +213 -0
  138. package/runtime/claude/bin/lib/metrics.sh +374 -0
  139. package/runtime/claude/bin/lib/noncode.sh +31 -0
  140. package/runtime/claude/bin/lib/permissions.sh +106 -0
  141. package/runtime/claude/bin/lib/time.sh +56 -0
  142. package/runtime/claude/bin/lib/worktree-links.sh +85 -0
  143. package/runtime/claude/bin/node-run.sh +42 -0
  144. package/runtime/claude/bin/notification.sh +6 -0
  145. package/runtime/claude/bin/notify.sh +636 -0
  146. package/runtime/claude/bin/observe-context.sh +14 -0
  147. package/runtime/claude/bin/onboarding.sh +6 -0
  148. package/runtime/claude/bin/person.py +634 -0
  149. package/runtime/claude/bin/person.sh +481 -0
  150. package/runtime/claude/bin/pi-render-spec.mjs +140 -0
  151. package/runtime/claude/bin/post-update.sh +37 -0
  152. package/runtime/claude/bin/prime-render-spec.mjs +147 -0
  153. package/runtime/claude/bin/publish-artifact.sh +324 -0
  154. package/runtime/claude/bin/publish-references.sh +144 -0
  155. package/runtime/claude/bin/quest.sh +9 -0
  156. package/runtime/claude/bin/question.sh +8 -0
  157. package/runtime/claude/bin/repo-state.sh +96 -0
  158. package/runtime/claude/bin/research-ingest.sh +7 -0
  159. package/runtime/claude/bin/restore-owned-skills.sh +67 -0
  160. package/runtime/claude/bin/retrieval_eval.py +385 -0
  161. package/runtime/claude/bin/runtime-identity.sh +70 -0
  162. package/runtime/claude/bin/runtime-upgrade.sh +43 -0
  163. package/runtime/claude/bin/scroll.sh +9 -0
  164. package/runtime/claude/bin/search.sh +318 -0
  165. package/runtime/claude/bin/session-autosave.sh +220 -0
  166. package/runtime/claude/bin/session-log.sh +199 -0
  167. package/runtime/claude/bin/session-start.sh +696 -0
  168. package/runtime/claude/bin/settings.sh +532 -0
  169. package/runtime/claude/bin/startup-check.sh +136 -0
  170. package/runtime/claude/bin/statusline.sh +41 -0
  171. package/runtime/claude/bin/telemetry.sh +666 -0
  172. package/runtime/claude/bin/test-changes.sh +344 -0
  173. package/runtime/claude/bin/thread.sh +9 -0
  174. package/runtime/claude/bin/todo.sh +9 -0
  175. package/runtime/claude/bin/view-render.sh +126 -0
  176. package/runtime/claude/bin/worktree-create.sh +145 -0
  177. package/runtime/claude/bin/worktree-remove.sh +50 -0
  178. package/runtime/claude/bin/worktree.sh +198 -0
  179. package/runtime/claude/egregore_runtime/__init__.py +228 -0
  180. package/runtime/claude/egregore_runtime/adapters/__init__.py +5 -0
  181. package/runtime/claude/egregore_runtime/adapters/invitation.py +237 -0
  182. package/runtime/claude/egregore_runtime/adapters/notification.py +59 -0
  183. package/runtime/claude/egregore_runtime/adapters/qmd.py +1701 -0
  184. package/runtime/claude/egregore_runtime/adapters/qmd_cli.py +210 -0
  185. package/runtime/claude/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  186. package/runtime/claude/egregore_runtime/admin_gate.py +102 -0
  187. package/runtime/claude/egregore_runtime/artifacts.py +523 -0
  188. package/runtime/claude/egregore_runtime/contracts.py +499 -0
  189. package/runtime/claude/egregore_runtime/entitlements.py +85 -0
  190. package/runtime/claude/egregore_runtime/errors.py +10 -0
  191. package/runtime/claude/egregore_runtime/graph.py +356 -0
  192. package/runtime/claude/egregore_runtime/handoff_lookup.py +196 -0
  193. package/runtime/claude/egregore_runtime/harness_cli.py +1221 -0
  194. package/runtime/claude/egregore_runtime/identity.py +734 -0
  195. package/runtime/claude/egregore_runtime/identity_cli.py +91 -0
  196. package/runtime/claude/egregore_runtime/ingest.py +575 -0
  197. package/runtime/claude/egregore_runtime/ingest_cli.py +254 -0
  198. package/runtime/claude/egregore_runtime/ingest_index_cli.py +147 -0
  199. package/runtime/claude/egregore_runtime/invitation_cli.py +51 -0
  200. package/runtime/claude/egregore_runtime/invitations.py +116 -0
  201. package/runtime/claude/egregore_runtime/issue_cli.py +305 -0
  202. package/runtime/claude/egregore_runtime/issues.py +359 -0
  203. package/runtime/claude/egregore_runtime/knowledge.py +376 -0
  204. package/runtime/claude/egregore_runtime/knowledge_cli.py +173 -0
  205. package/runtime/claude/egregore_runtime/lifecycle.py +888 -0
  206. package/runtime/claude/egregore_runtime/lifecycle_cli.py +269 -0
  207. package/runtime/claude/egregore_runtime/notification_cli.py +125 -0
  208. package/runtime/claude/egregore_runtime/notifications.py +230 -0
  209. package/runtime/claude/egregore_runtime/observe.py +342 -0
  210. package/runtime/claude/egregore_runtime/onboarding.py +290 -0
  211. package/runtime/claude/egregore_runtime/onboarding_cli.py +110 -0
  212. package/runtime/claude/egregore_runtime/policy.py +144 -0
  213. package/runtime/claude/egregore_runtime/profile.py +193 -0
  214. package/runtime/claude/egregore_runtime/quest_cli.py +216 -0
  215. package/runtime/claude/egregore_runtime/question_cli.py +180 -0
  216. package/runtime/claude/egregore_runtime/questions.py +304 -0
  217. package/runtime/claude/egregore_runtime/quests.py +419 -0
  218. package/runtime/claude/egregore_runtime/readiness.py +379 -0
  219. package/runtime/claude/egregore_runtime/research_ingest.py +256 -0
  220. package/runtime/claude/egregore_runtime/research_ingest_cli.py +44 -0
  221. package/runtime/claude/egregore_runtime/runtime.py +464 -0
  222. package/runtime/claude/egregore_runtime/scroll_cli.py +185 -0
  223. package/runtime/claude/egregore_runtime/scrolls.py +726 -0
  224. package/runtime/claude/egregore_runtime/status.py +412 -0
  225. package/runtime/claude/egregore_runtime/status_cli.py +174 -0
  226. package/runtime/claude/egregore_runtime/sync.py +218 -0
  227. package/runtime/claude/egregore_runtime/teamsync.py +139 -0
  228. package/runtime/claude/egregore_runtime/telemetry.py +640 -0
  229. package/runtime/claude/egregore_runtime/thread_cli.py +173 -0
  230. package/runtime/claude/egregore_runtime/threads.py +517 -0
  231. package/runtime/claude/egregore_runtime/todo_cli.py +142 -0
  232. package/runtime/claude/egregore_runtime/todos.py +244 -0
  233. package/runtime/claude/egregore_runtime/upgrade.py +770 -0
  234. package/runtime/claude/egregore_runtime/upgrade_worker.py +53 -0
  235. package/runtime/claude/egregore_runtime/writeback.py +391 -0
  236. package/runtime/claude/egregore_runtime/writeback_cli.py +114 -0
  237. package/runtime/claude/manifest.json +284 -0
  238. package/runtime/codex/.codex/hooks/search-hint.js +21 -52
  239. package/runtime/codex/.codex/hooks.json +3 -3
  240. package/runtime/codex/.codex/skills/activity/SKILL.md +23 -66
  241. package/runtime/codex/.codex/skills/announce/SKILL.md +27 -50
  242. package/runtime/codex/.codex/skills/archive/SKILL.md +21 -36
  243. package/runtime/codex/.codex/skills/checkup/SKILL.md +77 -36
  244. package/runtime/codex/.codex/skills/dark-mode/SKILL.md +1 -1
  245. package/runtime/codex/.codex/skills/dashboard/SKILL.md +17 -47
  246. package/runtime/codex/.codex/skills/handoff/SKILL.md +84 -133
  247. package/runtime/codex/.codex/skills/harvest/SKILL.md +32 -117
  248. package/runtime/codex/.codex/skills/ingest/SKILL.md +47 -25
  249. package/runtime/codex/.codex/skills/ingest-user-interview/SKILL.md +18 -36
  250. package/runtime/codex/.codex/skills/ingest-user-interview/references/analysis-contract.md +42 -0
  251. package/runtime/codex/.codex/skills/invite/SKILL.md +21 -35
  252. package/runtime/codex/.codex/skills/issue/SKILL.md +60 -41
  253. package/runtime/codex/.codex/skills/me/SKILL.md +1 -1
  254. package/runtime/codex/.codex/skills/meeting/SKILL.md +16 -36
  255. package/runtime/codex/.codex/skills/meeting/references/analysis-contract.md +48 -0
  256. package/runtime/codex/.codex/skills/note/SKILL.md +30 -25
  257. package/runtime/codex/.codex/skills/onboarding/SKILL.md +36 -41
  258. package/runtime/codex/.codex/skills/pull/SKILL.md +1 -1
  259. package/runtime/codex/.codex/skills/quest/SKILL.md +27 -66
  260. package/runtime/codex/.codex/skills/reflect/SKILL.md +22 -36
  261. package/runtime/codex/.codex/skills/save/SKILL.md +2 -2
  262. package/runtime/codex/.codex/skills/telemetry/SKILL.md +1 -1
  263. package/runtime/codex/.codex/skills/test/SKILL.md +1 -1
  264. package/runtime/codex/.codex/skills/tutorial/SKILL.md +40 -41
  265. package/runtime/codex/.codex/skills/view/SKILL.md +115 -111
  266. package/runtime/codex/.codex/skills/wrap/SKILL.md +45 -41
  267. package/runtime/codex/.codex/spec-manifest.json +9 -9
  268. package/runtime/codex/AGENTS.md +62 -58
  269. package/runtime/codex/bin/activity-action.sh +92 -0
  270. package/runtime/codex/bin/activity-data.sh +12 -233
  271. package/runtime/codex/bin/agent.sh +84 -100
  272. package/runtime/codex/bin/artifact-register.sh +164 -0
  273. package/runtime/codex/bin/artifact-writeback.sh +53 -0
  274. package/runtime/codex/bin/artifacts.sh +288 -0
  275. package/runtime/codex/bin/build-sealed-dataroom.mjs +722 -0
  276. package/runtime/codex/bin/capture-run.sh +18 -2
  277. package/runtime/codex/bin/codex-render-spec.mjs +41 -16
  278. package/runtime/codex/bin/codex-session-start.sh +14 -4
  279. package/runtime/codex/bin/codex-skill-render.mjs +9 -7
  280. package/runtime/codex/bin/corpus_map.py +806 -0
  281. package/runtime/codex/bin/corpus_survey.py +304 -0
  282. package/runtime/codex/bin/dashboard-data.sh +11 -171
  283. package/runtime/codex/bin/github-auth.sh +121 -0
  284. package/runtime/codex/bin/graph-batch.sh +7 -0
  285. package/runtime/codex/bin/graph-op.sh +4 -0
  286. package/runtime/codex/bin/graph-projection.sh +54 -0
  287. package/runtime/codex/bin/graph-wal.sh +13 -0
  288. package/runtime/codex/bin/graph.sh +44 -0
  289. package/runtime/codex/bin/handoff-lifecycle-job.sh +146 -0
  290. package/runtime/codex/bin/handoff-lifecycle.sh +280 -0
  291. package/runtime/codex/bin/handoff-preview.sh +169 -0
  292. package/runtime/codex/bin/handoff-run.sh +42 -26
  293. package/runtime/codex/bin/ingest-graph.sh +6 -0
  294. package/runtime/codex/bin/ingest-item.sh +10 -0
  295. package/runtime/codex/bin/ingest.sh +59 -30
  296. package/runtime/codex/bin/invite.sh +6 -0
  297. package/runtime/codex/bin/issue.sh +10 -0
  298. package/runtime/codex/bin/knowledge.sh +10 -0
  299. package/runtime/codex/bin/lib/config.sh +20 -0
  300. package/runtime/codex/bin/lib/context.sh +46 -25
  301. package/runtime/codex/bin/lib/git-sync.sh +70 -6
  302. package/runtime/codex/bin/lib/greeting.sh +34 -5
  303. package/runtime/codex/bin/lib/handoff-meta.sh +97 -0
  304. package/runtime/codex/bin/lib/worktree-links.sh +6 -0
  305. package/runtime/codex/bin/node-run.sh +42 -0
  306. package/runtime/codex/bin/notification.sh +6 -0
  307. package/runtime/codex/bin/observe-context.sh +14 -0
  308. package/runtime/codex/bin/onboarding.sh +6 -0
  309. package/runtime/codex/bin/person.py +4 -0
  310. package/runtime/codex/bin/person.sh +43 -10
  311. package/runtime/codex/bin/pi-render-spec.mjs +140 -0
  312. package/runtime/codex/bin/post-update.sh +37 -0
  313. package/runtime/codex/bin/prime-render-spec.mjs +147 -0
  314. package/runtime/codex/bin/publish-artifact.sh +55 -2
  315. package/runtime/codex/bin/quest.sh +9 -0
  316. package/runtime/codex/bin/question.sh +8 -0
  317. package/runtime/codex/bin/research-ingest.sh +7 -0
  318. package/runtime/codex/bin/restore-owned-skills.sh +67 -0
  319. package/runtime/codex/bin/retrieval_eval.py +385 -0
  320. package/runtime/codex/bin/runtime-identity.sh +70 -0
  321. package/runtime/codex/bin/runtime-upgrade.sh +43 -0
  322. package/runtime/codex/bin/scroll.sh +9 -0
  323. package/runtime/codex/bin/search.sh +231 -195
  324. package/runtime/codex/bin/settings.sh +174 -5
  325. package/runtime/codex/bin/startup-check.sh +136 -0
  326. package/runtime/codex/bin/telemetry.sh +522 -247
  327. package/runtime/codex/bin/test-changes.sh +344 -0
  328. package/runtime/codex/bin/thread.sh +9 -0
  329. package/runtime/codex/bin/todo.sh +9 -0
  330. package/runtime/codex/bin/view-render.sh +126 -0
  331. package/runtime/codex/bin/worktree-create.sh +19 -5
  332. package/runtime/codex/egregore_runtime/__init__.py +228 -0
  333. package/runtime/codex/egregore_runtime/adapters/__init__.py +5 -0
  334. package/runtime/codex/egregore_runtime/adapters/invitation.py +237 -0
  335. package/runtime/codex/egregore_runtime/adapters/notification.py +59 -0
  336. package/runtime/codex/egregore_runtime/adapters/qmd.py +1701 -0
  337. package/runtime/codex/egregore_runtime/adapters/qmd_cli.py +210 -0
  338. package/runtime/codex/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  339. package/runtime/codex/egregore_runtime/admin_gate.py +102 -0
  340. package/runtime/codex/egregore_runtime/artifacts.py +523 -0
  341. package/runtime/codex/egregore_runtime/contracts.py +499 -0
  342. package/runtime/codex/egregore_runtime/entitlements.py +85 -0
  343. package/runtime/codex/egregore_runtime/errors.py +10 -0
  344. package/runtime/codex/egregore_runtime/graph.py +356 -0
  345. package/runtime/codex/egregore_runtime/handoff_lookup.py +196 -0
  346. package/runtime/codex/egregore_runtime/harness_cli.py +1221 -0
  347. package/runtime/codex/egregore_runtime/identity.py +734 -0
  348. package/runtime/codex/egregore_runtime/identity_cli.py +91 -0
  349. package/runtime/codex/egregore_runtime/ingest.py +575 -0
  350. package/runtime/codex/egregore_runtime/ingest_cli.py +254 -0
  351. package/runtime/codex/egregore_runtime/ingest_index_cli.py +147 -0
  352. package/runtime/codex/egregore_runtime/invitation_cli.py +51 -0
  353. package/runtime/codex/egregore_runtime/invitations.py +116 -0
  354. package/runtime/codex/egregore_runtime/issue_cli.py +305 -0
  355. package/runtime/codex/egregore_runtime/issues.py +359 -0
  356. package/runtime/codex/egregore_runtime/knowledge.py +376 -0
  357. package/runtime/codex/egregore_runtime/knowledge_cli.py +173 -0
  358. package/runtime/codex/egregore_runtime/lifecycle.py +888 -0
  359. package/runtime/codex/egregore_runtime/lifecycle_cli.py +269 -0
  360. package/runtime/codex/egregore_runtime/notification_cli.py +125 -0
  361. package/runtime/codex/egregore_runtime/notifications.py +230 -0
  362. package/runtime/codex/egregore_runtime/observe.py +342 -0
  363. package/runtime/codex/egregore_runtime/onboarding.py +290 -0
  364. package/runtime/codex/egregore_runtime/onboarding_cli.py +110 -0
  365. package/runtime/codex/egregore_runtime/policy.py +144 -0
  366. package/runtime/codex/egregore_runtime/profile.py +193 -0
  367. package/runtime/codex/egregore_runtime/quest_cli.py +216 -0
  368. package/runtime/codex/egregore_runtime/question_cli.py +180 -0
  369. package/runtime/codex/egregore_runtime/questions.py +304 -0
  370. package/runtime/codex/egregore_runtime/quests.py +419 -0
  371. package/runtime/codex/egregore_runtime/readiness.py +379 -0
  372. package/runtime/codex/egregore_runtime/research_ingest.py +256 -0
  373. package/runtime/codex/egregore_runtime/research_ingest_cli.py +44 -0
  374. package/runtime/codex/egregore_runtime/runtime.py +464 -0
  375. package/runtime/codex/egregore_runtime/scroll_cli.py +185 -0
  376. package/runtime/codex/egregore_runtime/scrolls.py +726 -0
  377. package/runtime/codex/egregore_runtime/status.py +412 -0
  378. package/runtime/codex/egregore_runtime/status_cli.py +174 -0
  379. package/runtime/codex/egregore_runtime/sync.py +218 -0
  380. package/runtime/codex/egregore_runtime/teamsync.py +139 -0
  381. package/runtime/codex/egregore_runtime/telemetry.py +640 -0
  382. package/runtime/codex/egregore_runtime/thread_cli.py +173 -0
  383. package/runtime/codex/egregore_runtime/threads.py +517 -0
  384. package/runtime/codex/egregore_runtime/todo_cli.py +142 -0
  385. package/runtime/codex/egregore_runtime/todos.py +244 -0
  386. package/runtime/codex/egregore_runtime/upgrade.py +770 -0
  387. package/runtime/codex/egregore_runtime/upgrade_worker.py +53 -0
  388. package/runtime/codex/egregore_runtime/writeback.py +391 -0
  389. package/runtime/codex/egregore_runtime/writeback_cli.py +114 -0
  390. package/runtime/codex/manifest.json +98 -1
  391. package/runtime/pi/.codex/hooks/search-hint.js +21 -52
  392. package/runtime/pi/.codex/hooks.json +3 -3
  393. package/runtime/pi/.codex/skills/activity/SKILL.md +23 -66
  394. package/runtime/pi/.codex/skills/announce/SKILL.md +27 -50
  395. package/runtime/pi/.codex/skills/archive/SKILL.md +21 -36
  396. package/runtime/pi/.codex/skills/checkup/SKILL.md +77 -36
  397. package/runtime/pi/.codex/skills/dark-mode/SKILL.md +1 -1
  398. package/runtime/pi/.codex/skills/dashboard/SKILL.md +17 -47
  399. package/runtime/pi/.codex/skills/handoff/SKILL.md +84 -133
  400. package/runtime/pi/.codex/skills/harvest/SKILL.md +32 -117
  401. package/runtime/pi/.codex/skills/ingest/SKILL.md +47 -25
  402. package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +18 -36
  403. package/runtime/pi/.codex/skills/ingest-user-interview/references/analysis-contract.md +42 -0
  404. package/runtime/pi/.codex/skills/invite/SKILL.md +21 -35
  405. package/runtime/pi/.codex/skills/issue/SKILL.md +60 -41
  406. package/runtime/pi/.codex/skills/me/SKILL.md +1 -1
  407. package/runtime/pi/.codex/skills/meeting/SKILL.md +16 -36
  408. package/runtime/pi/.codex/skills/meeting/references/analysis-contract.md +48 -0
  409. package/runtime/pi/.codex/skills/note/SKILL.md +30 -25
  410. package/runtime/pi/.codex/skills/onboarding/SKILL.md +36 -41
  411. package/runtime/pi/.codex/skills/pull/SKILL.md +1 -1
  412. package/runtime/pi/.codex/skills/quest/SKILL.md +27 -66
  413. package/runtime/pi/.codex/skills/reflect/SKILL.md +22 -36
  414. package/runtime/pi/.codex/skills/save/SKILL.md +2 -2
  415. package/runtime/pi/.codex/skills/telemetry/SKILL.md +1 -1
  416. package/runtime/pi/.codex/skills/test/SKILL.md +1 -1
  417. package/runtime/pi/.codex/skills/tutorial/SKILL.md +40 -41
  418. package/runtime/pi/.codex/skills/view/SKILL.md +115 -111
  419. package/runtime/pi/.codex/skills/wrap/SKILL.md +45 -41
  420. package/runtime/pi/.codex/spec-manifest.json +9 -9
  421. package/runtime/pi/.pi/APPEND_SYSTEM.md +57 -48
  422. package/runtime/pi/.pi/extensions/egregore.ts +7 -0
  423. package/runtime/pi/.pi/spec-manifest.json +2 -2
  424. package/runtime/pi/AGENTS.md +62 -58
  425. package/runtime/pi/bin/activity-action.sh +92 -0
  426. package/runtime/pi/bin/activity-data.sh +12 -233
  427. package/runtime/pi/bin/agent.sh +84 -100
  428. package/runtime/pi/bin/artifact-register.sh +164 -0
  429. package/runtime/pi/bin/artifact-writeback.sh +53 -0
  430. package/runtime/pi/bin/artifacts.sh +288 -0
  431. package/runtime/pi/bin/build-sealed-dataroom.mjs +722 -0
  432. package/runtime/pi/bin/capture-run.sh +18 -2
  433. package/runtime/pi/bin/codex-render-spec.mjs +41 -16
  434. package/runtime/pi/bin/codex-session-start.sh +14 -4
  435. package/runtime/pi/bin/codex-skill-render.mjs +9 -7
  436. package/runtime/pi/bin/corpus_map.py +806 -0
  437. package/runtime/pi/bin/corpus_survey.py +304 -0
  438. package/runtime/pi/bin/dashboard-data.sh +11 -171
  439. package/runtime/pi/bin/github-auth.sh +121 -0
  440. package/runtime/pi/bin/graph-batch.sh +7 -0
  441. package/runtime/pi/bin/graph-op.sh +4 -0
  442. package/runtime/pi/bin/graph-projection.sh +54 -0
  443. package/runtime/pi/bin/graph-wal.sh +13 -0
  444. package/runtime/pi/bin/graph.sh +44 -0
  445. package/runtime/pi/bin/handoff-lifecycle-job.sh +146 -0
  446. package/runtime/pi/bin/handoff-lifecycle.sh +280 -0
  447. package/runtime/pi/bin/handoff-preview.sh +169 -0
  448. package/runtime/pi/bin/handoff-run.sh +42 -26
  449. package/runtime/pi/bin/ingest-graph.sh +6 -0
  450. package/runtime/pi/bin/ingest-item.sh +10 -0
  451. package/runtime/pi/bin/ingest.sh +59 -30
  452. package/runtime/pi/bin/invite.sh +6 -0
  453. package/runtime/pi/bin/issue.sh +10 -0
  454. package/runtime/pi/bin/knowledge.sh +10 -0
  455. package/runtime/pi/bin/lib/config.sh +20 -0
  456. package/runtime/pi/bin/lib/context.sh +46 -25
  457. package/runtime/pi/bin/lib/git-sync.sh +70 -6
  458. package/runtime/pi/bin/lib/greeting.sh +34 -5
  459. package/runtime/pi/bin/lib/handoff-meta.sh +97 -0
  460. package/runtime/pi/bin/lib/worktree-links.sh +6 -0
  461. package/runtime/pi/bin/node-run.sh +42 -0
  462. package/runtime/pi/bin/notification.sh +6 -0
  463. package/runtime/pi/bin/observe-context.sh +14 -0
  464. package/runtime/pi/bin/onboarding.sh +6 -0
  465. package/runtime/pi/bin/person.py +4 -0
  466. package/runtime/pi/bin/person.sh +43 -10
  467. package/runtime/pi/bin/pi-observe-context.mjs +93 -0
  468. package/runtime/pi/bin/pi-product-workflows.mjs +1 -1
  469. package/runtime/pi/bin/pi-render-spec.mjs +1 -1
  470. package/runtime/pi/bin/post-update.sh +37 -0
  471. package/runtime/pi/bin/prime-render-spec.mjs +147 -0
  472. package/runtime/pi/bin/publish-artifact.sh +55 -2
  473. package/runtime/pi/bin/quest.sh +9 -0
  474. package/runtime/pi/bin/question.sh +8 -0
  475. package/runtime/pi/bin/research-ingest.sh +7 -0
  476. package/runtime/pi/bin/restore-owned-skills.sh +67 -0
  477. package/runtime/pi/bin/retrieval_eval.py +385 -0
  478. package/runtime/pi/bin/runtime-identity.sh +70 -0
  479. package/runtime/pi/bin/runtime-upgrade.sh +43 -0
  480. package/runtime/pi/bin/scroll.sh +9 -0
  481. package/runtime/pi/bin/search.sh +231 -195
  482. package/runtime/pi/bin/settings.sh +174 -5
  483. package/runtime/pi/bin/startup-check.sh +136 -0
  484. package/runtime/pi/bin/telemetry.sh +522 -247
  485. package/runtime/pi/bin/test-changes.sh +344 -0
  486. package/runtime/pi/bin/thread.sh +9 -0
  487. package/runtime/pi/bin/todo.sh +9 -0
  488. package/runtime/pi/bin/view-render.sh +126 -0
  489. package/runtime/pi/bin/worktree-create.sh +19 -5
  490. package/runtime/pi/egregore_runtime/__init__.py +228 -0
  491. package/runtime/pi/egregore_runtime/adapters/__init__.py +5 -0
  492. package/runtime/pi/egregore_runtime/adapters/invitation.py +237 -0
  493. package/runtime/pi/egregore_runtime/adapters/notification.py +59 -0
  494. package/runtime/pi/egregore_runtime/adapters/qmd.py +1701 -0
  495. package/runtime/pi/egregore_runtime/adapters/qmd_cli.py +210 -0
  496. package/runtime/pi/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  497. package/runtime/pi/egregore_runtime/admin_gate.py +102 -0
  498. package/runtime/pi/egregore_runtime/artifacts.py +523 -0
  499. package/runtime/pi/egregore_runtime/contracts.py +499 -0
  500. package/runtime/pi/egregore_runtime/entitlements.py +85 -0
  501. package/runtime/pi/egregore_runtime/errors.py +10 -0
  502. package/runtime/pi/egregore_runtime/graph.py +356 -0
  503. package/runtime/pi/egregore_runtime/handoff_lookup.py +196 -0
  504. package/runtime/pi/egregore_runtime/harness_cli.py +1221 -0
  505. package/runtime/pi/egregore_runtime/identity.py +734 -0
  506. package/runtime/pi/egregore_runtime/identity_cli.py +91 -0
  507. package/runtime/pi/egregore_runtime/ingest.py +575 -0
  508. package/runtime/pi/egregore_runtime/ingest_cli.py +254 -0
  509. package/runtime/pi/egregore_runtime/ingest_index_cli.py +147 -0
  510. package/runtime/pi/egregore_runtime/invitation_cli.py +51 -0
  511. package/runtime/pi/egregore_runtime/invitations.py +116 -0
  512. package/runtime/pi/egregore_runtime/issue_cli.py +305 -0
  513. package/runtime/pi/egregore_runtime/issues.py +359 -0
  514. package/runtime/pi/egregore_runtime/knowledge.py +376 -0
  515. package/runtime/pi/egregore_runtime/knowledge_cli.py +173 -0
  516. package/runtime/pi/egregore_runtime/lifecycle.py +888 -0
  517. package/runtime/pi/egregore_runtime/lifecycle_cli.py +269 -0
  518. package/runtime/pi/egregore_runtime/notification_cli.py +125 -0
  519. package/runtime/pi/egregore_runtime/notifications.py +230 -0
  520. package/runtime/pi/egregore_runtime/observe.py +342 -0
  521. package/runtime/pi/egregore_runtime/onboarding.py +290 -0
  522. package/runtime/pi/egregore_runtime/onboarding_cli.py +110 -0
  523. package/runtime/pi/egregore_runtime/policy.py +144 -0
  524. package/runtime/pi/egregore_runtime/profile.py +193 -0
  525. package/runtime/pi/egregore_runtime/quest_cli.py +216 -0
  526. package/runtime/pi/egregore_runtime/question_cli.py +180 -0
  527. package/runtime/pi/egregore_runtime/questions.py +304 -0
  528. package/runtime/pi/egregore_runtime/quests.py +419 -0
  529. package/runtime/pi/egregore_runtime/readiness.py +379 -0
  530. package/runtime/pi/egregore_runtime/research_ingest.py +256 -0
  531. package/runtime/pi/egregore_runtime/research_ingest_cli.py +44 -0
  532. package/runtime/pi/egregore_runtime/runtime.py +464 -0
  533. package/runtime/pi/egregore_runtime/scroll_cli.py +185 -0
  534. package/runtime/pi/egregore_runtime/scrolls.py +726 -0
  535. package/runtime/pi/egregore_runtime/status.py +412 -0
  536. package/runtime/pi/egregore_runtime/status_cli.py +174 -0
  537. package/runtime/pi/egregore_runtime/sync.py +218 -0
  538. package/runtime/pi/egregore_runtime/teamsync.py +139 -0
  539. package/runtime/pi/egregore_runtime/telemetry.py +640 -0
  540. package/runtime/pi/egregore_runtime/thread_cli.py +173 -0
  541. package/runtime/pi/egregore_runtime/threads.py +517 -0
  542. package/runtime/pi/egregore_runtime/todo_cli.py +142 -0
  543. package/runtime/pi/egregore_runtime/todos.py +244 -0
  544. package/runtime/pi/egregore_runtime/upgrade.py +770 -0
  545. package/runtime/pi/egregore_runtime/upgrade_worker.py +53 -0
  546. package/runtime/pi/egregore_runtime/writeback.py +391 -0
  547. package/runtime/pi/egregore_runtime/writeback_cli.py +114 -0
  548. package/runtime/pi/manifest.json +98 -1
  549. package/runtime/prime/.codex/hooks/search-hint.js +21 -52
  550. package/runtime/prime/.codex/hooks.json +3 -3
  551. package/runtime/prime/.codex/skills/activity/SKILL.md +23 -66
  552. package/runtime/prime/.codex/skills/announce/SKILL.md +27 -50
  553. package/runtime/prime/.codex/skills/archive/SKILL.md +21 -36
  554. package/runtime/prime/.codex/skills/checkup/SKILL.md +77 -36
  555. package/runtime/prime/.codex/skills/dark-mode/SKILL.md +1 -1
  556. package/runtime/prime/.codex/skills/dashboard/SKILL.md +17 -47
  557. package/runtime/prime/.codex/skills/handoff/SKILL.md +84 -133
  558. package/runtime/prime/.codex/skills/harvest/SKILL.md +32 -117
  559. package/runtime/prime/.codex/skills/ingest/SKILL.md +47 -25
  560. package/runtime/prime/.codex/skills/ingest-user-interview/SKILL.md +18 -36
  561. package/runtime/prime/.codex/skills/ingest-user-interview/references/analysis-contract.md +42 -0
  562. package/runtime/prime/.codex/skills/invite/SKILL.md +21 -35
  563. package/runtime/prime/.codex/skills/issue/SKILL.md +60 -41
  564. package/runtime/prime/.codex/skills/me/SKILL.md +1 -1
  565. package/runtime/prime/.codex/skills/meeting/SKILL.md +16 -36
  566. package/runtime/prime/.codex/skills/meeting/references/analysis-contract.md +48 -0
  567. package/runtime/prime/.codex/skills/note/SKILL.md +30 -25
  568. package/runtime/prime/.codex/skills/onboarding/SKILL.md +36 -41
  569. package/runtime/prime/.codex/skills/pull/SKILL.md +1 -1
  570. package/runtime/prime/.codex/skills/quest/SKILL.md +27 -66
  571. package/runtime/prime/.codex/skills/reflect/SKILL.md +22 -36
  572. package/runtime/prime/.codex/skills/save/SKILL.md +2 -2
  573. package/runtime/prime/.codex/skills/telemetry/SKILL.md +1 -1
  574. package/runtime/prime/.codex/skills/test/SKILL.md +1 -1
  575. package/runtime/prime/.codex/skills/tutorial/SKILL.md +40 -41
  576. package/runtime/prime/.codex/skills/view/SKILL.md +115 -111
  577. package/runtime/prime/.codex/skills/wrap/SKILL.md +45 -41
  578. package/runtime/prime/.codex/spec-manifest.json +9 -9
  579. package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +57 -48
  580. package/runtime/prime/.prime/agent/extensions/egregore.ts +7 -0
  581. package/runtime/prime/.prime/agent/spec-manifest.json +2 -2
  582. package/runtime/prime/AGENTS.md +62 -58
  583. package/runtime/prime/bin/activity-action.sh +92 -0
  584. package/runtime/prime/bin/activity-data.sh +12 -233
  585. package/runtime/prime/bin/agent.sh +84 -100
  586. package/runtime/prime/bin/artifact-register.sh +164 -0
  587. package/runtime/prime/bin/artifact-writeback.sh +53 -0
  588. package/runtime/prime/bin/artifacts.sh +288 -0
  589. package/runtime/prime/bin/build-sealed-dataroom.mjs +722 -0
  590. package/runtime/prime/bin/capture-run.sh +18 -2
  591. package/runtime/prime/bin/codex-render-spec.mjs +41 -16
  592. package/runtime/prime/bin/codex-session-start.sh +14 -4
  593. package/runtime/prime/bin/codex-skill-render.mjs +9 -7
  594. package/runtime/prime/bin/corpus_map.py +806 -0
  595. package/runtime/prime/bin/corpus_survey.py +304 -0
  596. package/runtime/prime/bin/dashboard-data.sh +11 -171
  597. package/runtime/prime/bin/github-auth.sh +121 -0
  598. package/runtime/prime/bin/graph-batch.sh +7 -0
  599. package/runtime/prime/bin/graph-op.sh +4 -0
  600. package/runtime/prime/bin/graph-projection.sh +54 -0
  601. package/runtime/prime/bin/graph-wal.sh +13 -0
  602. package/runtime/prime/bin/graph.sh +44 -0
  603. package/runtime/prime/bin/handoff-lifecycle-job.sh +146 -0
  604. package/runtime/prime/bin/handoff-lifecycle.sh +280 -0
  605. package/runtime/prime/bin/handoff-preview.sh +169 -0
  606. package/runtime/prime/bin/handoff-run.sh +42 -26
  607. package/runtime/prime/bin/ingest-graph.sh +6 -0
  608. package/runtime/prime/bin/ingest-item.sh +10 -0
  609. package/runtime/prime/bin/ingest.sh +59 -30
  610. package/runtime/prime/bin/invite.sh +6 -0
  611. package/runtime/prime/bin/issue.sh +10 -0
  612. package/runtime/prime/bin/knowledge.sh +10 -0
  613. package/runtime/prime/bin/lib/config.sh +20 -0
  614. package/runtime/prime/bin/lib/context.sh +46 -25
  615. package/runtime/prime/bin/lib/git-sync.sh +70 -6
  616. package/runtime/prime/bin/lib/greeting.sh +34 -5
  617. package/runtime/prime/bin/lib/handoff-meta.sh +97 -0
  618. package/runtime/prime/bin/lib/worktree-links.sh +6 -0
  619. package/runtime/prime/bin/node-run.sh +42 -0
  620. package/runtime/prime/bin/notification.sh +6 -0
  621. package/runtime/prime/bin/observe-context.sh +14 -0
  622. package/runtime/prime/bin/onboarding.sh +6 -0
  623. package/runtime/prime/bin/person.py +4 -0
  624. package/runtime/prime/bin/person.sh +43 -10
  625. package/runtime/prime/bin/pi-observe-context.mjs +93 -0
  626. package/runtime/prime/bin/pi-product-workflows.mjs +1 -1
  627. package/runtime/prime/bin/pi-render-spec.mjs +140 -0
  628. package/runtime/prime/bin/post-update.sh +37 -0
  629. package/runtime/prime/bin/prime-render-spec.mjs +1 -1
  630. package/runtime/prime/bin/publish-artifact.sh +55 -2
  631. package/runtime/prime/bin/quest.sh +9 -0
  632. package/runtime/prime/bin/question.sh +8 -0
  633. package/runtime/prime/bin/research-ingest.sh +7 -0
  634. package/runtime/prime/bin/restore-owned-skills.sh +67 -0
  635. package/runtime/prime/bin/retrieval_eval.py +385 -0
  636. package/runtime/prime/bin/runtime-identity.sh +70 -0
  637. package/runtime/prime/bin/runtime-upgrade.sh +43 -0
  638. package/runtime/prime/bin/scroll.sh +9 -0
  639. package/runtime/prime/bin/search.sh +231 -195
  640. package/runtime/prime/bin/settings.sh +174 -5
  641. package/runtime/prime/bin/startup-check.sh +136 -0
  642. package/runtime/prime/bin/telemetry.sh +522 -247
  643. package/runtime/prime/bin/test-changes.sh +344 -0
  644. package/runtime/prime/bin/thread.sh +9 -0
  645. package/runtime/prime/bin/todo.sh +9 -0
  646. package/runtime/prime/bin/view-render.sh +126 -0
  647. package/runtime/prime/bin/worktree-create.sh +19 -5
  648. package/runtime/prime/egregore_runtime/__init__.py +228 -0
  649. package/runtime/prime/egregore_runtime/adapters/__init__.py +5 -0
  650. package/runtime/prime/egregore_runtime/adapters/invitation.py +237 -0
  651. package/runtime/prime/egregore_runtime/adapters/notification.py +59 -0
  652. package/runtime/prime/egregore_runtime/adapters/qmd.py +1701 -0
  653. package/runtime/prime/egregore_runtime/adapters/qmd_cli.py +210 -0
  654. package/runtime/prime/egregore_runtime/adapters/qmd_embed_worker.py +59 -0
  655. package/runtime/prime/egregore_runtime/admin_gate.py +102 -0
  656. package/runtime/prime/egregore_runtime/artifacts.py +523 -0
  657. package/runtime/prime/egregore_runtime/contracts.py +499 -0
  658. package/runtime/prime/egregore_runtime/entitlements.py +85 -0
  659. package/runtime/prime/egregore_runtime/errors.py +10 -0
  660. package/runtime/prime/egregore_runtime/graph.py +356 -0
  661. package/runtime/prime/egregore_runtime/handoff_lookup.py +196 -0
  662. package/runtime/prime/egregore_runtime/harness_cli.py +1221 -0
  663. package/runtime/prime/egregore_runtime/identity.py +734 -0
  664. package/runtime/prime/egregore_runtime/identity_cli.py +91 -0
  665. package/runtime/prime/egregore_runtime/ingest.py +575 -0
  666. package/runtime/prime/egregore_runtime/ingest_cli.py +254 -0
  667. package/runtime/prime/egregore_runtime/ingest_index_cli.py +147 -0
  668. package/runtime/prime/egregore_runtime/invitation_cli.py +51 -0
  669. package/runtime/prime/egregore_runtime/invitations.py +116 -0
  670. package/runtime/prime/egregore_runtime/issue_cli.py +305 -0
  671. package/runtime/prime/egregore_runtime/issues.py +359 -0
  672. package/runtime/prime/egregore_runtime/knowledge.py +376 -0
  673. package/runtime/prime/egregore_runtime/knowledge_cli.py +173 -0
  674. package/runtime/prime/egregore_runtime/lifecycle.py +888 -0
  675. package/runtime/prime/egregore_runtime/lifecycle_cli.py +269 -0
  676. package/runtime/prime/egregore_runtime/notification_cli.py +125 -0
  677. package/runtime/prime/egregore_runtime/notifications.py +230 -0
  678. package/runtime/prime/egregore_runtime/observe.py +342 -0
  679. package/runtime/prime/egregore_runtime/onboarding.py +290 -0
  680. package/runtime/prime/egregore_runtime/onboarding_cli.py +110 -0
  681. package/runtime/prime/egregore_runtime/policy.py +144 -0
  682. package/runtime/prime/egregore_runtime/profile.py +193 -0
  683. package/runtime/prime/egregore_runtime/quest_cli.py +216 -0
  684. package/runtime/prime/egregore_runtime/question_cli.py +180 -0
  685. package/runtime/prime/egregore_runtime/questions.py +304 -0
  686. package/runtime/prime/egregore_runtime/quests.py +419 -0
  687. package/runtime/prime/egregore_runtime/readiness.py +379 -0
  688. package/runtime/prime/egregore_runtime/research_ingest.py +256 -0
  689. package/runtime/prime/egregore_runtime/research_ingest_cli.py +44 -0
  690. package/runtime/prime/egregore_runtime/runtime.py +464 -0
  691. package/runtime/prime/egregore_runtime/scroll_cli.py +185 -0
  692. package/runtime/prime/egregore_runtime/scrolls.py +726 -0
  693. package/runtime/prime/egregore_runtime/status.py +412 -0
  694. package/runtime/prime/egregore_runtime/status_cli.py +174 -0
  695. package/runtime/prime/egregore_runtime/sync.py +218 -0
  696. package/runtime/prime/egregore_runtime/teamsync.py +139 -0
  697. package/runtime/prime/egregore_runtime/telemetry.py +640 -0
  698. package/runtime/prime/egregore_runtime/thread_cli.py +173 -0
  699. package/runtime/prime/egregore_runtime/threads.py +517 -0
  700. package/runtime/prime/egregore_runtime/todo_cli.py +142 -0
  701. package/runtime/prime/egregore_runtime/todos.py +244 -0
  702. package/runtime/prime/egregore_runtime/upgrade.py +770 -0
  703. package/runtime/prime/egregore_runtime/upgrade_worker.py +53 -0
  704. package/runtime/prime/egregore_runtime/writeback.py +391 -0
  705. package/runtime/prime/egregore_runtime/writeback_cli.py +114 -0
  706. package/runtime/prime/manifest.json +98 -1
@@ -0,0 +1,1221 @@
1
+ """Harness-neutral command adapter for organizational context.
2
+
3
+ Claude, Codex, Pi, Prime, and shell skills enter the Egregore Runtime here.
4
+ This module deliberately knows no QMD, graph, Supabase, or filesystem-index
5
+ implementation details. Infrastructure is composed behind ``local_runtime``.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import hashlib
12
+ import json
13
+ import os
14
+ import re
15
+ import subprocess
16
+ import sys
17
+ import time
18
+ import unicodedata
19
+ import uuid
20
+ from datetime import UTC, datetime, timedelta
21
+ from pathlib import Path
22
+
23
+ from .contracts import (
24
+ EvidenceItem,
25
+ Permission,
26
+ RetrievalMode,
27
+ RetrievalRequest,
28
+ TemporalScope,
29
+ )
30
+ from .errors import AuthorizationDenied, EgregoreRuntimeError
31
+ from .identity import organization_member_presentations
32
+ from .runtime import EgregoreRuntime, local_runtime
33
+
34
+
35
+ # Optional latency optimization only. The model remains responsible for
36
+ # interpreting organizational-recall intent when this conservative prefetch
37
+ # misses; see the actor-only context contract below.
38
+ _ORG_CONTEXT_PREFETCH_PATTERN = re.compile(
39
+ "|".join(
40
+ (
41
+ r"\b(find|locate|dig up|look up|pull up)\b.*\b"
42
+ r"(handoff|decision|notes?|docs?|meeting|harvest|quest|reflection)s?\b",
43
+ r"\bdid we (decide|discuss|agree|say|talk about|cover)\b",
44
+ r"\bdo we have (any )?(notes?|docs?|anything|something)( on| about)?\b",
45
+ r"\bwhat did we (decide|say|agree|discuss)\b",
46
+ r"\bhave we (discussed|decided|covered|talked about|looked at)\b",
47
+ r"\bnotes on\b",
48
+ r"\bhandoff (from|about)\b",
49
+ r"\bwho worked on\b",
50
+ r"\bdidn.?t (someone|we) already\b",
51
+ r"\bwas there (a|any) (handoff|decision|discussion|meeting)\b",
52
+ r"\bopen (the )?canonical (source|handoff|decision|thread|artifact|document)\b",
53
+ r"\b(?:restore|resume|continue|pick up)\b.*\b"
54
+ r"(?:handoff|organizational context|org context|prior work|runtime|project|thread)\b",
55
+ r"\b(?:handoff|organizational context|org context|prior work|runtime|project|thread)\b.*\b"
56
+ r"(?:restore|resume|continue|pick up)\b",
57
+ r"\bfrom (?:the )?handoff titled\b",
58
+ r"\bwhat\b.*\b(newest|latest|recorded|canonical)\b.*\b"
59
+ r"(handoffs?|decisions?|threads?|quests?|meetings?|artifacts?)\b",
60
+ r"\bwhat\b.*\b(handoffs?|decisions?|quests?|meetings?|artifacts?)\b.*\b"
61
+ r"(says?|records?|contains?|remains?|status)\b",
62
+ r"\b(our|company|org|organization|team)\b.*\b"
63
+ r"(pricing|price|tiers?|plans?|paid|free|strategy|policy|positioning|ownership|decision|"
64
+ r"purpose|mission|principles?|conventions?|values?|goals?|roadmap|architecture|priorities|"
65
+ r"roles?|people|team)\b",
66
+ r"\b(pricing|price|tiers?|plans?|paid|free|purpose|mission|principles?|conventions?|values?)\b.*\b"
67
+ r"(our|company|org|organization|team)\b",
68
+ r"\b(?:what(?:'s| is)?|where)\b.*\b"
69
+ r"(?:remaining|remains|left|next|status|state|scope|open work|working on)\b.*\b"
70
+ r"(?:egregore|runtime|architecture|mvp|implementation|release|project|thread|handoff)\b",
71
+ r"\b(?:egregore|runtime|architecture|mvp|implementation|release|project|thread|handoff)\b.*\b"
72
+ r"(?:remaining|remains|left|next|status|state|scope|open work|still needs?)\b",
73
+ )
74
+ ),
75
+ re.IGNORECASE,
76
+ )
77
+ _EXPLICIT_SEARCH = re.compile(
78
+ r"(/search\b|\$search\b|search\.sh|\bsearch (the )?memory\b)", re.I
79
+ )
80
+ _ORG_RITUAL_CONTEXT_PREFETCH_PATTERN = re.compile(
81
+ r"(?:/scroll\b|\$scroll\b|\b(?:create|make|compose|tend)\b.{0,48}\bscroll\b)",
82
+ re.I,
83
+ )
84
+ _HISTORICAL_SCOPE = re.compile(
85
+ r"\b(history|historical|previous|older|old decision|superseded|what changed|how .* evolv(?:e|ed))\b",
86
+ re.I,
87
+ )
88
+ _RECALL_LEX_PREFIXES = tuple(
89
+ re.compile(pattern, re.I)
90
+ for pattern in (
91
+ r"^\s*(?:what\s+)?did\s+we\s+(?:decide|discuss|agree|say|cover|talk\s+about)\s*(?:about|on)?\s*",
92
+ r"^\s*have\s+we\s+(?:discussed|decided|covered|talked\s+about|looked\s+at)\s*(?:about|on)?\s*",
93
+ r"^\s*do\s+we\s+have\s+(?:any\s+)?(?:notes?|docs?|anything|something)\s*(?:about|on)?\s*",
94
+ r"^\s*what\s+(?:exact\s+)?(?:invariants?|decisions?|details?|content|status)\s+"
95
+ r"(?:are|is)\s+(?:recorded|listed|defined|contained)\s+in\s+(?:the\s+)?",
96
+ )
97
+ )
98
+ _WORKTREE_PATH_PATTERN = re.compile(
99
+ r"(?P<path>/[^\s`\"']*?/\.claude/worktrees/[^\s`\"']+)",
100
+ )
101
+
102
+
103
+ def _root() -> Path:
104
+ configured = os.environ.get("EGREGORE_ROOT")
105
+ return Path(configured).resolve() if configured else Path.cwd().resolve()
106
+
107
+
108
+ def _prompt_root(payload: dict[str, object], default_root: Path) -> Path:
109
+ """Select an explicitly named worktree inside this Egregore instance.
110
+
111
+ Harness instructions and hooks are loaded when a session starts, so a
112
+ continuation prompt may name a newer task worktree while the process still
113
+ stands in the instance root. Runtime retrieval must follow that explicit
114
+ workspace instead of silently querying the stale launch checkout.
115
+ """
116
+
117
+ prompt = str(payload.get("prompt") or payload.get("user_prompt") or "")
118
+ root_text = str(default_root.resolve())
119
+ marker = f"{os.sep}.claude{os.sep}worktrees{os.sep}"
120
+ instance_root = Path(root_text.split(marker, 1)[0]) if marker in root_text else default_root
121
+ worktree_root = (instance_root / ".claude" / "worktrees").resolve()
122
+ for match in _WORKTREE_PATH_PATTERN.finditer(prompt):
123
+ raw = match.group("path").rstrip(".,;:)]}")
124
+ candidate = Path(raw).resolve()
125
+ try:
126
+ candidate.relative_to(worktree_root)
127
+ except ValueError:
128
+ continue
129
+ if candidate.is_dir() and (candidate / ".git").exists() and (candidate / "egregore.json").is_file():
130
+ return candidate
131
+ return default_root
132
+
133
+
134
+ def _session_id(root: Path) -> str:
135
+ configured = os.environ.get("EGREGORE_SESSION_ID", "").strip()
136
+ if configured:
137
+ return configured
138
+ try:
139
+ persisted = (root / ".egregore-session-id").read_text(encoding="utf-8").strip()
140
+ except OSError:
141
+ persisted = ""
142
+ return persisted or f"session_{uuid.uuid4().hex}"
143
+
144
+
145
+ def _actor(runtime: EgregoreRuntime, root: Path, harness: str):
146
+ return runtime.resolve_actor(session_id=_session_id(root), harness=harness)
147
+
148
+
149
+ def _observe_receipt_path(root: Path, harness: str) -> Path:
150
+ """Return the gitignored, current-session Observe receipt path."""
151
+
152
+ identity = f"{harness}:{_session_id(root)}".encode("utf-8")
153
+ name = hashlib.sha256(identity).hexdigest()[:24] + ".json"
154
+ return root / ".egregore" / "runtime" / "observe" / name
155
+
156
+
157
+ def _clear_observe_receipt(root: Path, harness: str) -> None:
158
+ try:
159
+ _observe_receipt_path(root, harness).unlink(missing_ok=True)
160
+ except OSError:
161
+ pass
162
+
163
+
164
+ def _write_observe_receipt(root: Path, harness: str, prompt: str, context) -> None:
165
+ """Record that this prompt already received useful authorized evidence.
166
+
167
+ This is ephemeral turn-deduplication state, not organizational memory or a
168
+ learned retrieval cache. The next UserPromptSubmit hook clears it before
169
+ deciding whether that new prompt needs Observe.
170
+ """
171
+
172
+ evidence = tuple(getattr(context, "evidence", ()) or ())
173
+ if not evidence:
174
+ return
175
+ path = _observe_receipt_path(root, harness)
176
+ try:
177
+ path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
178
+ os.chmod(path.parent, 0o700)
179
+ payload = {
180
+ "schema_version": "egregore.observe-receipt/v1",
181
+ "created_at_unix": time.time(),
182
+ "harness": harness,
183
+ "session_id": _session_id(root),
184
+ "prompt_sha256": hashlib.sha256(prompt.encode("utf-8")).hexdigest(),
185
+ "context_id": str(getattr(context, "context_id", "")),
186
+ "source_paths": [str(item.canonical_path) for item in evidence],
187
+ }
188
+ temporary = path.with_suffix(".tmp")
189
+ descriptor = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
190
+ with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
191
+ json.dump(payload, handle, separators=(",", ":"))
192
+ handle.write("\n")
193
+ os.chmod(temporary, 0o600)
194
+ os.replace(temporary, path)
195
+ except OSError:
196
+ # The hook remains advisory if local ephemeral state is unavailable.
197
+ pass
198
+
199
+
200
+ def _active_observe_receipt(root: Path, harness: str) -> dict[str, object] | None:
201
+ """Load a useful receipt for the current harness prompt, if present."""
202
+
203
+ receipt_dir = root / ".egregore" / "runtime" / "observe"
204
+ paths = [_observe_receipt_path(root, harness)]
205
+ if harness == "shell":
206
+ try:
207
+ paths = sorted(
208
+ receipt_dir.glob("*.json"),
209
+ key=lambda candidate: candidate.stat().st_mtime,
210
+ reverse=True,
211
+ )
212
+ except OSError:
213
+ paths = []
214
+ for path in paths:
215
+ try:
216
+ payload = json.loads(path.read_text(encoding="utf-8"))
217
+ except (OSError, json.JSONDecodeError):
218
+ continue
219
+ if not isinstance(payload, dict):
220
+ continue
221
+ if payload.get("session_id") != _session_id(root):
222
+ continue
223
+ if harness != "shell" and payload.get("harness") != harness:
224
+ continue
225
+ if payload.get("source_paths"):
226
+ return payload
227
+ return None
228
+
229
+
230
+ def _request(
231
+ *,
232
+ task: str,
233
+ org_id: str,
234
+ actor_id: str,
235
+ mode: RetrievalMode,
236
+ limit: int,
237
+ lex: tuple[str, ...] = (),
238
+ vec: tuple[str, ...] = (),
239
+ open_sources: bool = False,
240
+ temporal_scope: TemporalScope | None = None,
241
+ recent_days: int | None = None,
242
+ ) -> RetrievalRequest:
243
+ if mode is RetrievalMode.LEX and not lex:
244
+ lex = vec
245
+ if mode is RetrievalMode.VEC and not vec:
246
+ vec = lex
247
+ return RetrievalRequest(
248
+ request_id=f"observe-{uuid.uuid4().hex}",
249
+ org_id=org_id,
250
+ actor_id=actor_id,
251
+ task=task,
252
+ lex=lex,
253
+ vec=vec,
254
+ top_k=limit,
255
+ mode=mode,
256
+ open_sources=open_sources,
257
+ temporal_scope=temporal_scope or temporal_scope_for_task(task),
258
+ not_before=(
259
+ datetime.now(UTC) - timedelta(days=recent_days)
260
+ if recent_days is not None
261
+ else None
262
+ ),
263
+ )
264
+
265
+
266
+ def temporal_scope_for_task(task: str) -> TemporalScope:
267
+ """Select historical evidence only when the task explicitly asks for it."""
268
+
269
+ return (
270
+ TemporalScope.CURRENT_AND_HISTORICAL
271
+ if _HISTORICAL_SCOPE.search(task)
272
+ else TemporalScope.CURRENT
273
+ )
274
+
275
+
276
+ def _render_evidence(evidence: EvidenceItem) -> str:
277
+ parts = [
278
+ "---",
279
+ f"**file:** `{evidence.canonical_path}`",
280
+ f"**artifact:** `{evidence.artifact_id}`",
281
+ f"**reason:** {evidence.reason}",
282
+ ]
283
+ if evidence.content:
284
+ parts.extend(("", evidence.content))
285
+ return "\n".join(parts)
286
+
287
+
288
+ def _render_compact_evidence(evidence: EvidenceItem, rank: int) -> str:
289
+ excerpt = " ".join(evidence.content.split())
290
+ excerpt = re.sub(r"^@@.*?@@\s*(?:\([^)]*\)\s*)?", "", excerpt)
291
+ if len(excerpt) > 220:
292
+ excerpt = excerpt[:217].rstrip() + "..."
293
+ return "\n".join(
294
+ (
295
+ f"[{rank}] **file:** `{evidence.canonical_path}` · "
296
+ f"**artifact:** `{evidence.artifact_id}` · {evidence.reason}",
297
+ f" excerpt: {excerpt}",
298
+ )
299
+ )
300
+
301
+
302
+ def _query(args: argparse.Namespace) -> int:
303
+ root = _root()
304
+ receipt = (
305
+ None
306
+ if getattr(args, "new_search", False)
307
+ else _active_observe_receipt(root, args.harness)
308
+ )
309
+ if receipt is not None:
310
+ print("EGREGORE_OBSERVE_CONTEXT_REUSED")
311
+ print(
312
+ "Authorized organizational context was already compiled for this prompt; "
313
+ "no second retrieval was run. Use the attached EGREGORE_ORG_CONTEXT_V1 evidence."
314
+ )
315
+ return 0
316
+ runtime = local_runtime(root, push_remote=False)
317
+ actor = _actor(runtime, root, args.harness)
318
+ lexical = identity_aware_lexical_formulations(
319
+ root,
320
+ actor,
321
+ args.task,
322
+ tuple(args.lex),
323
+ )
324
+ context = runtime.observe(
325
+ actor,
326
+ _request(
327
+ task=args.task,
328
+ org_id=actor.profile.org_id,
329
+ actor_id=actor.actor.actor_id,
330
+ lex=lexical,
331
+ vec=tuple(args.vec),
332
+ mode=args.mode,
333
+ limit=args.limit,
334
+ temporal_scope=getattr(args, "temporal_scope", None),
335
+ recent_days=getattr(args, "recent_days", None),
336
+ ),
337
+ token_budget=actor.profile.default_context_budget,
338
+ )
339
+ if args.json:
340
+ print(json.dumps(context.to_dict(), indent=2))
341
+ elif len(context.evidence) < getattr(args, "min_evidence", 1):
342
+ minimum = getattr(args, "min_evidence", 1)
343
+ recent_days = getattr(args, "recent_days", None)
344
+ window = f" within the last {recent_days} days" if recent_days is not None else ""
345
+ print(
346
+ "EGREGORE_EVIDENCE_GAP "
347
+ f"actual={len(context.evidence)} required={minimum} "
348
+ f"recent_days={recent_days or 0}"
349
+ )
350
+ print(
351
+ f"Freshness evidence gap: found {len(context.evidence)} authorized source(s){window}; "
352
+ f"at least {minimum} are required for this synthesis. Do not substitute older sources."
353
+ )
354
+ elif context.evidence and getattr(args, "compact", False):
355
+ print(
356
+ "\n".join(
357
+ _render_compact_evidence(item, rank)
358
+ for rank, item in enumerate(context.evidence, start=1)
359
+ )
360
+ )
361
+ elif context.evidence:
362
+ print("\n\n".join(_render_evidence(item) for item in context.evidence))
363
+ else:
364
+ recent_days = getattr(args, "recent_days", None)
365
+ if recent_days is not None:
366
+ print(
367
+ f"No authorized evidence was found within the last {recent_days} days. "
368
+ "State the freshness gap; do not substitute older sources."
369
+ )
370
+ else:
371
+ print("No results found.")
372
+ return 0
373
+
374
+
375
+ def prompt_prefetches_org_context(prompt: str) -> bool:
376
+ """Return whether Observe should prefetch likely organizational context.
377
+
378
+ This is deliberately a best-effort latency optimization, not the semantic
379
+ authority for recall. A false result still injects actor context that tells
380
+ the model to interpret intent and enter Runtime/QMD once when recall is
381
+ actually needed.
382
+ """
383
+
384
+ return bool(
385
+ prompt
386
+ and not _EXPLICIT_SEARCH.search(prompt)
387
+ and (
388
+ _ORG_CONTEXT_PREFETCH_PATTERN.search(prompt)
389
+ or _ORG_RITUAL_CONTEXT_PREFETCH_PATTERN.search(prompt)
390
+ )
391
+ )
392
+
393
+
394
+ def prompt_requests_org_context(prompt: str) -> bool:
395
+ """Compatibility alias for the optional Observe prefetch predicate."""
396
+
397
+ return prompt_prefetches_org_context(prompt)
398
+
399
+
400
+ def prompt_requests_actor_context(prompt: str) -> bool:
401
+ """Return whether a normal prompt needs stable actor attribution.
402
+
403
+ Identity is cheap, local organizational context. Supplying it on every
404
+ prompt keeps every skill and harness consistent about ``me``/``myself``
405
+ without triggering retrieval or asking models to infer from OS/Git names.
406
+ """
407
+
408
+ return bool(prompt and prompt.strip())
409
+
410
+
411
+ def _actor_context_block(runtime: EgregoreRuntime, root: Path, harness: str) -> str:
412
+ """Render the minimum stable identity needed by harness rituals."""
413
+
414
+ actor_context = _actor(runtime, root, harness)
415
+ actor = actor_context.actor
416
+ aliases = ", ".join(
417
+ dict.fromkeys(
418
+ value.strip()
419
+ for value in getattr(actor, "aliases", {}).values()
420
+ if value and value.strip() and value.strip().casefold() != actor.display_name.casefold()
421
+ )
422
+ ) or "none"
423
+ member_names = "; ".join(
424
+ f"{', '.join(member.aliases)} → {member.display_name}"
425
+ if member.aliases
426
+ else member.display_name
427
+ for member in organization_member_presentations(root, actor_context)
428
+ ) or "unavailable"
429
+ search_command = 'bash bin/search.sh query "<concept>" -n 6 --compact'
430
+ if harness == "claude":
431
+ search_command += " --context-packet"
432
+ return "\n".join(
433
+ (
434
+ "EGREGORE_ACTOR_CONTEXT_V1",
435
+ "Resolved automatically by EgregoreRuntime before the ritual.",
436
+ f"Actor ID: {actor.actor_id}",
437
+ f"Actor display name: {actor.display_name}",
438
+ f"Actor aliases: {aliases}",
439
+ f"Organization ID: {actor_context.profile.org_id}",
440
+ f"Organization member names: {member_names}",
441
+ "Member names are presentation-only identity context. Use the display name when "
442
+ "retrieved evidence names one of its aliases. The directory is not activity "
443
+ "evidence: never mention a member merely because they are listed, never append it "
444
+ "to a retrieval query, and never use it for authorization.",
445
+ f"Runtime root: {root}",
446
+ "Run Egregore retrieval and workflow commands from this Runtime root. "
447
+ "Do not fall back to a launch checkout named elsewhere in the session.",
448
+ "Organizational retrieval status: NOT_PERFORMED. This actor-only block "
449
+ "does not mean organizational recall is unnecessary.",
450
+ "Interpret the user's intent semantically, without requiring trigger words. "
451
+ "If the request needs organizational history, synthesis of current team or person "
452
+ "work, a prior handoff, or continuation of earlier work and no "
453
+ "EGREGORE_ORG_CONTEXT_V1 block is attached, begin with "
454
+ f"exactly one `{search_command}` call. Compact "
455
+ "evidence is the normal model-led recall surface; do not open a full source unless "
456
+ "a necessary claim depends on context omitted from its excerpt. For a semantic "
457
+ "request about current team or person work, keep the user's actual concept and add "
458
+ "only useful time framing such as the current month and year. Never append the "
459
+ "organization roster, unmentioned member names, account handles, or aliases to a "
460
+ "retrieval query. Add a model-selected `--recent-days N` window; prefer 30 days for "
461
+ "a team-wide synthesis unless the user asks for another period. For one named "
462
+ "member, omit `--min-evidence`: one recent authorized source can support a narrow, "
463
+ "properly bounded answer, and Runtime expands only that member's stable identity "
464
+ "aliases during lexical fallback. Add `--min-evidence 3` only for a team-wide "
465
+ "synthesis so one stale-looking source cannot support a broad claim. These are "
466
+ "freshness and confidence constraints; lifecycle `current` alone "
467
+ "does not prove recency. `Freshness evidence gap` is a terminal result for that "
468
+ "prompt: report only the gap. Do not make current-work claims, run a second search, "
469
+ "or substitute Git, startup status, Activity, Dashboard, or older sources.",
470
+ "On Claude, `--context-packet` keeps the internal evidence trace out of the user "
471
+ "transcript and attaches it through PostToolUse. Keep that flag on model-led "
472
+ "searches; never repeat the attached ranking trace in the answer.",
473
+ "Exact lifecycle questions route differently: recognize them from meaning, not "
474
+ "fixed phrases. When the user asks for the latest/newest/oldest handoff addressed "
475
+ "to or sent by a specific person (including `me`), or open/unresolved handoffs, "
476
+ "run the typed deterministic lookup `bash bin/search.sh handoffs "
477
+ "[--mine|--sent|--addressed-to X|--sent-by X] [--status open] "
478
+ "[--order newest|oldest] [--limit N] [--open]` instead of a semantic query — one "
479
+ "memory-form retrieval beat, then answer from its result. Topical or synthesis "
480
+ "questions about handoffs (`the handoff about privacy`) remain semantic "
481
+ "`search.sh query` recall.",
482
+ "Do not substitute Activity, Dashboard, Project, Git inspection, graph, or raw "
483
+ "memory scans for that recall. A named request to display a status card is an "
484
+ "explicit status workflow; a question asking for an explained synthesis of "
485
+ "organizational work is Runtime/QMD recall. Do not query graph unless the user "
486
+ "explicitly requests relationship "
487
+ "or projected graph status.",
488
+ "For every identity-bearing workflow, `me`, `myself`, `from me`, "
489
+ "and `to myself` mean this Actor ID and display name. Use the "
490
+ "display name for presentation and the Actor ID for ownership, "
491
+ "authorization, attribution, creator, steward, recipient, and "
492
+ "respondent fields. Never infer identity from the OS user, Git, "
493
+ "GitHub, a branch name, or prose aliases.",
494
+ "END_EGREGORE_ACTOR_CONTEXT_V1",
495
+ )
496
+ )
497
+
498
+
499
+ def lexical_formulation(prompt: str) -> str:
500
+ """Remove conversational recall framing from the BM25 formulation.
501
+
502
+ This is deterministic typed-query planning, not query expansion: the
503
+ vector lane still receives the untouched task and no new terms are added.
504
+ """
505
+
506
+ concept = prompt.strip()
507
+ for prefix in _RECALL_LEX_PREFIXES:
508
+ match = prefix.match(concept)
509
+ if not match:
510
+ continue
511
+ reduced = concept[match.end() :].strip(" \t\r\n?!.:")
512
+ if reduced:
513
+ return reduced
514
+ return concept
515
+
516
+
517
+ def identity_aware_lexical_formulations(
518
+ root: Path,
519
+ actor: object,
520
+ task: str,
521
+ formulations: tuple[str, ...],
522
+ ) -> tuple[str, ...]:
523
+ """Add aliases only for organization members explicitly named by the task.
524
+
525
+ This keeps cold BM25 retrieval equivalent to stable identity resolution:
526
+ a chosen display name, provider handle, and legacy local alias all refer to
527
+ one member. The directory is never added wholesale and semantic queries
528
+ remain untouched.
529
+ """
530
+
531
+ def normalized(value: str) -> str:
532
+ decomposed = unicodedata.normalize("NFKD", value.casefold())
533
+ ascii_like = "".join(
534
+ character for character in decomposed if not unicodedata.combining(character)
535
+ )
536
+ return " ".join(re.findall(r"[^\W_]+", ascii_like, re.UNICODE))
537
+
538
+ task_tokens = f" {normalized(task)} "
539
+ expanded = list(formulations)
540
+ seen = {value.strip().casefold() for value in expanded if value.strip()}
541
+ for member in organization_member_presentations(root, actor):
542
+ references = (member.display_name, *member.aliases)
543
+ if not any(
544
+ reference_normalized
545
+ and f" {reference_normalized} " in task_tokens
546
+ for reference_normalized in (normalized(value) for value in references)
547
+ ):
548
+ continue
549
+ for reference in references:
550
+ key = reference.strip().casefold()
551
+ if not key or key in seen:
552
+ continue
553
+ expanded.append(reference)
554
+ seen.add(key)
555
+ return tuple(expanded)
556
+
557
+
558
+ def _hook_context(
559
+ runtime: EgregoreRuntime,
560
+ root: Path,
561
+ prompt: str,
562
+ harness: str,
563
+ limit: int,
564
+ ) -> str:
565
+ actor = _actor(runtime, root, harness)
566
+ aliases = ", ".join(
567
+ dict.fromkeys(
568
+ value.strip()
569
+ for value in getattr(actor.actor, "aliases", {}).values()
570
+ if value
571
+ and value.strip()
572
+ and value.strip().casefold() != actor.actor.display_name.casefold()
573
+ )
574
+ ) or "none"
575
+ lexical = lexical_formulation(prompt)
576
+ context = runtime.observe(
577
+ actor,
578
+ _request(
579
+ task=prompt,
580
+ org_id=actor.profile.org_id,
581
+ actor_id=actor.actor.actor_id,
582
+ lex=identity_aware_lexical_formulations(
583
+ root,
584
+ actor,
585
+ prompt,
586
+ (lexical,),
587
+ ),
588
+ vec=(prompt,),
589
+ mode=RetrievalMode.HYBRID,
590
+ limit=limit,
591
+ open_sources=True,
592
+ ),
593
+ token_budget=min(actor.profile.default_context_budget, 1_500),
594
+ )
595
+ _write_observe_receipt(root, harness, prompt, context)
596
+ lines = [
597
+ "EGREGORE_ORG_CONTEXT_V1",
598
+ "Compiled automatically by EgregoreRuntime.observe after actor resolution and authorization.",
599
+ f"Actor ID: {actor.actor.actor_id}",
600
+ f"Actor display name: {actor.actor.display_name}",
601
+ f"Actor aliases: {aliases}",
602
+ f"Organization ID: {actor.profile.org_id}",
603
+ f"Runtime root: {root}",
604
+ "Run Egregore retrieval and workflow commands from this Runtime root. "
605
+ "Do not fall back to a launch checkout named elsewhere in the session.",
606
+ "Identity rule: `me` and `myself` mean this Actor ID and display name. "
607
+ "Use the display name for presentation and the Actor ID for ownership "
608
+ "and authorization; never infer identity from OS/Git/GitHub names.",
609
+ "Retrieval status: COMPLETE for this prompt. RETRIEVAL_ALREADY_PERFORMED=true. "
610
+ "SECOND_QUERY_ALLOWED=false. Do not invoke the search skill or run "
611
+ "`bin/search.sh query` again in this prompt turn.",
612
+ "Exact lifecycle questions are different: `bash bin/search.sh handoffs "
613
+ "[--mine|--sent|--addressed-to X|--sent-by X] [--status open] [--order newest|oldest] "
614
+ "[--limit N] [--open]` is a typed deterministic Runtime lookup, not a second query. "
615
+ "When the user asks an exact organizational-state question (latest/newest/oldest "
616
+ "handoff addressed to or sent by someone, open or unresolved handoffs) and this "
617
+ "packet's evidence cannot answer it, run that lookup in this same turn, emit the "
618
+ "memory-form retrieval beat once, and answer from its result. If it returns nothing, "
619
+ "say no matching handoff exists — never substitute semantic evidence.",
620
+ "Source access: OPENED_BY_OBSERVE through the Runtime read-policy boundary for the "
621
+ "packaged evidence below; do not open it again solely for verification.",
622
+ f"Context: {context.context_id}",
623
+ f"Profile revision: {context.profile_revision}",
624
+ f"Source revision: {context.source_revision}",
625
+ f"Lifecycle revision: {context.freshness.get('lifecycle_revision', 'unavailable')}",
626
+ f"Temporal scope: {context.freshness.get('temporal_scope', 'current')}",
627
+ "Evidence (authorized canonical content; canonical Markdown remains authoritative):",
628
+ ]
629
+ if not context.evidence:
630
+ lines.append("- No authorized evidence found.")
631
+ for position, evidence in enumerate(context.evidence, start=1):
632
+ excerpt = " ".join(evidence.content.split())
633
+ lines.extend(
634
+ (
635
+ f"[{position}] {evidence.canonical_path}",
636
+ f"artifact={evidence.artifact_id} revision={evidence.revision} reason={evidence.reason}",
637
+ excerpt,
638
+ )
639
+ )
640
+ lines.extend(
641
+ (
642
+ "If additional evidence beyond the opened content below is required, the next retrieval "
643
+ 'action is only `bash bin/search.sh open "<another returned memory/... path>"`; do not '
644
+ "search again first and do not bypass the Runtime read-policy boundary. On Claude add "
645
+ "--context-packet so the full document attaches privately instead of printing raw "
646
+ "markdown into the transcript.",
647
+ "If the evidence cannot answer the question, state the evidence gap. Do not run a second "
648
+ "query in this prompt turn. A later user prompt that explicitly requests a new search "
649
+ "starts a new retrieval turn.",
650
+ "END_EGREGORE_ORG_CONTEXT_V1",
651
+ )
652
+ )
653
+ return "\n".join(lines)
654
+
655
+
656
+ def _prompt_hook(args: argparse.Namespace) -> int:
657
+ try:
658
+ payload = json.load(sys.stdin)
659
+ except (json.JSONDecodeError, OSError):
660
+ return 0
661
+ if not isinstance(payload, dict):
662
+ return 0
663
+ prompt = str(payload.get("prompt") or payload.get("user_prompt") or "").strip()
664
+ root = _prompt_root(payload, _root())
665
+ # A receipt is valid for one user-prompt turn only. Clearing it on every
666
+ # prompt preserves explicit/new searches while blocking a redundant skill
667
+ # query after this hook has already compiled useful evidence.
668
+ _clear_observe_receipt(root, args.harness)
669
+ prefetches_org_context = prompt_prefetches_org_context(prompt)
670
+ requests_actor_context = prompt_requests_actor_context(prompt)
671
+ if not prefetches_org_context and not requests_actor_context:
672
+ return 0
673
+ try:
674
+ runtime = local_runtime(root, push_remote=False)
675
+ if prefetches_org_context:
676
+ additional_context = _hook_context(
677
+ runtime,
678
+ root,
679
+ prompt,
680
+ args.harness,
681
+ args.limit,
682
+ )
683
+ else:
684
+ additional_context = _actor_context_block(
685
+ runtime,
686
+ root,
687
+ args.harness,
688
+ )
689
+ except Exception as exc: # Hooks are advisory and must never block a prompt.
690
+ additional_context = (
691
+ "Egregore Runtime context was requested but the Local Runtime is unavailable "
692
+ f"({type(exc).__name__}). Do not guess actor identity. Use the search skill once only "
693
+ "when organizational evidence is required."
694
+ )
695
+ print(
696
+ json.dumps(
697
+ {
698
+ "hookSpecificOutput": {
699
+ "hookEventName": "UserPromptSubmit",
700
+ "additionalContext": additional_context,
701
+ }
702
+ },
703
+ separators=(",", ":"),
704
+ )
705
+ )
706
+ return 0
707
+
708
+
709
+ def _admin_status(args: argparse.Namespace) -> int:
710
+ """Stable-identity admin capability for shell surfaces — fails closed.
711
+
712
+ Egregore-surface admin protection only: repository members retain raw Git
713
+ access regardless of this answer, and callers must treat any failure as
714
+ non-admin.
715
+ """
716
+
717
+ root = _root()
718
+ result = {"admin": False, "display_name": None, "actor_id": None}
719
+ try:
720
+ runtime = local_runtime(root, push_remote=False)
721
+ actor = _actor(runtime, root, args.harness)
722
+ result["display_name"] = actor.actor.display_name
723
+ result["actor_id"] = actor.actor.actor_id
724
+ gate = runtime.admin_gate
725
+ result["admin"] = bool(gate is not None and gate.actor_is_admin(actor))
726
+ except Exception:
727
+ result = {"admin": False, "display_name": None, "actor_id": None}
728
+ print(json.dumps(result, sort_keys=True))
729
+ return 0
730
+
731
+
732
+ def _access_status(args: argparse.Namespace) -> int:
733
+ """One authorized snapshot of identity, membership, and capabilities.
734
+
735
+ The Runtime authorization backend is the source of truth: every value is
736
+ a real authorize() decision, never derived independently by a UI. Any
737
+ failure reports status "attention" and nothing else — no partial claims.
738
+ """
739
+
740
+ root = _root()
741
+ try:
742
+ runtime = local_runtime(root, push_remote=False)
743
+ actor = _actor(runtime, root, args.harness)
744
+ gate = runtime.admin_gate
745
+
746
+ def allowed(*permissions: Permission) -> bool:
747
+ return all(
748
+ runtime.authorize(actor, permission).allowed
749
+ for permission in permissions
750
+ )
751
+
752
+ read_decision = runtime.authorize(actor, Permission.READ)
753
+ membership = actor.membership
754
+ out = {
755
+ "status": "ok",
756
+ "display_name": actor.actor.display_name,
757
+ "actor_id": actor.actor.actor_id,
758
+ "org_name": actor.profile.name,
759
+ "org_id": actor.profile.org_id,
760
+ "membership_status": membership.status if membership else "unknown",
761
+ "roles": sorted(membership.roles) if membership else [],
762
+ "admin": bool(gate is not None and gate.actor_is_admin(actor)),
763
+ "capabilities": {
764
+ "read": allowed(Permission.READ),
765
+ "create": allowed(Permission.WRITE),
766
+ "update": allowed(Permission.WRITE),
767
+ "publish": allowed(Permission.SHARE),
768
+ "notify": allowed(Permission.SHARE, Permission.EXECUTE),
769
+ "org_settings": allowed(Permission.ADMINISTER),
770
+ },
771
+ "shared_memory_scope": sorted(read_decision.scopes),
772
+ }
773
+ except Exception:
774
+ out = {"status": "attention"}
775
+ print(json.dumps(out, sort_keys=True))
776
+ return 0
777
+
778
+
779
+ def _handoffs(args: argparse.Namespace) -> int:
780
+ """Typed lifecycle lookup — exact handoff questions, zero semantic search.
781
+
782
+ This is not a second model-led query: it is a bounded deterministic
783
+ operation over canonical artifact metadata, available even when an
784
+ attached Observe packet missed.
785
+ """
786
+
787
+ from .handoff_lookup import HandoffLookupService
788
+
789
+ root = _root()
790
+ runtime = local_runtime(root, push_remote=False)
791
+ actor = _actor(runtime, root, args.harness)
792
+ service = HandoffLookupService(runtime, root)
793
+ started = time.monotonic()
794
+ records = service.query(
795
+ actor,
796
+ addressed_to="me" if args.mine else args.addressed_to,
797
+ sent_by="me" if args.sent else args.sent_by,
798
+ status_filter=args.status,
799
+ order=args.order,
800
+ limit=args.limit,
801
+ )
802
+ lookup_ms = round((time.monotonic() - started) * 1000)
803
+ if args.timing:
804
+ print(f"lookup: {lookup_ms}ms", file=sys.stderr)
805
+ if args.json:
806
+ print(
807
+ json.dumps(
808
+ {
809
+ "records": [record.__dict__ for record in records],
810
+ "lookup_ms": lookup_ms,
811
+ },
812
+ sort_keys=True,
813
+ )
814
+ )
815
+ return 0
816
+ if not records:
817
+ print("no matching handoff exists for that filter")
818
+ return 0
819
+ for index, record in enumerate(records, start=1):
820
+ day = record.occurred_at.split("T")[0]
821
+ print(f"{index}. {day} · from {record.sender} · to {record.recipient} · {record.status} · {record.topic}")
822
+ if record.claim:
823
+ print(f" claim: {record.claim}")
824
+ if record.ask:
825
+ print(f" ask: {record.ask}")
826
+ print(f" source: {record.canonical_path}")
827
+ if args.open and records:
828
+ content = runtime.open_source(actor, records[0].canonical_path)
829
+ print()
830
+ print(content)
831
+ return 0
832
+
833
+
834
+ def _status(args: argparse.Namespace) -> int:
835
+ health = local_runtime(_root(), push_remote=False).retrieval_health()
836
+ if args.json:
837
+ print(json.dumps(health.to_dict(), indent=2))
838
+ else:
839
+ print(f"adapter: {health.adapter} {health.adapter_version}")
840
+ print(f"index spec: {health.index_spec_version}")
841
+ print(f"index revision: {health.index_revision}")
842
+ print(f"source revision: {health.source_revision}")
843
+ print(f"embedding: {health.embedding_state}")
844
+ print(f"readiness: {health.runtime_state}")
845
+ print(f"bm25 ready: {'yes' if health.bm25_ready else 'no'}")
846
+ print(f"semantic ready: {'yes' if health.semantic_ready else 'no'}")
847
+ print(f"semantic build: {health.semantic_source_revision or 'none'}")
848
+ print(f"worker pid: {health.runtime_pid or 'none'}")
849
+ print(f"endpoint: {health.runtime_endpoint or 'none'}")
850
+ print(f"index: {health.index_path or 'unknown'}")
851
+ print(f"collection: {health.collection or 'unknown'}")
852
+ print(f"available: {'yes' if health.available else 'no'}")
853
+ for warning in health.warnings:
854
+ print(f"warning: {warning}")
855
+ return 0 if health.available else 1
856
+
857
+
858
+ _RUNTIME_MVP_VERSION = re.compile(
859
+ r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)-runtime-mvp\.(0|[1-9]\d*)$"
860
+ )
861
+
862
+
863
+ def _upgrade_context(root: Path):
864
+ from .upgrade import build_cli_context
865
+
866
+ return build_cli_context(root)
867
+
868
+
869
+ def _active_runtime_version(root: Path, store) -> str:
870
+ activation = store.load_activation()
871
+ if activation and activation.get("active_version"):
872
+ return str(activation["active_version"])
873
+ try:
874
+ package = json.loads(
875
+ (root / "packages" / "create-egregore" / "package.json").read_text(encoding="utf-8")
876
+ )
877
+ return str(package.get("version") or "unknown")
878
+ except (OSError, ValueError):
879
+ return "unknown"
880
+
881
+
882
+ def _upgrade(args: argparse.Namespace) -> int:
883
+ from . import upgrade as upgrade_module
884
+ from .teamsync import team_sync
885
+
886
+ root = _root()
887
+ try:
888
+ store, engine, retriever = _upgrade_context(root)
889
+ except upgrade_module.UpgradeError as exc:
890
+ # Fail closed: no stable organization identity means no upgrade
891
+ # state — never fall back to a path-inferred identity.
892
+ print(str(exc), file=sys.stderr)
893
+ return 1
894
+ action = args.action
895
+
896
+ if action == "status":
897
+ state = upgrade_module.describe(store.load())
898
+ state["active_version"] = _active_runtime_version(root, store)
899
+ state["instance_hash"] = upgrade_module.instance_key(root)
900
+ memory_root = (root / "memory").resolve()
901
+ if memory_root.is_dir():
902
+ state["team_sync"] = team_sync(memory_root, fetch=bool(args.fetch)).to_dict()
903
+ print(json.dumps(state, indent=2, sort_keys=True))
904
+ return 0
905
+
906
+ if action == "init":
907
+ version = (args.candidate or "").strip()
908
+ if not _RUNTIME_MVP_VERSION.match(version):
909
+ # The protected publish path enforces the same scheme through
910
+ # bin/validate-create-egregore-prerelease.mjs; mirror it here so a
911
+ # retired-scheme candidate can never even start preparing.
912
+ print(
913
+ f"candidate {version!r} is not on the runtime-mvp prerelease "
914
+ "scheme (expected X.Y.Z-runtime-mvp.N)",
915
+ file=sys.stderr,
916
+ )
917
+ return 1
918
+ config = json.loads((root / "egregore.json").read_text(encoding="utf-8"))
919
+ org_id = str(config.get("org_id") or "")
920
+ if not org_id:
921
+ print("this instance has no stable org_id; refusing to stage an upgrade", file=sys.stderr)
922
+ return 1
923
+ existing = store.load()
924
+ if existing and existing.get("status") in (
925
+ upgrade_module.STATUS_PREPARING,
926
+ upgrade_module.STATUS_READY,
927
+ ):
928
+ print("an upgrade is already staged for this instance", file=sys.stderr)
929
+ return 1
930
+ tarball = Path(args.tarball).expanduser().resolve() if args.tarball else None
931
+ if tarball is None or not tarball.is_file():
932
+ print(
933
+ "upgrade init requires --tarball <candidate .tgz>: the upgrade "
934
+ "installs actual packaged bytes, never a version string",
935
+ file=sys.stderr,
936
+ )
937
+ return 1
938
+ state = upgrade_module.new_state(
939
+ instance_path=root,
940
+ org_id=org_id,
941
+ instance_hash=upgrade_module.instance_key(root),
942
+ candidate_version=version,
943
+ active_version=_active_runtime_version(root, store),
944
+ candidate_source=str(tarball),
945
+ )
946
+ store.write(state)
947
+ print(json.dumps(upgrade_module.describe(state), indent=2, sort_keys=True))
948
+ return 0
949
+
950
+ if action == "prepare":
951
+ state = store.load()
952
+ if state is None:
953
+ print("run `upgrade init --candidate <version>` first", file=sys.stderr)
954
+ return 1
955
+ worker = state.get("worker") or {}
956
+ if state.get("status") == upgrade_module.STATUS_PREPARING and worker.get("pid"):
957
+ if upgrade_module._pid_alive(worker["pid"]):
958
+ print(json.dumps(upgrade_module.describe(state), indent=2, sort_keys=True))
959
+ return 0
960
+ environment = dict(os.environ)
961
+ package_root = str(Path(__file__).resolve().parents[1])
962
+ environment["PYTHONPATH"] = (
963
+ f"{package_root}{os.pathsep}{environment['PYTHONPATH']}"
964
+ if environment.get("PYTHONPATH")
965
+ else package_root
966
+ )
967
+ process = subprocess.Popen(
968
+ (
969
+ sys.executable,
970
+ "-m",
971
+ "egregore_runtime.upgrade_worker",
972
+ "--repository-root",
973
+ str(root),
974
+ ),
975
+ cwd=root,
976
+ env=environment,
977
+ stdin=subprocess.DEVNULL,
978
+ stdout=subprocess.DEVNULL,
979
+ stderr=subprocess.DEVNULL,
980
+ start_new_session=True,
981
+ )
982
+ state["worker"] = {"pid": process.pid, "started_at": int(time.time())}
983
+ state["status"] = upgrade_module.STATUS_PREPARING
984
+ store.write(state)
985
+ print(json.dumps(upgrade_module.describe(state, worker_alive=True), indent=2, sort_keys=True))
986
+ return 0
987
+
988
+ if action == "activate":
989
+ state = engine.activate()
990
+ print(json.dumps(upgrade_module.describe(state), indent=2, sort_keys=True))
991
+ return 0
992
+
993
+ if action == "cancel":
994
+ state = engine.cancel()
995
+ print(json.dumps(upgrade_module.describe(state), indent=2, sort_keys=True))
996
+ return 0
997
+
998
+ if action == "rollback":
999
+ state = engine.rollback()
1000
+ print(json.dumps(upgrade_module.describe(state), indent=2, sort_keys=True))
1001
+ return 0
1002
+
1003
+ print(f"unknown upgrade action: {action}", file=sys.stderr)
1004
+ return 2
1005
+
1006
+
1007
+ def _team_sync_cmd(args: argparse.Namespace) -> int:
1008
+ from .teamsync import team_sync
1009
+
1010
+ root = _root()
1011
+ memory_root = (root / "memory").resolve()
1012
+ if not memory_root.is_dir():
1013
+ print(json.dumps({"state": "attention", "label": "Sync needs attention"}))
1014
+ return 1
1015
+ result = team_sync(memory_root, fetch=bool(args.fetch))
1016
+ print(json.dumps(result.to_dict(), indent=2, sort_keys=True))
1017
+ return 0
1018
+
1019
+
1020
+ def _readiness(args: argparse.Namespace) -> int:
1021
+ from .readiness import collect_report, render
1022
+
1023
+ root = _root()
1024
+ runtime = local_runtime(root, push_remote=False)
1025
+ report = collect_report(
1026
+ root, runtime, harness=args.harness, session_id=_session_id(root)
1027
+ )
1028
+ if args.json:
1029
+ print(json.dumps(report.to_dict(), indent=2))
1030
+ else:
1031
+ tty = sys.stdout.isatty() and not args.plain
1032
+ print(render(report, tty=tty))
1033
+ ready = {item.key: item.stage for item in report.items}
1034
+ return 0 if ready.get("search") == "ready" else 1
1035
+
1036
+
1037
+ def _sync(args: argparse.Namespace) -> int:
1038
+ receipt = local_runtime(_root(), push_remote=False).synchronize()
1039
+ if args.json:
1040
+ print(json.dumps(receipt.to_dict(), indent=2))
1041
+ else:
1042
+ canonical = receipt.canonical_sync
1043
+ retrieval = receipt.retrieval
1044
+ print(f"synchronization: {receipt.status}")
1045
+ print(
1046
+ "canonical revision: "
1047
+ f"{canonical.local_revision if canonical is not None else 'unavailable'}"
1048
+ )
1049
+ print(f"canonical current: {'yes' if receipt.canonical_current else 'no'}")
1050
+ print(
1051
+ "canonical changed: "
1052
+ f"{'yes' if canonical is not None and canonical.changed else 'no'}"
1053
+ )
1054
+ print(
1055
+ "lexical ready: "
1056
+ f"{'yes' if retrieval is not None and retrieval.bm25_ready else 'no'}"
1057
+ )
1058
+ print(
1059
+ "semantic: "
1060
+ + (
1061
+ "ready"
1062
+ if retrieval is not None and retrieval.semantic_ready
1063
+ else "building"
1064
+ if receipt.semantic_building
1065
+ else "unavailable"
1066
+ )
1067
+ )
1068
+ print(
1069
+ "index/source aligned: "
1070
+ f"{'yes' if receipt.index_source_aligned else 'no'}"
1071
+ )
1072
+ if retrieval is not None:
1073
+ print(f"index revision: {retrieval.index_revision}")
1074
+ print(f"index source revision: {retrieval.index_source_revision or 'unavailable'}")
1075
+ print(f"source revision: {retrieval.source_revision}")
1076
+ for failure in receipt.failures:
1077
+ print(f"failure: {failure}")
1078
+ return 0 if receipt.status == "ready" else 1
1079
+
1080
+
1081
+ def _start(args: argparse.Namespace) -> int:
1082
+ health = local_runtime(_root(), push_remote=False).start_retrieval()
1083
+ print(json.dumps(health.to_dict(), indent=2) if args.json else health.runtime_state)
1084
+ return 0 if health.available and health.bm25_ready else 1
1085
+
1086
+
1087
+ def _stop(args: argparse.Namespace) -> int:
1088
+ health = local_runtime(_root(), push_remote=False).shutdown_retrieval()
1089
+ print(json.dumps(health.to_dict(), indent=2) if args.json else "stopped")
1090
+ return 0
1091
+
1092
+
1093
+ def _open(args: argparse.Namespace) -> int:
1094
+ root = _root()
1095
+ runtime = local_runtime(root, push_remote=False)
1096
+ actor = _actor(runtime, root, args.harness)
1097
+ sys.stdout.write(runtime.open_source(actor, args.path))
1098
+ return 0
1099
+
1100
+
1101
+ def _positive_int(value: str) -> int:
1102
+ parsed = int(value)
1103
+ if parsed < 1:
1104
+ raise argparse.ArgumentTypeError("value must be a positive integer")
1105
+ return parsed
1106
+
1107
+
1108
+ def _parser() -> argparse.ArgumentParser:
1109
+ parser = argparse.ArgumentParser(prog="egregore-runtime")
1110
+ commands = parser.add_subparsers(dest="command", required=True)
1111
+
1112
+ query = commands.add_parser("query")
1113
+ query.add_argument("--task", required=True)
1114
+ query.add_argument("--lex", action="append", default=[])
1115
+ query.add_argument("--vec", action="append", default=[])
1116
+ query.add_argument("--mode", type=RetrievalMode, default=RetrievalMode.HYBRID)
1117
+ query.add_argument("--limit", type=int, default=6)
1118
+ query.add_argument("--harness", default=os.environ.get("EGREGORE_RUNTIME", "shell"))
1119
+ query.add_argument(
1120
+ "--new-search",
1121
+ action="store_true",
1122
+ help="run a new retrieval even when this prompt already has compiled Observe context",
1123
+ )
1124
+ query.add_argument("--temporal-scope", type=TemporalScope)
1125
+ query.add_argument("--recent-days", type=_positive_int)
1126
+ query.add_argument("--min-evidence", type=_positive_int, default=1)
1127
+ query.add_argument("--compact", action="store_true")
1128
+ query.add_argument("--json", action="store_true")
1129
+ query.set_defaults(handler=_query)
1130
+
1131
+ prompt_hook = commands.add_parser("prompt-hook")
1132
+ prompt_hook.add_argument("--harness", required=True)
1133
+ prompt_hook.add_argument("--limit", type=int, default=6)
1134
+ prompt_hook.set_defaults(handler=_prompt_hook)
1135
+
1136
+ status = commands.add_parser("status")
1137
+ status.add_argument("--json", action="store_true")
1138
+ status.set_defaults(handler=_status)
1139
+
1140
+ admin_status = commands.add_parser("admin-status")
1141
+ admin_status.add_argument(
1142
+ "--harness", default=os.environ.get("EGREGORE_RUNTIME", "shell")
1143
+ )
1144
+ admin_status.set_defaults(handler=_admin_status)
1145
+
1146
+ handoffs = commands.add_parser("handoffs")
1147
+ handoffs.add_argument("--mine", action="store_true", help="addressed to the resolved actor")
1148
+ handoffs.add_argument("--addressed-to", default=None)
1149
+ handoffs.add_argument("--sent", action="store_true", help="sent by the resolved actor")
1150
+ handoffs.add_argument("--sent-by", default=None)
1151
+ handoffs.add_argument("--status", choices=("any", "open", "unresolved"), default="any")
1152
+ handoffs.add_argument("--order", choices=("newest", "oldest"), default="newest")
1153
+ handoffs.add_argument("--limit", type=_positive_int, default=1)
1154
+ handoffs.add_argument("--open", action="store_true", help="open the top result through Runtime read policy")
1155
+ handoffs.add_argument("--json", action="store_true")
1156
+ handoffs.add_argument("--timing", action="store_true")
1157
+ handoffs.add_argument(
1158
+ "--harness", default=os.environ.get("EGREGORE_RUNTIME", "shell")
1159
+ )
1160
+ handoffs.set_defaults(handler=_handoffs)
1161
+
1162
+ access_status = commands.add_parser("access-status")
1163
+ access_status.add_argument(
1164
+ "--harness", default=os.environ.get("EGREGORE_RUNTIME", "shell")
1165
+ )
1166
+ access_status.set_defaults(handler=_access_status)
1167
+
1168
+ readiness = commands.add_parser("readiness")
1169
+ readiness.add_argument("--json", action="store_true")
1170
+ readiness.add_argument("--plain", action="store_true")
1171
+ readiness.add_argument(
1172
+ "--harness", default=os.environ.get("EGREGORE_RUNTIME", "shell")
1173
+ )
1174
+ readiness.set_defaults(handler=_readiness)
1175
+
1176
+ upgrade = commands.add_parser("upgrade")
1177
+ upgrade.add_argument(
1178
+ "action",
1179
+ choices=("status", "init", "prepare", "activate", "cancel", "rollback"),
1180
+ )
1181
+ upgrade.add_argument("--candidate", default="")
1182
+ upgrade.add_argument("--tarball", default="")
1183
+ upgrade.add_argument("--fetch", action="store_true")
1184
+ upgrade.set_defaults(handler=_upgrade)
1185
+
1186
+ team_sync_parser = commands.add_parser("team-sync")
1187
+ team_sync_parser.add_argument("--fetch", action="store_true")
1188
+ team_sync_parser.set_defaults(handler=_team_sync_cmd)
1189
+
1190
+ sync = commands.add_parser("sync")
1191
+ sync.add_argument("--json", action="store_true")
1192
+ sync.set_defaults(handler=_sync)
1193
+
1194
+ start = commands.add_parser("start")
1195
+ start.add_argument("--json", action="store_true")
1196
+ start.set_defaults(handler=_start)
1197
+
1198
+ stop = commands.add_parser("stop")
1199
+ stop.add_argument("--json", action="store_true")
1200
+ stop.set_defaults(handler=_stop)
1201
+
1202
+ source = commands.add_parser("open")
1203
+ source.add_argument("path")
1204
+ source.add_argument("--harness", default=os.environ.get("EGREGORE_RUNTIME", "shell"))
1205
+ source.set_defaults(handler=_open)
1206
+ return parser
1207
+
1208
+
1209
+ def main() -> int:
1210
+ args = _parser().parse_args()
1211
+ if getattr(args, "limit", 1) < 1:
1212
+ raise ValueError("retrieval limit must be positive")
1213
+ return args.handler(args)
1214
+
1215
+
1216
+ if __name__ == "__main__":
1217
+ try:
1218
+ raise SystemExit(main())
1219
+ except (AuthorizationDenied, EgregoreRuntimeError, RuntimeError, ValueError) as exc:
1220
+ print(f"egregore: {exc}", file=sys.stderr)
1221
+ raise SystemExit(1) from exc