eagle-mem 4.10.1 → 4.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,11 +7,11 @@
7
7
 
8
8
  # Eagle Mem
9
9
 
10
- **Shared memory, release guardrails, and worker lanes for Claude Code, Codex, and Grok-assisted workflows.**
10
+ **Shared memory, release guardrails, and worker lanes for Claude Code, Codex, Grok, and Google Antigravity.**
11
11
 
12
- Eagle Mem turns AI coding sessions into compounding project knowledge. It gives Claude Code and Codex hook-backed shared memory, gives Grok the same skills and CLI memory surface, labels which agent created each memory, blocks risky release commands until affected features are verified, and lets broad work split into durable worker lanes.
12
+ Eagle Mem turns AI coding sessions into compounding project knowledge. It gives Claude Code, Codex, and Google Antigravity hook-backed shared memory, gives Grok the same skills and CLI memory surface, labels which agent created each memory, blocks risky release commands until affected features are verified, and lets broad work split into durable worker lanes.
13
13
 
14
- **v4.10.0 focuses on Grok support and Compaction Survival:** Grok users now get first-class skill linking and `eagle-mem grok-bootstrap`, while all agents can inspect project-level compaction readiness with `eagle-mem compaction`. Claude Code and Codex continue to get the deepest automatic lifecycle support through hooks; Grok currently uses the shared CLI and skill workflow until native lifecycle hooks are available.
14
+ **v4.10.0 and onward focuses on Grok, Google Antigravity support, and Compaction Survival:** Grok users get first-class skill linking and `eagle-mem grok-bootstrap`, while Antigravity users get native Python SDK hook integration via `google_antigravity_hook.py`. Claude Code, Codex, and Antigravity receive the deepest automatic lifecycle support through hooks; Grok currently uses the shared CLI and skill workflow.
15
15
 
16
16
  **Website:** [Product](https://eagleisbatman.github.io/eagle-mem/) |
17
17
  [Architecture](https://eagleisbatman.github.io/eagle-mem/architecture.html) |
@@ -22,12 +22,12 @@ Eagle Mem turns AI coding sessions into compounding project knowledge. It gives
22
22
  - **Start warmer** - every new session can recall project overviews, decisions, gotchas, summaries, hot files, mirrored memories, plans, and tasks.
23
23
  - **Ship safer** - feature-mapped changes create pending verification records, and release-boundary commands stay blocked until the current diff is verified or waived.
24
24
  - **Waste fewer tokens** - Eagle Mem injects compact context, nudges duplicate reads, and can route noisy shell output through RTK.
25
- - **Coordinate agents** - Codex and Claude Code can share one project memory while worker lanes record owner, model, effort, worktree, logs, validation, and handoff.
25
+ - **Coordinate agents** - Claude, Codex, Grok, and Antigravity can share one project memory while worker lanes record owner, model, effort, worktree, logs, validation, and handoff.
26
26
  - **Stay local** - no daemon, no hosted memory service, no vector database. The core is hooks plus SQLite/FTS5.
27
27
 
28
28
  ## The Problem
29
29
 
30
- Claude Code and Codex start every session with amnesia. They don't remember what you built yesterday, what decisions you made, what files matter, or what broke last time. Every `/compact` wipes context. Every new session is a cold start. You waste tokens re-explaining your project, re-reading files, and watching agents repeat mistakes you already corrected.
30
+ Claude Code, Codex, Grok, and Google Antigravity start every session with amnesia. They don't remember what you built yesterday, what decisions you made, what files matter, or what broke last time. Every `/compact` wipes context. Every new session is a cold start. You waste tokens re-explaining your project, re-reading files, and watching agents repeat mistakes you already corrected.
31
31
 
32
32
  The longer you work with Claude Code, the worse this gets. Projects accumulate history — decisions, gotchas, architectural patterns, feature dependencies — and none of it survives across sessions.
33
33
 
@@ -41,9 +41,9 @@ Eagle Mem is a local runtime layer for AI coding agents. It adds three things th
41
41
  | **Guardrails** | "The agent cannot casually undo known decisions or push unverified feature changes." | Surfaces decisions before edits and enforces feature verification on push, PR, and publish boundaries. |
42
42
  | **Lanes** | "A big task can survive compaction and split across agents." | Persists orchestrations, worker lanes, worktrees, logs, validation commands, and handoffs. |
43
43
 
44
- Claude Code and Codex share the same SQLite database at `~/.eagle-mem/memory.db`, and captured rows are source-attributed as `Claude Code` or `Codex`. Grok uses the same database through skills and CLI commands, with native lifecycle capture reserved for a future adapter.
44
+ Claude Code, Codex, and Google Antigravity share the same SQLite database at `~/.eagle-mem/memory.db`, and captured rows are source-attributed as `Claude Code`, `Codex`, or `Antigravity`. Grok uses the same database through skills and CLI commands.
45
45
 
46
- **Zero per-instance overhead.** No daemon, no vector DB, no MCP server. Just bash scripts, sqlite3 (WAL mode, FTS5 full-text search), and jq.
46
+ **Zero per-instance overhead.** No daemon, no vector DB, no MCP server. Just bash/python hooks, sqlite3 (WAL mode, FTS5 full-text search), and jq.
47
47
 
48
48
  ```
49
49
  ======================================
@@ -66,17 +66,17 @@ eagle-mem install
66
66
  eagle-mem doctor
67
67
  ```
68
68
 
69
- That's it. `doctor` should report a healthy install. Open Claude Code or Codex in any project directory and Eagle Mem activates automatically. For Grok, run `eagle-mem grok-bootstrap` after install to confirm the linked skills and CLI workflow.
69
+ That's it. `doctor` should report a healthy install. Open Claude Code or Codex, or import the Antigravity hook in your agent config, and Eagle Mem activates automatically. For Grok, run `eagle-mem grok-bootstrap` after install to confirm the linked skills and CLI workflow.
70
70
 
71
- For Claude Code and Codex, everything is automatic from here. Eagle Mem scans your codebase, indexes source files, captures session summaries, mirrors Claude's memories and tasks, learns which commands are noisy, prunes stale data, and installs patch bug fixes — all in the background via hooks.
71
+ For Claude Code, Codex, and Google Antigravity, everything is automatic. Eagle Mem scans your codebase, indexes source files, captures session summaries, mirrors memories and tasks (including planning-mode artifacts like `implementation_plan.md`, `task.md`, and `walkthrough.md`), learns which commands are noisy, and prunes stale data — all in the background via hooks.
72
72
 
73
- For Codex, the installer enables `codex_hooks` in `~/.codex/config.toml`, registers hooks in `~/.codex/hooks.json`, symlinks Eagle Mem skills into `~/.codex/skills`, and patches `~/.codex/AGENTS.md`. For Claude Code, it integrates with `~/.claude/settings.json`, `CLAUDE.md`, and `~/.claude/skills`. Grok users get skill symlinks into `~/.grok/skills/` and can run `eagle-mem grok-bootstrap` for setup guidance and self-linking.
73
+ For Google Antigravity, the installer copies the native Python integration to `~/.eagle-mem/integrations/google_antigravity_hook.py`. For Codex, the installer enables `codex_hooks` in `~/.codex/config.toml`, registers hooks in `~/.codex/hooks.json`, symlinks Eagle Mem skills into `~/.codex/skills`, and patches `~/.codex/AGENTS.md`. For Claude Code, it integrates with `~/.claude/settings.json`, `CLAUDE.md`, and `~/.claude/skills`. Grok users get skill symlinks into `~/.grok/skills/` and can run `eagle-mem grok-bootstrap` for setup guidance and self-linking.
74
74
 
75
75
  ### Prerequisites
76
76
 
77
77
  - `sqlite3` with FTS5 support (ships with macOS; Eagle Mem prefers known system/Homebrew SQLite binaries before PATH shims)
78
78
  - `jq` (the installer offers to install if missing)
79
- - [Claude Code](https://docs.anthropic.com/en/docs/claude-code), Codex, or a Grok environment (`~/.grok/`)
79
+ - [Claude Code](https://docs.anthropic.com/en/docs/claude-code), Codex, Google Antigravity SDK, or a Grok environment (`~/.grok/`)
80
80
 
81
81
  ## How It Works
82
82
 
@@ -110,7 +110,7 @@ Eagle Mem actively reduces token consumption:
110
110
 
111
111
  ### Compaction Survival
112
112
 
113
- One of the core promises of Eagle Mem is protecting against `/compact` and session amnesia. Compaction Survival is project-level, not Grok-specific: it reads shared Eagle Mem state such as durable tasks, enriched summaries, stale work, and orchestration lanes. Claude Code and Codex get automatic hook-backed recovery through SessionStart, Stop, task mirroring, and context-pressure nudges. Grok can inspect and use the same state through `eagle-mem compaction`, `eagle-mem tasks`, and the linked skills, but does not yet have native lifecycle hooks.
113
+ One of the core promises of Eagle Mem is protecting against `/compact` and session amnesia. Compaction Survival is project-level: it reads shared Eagle Mem state such as durable tasks, enriched summaries, stale work, and orchestration lanes. Claude Code, Codex, and Google Antigravity get automatic hook-backed recovery through `SessionStart`, `Stop`/`post_turn`, and context-pressure nudges. Grok can inspect and use the same state through `eagle-mem compaction`, `eagle-mem tasks`, and the linked skills.
114
114
 
115
115
  Run `eagle-mem compaction` anytime to check readiness.
116
116
 
@@ -134,7 +134,7 @@ Eagle Mem prevents Claude from repeating past mistakes:
134
134
  - **Gotcha surfacing** — past surprises and gotchas are surfaced when editing related files
135
135
  - **Stale memory detection** — warns when edits may contradict stored memories
136
136
  - **Token guard** — when `rtk` is installed, raw shell output commands are rewritten or blocked with an RTK equivalent so large output is compacted before it enters agent context
137
- - **Orchestration lanes** — long-running work can be split into durable worker lanes with owners, validation commands, worktree paths, status notes, and handoff output shared by Claude Code and Codex
137
+ - **Orchestration lanes** — long-running work can be split into durable worker lanes with owners, validation commands, worktree paths, status notes, and handoff output shared across Claude Code, Codex, Grok, and Google Antigravity
138
138
 
139
139
  ## Commands
140
140
 
@@ -175,7 +175,7 @@ eagle-mem uninstall --dry-run
175
175
 
176
176
  Install and update print the files/configs they intend to touch before they change the runtime. The installed runtime writes `~/.eagle-mem/install-manifest.json` with file sizes, modes, and SHA-256 hashes, so `doctor` can tell whether hooks, scripts, libraries, and database helpers still match the package that installed them.
177
177
 
178
- Uninstall removes Claude Code and Codex hook registrations, Eagle Mem instruction blocks, custom Claude statusline integration, and skill links. It backs up user config files before editing them and keeps `~/.eagle-mem/memory.db` unless you explicitly confirm data deletion.
178
+ Uninstall removes Claude Code, Codex, Grok, and Google Antigravity hook registrations, Eagle Mem instruction blocks, custom Claude statusline integration, and skill links. It backs up user config files before editing them and keeps `~/.eagle-mem/memory.db` unless you explicitly confirm data deletion.
179
179
 
180
180
  ### Download Counts, Privacy, and Telemetry
181
181
 
@@ -339,12 +339,12 @@ Each lane is stored in `orchestration_lanes` and mirrored into `agent_tasks`, so
339
339
 
340
340
  Both agents write to `~/.eagle-mem/memory.db`:
341
341
 
342
- - `sessions.agent` records whether a session came from Claude Code or Codex
342
+ - `sessions.agent` records whether a session came from Claude Code, Codex, or Antigravity
343
343
  - `summaries.agent` records which agent produced the session summary
344
344
  - mirrored memories, plans, and tasks include `origin_agent`
345
- - SessionStart recall labels sources as `Claude Code` or `Codex`
345
+ - SessionStart recall labels sources as `Claude Code`, `Codex`, or `Antigravity`
346
346
 
347
- That means opening the same project in Claude Code and Codex does not create two isolated memory worlds. They recall the same project history while preserving the source of each memory. Grok can search, inspect, and update that same project memory through the linked skills and CLI commands.
347
+ That means opening the same project in Claude Code, Codex, and Google Antigravity does not create isolated memory worlds. They recall the same project history while preserving the source of each memory. Grok can search, inspect, and update that same project memory through the linked skills and CLI commands.
348
348
 
349
349
  ## Skills (Inside Claude Code, Codex, and Grok)
350
350
 
@@ -354,7 +354,7 @@ That means opening the same project in Claude Code and Codex does not create two
354
354
  | `/eagle-mem-overview` | Build a rich project briefing from README, entry points, and git history |
355
355
  | `/eagle-mem-memories` | View and search mirrored agent memories and plans |
356
356
  | `/eagle-mem-tasks` | TaskAware Compact Loop — break complex work into tasks that survive `/compact` |
357
- | `/eagle-mem-orchestrate` | Orchestrator/worker lane handoffs across Claude Code and Codex, with shared CLI visibility for Grok |
357
+ | `/eagle-mem-orchestrate` | Orchestrator/worker lane handoffs across Claude Code, Codex, Grok, and Google Antigravity |
358
358
 
359
359
  ## Data
360
360
 
package/architecture.html CHANGED
@@ -683,7 +683,7 @@
683
683
  <div class="brand">
684
684
  <span class="brand-label">Eagle Mem</span>
685
685
  <h1>Agent Architecture Tutorial</h1>
686
- <p>Technical architecture plus UX architecture for Claude Code, Codex, Grok, and future coding agents.</p>
686
+ <p>Technical architecture plus UX architecture for Claude Code, Codex, Grok, Google Antigravity, and future coding agents.</p>
687
687
  </div>
688
688
 
689
689
  <p class="nav-title">Start Here</p>
@@ -719,7 +719,7 @@
719
719
  <main id="main">
720
720
  <section class="hero" id="purpose">
721
721
  <div class="hero-inner">
722
- <p class="eyebrow">Architecture guide - technical + UX - updated 2026-05-22</p>
722
+ <p class="eyebrow">Architecture guide - technical + UX - updated 2026-05-26</p>
723
723
  <h2>Eagle Mem is a local memory and safety layer that makes AI coding agents start warmer, ship safer, and coordinate better.</h2>
724
724
  <p class="hero-summary">
725
725
  This tutorial explains the project from first principles. You do not need to know the codebase first. Read it like a guided tour: what problem Eagle Mem solves, how hooks move data through the system, how SQLite stores shared memory, and why the user experience is intentionally quiet until the agent needs help.
@@ -728,11 +728,11 @@
728
728
  <div class="hero-meta">
729
729
  <div class="meta-box">
730
730
  <strong>Runtime</strong>
731
- <span>Bash hooks, CLI scripts, SQLite/FTS5, jq, optional RTK.</span>
731
+ <span>Bash hooks, Python integrations, SQLite/FTS5, jq, optional RTK.</span>
732
732
  </div>
733
733
  <div class="meta-box">
734
734
  <strong>Agents</strong>
735
- <span>Claude Code and Codex with hooks; Grok through skills and CLI today.</span>
735
+ <span>Claude Code, Codex, and Google Antigravity with hooks; Grok via skills.</span>
736
736
  </div>
737
737
  <div class="meta-box">
738
738
  <strong>Core Promise</strong>
@@ -793,7 +793,7 @@
793
793
 
794
794
  <div class="callout">
795
795
  <h3>Compaction Survival is shared state</h3>
796
- <p><code>eagle-mem compaction</code> is not a Grok-only feature. It reads project-level state from SQLite: enriched summaries, durable tasks, stale tasks, active orchestration lanes, and recent durable updates. Claude Code and Codex have hook-backed automatic recovery around compact and clear events. Grok can use the same state through linked skills and CLI commands until native lifecycle hooks exist.</p>
796
+ <p><code>eagle-mem compaction</code> reads project-level state from SQLite: enriched summaries, durable tasks, stale tasks, active orchestration lanes, and recent durable updates. Claude Code, Codex, and Google Antigravity have hook-backed automatic recovery around compact and clear events. Grok can use the same state through linked skills and CLI commands.</p>
797
797
  </div>
798
798
 
799
799
  <h3>Vocabulary</h3>
@@ -862,7 +862,7 @@
862
862
  <text x="40" y="42" class="label">User Layer</text>
863
863
  <rect x="40" y="58" width="220" height="72" class="box-cyan"></rect>
864
864
  <text x="62" y="90">Developer</text>
865
- <text x="62" y="112" class="small">Works in Claude Code, Codex, or Grok</text>
865
+ <text x="62" y="112" class="small">Works in Claude, Codex, Grok, or Antigravity</text>
866
866
 
867
867
  <text x="40" y="178" class="label">Agent Layer</text>
868
868
  <rect x="40" y="194" width="220" height="78" class="box"></rect>
@@ -871,6 +871,12 @@
871
871
  <rect x="300" y="194" width="220" height="78" class="box"></rect>
872
872
  <text x="322" y="225">Codex</text>
873
873
  <text x="322" y="247" class="small">config.toml, hooks.json, AGENTS.md</text>
874
+ <rect x="560" y="194" width="220" height="78" class="box"></rect>
875
+ <text x="582" y="225">Grok</text>
876
+ <text x="582" y="247" class="small">skills link, grok-bootstrap</text>
877
+ <rect x="820" y="194" width="220" height="78" class="box"></rect>
878
+ <text x="842" y="225">Antigravity (AGY)</text>
879
+ <text x="842" y="247" class="small">google_antigravity_hook.py</text>
874
880
 
875
881
  <text x="40" y="320" class="label">Hook Runtime</text>
876
882
  <rect x="40" y="336" width="160" height="68" class="box-soft"></rect>
@@ -902,8 +908,12 @@
902
908
 
903
909
  <path d="M150,130 L150,190" class="arrow"></path>
904
910
  <path d="M260,232 L300,232" class="arrow"></path>
911
+ <path d="M520,232 L560,232" class="arrow"></path>
912
+ <path d="M780,232 L820,232" class="arrow"></path>
905
913
  <path d="M150,272 L150,330" class="arrow"></path>
906
914
  <path d="M410,272 L410,330" class="arrow"></path>
915
+ <path d="M670,272 L670,330" class="arrow"></path>
916
+ <path d="M870,272 L870,330" class="arrow"></path>
907
917
  <path d="M840,404 L735,462" class="arrow"></path>
908
918
  <path d="M660,404 L452,462" class="arrow"></path>
909
919
  <path d="M300,404 L182,462" class="arrow"></path>
@@ -964,7 +974,7 @@
964
974
  <div class="step-num">5</div>
965
975
  <div>
966
976
  <h3>Agent hooks are registered</h3>
967
- <p>Claude Code hooks are patched into <code>~/.claude/settings.json</code>. Codex hooks are registered in <code>~/.codex/hooks.json</code>, and <code>codex_hooks = true</code> is enabled in <code>~/.codex/config.toml</code>. Grok currently has skills and CLI access rather than hook registration.</p>
977
+ <p>Claude Code hooks are patched into <code>~/.claude/settings.json</code>. Codex hooks are registered in <code>~/.codex/hooks.json</code>. Google Antigravity SDK hooks are registered programmatically in <code>google_antigravity_hook.py</code> using native Python async hooks. Grok has skills and CLI access.</p>
968
978
  </div>
969
979
  </article>
970
980
 
@@ -972,7 +982,7 @@
972
982
  <div class="step-num">6</div>
973
983
  <div>
974
984
  <h3>Skills and instructions are linked</h3>
975
- <p>Eagle Mem skills are symlinked into each agent's skill directory. Claude receives <code>CLAUDE.md</code> summary instructions. Codex receives <code>AGENTS.md</code> clean-output memory instructions. Grok receives the same Eagle Mem skills under <code>~/.grok/skills</code> and can run <code>eagle-mem grok-bootstrap</code> for setup guidance.</p>
985
+ <p>Eagle Mem skills are symlinked into each agent's skill directory. Claude receives <code>CLAUDE.md</code> instructions. Codex receives <code>AGENTS.md</code> instructions. Google Antigravity SDK maps and mirrors standard brain planning artifacts (plans, tasks, walkthroughs). Grok receives skills under <code>~/.grok/skills</code>.</p>
976
986
  </div>
977
987
  </article>
978
988
  </div>
@@ -1015,7 +1025,7 @@
1015
1025
  <tr>
1016
1026
  <td><code>~/.eagle-mem/memory.db</code></td>
1017
1027
  <td>Single source of local memory</td>
1018
- <td>Stores shared state across Claude Code, Codex, Grok skills, compactions, and sessions.</td>
1028
+ <td>Stores shared state across Claude Code, Codex, Grok skills, Google Antigravity hooks, compactions, and sessions.</td>
1019
1029
  </tr>
1020
1030
  </tbody>
1021
1031
  </table>
@@ -1087,7 +1097,7 @@
1087
1097
  <p class="section-number">06 / Technical Architecture</p>
1088
1098
  <h2>The Agent Adapter Layer</h2>
1089
1099
  <p class="lead">
1090
- The project is agent-generic below the adapter layer. Claude Code and Codex have different config files, tool names, transcript formats, and output expectations, while Grok currently participates through skills and CLI commands. Eagle Mem normalizes each supported surface into the same project memory model.
1100
+ The project is agent-generic below the adapter layer. Claude Code, Codex, and Google Antigravity have direct lifecycle hook adapters, while Grok participates through skills and CLI commands. Eagle Mem normalizes each supported surface into the same project memory model.
1091
1101
  </p>
1092
1102
 
1093
1103
  <div class="grid-2">
@@ -1125,6 +1135,17 @@
1125
1135
  <span class="tag">tasks</span>
1126
1136
  </div>
1127
1137
  </article>
1138
+
1139
+ <article class="adapter-rule">
1140
+ <h3>Google Antigravity SDK adapter</h3>
1141
+ <p>Integrated programmatically via <code>integrations/google_antigravity_hook.py</code>. Connects Antigravity's async Python hook triggers directly to Eagle Mem's lifecycle events, enabling direct database writes and background curation/sync.</p>
1142
+ <div class="tag-row">
1143
+ <span class="tag">on_session_start</span>
1144
+ <span class="tag">pre_tool_call_decide</span>
1145
+ <span class="tag">post_tool_call</span>
1146
+ <span class="tag">on_compaction</span>
1147
+ </div>
1148
+ </article>
1128
1149
  </div>
1129
1150
 
1130
1151
  <h3>Normalization rules</h3>
@@ -1275,7 +1296,7 @@
1275
1296
  </tr>
1276
1297
  <tr>
1277
1298
  <td><code>agent_memories</code>, <code>agent_plans</code>, <code>agent_tasks</code></td>
1278
- <td>What durable agent artifacts should be shared across Claude Code and Codex?</td>
1299
+ <td>What durable agent artifacts should be shared across Claude Code, Codex, Grok, and Antigravity?</td>
1279
1300
  <td>PostToolUse, SessionEnd, skills, search CLI</td>
1280
1301
  </tr>
1281
1302
  <tr>
@@ -1464,7 +1485,7 @@
1464
1485
 
1465
1486
  <h3>Default routing</h3>
1466
1487
  <p>
1467
- Eagle Mem can route broad work to the opposite agent by default. A Codex coordinator can spawn Claude Code workers; a Claude Code coordinator can spawn Codex workers. The goal is not to make agents compete. The goal is to let each lane have one owner and one validation path.
1488
+ Eagle Mem can route broad work to different agents by default. For example, a Codex or Antigravity coordinator can spawn Claude Code or Grok workers; any agent can coordinate or execute worker lanes. The goal is not to make agents compete, but to let each lane have one owner and one validation path.
1468
1489
  </p>
1469
1490
 
1470
1491
  <pre><code># Agent-run protocol, not usually a user task
@@ -1476,7 +1497,7 @@ eagle-mem orchestrate handoff --write docs/handoff-context.md</code></pre>
1476
1497
 
1477
1498
  <h3>Why lanes matter for all agents</h3>
1478
1499
  <p>
1479
- Context windows end. Tools fail. A user may switch from Claude Code to Codex. A worker may finish while the coordinator is compacted. Lanes make this survivable because the state is outside any one transcript.
1500
+ Context windows end. Tools fail. A user may switch from Claude Code to Codex, Grok, or Antigravity. A worker may finish while the coordinator is compacted. Lanes make this survivable because the state is outside any one transcript.
1480
1501
  </p>
1481
1502
  </div>
1482
1503
  </section>
@@ -1492,7 +1513,7 @@ eagle-mem orchestrate handoff --write docs/handoff-context.md</code></pre>
1492
1513
  <div class="grid-2">
1493
1514
  <article class="principle">
1494
1515
  <h3>1. Stay in the agent's flow</h3>
1495
- <p>Users already live in Claude Code or Codex. Eagle Mem should not require them to open a dashboard before every task. Hooks inject context where the agent already is.</p>
1516
+ <p>Users already live in Claude Code, Codex, Grok, or Antigravity. Eagle Mem should not require them to open a dashboard before every task. Hooks/skills inject context where the agent already is.</p>
1496
1517
  </article>
1497
1518
  <article class="principle">
1498
1519
  <h3>2. Show up only when useful</h3>
@@ -1512,7 +1533,7 @@ eagle-mem orchestrate handoff --write docs/handoff-context.md</code></pre>
1512
1533
  </article>
1513
1534
  <article class="principle">
1514
1535
  <h3>6. Respect each agent's display model</h3>
1515
- <p>Claude can handle richer hook context. Codex should keep user-facing replies clean and let Stop capture summaries from normal prose.</p>
1536
+ <p>Claude and Antigravity can handle richer hook context. Codex and Grok should keep user-facing replies clean and let Turn Stop/Stop capture summaries from normal prose.</p>
1516
1537
  </article>
1517
1538
  </div>
1518
1539
  </div>
@@ -1583,7 +1604,7 @@ eagle-mem orchestrate handoff --write docs/handoff-context.md</code></pre>
1583
1604
  <p class="section-number">13 / Tutorial</p>
1584
1605
  <h2>Walkthrough: From Empty Memory To Safer Release</h2>
1585
1606
  <p class="lead">
1586
- This walkthrough explains how the system feels to a beginner. The same flow works whether the active agent is Claude Code or Codex.
1607
+ This walkthrough explains how the system feels to a beginner. The same flow works whether the active agent is Claude Code, Codex, Grok, or Antigravity.
1587
1608
  </p>
1588
1609
 
1589
1610
  <div class="step-list">
@@ -1641,7 +1662,7 @@ eagle-mem install</code></pre>
1641
1662
  <div class="step-num">7</div>
1642
1663
  <div>
1643
1664
  <h3>The turn ends with durable memory</h3>
1644
- <p>Stop saves what happened so the next session can recall it. Codex can keep the final reply clean; Claude can use richer summary fields when appropriate. Either way, the durable memory lands in SQLite.</p>
1665
+ <p>Stop saves what happened so the next session can recall it. Codex and Grok can keep the final reply clean; Claude and Antigravity can use richer summary fields/artifacts when appropriate. Either way, the durable memory lands in SQLite.</p>
1645
1666
  </div>
1646
1667
  </article>
1647
1668
  </div>
@@ -1661,7 +1682,7 @@ eagle-mem install</code></pre>
1661
1682
  <p class="section-number">14 / All-Agent Applicability</p>
1662
1683
  <h2>How To Add Another Agent</h2>
1663
1684
  <p class="lead">
1664
- The project supports Claude Code and Codex with lifecycle hooks, and Grok with skills plus CLI workflows. The architecture should scale to any coding agent that can run local hooks, wrapper scripts, or a skill-like command surface. The integration work should live at the edge, not inside the database model.
1685
+ The project natively supports Claude Code, Codex, and Google Antigravity with lifecycle hooks, and Grok with skills plus CLI workflows. The architecture should scale to any coding agent that can run local hooks, wrapper scripts, or a skill-like command surface. The integration work should live at the edge, not inside the database model.
1665
1686
  </p>
1666
1687
 
1667
1688
  <h3>Minimum viable adapter</h3>
@@ -1705,7 +1726,7 @@ eagle-mem install</code></pre>
1705
1726
  <h3>Adapter checklist</h3>
1706
1727
  <ol>
1707
1728
  <li>Register the agent's lifecycle events to call the installed scripts in <code>~/.eagle-mem/hooks/</code>.</li>
1708
- <li>Set <code>EAGLE_AGENT_SOURCE</code> to a stable value, such as <code>codex</code>, <code>claude-code</code>, or a future agent key.</li>
1729
+ <li>Set <code>EAGLE_AGENT_SOURCE</code> to a stable value, such as <code>codex</code>, <code>claude-code</code>, <code>grok</code>, <code>antigravity</code>, or a future agent key.</li>
1709
1730
  <li>Map the agent's shell and file tools into Eagle Mem's known categories.</li>
1710
1731
  <li>Pass enough JSON to identify <code>session_id</code>, <code>cwd</code>, tool name, tool input, and optional transcript path.</li>
1711
1732
  <li>Teach output formatting for the agent: compact JSON, plain additional context, or deny decisions.</li>
@@ -318,12 +318,8 @@ esac
318
318
 
319
319
  [ -z "$context" ] && [ -z "$updated_input" ] && exit 0
320
320
 
321
- if [ "$agent" = "codex" ]; then
322
- # Codex PreToolUse currently supports deny decisions, but not advisory
323
- # additionalContext or updatedInput. Deny paths above already returned JSON;
324
- # non-blocking reminders are delivered through SessionStart/UserPromptSubmit.
325
- exit 0
326
- fi
321
+ # Codex PreToolUse now natively receives both blocking decisions and advisory context.
322
+ # Removing the old early-exit to align Codex's pre-tool capabilities with Claude and Antigravity.
327
323
 
328
324
  if [ -n "$updated_input" ]; then
329
325
  jq -nc --arg ctx "$context" --argjson ui "$updated_input" \
@@ -0,0 +1,416 @@
1
+ """
2
+ Native Google Antigravity (AGY) SDK integration module for Eagle Mem.
3
+ Enables Antigravity agents to automatically record session summaries, observations,
4
+ and tasks, enforce release-boundary guardrails, and survive context compaction.
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import json
10
+ import asyncio
11
+ import logging
12
+ import inspect
13
+ from typing import Any, Dict, List, Optional
14
+
15
+ # Setup dedicated logger
16
+ logging.basicConfig(level=logging.INFO)
17
+ logger = logging.getLogger("eagle_mem.antigravity")
18
+
19
+ # --- Import and Mock Fallback for google-antigravity SDK ---
20
+ try:
21
+ from google.antigravity import types
22
+ from google.antigravity.hooks import hooks
23
+ HAS_ANTIGRAVITY = True
24
+ except ImportError:
25
+ HAS_ANTIGRAVITY = False
26
+
27
+ # Mock fallback to prevent import errors and allow standalone execution/testing
28
+ class MockHooksRegistry:
29
+ def on_session_start(self, func):
30
+ return func
31
+ def on_session_end(self, func):
32
+ return func
33
+ def pre_turn(self, func):
34
+ return func
35
+ def post_turn(self, func):
36
+ return func
37
+ def pre_tool_call_decide(self, func):
38
+ return func
39
+ def post_tool_call(self, func):
40
+ return func
41
+ def on_tool_error(self, func):
42
+ return func
43
+ def on_compaction(self, func):
44
+ return func
45
+ def on_interaction(self, func):
46
+ return func
47
+
48
+ async def inject_agent_context(self, context: str):
49
+ logger.info(f"[Mock SDK] Injected context:\n{context[:100]}...")
50
+
51
+ class MockTypes:
52
+ class HookResult:
53
+ def __init__(self, allow: bool = True):
54
+ self.allow = allow
55
+ class ToolCallResult:
56
+ def __init__(self, tool_call: Any, output: str):
57
+ self.tool_call = tool_call
58
+ self.output = output
59
+ class ToolCall:
60
+ def __init__(self, name: str, arguments: Dict[str, Any]):
61
+ self.name = name
62
+ self.arguments = arguments
63
+
64
+ hooks = MockHooksRegistry()
65
+ types = MockTypes()
66
+
67
+ # --- Asynchronous Subprocess Helpers ---
68
+
69
+ async def run_cmd_async(cmd: List[str]) -> str:
70
+ """Runs a shell command asynchronously and returns stdout."""
71
+ # Prioritize workspace-local bin/eagle-mem if running from workspace or if it exists in cwd or relative to this script
72
+ if cmd and cmd[0] == "eagle-mem":
73
+ local_paths = [
74
+ os.path.join(os.getcwd(), "bin", "eagle-mem"),
75
+ os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "bin", "eagle-mem")
76
+ ]
77
+ for path in local_paths:
78
+ if os.path.exists(path):
79
+ cmd = [path] + cmd[1:]
80
+ break
81
+
82
+ try:
83
+ proc = await asyncio.create_subprocess_exec(
84
+ *cmd,
85
+ stdout=asyncio.subprocess.PIPE,
86
+ stderr=asyncio.subprocess.PIPE
87
+ )
88
+ stdout, stderr = await proc.communicate()
89
+ if proc.returncode == 0:
90
+ return stdout.decode('utf-8', errors='ignore')
91
+ else:
92
+ err_msg = stderr.decode('utf-8', errors='ignore').strip()
93
+ logger.warning(f"Command {' '.join(cmd)} failed with code {proc.returncode}: {err_msg}")
94
+ return ""
95
+ except FileNotFoundError:
96
+ # Fallback if command still fails (e.g. if local_bin substitution didn't happen or is broken)
97
+ logger.error(f"Executable not found for: {cmd[0]}")
98
+ return ""
99
+ except Exception as e:
100
+ logger.error(f"Error running {' '.join(cmd)}: {e}")
101
+ return ""
102
+
103
+ async def run_hook_async(script_name: str, input_data: Dict[str, Any]) -> str:
104
+ """Runs an Eagle Mem bash hook script asynchronously, piping JSON via stdin."""
105
+ # Resolve the physical path of the hook script
106
+ # First check ~/.eagle-mem/hooks/, then fall back to workspace hooks/
107
+ home_dir = os.path.expanduser("~")
108
+ hook_path = os.path.join(home_dir, ".eagle-mem", "hooks", script_name)
109
+ if not os.path.exists(hook_path):
110
+ hook_path = os.path.join(os.getcwd(), "hooks", script_name)
111
+
112
+ if not os.path.exists(hook_path):
113
+ logger.error(f"Eagle Mem hook script not found: {script_name}")
114
+ return ""
115
+
116
+ try:
117
+ proc = await asyncio.create_subprocess_exec(
118
+ "bash", hook_path,
119
+ stdin=asyncio.subprocess.PIPE,
120
+ stdout=asyncio.subprocess.PIPE,
121
+ stderr=asyncio.subprocess.PIPE
122
+ )
123
+ input_json = json.dumps(input_data).encode('utf-8')
124
+ stdout, stderr = await proc.communicate(input=input_json)
125
+ if proc.returncode == 0:
126
+ return stdout.decode('utf-8', errors='ignore')
127
+ else:
128
+ err_msg = stderr.decode('utf-8', errors='ignore').strip()
129
+ logger.warning(f"Hook script {script_name} failed with code {proc.returncode}: {err_msg}")
130
+ return ""
131
+ except Exception as e:
132
+ logger.error(f"Error executing hook {script_name}: {e}")
133
+ return ""
134
+
135
+ # --- Utility Helpers ---
136
+
137
+ def get_session_id() -> str:
138
+ """Retrieves or generates a persistent session ID for the current context."""
139
+ # Use environment variables if present (matches Claude/Codex)
140
+ session_id = os.environ.get("EAGLE_SESSION_ID") or os.environ.get("SESSION_ID")
141
+ if not session_id:
142
+ # Generate a unique hex session ID
143
+ import uuid
144
+ session_id = f"agy-{uuid.uuid4().hex[:16]}"
145
+ return session_id
146
+
147
+ def map_tool_name(agy_name: str) -> str:
148
+ """Maps Google Antigravity SDK tool names to Eagle Mem canonical tool names."""
149
+ name = agy_name.lower()
150
+ if "command" in name or "bash" in name or "shell" in name:
151
+ return "Bash"
152
+ elif "read" in name or "view" in name:
153
+ return "Read"
154
+ elif "write" in name or "create" in name:
155
+ return "Write"
156
+ elif "edit" in name or "replace" in name or "patch" in name:
157
+ return "Edit"
158
+ return agy_name
159
+
160
+ # --- Eagle Mem Antigravity Hook Implementation ---
161
+
162
+ class EagleMemAntigravityHook:
163
+ """
164
+ Natively compatible Google Antigravity SDK lifecycle hooks class for Eagle Mem.
165
+ Translates and routes events directly to Eagle Mem's native bash scripts.
166
+ """
167
+ def __init__(self, agent_name: str = "antigravity"):
168
+ self.agent_name = agent_name
169
+
170
+ async def on_session_start(self):
171
+ """Fires when the agent session starts. Injects overview, memories, tasks, and history."""
172
+ logger.info("Eagle Mem Hook: Session starting. Syncing context...")
173
+ session_id = get_session_id()
174
+ cwd = os.getcwd()
175
+
176
+ input_data = {
177
+ "session_id": session_id,
178
+ "cwd": cwd,
179
+ "source": "startup",
180
+ "model": "gemini",
181
+ "agent": self.agent_name
182
+ }
183
+
184
+ # Execute session-start.sh via stdin
185
+ stdout = await run_hook_async("session-start.sh", input_data)
186
+ context_injected = False
187
+
188
+ if stdout.strip():
189
+ try:
190
+ output_json = json.loads(stdout)
191
+ context = output_json.get("hookSpecificOutput", {}).get("additionalContext", "")
192
+ if context.strip():
193
+ res = hooks.inject_agent_context(context)
194
+ if inspect.isawaitable(res):
195
+ await res
196
+ context_injected = True
197
+ logger.info("Eagle Mem Hook: Injected session briefing.")
198
+ except Exception as e:
199
+ logger.warning(f"Eagle Mem Hook: Failed to parse session-start JSON: {e}")
200
+
201
+ # Robust fallback if native sessionstart failed or returned empty
202
+ if not context_injected:
203
+ logger.info("Eagle Mem Hook: Running fallback search context...")
204
+ timeline_task = run_cmd_async(["eagle-mem", "search", "--timeline"])
205
+ overview_task = run_cmd_async(["eagle-mem", "search", "--overview"])
206
+ timeline, overview = await asyncio.gather(timeline_task, overview_task)
207
+
208
+ fallback_context = ""
209
+ if overview.strip():
210
+ fallback_context += f"=== Eagle Mem Project Overview ===\n{overview.strip()}\n\n"
211
+ if timeline.strip():
212
+ fallback_context += f"=== Eagle Mem Session Timeline ===\n{timeline.strip()}\n"
213
+
214
+ if fallback_context.strip():
215
+ res = hooks.inject_agent_context(fallback_context)
216
+ if inspect.isawaitable(res):
217
+ await res
218
+ logger.info("Eagle Mem Hook: Injected fallback context.")
219
+
220
+ async def pre_tool_call_decide(self, tool_call: Any) -> Any:
221
+ """Fires before a tool execution. Blocks dangerous tasks or injects co-edits/recalls."""
222
+ tool_name = getattr(tool_call, "name", "")
223
+ tool_args = getattr(tool_call, "arguments", getattr(tool_call, "args", {}))
224
+ if not isinstance(tool_args, dict):
225
+ tool_args = {}
226
+
227
+ mapped_tool = map_tool_name(tool_name)
228
+ session_id = get_session_id()
229
+ cwd = os.getcwd()
230
+
231
+ # Build stdin payload matching PreToolUse schema
232
+ tool_input = {}
233
+ if mapped_tool == "Bash":
234
+ cmd = tool_args.get("CommandLine", tool_args.get("command", ""))
235
+ tool_input["command"] = cmd
236
+ else:
237
+ fp = tool_args.get("AbsolutePath", tool_args.get("TargetFile", tool_args.get("file_path", tool_args.get("path", ""))))
238
+ tool_input["file_path"] = fp
239
+
240
+ input_data = {
241
+ "session_id": session_id,
242
+ "cwd": cwd,
243
+ "tool_name": mapped_tool,
244
+ "tool_input": tool_input,
245
+ "agent": self.agent_name
246
+ }
247
+
248
+ stdout = await run_hook_async("pre-tool-use.sh", input_data)
249
+ if not stdout.strip():
250
+ return types.HookResult(allow=True)
251
+
252
+ try:
253
+ output_json = json.loads(stdout)
254
+ specific_output = output_json.get("hookSpecificOutput", {})
255
+
256
+ # 1. Check for deny decisions (safety guards/release boundaries)
257
+ if specific_output.get("permissionDecision") == "deny":
258
+ reason = specific_output.get("permissionDecisionReason", "Blocked by Eagle Mem guardrail.")
259
+ # Print clearly to the user's console
260
+ print(f"\n\033[1;31m[Eagle Mem Blocked]\033[0m {reason}\n", file=sys.stderr, flush=True)
261
+ return types.HookResult(allow=False)
262
+
263
+ # 2. Check for advisory additionalContext (co-edits, stuck loops, decision recalls)
264
+ additional_context = specific_output.get("additionalContext", "")
265
+ if additional_context.strip():
266
+ res = hooks.inject_agent_context(additional_context)
267
+ if inspect.isawaitable(res):
268
+ await res
269
+ logger.info(f"Eagle Mem Hook: Injected pre-tool context.")
270
+
271
+ # 3. Check for updatedInput (RTK rewriting)
272
+ updated_input = specific_output.get("updatedInput", {})
273
+ if updated_input and mapped_tool == "Bash" and "command" in updated_input:
274
+ rewritten_cmd = updated_input["command"]
275
+ logger.info(f"Eagle Mem Hook: Rewrote command to: {rewritten_cmd}")
276
+ if hasattr(tool_call, "arguments") and isinstance(tool_call.arguments, dict):
277
+ if "CommandLine" in tool_call.arguments:
278
+ tool_call.arguments["CommandLine"] = rewritten_cmd
279
+ elif "command" in tool_call.arguments:
280
+ tool_call.arguments["command"] = rewritten_cmd
281
+ elif hasattr(tool_call, "args") and isinstance(tool_call.args, dict):
282
+ if "CommandLine" in tool_call.args:
283
+ tool_call.args["CommandLine"] = rewritten_cmd
284
+ elif "command" in tool_call.args:
285
+ tool_call.args["command"] = rewritten_cmd
286
+
287
+ except Exception as e:
288
+ logger.warning(f"Eagle Mem Hook: Failed to parse pre-tool JSON: {e}")
289
+
290
+ return types.HookResult(allow=True)
291
+
292
+ async def post_tool_call(self, tool_call_result: Any):
293
+ """Fires after a tool completes. Records observations and triggers curation in the background."""
294
+ tool_call = getattr(tool_call_result, "tool_call", None)
295
+ tool_name = getattr(tool_call, "name", "") if tool_call else ""
296
+ tool_args = getattr(tool_call, "arguments", getattr(tool_call, "args", {})) if tool_call else {}
297
+ if not isinstance(tool_args, dict):
298
+ tool_args = {}
299
+
300
+ mapped_tool = map_tool_name(tool_name)
301
+ session_id = get_session_id()
302
+ cwd = os.getcwd()
303
+
304
+ tool_input = {}
305
+ if mapped_tool == "Bash":
306
+ cmd = tool_args.get("CommandLine", tool_args.get("command", ""))
307
+ tool_input["command"] = cmd
308
+ else:
309
+ fp = tool_args.get("AbsolutePath", tool_args.get("TargetFile", tool_args.get("file_path", tool_args.get("path", ""))))
310
+ tool_input["file_path"] = fp
311
+
312
+ output_str = getattr(tool_call_result, "output", getattr(tool_call_result, "result", ""))
313
+ if not isinstance(output_str, str):
314
+ output_str = str(output_str)
315
+
316
+ input_data = {
317
+ "session_id": session_id,
318
+ "cwd": cwd,
319
+ "tool_name": mapped_tool,
320
+ "tool_input": tool_input,
321
+ "tool_response": {"stdout": output_str},
322
+ "agent": self.agent_name
323
+ }
324
+
325
+ # 1. Trigger post-tool-use.sh in background
326
+ asyncio.create_task(run_hook_async("post-tool-use.sh", input_data))
327
+
328
+ # 2. Concurrently run eagle-mem curate in background to index changes
329
+ asyncio.create_task(run_cmd_async(["eagle-mem", "curate"]))
330
+
331
+ async def post_turn(self, final_response: str):
332
+ """Fires after each response. Records observaciones and saves sessions in the background."""
333
+ session_id = get_session_id()
334
+ cwd = os.getcwd()
335
+
336
+ input_data = {
337
+ "session_id": session_id,
338
+ "cwd": cwd,
339
+ "last_assistant_message": final_response,
340
+ "agent": self.agent_name
341
+ }
342
+
343
+ # 1. Trigger Stop hook (stop.sh) in background to capture transcript/summary
344
+ asyncio.create_task(run_hook_async("stop.sh", input_data))
345
+
346
+ # 2. Concurrently trigger session save CLI in background
347
+ summary = final_response[:200] if final_response else ""
348
+ asyncio.create_task(run_cmd_async([
349
+ "eagle-mem", "session", "save",
350
+ "--summary", summary,
351
+ "--agent", self.agent_name
352
+ ]))
353
+
354
+ async def on_compaction(self, data: Any):
355
+ """Fires when context is compacted. Queries active tasks and injects them to survive compaction."""
356
+ logger.info("Eagle Mem Hook: Compaction event. Preserving active tasks...")
357
+
358
+ # Query active tasks from SQLite FTS5 index
359
+ tasks_text = await run_cmd_async(["eagle-mem", "tasks"])
360
+ if tasks_text.strip():
361
+ compaction_banner = (
362
+ f"\n=== Eagle Mem: Context Compaction Task Survival ===\n"
363
+ f"The following active tasks have survived compaction:\n"
364
+ f"{tasks_text.strip()}\n"
365
+ f"==================================================\n"
366
+ )
367
+ res = hooks.inject_agent_context(compaction_banner)
368
+ if inspect.isawaitable(res):
369
+ await res
370
+ logger.info("Eagle Mem Hook: Tasks injected for compaction survival.")
371
+
372
+ async def on_session_end(self):
373
+ """Fires when the agent session closes. Cleans up runtime lock files."""
374
+ logger.info("Eagle Mem Hook: Session ending. Pruning locks...")
375
+ session_id = get_session_id()
376
+ cwd = os.getcwd()
377
+
378
+ input_data = {
379
+ "session_id": session_id,
380
+ "cwd": cwd,
381
+ "agent": self.agent_name
382
+ }
383
+
384
+ # 1. Trigger session-end.sh in background
385
+ asyncio.create_task(run_hook_async("session-end.sh", input_data))
386
+
387
+ # 2. Concurrently trigger prune CLI in background
388
+ asyncio.create_task(run_cmd_async(["eagle-mem", "prune"]))
389
+
390
+ # --- Expose Bound Methods as Global Functions ---
391
+
392
+ _global_hook = EagleMemAntigravityHook()
393
+
394
+ @hooks.on_session_start
395
+ async def on_session_start():
396
+ await _global_hook.on_session_start()
397
+
398
+ @hooks.pre_tool_call_decide
399
+ async def pre_tool_call_decide(tool_call: Any) -> Any:
400
+ return await _global_hook.pre_tool_call_decide(tool_call)
401
+
402
+ @hooks.post_tool_call
403
+ async def post_tool_call(tool_call_result: Any):
404
+ await _global_hook.post_tool_call(tool_call_result)
405
+
406
+ @hooks.post_turn
407
+ async def post_turn(final_response: str):
408
+ await _global_hook.post_turn(final_response)
409
+
410
+ @hooks.on_compaction
411
+ async def on_compaction(data: Any):
412
+ await _global_hook.on_compaction(data)
413
+
414
+ @hooks.on_session_end
415
+ async def on_session_end():
416
+ await _global_hook.on_session_end()
@@ -3,13 +3,27 @@
3
3
  # Eagle Mem — Codex hook registration helpers
4
4
  # Shared by install.sh, update.sh, and uninstall.sh
5
5
  # ═══════════════════════════════════════════════════════════
6
+ # ═══════════════════════════════════════════════════════════
6
7
  [ -n "${_EAGLE_CODEX_HOOKS_LOADED:-}" ] && return 0
7
8
  _EAGLE_CODEX_HOOKS_LOADED=1
8
9
 
10
+ eagle_codex_backup_file() {
11
+ local file="$1"
12
+ [ -f "$file" ] || return 0
13
+ if [ -z "${_EAGLE_CODEX_BACKUP_DONE:-}" ]; then
14
+ local timestamp
15
+ timestamp=$(date +%Y%m%d%H%M%S)
16
+ cp "$file" "${file}.bak.${timestamp}" 2>/dev/null || true
17
+ _EAGLE_CODEX_BACKUP_DONE=1
18
+ fi
19
+ }
20
+
9
21
  eagle_enable_codex_hooks() {
10
22
  local config="$EAGLE_CODEX_CONFIG"
11
23
  mkdir -p "$(dirname "$config")"
12
24
 
25
+ eagle_codex_backup_file "$config"
26
+
13
27
  if [ ! -f "$config" ]; then
14
28
  cat > "$config" << 'TOML'
15
29
  [features]
@@ -71,6 +85,7 @@ eagle_patch_codex_hook() {
71
85
  script_path="${script_path%\"}"
72
86
 
73
87
  mkdir -p "$(dirname "$hooks_file")"
88
+ eagle_codex_backup_file "$hooks_file"
74
89
  if [ ! -f "$hooks_file" ]; then
75
90
  printf '{"hooks":{}}\n' > "$hooks_file"
76
91
  chmod 600 "$hooks_file" 2>/dev/null || true
@@ -171,6 +186,8 @@ eagle_remove_codex_hooks() {
171
186
  [ -f "$hooks_file" ] || return 1
172
187
  command -v jq &>/dev/null || return 1
173
188
 
189
+ eagle_codex_backup_file "$hooks_file"
190
+
174
191
  local tmp
175
192
  tmp=$(mktemp)
176
193
  jq '
package/lib/common.sh CHANGED
@@ -771,6 +771,7 @@ eagle_agent_source() {
771
771
  case "$agent" in
772
772
  codex|openai-codex) echo "codex" ;;
773
773
  claude|claude-code|cloud-code) echo "claude-code" ;;
774
+ antigravity*|google-antigravity*|google_antigravity*) echo "antigravity" ;;
774
775
  *)
775
776
  if [ -n "${CODEX_THREAD_ID:-}" ] || [ -n "${CODEX_CI:-}" ] || [ -n "${CODEX_MANAGED_BY_NPM:-}" ]; then
776
777
  echo "codex"
@@ -789,10 +790,15 @@ eagle_agent_source_from_json() {
789
790
  return
790
791
  fi
791
792
 
792
- local transcript_path turn_id tool_name
793
+ local transcript_path turn_id tool_name agent_field
793
794
  transcript_path=$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null)
794
795
  turn_id=$(printf '%s' "$input" | jq -r '.turn_id // empty' 2>/dev/null)
795
796
  tool_name=$(printf '%s' "$input" | jq -r '.tool_name // empty' 2>/dev/null)
797
+ agent_field=$(printf '%s' "$input" | jq -r '.agent // empty' 2>/dev/null)
798
+
799
+ case "$agent_field" in
800
+ antigravity*) echo "antigravity"; return ;;
801
+ esac
796
802
 
797
803
  case "$transcript_path" in
798
804
  "$HOME/.codex/"*|*/.codex/*) echo "codex"; return ;;
@@ -807,6 +813,7 @@ eagle_agent_source_from_json() {
807
813
  eagle_agent_label() {
808
814
  case "${1:-$(eagle_agent_source)}" in
809
815
  codex) echo "Codex" ;;
816
+ antigravity*) echo "Antigravity" ;;
810
817
  *) echo "Claude Code" ;;
811
818
  esac
812
819
  }
@@ -27,6 +27,16 @@ eagle_posttool_mirror_writes() {
27
27
  eagle_capture_agent_plan "$fp" "$session_id" "$project" "$agent"
28
28
  fi
29
29
  ;;
30
+ */brain/*/implementation_plan.md)
31
+ if [ -f "$fp" ]; then
32
+ eagle_capture_agent_plan "$fp" "$session_id" "$project" "$agent"
33
+ fi
34
+ ;;
35
+ */brain/*/task.md|*/brain/*/walkthrough.md)
36
+ if [ -f "$fp" ]; then
37
+ eagle_capture_agent_memory "$fp" "$session_id" "$project" "$agent"
38
+ fi
39
+ ;;
30
40
  esac
31
41
  fi
32
42
  ;;
package/lib/hooks.sh CHANGED
@@ -4,11 +4,26 @@
4
4
  # Shared by install.sh and update.sh
5
5
  # ═══════════════════════════════════════════════════════════
6
6
 
7
+ # ═══════════════════════════════════════════════════════════
8
+
9
+ eagle_backup_file() {
10
+ local file="$1"
11
+ [ -f "$file" ] || return 0
12
+ if [ -z "${_EAGLE_BACKUP_DONE:-}" ]; then
13
+ local timestamp
14
+ timestamp=$(date +%Y%m%d%H%M%S)
15
+ cp "$file" "${file}.bak.${timestamp}" 2>/dev/null || true
16
+ _EAGLE_BACKUP_DONE=1
17
+ fi
18
+ }
19
+
7
20
  eagle_clean_hook_entries() {
8
21
  local settings="$1"
9
22
  local event="$2"
10
23
  local command="$3"
11
24
 
25
+ eagle_backup_file "$settings"
26
+
12
27
  local tmp
13
28
  tmp=$(mktemp)
14
29
  jq --arg cmd "$command" \
@@ -23,6 +38,8 @@ eagle_patch_hook() {
23
38
  local command="$4"
24
39
  local description="${5:-}"
25
40
 
41
+ eagle_backup_file "$settings"
42
+
26
43
  # Check both command AND matcher to avoid skipping entries with different matchers
27
44
  # (e.g. PreToolUse with "Bash" vs "Read" matcher using the same script)
28
45
  local match_query
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eagle-mem",
3
- "version": "4.10.1",
4
- "description": "Shared memory, release guardrails, RTK token protection, and worker lanes for Claude Code, Codex, and Grok",
3
+ "version": "4.10.2",
4
+ "description": "Shared memory, release guardrails, RTK token protection, and worker lanes for Claude Code, Codex, Grok, and Google Antigravity",
5
5
  "bin": {
6
6
  "eagle-mem": "bin/eagle-mem"
7
7
  },
@@ -13,7 +13,8 @@
13
13
  "db/",
14
14
  "skills/",
15
15
  "docs/",
16
- "architecture.html"
16
+ "architecture.html",
17
+ "integrations/"
17
18
  ],
18
19
  "keywords": [
19
20
  "claude-code",
@@ -26,22 +26,44 @@ eagle_ok "Grok environment detected ($EAGLE_GROK_DIR)"
26
26
 
27
27
  # Check skills
28
28
  skill_count=0
29
+ broken_links=0
29
30
  if [ -d "$EAGLE_GROK_SKILLS_DIR" ]; then
30
- skill_count=$(find "$EAGLE_GROK_SKILLS_DIR" -maxdepth 1 -name "eagle-mem-*" -type d 2>/dev/null | wc -l | tr -d ' ')
31
+ for link in "$EAGLE_GROK_SKILLS_DIR"/eagle-mem-*; do
32
+ if [ -L "$link" ] && [ ! -e "$link" ]; then
33
+ broken_links=$((broken_links + 1))
34
+ elif [ -d "$link" ]; then
35
+ skill_count=$((skill_count + 1))
36
+ fi
37
+ done
38
+ fi
39
+
40
+ if [ "$broken_links" -gt 0 ]; then
41
+ eagle_warn "Detected $broken_links broken or invalid Grok skill symlinks!"
31
42
  fi
32
43
 
33
- if [ "$skill_count" -gt 0 ]; then
44
+ if [ "$skill_count" -gt 0 ] && [ "$broken_links" -eq 0 ]; then
34
45
  eagle_ok "Grok skills installed ($skill_count eagle-mem-* skills)"
35
46
  else
36
- eagle_warn "No eagle-mem skills found in $EAGLE_GROK_SKILLS_DIR"
47
+ if [ "$broken_links" -gt 0 ]; then
48
+ echo ""
49
+ eagle_info "Repairing broken skill symlinks now..."
50
+ fi
37
51
  if [ -d "$PACKAGE_DIR/skills" ]; then
38
52
  echo ""
39
- if eagle_confirm "Link Eagle Mem skills into ~/.grok/skills/ now?"; then
53
+ if eagle_confirm "Link/repair Eagle Mem skills into ~/.grok/skills/ now?"; then
40
54
  mkdir -p "$EAGLE_GROK_SKILLS_DIR"
41
55
  for skill_dir in "$PACKAGE_DIR"/skills/*/; do
42
56
  [ ! -d "$skill_dir" ] && continue
43
57
  skill_name=$(basename "$skill_dir")
44
58
  dst="$EAGLE_GROK_SKILLS_DIR/$skill_name"
59
+
60
+ # Protect custom user folders with a timestamped backup
61
+ if [ -d "$dst" ] && [ ! -L "$dst" ]; then
62
+ backup_dst="${dst}.bak.$(date +%Y%m%d%H%M%S)"
63
+ eagle_warn "Custom directory found at $dst. Backing up to $(basename "$backup_dst")..."
64
+ mv "$dst" "$backup_dst"
65
+ fi
66
+
45
67
  [ -L "$dst" ] && rm "$dst"
46
68
  ln -sf "$skill_dir" "$dst"
47
69
  eagle_ok "Linked: $skill_name"
@@ -195,13 +195,14 @@ echo ""
195
195
  echo -e " ${BOLD}Installing Eagle Mem...${RESET}"
196
196
  echo ""
197
197
 
198
- mkdir -p "$EAGLE_MEM_DIR"/{hooks,lib,db,scripts}
198
+ mkdir -p "$EAGLE_MEM_DIR"/{hooks,lib,db,scripts,integrations}
199
199
 
200
200
  cp "$PACKAGE_DIR"/hooks/*.sh "$EAGLE_MEM_DIR/hooks/"
201
201
  cp "$PACKAGE_DIR"/lib/*.sh "$EAGLE_MEM_DIR/lib/"
202
202
  cp "$PACKAGE_DIR"/db/*.sh "$EAGLE_MEM_DIR/db/"
203
203
  cp "$PACKAGE_DIR"/db/*.sql "$EAGLE_MEM_DIR/db/"
204
204
  cp "$PACKAGE_DIR"/scripts/*.sh "$EAGLE_MEM_DIR/scripts/" 2>/dev/null
205
+ cp -r "$PACKAGE_DIR"/integrations/* "$EAGLE_MEM_DIR/integrations/" 2>/dev/null || true
205
206
 
206
207
  chmod +x "$EAGLE_MEM_DIR"/hooks/*.sh
207
208
  chmod +x "$EAGLE_MEM_DIR"/db/migrate.sh
@@ -410,6 +411,7 @@ eagle_kv "Hooks:" "$EAGLE_MEM_DIR/hooks/"
410
411
  [ "$claude_found" = true ] && eagle_kv "Claude settings:" "$SETTINGS"
411
412
  [ "$codex_found" = true ] && eagle_kv "Codex hooks:" "$EAGLE_CODEX_HOOKS"
412
413
  [ "$grok_found" = true ] && eagle_kv "Grok skills:" "$EAGLE_GROK_SKILLS_DIR"
414
+ eagle_kv "Antigravity Hook:" "$EAGLE_MEM_DIR/integrations/google_antigravity_hook.py"
413
415
 
414
416
  echo ""
415
417
  if [ "$grok_found" = true ]; then
@@ -419,3 +421,9 @@ if [ "$claude_found" = true ] || [ "$codex_found" = true ]; then
419
421
  eagle_dim "Start a new Claude Code or Codex session — Eagle Mem will activate automatically."
420
422
  fi
421
423
  echo ""
424
+ eagle_info "Google Antigravity SDK Integration:"
425
+ eagle_dim " To use Eagle Mem inside your Python Antigravity agents, simply import and register the hook:"
426
+ echo ""
427
+ eagle_dim " from integrations.google_antigravity_hook import EagleMemAntigravityHook"
428
+ eagle_dim " config = LocalAgentConfig(hooks=EagleMemAntigravityHook().get_hooks())"
429
+ echo ""
@@ -636,7 +636,7 @@ memories_sync() {
636
636
 
637
637
  if [ "$existing_hash" = "$new_hash" ] && { [ -z "$mem_project" ] || [ "$existing_project" = "$mem_project" ]; }; then
638
638
  mem_skipped=$((mem_skipped + 1))
639
- continue
639
+ return 0
640
640
  fi
641
641
 
642
642
  eagle_capture_agent_memory "$memfile" "" "$mem_project" "claude-code"
@@ -762,6 +762,84 @@ EOF
762
762
  eagle_kv "Tasks:" "$task_synced synced, $task_skipped unchanged"
763
763
  echo ""
764
764
 
765
+ # ─── Sync brain planning artifacts ───────────────────
766
+ eagle_info "Scanning for agent brain planning artifacts..."
767
+ echo ""
768
+
769
+ local artifact_synced=0
770
+ local artifact_skipped=0
771
+
772
+ # Determine brain paths to scan
773
+ local brain_paths=(
774
+ "$HOME/.claude/brain"
775
+ "$HOME/.codex/brain"
776
+ "$HOME/.gemini/antigravity/brain"
777
+ )
778
+
779
+ for bdir in "${brain_paths[@]}"; do
780
+ [ ! -d "$bdir" ] && continue
781
+
782
+ # 1. Sync plans (implementation_plan.md)
783
+ while IFS= read -r -d '' planfile; do
784
+ [ ! -f "$planfile" ] && continue
785
+
786
+ local existing_hash
787
+ existing_hash=$(eagle_db "SELECT content_hash FROM agent_plans WHERE file_path = '$(eagle_sql_escape "$planfile")';")
788
+ local new_hash
789
+ new_hash=$(shasum -a 256 "$planfile" | awk '{print $1}')
790
+
791
+ if [ "$existing_hash" = "$new_hash" ]; then
792
+ artifact_skipped=$((artifact_skipped + 1))
793
+ continue
794
+ fi
795
+
796
+ # Determine agent name based on brain folder path
797
+ local origin_agent="claude-code"
798
+ [[ "$planfile" == *".codex"* ]] && origin_agent="codex"
799
+ [[ "$planfile" == *"antigravity"* ]] && origin_agent="antigravity"
800
+
801
+ local artifact_project="$project"
802
+ [ -z "$artifact_project" ] && artifact_project=$(eagle_project_from_cwd "$(pwd)")
803
+
804
+ eagle_capture_agent_plan "$planfile" "" "$artifact_project" "$origin_agent"
805
+ artifact_synced=$((artifact_synced + 1))
806
+ local ptitle
807
+ ptitle=$(awk '/^# /{print; exit}' "$planfile" | sed 's/^# //')
808
+ [ -z "$ptitle" ] && ptitle="Implementation Plan"
809
+ eagle_ok "Mirrored plan [$(eagle_agent_label "$origin_agent")]: $ptitle"
810
+ done < <(find "$bdir" -name "implementation_plan.md" -print0 2>/dev/null)
811
+
812
+ # 2. Sync tasks and walkthroughs (task.md, walkthrough.md)
813
+ while IFS= read -r -d '' memfile; do
814
+ [ ! -f "$memfile" ] && continue
815
+
816
+ local existing_hash
817
+ existing_hash=$(eagle_db "SELECT content_hash FROM agent_memories WHERE file_path = '$(eagle_sql_escape "$memfile")';")
818
+ local new_hash
819
+ new_hash=$(shasum -a 256 "$memfile" | awk '{print $1}')
820
+
821
+ if [ "$existing_hash" = "$new_hash" ]; then
822
+ artifact_skipped=$((artifact_skipped + 1))
823
+ continue
824
+ fi
825
+
826
+ # Determine agent name based on brain folder path
827
+ local origin_agent="claude-code"
828
+ [[ "$memfile" == *".codex"* ]] && origin_agent="codex"
829
+ [[ "$memfile" == *"antigravity"* ]] && origin_agent="antigravity"
830
+
831
+ local artifact_project="$project"
832
+ [ -z "$artifact_project" ] && artifact_project=$(eagle_project_from_cwd "$(pwd)")
833
+
834
+ eagle_capture_agent_memory "$memfile" "" "$artifact_project" "$origin_agent"
835
+ artifact_synced=$((artifact_synced + 1))
836
+ eagle_ok "Mirrored $(basename "$memfile") [$(eagle_agent_label "$origin_agent")]"
837
+ done < <(find "$bdir" \( -name "task.md" -o -name "walkthrough.md" \) -print0 2>/dev/null)
838
+ done
839
+
840
+ eagle_kv "Brain Artifacts:" "$artifact_synced synced, $artifact_skipped unchanged"
841
+ echo ""
842
+
765
843
  # ─── Backfill project names ──────────────────────────
766
844
  eagle_info "Resolving project names from agent transcripts..."
767
845
 
@@ -164,8 +164,9 @@ save_session() {
164
164
  case "$agent" in
165
165
  codex|openai-codex) agent="codex" ;;
166
166
  claude|claude-code|cloud-code) agent="claude-code" ;;
167
+ antigravity*|google-antigravity*|google_antigravity*) agent="antigravity" ;;
167
168
  *)
168
- eagle_err "--agent must be codex or claude-code"
169
+ eagle_err "--agent must be codex, claude-code, or antigravity"
169
170
  exit 1
170
171
  ;;
171
172
  esac
@@ -99,6 +99,13 @@ else
99
99
  eagle_info "Statusline integration not present or not auto-removable"
100
100
  fi
101
101
 
102
+ # ─── Remove integration files ─────────────────────────────
103
+
104
+ if [ -d "$EAGLE_MEM_DIR/integrations" ]; then
105
+ rm -rf "$EAGLE_MEM_DIR/integrations"
106
+ eagle_ok "Antigravity integration files removed"
107
+ fi
108
+
102
109
  # ─── Remove skill symlinks ────────────────────────────────
103
110
 
104
111
  if [ -d "$EAGLE_SKILLS_DIR" ]; then