From 631d24bed5dd035ac2141afe3c929322ce05aeec Mon Sep 17 00:00:00 2001
From: Bet4 <0xbet4@gmail.com>
Date: Sun, 14 Jun 2026 14:41:41 +0800
Subject: [PATCH] feat: add support for Antigravity CLI sessions
---
DESIGN.md | 5 +-
README.md | 4 +-
docs/spool-positioning.md | 6 +-
packages/app/src/main/acp.ts | 8 +-
packages/app/src/main/index.ts | 6 +-
packages/app/src/renderer/App.tsx | 2 +
.../src/renderer/components/AiAnswerCard.tsx | 2 +-
.../renderer/components/FragmentResults.tsx | 2 +-
.../src/renderer/components/SettingsPanel.tsx | 7 +-
.../app/src/renderer/i18n/locales/de.json | 2 +-
.../app/src/renderer/i18n/locales/en.json | 2 +-
.../app/src/renderer/i18n/locales/fr.json | 2 +-
.../app/src/renderer/i18n/locales/ko.json | 2 +-
.../src/renderer/lib/compose-from-session.ts | 1 +
packages/app/src/shared/resumeCommand.test.ts | 2 +
packages/app/src/shared/resumeCommand.ts | 1 +
packages/app/src/shared/sessionSources.ts | 6 +
packages/cli/src/commands/list.ts | 4 +-
packages/cli/src/commands/search.ts | 4 +-
packages/core/README.md | 4 +-
packages/core/src/db/db.ts | 1 +
packages/core/src/db/migration-v1-v3.test.ts | 2 +-
packages/core/src/db/migration-v5.test.ts | 2 +-
packages/core/src/db/queries.ts | 2 +
packages/core/src/index.ts | 1 +
packages/core/src/parsers/antigravity.test.ts | 205 ++++++++++++++++++
packages/core/src/parsers/antigravity.ts | 193 +++++++++++++++++
packages/core/src/sync/source-paths.ts | 42 +++-
packages/core/src/sync/syncer.test.ts | 2 +
packages/core/src/sync/syncer.ts | 14 +-
packages/core/src/sync/watcher.test.ts | 5 +-
packages/core/src/sync/watcher.ts | 4 +-
packages/core/src/types.ts | 3 +-
packages/landing/pages/blog/hello-spool.md | 2 +-
.../landing/pages/docs/guides/data-sources.md | 1 +
packages/landing/pages/docs/installation.md | 2 +-
packages/landing/pages/docs/quick-start.md | 4 +-
.../pages/docs/reference/configuration.md | 1 +
packages/landing/pages/index.server.ts | 2 +-
packages/redact/src/detectors.ts | 2 +-
packages/share-kit/src/lib/types.ts | 2 +-
skills/spool/SKILL.md | 6 +-
42 files changed, 522 insertions(+), 48 deletions(-)
create mode 100644 packages/core/src/parsers/antigravity.test.ts
create mode 100644 packages/core/src/parsers/antigravity.ts
diff --git a/DESIGN.md b/DESIGN.md
index 39d1ea37..55177554 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -1,7 +1,7 @@
# Design System — Spool
## Product Context
-- **What this is:** A local AI session library — an Electron macOS app that collects, organizes, and lets you revisit every Claude Code, Codex, and Gemini session you've ever had.
+- **What this is:** A local AI session library — an Electron macOS app that collects, organizes, and lets you revisit every Claude Code, Codex, Gemini, Antigravity, and OpenCode session you've ever had.
- **Who it's for:** Developers who think with AI daily and have accumulated hundreds of sessions across multiple tools. The persona is overwhelmed by the archive itself, not only by re-explaining context.
- **Space/industry:** Developer productivity / local-first tooling. Peers: Raycast, Spotlight, Obsidian, DevonThink — but none of them treat AI sessions as first-class library items.
- **Project type:** macOS Electron app — sidebar + main pane shell, the shape of a library client.
@@ -89,6 +89,7 @@ Only currently-supported agent sources are listed. New sources arrive via the da
| Claude Code | `#C26A4E` | `#E89A7C` |
| Codex CLI | `#4A9670` | `#7CC9A2` |
| Gemini | `#5887D0` | `#8AB0E5` |
+| Antigravity | `#6B5CA5` | `#9B8FD0` |
| OpenCode | `#8A6F3D` | `#C9A761` |
### Semantic States
@@ -282,5 +283,5 @@ In list contexts (Library Home, Project View, search results), trust the surroun
| 2026-05-08 | Warm-tuned status colors replace Tailwind defaults | `green-400 / amber-400 / red-400` were the only un-tuned colors in the system. Replaced with warm green `#6BAF6B`, warm amber `#E4A640`, terracotta `#C95A4F` so status reads as part of the same palette. |
| 2026-05-08 | Page title type added (20px) | Library Home and Settings need a real h1 — previous scale topped at sidebar wordmark 16px, leaving the home pane labelless. |
| 2026-05-08 | First-person rule softened from "all metadata" to "where it adds signal" | Literal "You discussed this · Mar 15" prefix on every row was repetitive once a user had hundreds of sessions. Library context already conveys ownership; reserve first-person for empty states, detail headers, and confirmations. |
-| 2026-05-08 | Source badge list trimmed to active agents only | Twitter / GitHub / YouTube / ChatGPT were carryover from the connector era. Spool ships only Claude Code / Codex CLI / Gemini today; new sources arrive via the daemon and get a row when shipped, not preemptively. |
+| 2026-05-08 | Source badge list trimmed to active agents only | Twitter / GitHub / YouTube / ChatGPT were carryover from the connector era. Spool ships only Claude Code / Codex CLI / Gemini / Antigravity today; new sources arrive via the daemon and get a row when shipped, not preemptively. |
| 2026-05-26 | Retire the "icons only 12/14/16/20, stroke 1.5" rule — describe reality instead | The 2026-05-08 lock never held: the renderer actually uses 11/12/13/14 (13 & 14 dominant) at strokes 1.6–1.8 (1.6 most common, 1.5 a minority). The aspirational whitelist was actively misleading new work into picking sizes that clashed with adjacent icons. Replaced with a role-based working set + a "match adjacent icons" rule. Sizes/strokes are now chosen for local consistency, not global uniformity. |
diff --git a/README.md b/README.md
index 56c0a37f..ae7b7305 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Your local AI session library.
-Spool collects every Claude Code, Codex CLI, Gemini CLI, and OpenCode session you've ever had into a sidebar of projects you can browse, pin, and revisit. Press ⌘K to search across the whole archive.
+Spool collects every Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, and OpenCode session you've ever had into a sidebar of projects you can browse, pin, and revisit. Press ⌘K to search across the whole archive.
> **Early stage.** Spool is under active development — expect rough edges. Feedback, bug reports, and ideas are very welcome via [Issues](https://github.com/paperboytm/spool/issues) or [Discord](https://discord.gg/aqeDxQUs5E).
@@ -29,7 +29,7 @@ pnpm build
Spool turns the pile of AI sessions sitting on your disk into a browsable library.
- **Library shell** — sidebar of projects (derived from working-dir paths across agents) and a main pane that shows recent + pinned sessions for whatever you've selected
-- **Session indexing** — watches Claude/Codex/Gemini session dirs and OpenCode's SQLite database in real time, including profile-based paths like `~/.claude-profiles/*/projects`, `~/.codex-profiles/*/sessions`, Gemini's project temp dirs under `~/.gemini/tmp/*/chats`, and `~/.local/share/opencode/opencode.db`
+- **Session indexing** — watches Claude/Codex/Gemini/Antigravity session dirs and OpenCode's SQLite database in real time, including profile-based paths like `~/.claude-profiles/*/projects`, `~/.codex-profiles/*/sessions`, Gemini/Antigravity project temp dirs under `~/.gemini/tmp/*/chats` and `~/.gemini/antigravity-cli/brain/`, and `~/.local/share/opencode/opencode.db`
- **Pin** — keep important sessions on top of their project and on the global Library Home
- **⌘K search** — fast full-text search scoped to All or the current project; AI mode synthesizes answers across fragments
- **Agent search** — a `/spool` skill inside Claude Code (and any ACP agent) feeds matching fragments back into your conversation
diff --git a/docs/spool-positioning.md b/docs/spool-positioning.md
index 151eab09..e9619a82 100644
--- a/docs/spool-positioning.md
+++ b/docs/spool-positioning.md
@@ -2,7 +2,7 @@
> **The missing search engine for your own AI sessions.**
-Search your `[Claude Code sessions · Codex history · Gemini chats]` — locally.
+Search your `[Claude Code sessions · Codex history · Gemini chats · Antigravity transcripts]` — locally.
---
@@ -10,11 +10,11 @@ Search your `[Claude Code sessions · Codex history · Gemini chats]` — locall
### Your coding agent is already the best search engine you have.
-Spool lets Claude Code, Codex, Gemini CLI, and any coding agent search your past sessions from a single search box.
+Spool lets Claude Code, Codex, Gemini CLI, Antigravity CLI, and any coding agent search your past sessions from a single search box.
### Every agent session, indexed automatically.
-Spool watches `~/.claude/`, `~/.codex/`, and Gemini CLI's `~/.gemini/tmp/*/chats` in real time. Every conversation you have with Claude Code, Codex, or Gemini CLI — searchable the moment it's written.
+Spool watches `~/.claude/`, `~/.codex/`, Gemini CLI's `~/.gemini/tmp/*/chats`, and Antigravity CLI's `~/.gemini/antigravity-cli/brain/` in real time. Every conversation you have with Claude Code, Codex, Gemini CLI, or Antigravity CLI — searchable the moment it's written.
### Context that flows back in.
diff --git a/packages/app/src/main/acp.ts b/packages/app/src/main/acp.ts
index a93459f7..12335117 100644
--- a/packages/app/src/main/acp.ts
+++ b/packages/app/src/main/acp.ts
@@ -201,7 +201,7 @@ function ensureAgentSearchCwd(): string {
* the Spool-authored session write.
*/
function agentIdToSource(agentId: string): SessionSource | null {
- if (agentId === 'claude' || agentId === 'codex' || agentId === 'gemini' || agentId === 'opencode') return agentId
+ if (agentId === 'claude' || agentId === 'codex' || agentId === 'gemini' || agentId === 'antigravity' || agentId === 'opencode') return agentId
return null
}
@@ -873,12 +873,12 @@ export class AcpManager {
// after stripping the prelude only the bare query remains as the first
// user message — clean derived title, clean FTS, clean session detail.
const systemBody = [
- 'You have access to a local knowledge base called Spool that indexes the user\'s AI coding sessions (Claude Code, Codex CLI, Gemini CLI, OpenCode).',
+ 'You have access to a local knowledge base called Spool that indexes the user\'s AI coding sessions (Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode).',
'',
'The database is at ~/.spool/spool.db (SQLite with FTS5). You can query it directly with the `sqlite3` CLI.',
'',
'── Schema ──',
- ' sources(id, name TEXT, base_path TEXT) -- "claude", "codex", "gemini", or "opencode"',
+ ' sources(id, name TEXT, base_path TEXT) -- "claude", "codex", "gemini", "antigravity", or "opencode"',
' projects(id, source_id, slug, display_path, display_name, last_synced)',
' sessions(id, project_id, source_id, session_uuid TEXT, title TEXT, started_at TEXT, ended_at TEXT, message_count INT, has_tool_use INT)',
' messages(id, session_id, source_id, role TEXT, content_text TEXT, timestamp TEXT, tool_names TEXT)',
@@ -893,7 +893,7 @@ export class AcpManager {
'',
'Important:',
'- Interpret the user\'s intent and decide what to search. Don\'t just match their exact words.',
- '- If the user names a specific source (claude/codex/gemini/opencode), only return results from that source unless they explicitly ask for cross-source search.',
+ '- If the user names a specific source (claude/codex/gemini/antigravity/opencode), only return results from that source unless they explicitly ask for cross-source search.',
'- For cross-source questions, first identify the relevant sources, then query each source separately, confirm hits or no-hits per source, and only then merge them into one answer.',
'- For temporal queries ("what did I do recently"), use explicit date filters and be conservative when comparing times across different sources.',
'- You may run multiple queries to find relevant information.',
diff --git a/packages/app/src/main/index.ts b/packages/app/src/main/index.ts
index ff3ec1b4..9682e20c 100644
--- a/packages/app/src/main/index.ts
+++ b/packages/app/src/main/index.ts
@@ -802,7 +802,7 @@ ipcMain.handle('spool:search', (_e, { query, limit = 10, source, onlyPinned, ide
if (cached) return cached
}
- const sessionSource = source === 'claude' || source === 'codex' || source === 'gemini' || source === 'opencode'
+ const sessionSource = source === 'claude' || source === 'codex' || source === 'gemini' || source === 'antigravity' || source === 'opencode'
? source
: undefined
const results = searchFragments(db, query, {
@@ -824,7 +824,7 @@ ipcMain.handle('spool:search-preview', (_e, { query, limit = 5, source }: { quer
const cached = searchCache.get(cacheKey)
if (cached) return cached
- const sessionSource = source === 'claude' || source === 'codex' || source === 'gemini' || source === 'opencode'
+ const sessionSource = source === 'claude' || source === 'codex' || source === 'gemini' || source === 'antigravity' || source === 'opencode'
? source
: undefined
const fragments = searchSessionPreview(db, query, {
@@ -983,11 +983,11 @@ ipcMain.handle('spool:force-resync-session', (_e, { sessionUuid }: { sessionUuid
ipcMain.handle('spool:resume-cli', (_e, { sessionUuid, source, cwd }: { sessionUuid: string; source: string; cwd?: string }) => {
try {
+ const session = getSessionWithMessages(db, sessionUuid)?.session
const command = getSessionResumeCommand(source, sessionUuid)
if (!command) {
return { ok: false, error: `Session source "${source}" cannot be resumed from the CLI.` }
}
- const session = getSessionWithMessages(db, sessionUuid)?.session
const resumeCwd = session
? resolveResumeWorkingDirectory(session)
: resolveResumeWorkingDirectory({
diff --git a/packages/app/src/renderer/App.tsx b/packages/app/src/renderer/App.tsx
index 126475d4..fb488d07 100644
--- a/packages/app/src/renderer/App.tsx
+++ b/packages/app/src/renderer/App.tsx
@@ -907,6 +907,7 @@ export default function App() {
claudeCount={status?.claudeSessions ?? null}
codexCount={status?.codexSessions ?? null}
geminiCount={status?.geminiSessions ?? null}
+ antigravityCount={status?.antigravitySessions ?? null}
opencodeCount={status?.opencodeSessions ?? null}
themeEditor={themeEditor}
onThemeEditorChange={setThemeEditor}
@@ -1103,6 +1104,7 @@ export default function App() {
claudeCount={status?.claudeSessions ?? null}
codexCount={status?.codexSessions ?? null}
geminiCount={status?.geminiSessions ?? null}
+ antigravityCount={status?.antigravitySessions ?? null}
opencodeCount={status?.opencodeSessions ?? null}
themeEditor={themeEditor}
onThemeEditorChange={setThemeEditor}
diff --git a/packages/app/src/renderer/components/AiAnswerCard.tsx b/packages/app/src/renderer/components/AiAnswerCard.tsx
index 99014f33..81216339 100644
--- a/packages/app/src/renderer/components/AiAnswerCard.tsx
+++ b/packages/app/src/renderer/components/AiAnswerCard.tsx
@@ -109,7 +109,7 @@ export default function AiAnswerCard({ answer, streaming, agentName, sources, er
)}
{/* CTA — only shown when a resume target is wired (i.e. agent has a
- source we persisted a session row for: claude/codex/gemini/opencode). */}
+ source we persisted a session row for: claude/codex/gemini/antigravity/opencode). */}
{!streaming && answer && onResume && (