eagle-mem 4.10.13 → 4.12.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 (74) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +22 -22
  3. package/architecture.html +26 -14
  4. package/bin/eagle-mem +4 -0
  5. package/db/039_recall_events.sql +27 -0
  6. package/db/040_graph_decision_nodes.sql +21 -0
  7. package/db/041_graph_semantic_edge_types.sql +21 -0
  8. package/db/042_orchestration_auto_events.sql +23 -0
  9. package/db/043_eagle_events.sql +22 -0
  10. package/db/044_summary_capture_source.sql +12 -0
  11. package/docs/agent-compatibility/README.md +38 -0
  12. package/docs/agent-compatibility/claude-code.md +58 -0
  13. package/docs/agent-compatibility/codex.md +57 -0
  14. package/docs/agent-compatibility/opencode.md +72 -0
  15. package/hooks/post-tool-use.sh +8 -0
  16. package/hooks/pre-tool-use.sh +10 -1
  17. package/hooks/session-end.sh +3 -0
  18. package/hooks/session-start.sh +15 -17
  19. package/hooks/stop.sh +34 -5
  20. package/hooks/user-prompt-submit.sh +85 -10
  21. package/integrations/opencode_eagle_mem_plugin.js +387 -0
  22. package/lib/codex-hooks.sh +13 -6
  23. package/lib/common.sh +77 -7
  24. package/lib/db-events.sh +89 -0
  25. package/lib/db-graph.sh +154 -0
  26. package/lib/db-observations.sh +34 -0
  27. package/lib/db-orchestration.sh +149 -0
  28. package/lib/db-summaries.sh +70 -3
  29. package/lib/db.sh +2 -0
  30. package/lib/hooks.sh +41 -7
  31. package/lib/opencode-hooks.sh +105 -0
  32. package/lib/provider.sh +2 -2
  33. package/package.json +5 -2
  34. package/scripts/compaction.sh +109 -9
  35. package/scripts/dashboard.sh +372 -0
  36. package/scripts/doctor.sh +30 -3
  37. package/scripts/enrich-summary.sh +8 -2
  38. package/scripts/health.sh +40 -2
  39. package/scripts/help.sh +10 -2
  40. package/scripts/inspect.sh +285 -0
  41. package/scripts/install.sh +36 -7
  42. package/scripts/memories.sh +13 -0
  43. package/scripts/repair.sh +187 -0
  44. package/scripts/replay.sh +248 -0
  45. package/scripts/search.sh +44 -3
  46. package/scripts/session.sh +155 -18
  47. package/scripts/statusline-em.sh +34 -7
  48. package/scripts/tasks.sh +34 -0
  49. package/scripts/test.sh +13 -0
  50. package/scripts/uninstall.sh +9 -0
  51. package/scripts/update.sh +21 -2
  52. package/tests/fixtures/agent-hooks/claude-statusline.json +32 -0
  53. package/tests/fixtures/agent-hooks/claude-user-prompt-submit.json +9 -0
  54. package/tests/fixtures/agent-hooks/codex-pre-tool-use.json +10 -0
  55. package/tests/fixtures/agent-hooks/codex-user-prompt-submit.json +7 -0
  56. package/tests/fixtures/agent-hooks/opencode-chat-message.json +36 -0
  57. package/tests/fixtures/agent-hooks/opencode-session-compacting.json +9 -0
  58. package/tests/fixtures/agent-hooks/opencode-todo-updated.json +13 -0
  59. package/tests/fixtures/agent-hooks/opencode-tool-execute-after.json +15 -0
  60. package/tests/fixtures/agent-hooks/opencode-tool-execute-before.json +12 -0
  61. package/tests/test_agent_compatibility_docs_gate.sh +123 -0
  62. package/tests/test_auto_orchestration_detection.sh +109 -0
  63. package/tests/test_claude_stop_hook_registration.sh +56 -0
  64. package/tests/test_clean_session_capture.sh +105 -0
  65. package/tests/test_codex_hooks_config.sh +73 -0
  66. package/tests/test_compaction_survival_matrix.sh +237 -0
  67. package/tests/test_dashboard.sh +96 -0
  68. package/tests/test_eagle_events.sh +96 -0
  69. package/tests/test_opencode_hooks_config.sh +56 -0
  70. package/tests/test_opencode_plugin_adapter.sh +202 -0
  71. package/tests/test_recall_observability.sh +144 -0
  72. package/tests/test_repair.sh +63 -0
  73. package/tests/test_rust_migration_plan.sh +75 -0
  74. package/tests/test_trust_surfaces.sh +123 -0
@@ -0,0 +1,57 @@
1
+ # Codex Compatibility
2
+
3
+ Last verified: 2026-06-10
4
+
5
+ ## Official Sources
6
+
7
+ - Codex manual: https://developers.openai.com/codex/codex-manual.md
8
+ - Hooks reference: https://developers.openai.com/codex/hooks.md
9
+ - AGENTS.md reference: https://developers.openai.com/codex/guides/agents-md.md
10
+ - Advanced config reference: https://developers.openai.com/codex/config-advanced.md
11
+ - Memories reference: https://developers.openai.com/codex/memories.md
12
+
13
+ ## Behavior Relied On
14
+
15
+ - `AGENTS.md` is the durable repo-instruction surface for Codex. Closer nested files override earlier guidance because Codex concatenates instruction files from the project root down to the current working directory.
16
+ - Codex hooks are discovered from active config layers through `hooks.json` or inline `[hooks]` tables in `config.toml`.
17
+ - `features.hooks` is the canonical feature key. `features.codex_hooks` is a deprecated alias and should not be the primary setting.
18
+ - `SessionStart`, `PreToolUse`, `PostToolUse`, `PreCompact`, `PostCompact`, `UserPromptSubmit`, `SubagentStop`, and `Stop` run at the documented lifecycle scopes.
19
+ - `SessionStart` matchers use `startup`, `resume`, `clear`, and `compact`.
20
+ - `PreToolUse` and `PostToolUse` match tool names, including `Bash`, `apply_patch`, MCP tool names, and aliases such as `Edit` and `Write` for `apply_patch`.
21
+ - `UserPromptSubmit` and `Stop` do not support matchers; configured matchers are ignored for those events.
22
+ - Hook `timeout` is measured in seconds; `statusMessage` is optional.
23
+ - Codex memory files are generated state. Required team guidance belongs in `AGENTS.md` or checked-in documentation, not only in local memories.
24
+
25
+ ## Session Capture Behavior
26
+
27
+ - Codex replies stay prose-only; Eagle Mem never asks Codex to print summary blocks, XML, or hook payloads. The `Stop` hook captures a summary from the Codex rollout transcript automatically.
28
+ - For a richer structured capture, Codex may run `eagle-mem session save --session-id <session_id> --agent codex ...` once at wrap-up (injected by `SessionStart` and the `AGENTS.md` section). This sets `capture_source = agent`, which is authoritative: later Stop-hook heuristics only fill empty fields and background enrichment is skipped, so the capture is never clobbered.
29
+ - Modified-file lists are most reliable when Codex passes `--files-modified` explicitly; the transcript heuristic is Claude-shaped and may not populate file lists from Codex rollout tool calls.
30
+
31
+ ## Eagle Mem Files Depending On This
32
+
33
+ - `lib/codex-hooks.sh`
34
+ - `lib/provider.sh`
35
+ - `scripts/install.sh`
36
+ - `scripts/update.sh`
37
+ - `scripts/uninstall.sh`
38
+ - `hooks/session-start.sh`
39
+ - `hooks/user-prompt-submit.sh`
40
+ - `hooks/pre-tool-use.sh`
41
+ - `hooks/post-tool-use.sh`
42
+ - `hooks/stop.sh`
43
+ - `AGENTS.md`
44
+
45
+ ## Fixtures And Tests
46
+
47
+ - `tests/fixtures/agent-hooks/codex-user-prompt-submit.json`
48
+ - `tests/fixtures/agent-hooks/codex-pre-tool-use.json`
49
+ - `tests/test_agent_compatibility_docs_gate.sh`
50
+ - `tests/test_codex_hooks_config.sh`
51
+ - `tests/test_auto_orchestration_detection.sh`
52
+ - `tests/test_recall_observability.sh`
53
+ - `tests/test_trust_surfaces.sh`
54
+
55
+ ## Reverification Notes
56
+
57
+ When editing Codex hooks or install/update behavior, update this file with the new verification date and source URLs. If a future Codex version changes hook feature flags, matcher support, trust review, event names, or input/output schema, update fixtures first and then implementation.
@@ -0,0 +1,72 @@
1
+ # OpenCode Compatibility
2
+
3
+ Last verified: 2026-06-10
4
+
5
+ ## Official Sources
6
+
7
+ - Plugins reference: https://opencode.ai/docs/plugins/
8
+ - Config reference: https://opencode.ai/docs/config/
9
+ - Config schema: https://opencode.ai/config.json
10
+
11
+ ## Installed Surface Verified Locally
12
+
13
+ - OpenCode CLI: `opencode --version` reported `1.14.24`.
14
+ - OpenCode plugin package: `@opencode-ai/plugin@1.14.24`.
15
+ - Resolved config path: `~/.config/opencode/opencode.json`.
16
+ - Global plugin directory: `~/.config/opencode/plugins/`.
17
+
18
+ ## Behavior Relied On
19
+
20
+ - OpenCode local plugins are JavaScript or TypeScript modules placed in `.opencode/plugins/` for project scope or `~/.config/opencode/plugins/` for global scope.
21
+ - Files in those plugin directories are loaded automatically at startup.
22
+ - NPM plugins are declared with the top-level `plugin` array in `opencode.json`, but Eagle Mem uses the global local-plugin directory so it does not need to mutate the user plugin array.
23
+ - Plugin functions receive a context object with `project`, `directory`, `worktree`, `client`, and `$`, then return a hooks object.
24
+ - The plugin event bus includes `session.created`, `session.updated`, `session.idle`, `session.compacted`, `session.deleted`, `message.updated`, `message.part.updated`, and `todo.updated`.
25
+ - Direct hook keys include `chat.message`, `tool.execute.before`, `tool.execute.after`, `shell.env`, and `experimental.session.compacting`.
26
+ - `tool.execute.before` can deny a tool call by throwing an error and can mutate `output.args` before execution.
27
+ - `tool.execute.after` receives tool output fields that can be annotated for the model.
28
+ - `experimental.session.compacting` fires before compaction and can push additional strings into `output.context`.
29
+ - `opencode --pure` runs without external plugins; doctor checks should report that Eagle Mem OpenCode support depends on non-pure OpenCode sessions.
30
+
31
+ ## Eagle Mem Mapping
32
+
33
+ - `chat.message` maps to Eagle Mem `SessionStart` once per session and `UserPromptSubmit` on each user message.
34
+ - `tool.execute.before` maps to Eagle Mem `PreToolUse`; denial becomes a thrown OpenCode plugin error and `updatedInput` mutates `output.args`.
35
+ - `tool.execute.after` maps to Eagle Mem `PostToolUse`; additional context is appended to the tool output so the agent can see guardrail or stale-memory hints.
36
+ - `todo.updated` maps OpenCode todos into Eagle Mem task records through synthetic `TaskCreated` and `TaskUpdate` hook payloads.
37
+ - `session.idle` maps to Eagle Mem `Stop` using the latest assistant text accumulated from message events.
38
+ - `session.deleted` maps to Eagle Mem `SessionEnd`.
39
+ - `experimental.session.compacting` maps to Eagle Mem compact recall by running `SessionStart` with `source=compact` and appending the returned context.
40
+ - Session capture follows the shared clean-capture flow: the agent may run `eagle-mem session save --session-id <id> ...` at wrap-up (sets `capture_source = agent`, authoritative) and keep replies prose-only. The `session.idle` → `Stop` path then only fills gaps and never clobbers an agent-authored row.
41
+
42
+ ## Eagle Mem Files Depending On This
43
+
44
+ - `integrations/opencode_eagle_mem_plugin.js`
45
+ - `lib/opencode-hooks.sh`
46
+ - `lib/common.sh`
47
+ - `scripts/install.sh`
48
+ - `scripts/update.sh`
49
+ - `scripts/uninstall.sh`
50
+ - `scripts/doctor.sh`
51
+ - `scripts/test.sh`
52
+ - `hooks/session-start.sh`
53
+ - `hooks/user-prompt-submit.sh`
54
+ - `hooks/pre-tool-use.sh`
55
+ - `hooks/post-tool-use.sh`
56
+ - `hooks/stop.sh`
57
+ - `hooks/session-end.sh`
58
+
59
+ ## Fixtures And Tests
60
+
61
+ - `tests/fixtures/agent-hooks/opencode-chat-message.json`
62
+ - `tests/fixtures/agent-hooks/opencode-tool-execute-before.json`
63
+ - `tests/fixtures/agent-hooks/opencode-tool-execute-after.json`
64
+ - `tests/fixtures/agent-hooks/opencode-todo-updated.json`
65
+ - `tests/fixtures/agent-hooks/opencode-session-compacting.json`
66
+ - `tests/test_agent_compatibility_docs_gate.sh`
67
+ - `tests/test_opencode_hooks_config.sh`
68
+ - `tests/test_opencode_plugin_adapter.sh`
69
+
70
+ ## Reverification Notes
71
+
72
+ When editing OpenCode support, re-read the plugins and config docs first. If OpenCode changes plugin load order, local plugin directories, hook names, `tool.execute.*` mutation semantics, `chat.message` payloads, or compaction hooks, update these fixtures before implementation.
@@ -122,6 +122,7 @@ esac
122
122
 
123
123
  project=$(eagle_project_from_hook_input "$input")
124
124
  [ -z "$project" ] && exit 0
125
+ eagle_hook_observability_begin "$input" "PostToolUse"
125
126
 
126
127
  # Ensure session row exists before inserting observations (FK constraint).
127
128
  # PostToolUse can race SessionStart — the session row might not exist yet.
@@ -249,5 +250,12 @@ eagle_posttool_decision_surface "$tool_name" "$fp" "$project" "$agent"
249
250
  if ! eagle_insert_observation "$session_id" "$project" "$tool_name" "$tool_summary" "$files_read" "$files_modified" "$output_bytes" "$output_lines" "$command_category" "$agent"; then
250
251
  eagle_log "ERROR" "PostToolUse: observation insert failed for session=$session_id tool=$tool_name"
251
252
  fi
253
+ eagle_hook_observability_set_detail "$(jq -nc \
254
+ --arg tool "$tool_name" \
255
+ --arg summary "$tool_summary" \
256
+ --arg files_read "$files_read" \
257
+ --arg files_modified "$files_modified" \
258
+ '{tool_name:$tool, summary:$summary, files_read:($files_read | fromjson? // []), files_modified:($files_modified | fromjson? // [])}')"
259
+ eagle_hook_observability_complete 0
252
260
 
253
261
  exit 0
@@ -33,6 +33,7 @@ esac
33
33
  [ ! -f "$EAGLE_MEM_DB" ] && exit 0
34
34
  project=$(eagle_project_from_hook_input "$input")
35
35
  [ -z "$project" ] && exit 0
36
+ eagle_hook_observability_begin "$input" "PreToolUse"
36
37
 
37
38
  context=""
38
39
  updated_input=""
@@ -382,15 +383,23 @@ Use the existing context, run a narrower search, or bypass once with:
382
383
  ;;
383
384
  esac
384
385
 
385
- [ -z "$context" ] && [ -z "$updated_input" ] && exit 0
386
+ if [ -z "$context" ] && [ -z "$updated_input" ]; then
387
+ eagle_hook_observability_set_detail "$(jq -nc --arg tool "$tool_name" --arg action "no_action" '{tool_name:$tool, action:$action}')"
388
+ eagle_hook_observability_complete 0
389
+ exit 0
390
+ fi
386
391
 
387
392
  # Codex PreToolUse now natively receives both blocking decisions and advisory context.
388
393
  # Removing the old early-exit to align Codex's pre-tool capabilities with Claude and Antigravity.
389
394
 
390
395
  if [ -n "$updated_input" ]; then
396
+ eagle_hook_observability_set_detail "$(jq -nc --arg tool "$tool_name" --arg action "updated_input" '{tool_name:$tool, action:$action}')"
397
+ eagle_hook_observability_complete 0
391
398
  jq -nc --arg ctx "$context" --argjson ui "$updated_input" \
392
399
  '{"hookSpecificOutput":{"hookEventName":"PreToolUse","updatedInput":$ui,"additionalContext":$ctx}}'
393
400
  else
401
+ eagle_hook_observability_set_detail "$(jq -nc --arg tool "$tool_name" --arg action "additional_context" '{tool_name:$tool, action:$action}')"
402
+ eagle_hook_observability_complete 0
394
403
  jq -nc --arg ctx "$context" '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":$ctx}}'
395
404
  fi
396
405
 
@@ -24,6 +24,7 @@ agent=$(eagle_agent_source_from_json "$input")
24
24
  cwd=$(echo "$input" | jq -r '.cwd // empty')
25
25
  project=$(eagle_project_from_hook_input "$input")
26
26
  [ -z "$project" ] && exit 0
27
+ eagle_hook_observability_begin "$input" "SessionEnd"
27
28
 
28
29
  # Final sweep: re-capture all task files to catch status changes
29
30
  # Claude Code may update task status without triggering PostToolUse
@@ -40,6 +41,8 @@ fi
40
41
 
41
42
  eagle_end_session "$session_id"
42
43
  eagle_log "INFO" "SessionEnd: session=$session_id marked completed"
44
+ eagle_hook_observability_set_detail "$(jq -nc --arg action "session_completed" '{action:$action}')"
45
+ eagle_hook_observability_complete 0
43
46
 
44
47
  # Prune observations older than 90 days (keeps DB size bounded)
45
48
  eagle_prune_observations 90 "$project"
@@ -35,6 +35,7 @@ codex_compact=0
35
35
 
36
36
  project=$(eagle_project_from_hook_input "$input")
37
37
  [ -z "$project" ] && exit 0
38
+ eagle_hook_observability_begin "$input" "SessionStart"
38
39
 
39
40
  p_esc=$(eagle_sql_escape "$project")
40
41
  recall_scope=$(eagle_recall_project_scope_from_cwd "$cwd" "$project")
@@ -624,38 +625,35 @@ fi
624
625
  if [ "$agent" = "codex" ]; then
625
626
  context+="
626
627
  === Eagle Mem: Active ===
627
- Memory active for '$project'. Keep user-facing Codex replies clean: do not print Eagle Mem summary capture blocks, XML, JSON hook payloads, or internal templates unless the user explicitly asks. The Stop hook captures summaries from the transcript automatically.
628
+ Memory active for '$project'. Keep user-facing Codex replies clean: do not print Eagle Mem summary capture blocks, XML, JSON hook payloads, or internal templates unless the user explicitly asks. The Stop hook captures summaries from the transcript automatically. When you wrap up substantive work, you may persist a richer structured capture by running once: eagle-mem session save --session-id $session_id --agent codex --completed \"...\" --decisions \"choice — why\" --gotchas \"...\" --files-modified \"a.ts,b.ts\" (fill what applies). Keep the visible reply prose-only.
628
629
  "
629
630
  elif [ "$source_type" = "compact" ] || [ "$source_type" = "clear" ]; then
630
631
  context+="
631
632
  === Eagle Mem: Active ===
632
- Memory active. Attribute recalled context to Eagle Mem. Do not revert PostToolUse-surfaced decisions without asking. Emit <eagle-summary> before final response.
633
+ Memory active. Attribute recalled context to Eagle Mem. Do not revert PostToolUse-surfaced decisions without asking. Before your final response, capture the session quietly via the Bash tool (pre-approved): eagle-mem session save --session-id $session_id --completed \"...\" --decisions \"choice — why\" --gotchas \"...\" (fill what applies, omit the rest). Then give a short human recap — NEVER print <eagle-summary> tags or raw field lists.
633
634
  "
634
635
  else
635
636
  context+="
636
637
  === Eagle Mem: Active ===
637
638
  Memory active for '$project'. Scan, index, prune, and self-learning run automatically — never ask the user to run these. Attribute recalled context: \"Eagle Mem recalls:\" Do not revert PostToolUse-surfaced decisions without user request. No raw secrets in summaries. If you contradict a loaded memory, update the memory file.
638
639
 
639
- Before your final response, emit:
640
- <eagle-summary>
641
- request: [what user asked]
642
- completed: [what shipped]
643
- learned: [non-obvious discoveries]
644
- decisions: [choicewhy]
645
- gotchas: [what surprised]
646
- next_steps: [concrete actions]
647
- key_files: [path — role]
648
- files_read: [path, ...]
649
- files_modified: [path, ...]
650
- affected_features: [feature, ...]
651
- verified_features: [feature, ...]
652
- regression_risks: [risk, ...]
653
- </eagle-summary>
640
+ Session capture is clean: NEVER print <eagle-summary> tags, XML, or raw field lists (request:/completed:/...) in your visible reply. When you wrap up substantive work (shipped a change, made decisions worth remembering, the user signals done, or Eagle Mem warns of context pressure), capture it by running this ONCE via the Bash tool — it is pre-approved and prints only a short confirmation. Fill the flags you have; omit the rest:
641
+
642
+ eagle-mem session save --session-id $session_id --request \"...\" --completed \"...\" --learned \"...\" --decisions \"choice — why; choice — why\" --gotchas \"...\" --next-steps \"...\" --key-files \"path — role\" --files-modified \"a.ts,b.ts\" --affected-features \"...\" --verified-features \"...\" --regression-risks \"...\"
643
+
644
+ Then end with a brief, human recap of the session in prose, followed by one line:
645
+ **Eagle Mem** | Session captured N decisions, M gotchas
654
646
  "
655
647
  fi
656
648
 
657
649
  if [ -n "$context" ]; then
650
+ eagle_hook_observability_set_detail "$(jq -nc \
651
+ --arg source_type "$source_type" \
652
+ --arg recall_scope "$recall_scope" \
653
+ --argjson injected_chars "${#context}" \
654
+ '{source_type:$source_type, recall_scope:$recall_scope, injected_chars:$injected_chars}')"
658
655
  eagle_emit_context_for_agent "$agent" "SessionStart" "$context"
659
656
  fi
657
+ eagle_hook_observability_complete 0
660
658
 
661
659
  exit 0
package/hooks/stop.sh CHANGED
@@ -31,6 +31,7 @@ agent=$(eagle_agent_source_from_json "$input")
31
31
 
32
32
  project=$(eagle_project_from_hook_input "$input")
33
33
  [ -z "$project" ] && exit 0
34
+ eagle_hook_observability_begin "$input" "Stop"
34
35
 
35
36
  eagle_log "INFO" "Stop: session=$session_id project=$project transcript=$transcript_path agent=$agent"
36
37
 
@@ -237,7 +238,7 @@ if [ "$needs_enrichment" -eq 1 ]; then
237
238
  # lifecycle timeouts and make the hook look broken to users.
238
239
  if [ "${EAGLE_MEM_STOP_ENRICH:-0}" != "1" ]; then
239
240
  defer_enrichment=1
240
- eagle_log "INFO" "Stop: LLM enrichment skipped fast hook path (provider=$provider)"
241
+ eagle_log "INFO" "Stop: LLM enrichment skipped on fast hook path; provider=$provider"
241
242
  elif [ "$provider" != "none" ] && [ -n "$text_content" ]; then
242
243
  excerpt=$(echo "$text_content" | tail -c 3000)
243
244
 
@@ -395,16 +396,44 @@ if [ -n "$regression_notes" ]; then
395
396
  fi
396
397
 
397
398
  # ─── Write to database ─────────────────────────────────────
399
+ #
400
+ # Capture-source precedence:
401
+ # - A parsed <eagle-summary> block this turn is agent-authored → write 'agent'.
402
+ # - An existing 'agent' row (CLI `eagle-mem session save` or an earlier block)
403
+ # is authoritative → fill empty gaps only, never overwrite with heuristics.
404
+ # - Otherwise this is a heuristic capture → normal 'hook' write.
405
+ # agent_authored also gates background enrichment so it can't clobber later.
406
+
407
+ existing_source=$(eagle_summary_capture_source "$session_id" 2>/dev/null || true)
408
+ agent_authored=0
409
+ [ -n "$summary_block" ] && agent_authored=1
410
+ [ "$existing_source" = "agent" ] && agent_authored=1
398
411
 
399
412
  if [ -n "$request" ] || [ -n "$completed" ] || [ -n "$learned" ]; then
400
- if eagle_insert_summary "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes" "$decisions" "$gotchas" "$key_files" "$agent"; then
401
- eagle_log "INFO" "Stop: summary saved for session=$session_id"
413
+ write_rc=0
414
+ if [ -n "$summary_block" ]; then
415
+ eagle_insert_summary "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes" "$decisions" "$gotchas" "$key_files" "$agent" "agent" || write_rc=$?
416
+ elif [ "$existing_source" = "agent" ]; then
417
+ eagle_insert_summary_fill_only "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes" "$decisions" "$gotchas" "$key_files" "$agent" "hook" || write_rc=$?
418
+ else
419
+ eagle_insert_summary "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes" "$decisions" "$gotchas" "$key_files" "$agent" "hook" || write_rc=$?
420
+ fi
421
+ if [ "$write_rc" -eq 0 ]; then
422
+ eagle_log "INFO" "Stop: summary saved for session=$session_id (prior_source=${existing_source:-none}, block=$([ -n "$summary_block" ] && echo yes || echo no))"
423
+ eagle_insert_event "$project" "$session_id" "$agent" "memory_created" "" "Stop" "ok" "$(jq -nc --arg source "summary" '{source:$source}')" >/dev/null 2>&1 || true
402
424
  else
403
425
  eagle_log "ERROR" "Stop: summary insert FAILED for session=$session_id — check DB constraints"
404
426
  fi
405
427
  fi
406
-
407
- if [ "$defer_enrichment" -eq 1 ] && [ "${EAGLE_MEM_STOP_BACKGROUND_ENRICH:-1}" = "1" ] && [ -n "$text_content" ]; then
428
+ eagle_hook_observability_set_detail "$(jq -nc \
429
+ --argjson files_read "$files_read" \
430
+ --argjson files_modified "$files_modified" \
431
+ --arg request "$request" \
432
+ --arg completed "$completed" \
433
+ '{request_chars:($request | length), completed_chars:($completed | length), files_read:$files_read, files_modified:$files_modified}')"
434
+ eagle_hook_observability_complete 0
435
+
436
+ if [ "$defer_enrichment" -eq 1 ] && [ "${EAGLE_MEM_STOP_BACKGROUND_ENRICH:-1}" = "1" ] && [ -n "$text_content" ] && [ "$agent_authored" -eq 0 ]; then
408
437
  mkdir -p "$EAGLE_MEM_DIR/tmp" 2>/dev/null || true
409
438
  enrich_job=$(mktemp "$EAGLE_MEM_DIR/tmp/summary-enrich.XXXXXX.json" 2>/dev/null)
410
439
  if [ -n "$enrich_job" ]; then
@@ -30,11 +30,22 @@ recall_scope=$(eagle_recall_project_scope_from_cwd "$cwd" "$project")
30
30
  [ -z "$recall_scope" ] && recall_scope="$project"
31
31
  codex_compact=0
32
32
  [ "$agent" = "codex" ] && codex_compact=1
33
+ eagle_hook_observability_begin "$input" "UserPromptSubmit"
33
34
 
34
35
  # ─── Context pressure detection (turn counter since last compact) ──
35
36
  # Must run before any early exits so every prompt is counted
36
37
 
37
38
  context=""
39
+ summary_matches=0
40
+ memory_matches=0
41
+ code_matches=0
42
+ summary_refs="[]"
43
+ memory_refs="[]"
44
+ code_refs="[]"
45
+
46
+ count_pipe_rows() {
47
+ awk -F'|' '($1 != "" || $2 != "") { c++ } END { print c + 0 }'
48
+ }
38
49
 
39
50
  if [ -n "$session_id" ] && eagle_validate_session_id "$session_id"; then
40
51
  counter_file="$EAGLE_MEM_DIR/.turn-counter.${session_id}"
@@ -56,8 +67,9 @@ Eagle Mem context pressure: critical ($turn_count turns since compact)
56
67
  else
57
68
  context+="
58
69
  === Eagle Mem: Context Pressure Critical ($turn_count turns since compact) ===
59
- IMMEDIATELY emit a detailed <eagle-summary> covering ALL work this session.
60
- Tell the user to run /compact NOW to avoid losing context.
70
+ IMMEDIATELY capture ALL work this session by running (pre-approved, quiet):
71
+ eagle-mem session save --session-id $session_id --completed \"...\" --decisions \"choice why\" --gotchas \"...\" --learned \"...\" --next-steps \"...\" --key-files \"path — role\"
72
+ Then tell the user to run /compact NOW. Do NOT print <eagle-summary> tags or raw field lists.
61
73
  "
62
74
  fi
63
75
  echo "$turn_count" > "$EAGLE_MEM_DIR/.context-pressure"
@@ -72,8 +84,9 @@ Eagle Mem context pressure: high ($turn_count turns since compact)
72
84
  else
73
85
  context+="
74
86
  === Eagle Mem: Context Pressure High ($turn_count turns since compact) ===
75
- Include a thorough <eagle-summary> in your next response capture all decisions, gotchas, and learned context before compaction.
76
- Suggest the user run /compact to free context for continued work.
87
+ Capture your work before compaction by running (pre-approved, quiet):
88
+ eagle-mem session save --session-id $session_id --completed \"...\" --decisions \"choice why\" --gotchas \"...\" --learned \"...\"
89
+ Then suggest the user run /compact. Do NOT print <eagle-summary> tags or raw field lists.
77
90
  "
78
91
  fi
79
92
  echo "$turn_count" > "$EAGLE_MEM_DIR/.context-pressure"
@@ -85,6 +98,9 @@ fi
85
98
  # Skip short prompts — not enough signal for meaningful search
86
99
  word_count=$(echo "$user_prompt" | wc -w | tr -d ' ')
87
100
  if [ "$word_count" -lt 3 ]; then
101
+ eagle_insert_recall_event "$session_id" "$recall_scope" "$cwd" "$agent" "$user_prompt" "" 0 0 0 "${#context}" "skipped_short_prompt" "" >/dev/null 2>&1 || true
102
+ eagle_hook_observability_set_detail "$(jq -nc --arg recall_status "skipped_short_prompt" --argjson injected_chars "${#context}" '{recall_status:$recall_status, injected_chars:$injected_chars}')"
103
+ eagle_hook_observability_complete 0
88
104
  eagle_emit_context_for_agent "$agent" "UserPromptSubmit" "$context"
89
105
  exit 0
90
106
  fi
@@ -105,6 +121,9 @@ fts_query=$(echo "$user_prompt" | tr -cs '[:alnum:]' ' ' | tr '[:upper:]' '[:low
105
121
  }')
106
122
 
107
123
  if [ -z "$fts_query" ]; then
124
+ eagle_insert_recall_event "$session_id" "$recall_scope" "$cwd" "$agent" "$user_prompt" "" 0 0 0 "${#context}" "skipped_no_query" "" >/dev/null 2>&1 || true
125
+ eagle_hook_observability_set_detail "$(jq -nc --arg recall_status "skipped_no_query" --argjson injected_chars "${#context}" '{recall_status:$recall_status, injected_chars:$injected_chars}')"
126
+ eagle_hook_observability_complete 0
108
127
  eagle_emit_context_for_agent "$agent" "UserPromptSubmit" "$context"
109
128
  exit 0
110
129
  fi
@@ -113,19 +132,27 @@ fi
113
132
 
114
133
  lower_prompt=$(printf '%s' "$user_prompt" | tr '[:upper:]' '[:lower:]')
115
134
  if printf '%s\n' "$lower_prompt" | grep -Eq '(orchestrat|worker|parallel|multi-agent|multi agent|split|lane|scope out|plan and get started|broad|full codebase|release|publish|ship)'; then
135
+ auto_orchestration=$(eagle_auto_orchestrate_from_prompt "$project" "$session_id" "$agent" "$user_prompt" "$cwd" "broad_prompt" 2>/dev/null || true)
136
+ if [ -n "$auto_orchestration" ]; then
137
+ IFS='|' read -r auto_name auto_id auto_lane_count _auto_lanes_json <<< "$auto_orchestration"
138
+ context+="
139
+ Eagle Mem orchestration: detected broad work and created durable orchestration '$auto_name' with $auto_lane_count lanes.
140
+ - Inspect it with: eagle-mem orchestrate --name $auto_name
141
+ - Lanes already exist as durable tasks; update them instead of relying on memory alone.
142
+ "
143
+ fi
116
144
  if [ "$codex_compact" -eq 1 ]; then
117
145
  context+="
118
146
  Eagle Mem orchestration:
119
- - For broad work, you run eagle-mem orchestrate yourself.
120
- - Use durable lanes, opposite-agent workers, and concise user-visible status.
147
+ - Continue from the durable lanes Eagle already created.
148
+ - Keep lane/task status current as work progresses.
121
149
  "
122
150
  else
123
151
  context+="=== Eagle Mem: Orchestration Protocol ===
124
- If this request is broad enough to split into worker lanes, YOU run the orchestration commands. Do not ask the user to run them.
152
+ Eagle has already detected broad work and registered durable orchestration state.
125
153
 
126
154
  Use:
127
- eagle-mem orchestrate init \"<goal>\"
128
- eagle-mem orchestrate lane add <key> --agent codex|claude-code --desc \"<self-contained scope>\" --validate \"<command>\"
155
+ eagle-mem orchestrate --name auto
129
156
  eagle-mem orchestrate lane start|block|complete <key>
130
157
 
131
158
  Keep this mostly invisible to the user; surface only concise status or handoff when useful.
@@ -146,6 +173,8 @@ memory_limit=3
146
173
 
147
174
  results=$(eagle_search_summaries "$fts_query" "$recall_scope" "$summary_limit")
148
175
  memory_results=$(eagle_search_agent_memories "$fts_query" "$recall_scope" "$memory_limit" 2>/dev/null || true)
176
+ summary_matches=$(printf '%s\n' "$results" | count_pipe_rows)
177
+ memory_matches=$(printf '%s\n' "$memory_results" | count_pipe_rows)
149
178
 
150
179
  if [ -n "$results" ] || [ -n "$memory_results" ]; then
151
180
  if [ "$codex_compact" -eq 1 ]; then
@@ -195,6 +224,13 @@ Eagle Mem recalls:
195
224
  context+="
196
225
  "
197
226
  fi
227
+ summary_refs=$(printf '%s' "$summary_refs" | jq -c \
228
+ --arg created_at "$created_at" \
229
+ --arg agent "$summary_agent" \
230
+ --arg request "$req" \
231
+ --arg completed "$completed" \
232
+ --arg learned "$learned" \
233
+ '. + [{created_at:$created_at, agent:$agent, request:$request, completed:$completed, learned:$learned}]' 2>/dev/null || printf '[]')
198
234
  done <<< "$results"
199
235
 
200
236
  while IFS='|' read -r mname mtype mdesc msnippet _mfile _mupdated morigin; do
@@ -219,6 +255,12 @@ Eagle Mem recalls:
219
255
  context+="
220
256
  "
221
257
  fi
258
+ memory_refs=$(printf '%s' "$memory_refs" | jq -c \
259
+ --arg name "$mname" \
260
+ --arg type "$mtype" \
261
+ --arg description "$mdesc" \
262
+ --arg agent "$morigin" \
263
+ '. + [{name:$name, type:$type, description:$description, agent:$agent}]' 2>/dev/null || printf '[]')
222
264
  done <<< "$memory_results"
223
265
  fi
224
266
 
@@ -226,6 +268,7 @@ fi
226
268
  has_chunks=$(eagle_count_code_chunks "$project")
227
269
  if [ "${has_chunks:-0}" -gt 0 ]; then
228
270
  code_results=$(eagle_search_code_chunks "$fts_query" "$project" "$code_limit")
271
+ code_matches=$(printf '%s\n' "$code_results" | count_pipe_rows)
229
272
 
230
273
  if [ -n "$code_results" ]; then
231
274
  if [ "$codex_compact" -eq 1 ]; then
@@ -246,11 +289,27 @@ Relevant code:
246
289
  [ -n "$lang" ] && context+=" ($lang)"
247
290
  context+="
248
291
  "
292
+ code_refs=$(printf '%s' "$code_refs" | jq -c \
293
+ --arg file "$fpath" \
294
+ --arg start_line "$sline" \
295
+ --arg end_line "$eline" \
296
+ --arg language "$lang" \
297
+ '. + [{file:$file, start_line:$start_line, end_line:$end_line, language:$language}]' 2>/dev/null || printf '[]')
249
298
  done <<< "$code_results"
250
299
  fi
251
300
  fi
252
301
 
253
- [ -z "$context" ] && exit 0
302
+ if [ -z "$context" ]; then
303
+ eagle_insert_recall_event "$session_id" "$recall_scope" "$cwd" "$agent" "$user_prompt" "$fts_query" "$summary_matches" "$memory_matches" "$code_matches" 0 "no_context" "" "$summary_refs" "$memory_refs" "$code_refs" >/dev/null 2>&1 || true
304
+ eagle_hook_observability_set_detail "$(jq -nc \
305
+ --arg recall_status "no_context" \
306
+ --argjson summary_matches "${summary_matches:-0}" \
307
+ --argjson memory_matches "${memory_matches:-0}" \
308
+ --argjson code_matches "${code_matches:-0}" \
309
+ '{recall_status:$recall_status, summary_matches:$summary_matches, memory_matches:$memory_matches, code_matches:$code_matches, injected_chars:0}')"
310
+ eagle_hook_observability_complete 0
311
+ exit 0
312
+ fi
254
313
 
255
314
  if [ "$codex_compact" -eq 1 ]; then
256
315
  context+="
@@ -264,5 +323,21 @@ IMPORTANT: If directly useful, start with one short Eagle Mem attribution line,
264
323
  "
265
324
  fi
266
325
 
326
+ eagle_insert_recall_event "$session_id" "$recall_scope" "$cwd" "$agent" "$user_prompt" "$fts_query" "$summary_matches" "$memory_matches" "$code_matches" "${#context}" "ok" "" "$summary_refs" "$memory_refs" "$code_refs" >/dev/null 2>&1 || true
327
+ eagle_insert_event "$recall_scope" "$session_id" "$agent" "context_injected" "" "UserPromptSubmit" "ok" "$(jq -nc \
328
+ --argjson summary_matches "${summary_matches:-0}" \
329
+ --argjson memory_matches "${memory_matches:-0}" \
330
+ --argjson code_matches "${code_matches:-0}" \
331
+ --argjson injected_chars "${#context}" \
332
+ '{summary_matches:$summary_matches, memory_matches:$memory_matches, code_matches:$code_matches, injected_chars:$injected_chars}')" >/dev/null 2>&1 || true
333
+ eagle_hook_observability_set_detail "$(jq -nc \
334
+ --arg recall_status "ok" \
335
+ --argjson summary_matches "${summary_matches:-0}" \
336
+ --argjson memory_matches "${memory_matches:-0}" \
337
+ --argjson code_matches "${code_matches:-0}" \
338
+ --argjson injected_chars "${#context}" \
339
+ '{recall_status:$recall_status, summary_matches:$summary_matches, memory_matches:$memory_matches, code_matches:$code_matches, injected_chars:$injected_chars}')"
340
+ eagle_hook_observability_complete 0
341
+
267
342
  eagle_emit_context_for_agent "$agent" "UserPromptSubmit" "$context"
268
343
  exit 0