create-egregore 0.19.33 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/assets/egregore-launcher.js +118 -13
  2. package/bin/cli.js +19 -3
  3. package/lib/connect-runtime.js +4 -2
  4. package/lib/local.js +15 -1
  5. package/lib/prime-runtime.js +208 -0
  6. package/lib/setup.js +45 -3
  7. package/package.json +4 -3
  8. package/runtime/codex/.codex/skills/ingest-notion/SKILL.md +29 -0
  9. package/runtime/codex/.codex/skills/notion-connect/SKILL.md +29 -0
  10. package/runtime/codex/.codex/skills/teams-connect/SKILL.md +29 -0
  11. package/runtime/codex/.codex/spec-manifest.json +3 -3
  12. package/runtime/codex/AGENTS.md +11 -4
  13. package/runtime/codex/bin/activity-data.sh +4 -8
  14. package/runtime/codex/bin/attendant.sh +13 -0
  15. package/runtime/codex/bin/autosave.sh +27 -1
  16. package/runtime/codex/bin/codex-render-spec.mjs +6 -0
  17. package/runtime/codex/bin/codex-session-start.sh +3 -1
  18. package/runtime/codex/bin/graph-batch.sh +25 -6
  19. package/runtime/codex/bin/graph-op.sh +5 -4
  20. package/runtime/codex/bin/graph.sh +31 -5
  21. package/runtime/codex/bin/ingest.py +81 -5
  22. package/runtime/codex/bin/lib/context.sh +26 -1
  23. package/runtime/codex/bin/lib/greeting.sh +4 -1
  24. package/runtime/codex/bin/lib/worktree-links.sh +25 -0
  25. package/runtime/codex/manifest.json +7 -1
  26. package/runtime/pi/.codex/skills/ingest-notion/SKILL.md +29 -0
  27. package/runtime/pi/.codex/skills/notion-connect/SKILL.md +29 -0
  28. package/runtime/pi/.codex/skills/teams-connect/SKILL.md +29 -0
  29. package/runtime/pi/.codex/spec-manifest.json +3 -3
  30. package/runtime/pi/.pi/APPEND_SYSTEM.md +3 -2
  31. package/runtime/pi/.pi/extensions/egregore.ts +17 -6
  32. package/runtime/pi/.pi/spec-manifest.json +2 -2
  33. package/runtime/pi/AGENTS.md +11 -4
  34. package/runtime/pi/bin/activity-data.sh +4 -8
  35. package/runtime/pi/bin/attendant.sh +13 -0
  36. package/runtime/pi/bin/autosave.sh +27 -1
  37. package/runtime/pi/bin/codex-render-spec.mjs +6 -0
  38. package/runtime/pi/bin/codex-session-start.sh +3 -1
  39. package/runtime/pi/bin/graph-batch.sh +25 -6
  40. package/runtime/pi/bin/graph-op.sh +5 -4
  41. package/runtime/pi/bin/graph.sh +31 -5
  42. package/runtime/pi/bin/ingest.py +81 -5
  43. package/runtime/pi/bin/lib/context.sh +26 -1
  44. package/runtime/pi/bin/lib/greeting.sh +4 -1
  45. package/runtime/pi/bin/lib/worktree-links.sh +25 -0
  46. package/runtime/pi/bin/pi-branch-policy.mjs +138 -1
  47. package/runtime/pi/bin/pi-product-workflows.mjs +35 -7
  48. package/runtime/pi/manifest.json +7 -1
  49. package/runtime/prime/.claude/context/notification-consent.md +66 -0
  50. package/runtime/prime/.codex/config.toml +17 -0
  51. package/runtime/prime/.codex/hooks/branch-guard.js +461 -0
  52. package/runtime/prime/.codex/hooks/search-hint.js +67 -0
  53. package/runtime/prime/.codex/hooks.json +30 -0
  54. package/runtime/prime/.codex/skills/activity/SKILL.md +82 -0
  55. package/runtime/prime/.codex/skills/announce/SKILL.md +67 -0
  56. package/runtime/prime/.codex/skills/archive/SKILL.md +45 -0
  57. package/runtime/prime/.codex/skills/branch/SKILL.md +29 -0
  58. package/runtime/prime/.codex/skills/checkup/SKILL.md +45 -0
  59. package/runtime/prime/.codex/skills/commit/SKILL.md +29 -0
  60. package/runtime/prime/.codex/skills/contribute/SKILL.md +29 -0
  61. package/runtime/prime/.codex/skills/create-skill/SKILL.md +29 -0
  62. package/runtime/prime/.codex/skills/dark-mode/SKILL.md +29 -0
  63. package/runtime/prime/.codex/skills/dashboard/SKILL.md +59 -0
  64. package/runtime/prime/.codex/skills/deep-reflect/SKILL.md +109 -0
  65. package/runtime/prime/.codex/skills/delete-user/SKILL.md +29 -0
  66. package/runtime/prime/.codex/skills/emissary/SKILL.md +45 -0
  67. package/runtime/prime/.codex/skills/handoff/SKILL.md +166 -0
  68. package/runtime/prime/.codex/skills/harvest/QUESTION_PALETTE.md +76 -0
  69. package/runtime/prime/.codex/skills/harvest/SKILL.md +131 -0
  70. package/runtime/prime/.codex/skills/ingest/SKILL.md +29 -0
  71. package/runtime/prime/.codex/skills/ingest-notion/SKILL.md +29 -0
  72. package/runtime/prime/.codex/skills/ingest-user-interview/SKILL.md +45 -0
  73. package/runtime/prime/.codex/skills/invite/SKILL.md +44 -0
  74. package/runtime/prime/.codex/skills/issue/SKILL.md +45 -0
  75. package/runtime/prime/.codex/skills/me/SKILL.md +29 -0
  76. package/runtime/prime/.codex/skills/meeting/SKILL.md +45 -0
  77. package/runtime/prime/.codex/skills/note/SKILL.md +29 -0
  78. package/runtime/prime/.codex/skills/notion-connect/SKILL.md +29 -0
  79. package/runtime/prime/.codex/skills/onboarding/SKILL.md +45 -0
  80. package/runtime/prime/.codex/skills/pr/SKILL.md +29 -0
  81. package/runtime/prime/.codex/skills/pull/SKILL.md +29 -0
  82. package/runtime/prime/.codex/skills/push/SKILL.md +29 -0
  83. package/runtime/prime/.codex/skills/quest/SKILL.md +80 -0
  84. package/runtime/prime/.codex/skills/reflect/SKILL.md +45 -0
  85. package/runtime/prime/.codex/skills/review-pr/SKILL.md +45 -0
  86. package/runtime/prime/.codex/skills/save/SKILL.md +125 -0
  87. package/runtime/prime/.codex/skills/slack-connect/SKILL.md +29 -0
  88. package/runtime/prime/.codex/skills/summon/SKILL.md +45 -0
  89. package/runtime/prime/.codex/skills/sync-repos/SKILL.md +29 -0
  90. package/runtime/prime/.codex/skills/teams-connect/SKILL.md +29 -0
  91. package/runtime/prime/.codex/skills/telegram-connect/SKILL.md +29 -0
  92. package/runtime/prime/.codex/skills/telemetry/SKILL.md +29 -0
  93. package/runtime/prime/.codex/skills/test/SKILL.md +45 -0
  94. package/runtime/prime/.codex/skills/the-spiral/SKILL.md +84 -0
  95. package/runtime/prime/.codex/skills/tui-design/SKILL.md +45 -0
  96. package/runtime/prime/.codex/skills/tutorial/SKILL.md +45 -0
  97. package/runtime/prime/.codex/skills/update/SKILL.md +29 -0
  98. package/runtime/prime/.codex/skills/view/SKILL.md +156 -0
  99. package/runtime/prime/.codex/skills/view/agents/openai.yaml +4 -0
  100. package/runtime/prime/.codex/skills/view/assets/compose-scaffold.html +221 -0
  101. package/runtime/prime/.codex/skills/visual-explain/SKILL.md +45 -0
  102. package/runtime/prime/.codex/skills/wrap/SKILL.md +58 -0
  103. package/runtime/prime/.codex/spec-manifest.json +132 -0
  104. package/runtime/prime/.prime/agent/APPEND_SYSTEM.md +393 -0
  105. package/runtime/prime/.prime/agent/extensions/egregore.ts +460 -0
  106. package/runtime/prime/.prime/agent/settings.json +4 -0
  107. package/runtime/prime/.prime/agent/skills/egregore/SKILL.md +34 -0
  108. package/runtime/prime/.prime/agent/skills/egregore/pyproject.toml +13 -0
  109. package/runtime/prime/.prime/agent/skills/egregore/src/egregore/__init__.py +156 -0
  110. package/runtime/prime/.prime/agent/spec-manifest.json +12 -0
  111. package/runtime/prime/AGENTS.md +489 -0
  112. package/runtime/prime/bin/activity-data.sh +238 -0
  113. package/runtime/prime/bin/agent.sh +775 -0
  114. package/runtime/prime/bin/attendant.sh +707 -0
  115. package/runtime/prime/bin/autosave.sh +112 -0
  116. package/runtime/prime/bin/capture-reconcile.sh +69 -0
  117. package/runtime/prime/bin/capture-run.sh +341 -0
  118. package/runtime/prime/bin/codex-install-skills.sh +78 -0
  119. package/runtime/prime/bin/codex-render-spec.mjs +440 -0
  120. package/runtime/prime/bin/codex-session-start.sh +265 -0
  121. package/runtime/prime/bin/codex-skill-render.mjs +347 -0
  122. package/runtime/prime/bin/codex-sync-skills.sh +232 -0
  123. package/runtime/prime/bin/connect-refresh.sh +33 -0
  124. package/runtime/prime/bin/dashboard-data.sh +178 -0
  125. package/runtime/prime/bin/graph-batch.sh +79 -0
  126. package/runtime/prime/bin/graph-op.sh +1102 -0
  127. package/runtime/prime/bin/graph-wal.sh +229 -0
  128. package/runtime/prime/bin/graph.sh +223 -0
  129. package/runtime/prime/bin/handoff-pr-backfill.sh +86 -0
  130. package/runtime/prime/bin/handoff-run.sh +671 -0
  131. package/runtime/prime/bin/handoff-save-egregore.sh +212 -0
  132. package/runtime/prime/bin/index-handoff.sh +322 -0
  133. package/runtime/prime/bin/ingest-graph.sh +80 -0
  134. package/runtime/prime/bin/ingest-surface.html +495 -0
  135. package/runtime/prime/bin/ingest.py +756 -0
  136. package/runtime/prime/bin/ingest.sh +279 -0
  137. package/runtime/prime/bin/ingest_graph.py +856 -0
  138. package/runtime/prime/bin/ingest_surface.py +544 -0
  139. package/runtime/prime/bin/lib/artifact-id.sh +46 -0
  140. package/runtime/prime/bin/lib/config.sh +116 -0
  141. package/runtime/prime/bin/lib/context.sh +621 -0
  142. package/runtime/prime/bin/lib/dashboard-artifact.sh +242 -0
  143. package/runtime/prime/bin/lib/ensure-develop.sh +183 -0
  144. package/runtime/prime/bin/lib/git-sync.sh +406 -0
  145. package/runtime/prime/bin/lib/greeting.sh +519 -0
  146. package/runtime/prime/bin/lib/hash.sh +13 -0
  147. package/runtime/prime/bin/lib/identity.sh +213 -0
  148. package/runtime/prime/bin/lib/metrics.sh +374 -0
  149. package/runtime/prime/bin/lib/noncode.sh +31 -0
  150. package/runtime/prime/bin/lib/permissions.sh +106 -0
  151. package/runtime/prime/bin/lib/time.sh +56 -0
  152. package/runtime/prime/bin/lib/worktree-links.sh +79 -0
  153. package/runtime/prime/bin/notify.sh +636 -0
  154. package/runtime/prime/bin/person.py +630 -0
  155. package/runtime/prime/bin/person.sh +448 -0
  156. package/runtime/prime/bin/pi-branch-policy.mjs +312 -0
  157. package/runtime/prime/bin/pi-product-workflows.mjs +394 -0
  158. package/runtime/prime/bin/prime-render-spec.mjs +123 -0
  159. package/runtime/prime/bin/prime-session-start.sh +24 -0
  160. package/runtime/prime/bin/publish-artifact.sh +271 -0
  161. package/runtime/prime/bin/publish-references.sh +144 -0
  162. package/runtime/prime/bin/repo-state.sh +96 -0
  163. package/runtime/prime/bin/search.sh +240 -0
  164. package/runtime/prime/bin/session-autosave.sh +209 -0
  165. package/runtime/prime/bin/session-log.sh +199 -0
  166. package/runtime/prime/bin/settings.sh +304 -0
  167. package/runtime/prime/bin/telemetry.sh +391 -0
  168. package/runtime/prime/bin/worktree-create.sh +128 -0
  169. package/runtime/prime/bin/worktree-remove.sh +50 -0
  170. package/runtime/prime/bin/worktree.sh +198 -0
  171. package/runtime/prime/manifest.json +178 -0
package/lib/setup.js CHANGED
@@ -17,6 +17,11 @@ const {
17
17
  installPiRuntime,
18
18
  reportPiRuntimeSummary,
19
19
  } = require("./pi-runtime");
20
+ const {
21
+ hasPrimeRuntimeSupport,
22
+ installPrimeRuntime,
23
+ reportPrimeRuntimeSummary,
24
+ } = require("./prime-runtime");
20
25
  const {
21
26
  installConnectRuntime,
22
27
  reportConnectRuntimeSummary,
@@ -524,6 +529,9 @@ async function install(data, ui, targetDir, opts = {}) {
524
529
  } else if (preferredRuntime === "pi") {
525
530
  const piRuntime = installPiRuntime(egregoreDir);
526
531
  reportPiRuntimeSummary(piRuntime, ui);
532
+ } else if (preferredRuntime === "prime") {
533
+ const primeRuntime = installPrimeRuntime(egregoreDir);
534
+ reportPrimeRuntimeSummary(primeRuntime, ui);
527
535
  }
528
536
 
529
537
  // Connect is an authenticated additive overlay on the exact OSS runtime.
@@ -844,6 +852,7 @@ function normalizeRuntime(runtime) {
844
852
  if (raw === "claude" || raw === "claude-code" || raw === "claude_code") return "claude-code";
845
853
  if (raw === "codex" || raw === "openai-codex" || raw === "openai_codex") return "codex";
846
854
  if (raw === "pi" || raw === "pi-coding-agent" || raw === "pi_coding_agent") return "pi";
855
+ if (raw === "prime" || raw === "prime-agent" || raw === "prime_agent") return "prime";
847
856
  throw new Error(`Unsupported Egregore runtime: ${runtime}`);
848
857
  }
849
858
 
@@ -851,6 +860,7 @@ function runtimeDisplay(runtime) {
851
860
  const normalized = normalizeRuntime(runtime);
852
861
  if (normalized === "codex") return "Codex";
853
862
  if (normalized === "pi") return "Pi";
863
+ if (normalized === "prime") return "Prime Agent";
854
864
  return "Claude Code";
855
865
  }
856
866
 
@@ -858,6 +868,7 @@ function runtimeBinary(runtime) {
858
868
  const normalized = normalizeRuntime(runtime);
859
869
  if (normalized === "codex") return "codex";
860
870
  if (normalized === "pi") return "pi";
871
+ if (normalized === "prime") return "prime-agent";
861
872
  return "claude";
862
873
  }
863
874
 
@@ -867,6 +878,8 @@ function assistantInstallCommand(runtime) {
867
878
  const normalized = normalizeRuntime(runtime);
868
879
  if (normalized === "codex") return "npm install -g @openai/codex";
869
880
  if (normalized === "pi") return "npm install -g --ignore-scripts @earendil-works/pi-coding-agent";
881
+ // Prime Agent is not on the public npm registry — install via its own script.
882
+ if (normalized === "prime") return "curl -fsSL https://app.primeintellect.ai/prime-agent/install.sh | sh";
870
883
  return "npm install -g @anthropic-ai/claude-code";
871
884
  }
872
885
 
@@ -879,6 +892,15 @@ function piTrustArgs() {
879
892
  }
880
893
  }
881
894
 
895
+ function primeTrustArgs() {
896
+ try {
897
+ const help = spawnSync("prime-agent", ["--help"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
898
+ return `${help.stdout || ""}\n${help.stderr || ""}`.includes("--approve") ? ["--approve"] : [];
899
+ } catch {
900
+ return [];
901
+ }
902
+ }
903
+
882
904
  function claudeLaunchArgs(egregoreDir) {
883
905
  const args = ["start"];
884
906
  const memoryLink = path.join(egregoreDir, "memory");
@@ -903,6 +925,7 @@ function runtimeLaunchArgs(runtime, egregoreDir) {
903
925
  ];
904
926
  }
905
927
  if (normalizeRuntime(runtime) === "pi") return piTrustArgs();
928
+ if (normalizeRuntime(runtime) === "prime") return primeTrustArgs();
906
929
  return claudeLaunchArgs(egregoreDir);
907
930
  }
908
931
 
@@ -1000,6 +1023,16 @@ function piSupportMessage(egregoreDir) {
1000
1023
  ].join("\n");
1001
1024
  }
1002
1025
 
1026
+ function primeSupportMessage(egregoreDir) {
1027
+ return [
1028
+ "Prime Agent runtime support is missing from this Egregore checkout.",
1029
+ ` path: ${egregoreDir}`,
1030
+ "",
1031
+ "Run npx -y create-egregore@latest to install the packaged Prime Agent runtime, then rerun egregore.",
1032
+ "Prime Agent loads Egregore through project-local .prime/agent resources and the shared portable skill corpus.",
1033
+ ].join("\n");
1034
+ }
1035
+
1003
1036
  function installCodexSkills(egregoreDir) {
1004
1037
  const script = path.join(egregoreDir, "bin", "codex-install-skills.sh");
1005
1038
  if (!fs.existsSync(script)) return false;
@@ -1093,10 +1126,10 @@ async function launchOrInstruct(egregoreDir, alias, ui, ctx = {}) {
1093
1126
  }
1094
1127
 
1095
1128
  if (!commandExists(binary)) {
1096
- const available = ["claude-code", "codex", "pi"].filter((candidate) => commandExists(runtimeBinary(candidate)));
1129
+ const available = ["claude-code", "codex", "pi", "prime"].filter((candidate) => commandExists(runtimeBinary(candidate)));
1097
1130
  // The user already chose `runtime` at the picker — lead with installing
1098
1131
  // THAT one ("install Codex first"), then offer the other as an alternative.
1099
- const other = available[0] || ["claude-code", "codex", "pi"].find((candidate) => candidate !== runtime);
1132
+ const other = available[0] || ["claude-code", "codex", "pi", "prime"].find((candidate) => candidate !== runtime);
1100
1133
  if (available.length === 0) {
1101
1134
  ui.warn(`Almost there — install ${display} to start sessions.`);
1102
1135
  ui.info(` Install ${display} first:`);
@@ -1115,7 +1148,7 @@ async function launchOrInstruct(egregoreDir, alias, ui, ctx = {}) {
1115
1148
  return;
1116
1149
  }
1117
1150
 
1118
- const quitCommand = runtime === "pi" ? "/quit" : "/exit";
1151
+ const quitCommand = runtime === "pi" || runtime === "prime" ? "/quit" : "/exit";
1119
1152
  ui.info(`Starting Egregore in ${ui.bold(display)} now — press ${ui.bold("Ctrl+D")} (or ${quitCommand}) to return to your shell.`);
1120
1153
  ui.info(`Next time, ${launcherNextStep(ui, aliasName)}`);
1121
1154
  console.log("");
@@ -1146,6 +1179,15 @@ async function launchOrInstruct(egregoreDir, alias, ui, ctx = {}) {
1146
1179
  console.log("");
1147
1180
  return;
1148
1181
  }
1182
+ } else if (runtime === "prime") {
1183
+ const primeRuntime = installPrimeRuntime(egregoreDir);
1184
+ reportPrimeRuntimeSummary(primeRuntime, ui);
1185
+ if (!hasPrimeRuntimeSupport(egregoreDir)) {
1186
+ ui.warn(primeSupportMessage(egregoreDir));
1187
+ ui.info(`Run ${ui.bold(aliasName)} after updating the checkout.`);
1188
+ console.log("");
1189
+ return;
1190
+ }
1149
1191
  }
1150
1192
 
1151
1193
  const result = spawnSync(binary, runtimeLaunchArgs(runtime, egregoreDir), {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-egregore",
3
- "version": "0.19.33",
3
+ "version": "0.20.0",
4
4
  "description": "Set up Egregore for your team in one command \u2014 installs the egregore launcher and your choice of Claude Code, Codex, or Pi.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -10,9 +10,10 @@
10
10
  "node": ">=18"
11
11
  },
12
12
  "scripts": {
13
- "build:runtime": "node ../../bin/capability-distribution.mjs generate-skill-view --root ../.. && node scripts/build-runtime-bundle.mjs && node scripts/build-pi-runtime-bundle.mjs && node ../../api/scripts/build-connect-runtime-pack.mjs",
13
+ "build:runtime": "node ../../bin/capability-distribution.mjs generate-skill-view --root ../.. && node scripts/build-runtime-bundle.mjs && node scripts/build-pi-runtime-bundle.mjs && node scripts/build-prime-runtime-bundle.mjs && node ../../api/scripts/build-connect-runtime-pack.mjs",
14
14
  "build:pi-runtime": "node scripts/build-pi-runtime-bundle.mjs",
15
- "test": "node ../../bin/capability-distribution.mjs validate --root ../.. && node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node ../../api/scripts/build-connect-runtime-pack.mjs --check && node --test test/capability-distribution.test.js test/connect-runtime.test.js test/context.test.js test/path-lookup.test.js test/nixos-portability.test.js test/parse-join-target.test.js test/skip-repos.test.js test/install-origin-guard.test.js test/onboarding-shortcircuit.test.js test/welcome-screen.test.js test/runtime-selection.test.js test/command-generation.test.js test/auth-gh.test.js test/gauntlet-fixes.test.js test/codex-runtime.test.js test/pi-runtime.test.js test/pi-product-workflows.test.js test/installer-runtime-source.test.js test/scroll-repro.test.js test/launcher-refocus-redraw.test.js test/multiselect-remote-search.test.js test/back-navigation.test.js test/manifest-form.test.js test/launcher-delete.test.js test/launcher-connect.test.js test/installer-connect-choice.test.js test/launcher-connected-status.test.js test/launcher-permissions.test.js test/launcher-update.test.js test/connected-config.test.js",
15
+ "build:prime-runtime": "node scripts/build-prime-runtime-bundle.mjs",
16
+ "test": "node ../../bin/capability-distribution.mjs validate --root ../.. && node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node scripts/build-prime-runtime-bundle.mjs --check && node ../../bin/prime-render-spec.mjs --check && node ../../bin/pi-render-spec.mjs --check && node ../../api/scripts/build-connect-runtime-pack.mjs --check && node --test test/capability-distribution.test.js test/connect-runtime.test.js test/context.test.js test/path-lookup.test.js test/nixos-portability.test.js test/parse-join-target.test.js test/skip-repos.test.js test/install-origin-guard.test.js test/onboarding-shortcircuit.test.js test/welcome-screen.test.js test/runtime-selection.test.js test/command-generation.test.js test/auth-gh.test.js test/gauntlet-fixes.test.js test/codex-runtime.test.js test/pi-runtime.test.js test/prime-runtime.test.js test/prime-branch-policy.test.js test/prime-bridge-skill.test.js test/prime-session-smoke.test.js test/pi-product-workflows.test.js test/installer-runtime-source.test.js test/scroll-repro.test.js test/launcher-refocus-redraw.test.js test/multiselect-remote-search.test.js test/back-navigation.test.js test/manifest-form.test.js test/launcher-delete.test.js test/launcher-connect.test.js test/installer-connect-choice.test.js test/launcher-connected-status.test.js test/launcher-permissions.test.js test/launcher-update.test.js test/connected-config.test.js",
16
17
  "test:e2e": "node --test test/e2e-local.test.js",
17
18
  "test:all": "node scripts/build-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node --test test/"
18
19
  },
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: ingest-notion
3
+ description: 'Fallback Codex adapter for the Egregore ingest-notion workflow.'
4
+ ---
5
+
6
+ <!-- generated-by: bin/codex-sync-skills.sh -->
7
+
8
+ # Egregore ingest-notion Adapter
9
+
10
+ This is fallback coverage for a long-tail Egregore workflow that has not been
11
+ ported to a hand-written Codex-native skill yet.
12
+
13
+ Use the project shell and filesystem directly. Do not invoke Claude Code
14
+ commands. Translate interactive choices to structured Codex question tooling
15
+ when it is available; otherwise render compact numbered choices with an
16
+ `Other:` option and wait for the user.
17
+
18
+ 1. Read `.claude/skills/ingest-notion/SKILL.md` for the workflow details.
19
+ 2. Run the referenced `bin/` scripts directly from Codex.
20
+ 3. Treat graph and publish steps as best-effort unless that workflow explicitly
21
+ says they are required.
22
+ 4. For every external notification, follow
23
+ `.claude/context/notification-consent.md`: plan without sending, then show
24
+ a separate exact Send / Edit / Cancel checkpoint. Never infer notification
25
+ consent from the workflow request or a batch approval.
26
+ 5. Keep local-mode behavior filesystem-first and avoid graph or notification
27
+ calls when `egregore.json` declares `"mode": "local"`.
28
+ 6. Never call the deprecated `egregore-handoff` CLI for Egregore project
29
+ handoffs.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: notion-connect
3
+ description: 'Fallback Codex adapter for the Egregore notion-connect workflow.'
4
+ ---
5
+
6
+ <!-- generated-by: bin/codex-sync-skills.sh -->
7
+
8
+ # Egregore notion-connect Adapter
9
+
10
+ This is fallback coverage for a long-tail Egregore workflow that has not been
11
+ ported to a hand-written Codex-native skill yet.
12
+
13
+ Use the project shell and filesystem directly. Do not invoke Claude Code
14
+ commands. Translate interactive choices to structured Codex question tooling
15
+ when it is available; otherwise render compact numbered choices with an
16
+ `Other:` option and wait for the user.
17
+
18
+ 1. Read `.claude/skills/notion-connect/SKILL.md` for the workflow details.
19
+ 2. Run the referenced `bin/` scripts directly from Codex.
20
+ 3. Treat graph and publish steps as best-effort unless that workflow explicitly
21
+ says they are required.
22
+ 4. For every external notification, follow
23
+ `.claude/context/notification-consent.md`: plan without sending, then show
24
+ a separate exact Send / Edit / Cancel checkpoint. Never infer notification
25
+ consent from the workflow request or a batch approval.
26
+ 5. Keep local-mode behavior filesystem-first and avoid graph or notification
27
+ calls when `egregore.json` declares `"mode": "local"`.
28
+ 6. Never call the deprecated `egregore-handoff` CLI for Egregore project
29
+ handoffs.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: teams-connect
3
+ description: 'Fallback Codex adapter for the Egregore teams-connect workflow.'
4
+ ---
5
+
6
+ <!-- generated-by: bin/codex-sync-skills.sh -->
7
+
8
+ # Egregore teams-connect Adapter
9
+
10
+ This is fallback coverage for a long-tail Egregore workflow that has not been
11
+ ported to a hand-written Codex-native skill yet.
12
+
13
+ Use the project shell and filesystem directly. Do not invoke Claude Code
14
+ commands. Translate interactive choices to structured Codex question tooling
15
+ when it is available; otherwise render compact numbered choices with an
16
+ `Other:` option and wait for the user.
17
+
18
+ 1. Read `.claude/skills/teams-connect/SKILL.md` for the workflow details.
19
+ 2. Run the referenced `bin/` scripts directly from Codex.
20
+ 3. Treat graph and publish steps as best-effort unless that workflow explicitly
21
+ says they are required.
22
+ 4. For every external notification, follow
23
+ `.claude/context/notification-consent.md`: plan without sending, then show
24
+ a separate exact Send / Edit / Cancel checkpoint. Never infer notification
25
+ consent from the workflow request or a batch approval.
26
+ 5. Keep local-mode behavior filesystem-first and avoid graph or notification
27
+ calls when `egregore.json` declares `"mode": "local"`.
28
+ 6. Never call the deprecated `egregore-handoff` CLI for Egregore project
29
+ handoffs.
@@ -35,7 +35,7 @@
35
35
  {
36
36
  "section": "After Greeting — BRANCH ON FIRST RESPONSE",
37
37
  "action": "replace",
38
- "sourceHash": "88410d7c6c00",
38
+ "sourceHash": "d28a5c162ab4",
39
39
  "note": "EnterWorktree -> bin/agent.sh branch with git checkout fallback; AskUserQuestion -> numbered options in plain text; branch-guard mapped to .codex/hooks/branch-guard.js with instruction fallback; plan-mode note dropped (no plan mode on Codex); /branch + /onboarding -> skill tokens. Handoff claiming and repoState auto-checkout kept verbatim (pure git)."
40
40
  },
41
41
  {
@@ -101,7 +101,7 @@
101
101
  {
102
102
  "section": "Command Awareness",
103
103
  "action": "keep",
104
- "sourceHash": "905ad739e18c",
104
+ "sourceHash": "be00d1fc715f",
105
105
  "note": "Prepended the Codex command surface (skill tokens, native vs adapter split, $save abstraction); disambiguation map kept with /x -> $x token rendering. Tokens with no Codex skill (e.g. /loop, a Claude Code harness feature) are left as-is."
106
106
  },
107
107
  {
@@ -119,7 +119,7 @@
119
119
  {
120
120
  "section": "Mode",
121
121
  "action": "keep",
122
- "sourceHash": "ae5cbb9c5d30",
122
+ "sourceHash": "0f74e18fd1b4",
123
123
  "note": "Kept; /env and /checkup rendered as $skill tokens."
124
124
  },
125
125
  {
@@ -14,6 +14,12 @@
14
14
  > `.pi/APPEND_SYSTEM.md`, and your workflows are exposed through the
15
15
  > project-local `.pi/` runtime. Do not follow the Codex-specific block below.
16
16
  >
17
+ > **If you are Prime Agent** (the `prime-agent` harness): **stop here.** Your
18
+ > authoritative Egregore instructions are loaded from
19
+ > `.prime/agent/APPEND_SYSTEM.md`, and your workflows are exposed through the
20
+ > project-local `.prime/agent/` runtime. Do not follow the Codex-specific
21
+ > block below.
22
+ >
17
23
  > **If you are Codex or another shell-only agent:** this file is yours — continue.
18
24
 
19
25
  Egregore is no longer only a Claude Code workspace. Claude Code remains the
@@ -395,7 +401,7 @@ Invoke commands from user intent — don't wait for the slash. Each command file
395
401
  **Knowledge** — `$search` `$deep-reflect` `$archive` `$note` `$add` `$meeting` `$ingest` `$scroll` `$mock` `$audit`
396
402
  **Identity** — `$me` (view profile or set display name)
397
403
  **Coordination** — `$ask` `$quest` `$issue` `$invite` `$delete-user` `$announce`
398
- **Connectors** — `$notion-connect` (Notion workspace) `$telegram-connect` (Telegram group setup) `$teams-connect` (Microsoft Teams channel setup)
404
+ **Connectors** — `$notion-connect` (Notion workspace) `$telegram-connect` (Telegram group setup) `$teams-connect` (Microsoft Teams channel setup) `$slack-connect` (Slack channel setup)
399
405
  **Git** — `$branch` `$commit` `$push` `$pr` `$save` `$review-pr` `$contribute`
400
406
  **Spirits** — `$summon` (persistent agent processes)
401
407
  **Skills** — `$create-skill` (org-owned skill: scaffold, protect from updates, share)
@@ -411,7 +417,7 @@ Invoke commands from user intent — don't wait for the slash. Each command file
411
417
  - Tasks: `$todo` (personal) · `$quest` (team exploration) · `$issue` (something broken)
412
418
  - Questions: `$ask [person]` (async) · just ask (agent answers from context)
413
419
  - Ingestion: `$ingest <file-or-folder>` (org-scoped corpus intake) · `$ingest meeting` · `$ingest user-interview` · `$ingest google` · ambiguous → ask which type
414
- - Connectors: `$notion-connect` (Notion workspace) · `$telegram-connect` (Telegram group) · `$teams-connect` (MS Teams channel) · `$ingest` (bring content in) · `$ingest notion` (promote Notion docs)
420
+ - Connectors: `$notion-connect` (Notion workspace) · `$telegram-connect` (Telegram group) · `$teams-connect` (MS Teams channel) · `$slack-connect` (Slack channel) · `$ingest` (bring content in) · `$ingest notion` (promote Notion docs)
415
421
  - Identity: `$me` — "who am I", "call me oz"
416
422
  - People: `$invite` (add) · `$delete-user` (remove)
417
423
  - PRs: `$pr` (create) · `$review-pr` (review)
@@ -451,8 +457,9 @@ Egregore runs in one of two configurations, set by `mode` in `egregore.json`. De
451
457
 
452
458
  **Hard rules in local mode:**
453
459
  - Never tell the user to "ask their admin" for credentials. The user IS the admin.
454
- - Never surface `api_url`, `EGREGORE_API_KEY`, or "connected mode" as an upgrade path. Hosted Egregore is a separate service, not something a user can turn on by adding fields to `egregore.json`.
455
- - If a feature genuinely requires the hosted service, say so plainly ("this isn't available in this configuration") and stop. Do not improvise a path to enabling it.
460
+ - Never surface `api_url`, `EGREGORE_API_KEY`, or config edits as an upgrade path. Hosted Egregore is not something a user can turn on by adding fields to `egregore.json`.
461
+ - **The one sanctioned upgrade path is `egregore connect`** (the launcher flow: registers the org, provisions the key, replays the graph). Connect-tier connector skills carry an explicit upsell gate for local instances — deliver their message verbatim, offer the upgrade via `egregore connect` or a clean "not now", and stop on decline. Beyond that gate, do not improvise: no hand-set `api_url`, no partial flows.
462
+ - If a feature requires the hosted service and has no upsell gate, say so plainly ("this isn't available in this configuration") and stop.
456
463
  - Calling `bin/graph.sh` or `bin/notify.sh` in local mode is harmless — they fail soft and return empty results — but there is no need to call them; prefer reading `memory/` directly.
457
464
 
458
465
  **Connected mode** (`"mode": "connected"`, `api_url` set) — the hosted configuration, used by organizations on the hosted service. Full feature set: Neo4j knowledge graph via `bin/graph.sh`, Telegram notifications via `bin/notify.sh`, dashboard publication, API-backed context gathering on session start. Use `$env` to check API key, `$checkup` for diagnostics. If the graph is offline, show troubleshooting.
@@ -76,15 +76,11 @@ API_PID=$!
76
76
 
77
77
  # Git/disk: runs in parallel (stays client-side)
78
78
  (
79
- # Sync
79
+ # Refresh remote refs only. A data read must never mutate the working
80
+ # branch: the rebase this block used to run rewrote users' task branches as
81
+ # a side effect of /activity (observed rewinding a pushed branch mid-session).
82
+ # Workspace sync belongs to agent.sh sync / the session-start path.
80
83
  git -C "$SCRIPT_DIR" fetch origin --quiet 2>/dev/null || true
81
- CURRENT=$(git -C "$SCRIPT_DIR" branch --show-current 2>/dev/null || echo "unknown")
82
- if [ "$CURRENT" != "develop" ]; then
83
- git -C "$SCRIPT_DIR" fetch origin develop:develop --quiet 2>/dev/null || true
84
- fi
85
- if [[ "$CURRENT" == dev/* ]]; then
86
- git -C "$SCRIPT_DIR" rebase develop --quiet >/dev/null 2>&1 || git -C "$SCRIPT_DIR" rebase --abort >/dev/null 2>&1 || true
87
- fi
88
84
 
89
85
  # Memory sync
90
86
  if [ -d "$SCRIPT_DIR/memory/.git" ] || [ -L "$SCRIPT_DIR/memory" ]; then
@@ -99,6 +99,16 @@ _trigger_auto_thread() {
99
99
  ) >> "$LOGFILE" 2>&1 &
100
100
  }
101
101
 
102
+ # Personal off switch for ambient capture. ripcord_enabled=false disables BOTH
103
+ # ripcord notes and auto-push of dirty worktrees — a user who opts out of
104
+ # ambient capture must not find silent commits either. The attendant's other
105
+ # duties (graph cache, context seed, handoff lifecycle) are unaffected.
106
+ # NOTE: jq's `//` treats false as empty (the auto_update:false gotcha), so the
107
+ # test compares the raw value, never `.key // true`.
108
+ _capture_enabled() {
109
+ [ "$(jq -r '.ripcord_enabled' "$MAIN_DIR/.egregore-state.json" 2>/dev/null)" != "false" ]
110
+ }
111
+
102
112
  _author() {
103
113
  local a
104
114
  a=$(jq -r '.github_username // empty' "$MAIN_DIR/.egregore-state.json" 2>/dev/null)
@@ -249,6 +259,8 @@ _ripcord() {
249
259
  local transcript="$1" base author date_ym date_d slug topic file prompts gitsum
250
260
  base=$(basename "$transcript" .jsonl)
251
261
 
262
+ _capture_enabled || return 0
263
+
252
264
  grep -q "$base" "$JOURNAL" 2>/dev/null && return 0
253
265
  # Session already ended with ceremony? Then the attendant has no business
254
266
  # here. Scan only the tail — a session that merely *read* the /handoff or
@@ -336,6 +348,7 @@ _ripcord() {
336
348
  # --- Auto-push -------------------------------------------------------------
337
349
 
338
350
  _auto_push() {
351
+ _capture_enabled || return 0
339
352
  local wt branch dirty ahead upstream
340
353
  git -C "$MAIN_DIR" worktree list --porcelain 2>/dev/null | awk '/^worktree /{print $2}' | while read -r wt; do
341
354
  branch=$(git -C "$wt" branch --show-current 2>/dev/null)
@@ -28,6 +28,17 @@ set -uo pipefail
28
28
  SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
29
29
  STATE_FILE="$SCRIPT_DIR/.egregore-state.json"
30
30
 
31
+ # The attendant runs against the MAIN checkout and reads its state file, so
32
+ # ambient-capture settings must be written there — a worktree keeps its own
33
+ # copy, and writing the flag into it would silently do nothing.
34
+ MAIN_STATE_DIR="$SCRIPT_DIR"
35
+ if [ -f "$SCRIPT_DIR/.git" ]; then
36
+ _WT_GITDIR=$(sed 's/^gitdir: //' "$SCRIPT_DIR/.git" 2>/dev/null || true)
37
+ [ -n "$_WT_GITDIR" ] && MAIN_STATE_DIR=$(cd "$_WT_GITDIR/../../.." 2>/dev/null && pwd || echo "$SCRIPT_DIR")
38
+ fi
39
+ MAIN_STATE_FILE="$MAIN_STATE_DIR/.egregore-state.json"
40
+ [ -f "$MAIN_STATE_FILE" ] || MAIN_STATE_FILE="$STATE_FILE"
41
+
31
42
  [ -f "$STATE_FILE" ] || echo '{}' > "$STATE_FILE"
32
43
 
33
44
  # NB: jq's `//` swallows false — status would show "on" for enabled:false.
@@ -42,6 +53,11 @@ set_key() { # key value(json-encoded)
42
53
  jq ".$1 = $2" "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
43
54
  }
44
55
 
56
+ _set_main() { # key value(json-encoded) — writes where the attendant reads
57
+ jq ".$1 = $2" "$MAIN_STATE_FILE" > "$MAIN_STATE_FILE.tmp" \
58
+ && mv "$MAIN_STATE_FILE.tmp" "$MAIN_STATE_FILE"
59
+ }
60
+
45
61
  status() {
46
62
  local enabled scope publish
47
63
  enabled=$(get '.autosave_enabled' 'false')
@@ -50,6 +66,7 @@ status() {
50
66
  echo "autosave: $([ "$enabled" = "true" ] && echo on || echo "off (opt-in — 'autosave on' to join the experiment)")"
51
67
  echo "scope: $scope (all = handoffs + artifacts + docs · handoffs = memory repo only)"
52
68
  echo "publish: $publish (gate = PRs wait for your merge · auto = merge to develop automatically)"
69
+ echo "ripcord: $(jq -r 'if (.ripcord_enabled != null) then (.ripcord_enabled|tostring) else "true" end' "$MAIN_STATE_FILE" 2>/dev/null || echo true) (crash-recovery notes + branch auto-push when a session dies without /wrap)"
53
70
  }
54
71
 
55
72
  case "${1:-status}" in
@@ -61,6 +78,15 @@ case "${1:-status}" in
61
78
  all|handoffs) set_key autosave_scope "\"$2\"" && echo "scope: $2" ;;
62
79
  *) echo "usage: autosave.sh scope all|handoffs" >&2; exit 2 ;;
63
80
  esac ;;
81
+ ripcord)
82
+ # Ambient crash-recovery capture (the attendant): ripcord notes AND
83
+ # auto-push of dirty task branches. Separate from the autosave
84
+ # experiment above — this one defaults ON.
85
+ case "${2:-}" in
86
+ on) _set_main ripcord_enabled true && echo "ripcord: on — dead sessions leave a recovery note" ;;
87
+ off) _set_main ripcord_enabled false && echo "ripcord: off — no ambient notes, no branch auto-push" ;;
88
+ *) echo "usage: autosave.sh ripcord on|off" >&2; exit 2 ;;
89
+ esac ;;
64
90
  publish)
65
91
  case "${2:-}" in
66
92
  gate|auto) set_key autosave_publish "\"$2\"" && echo "publish: $2" ;;
@@ -82,5 +108,5 @@ case "${1:-status}" in
82
108
  echo "✗ PR #$n did not merge (conflict with develop?) — it stays open"
83
109
  fi
84
110
  done ;;
85
- *) echo "usage: autosave.sh [status|on|off|scope all|handoffs|publish gate|auto|merge]" >&2; exit 2 ;;
111
+ *) echo "usage: autosave.sh [status|on|off|scope all|handoffs|publish gate|auto|merge|ripcord on|off]" >&2; exit 2 ;;
86
112
  esac
@@ -58,6 +58,12 @@ const AGENTS_PREAMBLE = `# Egregore Agent Protocol
58
58
  > \`.pi/APPEND_SYSTEM.md\`, and your workflows are exposed through the
59
59
  > project-local \`.pi/\` runtime. Do not follow the Codex-specific block below.
60
60
  >
61
+ > **If you are Prime Agent** (the \`prime-agent\` harness): **stop here.** Your
62
+ > authoritative Egregore instructions are loaded from
63
+ > \`.prime/agent/APPEND_SYSTEM.md\`, and your workflows are exposed through the
64
+ > project-local \`.prime/agent/\` runtime. Do not follow the Codex-specific
65
+ > block below.
66
+ >
61
67
  > **If you are Codex or another shell-only agent:** this file is yours — continue.
62
68
 
63
69
  Egregore is no longer only a Claude Code workspace. Claude Code remains the
@@ -210,7 +210,9 @@ render_card() {
210
210
 
211
211
  # Staged auto-saves awaiting the user's merge (the autosave consent gate).
212
212
  # Live gh query so the line persists until the PRs actually merge.
213
- if command -v gh >/dev/null 2>&1; then
213
+ # Shown only while the autosave experiment is enabled.
214
+ autosave_on=$(jq -r '.autosave_enabled // false' "$STATE_FILE" 2>/dev/null)
215
+ if [ "$autosave_on" = "true" ] && command -v gh >/dev/null 2>&1; then
214
216
  gh_self=$(jq -r '.github_username // empty' "$STATE_FILE" 2>/dev/null)
215
217
  if [ -n "$gh_self" ]; then
216
218
  waiting_as=$(gh pr list --state open --author "$gh_self" --limit 20 \
@@ -24,21 +24,40 @@ if [ "$_MODE" = "local" ]; then
24
24
  exit 0
25
25
  fi
26
26
 
27
- # Load specific variables from .env if it exists (safe extraction, no arbitrary code execution)
28
- if [ -f "$SCRIPT_DIR/.env" ]; then
29
- EGREGORE_API_URL="${EGREGORE_API_URL:-$(grep '^EGREGORE_API_URL=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)}"
30
- EGREGORE_API_KEY="${EGREGORE_API_KEY:-$(grep '^EGREGORE_API_KEY=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)}"
27
+ # Load specific variables from .env if it exists (safe extraction, no arbitrary code execution).
28
+ # A worktree missing its .env symlink resolves through worktree-links.sh, which
29
+ # self-heals the link and falls back to the main checkout's .env.
30
+ _ENV_FILE="$SCRIPT_DIR/.env"
31
+ if [ ! -f "$_ENV_FILE" ] && [ -f "$SCRIPT_DIR/bin/lib/worktree-links.sh" ]; then
32
+ # shellcheck source=bin/lib/worktree-links.sh
33
+ source "$SCRIPT_DIR/bin/lib/worktree-links.sh" 2>/dev/null || true
34
+ _ENV_FILE="$(egregore_env_file "$SCRIPT_DIR" 2>/dev/null || true)"
35
+ fi
36
+ if [ -n "$_ENV_FILE" ] && [ -f "$_ENV_FILE" ]; then
37
+ EGREGORE_API_URL="${EGREGORE_API_URL:-$(grep '^EGREGORE_API_URL=' "$_ENV_FILE" 2>/dev/null | cut -d'=' -f2- || true)}"
38
+ EGREGORE_API_KEY="${EGREGORE_API_KEY:-$(grep '^EGREGORE_API_KEY=' "$_ENV_FILE" 2>/dev/null | cut -d'=' -f2- || true)}"
31
39
  fi
32
40
 
33
41
  API_URL="${EGREGORE_API_URL:-$(jq -r '.api_url // empty' "$CONFIG")}"
34
42
  API_KEY="${EGREGORE_API_KEY:-}"
35
43
 
36
- if [ -z "$API_URL" ] || [ -z "$API_KEY" ]; then
37
- # === OFFLINE MODE: No API key — return empty results (OSS/local) ===
44
+ if [ -z "$API_URL" ]; then
45
+ # === OFFLINE MODE: no api_url configured (OSS/unconfigured) ===
38
46
  echo '{"results":[]}'
39
47
  exit 0
40
48
  fi
41
49
 
50
+ if [ -z "$API_KEY" ]; then
51
+ # api_url is configured but no key was found — the local-mode gate exited
52
+ # above, so the org expects a live graph. Faking empty results here hides a
53
+ # missing .env (e.g. a worktree without its symlink) from every caller.
54
+ {
55
+ echo "Error: api_url is configured but EGREGORE_API_KEY is empty (looked in: ${_ENV_FILE:-$SCRIPT_DIR/.env})."
56
+ echo " If this is a worktree, its .env symlink may be missing. Run /env to configure."
57
+ } >&2
58
+ exit 1
59
+ fi
60
+
42
61
  QUERIES_JSON="${1:?Usage: graph-batch.sh '<json array of queries>'}"
43
62
 
44
63
  # Wrap the array into the batch request format
@@ -708,7 +708,8 @@ case "$OP" in
708
708
  fi
709
709
  bash "$GS" query "
710
710
  MATCH (s:Session)-[:HANDED_TO]->(p:Person)
711
- WHERE (
711
+ WHERE NOT coalesce(p.kind, '') IN ['identity_alias']
712
+ AND (
712
713
  toLower(coalesce(p.name, '')) = toLower(\$user)
713
714
  OR toLower(coalesce(p.github, '')) = toLower(\$user)
714
715
  OR toLower(coalesce(p.githubUsername, '')) = toLower(\$user)
@@ -718,13 +719,13 @@ case "$OP" in
718
719
  AND coalesce(s.handoffStatus, 'pending')
719
720
  IN ['pending','unread','read','claimed']
720
721
  WITH DISTINCT s
721
- OPTIONAL MATCH (s)-[:BY]->(author:Person)
722
- WITH s, author,
722
+ WITH s, head([(s)-[:BY]->(author:Person)
723
+ WHERE NOT coalesce(author.kind, '') IN ['identity_alias'] | author.name]) AS authorName,
723
724
  CASE WHEN s.date IS NULL THEN null
724
725
  ELSE duration.inDays(date(s.date), date()).days END AS ageDays
725
726
  RETURN s.id AS id,
726
727
  coalesce(s.topic, s.summary, s.branch) AS topic,
727
- coalesce(author.name, s.author, 'unknown') AS author,
728
+ coalesce(authorName, s.author, 'unknown') AS author,
728
729
  toString(s.date) AS date,
729
730
  coalesce(s.handoffStatus, 'pending') AS status,
730
731
  coalesce(s.handoffIntent, 'unclassified') AS intent,
@@ -21,10 +21,18 @@ if [ "$_MODE" = "local" ]; then
21
21
  exit 0
22
22
  fi
23
23
 
24
- # Load specific variables from .env if it exists (safe extraction, no arbitrary code execution)
25
- if [ -f "$SCRIPT_DIR/.env" ]; then
26
- EGREGORE_API_URL="${EGREGORE_API_URL:-$(grep '^EGREGORE_API_URL=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)}"
27
- EGREGORE_API_KEY="${EGREGORE_API_KEY:-$(grep '^EGREGORE_API_KEY=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2- || true)}"
24
+ # Load specific variables from .env if it exists (safe extraction, no arbitrary code execution).
25
+ # A worktree missing its .env symlink resolves through worktree-links.sh, which
26
+ # self-heals the link and falls back to the main checkout's .env.
27
+ _ENV_FILE="$SCRIPT_DIR/.env"
28
+ if [ ! -f "$_ENV_FILE" ] && [ -f "$SCRIPT_DIR/bin/lib/worktree-links.sh" ]; then
29
+ # shellcheck source=bin/lib/worktree-links.sh
30
+ source "$SCRIPT_DIR/bin/lib/worktree-links.sh" 2>/dev/null || true
31
+ _ENV_FILE="$(egregore_env_file "$SCRIPT_DIR" 2>/dev/null || true)"
32
+ fi
33
+ if [ -n "$_ENV_FILE" ] && [ -f "$_ENV_FILE" ]; then
34
+ EGREGORE_API_URL="${EGREGORE_API_URL:-$(grep '^EGREGORE_API_URL=' "$_ENV_FILE" 2>/dev/null | cut -d'=' -f2- || true)}"
35
+ EGREGORE_API_KEY="${EGREGORE_API_KEY:-$(grep '^EGREGORE_API_KEY=' "$_ENV_FILE" 2>/dev/null | cut -d'=' -f2- || true)}"
28
36
  fi
29
37
 
30
38
  # api_url comes from egregore.json (committed, non-secret)
@@ -168,8 +176,26 @@ if [ -n "$API_URL" ] && [ -n "$API_KEY" ]; then
168
176
  fi
169
177
  }
170
178
 
179
+ elif [ -n "$API_URL" ]; then
180
+ # === CONNECTED CONFIG, MISSING KEY ===
181
+ # api_url is configured, so the org expects a live graph, but no API key was
182
+ # found. Faking '{"results":[]}' here made a missing credential (e.g. a
183
+ # worktree without its .env symlink) indistinguishable from an empty graph —
184
+ # fail loudly instead. `test` keeps its offline JSON contract: dashboards,
185
+ # render-card, and startup-check consume it.
186
+ _missing_credentials() {
187
+ {
188
+ echo "Error: api_url is configured but EGREGORE_API_KEY is empty (looked in: ${_ENV_FILE:-$SCRIPT_DIR/.env})."
189
+ echo " If this is a worktree, its .env symlink may be missing. Run /env to configure."
190
+ } >&2
191
+ exit 1
192
+ }
193
+ run_query() { _missing_credentials; }
194
+ get_schema() { _missing_credentials; }
195
+ test_connection() { echo '{"status":"offline","reason":"no_api_key"}'; }
196
+
171
197
  else
172
- # === OFFLINE MODE: No API key — return empty results (OSS/local) ===
198
+ # === OFFLINE MODE: no api_url configured (OSS/unconfigured) ===
173
199
  run_query() { echo '{"results":[]}'; }
174
200
  get_schema() { echo '{}'; }
175
201
  test_connection() { echo '{"status":"offline","reason":"no_api_key"}'; }