eagle-mem 4.9.6 → 4.9.8

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.
package/bin/eagle-mem CHANGED
@@ -21,6 +21,7 @@ case "$command" in
21
21
  uninstall) bash "$SCRIPTS_DIR/uninstall.sh" "$@" ;;
22
22
  search) bash "$SCRIPTS_DIR/search.sh" "$@" ;;
23
23
  health) bash "$SCRIPTS_DIR/health.sh" "$@" ;;
24
+ doctor) bash "$SCRIPTS_DIR/doctor.sh" "$PACKAGE_DIR" "$@" ;;
24
25
  config) bash "$SCRIPTS_DIR/config.sh" "$@" ;;
25
26
  updates) bash "$SCRIPTS_DIR/updates.sh" "$@" ;;
26
27
  statusline) "$SCRIPTS_DIR/statusline-em.sh" "$@" ;;
package/db/migrate.sh CHANGED
@@ -44,7 +44,18 @@ run_migration() {
44
44
 
45
45
  # Set connection PRAGMAs, then run migration body + tracking insert atomically
46
46
  # .bail on ensures sqlite3 stops on the first error instead of continuing
47
- { echo ".bail on"; echo "PRAGMA trusted_schema=ON;"; echo "PRAGMA foreign_keys=ON;"; echo "PRAGMA busy_timeout=5000;"; echo "BEGIN;"; echo "$body"; echo "INSERT INTO _migrations (name) VALUES ('$name');"; echo "COMMIT;"; } | "$SQLITE_BIN" "$DB"
47
+ {
48
+ echo ".bail on"
49
+ echo ".output /dev/null"
50
+ echo "PRAGMA trusted_schema=ON;"
51
+ echo "PRAGMA foreign_keys=ON;"
52
+ echo "PRAGMA busy_timeout=5000;"
53
+ echo ".output stdout"
54
+ echo "BEGIN;"
55
+ echo "$body"
56
+ echo "INSERT INTO _migrations (name) VALUES ('$name');"
57
+ echo "COMMIT;"
58
+ } | "$SQLITE_BIN" "$DB"
48
59
  echo " applied: $name"
49
60
  fi
50
61
  }
@@ -57,7 +68,7 @@ run_migration() {
57
68
  );"
58
69
 
59
70
  # Set PRAGMAs (these must be set on every connection)
60
- "$SQLITE_BIN" "$DB" "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA busy_timeout = 5000; PRAGMA foreign_keys = ON;"
71
+ "$SQLITE_BIN" "$DB" "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA busy_timeout = 5000; PRAGMA foreign_keys = ON;" >/dev/null
61
72
 
62
73
  # ─── Migration 001: Initial schema (special name) ──────────
63
74
  run_migration "001_initial_schema" "$SCRIPT_DIR/schema.sql"
@@ -0,0 +1,53 @@
1
+ # Eagle Mem Visible Surface UX Contract
2
+
3
+ Eagle Mem has two audiences for visible output:
4
+
5
+ - The user, who should see a calm product surface.
6
+ - The active agent, which needs compact operational context without raw internals.
7
+
8
+ Default output must be useful without exposing implementation details. Raw database
9
+ IDs, file paths, session IDs, backing JSON, hook payloads, and source file content
10
+ belong behind `--raw`, `--debug`, or `--json`.
11
+
12
+ ## Output Modes
13
+
14
+ | Mode | Purpose | Allowed Content |
15
+ | --- | --- | --- |
16
+ | Default | Human product UX | Brand, status, concise summaries, freshness, next action |
17
+ | `--json` | Machine-readable automation | Structured complete fields |
18
+ | `--raw` | Developer inspection | IDs, source paths, backing files, raw task JSON |
19
+ | `--debug` | Troubleshooting | Same as `--raw`, plus diagnostic hints where useful |
20
+
21
+ ## Visible Surfaces
22
+
23
+ | Surface | User Sees It? | Default Standard |
24
+ | --- | --- | --- |
25
+ | `SessionStart` | Yes, in agent transcript | Branded compact briefing: project, memory, relevant now, work state, guardrails |
26
+ | `UserPromptSubmit` | Yes, in agent transcript | `Eagle Mem recalls` with 1-2 useful bullets and relevant code |
27
+ | `PreToolUse` | Sometimes, when blocking | Calm explanation, recommended fix, one-off bypass if appropriate |
28
+ | `PostToolUse` | Sometimes, after reads/edits | Structured memory/decision/feature notes, no separator blocks for Codex |
29
+ | `statusline` | Yes | Short branded status: version, sessions, memories, turn |
30
+ | `search` | Yes | Freshness-aware results, no raw IDs in headings |
31
+ | `memories` | Yes | Project-scoped list by default, no source paths unless raw/debug |
32
+ | `tasks` | Yes | Task subject/status/source, no session/task IDs unless raw/debug |
33
+ | `feature` | Yes | Pending work grouped by action, raw diff fingerprints only when needed |
34
+ | `health` | Yes | Overall verdict first, then sectioned checks and next action |
35
+ | `install/update/uninstall` | Yes | Explain changed footprint, reversibility, backups, and success/failure plainly |
36
+ | `doctor` | Yes | Trust report: installed runtime, hooks, SQLite/FTS5, install manifest, drift, uninstall coverage |
37
+
38
+ ## Product Voice
39
+
40
+ - Use `Eagle Mem` or `Eagle`; avoid cryptic `EM` in user-facing output.
41
+ - Prefer headings like `Relevant now`, `Work state`, `Guardrail`, and `Next`.
42
+ - Prefer freshness labels like `Fresh`, `Recent`, `Older`, or `may be stale`.
43
+ - Avoid dumping raw hook payloads, XML templates, SQL results, or JSON unless the user requested raw/debug output.
44
+ - Keep Codex transcript injections more compact than Claude Code injections.
45
+
46
+ ## Install/Update/Uninstall Standard
47
+
48
+ - Before mutating user config or runtime files, show a short "What will change" plan.
49
+ - Treat `--dry-run` as a first-class product path for destructive or cleanup commands.
50
+ - Back up user-owned config files before editing `~/.claude` or `~/.codex` state.
51
+ - Preserve `~/.eagle-mem/memory.db` by default; require explicit confirmation before deleting stored memory.
52
+ - After install/update, write a manifest with runtime file metadata so `doctor` can verify drift without noisy shell dumps.
53
+ - Prefer one clear verdict first (`Healthy`, `Needs attention`, or `Broken`), then details.
@@ -200,8 +200,8 @@ esac
200
200
 
201
201
  eagle_posttool_mirror_writes "$tool_name" "$fp" "$session_id" "$project" "$agent"
202
202
  eagle_posttool_mirror_tasks "$tool_name" "$session_id" "$project" "$input" "$agent"
203
- eagle_posttool_stale_hint "$tool_name" "$fp" "$project"
204
- eagle_posttool_decision_surface "$tool_name" "$fp" "$project"
203
+ eagle_posttool_stale_hint "$tool_name" "$fp" "$project" "$agent"
204
+ eagle_posttool_decision_surface "$tool_name" "$fp" "$project" "$agent"
205
205
 
206
206
  # ─── Record observation ──────────────────────────────────
207
207
 
@@ -96,12 +96,12 @@ Pending checks:"
96
96
  rtk_cmd=$(eagle_rtk_rewrite_command "$cmd")
97
97
  if [ -n "$rtk_cmd" ]; then
98
98
  if [ "$agent" = "codex" ] && [ "$raw_bash_mode" != "allow" ] && ! eagle_raw_bash_unlock_active; then
99
- reason="Eagle Mem token guard blocked raw shell output.
99
+ reason="Eagle Mem blocked raw shell output to keep Codex context clean.
100
100
 
101
- Use RTK so large output is compact before it enters context:
101
+ Recommended compact command:
102
102
  $rtk_cmd
103
103
 
104
- Temporary escape hatch for one-off raw output:
104
+ One-off developer bypass:
105
105
  touch $EAGLE_RAW_BASH_UNLOCK"
106
106
  jq -nc --arg reason "$reason" '{
107
107
  "decision":"block",
@@ -120,15 +120,15 @@ Temporary escape hatch for one-off raw output:
120
120
  context+="Eagle Mem token guard: rewrote raw shell command through RTK to reduce context load: ${rtk_cmd}. "
121
121
  fi
122
122
  elif [ "$rtk_mode" = "enforce" ] && ! command -v rtk >/dev/null 2>&1 && eagle_raw_output_command_needs_guard "$cmd" && ! eagle_raw_bash_unlock_active; then
123
- reason="Eagle Mem token guard is set to enforce, but RTK is not installed or not on PATH.
123
+ reason="Eagle Mem blocked this command because RTK enforcement is on, but RTK is not installed or not on PATH.
124
124
 
125
125
  This command can dump raw output into agent context:
126
126
  $cmd
127
127
 
128
- Install RTK or disable enforcement:
128
+ Install RTK or switch enforcement to auto:
129
129
  eagle-mem config set token_guard.rtk auto
130
130
 
131
- Temporary escape hatch:
131
+ One-off developer bypass:
132
132
  touch $EAGLE_RAW_BASH_UNLOCK"
133
133
  jq -nc --arg reason "$reason" '{
134
134
  "decision":"block",
@@ -37,6 +37,12 @@ project=$(eagle_project_from_hook_input "$input")
37
37
  [ -z "$project" ] && exit 0
38
38
 
39
39
  p_esc=$(eagle_sql_escape "$project")
40
+ recall_scope=$(eagle_recall_project_scope_from_cwd "$cwd" "$project")
41
+ [ -z "$recall_scope" ] && recall_scope="$project"
42
+ recall_scope_label=$(eagle_project_scope_label "$recall_scope")
43
+ recall_project_filter=$(eagle_sql_project_scope_condition "project" "$recall_scope")
44
+ recall_memory_filter=$(eagle_sql_project_scope_condition "m.project" "$recall_scope")
45
+ recall_lane_filter=$(eagle_sql_project_scope_condition "l.project" "$recall_scope")
40
46
 
41
47
  eagle_log "INFO" "SessionStart: session=$session_id project=$project source=$source_type agent=$agent"
42
48
 
@@ -96,7 +102,7 @@ while IFS='|' read -r key val; do
96
102
  last_active) stat_last_active="$val" ;;
97
103
  last_summary) stat_last_summary="$val" ;;
98
104
  esac
99
- done <<< "$(eagle_get_project_stats "$project")"
105
+ done <<< "$(eagle_get_project_stats "$recall_scope")"
100
106
 
101
107
  # ─── Build compressed banner (elide zero-value lines) ────
102
108
 
@@ -119,6 +125,10 @@ eagle_banner="======================================
119
125
  Project | $project
120
126
  Agent | $agent_label
121
127
  Sessions | $stat_sessions ($stat_with_summaries with summaries)"
128
+ if [ "$recall_scope_label" != "$project" ]; then
129
+ eagle_banner+="
130
+ Recall Scope | $recall_scope_label"
131
+ fi
122
132
  if [ "$stat_sessions_codex" -gt 0 ] || [ "$stat_sessions_claude" -gt 0 ]; then
123
133
  eagle_banner+="
124
134
  Sources | Claude $stat_sessions_claude, Codex $stat_sessions_codex"
@@ -137,8 +147,196 @@ eagle_banner+="
137
147
  ======================================"
138
148
 
139
149
  context="$eagle_banner
150
+ Eagle Mem recalls: use the project memory below before making design or implementation claims. If it affects your answer, mention the recall in one short attribution line.
140
151
  "
141
152
 
153
+ if [ "$codex_compact" -eq 1 ]; then
154
+ codex_context="Eagle Mem Recall Ready
155
+ Project: $project | Agent: $agent_label
156
+ Memory: $stat_sessions sessions"
157
+ if [ "$recall_scope_label" != "$project" ]; then
158
+ codex_context="Eagle Mem Recall Ready
159
+ Project: $project | Recall: $recall_scope_label | Agent: $agent_label
160
+ Memory: $stat_sessions sessions"
161
+ fi
162
+ [ "$stat_with_summaries" -gt 0 ] && codex_context+=", $stat_with_summaries summarized"
163
+ [ "$stat_memories" -gt 0 ] && codex_context+=", $stat_memories memories"
164
+ [ "$stat_chunks" -gt 0 ] && codex_context+=", $stat_chunks code chunks"
165
+ codex_context+="
166
+ "
167
+
168
+ if [ -n "$update_notice" ]; then
169
+ codex_context+="
170
+ Update: $(eagle_trim_text "$update_notice" 180)
171
+ "
172
+ fi
173
+
174
+ if [ "${stat_with_summaries:-0}" -eq 0 ] 2>/dev/null; then
175
+ codex_context+="
176
+ Capture: Codex hooks are active. Eagle Mem will summarize decisions and gotchas from the transcript automatically.
177
+ "
178
+ fi
179
+
180
+ overview=$(eagle_get_overview "$project")
181
+ if [ -n "$overview" ]; then
182
+ codex_context+="
183
+ Project brief: $(eagle_trim_text "$overview" 260)
184
+ "
185
+ else
186
+ codex_context+="
187
+ Project brief: no overview yet; background scan is running.
188
+ "
189
+ fi
190
+
191
+ recent=$(eagle_get_recent_summaries "$recall_scope" 1)
192
+ if [ -n "$recent" ]; then
193
+ codex_context+="
194
+ Relevant now:
195
+ "
196
+ while IFS='|' read -r request completed learned _next_steps created_at _decisions gotchas _key_files summary_agent; do
197
+ [ -z "$request" ] && [ -z "$completed" ] && continue
198
+ summary_agent_label=$(eagle_agent_label "$summary_agent")
199
+ recent_line="$completed"
200
+ [ -z "$recent_line" ] && recent_line="$request"
201
+ codex_context+="- Recent [$summary_agent_label]: $(eagle_trim_text "$recent_line" 180)
202
+ "
203
+ [ -n "$learned" ] && codex_context+=" Learned: $(eagle_trim_text "$learned" 140)
204
+ "
205
+ [ -n "$gotchas" ] && codex_context+=" Watch: $(eagle_trim_text "$gotchas" 120)
206
+ "
207
+ done <<< "$recent"
208
+ fi
209
+
210
+ memories=$(eagle_db "SELECT memory_name, memory_type, description, origin_agent,
211
+ CAST(julianday('now') - julianday(updated_at) AS INTEGER) as days_ago
212
+ FROM agent_memories
213
+ WHERE $recall_project_filter
214
+ AND memory_name NOT IN ('Codex Memory Registry', 'Codex Memory Summary')
215
+ ORDER BY
216
+ CASE
217
+ WHEN lower(memory_name) LIKE 'current status%' THEN 4
218
+ WHEN memory_type = 'project' THEN 0
219
+ WHEN memory_type = 'feedback' THEN 1
220
+ WHEN memory_type IN ('user', 'reference') THEN 2
221
+ ELSE 3
222
+ END,
223
+ updated_at DESC
224
+ LIMIT 4;")
225
+ if [ -n "$memories" ]; then
226
+ [ -z "$recent" ] && codex_context+="
227
+ Relevant now:
228
+ "
229
+ while IFS='|' read -r mname mtype mdesc morigin days_ago; do
230
+ [ -z "$mname" ] && continue
231
+ origin_label=$(eagle_agent_label "$morigin")
232
+ age_label="fresh"
233
+ if [ -n "$days_ago" ] && [ "$days_ago" -gt 14 ] 2>/dev/null; then
234
+ age_label="older"
235
+ elif [ -n "$days_ago" ] && [ "$days_ago" -gt 0 ] 2>/dev/null; then
236
+ age_label="${days_ago}d old"
237
+ fi
238
+ codex_context+="- Memory [$mtype][$origin_label][$age_label]: $mname"
239
+ [ -n "$mdesc" ] && codex_context+=" — $(eagle_trim_text "$mdesc" 120)"
240
+ codex_context+="
241
+ "
242
+ done <<< "$memories"
243
+ fi
244
+
245
+ synced_tasks=$(eagle_db "SELECT subject, status, blocked_by, origin_agent FROM agent_tasks
246
+ WHERE $recall_project_filter
247
+ AND status IN ('in_progress', 'pending')
248
+ AND source_session_id != 'orchestration'
249
+ AND updated_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days')
250
+ ORDER BY CASE status WHEN 'in_progress' THEN 0 ELSE 1 END, updated_at DESC
251
+ LIMIT 3;")
252
+ orchestration_lanes=$(eagle_db "SELECT o.name, l.lane_key, l.title, l.agent, l.status
253
+ FROM orchestration_lanes l
254
+ JOIN orchestrations o ON o.id = l.orchestration_id
255
+ WHERE $recall_lane_filter
256
+ AND o.status = 'active'
257
+ AND l.status IN ('in_progress', 'pending', 'blocked')
258
+ ORDER BY CASE l.status WHEN 'in_progress' THEN 0 WHEN 'blocked' THEN 1 ELSE 2 END, l.updated_at DESC
259
+ LIMIT 3;" 2>/dev/null)
260
+ if [ -n "$synced_tasks" ] || [ -n "$orchestration_lanes" ]; then
261
+ codex_context+="
262
+ Work state:
263
+ "
264
+ while IFS='|' read -r tsubject tstatus tblocked torigin; do
265
+ [ -z "$tsubject" ] && continue
266
+ origin_label=$(eagle_agent_label "$torigin")
267
+ block_marker=""
268
+ [ "$tblocked" != "[]" ] && [ -n "$tblocked" ] && block_marker=" blocked"
269
+ codex_context+="- Task [$tstatus][$origin_label$block_marker]: $(eagle_trim_text "$tsubject" 130)
270
+ "
271
+ done <<< "$synced_tasks"
272
+ while IFS='|' read -r oname lkey ltitle lagent lstatus; do
273
+ [ -z "$lkey" ] && continue
274
+ origin_label=$(eagle_agent_label "$lagent")
275
+ codex_context+="- Lane [$lstatus][$origin_label]: $lkey"
276
+ [ -n "$ltitle" ] && codex_context+=" — $(eagle_trim_text "$ltitle" 100)"
277
+ [ -n "$oname" ] && codex_context+=" ($oname)"
278
+ codex_context+="
279
+ "
280
+ done <<< "$orchestration_lanes"
281
+ [ -n "$orchestration_lanes" ] && codex_context+=" Agent rule: you update lane status with eagle-mem orchestrate; do not ask the user to run it.
282
+ "
283
+ fi
284
+
285
+ pending_features=$(eagle_list_pending_feature_verifications "$project" 3 2>/dev/null)
286
+ if [ -n "$pending_features" ]; then
287
+ codex_context+="
288
+ Guardrail:
289
+ "
290
+ while IFS='|' read -r pf_id pf_name pf_file pf_reason _pf_trigger _pf_created pf_smoke _pfingerprint; do
291
+ [ -z "$pf_id" ] && continue
292
+ codex_context+="- Pending verification #$pf_id: $pf_name"
293
+ [ -n "$pf_file" ] && codex_context+=" ($pf_file)"
294
+ [ -n "$pf_reason" ] && codex_context+=" — $(eagle_trim_text "$pf_reason" 90)"
295
+ [ -n "$pf_smoke" ] && codex_context+=" | smoke: $(eagle_trim_text "$pf_smoke" 100)"
296
+ codex_context+="
297
+ "
298
+ done <<< "$pending_features"
299
+ codex_context+=" Release commands are blocked until these are verified or waived.
300
+ "
301
+ fi
302
+
303
+ hot_files=$(eagle_get_hot_files "$project")
304
+ if [ -n "$hot_files" ]; then
305
+ core_files=""
306
+ IFS=',' read -ra hf_arr <<< "$hot_files"
307
+ hf_count=0
308
+ for hf in "${hf_arr[@]}"; do
309
+ [ "$hf_count" -ge 5 ] && break
310
+ [ -z "$hf" ] && continue
311
+ [ -n "$core_files" ] && core_files+=", "
312
+ core_files+="$(basename "$hf")"
313
+ hf_count=$((hf_count + 1))
314
+ done
315
+ [ -n "$core_files" ] && codex_context+="
316
+ Core files: $core_files
317
+ "
318
+ fi
319
+
320
+ if [ "$source_type" = "compact" ] || [ "$source_type" = "clear" ]; then
321
+ working_set=$(eagle_get_working_set "$session_id")
322
+ if [ -n "$working_set" ]; then
323
+ codex_context+="
324
+ Working set:
325
+ "
326
+ while IFS='|' read -r ws_path ws_edits; do
327
+ [ -z "$ws_path" ] && continue
328
+ codex_context+="- $(basename "$ws_path") (${ws_edits} edits)
329
+ "
330
+ done <<< "$working_set"
331
+ fi
332
+ fi
333
+
334
+ codex_context+="
335
+ Use recalled context only when relevant. Keep user-facing replies clean; do not print raw Eagle Mem internals."
336
+ eagle_emit_context_for_agent "$agent" "SessionStart" "$codex_context"
337
+ exit 0
338
+ fi
339
+
142
340
  if [ -n "$update_notice" ]; then
143
341
  context+="
144
342
  === Eagle Mem: Update Available ===
@@ -181,7 +379,7 @@ else
181
379
  _summary_limit=2
182
380
  fi
183
381
 
184
- recent=$(eagle_get_recent_summaries "$project" "$_summary_limit")
382
+ recent=$(eagle_get_recent_summaries "$recall_scope" "$_summary_limit")
185
383
 
186
384
  if [ -n "$recent" ]; then
187
385
  context+="
@@ -230,13 +428,22 @@ fi
230
428
 
231
429
  # ─── Memories (skip if none) ─────────────────────────────
232
430
 
233
- memory_limit=3
234
- [ "$codex_compact" -eq 1 ] && memory_limit=2
431
+ memory_limit=5
432
+ [ "$codex_compact" -eq 1 ] && memory_limit=3
235
433
  memories=$(eagle_db "SELECT memory_name, memory_type, description, file_path, updated_at, origin_agent,
236
434
  CAST(julianday('now') - julianday(updated_at) AS INTEGER) as days_ago
237
435
  FROM agent_memories
238
- WHERE project = '$p_esc'
239
- ORDER BY updated_at DESC
436
+ WHERE $recall_project_filter
437
+ AND memory_name NOT IN ('Codex Memory Registry', 'Codex Memory Summary')
438
+ ORDER BY
439
+ CASE
440
+ WHEN lower(memory_name) LIKE 'current status%' THEN 4
441
+ WHEN memory_type = 'project' THEN 0
442
+ WHEN memory_type = 'feedback' THEN 1
443
+ WHEN memory_type IN ('user', 'reference') THEN 2
444
+ ELSE 3
445
+ END,
446
+ updated_at DESC
240
447
  LIMIT $memory_limit;")
241
448
  if [ -n "$memories" ]; then
242
449
  context+="
@@ -263,7 +470,7 @@ fi
263
470
 
264
471
  # ─── Plans (skip if none) ────────────────────────────────
265
472
 
266
- plans=$(eagle_list_agent_plans "$project" 3)
473
+ plans=$(eagle_list_agent_plans "$recall_scope" 3)
267
474
  if [ -n "$plans" ]; then
268
475
  context+="
269
476
  === Eagle Mem: Plans ===
@@ -281,7 +488,7 @@ fi
281
488
  task_limit=5
282
489
  [ "$codex_compact" -eq 1 ] && task_limit=3
283
490
  synced_tasks=$(eagle_db "SELECT subject, status, blocked_by, origin_agent FROM agent_tasks
284
- WHERE project = '$p_esc'
491
+ WHERE $recall_project_filter
285
492
  AND status IN ('in_progress', 'pending')
286
493
  AND source_session_id != 'orchestration'
287
494
  AND updated_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days')
@@ -314,7 +521,7 @@ orchestration_lanes=$(eagle_db "SELECT o.name, o.goal, l.lane_key, l.title,
314
521
  l.agent, l.status, l.validation, l.worktree_path, l.notes
315
522
  FROM orchestration_lanes l
316
523
  JOIN orchestrations o ON o.id = l.orchestration_id
317
- WHERE l.project = '$p_esc'
524
+ WHERE $recall_lane_filter
318
525
  AND o.status = 'active'
319
526
  AND l.status IN ('in_progress', 'pending', 'blocked')
320
527
  ORDER BY
@@ -26,6 +26,8 @@ agent=$(eagle_agent_source_from_json "$input")
26
26
  [ -z "$user_prompt" ] && exit 0
27
27
 
28
28
  project=$(eagle_project_from_hook_input "$input")
29
+ recall_scope=$(eagle_recall_project_scope_from_cwd "$cwd" "$project")
30
+ [ -z "$recall_scope" ] && recall_scope="$project"
29
31
  codex_compact=0
30
32
  [ "$agent" = "codex" ] && codex_compact=1
31
33
 
@@ -46,8 +48,10 @@ if [ -n "$session_id" ] && eagle_validate_session_id "$session_id"; then
46
48
  if [ "$turn_count" -ge 30 ]; then
47
49
  if [ "$codex_compact" -eq 1 ]; then
48
50
  context+="
49
- === Eagle Mem: Context Pressure Critical ($turn_count turns since compact) ===
50
- Keep the next Codex reply user-clean. Do not print Eagle Mem summary capture blocks or other internals. Include a short normal handoff note if useful, then ask the user to run /compact.
51
+ Eagle Mem context pressure: critical ($turn_count turns since compact)
52
+ - Keep the next Codex reply user-clean.
53
+ - Do not print Eagle Mem summary blocks or internals.
54
+ - Add a short normal handoff note if useful, then ask the user to run /compact.
51
55
  "
52
56
  else
53
57
  context+="
@@ -60,8 +64,10 @@ Tell the user to run /compact NOW to avoid losing context.
60
64
  elif [ "$turn_count" -ge 20 ]; then
61
65
  if [ "$codex_compact" -eq 1 ]; then
62
66
  context+="
63
- === Eagle Mem: Context Pressure High ($turn_count turns since compact) ===
64
- Keep the next Codex reply clean. Do not print Eagle Mem summary capture blocks or other internals. Summarize any durable decisions in normal prose only.
67
+ Eagle Mem context pressure: high ($turn_count turns since compact)
68
+ - Keep the next Codex reply clean.
69
+ - Do not print Eagle Mem summary blocks or internals.
70
+ - Summarize durable decisions in normal prose only.
65
71
  "
66
72
  else
67
73
  context+="
@@ -89,8 +95,10 @@ fts_query=$(echo "$user_prompt" | tr -cs '[:alnum:]' ' ' | tr '[:upper:]' '[:low
89
95
  split("the a an is are was were be been being have has had do does did will would shall should may might can could of in to for on with at by from", sw, " ")
90
96
  for (i in sw) stop[sw[i]]=1
91
97
  n=0
98
+ split("ad ai ui ux db", keep, " ")
99
+ for (i in keep) short_keep[keep[i]]=1
92
100
  for (i=1; i<=NF && n<6; i++) {
93
- if (length($i) > 2 && !($i in stop)) {
101
+ if ((length($i) > 2 || ($i in short_keep)) && !($i in stop)) {
94
102
  printf "%s%s", (n>0?" OR ":""), $i; n++
95
103
  }
96
104
  }
@@ -106,8 +114,10 @@ fi
106
114
  lower_prompt=$(printf '%s' "$user_prompt" | tr '[:upper:]' '[:lower:]')
107
115
  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
108
116
  if [ "$codex_compact" -eq 1 ]; then
109
- context+="=== Eagle Mem: Orchestration Protocol ===
110
- For broad work, you run eagle-mem orchestrate yourself. Use durable lanes, opposite-agent workers, and concise user-visible status.
117
+ context+="
118
+ 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.
111
121
  "
112
122
  else
113
123
  context+="=== Eagle Mem: Orchestration Protocol ===
@@ -131,11 +141,23 @@ if [ "$codex_compact" -eq 1 ]; then
131
141
  code_limit=2
132
142
  fi
133
143
 
134
- results=$(eagle_search_summaries "$fts_query" "$project" "$summary_limit")
144
+ memory_limit=3
145
+ [ "$codex_compact" -eq 1 ] && memory_limit=2
146
+
147
+ results=$(eagle_search_summaries "$fts_query" "$recall_scope" "$summary_limit")
148
+ memory_results=$(eagle_search_agent_memories "$fts_query" "$recall_scope" "$memory_limit" 2>/dev/null || true)
149
+
150
+ if [ -n "$results" ] || [ -n "$memory_results" ]; then
151
+ if [ "$codex_compact" -eq 1 ]; then
152
+ context+="
153
+ Eagle Mem recalls:
154
+ "
155
+ else
156
+ context+="Eagle Mem recalls: apply these retrieved project facts before answering. If they are relevant to the user's prompt, start with one short \"Eagle Mem recalls:\" attribution line.
135
157
 
136
- if [ -n "$results" ]; then
137
- context+="=== Eagle Mem: Relevant Recall ===
158
+ === Eagle Mem: Relevant Recall ===
138
159
  "
160
+ fi
139
161
  while IFS='|' read -r req completed learned _next_steps created_at _proj decisions gotchas key_files summary_agent; do
140
162
  [ -z "$req" ] && [ -z "$completed" ] && continue
141
163
  origin_label=$(eagle_agent_label "$summary_agent")
@@ -143,13 +165,14 @@ if [ -n "$results" ]; then
143
165
  req=$(eagle_trim_text "$req" 90)
144
166
  completed=$(eagle_trim_text "$completed" 150)
145
167
  learned=$(eagle_trim_text "$learned" 110)
146
- context+="- [$origin_label] "
168
+ context+="- Recent [$origin_label]: "
147
169
  if [ -n "$completed" ]; then
148
170
  context+="$completed"
149
171
  else
150
172
  context+="$req"
151
173
  fi
152
- [ -n "$learned" ] && context+=" | learned: $learned"
174
+ [ -n "$learned" ] && context+="
175
+ Learned: $learned"
153
176
  context+="
154
177
  "
155
178
  else
@@ -173,6 +196,30 @@ if [ -n "$results" ]; then
173
196
  "
174
197
  fi
175
198
  done <<< "$results"
199
+
200
+ while IFS='|' read -r mname mtype mdesc msnippet _mfile _mupdated morigin; do
201
+ [ -z "$mname" ] && continue
202
+ case "$mname" in
203
+ "Codex Memory Registry"|"Codex Memory Summary") continue ;;
204
+ esac
205
+ origin_label=$(eagle_agent_label "$morigin")
206
+ if [ "$codex_compact" -eq 1 ]; then
207
+ mdesc=$(eagle_trim_text "$mdesc" 120)
208
+ context+="- Memory [$mtype][$origin_label]: $mname"
209
+ [ -n "$mdesc" ] && context+=" — $mdesc"
210
+ context+="
211
+ "
212
+ else
213
+ mdesc=$(eagle_trim_text "$mdesc" 180)
214
+ msnippet=$(eagle_trim_text "$msnippet" 220)
215
+ context+="[Memory][$origin_label][$mtype] $mname"
216
+ [ -n "$mdesc" ] && context+=" — $mdesc"
217
+ [ -n "$msnippet" ] && context+="
218
+ Snippet: $msnippet"
219
+ context+="
220
+ "
221
+ fi
222
+ done <<< "$memory_results"
176
223
  fi
177
224
 
178
225
  # Search indexed code chunks (if any exist for this project)
@@ -181,11 +228,21 @@ if [ "${has_chunks:-0}" -gt 0 ]; then
181
228
  code_results=$(eagle_search_code_chunks "$fts_query" "$project" "$code_limit")
182
229
 
183
230
  if [ -n "$code_results" ]; then
184
- context+="=== Eagle Mem: Relevant Code ===
231
+ if [ "$codex_compact" -eq 1 ]; then
232
+ context+="
233
+ Relevant code:
234
+ "
235
+ else
236
+ context+="=== Eagle Mem: Relevant Code ===
185
237
  "
238
+ fi
186
239
  while IFS='|' read -r fpath sline eline lang; do
187
240
  [ -z "$fpath" ] && continue
188
- context+="$fpath:${sline}-${eline}"
241
+ if [ "$codex_compact" -eq 1 ]; then
242
+ context+="- $fpath:${sline}-${eline}"
243
+ else
244
+ context+="$fpath:${sline}-${eline}"
245
+ fi
189
246
  [ -n "$lang" ] && context+=" ($lang)"
190
247
  context+="
191
248
  "
@@ -197,7 +254,7 @@ fi
197
254
 
198
255
  if [ "$codex_compact" -eq 1 ]; then
199
256
  context+="
200
- Use only if directly useful. If you mention it to the user, keep Eagle Mem attribution to one short line.
257
+ Note: use only if directly useful. If you mention it to the user, keep Eagle Mem attribution to one short line.
201
258
  "
202
259
  else
203
260
  context+="