Skip to content

Commit cf4dcb8

Browse files
jgravelleclaude
andcommitted
v1.108.88 — Antigravity (Google) install target (#307, phase 1)
First-class onboarding for Antigravity, which follows the Gemini CLI contract. - install antigravity / install --all / init / uninstall / install-status wired. MCP registration into ~/.gemini/settings.json rides the existing json_patch client path (Antigravity is detected when ~/.gemini exists; "antigravity" added to _AGENT_ALIASES). Skill bundle -> ~/.gemini/antigravity/skills/. - New cli/antigravity.py owns the Gemini-family paths + skill install/uninstall/ status. cli/skills.py refactored to a directory-keyed core (_install_skill_at / _uninstall_skill_at / _skill_status_at) shared by the Claude and Antigravity bundles; Claude skill return strings byte-identical. - install_status reports skills.antigravity; README/CLAUDE.md/CHANGELOG updated. Scope = PRD phase 1 (MCP + skills). The AfterTool context-enrichment hook is a later phase; #307 stays open pending a real-Antigravity end-to-end check (unit tests can't prove the live channel). New tests/test_antigravity_install.py (13). Full suite 4885 passed / 10 skipped. No INDEX_VERSION bump. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent defef44 commit cf4dcb8

10 files changed

Lines changed: 315 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,36 @@
22

33
All notable changes to jcodemunch-mcp are documented here.
44

5+
## [1.108.88] - 2026-06-30 - Antigravity (Google) install target (#307)
6+
7+
First-class onboarding for Google's Antigravity agent, which follows the Gemini
8+
CLI configuration contract.
9+
10+
### Added
11+
12+
- **`jcodemunch-mcp install antigravity`** (and `install --all` / `init`
13+
auto-detection / `install-status`). Antigravity is detected when `~/.gemini/`
14+
exists. Two artifacts:
15+
- **MCP registration** into `~/.gemini/settings.json` under the top-level
16+
`mcpServers` object — the same shape every other JSON client uses, so it
17+
rides the existing patch path.
18+
- **Skill bundle** written to `~/.gemini/antigravity/skills/jcodemunch/SKILL.md`
19+
(the same tier-aware bundle as the Claude skill).
20+
- `install-status` / `--json` now reports the Antigravity skill alongside the
21+
Claude global/project skills.
22+
- `uninstall` removes the Antigravity MCP entry and skill (preserving any
23+
user-authored skill at that path).
24+
25+
New `cli/antigravity.py` owns the Antigravity-specific paths; `cli/skills.py`
26+
gains a directory-keyed core (`_install_skill_at` / `_uninstall_skill_at` /
27+
`_skill_status_at`) shared by the Claude and Antigravity bundles (no behavior
28+
change to the Claude skill). New `tests/test_antigravity_install.py` (13). No
29+
INDEX_VERSION bump.
30+
31+
> Scope note: this is the MCP + skills layer (PRD phase 1). The AfterTool
32+
> context-enrichment hook is a later phase. Live end-to-end confirmation in an
33+
> Antigravity session is still pending before #307 is closed.
34+
535
## [1.108.87] - 2026-06-30 - License v1.1: tighten redistribution & attribution terms
636

737
Dual-Use License updated to **v1.1**. The non-commercial grant previously

CLAUDE.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# jcodemunch-mcp — Project Brief
22

33
## Current State
4+
- **Version:** 1.108.88 — Antigravity (Google) install target (#307). Antigravity follows the Gemini CLI contract: MCP servers in `~/.gemini/settings.json` under a top-level `mcpServers` object (same shape as every other json_patch client), skills under `~/.gemini/antigravity/skills/`. So MCP registration rides the existing path: `_detect_clients()` adds an `MCPClient("Antigravity", ~/.gemini/settings.json, "json_patch")` when `~/.gemini` exists, and `"antigravity"` is in `_AGENT_ALIASES` → `install antigravity` / `install --all` / `init` / `uninstall` / `install-status` all work. New `cli/antigravity.py` owns the Antigravity paths + skill install (`install_antigravity_skill`/`uninstall_antigravity_skill`/`antigravity_skill_status`). `cli/skills.py` refactored: new directory-keyed core (`_install_skill_at`/`_uninstall_skill_at`/`_skill_status_at`) shared by Claude + Antigravity bundles — Claude skill behavior/return-strings byte-identical (existing tests pass). `run_init` installs the Antigravity skill when `antigravity_present()`; `install_status` reports it under `skills.antigravity`. **Scope = PRD phase 1 (MCP + skills only); the AfterTool context-enrichment hook is a later phase, and #307 stays OPEN pending a real-Antigravity end-to-end confirmation (unit tests can't prove the live channel — verification asymmetry).** New `tests/test_antigravity_install.py` (13). NO INDEX_VERSION bump. Files: `cli/antigravity.py` (new), `cli/skills.py`, `cli/init.py`, `server.py` (install help). PRD: `docs/prd-antigravity-hooks.md`. Clean-room competitive response (see memory `reference_competitor_gitnexus`).
5+
- **Versions 1.108.85–1.108.87** (all 2026-06-30): **.85** install-mechanism-aware `watch` hint (`watch_extra_install_command()` → pipx inject / uv tool install / uvx --with) + migration-warning de-spam (`_MIGRATION_SCHEMA_WARNED` warn-once per repo) — #357 follow-up @zakblacki. **.86** `watch-all` prints a steady-state line (Ctrl+C / `watch-install`) + per-repo "Now watching … (idle until you edit a file)" so the post-index silence isn't read as a hang. **.87** License v1.1: non-commercial use/copy/modify stay free but redistribution narrowed (no registry republish, no rename/rebrand, no false-authorship, no name/marks) — response to the AnimAIOS `animamunch` PyPI fork; see memory `project_animamunch_fork`.
46
- **Version:** 1.108.84 — Install-mechanism-aware `upgrade` (#357, reported by @zakblacki on a pipx install). `jcodemunch-mcp upgrade` ran `sys.executable -m pip install -U` blindly; pipx/uv venvs ship NO `pip` module → `No module named pip`, pip exited non-zero, and the command **bailed before refreshing hooks**. Compounding it: the startup version-drift warning (`server.py`) told the user to run `jcodemunch-mcp upgrade` to clear the stale-hook nag — the exact pip-less-failing command — so it never cleared. Fix (rewrote `cli/upgrade.py`): new `detect_install_mechanism()` (path/env heuristic, no subprocess) → `(mechanism, upgrade_command)` for pip/pipx/uv/uvx/venv. `_pip_available()` gates the in-process `pip install -U`: present → runs as before (a genuine pip *failure* now refreshes hooks anyway + preserves the non-zero rc, was: skip-and-bail); **absent → does NOT shell out to a foreign package manager** (honors jjg's stated "detect then tell, don't guess-and-run" stance from the issue thread), prints the exact command (`pipx upgrade` / `uv tool upgrade`), and refreshes hooks in-process via `init --hooks` (pip-free, stamps `last_init_version.txt` so the nag clears). The nag warning now leads with `init --hooks`. NO INDEX_VERSION bump. New `tests/test_v1_108_84.py` (11). Files: `cli/upgrade.py` (rewrite), `server.py` (warning text). Side issues answered in #357 reply (not bugs): `.pack/nodejs` migration warning = stale starter-pack index; `find_dead_code` `framework_warning` inflated dead-code % on a Node project because its entry-point heuristic looks for `main.py`/`app.py` (pass `entry_point_patterns` or reindex); real-time freshness = `watch-all`. See [[project_jmunch_console]].
57
- **Version:** 1.108.83 — Tame `watch-all` CPU under WSL (#356, reported by @Blainexi). `watch-all` pegged 15-30% CPU non-stop on WSL. NOT a busy loop: **`watchfiles` auto-enables polling whenever it detects WSL** (inotify unreliable across the boundary, confirmed in watchfiles docs), and its default 300ms poll re-stats the whole watched tree several times/sec — multiplied across every indexed repo. `DefaultFilter` drops `node_modules`/`.git` *events* but the polling walk still stats them (structural cost). Fix: the `awatch` call now passes `poll_delay_ms=_watch_poll_delay_ms()` (resolves `JCODEMUNCH_WATCH_POLL_DELAY_MS` → `WATCHFILES_POLL_DELAY_MS` → `DEFAULT_WATCH_POLL_DELAY_MS=1000`; non-positive/garbage → default); ignored when native FS events are used (no-op off WSL). Plus a one-time WSL startup hint (`_is_wsl()`) naming the two levers: raise the poll delay, or set `WATCHFILES_FORCE_POLLING=false` for Linux-filesystem repos to use native inotify (~0 idle CPU); `/mnt/*` repos need polling. NO INDEX_VERSION bump. New `tests/test_v1_108_83.py` (11); `test_watch_all.py`/`test_watcher_lock.py` green. Files: `watcher.py`, `watch_all.py`. See [[project_jmunch_console]].
68
- **Version:** 1.108.82 — Exclude `org_savings.db` from `list_repos`. The team-SKU org-rollup store (`org_savings.db`, written by `org/store.py`) sits in `~/.code-index/` next to per-repo index `.db` files, but `_NON_REPO_DB_FILES` only excluded `telemetry.db` → `list_repos` enumerated it as a phantom `local/org_savings` repo (sym 0, empty source_root, display==repo_id). In the jMunch Console it showed an un-removable card; `delete-index local/org_savings` failed (no matching `local-org_savings.db` index → non-zero exit), which the Console surfaced as the misleading "needs jcodemunch-mcp >= 1.108.50". Fix: `_NON_REPO_DB_FILES = frozenset({"telemetry.db", "org_savings.db"})` (1-line). NO INDEX_VERSION bump. New `tests/test_telemetry_db_skip.py::test_list_repos_skips_org_savings_db`; storage/sqlite_store suites green. Files: `storage/sqlite_store.py`. Console-side companion: the Console's delete-failure message now surfaces jcm's real error instead of the hard-coded version hint (jmunch-console). See [[project_jmunch_console]], [[project_org_rollup_sku]].
@@ -97,7 +99,8 @@ src/jcodemunch_mcp/
9799
agent_selector.py # Complexity scoring + model routing (off/manual/auto); default provider batting orders
98100
cli/
99101
init.py # `jcodemunch-mcp init` — one-command onboarding (client detection, config patching, CLAUDE.md, Cursor rules, Windsurf rules, hooks); --demo flag. v1.105.1: `install <agent>` / `uninstall` / `install-status` verbs. v1.107.0: `--skills` flag on install, skills block in install_status report
100-
skills.py # v1.107.0: Claude Agent Skill bundle writer. _build_skill_content() composes YAML frontmatter + tier-filtered tool-usage decision tree. install_claude_skill / uninstall_claude_skill / skill_status. Lives at ~/.claude/skills/jcodemunch/SKILL.md (global) or ./.claude/skills/jcodemunch/SKILL.md (project). Reuses _filter_policy_for_tools from init.py for tier awareness
102+
skills.py # v1.107.0: Claude Agent Skill bundle writer. _build_skill_content() composes YAML frontmatter + tier-filtered tool-usage decision tree. install_claude_skill / uninstall_claude_skill / skill_status. Lives at ~/.claude/skills/jcodemunch/SKILL.md (global) or ./.claude/skills/jcodemunch/SKILL.md (project). Reuses _filter_policy_for_tools from init.py for tier awareness. v1.108.88: directory-keyed core (_install_skill_at / _uninstall_skill_at / _skill_status_at) shared with the Antigravity bundle
103+
antigravity.py # v1.108.88: Antigravity (Google) integration. Gemini-family paths (gemini_settings_path = ~/.gemini/settings.json for MCP; antigravity_skills_dir = ~/.gemini/antigravity/skills/) + skill install/uninstall/status reusing skills.py's directory-keyed core. MCP registration itself rides init.py's json_patch path (Antigravity is a detected client). PRD phase 1 (no AfterTool hook yet); see docs/prd-antigravity-hooks.md
101104
hooks.py # PreToolUse (Read interceptor) + PostToolUse (auto-reindex) + PreCompact (session snapshot) + TaskCompleted (post-task diagnostics) + SubagentStart (repo briefing) hook handlers for Claude Code
102105
groq/
103106
cli.py # `gcm` CLI entrypoint — codebase Q&A (single question + --chat mode)

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ pip install jcodemunch-mcp
369369
jcodemunch-mcp init
370370
```
371371

372-
`init` auto-detects your MCP clients (Claude Code, Claude Desktop, Cursor, Windsurf, Continue), writes their config entries, installs the CLAUDE.md prompt policy so your agent actually uses jCodeMunch, optionally installs enforcement hooks (PreToolUse read guard + PostToolUse auto-reindex + PreCompact session snapshot), optionally indexes your project, and audits your agent config files for token waste. Run `jcodemunch-mcp init --help` for all flags.
372+
`init` auto-detects your MCP clients (Claude Code, Claude Desktop, Cursor, Windsurf, Continue, Antigravity), writes their config entries, installs the CLAUDE.md prompt policy so your agent actually uses jCodeMunch, optionally installs enforcement hooks (PreToolUse read guard + PostToolUse auto-reindex + PreCompact session snapshot), optionally indexes your project, and audits your agent config files for token waste. Run `jcodemunch-mcp init --help` for all flags.
373373

374374
> **Prefer a one-line CLAUDE.md?** From v1.71.0 the server exposes a
375375
> `jcodemunch_guide` tool that returns the same policy snippet `claude-md
@@ -862,6 +862,7 @@ Tested configurations:
862862
|----------|--------|
863863
| **Claude Code / Claude Desktop** | `jcodemunch-mcp init` (auto-detects and patches config) |
864864
| **Cursor / Windsurf / Continue** | `jcodemunch-mcp init` or manual `mcp.json` |
865+
| **Antigravity (Google)** | `jcodemunch-mcp install antigravity` — registers the MCP server in `~/.gemini/settings.json` and installs the skill bundle under `~/.gemini/antigravity/skills/` |
865866
| **OpenAI Codex CLI** | Add `[mcp_servers.jcodemunch]` block to `~/.codex/config.toml` (see below) |
866867
| **Cline / Roo Code** | Add via the MCP marketplace UI or paste `command: uvx`, `args: ["jcodemunch-mcp"]` |
867868
| **Zed** | Add to `settings.json` under `context_servers` |

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "jcodemunch-mcp"
3-
version = "1.108.87"
3+
version = "1.108.88"
44
description = "Token-efficient MCP server for source code exploration via tree-sitter AST parsing"
55
readme = "README.md"
66
requires-python = ">=3.10"
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""Antigravity (Google) integration for jCodeMunch.
2+
3+
Antigravity follows the Gemini CLI configuration contract:
4+
5+
- **MCP servers** are declared in ``~/.gemini/settings.json`` under a top-level
6+
``mcpServers`` object — the same shape every other ``json_patch`` client uses.
7+
So MCP *registration* is handled by the shared client-detection/patch path in
8+
``init.py``: Antigravity is registered there as a detected ``json_patch``
9+
client pointing at the Gemini settings file. This module does not duplicate
10+
that; it owns the Antigravity-specific *paths* and the *skill bundle*.
11+
- **Agent skills** install under ``~/.gemini/antigravity/skills/``.
12+
13+
Keeping the Antigravity-specific paths in one module means a contract change is a
14+
one-file edit. P1 scope (this module): skill bundle + status; MCP registration
15+
rides the shared path. The ``AfterTool`` context-enrichment hook is a later
16+
phase (see docs/prd-antigravity-hooks.md).
17+
"""
18+
from __future__ import annotations
19+
20+
from pathlib import Path
21+
22+
23+
def gemini_dir() -> Path:
24+
"""Root config dir shared by the Gemini CLI and Antigravity."""
25+
return Path.home() / ".gemini"
26+
27+
28+
def gemini_settings_path() -> Path:
29+
"""Global settings file holding the ``mcpServers`` block."""
30+
return gemini_dir() / "settings.json"
31+
32+
33+
def antigravity_skills_dir() -> Path:
34+
"""Directory Antigravity loads agent skills from."""
35+
return gemini_dir() / "antigravity" / "skills"
36+
37+
38+
def antigravity_present() -> bool:
39+
"""True when a Gemini/Antigravity config dir exists to configure."""
40+
return gemini_dir().exists()
41+
42+
43+
def _skill_dir() -> Path:
44+
from .skills import _SKILL_NAME
45+
46+
return antigravity_skills_dir() / _SKILL_NAME
47+
48+
49+
def install_antigravity_skill(*, dry_run: bool = False, backup: bool = True) -> str:
50+
"""Write the jcodemunch skill bundle into the Antigravity skills dir."""
51+
from .skills import _install_skill_at
52+
53+
return _install_skill_at(_skill_dir(), dry_run=dry_run, backup=backup)
54+
55+
56+
def uninstall_antigravity_skill(*, dry_run: bool = False) -> str:
57+
"""Remove the jcodemunch skill bundle from the Antigravity skills dir."""
58+
from .skills import _uninstall_skill_at
59+
60+
return _uninstall_skill_at(_skill_dir(), dry_run=dry_run)
61+
62+
63+
def antigravity_skill_status() -> dict:
64+
"""Read-only status: is the jcodemunch Antigravity skill installed?"""
65+
from .skills import _skill_status_at
66+
67+
return _skill_status_at(_skill_dir())

src/jcodemunch_mcp/cli/init.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,14 @@ def _detect_clients() -> list[MCPClient]:
247247
if continue_dir.exists():
248248
clients.append(MCPClient("Continue", continue_dir / "config.json", "json_patch"))
249249

250+
# Antigravity (Google) — Gemini-family contract: MCP servers live in
251+
# ~/.gemini/settings.json under the same `mcpServers` shape we patch
252+
# elsewhere, so registration reuses the json_patch path. (Skills install
253+
# separately under ~/.gemini/antigravity/skills/, handled in cli/antigravity.)
254+
from .antigravity import gemini_dir, gemini_settings_path
255+
if gemini_dir().exists():
256+
clients.append(MCPClient("Antigravity", gemini_settings_path(), "json_patch"))
257+
250258
return clients
251259

252260

@@ -1167,6 +1175,17 @@ def run_init(
11671175
f"Write .claude/skills/jcodemunch/SKILL.md {where}",
11681176
"Claude loads the skill on demand for code-navigation tasks instead of carrying the policy block in baseline context every turn",
11691177
))
1178+
# Antigravity uses a separate skills dir (~/.gemini/antigravity/skills/);
1179+
# install the same bundle there when an Antigravity/Gemini config exists.
1180+
from .antigravity import antigravity_present, install_antigravity_skill
1181+
if antigravity_present():
1182+
amsg = install_antigravity_skill(dry_run=dry_run, backup=backup)
1183+
print(f" Antigravity Skill:{amsg}")
1184+
if demo and "would" in amsg:
1185+
_demo_actions.append((
1186+
"Write ~/.gemini/antigravity/skills/jcodemunch/SKILL.md",
1187+
"Antigravity loads the jCodemunch skill on demand for code-navigation tasks",
1188+
))
11701189

11711190
# ----- Step 3: Agent hooks -----
11721191
do_hooks = hooks
@@ -1553,6 +1572,7 @@ def uninstall_copilot_hooks(*, dry_run: bool = False, backup: bool = True) -> st
15531572
"cursor": "Cursor",
15541573
"windsurf": "Windsurf",
15551574
"continue": "Continue",
1575+
"antigravity": "Antigravity",
15561576
"all": "__all__",
15571577
}
15581578

@@ -1650,6 +1670,9 @@ def run_uninstall(
16501670
for scope in ("global", "project"):
16511671
msg = uninstall_claude_skill(scope=scope, dry_run=dry_run, backup=backup)
16521672
print(f" Claude Skill ({scope}):{msg}")
1673+
from .antigravity import uninstall_antigravity_skill
1674+
amsg = uninstall_antigravity_skill(dry_run=dry_run)
1675+
print(f" Antigravity Skill:{amsg}")
16531676

16541677
print()
16551678
if dry_run:
@@ -1757,9 +1780,11 @@ def install_status() -> dict[str, Any]:
17571780

17581781
# Claude Agent Skill bundle (v1.107.0) — per-scope presence
17591782
from .skills import skill_status as _skill_status
1783+
from .antigravity import antigravity_skill_status as _ag_skill_status
17601784
report["skills"] = {
17611785
"global": _skill_status("global"),
17621786
"project": _skill_status("project"),
1787+
"antigravity": _ag_skill_status(),
17631788
}
17641789

17651790
return report
@@ -1802,6 +1827,10 @@ def print_status(report: Optional[dict[str, Any]] = None, *, as_json: bool = Fal
18021827
info = report["skills"].get(scope, {})
18031828
flag = "[x]" if info.get("present") else "[ ]"
18041829
print(f" {flag} {scope} ({info.get('path', '')})")
1830+
ag = report["skills"].get("antigravity")
1831+
if ag:
1832+
flag = "[x]" if ag.get("present") else "[ ]"
1833+
print(f" {flag} antigravity ({ag.get('path', '')})")
18051834
print()
18061835

18071836

0 commit comments

Comments
 (0)