aether-colony 5.0.0 → 5.1.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 (312) hide show
  1. package/.aether/aether-utils.sh +3150 -3349
  2. package/.aether/agents-claude/aether-ambassador.md +265 -0
  3. package/.aether/agents-claude/aether-archaeologist.md +327 -0
  4. package/.aether/agents-claude/aether-architect.md +236 -0
  5. package/.aether/agents-claude/aether-auditor.md +271 -0
  6. package/.aether/agents-claude/aether-builder.md +224 -0
  7. package/.aether/agents-claude/aether-chaos.md +269 -0
  8. package/.aether/agents-claude/aether-chronicler.md +305 -0
  9. package/.aether/agents-claude/aether-gatekeeper.md +330 -0
  10. package/.aether/agents-claude/aether-includer.md +374 -0
  11. package/.aether/agents-claude/aether-keeper.md +272 -0
  12. package/.aether/agents-claude/aether-measurer.md +322 -0
  13. package/.aether/agents-claude/aether-oracle.md +237 -0
  14. package/.aether/agents-claude/aether-probe.md +211 -0
  15. package/.aether/agents-claude/aether-queen.md +330 -0
  16. package/.aether/agents-claude/aether-route-setter.md +178 -0
  17. package/.aether/agents-claude/aether-sage.md +418 -0
  18. package/.aether/agents-claude/aether-scout.md +179 -0
  19. package/.aether/agents-claude/aether-surveyor-disciplines.md +417 -0
  20. package/.aether/agents-claude/aether-surveyor-nest.md +355 -0
  21. package/.aether/agents-claude/aether-surveyor-pathogens.md +289 -0
  22. package/.aether/agents-claude/aether-surveyor-provisions.md +360 -0
  23. package/.aether/agents-claude/aether-tracker.md +270 -0
  24. package/.aether/agents-claude/aether-watcher.md +280 -0
  25. package/.aether/agents-claude/aether-weaver.md +248 -0
  26. package/.aether/commands/archaeology.yaml +653 -0
  27. package/.aether/commands/build.yaml +1221 -0
  28. package/.aether/commands/chaos.yaml +653 -0
  29. package/.aether/commands/colonize.yaml +438 -0
  30. package/.aether/commands/continue.yaml +1484 -0
  31. package/.aether/commands/council.yaml +304 -0
  32. package/.aether/commands/data-clean.yaml +80 -0
  33. package/.aether/commands/dream.yaml +275 -0
  34. package/.aether/commands/entomb.yaml +863 -0
  35. package/.aether/commands/export-signals.yaml +64 -0
  36. package/.aether/commands/feedback.yaml +158 -0
  37. package/.aether/commands/flag.yaml +160 -0
  38. package/.aether/commands/flags.yaml +177 -0
  39. package/.aether/commands/focus.yaml +112 -0
  40. package/.aether/commands/help.yaml +167 -0
  41. package/.aether/commands/history.yaml +137 -0
  42. package/.aether/commands/import-signals.yaml +79 -0
  43. package/.aether/commands/init.yaml +469 -0
  44. package/.aether/commands/insert-phase.yaml +98 -0
  45. package/.aether/commands/interpret.yaml +285 -0
  46. package/.aether/commands/lay-eggs.yaml +224 -0
  47. package/.aether/commands/maturity.yaml +122 -0
  48. package/.aether/commands/memory-details.yaml +74 -0
  49. package/.aether/commands/migrate-state.yaml +174 -0
  50. package/.aether/commands/oracle.yaml +1224 -0
  51. package/.aether/commands/organize.yaml +446 -0
  52. package/.aether/commands/patrol.yaml +621 -0
  53. package/.aether/commands/pause-colony.yaml +424 -0
  54. package/.aether/commands/phase.yaml +124 -0
  55. package/.aether/commands/pheromones.yaml +153 -0
  56. package/.aether/commands/plan.yaml +1313 -0
  57. package/.aether/commands/preferences.yaml +63 -0
  58. package/.aether/commands/redirect.yaml +123 -0
  59. package/.aether/commands/resume-colony.yaml +373 -0
  60. package/.aether/commands/resume.yaml +398 -0
  61. package/.aether/commands/run.yaml +193 -0
  62. package/.aether/commands/seal.yaml +1205 -0
  63. package/.aether/commands/skill-create.yaml +337 -0
  64. package/.aether/commands/status.yaml +364 -0
  65. package/.aether/commands/swarm.yaml +352 -0
  66. package/.aether/commands/tunnels.yaml +814 -0
  67. package/.aether/commands/update.yaml +131 -0
  68. package/.aether/commands/verify-castes.yaml +159 -0
  69. package/.aether/commands/watch.yaml +454 -0
  70. package/.aether/docs/INCIDENT_TEMPLATE.md +32 -0
  71. package/.aether/docs/QUEEN-SYSTEM.md +11 -11
  72. package/.aether/docs/README.md +32 -2
  73. package/.aether/docs/command-playbooks/README.md +23 -0
  74. package/.aether/docs/command-playbooks/build-complete.md +349 -0
  75. package/.aether/docs/command-playbooks/build-context.md +282 -0
  76. package/.aether/docs/command-playbooks/build-full.md +1682 -0
  77. package/.aether/docs/command-playbooks/build-prep.md +283 -0
  78. package/.aether/docs/command-playbooks/build-verify.md +405 -0
  79. package/.aether/docs/command-playbooks/build-wave.md +749 -0
  80. package/.aether/docs/command-playbooks/continue-advance.md +524 -0
  81. package/.aether/docs/command-playbooks/continue-finalize.md +447 -0
  82. package/.aether/docs/command-playbooks/continue-full.md +1724 -0
  83. package/.aether/docs/command-playbooks/continue-gates.md +686 -0
  84. package/.aether/docs/command-playbooks/continue-verify.md +406 -0
  85. package/.aether/docs/context-continuity.md +84 -0
  86. package/.aether/docs/disciplines/DISCIPLINES.md +9 -7
  87. package/.aether/docs/error-codes.md +1 -1
  88. package/.aether/docs/known-issues.md +34 -173
  89. package/.aether/docs/pheromones.md +86 -6
  90. package/.aether/docs/plans/pheromone-display-plan.md +257 -0
  91. package/.aether/docs/queen-commands.md +10 -9
  92. package/.aether/docs/source-of-truth-map.md +132 -0
  93. package/.aether/docs/xml-utilities.md +47 -0
  94. package/.aether/rules/aether-colony.md +23 -13
  95. package/.aether/scripts/incident-test-add.sh +47 -0
  96. package/.aether/scripts/weekly-audit.sh +79 -0
  97. package/.aether/skills/.index.json +649 -0
  98. package/.aether/skills/colony/.manifest.json +16 -0
  99. package/.aether/skills/colony/build-discipline/SKILL.md +78 -0
  100. package/.aether/skills/colony/colony-interaction/SKILL.md +56 -0
  101. package/.aether/skills/colony/colony-lifecycle/SKILL.md +77 -0
  102. package/.aether/skills/colony/colony-visuals/SKILL.md +112 -0
  103. package/.aether/skills/colony/context-management/SKILL.md +80 -0
  104. package/.aether/skills/colony/error-presentation/SKILL.md +99 -0
  105. package/.aether/skills/colony/pheromone-protocol/SKILL.md +79 -0
  106. package/.aether/skills/colony/pheromone-visibility/SKILL.md +81 -0
  107. package/.aether/skills/colony/state-safety/SKILL.md +84 -0
  108. package/.aether/skills/colony/worker-priming/SKILL.md +82 -0
  109. package/.aether/skills/domain/.manifest.json +24 -0
  110. package/.aether/skills/domain/README.md +33 -0
  111. package/.aether/skills/domain/django/SKILL.md +49 -0
  112. package/.aether/skills/domain/docker/SKILL.md +52 -0
  113. package/.aether/skills/domain/golang/SKILL.md +52 -0
  114. package/.aether/skills/domain/graphql/SKILL.md +51 -0
  115. package/.aether/skills/domain/html-css/SKILL.md +48 -0
  116. package/.aether/skills/domain/nextjs/SKILL.md +45 -0
  117. package/.aether/skills/domain/nodejs/SKILL.md +53 -0
  118. package/.aether/skills/domain/postgresql/SKILL.md +53 -0
  119. package/.aether/skills/domain/prisma/SKILL.md +59 -0
  120. package/.aether/skills/domain/python/SKILL.md +50 -0
  121. package/.aether/skills/domain/rails/SKILL.md +52 -0
  122. package/.aether/skills/domain/react/SKILL.md +45 -0
  123. package/.aether/skills/domain/rest-api/SKILL.md +58 -0
  124. package/.aether/skills/domain/svelte/SKILL.md +47 -0
  125. package/.aether/skills/domain/tailwind/SKILL.md +45 -0
  126. package/.aether/skills/domain/testing/SKILL.md +53 -0
  127. package/.aether/skills/domain/typescript/SKILL.md +58 -0
  128. package/.aether/skills/domain/vue/SKILL.md +49 -0
  129. package/.aether/templates/QUEEN.md.template +23 -41
  130. package/.aether/templates/colony-state-reset.jq.template +1 -0
  131. package/.aether/templates/colony-state.template.json +4 -0
  132. package/.aether/templates/learning-observations.template.json +6 -0
  133. package/.aether/templates/midden.template.json +13 -0
  134. package/.aether/templates/pheromones.template.json +6 -0
  135. package/.aether/templates/session.template.json +9 -0
  136. package/.aether/utils/atomic-write.sh +63 -17
  137. package/.aether/utils/chamber-utils.sh +145 -2
  138. package/.aether/utils/emoji-audit.sh +166 -0
  139. package/.aether/utils/error-handler.sh +21 -7
  140. package/.aether/utils/file-lock.sh +182 -27
  141. package/.aether/utils/flag.sh +267 -0
  142. package/.aether/utils/hive.sh +572 -0
  143. package/.aether/utils/learning.sh +1928 -0
  144. package/.aether/utils/midden.sh +342 -0
  145. package/.aether/utils/oracle/oracle.md +168 -0
  146. package/.aether/utils/oracle/oracle.sh +1023 -0
  147. package/.aether/utils/pheromone.sh +2029 -0
  148. package/.aether/utils/queen.sh +1698 -0
  149. package/.aether/utils/scan.sh +860 -0
  150. package/.aether/utils/semantic-cli.sh +10 -8
  151. package/.aether/utils/session.sh +552 -0
  152. package/.aether/utils/skills.sh +509 -0
  153. package/.aether/utils/spawn-tree.sh +103 -271
  154. package/.aether/utils/spawn.sh +260 -0
  155. package/.aether/utils/state-api.sh +199 -0
  156. package/.aether/utils/state-loader.sh +8 -6
  157. package/.aether/utils/suggest.sh +611 -0
  158. package/.aether/utils/swarm-display.sh +10 -1
  159. package/.aether/utils/swarm.sh +1004 -0
  160. package/.aether/utils/watch-spawn-tree.sh +11 -2
  161. package/.aether/utils/xml-compose.sh +2 -2
  162. package/.aether/utils/xml-convert.sh +9 -5
  163. package/.aether/utils/xml-core.sh +5 -9
  164. package/.aether/utils/xml-query.sh +4 -4
  165. package/.aether/workers.md +86 -67
  166. package/.claude/agents/ant/aether-ambassador.md +2 -1
  167. package/.claude/agents/ant/aether-archaeologist.md +6 -1
  168. package/.claude/agents/ant/aether-architect.md +236 -0
  169. package/.claude/agents/ant/aether-auditor.md +6 -1
  170. package/.claude/agents/ant/aether-builder.md +38 -1
  171. package/.claude/agents/ant/aether-chaos.md +2 -1
  172. package/.claude/agents/ant/aether-chronicler.md +1 -0
  173. package/.claude/agents/ant/aether-gatekeeper.md +6 -1
  174. package/.claude/agents/ant/aether-includer.md +1 -0
  175. package/.claude/agents/ant/aether-keeper.md +1 -0
  176. package/.claude/agents/ant/aether-measurer.md +6 -1
  177. package/.claude/agents/ant/aether-oracle.md +237 -0
  178. package/.claude/agents/ant/aether-probe.md +2 -1
  179. package/.claude/agents/ant/aether-queen.md +6 -1
  180. package/.claude/agents/ant/aether-route-setter.md +6 -1
  181. package/.claude/agents/ant/aether-sage.md +68 -3
  182. package/.claude/agents/ant/aether-scout.md +38 -1
  183. package/.claude/agents/ant/aether-surveyor-disciplines.md +2 -1
  184. package/.claude/agents/ant/aether-surveyor-nest.md +2 -1
  185. package/.claude/agents/ant/aether-surveyor-pathogens.md +2 -1
  186. package/.claude/agents/ant/aether-surveyor-provisions.md +2 -1
  187. package/.claude/agents/ant/aether-tracker.md +6 -1
  188. package/.claude/agents/ant/aether-watcher.md +37 -1
  189. package/.claude/agents/ant/aether-weaver.md +2 -1
  190. package/.claude/commands/ant/archaeology.md +1 -8
  191. package/.claude/commands/ant/build.md +43 -1159
  192. package/.claude/commands/ant/chaos.md +1 -14
  193. package/.claude/commands/ant/colonize.md +1 -14
  194. package/.claude/commands/ant/continue.md +40 -1026
  195. package/.claude/commands/ant/council.md +9 -16
  196. package/.claude/commands/ant/data-clean.md +81 -0
  197. package/.claude/commands/ant/dream.md +12 -9
  198. package/.claude/commands/ant/entomb.md +62 -87
  199. package/.claude/commands/ant/export-signals.md +57 -0
  200. package/.claude/commands/ant/feedback.md +18 -0
  201. package/.claude/commands/ant/flag.md +12 -0
  202. package/.claude/commands/ant/flags.md +22 -8
  203. package/.claude/commands/ant/focus.md +18 -0
  204. package/.claude/commands/ant/help.md +40 -8
  205. package/.claude/commands/ant/history.md +3 -0
  206. package/.claude/commands/ant/import-signals.md +71 -0
  207. package/.claude/commands/ant/init.md +316 -191
  208. package/.claude/commands/ant/insert-phase.md +101 -0
  209. package/.claude/commands/ant/interpret.md +11 -0
  210. package/.claude/commands/ant/lay-eggs.md +167 -158
  211. package/.claude/commands/ant/maturity.md +22 -11
  212. package/.claude/commands/ant/memory-details.md +77 -0
  213. package/.claude/commands/ant/migrate-state.md +6 -0
  214. package/.claude/commands/ant/oracle.md +317 -62
  215. package/.claude/commands/ant/organize.md +10 -5
  216. package/.claude/commands/ant/patrol.md +620 -0
  217. package/.claude/commands/ant/pause-colony.md +8 -22
  218. package/.claude/commands/ant/phase.md +26 -37
  219. package/.claude/commands/ant/pheromones.md +156 -0
  220. package/.claude/commands/ant/plan.md +175 -52
  221. package/.claude/commands/ant/preferences.md +65 -0
  222. package/.claude/commands/ant/redirect.md +18 -0
  223. package/.claude/commands/ant/resume-colony.md +34 -20
  224. package/.claude/commands/ant/resume.md +51 -7
  225. package/.claude/commands/ant/run.md +195 -0
  226. package/.claude/commands/ant/seal.md +497 -78
  227. package/.claude/commands/ant/skill-create.md +286 -0
  228. package/.claude/commands/ant/status.md +127 -1
  229. package/.claude/commands/ant/swarm.md +11 -23
  230. package/.claude/commands/ant/tunnels.md +1 -0
  231. package/.claude/commands/ant/update.md +58 -135
  232. package/.claude/commands/ant/verify-castes.md +90 -42
  233. package/.claude/commands/ant/watch.md +1 -0
  234. package/.opencode/agents/aether-ambassador.md +1 -1
  235. package/.opencode/agents/aether-architect.md +133 -0
  236. package/.opencode/agents/aether-builder.md +3 -3
  237. package/.opencode/agents/aether-oracle.md +137 -0
  238. package/.opencode/agents/aether-queen.md +1 -1
  239. package/.opencode/agents/aether-route-setter.md +1 -1
  240. package/.opencode/agents/aether-scout.md +1 -1
  241. package/.opencode/agents/aether-surveyor-disciplines.md +6 -1
  242. package/.opencode/agents/aether-surveyor-nest.md +6 -1
  243. package/.opencode/agents/aether-surveyor-pathogens.md +6 -1
  244. package/.opencode/agents/aether-surveyor-provisions.md +6 -1
  245. package/.opencode/agents/aether-tracker.md +1 -1
  246. package/.opencode/agents/aether-watcher.md +1 -1
  247. package/.opencode/agents/aether-weaver.md +1 -1
  248. package/.opencode/commands/ant/archaeology.md +7 -14
  249. package/.opencode/commands/ant/build.md +54 -88
  250. package/.opencode/commands/ant/chaos.md +7 -24
  251. package/.opencode/commands/ant/colonize.md +8 -17
  252. package/.opencode/commands/ant/continue.md +595 -66
  253. package/.opencode/commands/ant/council.md +11 -22
  254. package/.opencode/commands/ant/data-clean.md +77 -0
  255. package/.opencode/commands/ant/dream.md +15 -17
  256. package/.opencode/commands/ant/entomb.md +28 -18
  257. package/.opencode/commands/ant/export-signals.md +54 -0
  258. package/.opencode/commands/ant/feedback.md +24 -5
  259. package/.opencode/commands/ant/flag.md +16 -4
  260. package/.opencode/commands/ant/flags.md +24 -10
  261. package/.opencode/commands/ant/focus.md +22 -5
  262. package/.opencode/commands/ant/help.md +41 -8
  263. package/.opencode/commands/ant/history.md +9 -0
  264. package/.opencode/commands/ant/import-signals.md +68 -0
  265. package/.opencode/commands/ant/init.md +365 -156
  266. package/.opencode/commands/ant/insert-phase.md +107 -0
  267. package/.opencode/commands/ant/interpret.md +16 -0
  268. package/.opencode/commands/ant/lay-eggs.md +184 -112
  269. package/.opencode/commands/ant/maturity.md +18 -2
  270. package/.opencode/commands/ant/memory-details.md +83 -0
  271. package/.opencode/commands/ant/migrate-state.md +12 -0
  272. package/.opencode/commands/ant/oracle.md +322 -67
  273. package/.opencode/commands/ant/organize.md +14 -12
  274. package/.opencode/commands/ant/patrol.md +626 -0
  275. package/.opencode/commands/ant/pause-colony.md +12 -29
  276. package/.opencode/commands/ant/phase.md +30 -40
  277. package/.opencode/commands/ant/pheromones.md +162 -0
  278. package/.opencode/commands/ant/plan.md +184 -56
  279. package/.opencode/commands/ant/preferences.md +71 -0
  280. package/.opencode/commands/ant/redirect.md +22 -5
  281. package/.opencode/commands/ant/resume-colony.md +38 -27
  282. package/.opencode/commands/ant/resume.md +71 -20
  283. package/.opencode/commands/ant/run.md +201 -0
  284. package/.opencode/commands/ant/seal.md +230 -25
  285. package/.opencode/commands/ant/skill-create.md +63 -0
  286. package/.opencode/commands/ant/status.md +124 -31
  287. package/.opencode/commands/ant/swarm.md +3 -345
  288. package/.opencode/commands/ant/tunnels.md +3 -9
  289. package/.opencode/commands/ant/update.md +63 -127
  290. package/.opencode/commands/ant/verify-castes.md +96 -42
  291. package/.opencode/commands/ant/watch.md +7 -0
  292. package/CHANGELOG.md +278 -1
  293. package/README.md +188 -340
  294. package/bin/cli.js +236 -429
  295. package/bin/generate-commands.js +186 -0
  296. package/bin/generate-commands.sh +128 -89
  297. package/bin/lib/spawn-logger.js +0 -15
  298. package/bin/lib/update-transaction.js +285 -35
  299. package/bin/npx-install.js +178 -0
  300. package/bin/validate-package.sh +85 -3
  301. package/package.json +7 -3
  302. package/.aether/CONTEXT.md +0 -160
  303. package/.aether/docs/QUEEN.md +0 -84
  304. package/.aether/exchange/colony-registry.xml +0 -11
  305. package/.aether/exchange/pheromones.xml +0 -87
  306. package/.aether/exchange/queen-wisdom.xml +0 -14
  307. package/.aether/model-profiles.yaml +0 -100
  308. package/.aether/utils/spawn-with-model.sh +0 -56
  309. package/bin/lib/model-profiles.js +0 -445
  310. package/bin/lib/model-verify.js +0 -288
  311. package/bin/lib/proxy-health.js +0 -253
  312. package/bin/lib/telemetry.js +0 -441
@@ -0,0 +1,1023 @@
1
+ #!/bin/bash
2
+ # Oracle Ant - Deep research loop using RALF pattern
3
+ # Usage: ./oracle.sh [max_iterations_override]
4
+ # Based on: https://github.com/snarktank/ralph
5
+ #
6
+ # Configuration is read from state.json (written by /ant:oracle wizard).
7
+ # Command-line arg overrides max_iterations if provided.
8
+
9
+ set -e
10
+
11
+ # Unset CLAUDECODE to allow spawning Claude CLI from within Claude Code
12
+ unset CLAUDECODE 2>/dev/null || true
13
+
14
+ # Configuration
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ AETHER_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
17
+
18
+ # State files live in the colony's .aether/oracle/ directory (not alongside this script)
19
+ ORACLE_STATE_DIR="$AETHER_ROOT/.aether/oracle"
20
+
21
+ # Files
22
+ STATE_FILE="$ORACLE_STATE_DIR/state.json"
23
+ PLAN_FILE="$ORACLE_STATE_DIR/plan.json"
24
+ GAPS_FILE="$ORACLE_STATE_DIR/gaps.md"
25
+ SYNTHESIS_FILE="$ORACLE_STATE_DIR/synthesis.md"
26
+ RESEARCH_PLAN_FILE="$ORACLE_STATE_DIR/research-plan.md"
27
+ STOP_FILE="$ORACLE_STATE_DIR/.stop"
28
+ ARCHIVE_DIR="$ORACLE_STATE_DIR/archive"
29
+ DISCOVERIES_DIR="$ORACLE_STATE_DIR/discoveries"
30
+
31
+ # Generate research-plan.md from state.json and plan.json
32
+ generate_research_plan() {
33
+ local state_file="$STATE_FILE"
34
+ local plan_file="$PLAN_FILE"
35
+ local output_file="$RESEARCH_PLAN_FILE"
36
+
37
+ # Bail if source files don't exist
38
+ [ -f "$state_file" ] || return 0
39
+ [ -f "$plan_file" ] || return 0
40
+
41
+ local topic iteration max_iter confidence status
42
+ topic=$(jq -r '.topic' "$state_file")
43
+ iteration=$(jq -r '.iteration' "$state_file")
44
+ max_iter=$(jq -r '.max_iterations' "$state_file")
45
+ confidence=$(jq -r '.overall_confidence' "$state_file")
46
+ status=$(jq -r '.status' "$state_file")
47
+
48
+ {
49
+ echo "# Research Plan"
50
+ echo ""
51
+ echo "**Topic:** $topic"
52
+ echo "**Status:** $status | **Iteration:** $iteration of $max_iter"
53
+ echo "**Overall Confidence:** ${confidence}%"
54
+ echo ""
55
+ echo "## Questions"
56
+ echo "| # | Question | Status | Confidence |"
57
+ echo "|---|----------|--------|------------|"
58
+ jq -r '.questions[] | "| \(.id) | \(.text) | \(.status) | \(.confidence)% |"' "$plan_file"
59
+ echo ""
60
+ echo "## Next Steps"
61
+ local next
62
+ next=$(jq -r '[.questions[] | select(.status != "answered")] | sort_by(.confidence) | first | .text // "All questions answered"' "$plan_file")
63
+ echo "Next investigation: $next"
64
+
65
+ # Show trust summary if available
66
+ local trust_ratio
67
+ trust_ratio=$(jq '.trust_summary.trust_ratio // -1' "$plan_file" 2>/dev/null || echo "-1")
68
+ if [ "$trust_ratio" -ge 0 ]; then
69
+ local total single multi
70
+ total=$(jq '.trust_summary.total_findings // 0' "$plan_file")
71
+ single=$(jq '.trust_summary.single_source // 0' "$plan_file")
72
+ multi=$(jq '.trust_summary.multi_source // 0' "$plan_file")
73
+ echo ""
74
+ echo "## Source Trust"
75
+ echo "| Total Findings | Multi-Source | Single-Source | Trust Ratio |"
76
+ echo "|----------------|-------------|---------------|-------------|"
77
+ echo "| $total | $multi | $single | ${trust_ratio}% |"
78
+ fi
79
+
80
+ echo ""
81
+ echo "---"
82
+ echo "*Generated from plan.json -- do not edit directly*"
83
+ } > "$output_file"
84
+ }
85
+
86
+ # Determine research phase based on structural metrics in state.json and plan.json
87
+ # Phases: survey -> investigate -> synthesize -> verify
88
+ determine_phase() {
89
+ local state_file="$1"
90
+ local plan_file="$2"
91
+
92
+ # Bail to default if files missing
93
+ [ -f "$state_file" ] || { echo "survey"; return 0; }
94
+ [ -f "$plan_file" ] || { echo "survey"; return 0; }
95
+
96
+ local total_questions touched_count avg_confidence below_50_count
97
+
98
+ total_questions=$(jq '[.questions[]] | length' "$plan_file" 2>/dev/null || echo "0")
99
+ if [ "$total_questions" -eq 0 ]; then
100
+ echo "survey"
101
+ return 0
102
+ fi
103
+
104
+ # Count questions with non-empty iterations_touched arrays
105
+ touched_count=$(jq '[.questions[] | select((.iterations_touched // []) | length > 0)] | length' "$plan_file" 2>/dev/null || echo "0")
106
+
107
+ # Average confidence across all questions
108
+ avg_confidence=$(jq '[.questions[].confidence] | if length > 0 then (add / length) else 0 end | floor' "$plan_file" 2>/dev/null || echo "0")
109
+
110
+ # Count questions below 50% confidence that are not answered
111
+ below_50_count=$(jq '[.questions[] | select(.status != "answered" and .confidence < 50)] | length' "$plan_file" 2>/dev/null || echo "0")
112
+
113
+ # verify: avg confidence >= 80%
114
+ if [ "$avg_confidence" -ge 80 ]; then
115
+ echo "verify"
116
+ return 0
117
+ fi
118
+
119
+ # synthesize: avg confidence >= 60% OR fewer than 2 questions below 50%
120
+ if [ "$avg_confidence" -ge 60 ] || [ "$below_50_count" -lt 2 ]; then
121
+ echo "synthesize"
122
+ return 0
123
+ fi
124
+
125
+ # investigate: all questions touched OR avg confidence >= 25%
126
+ if [ "$touched_count" -ge "$total_questions" ] || [ "$avg_confidence" -ge 25 ]; then
127
+ echo "investigate"
128
+ return 0
129
+ fi
130
+
131
+ # Default: survey
132
+ echo "survey"
133
+ }
134
+
135
+ # Build the complete prompt by prepending a phase-specific directive to oracle.md
136
+ build_oracle_prompt() {
137
+ local state_file="$1"
138
+ local oracle_md="$2"
139
+ local steering_directive="${3:-}"
140
+
141
+ local current_phase
142
+ current_phase=$(jq -r '.phase // "survey"' "$state_file" 2>/dev/null || echo "survey")
143
+
144
+ # Emit phase-specific directive
145
+ case "$current_phase" in
146
+ survey)
147
+ cat <<'DIRECTIVE'
148
+ ## Current Phase: SURVEY
149
+
150
+ Cast a wide net -- get initial findings for every open question. Target untouched
151
+ questions first (those with empty iterations_touched arrays). Aim for 20-40%
152
+ confidence per question. List all discovered unknowns in gaps.md.
153
+
154
+ Do NOT go deep on any single question yet. Breadth over depth in this phase.
155
+ Your goal is to ensure every question has at least some initial findings before
156
+ the research moves to the investigation phase.
157
+
158
+ Source tracking is MANDATORY -- register sources and link every finding to source_ids.
159
+
160
+ ---
161
+
162
+ DIRECTIVE
163
+ ;;
164
+ investigate)
165
+ cat <<'DIRECTIVE'
166
+ ## Current Phase: INVESTIGATE
167
+
168
+ Target the lowest-confidence question and go DEEP. You MUST reference existing
169
+ findings in synthesis.md and ADD NEW information, not restate what is already there.
170
+ Aim to push confidence above 70% for your target question.
171
+
172
+ Update gaps.md with specific remaining unknowns. If you find contradictions with
173
+ existing findings, document them explicitly. One thoroughly investigated question
174
+ per iteration is better than shallow passes on many.
175
+
176
+ Source tracking is MANDATORY this iteration. Every new finding must have at least one source_id.
177
+
178
+ ---
179
+
180
+ DIRECTIVE
181
+ ;;
182
+ synthesize)
183
+ cat <<'DIRECTIVE'
184
+ ## Current Phase: SYNTHESIZE
185
+
186
+ Read ALL findings in synthesis.md before doing anything. Identify connections,
187
+ patterns, and contradictions ACROSS questions. Consolidate redundant findings.
188
+ Resolve contradictions with evidence. Push overall confidence toward the target.
189
+
190
+ Your job is NOT to find new information -- it is to make sense of what has already
191
+ been found. Cross-reference answers between questions. Strengthen weak claims
192
+ with evidence from other questions. Remove speculation that lacks support.
193
+
194
+ Verify source attribution is complete. Flag any findings missing source_ids.
195
+
196
+ ---
197
+
198
+ DIRECTIVE
199
+ ;;
200
+ verify)
201
+ cat <<'DIRECTIVE'
202
+ ## Current Phase: VERIFY
203
+
204
+ Focus on claims in gaps.md contradictions section. Cross-reference key findings
205
+ with additional sources. Confirm or correct confidence scores. Mark well-supported
206
+ questions as answered with 90%+ confidence.
207
+
208
+ Final gaps.md should contain only genuinely unresolvable unknowns. If a contradiction
209
+ cannot be resolved, document both positions with evidence quality assessment.
210
+ This is the final quality pass before research completion.
211
+
212
+ Cross-reference source coverage. Ensure all key findings have 2+ independent sources.
213
+
214
+ ---
215
+
216
+ DIRECTIVE
217
+ ;;
218
+ *)
219
+ echo "## Current Phase: $current_phase"
220
+ echo ""
221
+ echo "---"
222
+ echo ""
223
+ ;;
224
+ esac
225
+
226
+ # Inject steering directive if provided
227
+ if [ -n "$steering_directive" ]; then
228
+ echo "$steering_directive"
229
+ fi
230
+
231
+ # Read strategy and emit modifier
232
+ local strategy
233
+ strategy=$(jq -r '.strategy // "adaptive"' "$state_file" 2>/dev/null || echo "adaptive")
234
+
235
+ case "$strategy" in
236
+ breadth-first)
237
+ cat <<'STRATEGY'
238
+
239
+ STRATEGY NOTE: Breadth-first mode is active. Prioritize covering ALL questions
240
+ before going deep on any single one. Aim for broad coverage across the research
241
+ plan. When multiple questions are untouched, target the easiest-to-answer first
242
+ for maximum coverage.
243
+
244
+ STRATEGY
245
+ ;;
246
+ depth-first)
247
+ cat <<'STRATEGY'
248
+
249
+ STRATEGY NOTE: Depth-first mode is active. Pick the single most important open
250
+ question and investigate it exhaustively. Push confidence to 80%+ before moving
251
+ to the next question. Prefer thorough, well-sourced answers over broad coverage.
252
+
253
+ STRATEGY
254
+ ;;
255
+ *)
256
+ # adaptive: no strategy modifier needed
257
+ ;;
258
+ esac
259
+
260
+ # Emit the base oracle.md prompt
261
+ cat "$oracle_md"
262
+ }
263
+
264
+ # Compute convergence metrics from plan.json structural data
265
+ # Returns JSON object with gap_resolution_pct, coverage_pct, novelty_delta, total_findings
266
+ compute_convergence() {
267
+ local plan_file="$1"
268
+ local state_file="$2"
269
+
270
+ local total answered partial_high
271
+
272
+ total=$(jq '[.questions[]] | length' "$plan_file" 2>/dev/null || echo "0")
273
+ answered=$(jq '[.questions[] | select(.status == "answered")] | length' "$plan_file" 2>/dev/null || echo "0")
274
+ partial_high=$(jq '[.questions[] | select(.status == "partial" and .confidence >= 70)] | length' "$plan_file" 2>/dev/null || echo "0")
275
+
276
+ # Gap resolution: fraction of questions substantively addressed
277
+ local gap_resolution
278
+ if [ "$total" -eq 0 ]; then
279
+ gap_resolution=100
280
+ else
281
+ gap_resolution=$(( (answered + partial_high) * 100 / total ))
282
+ fi
283
+
284
+ # Coverage: fraction of questions with non-empty iterations_touched
285
+ local touched coverage
286
+ touched=$(jq '[.questions[] | select((.iterations_touched // []) | length > 0)] | length' "$plan_file" 2>/dev/null || echo "0")
287
+ if [ "$total" -eq 0 ]; then
288
+ coverage=100
289
+ else
290
+ coverage=$(( touched * 100 / total ))
291
+ fi
292
+
293
+ # Novelty: compare total findings count to previous iteration
294
+ local current_findings prev_findings novelty_delta
295
+ current_findings=$(jq '[.questions[].key_findings | length] | add // 0' "$plan_file" 2>/dev/null || echo "0")
296
+ prev_findings=$(jq '.convergence.prev_findings_count // 0' "$state_file" 2>/dev/null || echo "0")
297
+ novelty_delta=$(( current_findings - prev_findings ))
298
+
299
+ jq -n --argjson gap "$gap_resolution" --argjson cov "$coverage" \
300
+ --argjson novelty "$novelty_delta" --argjson findings "$current_findings" \
301
+ '{gap_resolution_pct: $gap, coverage_pct: $cov, novelty_delta: $novelty, total_findings: $findings}'
302
+ }
303
+
304
+ # Update convergence metrics in state.json after each iteration
305
+ update_convergence_metrics() {
306
+ local state_file="$1"
307
+ local plan_file="$2"
308
+
309
+ local metrics
310
+ metrics=$(compute_convergence "$plan_file" "$state_file")
311
+
312
+ local gap_pct coverage_pct novelty_delta total_findings
313
+ gap_pct=$(echo "$metrics" | jq '.gap_resolution_pct')
314
+ coverage_pct=$(echo "$metrics" | jq '.coverage_pct')
315
+ novelty_delta=$(echo "$metrics" | jq '.novelty_delta')
316
+ total_findings=$(echo "$metrics" | jq '.total_findings')
317
+
318
+ local current_confidence prev_confidence confidence_delta current_iteration current_phase
319
+ current_confidence=$(jq '.overall_confidence // 0' "$state_file" 2>/dev/null || echo "0")
320
+ prev_confidence=$(jq '.convergence.prev_overall_confidence // 0' "$state_file" 2>/dev/null || echo "0")
321
+ confidence_delta=$(( current_confidence - prev_confidence ))
322
+ current_iteration=$(jq '.iteration // 0' "$state_file" 2>/dev/null || echo "0")
323
+ current_phase=$(jq -r '.phase // "survey"' "$state_file" 2>/dev/null || echo "survey")
324
+
325
+ # Compute composite score:
326
+ # gap_resolution * 0.4 + coverage * 0.3 + (novelty_delta <= 1 ? 100 : 0) * 0.3
327
+ # Using integer arithmetic scaled by 100
328
+ local novelty_component composite_score converged
329
+ if [ "$novelty_delta" -le 1 ]; then
330
+ novelty_component=100
331
+ else
332
+ novelty_component=0
333
+ fi
334
+ composite_score=$(( gap_pct * 40 / 100 + coverage_pct * 30 / 100 + novelty_component * 30 / 100 ))
335
+
336
+ local conv_threshold
337
+ conv_threshold=${ORACLE_CONVERGENCE_THRESHOLD:-85}
338
+ if [ "$composite_score" -ge "$conv_threshold" ]; then
339
+ converged="true"
340
+ else
341
+ converged="false"
342
+ fi
343
+
344
+ # Update state.json with convergence data
345
+ jq --argjson prev_findings "$total_findings" \
346
+ --argjson prev_confidence "$current_confidence" \
347
+ --argjson iteration "$current_iteration" \
348
+ --argjson novelty "$novelty_delta" \
349
+ --argjson conf_delta "$confidence_delta" \
350
+ --argjson gap "$gap_pct" \
351
+ --argjson cov "$coverage_pct" \
352
+ --arg phase "$current_phase" \
353
+ --argjson composite "$composite_score" \
354
+ --argjson converged "$converged" \
355
+ '
356
+ .convergence = (.convergence // {}) |
357
+ .convergence.prev_findings_count = $prev_findings |
358
+ .convergence.prev_overall_confidence = $prev_confidence |
359
+ .convergence.history = ((.convergence.history // []) + [{
360
+ iteration: $iteration,
361
+ novelty_delta: $novelty,
362
+ confidence_delta: $conf_delta,
363
+ gap_resolution_pct: $gap,
364
+ coverage_pct: $cov,
365
+ phase: $phase
366
+ }]) |
367
+ .convergence.composite_score = $composite |
368
+ .convergence.converged = $converged
369
+ ' "$state_file" > "$state_file.tmp" && mv "$state_file.tmp" "$state_file"
370
+ }
371
+
372
+ # Compute trust scores from plan.json source tracking data
373
+ # Writes trust metadata to plan.json (trust_summary field)
374
+ compute_trust_scores() {
375
+ local plan_file="$1"
376
+
377
+ # Check if plan.json uses the new structured findings format
378
+ local has_structured
379
+ has_structured=$(jq '
380
+ [.questions[].key_findings[] | type] | if length == 0 then false else any(. == "object") end
381
+ ' "$plan_file" 2>/dev/null || echo "false")
382
+
383
+ if [ "$has_structured" != "true" ]; then
384
+ # Pre-Phase-9 plan.json with string findings -- skip trust computation
385
+ return 0
386
+ fi
387
+
388
+ local total_findings single_source multi_source no_source
389
+ total_findings=$(jq '[.questions[].key_findings[]] | length' "$plan_file" 2>/dev/null || echo "0")
390
+ single_source=$(jq '[.questions[].key_findings[] | select(type == "object" and (.source_ids | length) == 1)] | length' "$plan_file" 2>/dev/null || echo "0")
391
+ multi_source=$(jq '[.questions[].key_findings[] | select(type == "object" and (.source_ids | length) >= 2)] | length' "$plan_file" 2>/dev/null || echo "0")
392
+ no_source=$(jq '[.questions[].key_findings[] | select(type == "object" and ((.source_ids // []) | length) == 0)] | length' "$plan_file" 2>/dev/null || echo "0")
393
+
394
+ local trust_ratio=0
395
+ if [ "$total_findings" -gt 0 ]; then
396
+ trust_ratio=$(( multi_source * 100 / total_findings ))
397
+ fi
398
+
399
+ jq --argjson total "$total_findings" \
400
+ --argjson single "$single_source" \
401
+ --argjson multi "$multi_source" \
402
+ --argjson nosrc "$no_source" \
403
+ --argjson ratio "$trust_ratio" \
404
+ '.trust_summary = {
405
+ total_findings: $total,
406
+ single_source: $single,
407
+ multi_source: $multi,
408
+ no_source: $nosrc,
409
+ trust_ratio: $ratio
410
+ }' "$plan_file" > "$plan_file.tmp" && mv "$plan_file.tmp" "$plan_file"
411
+ }
412
+
413
+ # Read active pheromone signals and format as a steering directive for the AI prompt
414
+ # Returns formatted steering text, or empty string if no signals active
415
+ read_steering_signals() {
416
+ local aether_root="$1"
417
+ local utils="$aether_root/.aether/aether-utils.sh"
418
+
419
+ # Gracefully handle missing pheromone system
420
+ if [ ! -f "$utils" ]; then
421
+ echo ""
422
+ return 0
423
+ fi
424
+
425
+ # Read active signals via pheromone-read (handles decay, expiry, filtering)
426
+ local signals
427
+ signals=$(bash "$utils" pheromone-read 2>/dev/null || echo '{"signals":[]}')
428
+
429
+ # Extract the signals array from the json_ok wrapper
430
+ local signal_array
431
+ signal_array=$(echo "$signals" | jq -c '.result.signals // .signals // []' 2>/dev/null || echo '[]')
432
+
433
+ local count
434
+ count=$(echo "$signal_array" | jq 'length' 2>/dev/null || echo "0")
435
+
436
+ if [ "$count" -eq 0 ]; then
437
+ echo ""
438
+ return 0
439
+ fi
440
+
441
+ # Format steering directive
442
+ local directive=""
443
+
444
+ # REDIRECT signals (highest priority -- hard constraints, max 2)
445
+ local redirects
446
+ redirects=$(echo "$signal_array" | jq -r '
447
+ map(select(.type == "REDIRECT"))
448
+ | sort_by(-.effective_strength)
449
+ | .[:2]
450
+ | .[] | "- [" + ((.effective_strength * 100 | floor | tostring)) + "%] \"" + (.content.text // "") + "\""
451
+ ' 2>/dev/null || echo "")
452
+
453
+ if [ -n "$redirects" ]; then
454
+ directive+="**REDIRECT (Hard constraints -- MUST follow):**"$'\n'"$redirects"$'\n\n'
455
+ fi
456
+
457
+ # FOCUS signals (prioritization, max 3)
458
+ local focuses
459
+ focuses=$(echo "$signal_array" | jq -r '
460
+ map(select(.type == "FOCUS"))
461
+ | sort_by(-.effective_strength)
462
+ | .[:3]
463
+ | .[] | "- [" + ((.effective_strength * 100 | floor | tostring)) + "%] \"" + (.content.text // "") + "\""
464
+ ' 2>/dev/null || echo "")
465
+
466
+ if [ -n "$focuses" ]; then
467
+ directive+="**FOCUS (Prioritize these areas):**"$'\n'"$focuses"$'\n\n'
468
+ fi
469
+
470
+ # FEEDBACK signals (behavioral adjustment, max 2)
471
+ local feedbacks
472
+ feedbacks=$(echo "$signal_array" | jq -r '
473
+ map(select(.type == "FEEDBACK"))
474
+ | sort_by(-.effective_strength)
475
+ | .[:2]
476
+ | .[] | "- [" + ((.effective_strength * 100 | floor | tostring)) + "%] \"" + (.content.text // "") + "\""
477
+ ' 2>/dev/null || echo "")
478
+
479
+ if [ -n "$feedbacks" ]; then
480
+ directive+="**FEEDBACK (Adjust approach):**"$'\n'"$feedbacks"$'\n\n'
481
+ fi
482
+
483
+ if [ -n "$directive" ]; then
484
+ echo "## Active Steering Signals"
485
+ echo ""
486
+ echo "$directive"
487
+ echo "When selecting your target question, PRIORITIZE questions related to FOCUS areas."
488
+ echo "REDIRECT signals are hard constraints -- adjust your approach to comply."
489
+ echo "FEEDBACK signals are suggestions -- incorporate where appropriate."
490
+ echo ""
491
+ echo "---"
492
+ echo ""
493
+ fi
494
+ }
495
+
496
+ # Check if research has converged
497
+ # Returns 0 (true) if composite_score >= threshold AND last 2 history entries have low novelty
498
+ check_convergence() {
499
+ local state_file="$1"
500
+
501
+ local conv_threshold
502
+ conv_threshold=${ORACLE_CONVERGENCE_THRESHOLD:-85}
503
+
504
+ local composite_score
505
+ composite_score=$(jq '.convergence.composite_score // 0' "$state_file" 2>/dev/null || echo "0")
506
+
507
+ if [ "$composite_score" -lt "$conv_threshold" ]; then
508
+ return 1
509
+ fi
510
+
511
+ # Check that at least 2 history entries exist and last 2 have novelty_delta <= 1
512
+ local history_len
513
+ history_len=$(jq '(.convergence.history // []) | length' "$state_file" 2>/dev/null || echo "0")
514
+ if [ "$history_len" -lt 2 ]; then
515
+ return 1
516
+ fi
517
+
518
+ local low_novelty_count
519
+ low_novelty_count=$(jq '[(.convergence.history // [])[-2:][] | select(.novelty_delta <= 1)] | length' "$state_file" 2>/dev/null || echo "0")
520
+
521
+ if [ "$low_novelty_count" -ge 2 ]; then
522
+ return 0
523
+ fi
524
+
525
+ return 1
526
+ }
527
+
528
+ # Detect diminishing returns from convergence history
529
+ # Outputs: "strategy_change", "synthesize_now", or "continue"
530
+ detect_diminishing_returns() {
531
+ local state_file="$1"
532
+
533
+ local dr_window
534
+ dr_window=${ORACLE_DR_WINDOW:-3}
535
+
536
+ local history_len
537
+ history_len=$(jq '(.convergence.history // []) | length' "$state_file" 2>/dev/null || echo "0")
538
+
539
+ if [ "$history_len" -lt "$dr_window" ]; then
540
+ echo "continue"
541
+ return 0
542
+ fi
543
+
544
+ local current_phase
545
+ current_phase=$(jq -r '.phase // "survey"' "$state_file" 2>/dev/null || echo "survey")
546
+
547
+ # Phase-adjusted novelty threshold
548
+ local novelty_threshold
549
+ case "$current_phase" in
550
+ investigate) novelty_threshold=0 ;;
551
+ *) novelty_threshold=1 ;;
552
+ esac
553
+
554
+ # Count entries in the last dr_window with novelty at or below threshold
555
+ local low_change_count
556
+ low_change_count=$(jq --argjson window "$dr_window" --argjson threshold "$novelty_threshold" \
557
+ '[(.convergence.history // [])[-$window:][] | select(.novelty_delta <= $threshold)] | length' \
558
+ "$state_file" 2>/dev/null || echo "0")
559
+
560
+ if [ "$low_change_count" -ge "$dr_window" ]; then
561
+ case "$current_phase" in
562
+ survey|investigate)
563
+ echo "strategy_change"
564
+ ;;
565
+ synthesize|verify)
566
+ echo "synthesize_now"
567
+ ;;
568
+ *)
569
+ echo "continue"
570
+ ;;
571
+ esac
572
+ else
573
+ echo "continue"
574
+ fi
575
+ }
576
+
577
+ # Validate a JSON file and recover from backup if invalid
578
+ validate_and_recover() {
579
+ local file="$1"
580
+
581
+ if jq -e . "$file" >/dev/null 2>&1; then
582
+ return 0
583
+ fi
584
+
585
+ echo "WARNING: $(basename "$file") is invalid JSON. Attempting recovery..." >&2
586
+
587
+ # Try pre-iteration backup
588
+ if [ -f "${file}.pre-iteration" ] && jq -e . "${file}.pre-iteration" >/dev/null 2>&1; then
589
+ cp "${file}.pre-iteration" "$file"
590
+ echo " Recovered $(basename "$file") from pre-iteration backup." >&2
591
+ return 0
592
+ fi
593
+
594
+ # Fall back to atomic-write backup system
595
+ if [ -f "$AETHER_ROOT/.aether/utils/atomic-write.sh" ]; then
596
+ source "$AETHER_ROOT/.aether/utils/atomic-write.sh" 2>/dev/null || true
597
+ if type restore_backup >/dev/null 2>&1 && restore_backup "$file" 2>/dev/null; then
598
+ echo " Recovered $(basename "$file") from atomic-write backup." >&2
599
+ return 0
600
+ fi
601
+ fi
602
+
603
+ echo " FATAL: Cannot recover $(basename "$file")." >&2
604
+ return 1
605
+ }
606
+
607
+ # Build the synthesis-specific prompt for the final AI pass
608
+ build_synthesis_prompt() {
609
+ local reason="$1"
610
+
611
+ # Read template type from state.json
612
+ local template
613
+ template=$(jq -r '.template // "custom"' "$STATE_FILE" 2>/dev/null || echo "custom")
614
+
615
+ cat <<SYNTHESIS_DIRECTIVE
616
+ ## SYNTHESIS PASS (Final Report)
617
+
618
+ This is the final pass. The oracle loop has ended (reason: $reason).
619
+ Produce the best possible research report from the current state.
620
+
621
+ Read ALL of these files:
622
+ - .aether/oracle/state.json -- session metadata
623
+ - .aether/oracle/plan.json -- questions, findings, confidence, AND sources registry
624
+ - .aether/oracle/synthesis.md -- accumulated findings
625
+ - .aether/oracle/gaps.md -- remaining unknowns
626
+
627
+ If any state file is unreadable, skip it and work with what you have.
628
+
629
+ Then REWRITE synthesis.md as a structured final report.
630
+
631
+ SYNTHESIS_DIRECTIVE
632
+
633
+ # Emit template-specific sections
634
+ case "$template" in
635
+ tech-eval)
636
+ cat <<'TEMPLATE'
637
+ ### Required Sections:
638
+ 1. **Executive Summary** -- 2-3 paragraphs: what was evaluated, key conclusion, recommendation
639
+ 2. **Comparison Matrix** -- Table comparing the evaluated technology against alternatives on key dimensions (performance, community, learning curve, maturity, ecosystem)
640
+ 3. **Pros and Cons** -- Bullet lists of advantages and disadvantages with evidence citations
641
+ 4. **Adoption Assessment** -- Community size, maintenance status, release cadence, corporate backing
642
+ 5. **Migration/Integration Path** -- Steps to adopt, estimated effort, risks
643
+ 6. **Recommendation** -- Clear recommendation with confidence level and conditions/caveats
644
+ 7. **Open Questions** -- Remaining gaps
645
+ 8. **Sources** -- All sources with inline citations [S1], [S2] format
646
+
647
+ TEMPLATE
648
+ ;;
649
+ architecture-review)
650
+ cat <<'TEMPLATE'
651
+ ### Required Sections:
652
+ 1. **Executive Summary** -- 2-3 paragraphs: system overview, key findings, critical risks
653
+ 2. **Component Map** -- List of major components with responsibilities and boundaries
654
+ 3. **Dependency Analysis** -- How components connect, coupling assessment, external dependencies
655
+ 4. **Risk Assessment** -- Single points of failure, complexity hotspots, scaling bottlenecks
656
+ 5. **Scalability Analysis** -- Current capacity, growth limitations, scaling strategy
657
+ 6. **Improvement Recommendations** -- Prioritized list of architectural improvements
658
+ 7. **Open Questions** -- Remaining gaps
659
+ 8. **Sources** -- All sources with inline citations [S1], [S2] format
660
+
661
+ TEMPLATE
662
+ ;;
663
+ bug-investigation)
664
+ cat <<'TEMPLATE'
665
+ ### Required Sections:
666
+ 1. **Executive Summary** -- 1-2 paragraphs: bug description, root cause, recommended fix
667
+ 2. **Reproduction Steps** -- Exact steps to reproduce, environment details, frequency
668
+ 3. **Root Cause Analysis** -- What causes the bug, code paths involved, why it was introduced
669
+ 4. **Impact Assessment** -- Who is affected, severity, data loss risk
670
+ 5. **Fix Recommendations** -- Proposed fixes ranked by safety and effort, with tradeoffs
671
+ 6. **Related Issues** -- Similar bugs, upstream/downstream effects, regression risk
672
+ 7. **Open Questions** -- Remaining gaps
673
+ 8. **Sources** -- All sources with inline citations [S1], [S2] format
674
+
675
+ TEMPLATE
676
+ ;;
677
+ best-practices)
678
+ cat <<'TEMPLATE'
679
+ ### Required Sections:
680
+ 1. **Executive Summary** -- 2-3 paragraphs: domain overview, current state assessment, key recommendations
681
+ 2. **Best Practice Benchmark** -- What industry/community consensus considers best practice, with evidence
682
+ 3. **Current State Assessment** -- How the subject compares to best practice (strengths and gaps)
683
+ 4. **Gap Analysis** -- Specific gaps between current state and best practice, prioritized by impact
684
+ 5. **Action Plan** -- Ordered steps to close gaps, estimated effort, quick wins highlighted
685
+ 6. **Open Questions** -- Remaining gaps
686
+ 7. **Sources** -- All sources with inline citations [S1], [S2] format
687
+
688
+ TEMPLATE
689
+ ;;
690
+ *)
691
+ # custom or unrecognized: use existing generic structure
692
+ cat <<'TEMPLATE'
693
+ ### Required Sections:
694
+ 1. **Executive Summary** -- 2-3 paragraphs summarizing what was found
695
+ 2. **Findings by Question** -- organized by sub-question, with confidence %. Use inline citations [S1], [S2] linking findings to their sources. Flag single-source findings with (single source) marker.
696
+ 3. **Open Questions** -- remaining gaps with explanation of what is unknown and why
697
+ 4. **Methodology Notes** -- how many iterations, which phases completed
698
+ 5. **Sources** -- List ALL sources from plan.json sources registry: Format: [S1] Title -- URL (accessed: date). Group by type (documentation, blog, codebase, etc.). Note total source count and multi-source coverage percentage.
699
+
700
+ TEMPLATE
701
+ ;;
702
+ esac
703
+
704
+ # Common directives for all templates
705
+ cat <<'COMMON'
706
+
707
+ ### Confidence Grouping:
708
+ Within each findings section, group findings by confidence level:
709
+ - **High confidence (80%+)** -- list first with full citations
710
+ - **Medium confidence (50-79%)** -- list with caveats noted
711
+ - **Low confidence (<50%)** -- list as tentative/unverified
712
+
713
+ Use inline citations [S1], [S2] linking findings to their sources.
714
+ Flag single-source findings with (single source) marker.
715
+
716
+ Also update state.json: set status to "complete" if reason is "converged",
717
+ or "stopped" otherwise.
718
+
719
+ COMMON
720
+
721
+ # Append the base oracle.md for tool access and rules
722
+ cat "$SCRIPT_DIR/oracle.md"
723
+ }
724
+
725
+ # Run the synthesis pass: update state, invoke AI, regenerate research plan
726
+ run_synthesis_pass() {
727
+ local reason="$1"
728
+
729
+ # Update state.json status and stop_reason before AI call
730
+ local new_status
731
+ case "$reason" in
732
+ converged) new_status="complete" ;;
733
+ *) new_status="stopped" ;;
734
+ esac
735
+
736
+ if [ -f "$STATE_FILE" ] && jq -e . "$STATE_FILE" >/dev/null 2>&1; then
737
+ jq --arg status "$new_status" --arg reason "$reason" \
738
+ '.status = $status | .stop_reason = $reason' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
739
+ fi
740
+
741
+ echo ""
742
+ echo "==============================================================="
743
+ echo " SYNTHESIS PASS ($reason)"
744
+ echo "==============================================================="
745
+
746
+ # Invoke AI with synthesis prompt
747
+ if command -v timeout >/dev/null 2>&1; then
748
+ build_synthesis_prompt "$reason" | timeout 180 $AI_CMD 2>&1 | tee /dev/stderr || true
749
+ else
750
+ build_synthesis_prompt "$reason" | $AI_CMD 2>&1 | tee /dev/stderr || true
751
+ fi
752
+
753
+ # Regenerate research-plan.md one final time
754
+ generate_research_plan
755
+
756
+ echo ""
757
+ echo "Results saved to:"
758
+ echo " $SYNTHESIS_FILE"
759
+ echo " $RESEARCH_PLAN_FILE"
760
+ }
761
+
762
+ # Promote high-confidence oracle findings to colony knowledge
763
+ # Reads plan.json, extracts findings from questions with confidence >= 80% and status "answered"
764
+ # Calls instinct-create, learning-promote, and memory-capture for each qualifying finding
765
+ promote_to_colony() {
766
+ local plan_file="$1"
767
+ local state_file="$2"
768
+ local aether_root="$3"
769
+ local utils="$aether_root/.aether/aether-utils.sh"
770
+
771
+ # Verify state is complete or stopped (not active)
772
+ local status
773
+ status=$(jq -r '.status // "active"' "$state_file" 2>/dev/null || echo "active")
774
+ if [ "$status" = "active" ]; then
775
+ echo "ERROR: Research is still active. Wait for completion or stop the oracle first."
776
+ return 1
777
+ fi
778
+
779
+ # Verify colony state exists (promotion requires active colony)
780
+ if [ ! -f "$aether_root/.aether/data/COLONY_STATE.json" ]; then
781
+ echo "ERROR: No active colony. Run /ant:init first."
782
+ return 1
783
+ fi
784
+
785
+ local topic
786
+ topic=$(jq -r '.topic // "unknown"' "$state_file" 2>/dev/null || echo "unknown")
787
+
788
+ # Extract high-confidence answered questions (>= 80%)
789
+ local questions
790
+ questions=$(jq -c '[.questions[] | select(.status == "answered" and .confidence >= 80)]' "$plan_file" 2>/dev/null || echo "[]")
791
+
792
+ local count
793
+ count=$(echo "$questions" | jq 'length')
794
+
795
+ if [ "$count" -eq 0 ]; then
796
+ echo "No findings meet promotion threshold (answered + 80%+ confidence)."
797
+ echo "Lower-confidence findings remain in .aether/oracle/synthesis.md for reference."
798
+ return 0
799
+ fi
800
+
801
+ echo "Promoting $count high-confidence findings to colony knowledge..."
802
+
803
+ # Use process substitution to avoid subshell variable loss with while-read
804
+ local promoted=0
805
+ local failed=0
806
+
807
+ while IFS= read -r question; do
808
+ local q_text q_confidence findings_text
809
+ q_text=$(echo "$question" | jq -r '.text')
810
+ q_confidence=$(echo "$question" | jq -r '.confidence')
811
+
812
+ # Handle both v1.1 structured findings {text, source_ids, iteration} and v1.0 string findings
813
+ findings_text=$(echo "$question" | jq -r '[.key_findings[].text // .key_findings[]] | join("; ")' 2>/dev/null | head -c 200)
814
+
815
+ # Create instinct from the research finding
816
+ bash "$utils" instinct-create \
817
+ --trigger "researching: $q_text" \
818
+ --action "Oracle found (${q_confidence}% confidence): $findings_text" \
819
+ --confidence "$(echo "scale=2; $q_confidence / 100" | bc)" \
820
+ --domain "research" \
821
+ --source "oracle:$topic" \
822
+ --evidence "Oracle research: $q_text" 2>/dev/null || true
823
+
824
+ # Promote as learning (extract first finding for content)
825
+ local first_finding
826
+ first_finding=$(echo "$question" | jq -r '[.key_findings[].text // .key_findings[]] | first // "No findings"' 2>/dev/null)
827
+ bash "$utils" learning-promote \
828
+ "Oracle: $q_text -- $first_finding" \
829
+ "oracle" \
830
+ "oracle-research" \
831
+ "oracle,research" 2>/dev/null || true
832
+
833
+ # Record via memory-capture for observation tracking
834
+ bash "$utils" memory-capture learning \
835
+ "Oracle research finding: $q_text (${q_confidence}%)" \
836
+ "pattern" \
837
+ "oracle:promote" 2>/dev/null || true
838
+
839
+ promoted=$((promoted + 1))
840
+ done < <(echo "$questions" | jq -c '.[]')
841
+
842
+ echo ""
843
+ echo "Promoted $promoted findings to colony knowledge."
844
+ echo " - Instincts created in COLONY_STATE.json"
845
+ echo " - Learnings stored in learnings.json"
846
+ echo " - Observations tracked for wisdom promotion"
847
+ }
848
+
849
+ # Trap handler: synthesize before exit on SIGINT/SIGTERM
850
+ cleanup_and_synthesize() {
851
+ if [ "$INTERRUPTED" = true ]; then
852
+ exit 130
853
+ fi
854
+ INTERRUPTED=true
855
+ echo ""
856
+ echo "Oracle interrupted. Running synthesis pass..."
857
+ run_synthesis_pass "interrupted"
858
+ exit 130
859
+ }
860
+
861
+ # Check state.json exists (wizard must create it before launching oracle.sh)
862
+ if [ ! -f "$STATE_FILE" ]; then
863
+ echo "Error: No state.json found. Run /ant:oracle to configure research first."
864
+ exit 1
865
+ fi
866
+
867
+ # Read config from state.json (wizard writes these)
868
+ CURRENT_TOPIC=$(jq -r '.topic // empty' "$STATE_FILE" 2>/dev/null || echo "")
869
+ TARGET_CONFIDENCE=$(jq -r '.target_confidence // 95' "$STATE_FILE" 2>/dev/null || echo "95")
870
+ JSON_MAX_ITER=$(jq -r '.max_iterations // 50' "$STATE_FILE" 2>/dev/null || echo "50")
871
+
872
+ # Command-line arg overrides state.json
873
+ MAX_ITERATIONS=${1:-$JSON_MAX_ITER}
874
+
875
+ # Detect AI CLI (claude or opencode)
876
+ if command -v claude &>/dev/null; then
877
+ AI_CMD="claude --dangerously-skip-permissions --print"
878
+ elif command -v opencode &>/dev/null; then
879
+ AI_CMD="opencode --dangerously-skip-permissions --print"
880
+ else
881
+ echo "Error: Neither 'claude' nor 'opencode' CLI found on PATH."
882
+ exit 1
883
+ fi
884
+
885
+ # Archive previous run if topic changed
886
+ if [ -f "$STATE_FILE" ]; then
887
+ LAST_TOPIC=$(jq -r '.topic // empty' "$STATE_FILE" 2>/dev/null || echo "")
888
+ # If the wizard passed a new topic via environment, compare
889
+ if [ -n "${ORACLE_NEW_TOPIC:-}" ] && [ -n "$LAST_TOPIC" ] && [ "$ORACLE_NEW_TOPIC" != "$LAST_TOPIC" ]; then
890
+ ARCHIVE_FOLDER="$ARCHIVE_DIR/$(date +%Y-%m-%d-%H%M%S)"
891
+
892
+ echo "Archiving previous research: $LAST_TOPIC"
893
+ mkdir -p "$ARCHIVE_FOLDER"
894
+ for f in state.json plan.json gaps.md synthesis.md research-plan.md; do
895
+ [ -f "$ORACLE_STATE_DIR/$f" ] && cp "$ORACLE_STATE_DIR/$f" "$ARCHIVE_FOLDER/"
896
+ done
897
+ echo " Archived to: $ARCHIVE_FOLDER"
898
+ # Do NOT create empty files -- the wizard handles initial file creation
899
+ fi
900
+ fi
901
+
902
+ # Initialize discoveries directory
903
+ mkdir -p "$DISCOVERIES_DIR"
904
+
905
+ echo ""
906
+ echo "==============================================================="
907
+ echo " ORACLE ANT - Deep Research Loop"
908
+ echo "==============================================================="
909
+ echo "Topic: $CURRENT_TOPIC"
910
+ echo "Iterations: $MAX_ITERATIONS"
911
+ echo "Confidence: $TARGET_CONFIDENCE%"
912
+ echo "CLI: $AI_CMD"
913
+ echo ""
914
+
915
+ # Signal handling setup
916
+ INTERRUPTED=false
917
+ trap cleanup_and_synthesize SIGINT SIGTERM
918
+
919
+ # Main loop
920
+ for i in $(seq 1 "$MAX_ITERATIONS"); do
921
+ # Check for stop signal (cooperative stop)
922
+ if [ -f "$STOP_FILE" ]; then
923
+ rm -f "$STOP_FILE"
924
+ echo ""
925
+ echo "Oracle stopped by user at iteration $i"
926
+ run_synthesis_pass "stopped"
927
+ exit 0
928
+ fi
929
+
930
+ # Read steering signals from pheromones
931
+ STEERING_DIRECTIVE=$(read_steering_signals "$AETHER_ROOT")
932
+
933
+ # Build iteration header with optional steering info
934
+ SIGNAL_COUNT=$(echo "$STEERING_DIRECTIVE" | grep -c '^\- \[' 2>/dev/null || echo 0)
935
+ STRATEGY=$(jq -r '.strategy // "adaptive"' "$STATE_FILE" 2>/dev/null || echo "adaptive")
936
+
937
+ echo ""
938
+ echo "---------------------------------------------------------------"
939
+ echo " Iteration $i of $MAX_ITERATIONS"
940
+ if [ -n "$STEERING_DIRECTIVE" ] || [ "$STRATEGY" != "adaptive" ]; then
941
+ echo " Steering: $SIGNAL_COUNT signals active"
942
+ echo " Strategy: $STRATEGY"
943
+ fi
944
+ echo "---------------------------------------------------------------"
945
+
946
+ # Pre-iteration backup for recovery
947
+ cp "$STATE_FILE" "$STATE_FILE.pre-iteration"
948
+ cp "$PLAN_FILE" "$PLAN_FILE.pre-iteration"
949
+
950
+ # Run AI with phase-aware prompt (directive + steering + oracle.md)
951
+ OUTPUT=$(build_oracle_prompt "$STATE_FILE" "$SCRIPT_DIR/oracle.md" "$STEERING_DIRECTIVE" | $AI_CMD 2>&1 | tee /dev/stderr) || true
952
+
953
+ # Validate and recover from malformed JSON
954
+ if ! validate_and_recover "$STATE_FILE" || ! validate_and_recover "$PLAN_FILE"; then
955
+ run_synthesis_pass "corruption"
956
+ exit 1
957
+ fi
958
+
959
+ # Increment iteration counter
960
+ ITER_TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
961
+ jq --arg ts "$ITER_TS" '.iteration += 1 | .last_updated = $ts' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
962
+
963
+ # Check for phase transition
964
+ NEW_PHASE=$(determine_phase "$STATE_FILE" "$PLAN_FILE")
965
+ CURRENT_PHASE=$(jq -r '.phase' "$STATE_FILE")
966
+ if [ "$NEW_PHASE" != "$CURRENT_PHASE" ]; then
967
+ echo " Phase transition: $CURRENT_PHASE -> $NEW_PHASE"
968
+ jq --arg phase "$NEW_PHASE" '.phase = $phase' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
969
+ fi
970
+
971
+ # Update convergence metrics
972
+ update_convergence_metrics "$STATE_FILE" "$PLAN_FILE"
973
+
974
+ # Compute trust scores from source tracking data
975
+ compute_trust_scores "$PLAN_FILE"
976
+
977
+ # Check for diminishing returns
978
+ DR_RESULT=$(detect_diminishing_returns "$STATE_FILE")
979
+ case "$DR_RESULT" in
980
+ strategy_change)
981
+ echo " Diminishing returns detected. Advancing to synthesize phase."
982
+ jq '.phase = "synthesize"' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
983
+ ;;
984
+ synthesize_now)
985
+ echo " Research plateaued. Running synthesis."
986
+ run_synthesis_pass "converged"
987
+ exit 0
988
+ ;;
989
+ esac
990
+
991
+ # Check for convergence
992
+ if check_convergence "$STATE_FILE"; then
993
+ echo " Research converged."
994
+ run_synthesis_pass "converged"
995
+ exit 0
996
+ fi
997
+
998
+ # Regenerate research-plan.md from current state
999
+ generate_research_plan
1000
+
1001
+ # Check for AI completion signal
1002
+ if echo "$OUTPUT" | grep -q "<oracle>COMPLETE</oracle>"; then
1003
+ echo ""
1004
+ echo "==============================================================="
1005
+ echo " ORACLE RESEARCH COMPLETE!"
1006
+ echo "==============================================================="
1007
+ echo "Completed at iteration $i"
1008
+ run_synthesis_pass "converged"
1009
+ exit 0
1010
+ fi
1011
+
1012
+ echo ""
1013
+ echo "Iteration $i complete. Continuing..."
1014
+ sleep 2
1015
+ done
1016
+
1017
+ echo ""
1018
+ echo "==============================================================="
1019
+ echo " ORACLE REACHED MAX ITERATIONS"
1020
+ echo "==============================================================="
1021
+ echo "Max iterations ($MAX_ITERATIONS) reached."
1022
+ run_synthesis_pass "max_iterations"
1023
+ exit 0