diff --git a/README.md b/README.md
index faf357bc..5d43d949 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
# CodeGraph
-### Supercharge Claude Code, Cursor, Codex, OpenCode, and Hermes Agent with Semantic Code Intelligence
+### Supercharge Claude Code, Cursor, Codex, OpenCode, Hermes Agent, and Antigravity with Semantic Code Intelligence
**~35% cheaper · ~70% fewer tool calls · 100% local**
@@ -19,6 +19,7 @@
[](#supported-agents)
[](#supported-agents)
[](#supported-agents)
+[](#supported-agents)
@@ -41,7 +42,7 @@ npx @colbymchenry/codegraph # zero-install, or:
npm i -g @colbymchenry/codegraph
```
-CodeGraph bundles its own runtime — nothing to compile, no native build, works the same everywhere. The interactive installer auto-configures your agent(s) — Claude Code, Cursor, Codex CLI, opencode, Hermes Agent.
+CodeGraph bundles its own runtime — nothing to compile, no native build, works the same everywhere. The interactive installer auto-configures your agent(s) — Claude Code, Cursor, Codex CLI, opencode, Hermes Agent, and Antigravity.
### Initialize Projects
@@ -171,7 +172,7 @@ npx @colbymchenry/codegraph
```
The installer will:
-- Ask which agent(s) to configure — auto-detects installed ones from: **Claude Code**, **Cursor**, **Codex CLI**, **opencode**, **Hermes Agent**
+- Ask which agent(s) to configure — auto-detects installed ones from: **Claude Code**, **Cursor**, **Codex CLI**, **opencode**, **Hermes Agent**, **Antigravity**
- Prompt to install `codegraph` on your PATH (so agents can launch the MCP server)
- Ask whether configs apply to all your projects or just this one
- Write each chosen agent's MCP server config + an instructions file (e.g. `CLAUDE.md`, `.cursor/rules/codegraph.mdc`, `~/.codex/AGENTS.md`)
@@ -197,7 +198,7 @@ codegraph install --print-config codex # print snippet, no file wr
### 2. Restart Your Agent
-Restart your agent (Claude Code / Cursor / Codex CLI / opencode / Hermes Agent) for the MCP server to load.
+Restart your agent (Claude Code / Cursor / Codex CLI / opencode / Hermes Agent / Antigravity) for the MCP server to load.
### 3. Initialize Projects
@@ -534,7 +535,7 @@ MIT
-**Made for AI coding agents — Claude Code, Cursor, Codex CLI, opencode, and Hermes Agent**
+**Made for AI coding agents — Claude Code, Cursor, Codex CLI, opencode, Hermes Agent, and Antigravity**
[Report Bug](https://github.com/colbymchenry/codegraph/issues) · [Request Feature](https://github.com/colbymchenry/codegraph/issues)
diff --git a/__tests__/installer-targets.test.ts b/__tests__/installer-targets.test.ts
index 59e869e2..34cda9c4 100644
--- a/__tests__/installer-targets.test.ts
+++ b/__tests__/installer-targets.test.ts
@@ -494,7 +494,6 @@ describe('Installer targets — partial-state idempotency', () => {
expect(legacy.mcpServers.codegraph).toBeUndefined();
expect(legacy.mcpServers.other).toBeDefined();
});
-
// ---- Legacy auto-sync hook cleanup ----
// Pre-0.8 installs wrote `codegraph mark-dirty` / `sync-if-dirty`
// hooks to settings.json. Both subcommands were removed from the CLI,
@@ -608,6 +607,46 @@ describe('Installer targets — partial-state idempotency', () => {
// Both events emptied → the whole `hooks` object is removed.
expect(after.hooks).toBeUndefined();
});
+
+ it('antigravity: install writes mcp_config.json with correct format', () => {
+ const target = getTarget('antigravity')!;
+ target.install('global', { autoAllow: true });
+
+ const configPath = path.join(tmpHome, '.gemini', 'config', 'mcp_config.json');
+ expect(fs.existsSync(configPath)).toBe(true);
+
+ const content = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
+ expect(content.mcpServers).toBeDefined();
+ expect(content.mcpServers.codegraph).toBeDefined();
+ expect(content.mcpServers.codegraph.command).toBe('codegraph');
+ expect(content.mcpServers.codegraph.args).toEqual(['serve', '--mcp']);
+ expect(content.mcpServers.codegraph.env).toEqual({});
+ expect(content.mcpServers.codegraph.type).toBeUndefined();
+
+ const agentsMd = path.join(tmpHome, '.gemini', 'GEMINI.md');
+ expect(fs.existsSync(agentsMd)).toBe(true);
+ });
+
+ it('antigravity: uninstall removes only mcpServers.codegraph, preserving siblings', () => {
+ const target = getTarget('antigravity')!;
+ const configPath = path.join(tmpHome, '.gemini', 'config', 'mcp_config.json');
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
+
+ const initialConfig = {
+ mcpServers: {
+ other: { command: 'other-command' }
+ }
+ };
+ fs.writeFileSync(configPath, JSON.stringify(initialConfig, null, 2) + '\n');
+
+ target.install('global', { autoAllow: true });
+ target.uninstall('global');
+
+ const content = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
+ expect(content.mcpServers).toBeDefined();
+ expect(content.mcpServers.other).toEqual({ command: 'other-command' });
+ expect(content.mcpServers.codegraph).toBeUndefined();
+ });
});
describe('Installer targets — registry', () => {
@@ -617,6 +656,7 @@ describe('Installer targets — registry', () => {
expect(getTarget('codex')?.id).toBe('codex');
expect(getTarget('opencode')?.id).toBe('opencode');
expect(getTarget('hermes')?.id).toBe('hermes');
+ expect(getTarget('antigravity')?.id).toBe('antigravity');
expect(getTarget('not-a-real-target')).toBeUndefined();
});
diff --git a/package-lock.json b/package-lock.json
index 36c592b1..ff5f07e8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1431,7 +1431,6 @@
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
diff --git a/src/bin/codegraph.ts b/src/bin/codegraph.ts
index 6bc63b3f..9e325b26 100644
--- a/src/bin/codegraph.ts
+++ b/src/bin/codegraph.ts
@@ -1611,7 +1611,7 @@ program
*/
program
.command('install')
- .description('Install codegraph MCP server into one or more agents (Claude Code, Cursor, Codex CLI, opencode, Hermes Agent)')
+ .description('Install codegraph MCP server into one or more agents (Claude Code, Cursor, Codex CLI, opencode, Hermes Agent, antigravity)')
.option('-t, --target ', 'Target agent(s): comma-separated ids, or "auto"|"all"|"none". Default: prompt')
.option('-l, --location ', 'Install location: "global" or "local". Default: prompt')
.option('-y, --yes', 'Non-interactive: defaults to --location=global --target=auto, auto-allow on')
diff --git a/src/installer/targets/antigravity.ts b/src/installer/targets/antigravity.ts
new file mode 100644
index 00000000..800450ea
--- /dev/null
+++ b/src/installer/targets/antigravity.ts
@@ -0,0 +1,210 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import * as os from 'os';
+import {
+ AgentTarget,
+ DetectionResult,
+ InstallOptions,
+ Location,
+ WriteResult,
+} from './types';
+import {
+ jsonDeepEqual,
+ readJsonFile,
+ removeMarkedSection,
+ replaceOrAppendMarkedSection,
+ writeJsonFile,
+} from './shared';
+import {
+ CODEGRAPH_SECTION_END,
+ CODEGRAPH_SECTION_START,
+ INSTRUCTIONS_TEMPLATE,
+} from '../instructions-template';
+
+/**
+ * Returns the path to the antigravity configuration directory.
+ * Under ~/.gemini/config
+ */
+function configDir(): string {
+ return path.join(os.homedir(), '.gemini', 'config');
+}
+
+/**
+ * Returns the path to the antigravity MCP configuration JSON file.
+ * Under ~/.gemini/config/mcp_config.json
+ */
+function mcpConfigPath(): string {
+ return path.join(configDir(), 'mcp_config.json');
+}
+
+/**
+ * Returns the path to the GEMINI.md instruction file for antigravity.
+ * Under ~/.gemini/GEMINI.md
+ */
+function instructionsPath(): string {
+ return path.join(os.homedir(), '.gemini', 'GEMINI.md');
+}
+
+/**
+ * Builds the canonical MCP configuration object for antigravity.
+ * Excludes the "type" field and includes "env: {}" as requested.
+ */
+function buildAntigravityMcpConfig(): { command: string; args: string[]; env: Record } {
+ return {
+ command: 'codegraph',
+ args: ['serve', '--mcp'],
+ env: {},
+ };
+}
+
+/**
+ * Writes the antigravity MCP entry into ~/.gemini/config/mcp_config.json.
+ * Preserves sibling servers and creates directory/file if they do not exist.
+ */
+function writeMcpEntry(): WriteResult['files'][number] {
+ const file = mcpConfigPath();
+ const dir = path.dirname(file);
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
+
+ const existing = readJsonFile(file);
+ const before = existing.mcpServers?.codegraph;
+ const after = buildAntigravityMcpConfig();
+
+ if (jsonDeepEqual(before, after)) {
+ return { path: file, action: 'unchanged' };
+ }
+
+ const action: 'created' | 'updated' = before ? 'updated' : (fs.existsSync(file) ? 'updated' : 'created');
+ if (!existing.mcpServers) existing.mcpServers = {};
+ existing.mcpServers.codegraph = after;
+ writeJsonFile(file, existing);
+ return { path: file, action };
+}
+
+/**
+ * Writes the markdown agent instructions into ~/.gemini/config/AGENTS.md.
+ * Appends or replaces the section with the CodeGraph markers.
+ */
+function writeInstructionsEntry(): WriteResult['files'][number] {
+ const file = instructionsPath();
+ const dir = path.dirname(file);
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
+
+ const action = replaceOrAppendMarkedSection(
+ file,
+ INSTRUCTIONS_TEMPLATE,
+ CODEGRAPH_SECTION_START,
+ CODEGRAPH_SECTION_END,
+ );
+ const mapped: 'created' | 'updated' | 'unchanged' =
+ action === 'created' ? 'created'
+ : action === 'unchanged' ? 'unchanged'
+ : 'updated';
+ return { path: file, action: mapped };
+}
+
+class AntigravityTarget implements AgentTarget {
+ readonly id = 'antigravity' as const;
+ readonly displayName = 'antigravity';
+ readonly docsUrl = 'https://antigravity.google/download';
+
+ /**
+ * Returns true if the location is supported.
+ * antigravity target only supports global installation.
+ */
+ supportsLocation(loc: Location): boolean {
+ return loc === 'global';
+ }
+
+ /**
+ * Detects whether antigravity target has been installed and configured.
+ */
+ detect(loc: Location): DetectionResult {
+ if (loc !== 'global') {
+ return { installed: false, alreadyConfigured: false };
+ }
+ const mcpPath = mcpConfigPath();
+ const config = readJsonFile(mcpPath);
+ const alreadyConfigured = !!config.mcpServers?.codegraph;
+ const installed = fs.existsSync(path.join(os.homedir(), '.gemini')) || fs.existsSync(mcpPath);
+ return { installed, alreadyConfigured, configPath: mcpPath };
+ }
+
+ /**
+ * Installs codegraph MCP configurations and instructions for antigravity.
+ */
+ install(loc: Location, _opts: InstallOptions): WriteResult {
+ if (loc !== 'global') {
+ return {
+ files: [],
+ notes: ['antigravity has no project-local config — re-run with --location=global to install.'],
+ };
+ }
+ const files: WriteResult['files'] = [];
+
+ files.push(writeMcpEntry());
+ files.push(writeInstructionsEntry());
+
+ return {
+ files,
+ notes: ['Restart antigravity for MCP changes to take effect.'],
+ };
+ }
+
+ /**
+ * Uninstalls codegraph configurations and instructions for antigravity.
+ */
+ uninstall(loc: Location): WriteResult {
+ if (loc !== 'global') return { files: [] };
+ const files: WriteResult['files'] = [];
+
+ const mcpPath = mcpConfigPath();
+ const config = readJsonFile(mcpPath);
+ if (config.mcpServers?.codegraph) {
+ delete config.mcpServers.codegraph;
+ if (Object.keys(config.mcpServers).length === 0) {
+ delete config.mcpServers;
+ }
+ writeJsonFile(mcpPath, config);
+ files.push({ path: mcpPath, action: 'removed' });
+ } else {
+ files.push({ path: mcpPath, action: 'not-found' });
+ }
+
+ const instr = instructionsPath();
+ const action = removeMarkedSection(instr, CODEGRAPH_SECTION_START, CODEGRAPH_SECTION_END);
+ files.push({ path: instr, action });
+
+ return { files };
+ }
+
+ /**
+ * Prints the configuration snippet for manual pasting.
+ */
+ printConfig(loc: Location): string {
+ if (loc !== 'global') {
+ return '# antigravity has no project-local config — use --location=global.\n';
+ }
+ const target = mcpConfigPath();
+ const snippet = JSON.stringify(
+ {
+ mcpServers: {
+ codegraph: buildAntigravityMcpConfig(),
+ },
+ },
+ null,
+ 2
+ );
+ return `# Add to ${target}\n\n${snippet}\n`;
+ }
+
+ /**
+ * Returns list of paths created/modified by this target.
+ */
+ describePaths(loc: Location): string[] {
+ if (loc !== 'global') return [];
+ return [mcpConfigPath(), instructionsPath()];
+ }
+}
+
+export const antigravityTarget: AgentTarget = new AntigravityTarget();
diff --git a/src/installer/targets/registry.ts b/src/installer/targets/registry.ts
index 0091ab64..102ecd54 100644
--- a/src/installer/targets/registry.ts
+++ b/src/installer/targets/registry.ts
@@ -13,6 +13,7 @@ import { cursorTarget } from './cursor';
import { codexTarget } from './codex';
import { opencodeTarget } from './opencode';
import { hermesTarget } from './hermes';
+import { antigravityTarget } from './antigravity';
export const ALL_TARGETS: readonly AgentTarget[] = Object.freeze([
claudeTarget,
@@ -20,6 +21,7 @@ export const ALL_TARGETS: readonly AgentTarget[] = Object.freeze([
codexTarget,
opencodeTarget,
hermesTarget,
+ antigravityTarget,
]);
export function getTarget(id: string): AgentTarget | undefined {
diff --git a/src/installer/targets/types.ts b/src/installer/targets/types.ts
index 290f13ce..158a1e8d 100644
--- a/src/installer/targets/types.ts
+++ b/src/installer/targets/types.ts
@@ -19,7 +19,7 @@ export type Location = 'global' | 'local';
* lookup. New targets add a value here when they're added to the
* registry. Keep these short and lowercase.
*/
-export type TargetId = 'claude' | 'cursor' | 'codex' | 'opencode' | 'hermes';
+export type TargetId = 'claude' | 'cursor' | 'codex' | 'opencode' | 'hermes' | 'antigravity';
/**
* Result of `target.detect(location)`.