From 706934a9e4d4d536013d26bdedf614b50b48d1fb Mon Sep 17 00:00:00 2001 From: Kasper Junge Date: Tue, 9 Jun 2026 14:02:31 +0200 Subject: [PATCH 1/3] feat: replace Antigravity with Pi (pi.dev) tool support Drop the Antigravity integration and add Pi as a supported coding tool so teams using Pi can manage skills with agr. Pi installs skills to .pi/skills/ (project) and ~/.pi/agent/skills/ (global), is detected from .pi/ or the shared .agents/ directory, uses AGENTS.md for instructions, and has full CLI wiring (pi -p / -a / --continue) for agr run and agrx. Existing configs pinned to the former Antigravity canonical file are coerced on load (canonical_instructions = "GEMINI.md" -> "AGENTS.md") so they keep working instead of erroring on every command. Co-Authored-By: Claude Opus 4.8 --- agr/commands/migrations.py | 20 +------- agr/commands/remove.py | 4 +- agr/config.py | 5 ++ agr/main.py | 2 +- agr/tool.py | 37 ++++++++------- tests/cli/agr/test_antigravity.py | 78 ------------------------------- tests/cli/agr/test_init.py | 14 +++--- tests/cli/agr/test_pi.py | 78 +++++++++++++++++++++++++++++++ tests/cli/agr/test_run.py | 9 ---- tests/cli/agr/test_sync.py | 11 +++-- tests/cli/agrx/test_tool_flag.py | 9 ++-- tests/test_config.py | 6 +-- tests/test_docs.py | 5 +- tests/test_sdk_hub.py | 4 ++ tests/test_tool.py | 46 +++++++++--------- tests/unit/test_detect.py | 30 ++++++------ tests/unit/test_instructions.py | 4 +- tests/unit/test_migrations.py | 46 +----------------- 18 files changed, 176 insertions(+), 232 deletions(-) delete mode 100644 tests/cli/agr/test_antigravity.py create mode 100644 tests/cli/agr/test_pi.py diff --git a/agr/commands/migrations.py b/agr/commands/migrations.py index e2db0aff..19d008d8 100644 --- a/agr/commands/migrations.py +++ b/agr/commands/migrations.py @@ -23,7 +23,7 @@ stamp_resource_metadata, ) from agr.skill import SKILL_MARKER, is_valid_skill_dir, update_skill_md_name -from agr.tool import ANTIGRAVITY, CODEX, CURSOR, OPENCODE, ToolConfig +from agr.tool import CODEX, CURSOR, OPENCODE, ToolConfig def _print_migrated(label: str, old_name: str, new_name: str) -> None: @@ -165,24 +165,6 @@ def run_tool_migrations( cleanup_parent=False, ) - # Antigravity migration: .agent/skills/ -> .gemini/skills/ - # Gemini CLI moved from .agent/ to .gemini/ as the primary skills path. - if ANTIGRAVITY.name in tool_by_name: - _migrate_skills_directory( - base / ".agent" / "skills", - ANTIGRAVITY.get_skills_dir(base), - cleanup_parent=True, - ) - - # Antigravity global migration: .gemini/antigravity/skills/ -> .gemini/skills/ - # Older versions used a nested .gemini/antigravity/ subdir for global skills. - if ANTIGRAVITY.name in tool_by_name and global_install: - _migrate_skills_directory( - base / ".gemini" / "antigravity" / "skills", - ANTIGRAVITY.get_skills_dir(base), - cleanup_parent=True, - ) - # Cursor migration: flatten nested skill dirs to flat naming. # Old layout stored skills as user/repo/skill/ or local/skill/ inside # .cursor/skills/. Cursor expects flat naming where each skill is a diff --git a/agr/commands/remove.py b/agr/commands/remove.py index dbbb0a8c..baab8d8e 100644 --- a/agr/commands/remove.py +++ b/agr/commands/remove.py @@ -58,7 +58,9 @@ def _uninstall_from_filesystem( Returns True if anything was removed. """ if is_ralph: - return uninstall_ralph(handle, repo_root, source_name, default_repo=default_repo) + return uninstall_ralph( + handle, repo_root, source_name, default_repo=default_repo + ) removed = False for tool in tools: if uninstall_skill( diff --git a/agr/config.py b/agr/config.py index 52cf0c45..9a501e02 100644 --- a/agr/config.py +++ b/agr/config.py @@ -522,6 +522,11 @@ def load(cls, path: Path) -> "AgrConfig": canonical_instructions = doc.get("canonical_instructions") if canonical_instructions is not None: canonical_instructions = str(canonical_instructions) + # Legacy compatibility: GEMINI.md was the Antigravity canonical file. + # Antigravity is no longer supported, so coerce old configs to + # AGENTS.md instead of erroring on every command. + if canonical_instructions == "GEMINI.md": + canonical_instructions = "AGENTS.md" validate_canonical_instructions(canonical_instructions) config.canonical_instructions = canonical_instructions diff --git a/agr/main.py b/agr/main.py index 8c56a73d..78be6424 100644 --- a/agr/main.py +++ b/agr/main.py @@ -193,7 +193,7 @@ def init( str | None, typer.Option( "--canonical-instructions", - help="Canonical instruction file (AGENTS.md, CLAUDE.md, or GEMINI.md).", + help="Canonical instruction file (AGENTS.md or CLAUDE.md).", ), ] = None, ) -> None: diff --git a/agr/tool.py b/agr/tool.py index 6e01a82b..bd7823ab 100644 --- a/agr/tool.py +++ b/agr/tool.py @@ -2,7 +2,7 @@ All tool-specific paths and configuration are isolated in this module. Supports Claude Code, Cursor, OpenAI Codex, OpenCode, -GitHub Copilot, and Antigravity. All tools use flat naming. +GitHub Copilot, and Pi. All tools use flat naming. """ from dataclasses import dataclass @@ -39,7 +39,9 @@ class ToolConfig: skill_prompt_prefix: str = "/" # Prefix for invoking a skill install_hint: str | None = None # Help text for installation detection_signals: tuple[str, ...] = () # Paths that indicate tool presence - instruction_file: str = DEFAULT_INSTRUCTION_FILE # Canonical instruction file for this tool + instruction_file: str = ( + DEFAULT_INSTRUCTION_FILE # Canonical instruction file for this tool + ) def get_skills_dir(self, repo_root: Path) -> Path: """Get the skills directory for this tool in a repo.""" @@ -136,19 +138,22 @@ def get_global_skills_dir(self) -> Path: ), ) -# Antigravity tool configuration (flat naming: ) -# Skill paths based on Gemini CLI documentation: -# - Workspace: .gemini/skills/ (primary; .agents/skills/ is an alias) -# - User: ~/.gemini/skills/ (primary; ~/.agents/skills/ is an alias) -# No CLI support — only fields that differ from ToolConfig defaults are set. -ANTIGRAVITY = ToolConfig( - name="antigravity", - config_dir=".gemini", - cli_prompt_flag=None, - cli_continue_flag=None, - skill_prompt_prefix="", - detection_signals=(".gemini", ".agents"), - instruction_file="GEMINI.md", +# Pi tool configuration (flat naming: ) +# Skill paths based on Pi documentation (https://pi.dev): +# - Project: .pi/skills/ (primary; .agents/skills/ is an alias) +# - User: ~/.pi/agent/skills/ (primary; ~/.agents/skills/ is an alias) +# CLI `pi`: one-shot `-p/--print`, auto-approve `-a/--approve`, resume `--continue`. +PI = ToolConfig( + name="pi", + config_dir=".pi", + global_config_dir=".pi/agent", # global -> ~/.pi/agent/skills/ + cli_command="pi", + cli_prompt_flag="-p", # pi -p "" + cli_force_flag="-a", # pi -a (trust project-local files) + cli_interactive_prompt_positional=True, + install_hint="Install Pi (https://pi.dev)", + detection_signals=(".pi", ".agents"), + instruction_file="AGENTS.md", ) # All tool configurations — order here determines iteration order in TOOLS. @@ -158,7 +163,7 @@ def get_global_skills_dir(self) -> Path: CODEX, OPENCODE, COPILOT, - ANTIGRAVITY, + PI, ) # Registry of all supported tools, keyed by ToolConfig.name. diff --git a/tests/cli/agr/test_antigravity.py b/tests/cli/agr/test_antigravity.py deleted file mode 100644 index 5c3cc01a..00000000 --- a/tests/cli/agr/test_antigravity.py +++ /dev/null @@ -1,78 +0,0 @@ -"""CLI tests for Antigravity tool support.""" - -from tests.cli.assertions import assert_cli - - -class TestAntigravityAdd: - """Tests for agr add with Antigravity tool.""" - - def test_add_local_skill_to_antigravity_flat_structure( - self, agr, cli_project, cli_skill, cli_config - ): - """agr add local skill installs to .gemini/skills//.""" - cli_config('tools = ["antigravity"]\ndependencies = []') - - result = agr("add", "./skills/test-skill") - - assert_cli(result).succeeded() - installed = cli_project / ".gemini" / "skills" / "test-skill" - assert installed.exists() - assert (installed / "SKILL.md").exists() - - -class TestAntigravitySync: - """Tests for agr sync with Antigravity tool.""" - - def test_sync_installs_to_antigravity_when_configured( - self, agr, cli_project, cli_skill, cli_config - ): - """agr sync with tools = ["antigravity"] installs to correct path.""" - cli_config( - """ -tools = ["antigravity"] -dependencies = [ - { path = "./skills/test-skill", type = "skill" }, -] -""" - ) - - result = agr("sync") - - assert_cli(result).succeeded() - installed = cli_project / ".gemini" / "skills" / "test-skill" - assert installed.exists() - - -class TestAntigravityRemove: - """Tests for agr remove with Antigravity tool.""" - - def test_remove_cleans_up_antigravity_flat_structure( - self, agr, cli_project, cli_skill, cli_config - ): - """agr remove removes skill from .gemini/skills/.""" - cli_config('tools = ["antigravity"]\ndependencies = []') - agr("add", "./skills/test-skill") - - installed = cli_project / ".gemini" / "skills" / "test-skill" - assert installed.exists() - - result = agr("remove", "./skills/test-skill") - - assert_cli(result).succeeded() - assert not installed.exists() - - -class TestMultiToolAntigravityClaude: - """Tests for multi-tool scenarios with Antigravity and Claude.""" - - def test_add_installs_to_both_claude_and_antigravity( - self, agr, cli_project, cli_skill, cli_config - ): - """agr add with tools = ["claude", "antigravity"] installs to both.""" - cli_config('tools = ["claude", "antigravity"]\ndependencies = []') - - result = agr("add", "./skills/test-skill") - - assert_cli(result).succeeded() - assert (cli_project / ".claude" / "skills" / "test-skill").exists() - assert (cli_project / ".gemini" / "skills" / "test-skill").exists() diff --git a/tests/cli/agr/test_init.py b/tests/cli/agr/test_init.py index 434c4088..8d50dc45 100644 --- a/tests/cli/agr/test_init.py +++ b/tests/cli/agr/test_init.py @@ -150,22 +150,22 @@ def test_init_discovers_tools_and_syncs_instructions(self, agr, cli_project): assert config.sync_instructions is True assert config.canonical_instructions == "CLAUDE.md" - def test_init_detects_antigravity_tools(self, agr, cli_project): - """agr init detects Antigravity tools when .gemini/ exists.""" - (cli_project / ".gemini").mkdir() + def test_init_detects_pi_tools(self, agr, cli_project): + """agr init detects Pi tools when .pi/ exists.""" + (cli_project / ".pi").mkdir() result = agr("init") assert_cli(result).succeeded() config = AgrConfig.load(cli_project / "agr.toml") - assert "antigravity" in config.tools + assert "pi" in config.tools - def test_init_detects_antigravity_from_agents_dir(self, agr, cli_project): - """agr init detects Antigravity from .agents/ directory (shared with Codex).""" + def test_init_detects_pi_from_agents_dir(self, agr, cli_project): + """agr init detects Pi from .agents/ directory (shared with Codex).""" (cli_project / ".agents").mkdir() result = agr("init") assert_cli(result).succeeded() config = AgrConfig.load(cli_project / "agr.toml") - assert "antigravity" in config.tools + assert "pi" in config.tools diff --git a/tests/cli/agr/test_pi.py b/tests/cli/agr/test_pi.py new file mode 100644 index 00000000..32114e33 --- /dev/null +++ b/tests/cli/agr/test_pi.py @@ -0,0 +1,78 @@ +"""CLI tests for Pi tool support.""" + +from tests.cli.assertions import assert_cli + + +class TestPiAdd: + """Tests for agr add with Pi tool.""" + + def test_add_local_skill_to_pi_flat_structure( + self, agr, cli_project, cli_skill, cli_config + ): + """agr add local skill installs to .pi/skills//.""" + cli_config('tools = ["pi"]\ndependencies = []') + + result = agr("add", "./skills/test-skill") + + assert_cli(result).succeeded() + installed = cli_project / ".pi" / "skills" / "test-skill" + assert installed.exists() + assert (installed / "SKILL.md").exists() + + +class TestPiSync: + """Tests for agr sync with Pi tool.""" + + def test_sync_installs_to_pi_when_configured( + self, agr, cli_project, cli_skill, cli_config + ): + """agr sync with tools = ["pi"] installs to correct path.""" + cli_config( + """ +tools = ["pi"] +dependencies = [ + { path = "./skills/test-skill", type = "skill" }, +] +""" + ) + + result = agr("sync") + + assert_cli(result).succeeded() + installed = cli_project / ".pi" / "skills" / "test-skill" + assert installed.exists() + + +class TestPiRemove: + """Tests for agr remove with Pi tool.""" + + def test_remove_cleans_up_pi_flat_structure( + self, agr, cli_project, cli_skill, cli_config + ): + """agr remove removes skill from .pi/skills/.""" + cli_config('tools = ["pi"]\ndependencies = []') + agr("add", "./skills/test-skill") + + installed = cli_project / ".pi" / "skills" / "test-skill" + assert installed.exists() + + result = agr("remove", "./skills/test-skill") + + assert_cli(result).succeeded() + assert not installed.exists() + + +class TestMultiToolPiClaude: + """Tests for multi-tool scenarios with Pi and Claude.""" + + def test_add_installs_to_both_claude_and_pi( + self, agr, cli_project, cli_skill, cli_config + ): + """agr add with tools = ["claude", "pi"] installs to both.""" + cli_config('tools = ["claude", "pi"]\ndependencies = []') + + result = agr("add", "./skills/test-skill") + + assert_cli(result).succeeded() + assert (cli_project / ".claude" / "skills" / "test-skill").exists() + assert (cli_project / ".pi" / "skills" / "test-skill").exists() diff --git a/tests/cli/agr/test_run.py b/tests/cli/agr/test_run.py index 682e2821..8722a841 100644 --- a/tests/cli/agr/test_run.py +++ b/tests/cli/agr/test_run.py @@ -80,15 +80,6 @@ def test_run_tool_cli_not_found(self, agr, cli_config, cli_project): assert_cli(result).failed().stdout_contains("agent CLI not found") - def test_run_tool_no_cli_configured(self, agr, cli_config, cli_project): - """agr run with a tool that has no CLI command (antigravity) errors.""" - cli_config('tools = ["antigravity"]\ndependencies = []') - _install_skill(cli_project, ".gemini", "demo") - - result = agr("run", "demo") - - assert_cli(result).failed().stdout_contains("has no CLI command configured") - @pytest.mark.skipif( shutil.which("agent") is not None, reason="agent CLI is installed" ) diff --git a/tests/cli/agr/test_sync.py b/tests/cli/agr/test_sync.py index dbf98eab..b3774583 100644 --- a/tests/cli/agr/test_sync.py +++ b/tests/cli/agr/test_sync.py @@ -47,14 +47,14 @@ def test_sync_instructions(self, agr, cli_project, cli_config): cli_project / "CLAUDE.md" ).read_text() - def test_sync_instructions_creates_gemini_for_antigravity( + def test_sync_instructions_creates_agents_for_pi( self, agr, cli_project, cli_config ): - """agr sync creates GEMINI.md from CLAUDE.md when antigravity is configured.""" + """agr sync creates AGENTS.md from CLAUDE.md when pi is configured.""" (cli_project / "CLAUDE.md").write_text("Claude instructions\n") cli_config( """ -tools = ["claude", "antigravity"] +tools = ["claude", "pi"] sync_instructions = true canonical_instructions = "CLAUDE.md" dependencies = [] @@ -64,8 +64,8 @@ def test_sync_instructions_creates_gemini_for_antigravity( result = agr("sync") assert_cli(result).succeeded() - assert (cli_project / "GEMINI.md").exists() - assert (cli_project / "GEMINI.md").read_text() == "Claude instructions\n" + assert (cli_project / "AGENTS.md").exists() + assert (cli_project / "AGENTS.md").read_text() == "Claude instructions\n" def test_sync_instructions_creates_agents_for_cursor( self, agr, cli_project, cli_config @@ -173,6 +173,7 @@ def test_sync_rewrites_shorthand_handle_in_toml( dep = config.dependencies[0] assert dep.handle == "acme/skills/test-skill" + class TestAgrSyncRalph: """Tests for agr sync with ralph dependencies.""" diff --git a/tests/cli/agrx/test_tool_flag.py b/tests/cli/agrx/test_tool_flag.py index 134543cd..4b1154c5 100644 --- a/tests/cli/agrx/test_tool_flag.py +++ b/tests/cli/agrx/test_tool_flag.py @@ -60,11 +60,12 @@ def test_agrx_tool_cli_not_found_opencode(self, agrx): assert_cli(result).failed().stdout_contains("opencode CLI not found") - def test_agrx_tool_no_cli_antigravity(self, agrx): - """agrx --tool antigravity fails when no CLI is configured.""" - result = agrx("user/skill", "--tool", "antigravity") + @pytest.mark.skipif(shutil.which("pi") is not None, reason="pi CLI is installed") + def test_agrx_tool_cli_not_found_pi(self, agrx): + """agrx --tool pi fails when pi CLI not found.""" + result = agrx("user/skill", "--tool", "pi") - assert_cli(result).failed().stdout_contains("has no CLI command configured") + assert_cli(result).failed().stdout_contains("pi CLI not found") class TestAgrxToolFromConfig: diff --git a/tests/test_config.py b/tests/test_config.py index 31c9713b..2480b779 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -356,14 +356,14 @@ def test_load_canonical_instructions(self, tmp_path): config = AgrConfig.load(config_path) assert config.canonical_instructions == "AGENTS.md" - def test_load_canonical_instructions_gemini(self, tmp_path): - """Load config with GEMINI.md as canonical_instructions.""" + def test_load_canonical_instructions_legacy_gemini_coerced(self, tmp_path): + """Legacy GEMINI.md (Antigravity) coerces to AGENTS.md instead of erroring.""" config_path = tmp_path / "agr.toml" config_path.write_text( 'canonical_instructions = "GEMINI.md"\ndependencies = []\n' ) config = AgrConfig.load(config_path) - assert config.canonical_instructions == "GEMINI.md" + assert config.canonical_instructions == "AGENTS.md" def test_load_invalid_canonical_instructions_raises(self, tmp_path): """Invalid canonical_instructions raises ConfigError.""" diff --git a/tests/test_docs.py b/tests/test_docs.py index 0723cb5f..e260bb85 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -189,9 +189,7 @@ def test_managing_mentions_all_tools(self): """managing.md Multi-tool section lists all supported tools.""" content = (DOCS_DIR / "managing.md").read_text() section_marker = "## Multi-tool" - assert section_marker in content, ( - "managing.md missing 'Multi-tool' section" - ) + assert section_marker in content, "managing.md missing 'Multi-tool' section" section = content[content.index(section_marker) :] for tool in self.ALL_TOOL_NAMES: assert tool in section.lower(), ( @@ -206,6 +204,7 @@ def test_reference_agrx_section_mentions_all_tools(self): f"Tool '{tool}' not mentioned in reference.md" ) + class TestContentQuality: """Test documentation content quality.""" diff --git a/tests/test_sdk_hub.py b/tests/test_sdk_hub.py index c60026c4..8d52e932 100644 --- a/tests/test_sdk_hub.py +++ b/tests/test_sdk_hub.py @@ -13,6 +13,7 @@ def _raises_invalid_handle(repo_handle: str) -> None: # --- Control-character / whitespace rejection (SF-008) --- + def test_list_skills_rejects_newline_in_owner(): _raises_invalid_handle("owner\nevil/repo") @@ -27,6 +28,7 @@ def test_list_skills_rejects_space_in_owner_single_part(): # --- YAML character rejection (SF-010 / SF-011 / SF-012) --- + def test_list_skills_rejects_bracket_in_owner(): _raises_invalid_handle("[owner]/repo") @@ -41,6 +43,7 @@ def test_list_skills_rejects_pipe_in_owner(): # --- Path traversal rejection (SF-003) --- + def test_list_skills_rejects_dotdot_owner(): _raises_invalid_handle("../repo") @@ -51,6 +54,7 @@ def test_list_skills_rejects_dotdot_repo(): # --- Valid handles still work (no regression) --- + def test_list_skills_valid_single_part_raises_network_not_handle(monkeypatch): """Valid owner should pass handle validation; network call is mocked to raise.""" import agr.sdk.hub as hub diff --git a/tests/test_tool.py b/tests/test_tool.py index acc236bc..f39e9d0b 100644 --- a/tests/test_tool.py +++ b/tests/test_tool.py @@ -3,12 +3,12 @@ from pathlib import Path from agr.tool import ( - ANTIGRAVITY, CLAUDE, CODEX, COPILOT, CURSOR, OPENCODE, + PI, TOOLS, available_tools_string, build_global_skills_dirs, @@ -27,7 +27,7 @@ def test_tool_config_has_cli_command(self): assert CODEX.cli_command == "codex" assert OPENCODE.cli_command == "opencode" assert COPILOT.cli_command == "copilot" - assert ANTIGRAVITY.cli_command is None + assert PI.cli_command == "pi" def test_tool_config_has_cli_flags(self): """ToolConfig includes CLI flag fields.""" @@ -37,7 +37,7 @@ def test_tool_config_has_cli_flags(self): assert CODEX.cli_prompt_flag is None assert OPENCODE.cli_prompt_flag is None assert COPILOT.cli_prompt_flag == "-p" - assert ANTIGRAVITY.cli_prompt_flag is None + assert PI.cli_prompt_flag == "-p" # Each tool has its own force flag assert CLAUDE.cli_force_flag == "--dangerously-skip-permissions" @@ -45,7 +45,7 @@ def test_tool_config_has_cli_flags(self): assert CODEX.cli_force_flag == "--full-auto" assert OPENCODE.cli_force_flag is None assert COPILOT.cli_force_flag == "--allow-all-tools" - assert ANTIGRAVITY.cli_force_flag is None + assert PI.cli_force_flag == "-a" # All tools have continue flag assert CLAUDE.cli_continue_flag == "--continue" @@ -53,7 +53,7 @@ def test_tool_config_has_cli_flags(self): assert CODEX.cli_continue_flag is None assert OPENCODE.cli_continue_flag == "--continue" assert COPILOT.cli_continue_flag == "--continue" - assert ANTIGRAVITY.cli_continue_flag is None + assert PI.cli_continue_flag == "--continue" def test_tool_config_has_cli_commands(self): """ToolConfig includes CLI command fields.""" @@ -62,14 +62,14 @@ def test_tool_config_has_cli_commands(self): assert CODEX.cli_exec_command == ["codex", "exec"] assert OPENCODE.cli_exec_command == ["opencode", "run"] assert COPILOT.cli_exec_command is None - assert ANTIGRAVITY.cli_exec_command is None + assert PI.cli_exec_command is None assert CLAUDE.cli_continue_command is None assert CURSOR.cli_continue_command is None assert CODEX.cli_continue_command == ["codex", "resume", "--last"] assert OPENCODE.cli_continue_command is None assert COPILOT.cli_continue_command is None - assert ANTIGRAVITY.cli_continue_command is None + assert PI.cli_continue_command is None def test_tool_config_has_output_handling(self): """ToolConfig includes non-interactive output controls.""" @@ -78,7 +78,7 @@ def test_tool_config_has_output_handling(self): assert CODEX.suppress_stderr_non_interactive is True assert OPENCODE.suppress_stderr_non_interactive is False assert COPILOT.suppress_stderr_non_interactive is False - assert ANTIGRAVITY.suppress_stderr_non_interactive is False + assert PI.suppress_stderr_non_interactive is False def test_tool_config_has_interactive_prompt_mode(self): """ToolConfig includes interactive prompt mode controls.""" @@ -87,19 +87,19 @@ def test_tool_config_has_interactive_prompt_mode(self): assert CODEX.cli_interactive_prompt_positional is True assert OPENCODE.cli_interactive_prompt_positional is False assert COPILOT.cli_interactive_prompt_positional is False - assert ANTIGRAVITY.cli_interactive_prompt_positional is False + assert PI.cli_interactive_prompt_positional is True assert CLAUDE.cli_interactive_prompt_flag is None assert CURSOR.cli_interactive_prompt_flag is None assert CODEX.cli_interactive_prompt_flag is None assert OPENCODE.cli_interactive_prompt_flag == "--prompt" assert COPILOT.cli_interactive_prompt_flag == "-i" - assert ANTIGRAVITY.cli_interactive_prompt_flag is None + assert PI.cli_interactive_prompt_flag is None assert CLAUDE.skill_prompt_prefix == "/" assert CURSOR.skill_prompt_prefix == "/" assert CODEX.skill_prompt_prefix == "$" assert OPENCODE.skill_prompt_prefix == "" assert COPILOT.skill_prompt_prefix == "/" - assert ANTIGRAVITY.skill_prompt_prefix == "" + assert PI.skill_prompt_prefix == "/" def test_tool_config_has_install_hint(self): """ToolConfig includes install_hint field.""" @@ -108,7 +108,7 @@ def test_tool_config_has_install_hint(self): assert CODEX.install_hint is not None assert OPENCODE.install_hint is not None assert COPILOT.install_hint is not None - assert ANTIGRAVITY.install_hint is None + assert PI.install_hint is not None def test_all_tools_have_cli_config(self): """All registered tools have CLI configuration.""" @@ -157,7 +157,7 @@ def test_get_tool_returns_correct_config(self): assert get_tool("codex") == CODEX assert get_tool("opencode") == OPENCODE assert get_tool("copilot") == COPILOT - assert get_tool("antigravity") == ANTIGRAVITY + assert get_tool("pi") == PI def test_get_tool_unknown_raises(self): """get_tool raises AgrError for unknown tool.""" @@ -210,14 +210,12 @@ def test_copilot_global_skills_dir(self): """Copilot uses ~/.copilot/skills/ (asymmetric from .github project path).""" assert COPILOT.get_global_skills_dir() == (Path.home() / ".copilot" / "skills") - def test_antigravity_project_skills_dir(self, tmp_path): - assert ANTIGRAVITY.get_skills_dir(tmp_path) == (tmp_path / ".gemini" / "skills") + def test_pi_project_skills_dir(self, tmp_path): + assert PI.get_skills_dir(tmp_path) == (tmp_path / ".pi" / "skills") - def test_antigravity_global_skills_dir(self): - """Antigravity uses ~/.gemini/skills/ for personal skills.""" - assert ANTIGRAVITY.get_global_skills_dir() == ( - Path.home() / ".gemini" / "skills" - ) + def test_pi_global_skills_dir(self): + """Pi uses ~/.pi/agent/skills/ for personal skills.""" + assert PI.get_global_skills_dir() == (Path.home() / ".pi" / "agent" / "skills") class TestDetectionSignals: @@ -251,8 +249,8 @@ def test_copilot_detection_signals(self): ".github/instructions", ) - def test_antigravity_detection_signals(self): - assert ANTIGRAVITY.detection_signals == (".gemini", ".agents") + def test_pi_detection_signals(self): + assert PI.detection_signals == (".pi", ".agents") class TestInstructionFiles: @@ -273,8 +271,8 @@ def test_opencode_instruction_file(self): def test_copilot_instruction_file(self): assert COPILOT.instruction_file == "AGENTS.md" - def test_antigravity_instruction_file(self): - assert ANTIGRAVITY.instruction_file == "GEMINI.md" + def test_pi_instruction_file(self): + assert PI.instruction_file == "AGENTS.md" class TestUtilityFunctions: diff --git a/tests/unit/test_detect.py b/tests/unit/test_detect.py index 2aec36d7..7cebbb78 100644 --- a/tests/unit/test_detect.py +++ b/tests/unit/test_detect.py @@ -96,37 +96,37 @@ def test_opencode_detected_from_opencode_jsonc(self, tmp_path): assert "opencode" in result - def test_antigravity_detected_from_gemini_dir(self, tmp_path): - """detect_tools finds antigravity from .gemini/ directory.""" - (tmp_path / ".gemini").mkdir() + def test_pi_detected_from_pi_dir(self, tmp_path): + """detect_tools finds pi from .pi/ directory.""" + (tmp_path / ".pi").mkdir() result = detect_tools(tmp_path) - assert "antigravity" in result + assert "pi" in result - def test_antigravity_detected_from_agents_dir(self, tmp_path): - """detect_tools finds antigravity from .agents/ directory (shared with Codex).""" + def test_pi_detected_from_agents_dir(self, tmp_path): + """detect_tools finds pi from .agents/ directory (shared with Codex).""" (tmp_path / ".agents").mkdir() result = detect_tools(tmp_path) - assert "antigravity" in result + assert "pi" in result - def test_agents_dir_detects_both_codex_and_antigravity(self, tmp_path): - """The .agents/ directory is a shared signal that detects both Codex and Antigravity. + def test_agents_dir_detects_both_codex_and_pi(self, tmp_path): + """The .agents/ directory is a shared signal that detects both Codex and Pi. The .agents/ path is the Agent Skills spec standard directory. - Both Codex (primary skill path) and Antigravity (alias for .gemini/) - declare it as a detection signal. Other tools (Cursor, Claude, - OpenCode, Copilot) do NOT use .agents/ as a detection signal, even - though some of them read skills from that path at runtime. + Both Codex (primary skill path) and Pi (alias for .pi/) declare it as + a detection signal. Other tools (Cursor, Claude, OpenCode, Copilot) + do NOT use .agents/ as a detection signal, even though some of them + read skills from that path at runtime. """ (tmp_path / ".agents").mkdir() result = detect_tools(tmp_path) assert "codex" in result - assert "antigravity" in result + assert "pi" in result # Other tools must NOT be detected from .agents/ alone assert "claude" not in result assert "cursor" not in result @@ -174,7 +174,7 @@ def test_all_tools_detectable(self, tmp_path): (tmp_path / ".agents").mkdir() (tmp_path / ".opencode").mkdir() (tmp_path / ".github" / "copilot").mkdir(parents=True) - (tmp_path / ".gemini").mkdir() + (tmp_path / ".pi").mkdir() result = detect_tools(tmp_path) diff --git a/tests/unit/test_instructions.py b/tests/unit/test_instructions.py index d82a7c64..38e56d60 100644 --- a/tests/unit/test_instructions.py +++ b/tests/unit/test_instructions.py @@ -26,8 +26,8 @@ def test_copilot_tool(self) -> None: def test_opencode_tool(self) -> None: assert canonical_instruction_file("opencode") == "AGENTS.md" - def test_antigravity_tool(self) -> None: - assert canonical_instruction_file("antigravity") == "GEMINI.md" + def test_pi_tool(self) -> None: + assert canonical_instruction_file("pi") == "AGENTS.md" def test_unknown_tool_returns_agents_md(self) -> None: assert canonical_instruction_file("nonexistent") == "AGENTS.md" diff --git a/tests/unit/test_migrations.py b/tests/unit/test_migrations.py index e3fab36a..b0f0e1fa 100644 --- a/tests/unit/test_migrations.py +++ b/tests/unit/test_migrations.py @@ -14,7 +14,7 @@ from agr.handle import INSTALLED_NAME_SEPARATOR, LEGACY_SEPARATOR from agr.metadata import METADATA_FILENAME from agr.skill import SKILL_MARKER -from agr.tool import ANTIGRAVITY, CLAUDE, CODEX, CURSOR, OPENCODE +from agr.tool import CLAUDE, CODEX, CURSOR, OPENCODE def _make_skill(path, *, metadata=None): @@ -431,30 +431,6 @@ def test_opencode_migration(self, tmp_path): assert (tmp_path / ".opencode" / "skills" / "my-skill" / SKILL_MARKER).exists() assert not (tmp_path / ".opencode" / "skill").exists() - def test_antigravity_migration(self, tmp_path): - """Antigravity skills are migrated from .agent/ to .gemini/.""" - _make_skill(tmp_path / ".agent" / "skills" / "my-skill") - - run_tool_migrations([ANTIGRAVITY], tmp_path) - - assert (tmp_path / ".gemini" / "skills" / "my-skill" / SKILL_MARKER).exists() - # Old .agent dir should be cleaned up - assert not (tmp_path / ".agent").exists() - - def test_antigravity_global_subdir_migration(self, tmp_path): - """Antigravity legacy .gemini/antigravity/skills/ is migrated to .gemini/skills/.""" - _make_skill(tmp_path / ".gemini" / "antigravity" / "skills" / "my-skill") - - _migrate_skills_directory( - tmp_path / ".gemini" / "antigravity" / "skills", - tmp_path / ".gemini" / "skills", - cleanup_parent=True, - ) - - assert (tmp_path / ".gemini" / "skills" / "my-skill" / SKILL_MARKER).exists() - # Old .gemini/antigravity dir should be cleaned up - assert not (tmp_path / ".gemini" / "antigravity").exists() - def test_noop_when_repo_root_none(self): """No-op when repo_root is None and not global.""" run_tool_migrations([CLAUDE], None) # Should not raise @@ -482,16 +458,6 @@ def test_opencode_global_migration_uses_global_config_dir( ).exists() assert not (tmp_path / ".config" / "opencode" / "skill").exists() - def test_antigravity_global_migration(self, tmp_path, monkeypatch): - """Antigravity global migration moves .gemini/antigravity/skills/ to .gemini/skills/.""" - monkeypatch.setattr(Path, "home", staticmethod(lambda: tmp_path)) - _make_skill(tmp_path / ".gemini" / "antigravity" / "skills" / "my-skill") - - run_tool_migrations([ANTIGRAVITY], None, global_install=True) - - assert (tmp_path / ".gemini" / "skills" / "my-skill" / SKILL_MARKER).exists() - assert not (tmp_path / ".gemini" / "antigravity").exists() - def test_codex_global_migration(self, tmp_path, monkeypatch): """Codex global migration moves ~/.codex/skills/ to ~/.agents/skills/.""" monkeypatch.setattr(Path, "home", staticmethod(lambda: tmp_path)) @@ -512,16 +478,6 @@ def test_cursor_global_migration_flattens_nested(self, tmp_path, monkeypatch): assert (tmp_path / ".cursor" / "skills" / "my-skill" / SKILL_MARKER).exists() assert not (tmp_path / ".cursor" / "skills" / "user").exists() - def test_antigravity_global_agent_to_gemini_migration(self, tmp_path, monkeypatch): - """Antigravity global migration moves ~/.agent/skills/ to ~/.gemini/skills/.""" - monkeypatch.setattr(Path, "home", staticmethod(lambda: tmp_path)) - _make_skill(tmp_path / ".agent" / "skills" / "my-skill") - - run_tool_migrations([ANTIGRAVITY], None, global_install=True) - - assert (tmp_path / ".gemini" / "skills" / "my-skill" / SKILL_MARKER).exists() - assert not (tmp_path / ".agent").exists() - def test_skips_unconfigured_tools(self, tmp_path): """Only migrates tools that are in the tools list.""" _make_skill(tmp_path / ".codex" / "skills" / "my-skill") From e7f3ab896c062ce5f7801c60e2b412067196b7a3 Mon Sep 17 00:00:00 2001 From: Kasper Junge Date: Tue, 9 Jun 2026 14:02:40 +0200 Subject: [PATCH 2/3] docs: replace Antigravity with Pi across docs and agr-cli skill Update the README invocation table, supported-tool lists, the agr-cli skill references, the shipping JSON-LD SEO template (docs/overrides/main.html), and the CHANGELOG so users see Pi instead of Antigravity. Drop GEMINI.md as a canonical instruction file everywhere it was listed. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 9 +++ README.md | 2 +- docs/managing.md | 2 +- docs/overrides/main.html | 68 ++++++++++----------- docs/reference.md | 2 +- skills/agr-cli/SKILL.md | 8 +-- skills/agr-cli/references/configuration.md | 9 ++- skills/agr-cli/references/running-skills.md | 2 +- skills/agr-cli/references/setup.md | 10 +-- skills/agr-cli/references/syncing.md | 2 +- 10 files changed, 61 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e3021be..8dd2a014 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## [Unreleased] +### Added +- Pi (pi.dev) tool support — skills install to `.pi/skills//` (global `~/.pi/agent/skills/`), with `pi` CLI support for `agr run` / `agrx --tool pi` and detection from `.pi/`/`.agents/`. + +### Removed +- Antigravity tool support. + +### Changed +- `canonical_instructions = "GEMINI.md"` (the former Antigravity instruction file) is no longer a valid value, but existing configs are coerced to `AGENTS.md` on load so they keep working. Update your `agr.toml` to `AGENTS.md` (or `CLAUDE.md`) when convenient. + ## [0.8.4] - 2026-04-15 ### Added diff --git a/README.md b/README.md index 2c1c4d67..50199b4b 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ the skill into each. Then invoke it in your tool: | OpenAI Codex | `$pdf` | | OpenCode | `pdf` | | GitHub Copilot | `/pdf` | -| Antigravity | *(via IDE)* | +| Pi | `/pdf` | ### 2. Use your own local skills diff --git a/docs/managing.md b/docs/managing.md index 9b7ad655..ca99e900 100644 --- a/docs/managing.md +++ b/docs/managing.md @@ -64,7 +64,7 @@ agr list tools = ["claude", "cursor", "codex"] ``` -Supported: `claude`, `cursor`, `codex`, `opencode`, `copilot`, `antigravity`. +Supported: `claude`, `cursor`, `codex`, `opencode`, `copilot`, `pi`. Each maps to that tool's expected skill directory. --- diff --git a/docs/overrides/main.html b/docs/overrides/main.html index 506cee4b..9c4ee1bf 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -46,7 +46,7 @@ "@type": "SoftwareApplication", "name": "agr", "alternateName": "Agent Resources", - "description": "The package manager for AI agents. Install, share, and sync agent resources across Claude Code, Cursor, Codex, OpenCode, Copilot, and Antigravity. Built for teams practicing Agentic Engineering.", + "description": "The package manager for AI agents. Install, share, and sync agent resources across Claude Code, Cursor, Codex, OpenCode, Copilot, and Pi. Built for teams practicing Agentic Engineering.", "applicationCategory": "DeveloperApplication", "operatingSystem": "Cross-platform", "url": "https://computerlovetech.github.io/agr/", @@ -65,7 +65,7 @@ }, "featureList": [ "Install AI agent resources from GitHub with one command", - "Multi-tool support: Claude Code, Cursor, Codex, OpenCode, Copilot, Antigravity", + "Multi-tool support: Claude Code, Cursor, Codex, OpenCode, Copilot, Pi", "Team sync via agr.toml", "Ephemeral skill runner (agrx)", "Python SDK for programmatic access" @@ -78,7 +78,7 @@ "OpenAI Codex", "OpenCode", "GitHub Copilot", - "Antigravity", + "Pi", "skills", "developer tools" ] @@ -273,7 +273,7 @@ "name": "How do I fix \"Unknown tool\" in agr?", "acceptedAnswer": { "@type": "Answer", - "text": "Check your agr.toml for typos in the tools list. Available tools are: claude (Claude Code), cursor (Cursor), codex (OpenAI Codex), opencode (OpenCode), copilot (GitHub Copilot), and antigravity (Antigravity)." + "text": "Check your agr.toml for typos in the tools list. Available tools are: claude (Claude Code), cursor (Cursor), codex (OpenAI Codex), opencode (OpenCode), copilot (GitHub Copilot), and pi (Pi)." } }, { @@ -281,7 +281,7 @@ "name": "Why does agr init detect a tool I don't use?", "acceptedAnswer": { "@type": "Answer", - "text": "Some detection signals are shared between tools. For example, the .agents/ directory detects both OpenAI Codex and Antigravity because both tools use that path. Override detection with: agr init --tools claude,codex — or remove unwanted tools after setup with: agr config remove tools antigravity." + "text": "Some detection signals are shared between tools. For example, the .agents/ directory detects both OpenAI Codex and Pi because both tools read skills from that path. Override detection with: agr init --tools claude,codex — or remove unwanted tools after setup with: agr config remove tools pi." } }, { @@ -358,10 +358,10 @@ }, { "@type": "Question", - "name": "Why can't I use agrx with Antigravity?", + "name": "Where does agr install Pi skills?", "acceptedAnswer": { "@type": "Answer", - "text": "Antigravity does not have a standalone CLI, so agrx cannot run skills with it. Use agr add to install skills permanently, then invoke them through the Antigravity IDE interface." + "text": "agr installs Pi skills into .pi/skills/ in your project (and ~/.pi/agent/skills/ for global installs). Pi also reads the shared .agents/skills/ path, and agr detects Pi from a .pi/ or .agents/ directory. Pi has a CLI, so agrx --tool pi can run skills ephemerally too." } }, { @@ -430,10 +430,10 @@ }, { "@type": "Question", - "name": "How do I fix \"canonical_instructions must be 'AGENTS.md', 'CLAUDE.md', or 'GEMINI.md'\" in agr?", + "name": "How do I fix \"canonical_instructions must be 'AGENTS.md' or 'CLAUDE.md'\" in agr?", "acceptedAnswer": { "@type": "Answer", - "text": "Only three instruction file names are supported for syncing: AGENTS.md, CLAUDE.md, and GEMINI.md. Other filenames like README.md or INSTRUCTIONS.md won't work. Set it with: agr config set canonical_instructions CLAUDE.md." + "text": "Only two instruction file names are supported for syncing: AGENTS.md and CLAUDE.md. Other filenames like README.md or INSTRUCTIONS.md won't work. Set it with: agr config set canonical_instructions CLAUDE.md." } }, { @@ -561,7 +561,7 @@ "name": "How do I fix \"Unknown tool(s)\" from agr config?", "acceptedAnswer": { "@type": "Answer", - "text": "You passed an unrecognized tool name to agr config set tools, agr config add tools, or agr config remove tools. Check for typos — valid names are: claude, cursor, codex, opencode, copilot, antigravity." + "text": "You passed an unrecognized tool name to agr config set tools, agr config add tools, or agr config remove tools. Check for typos — valid names are: claude, cursor, codex, opencode, copilot, pi." } }, { @@ -719,7 +719,7 @@ { "@type": "DefinedTerm", "name": "agrx errors", - "description": "Fix tool CLI not found, Antigravity not supported, and running agrx outside a git repository" + "description": "Fix tool CLI not found and running agrx outside a git repository" } ], "keywords": ["agr troubleshooting", "agr errors", "fix agr", "agr sync not working", "GitHub authentication agr", "skill not found agr"] @@ -743,7 +743,7 @@ }, { "@type": "HowToTool", - "name": "An AI coding tool (Claude Code, Cursor, Codex, OpenCode, Copilot, or Antigravity)" + "name": "An AI coding tool (Claude Code, Cursor, Codex, OpenCode, Copilot, or Pi)" }, { "@type": "HowToTool", @@ -793,7 +793,7 @@ "@context": "https://schema.org", "@type": "HowTo", "name": "Get Started with agr: Install, Add, and Share AI Agent Skills", - "description": "Step-by-step guide to installing agr, adding AI agent skills to Claude Code, Cursor, Codex, OpenCode, Copilot, or Antigravity, syncing skills across a team, and creating your own.", + "description": "Step-by-step guide to installing agr, adding AI agent skills to Claude Code, Cursor, Codex, OpenCode, Copilot, or Pi, syncing skills across a team, and creating your own.", "totalTime": "PT10M", "tool": [ { @@ -852,7 +852,7 @@ "@context": "https://schema.org", "@type": "HowTo", "name": "Share AI Agent Skills Across a Team with agr", - "description": "Set up agr so your team shares the same AI coding agent skills across Claude Code, Cursor, Codex, OpenCode, Copilot, and Antigravity — with agr.toml as a single source of truth.", + "description": "Set up agr so your team shares the same AI coding agent skills across Claude Code, Cursor, Codex, OpenCode, Copilot, and Pi — with agr.toml as a single source of truth.", "totalTime": "PT10M", "tool": [ { @@ -907,7 +907,7 @@ "@context": "https://schema.org", "@type": "HowTo", "name": "Try AI Agent Skills Without Installing — agrx", - "description": "Use agrx to download and run AI agent skills ephemerally in Claude Code, Cursor, Codex, OpenCode, Copilot, or Antigravity — no agr.toml changes, no cleanup needed.", + "description": "Use agrx to download and run AI agent skills ephemerally in Claude Code, Cursor, Codex, OpenCode, Copilot, or Pi — no agr.toml changes, no cleanup needed.", "totalTime": "PT2M", "tool": [ { @@ -956,7 +956,7 @@ "@context": "https://schema.org", "@type": "HowTo", "name": "Configure agr for Multi-Tool Setup, Sources, and Instruction Syncing", - "description": "Configure agr.toml for multi-tool setup across Claude Code, Cursor, Codex, OpenCode, Copilot, and Antigravity — custom Git sources, instruction syncing, and global installs.", + "description": "Configure agr.toml for multi-tool setup across Claude Code, Cursor, Codex, OpenCode, Copilot, and Pi — custom Git sources, instruction syncing, and global installs.", "totalTime": "PT5M", "tool": [ { @@ -980,7 +980,7 @@ { "@type": "HowToStep", "name": "Enable instruction syncing", - "text": "Run agr config set sync_instructions true and agr config set canonical_instructions CLAUDE.md to keep CLAUDE.md, AGENTS.md, and GEMINI.md in sync across tools.", + "text": "Run agr config set sync_instructions true and agr config set canonical_instructions CLAUDE.md to keep CLAUDE.md and AGENTS.md in sync across tools.", "url": "https://computerlovetech.github.io/agr/configuration/#instruction-syncing" }, { @@ -1006,7 +1006,7 @@ "@context": "https://schema.org", "@type": "TechArticle", "headline": "Configure agr.toml — Multi-Tool Setup, Sources, and Instruction Syncing", - "description": "Configure agr.toml for multi-tool setup across Claude Code, Cursor, Codex, OpenCode, Copilot, and Antigravity — custom Git sources, instruction syncing, and global installs.", + "description": "Configure agr.toml for multi-tool setup across Claude Code, Cursor, Codex, OpenCode, Copilot, and Pi — custom Git sources, instruction syncing, and global installs.", "url": "https://computerlovetech.github.io/agr/configuration/", "author": { "@type": "Person", @@ -1022,7 +1022,7 @@ { "@type": "DefinedTerm", "name": "tools", - "description": "List of AI coding tools to install skills into — claude, cursor, codex, opencode, copilot, antigravity" + "description": "List of AI coding tools to install skills into — claude, cursor, codex, opencode, copilot, pi" }, { "@type": "DefinedTerm", @@ -1037,7 +1037,7 @@ { "@type": "DefinedTerm", "name": "sync_instructions", - "description": "When true, agr sync copies the canonical instruction file (CLAUDE.md, AGENTS.md, or GEMINI.md) to other tools' instruction files" + "description": "When true, agr sync copies the canonical instruction file (CLAUDE.md or AGENTS.md) to other tools' instruction files" }, { "@type": "DefinedTerm", @@ -1061,8 +1061,8 @@ { "@context": "https://schema.org", "@type": "HowTo", - "name": "Install AI Skills Across Claude Code, Cursor, Codex, Copilot, OpenCode, and Antigravity", - "description": "Configure agr to install AI agent skills into multiple coding tools at once — Claude Code, Cursor, OpenAI Codex, OpenCode, GitHub Copilot, and Antigravity.", + "name": "Install AI Skills Across Claude Code, Cursor, Codex, Copilot, OpenCode, and Pi", + "description": "Configure agr to install AI agent skills into multiple coding tools at once — Claude Code, Cursor, OpenAI Codex, OpenCode, GitHub Copilot, and Pi.", "totalTime": "PT5M", "tool": [ { @@ -1086,7 +1086,7 @@ { "@type": "HowToStep", "name": "Sync instruction files", - "text": "Enable instruction syncing with agr config set sync_instructions true and agr config set canonical_instructions CLAUDE.md. On agr sync, the canonical file is copied to AGENTS.md and GEMINI.md as needed.", + "text": "Enable instruction syncing with agr config set sync_instructions true and agr config set canonical_instructions CLAUDE.md. On agr sync, the canonical file is copied to AGENTS.md as needed.", "url": "https://computerlovetech.github.io/agr/tools/#keep-instruction-files-in-sync-across-tools" } ] @@ -1098,8 +1098,8 @@ { "@context": "https://schema.org", "@type": "TechArticle", - "headline": "Install AI Skills in Claude Code, Cursor, Codex, Copilot, OpenCode, and Antigravity", - "description": "How agr installs skills into Claude Code, Cursor, Codex, GitHub Copilot, OpenCode, and Antigravity — directories, detection signals, and multi-tool setup.", + "headline": "Install AI Skills in Claude Code, Cursor, Codex, Copilot, OpenCode, and Pi", + "description": "How agr installs skills into Claude Code, Cursor, Codex, GitHub Copilot, OpenCode, and Pi — directories, detection signals, and multi-tool setup.", "url": "https://computerlovetech.github.io/agr/tools/", "author": { "@type": "Person", @@ -1139,11 +1139,11 @@ }, { "@type": "DefinedTerm", - "name": "Antigravity", - "description": "Google's AI coding agent — skills in .gemini/skills/, no CLI available, detected by .gemini/ and .agents/" + "name": "Pi", + "description": "Minimal terminal coding agent (pi.dev) — skills in .pi/skills/ (global ~/.pi/agent/skills/), pi CLI available, detected by .pi/ and .agents/" } ], - "keywords": ["agr supported tools", "Claude Code skills", "Cursor skills", "Codex skills", "OpenCode skills", "GitHub Copilot skills", "Antigravity skills", "multi-tool AI setup"] + "keywords": ["agr supported tools", "Claude Code skills", "Cursor skills", "Codex skills", "OpenCode skills", "GitHub Copilot skills", "Pi skills", "multi-tool AI setup"] } {% endif %} @@ -1269,7 +1269,7 @@ "@context": "https://schema.org", "@type": "TechArticle", "headline": "CLI Reference — All agr and agrx Commands, Flags, and Options", - "description": "Complete CLI reference for agr and agrx — all commands, flags, and handle formats for managing AI agent skills across Claude Code, Cursor, Codex, OpenCode, Copilot, and Antigravity.", + "description": "Complete CLI reference for agr and agrx — all commands, flags, and handle formats for managing AI agent skills across Claude Code, Cursor, Codex, OpenCode, Copilot, and Pi.", "url": "https://computerlovetech.github.io/agr/reference/", "author": { "@type": "Person", @@ -1351,7 +1351,7 @@ { "@type": "DefinedTerm", "name": "Tool", - "description": "An AI coding agent (Claude Code, Cursor, Codex, OpenCode, Copilot, or Antigravity) that reads and executes skills" + "description": "An AI coding agent (Claude Code, Cursor, Codex, OpenCode, Copilot, or Pi) that reads and executes skills" }, { "@type": "DefinedTerm", @@ -1391,8 +1391,8 @@ "about": [ { "@type": "DefinedTerm", - "name": "Antigravity .gemini/ migration", - "description": "Skills now install to .gemini/skills/ with automatic migration from .agent/skills/" + "name": "Pi support", + "description": "Skills install to .pi/skills/ (global ~/.pi/agent/skills/) with pi CLI support" }, { "@type": "DefinedTerm", @@ -1407,7 +1407,7 @@ { "@type": "DefinedTerm", "name": "Multi-tool support", - "description": "Skills install to Claude Code, Cursor, Codex, OpenCode, Copilot, and Antigravity simultaneously" + "description": "Skills install to Claude Code, Cursor, Codex, OpenCode, Copilot, and Pi simultaneously" }, { "@type": "DefinedTerm", @@ -1427,7 +1427,7 @@ "@context": "https://schema.org", "@type": "CollectionPage", "name": "AI Agent Skill Directory — Browse and Install Skills for Claude Code, Cursor, Codex, and More", - "description": "Browse official and community AI agent skills available for agr — PDF, frontend design, API integration, Go, Drupal, and more. Install into Claude Code, Cursor, Codex, OpenCode, Copilot, or Antigravity with one command.", + "description": "Browse official and community AI agent skills available for agr — PDF, frontend design, API integration, Go, Drupal, and more. Install into Claude Code, Cursor, Codex, OpenCode, Copilot, or Pi with one command.", "url": "https://computerlovetech.github.io/agr/skills/", "mainEntity": { "@type": "ItemList", diff --git a/docs/reference.md b/docs/reference.md index c578997b..d0cf1fed 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -100,7 +100,7 @@ agr run pdf --tool cursor | Flag | Default | Description | |---------------------|------------|--------------------------------------------------------------------------------------| -| `-t, --tool` | configured | Tool CLI: `claude`, `cursor`, `codex`, `opencode`, `copilot`, `antigravity`. | +| `-t, --tool` | configured | Tool CLI: `claude`, `cursor`, `codex`, `opencode`, `copilot`, `pi`. | | `-i, --interactive` | false | Invoke the tool in interactive mode with the skill prefilled. | | `-p, --prompt` | | Extra prompt text appended after the skill reference. | diff --git a/skills/agr-cli/SKILL.md b/skills/agr-cli/SKILL.md index 3054e37f..d0a4840b 100644 --- a/skills/agr-cli/SKILL.md +++ b/skills/agr-cli/SKILL.md @@ -2,7 +2,7 @@ name: agr-cli description: > Install, share, sync, and create AI agent skills across coding tools (Claude - Code, Cursor, Codex, OpenCode, Copilot, Antigravity) using the agr CLI. Use + Code, Cursor, Codex, OpenCode, Copilot, Pi) using the agr CLI. Use whenever the user mentions agr, agr.toml, agr.lock, agrx, or asks to: add a skill ("install the pdf skill", "agr add ..."), sync agent resources across tools, share skills with their team, scaffold a new SKILL.md, run a skill @@ -16,7 +16,7 @@ description: > agr is the package manager for AI agent skills. It installs, shares, and syncs SKILL.md folders across Claude Code, Cursor, Codex, OpenCode, GitHub Copilot, -and Antigravity. This skill helps you operate the `agr` CLI on the user's +and Pi. This skill helps you operate the `agr` CLI on the user's behalf — set up new repos, install and sync skills, manage `agr.toml` / `agr.lock`, and scaffold in-repo skills under `skills/`. @@ -84,11 +84,11 @@ When the user wants to start using agr in a project that has none configured: 1. Run `agr init`. agr auto-detects which AI tools the repo uses (`.claude/`, `CLAUDE.md`, `.cursor/`, `.cursorrules`, `.codex/`, `.opencode/`, - `.github/copilot-instructions.md`, `.gemini/`) and writes `agr.toml`. + `.github/copilot-instructions.md`, `.pi/`, `.agents/`) and writes `agr.toml`. 2. Confirm or adjust the detected tools. For multi-tool: `agr config set tools claude codex opencode`. 3. If the user maintains a canonical instruction file (e.g. `CLAUDE.md`) and - wants it mirrored to others (`AGENTS.md`, `GEMINI.md`), enable instruction + wants it mirrored to others (`AGENTS.md`), enable instruction syncing: `agr config set sync_instructions true` then `agr config set canonical_instructions CLAUDE.md`. 4. Commit `agr.toml`. (`agr.lock` will appear after the first `agr add` or diff --git a/skills/agr-cli/references/configuration.md b/skills/agr-cli/references/configuration.md index 7a1d01b1..71f291be 100644 --- a/skills/agr-cli/references/configuration.md +++ b/skills/agr-cli/references/configuration.md @@ -26,7 +26,7 @@ Add `-g` / `--global` to operate on `~/.agr/agr.toml` instead of `./agr.toml`. | `default_owner` | string | `computerlovetech` | GitHub owner for 1-part handles (`agr add setup` → `/skills/setup`) | | `default_source` | string | `github` | Source used when `--source` is not specified | | `sync_instructions` | bool | `false` | Mirror canonical instruction file to other tools on `agr sync` | -| `canonical_instructions` | string | derived from `default_tool` | Source of truth: `CLAUDE.md`, `AGENTS.md`, or `GEMINI.md` | +| `canonical_instructions` | string | derived from `default_tool` | Source of truth: `CLAUDE.md` or `AGENTS.md` | | `sources` | list | `[github]` | Git URL templates (see [Sources](#sources)) | ## Common operations @@ -119,8 +119,8 @@ For GitLab, use `GITLAB_TOKEN`; for self-hosted Git, see your host's docs. ## Instruction syncing When the user maintains a canonical instructions file (e.g. `CLAUDE.md`) and -wants the same content in the other tools' equivalents (`AGENTS.md`, -`GEMINI.md`), enable instruction syncing: +wants the same content in the other tools' equivalents (`AGENTS.md`), +enable instruction syncing: ```bash agr config set sync_instructions true @@ -132,8 +132,7 @@ Then `agr sync` copies the canonical file to the others. Mappings: | Tool | Instruction file | |---|---| | Claude Code | `CLAUDE.md` | -| Codex / OpenCode / Copilot | `AGENTS.md` | -| Antigravity / Gemini | `GEMINI.md` | +| Codex / OpenCode / Copilot / Pi | `AGENTS.md` | Only fires when 2+ tools are configured. With one tool, it's a no-op. diff --git a/skills/agr-cli/references/running-skills.md b/skills/agr-cli/references/running-skills.md index 525fd911..1782f2ae 100644 --- a/skills/agr-cli/references/running-skills.md +++ b/skills/agr-cli/references/running-skills.md @@ -104,7 +104,7 @@ Both commands shell out to the tool's CLI: | Codex | `codex` | | OpenCode | `opencode` | | Copilot | `gh copilot` | -| Antigravity | (IDE-driven) | +| Pi | `pi` | If the tool's CLI isn't installed, both commands will fail with a "command not found" error. Surface that clearly to the user — agr can't help install diff --git a/skills/agr-cli/references/setup.md b/skills/agr-cli/references/setup.md index 624b230a..afed375b 100644 --- a/skills/agr-cli/references/setup.md +++ b/skills/agr-cli/references/setup.md @@ -9,8 +9,8 @@ For the canonical CLI reference, run `agr init --help` or - `agr --version` works (install with `uv tool install agr` if not). - The repo has at least one supported AI tool's marker — `.claude/`, `CLAUDE.md`, `.cursor/`, `.cursorrules`, `.codex/`, `.opencode/`, - `.github/copilot-instructions.md`, `.gemini/`, etc. agr auto-detects from - these. + `.github/copilot-instructions.md`, `.pi/`, `.agents/`, etc. agr auto-detects + from these. ## Initialize @@ -33,7 +33,7 @@ Flags: | `--tools` | Comma-separated list of tools (override auto-detect) | | `--default-tool` | Tool used by `agrx` and instruction sync (defaults to first in `tools`) | | `--sync-instructions` / `--no-sync-instructions` | Mirror canonical instruction file to others on `agr sync` | -| `--canonical-instructions` | Source of truth for instructions: `CLAUDE.md`, `AGENTS.md`, or `GEMINI.md` | +| `--canonical-instructions` | Source of truth for instructions: `CLAUDE.md` or `AGENTS.md` | Anything you skip can be set later with `agr config`. @@ -54,7 +54,7 @@ Skills install into each configured tool's directory: | Codex | `.agents/skills//` (older repos: `.codex/`) | | OpenCode | `.opencode/skills//` (older: `.opencode/skill/`) | | GitHub Copilot | `.github/skills//` | -| Antigravity / Gemini | `.gemini/skills//` (older: `.agent/`) | +| Pi | `.pi/skills//` (global: `~/.pi/agent/skills/`) | `agr sync` runs migrations automatically when it sees old layouts. @@ -81,7 +81,7 @@ Mappings: - `CLAUDE.md` ↔ `.claude/CLAUDE.md` - `AGENTS.md` ↔ Codex / OpenCode -- `GEMINI.md` ↔ Antigravity +- `AGENTS.md` ↔ Pi `agr sync` copies the canonical file to the others. Only fires when 2+ tools are configured. If only one tool is configured, instruction syncing is a no-op. diff --git a/skills/agr-cli/references/syncing.md b/skills/agr-cli/references/syncing.md index 0de12738..b578ad1d 100644 --- a/skills/agr-cli/references/syncing.md +++ b/skills/agr-cli/references/syncing.md @@ -12,7 +12,7 @@ agr sync Runs four stages in order: 1. **Instruction sync** — copies the canonical instruction file - (`CLAUDE.md` / `AGENTS.md` / `GEMINI.md`) to the others. Fires only when + (`CLAUDE.md` / `AGENTS.md`) to the others. Fires only when `sync_instructions = true` and 2+ tools are configured. 2. **Migrations** — renames legacy skill directories (`.codex/skills/` → `.agents/skills/`, `.opencode/skill/` → From 0b23de139ff9c293ee94912649646b6f162b20cf Mon Sep 17 00:00:00 2001 From: Kasper Junge Date: Tue, 9 Jun 2026 14:02:40 +0200 Subject: [PATCH 3/3] docs: add implementation diary for the Antigravity-to-Pi swap Co-Authored-By: Claude Opus 4.8 --- .../2026-06-09-replace-antigravity-with-pi.md | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 docs/diary/2026-06-09-replace-antigravity-with-pi.md diff --git a/docs/diary/2026-06-09-replace-antigravity-with-pi.md b/docs/diary/2026-06-09-replace-antigravity-with-pi.md new file mode 100644 index 00000000..6f3a0a8f --- /dev/null +++ b/docs/diary/2026-06-09-replace-antigravity-with-pi.md @@ -0,0 +1,201 @@ +# Diary: Replace Antigravity tool support with Pi (pi.dev) + +Drop the Antigravity integration from agr and add support for Pi +(https://pi.dev), a minimal open-source terminal coding agent. agr models each +supported coding tool as a `ToolConfig` in `/agr/tool.py`; the work threads a +new tool through the registry, migrations, docs, the bundled `agr-cli` skill, +and the test suite. + +## Step 1: Research and plan the swap + +**Author:** main + +### Prompt Context + +**Verbatim prompt:** "I want to remove support for Antigravity and add support for Pi (pi.dev). Please research how to add support for Pi" +**Interpretation:** Remove every Antigravity touchpoint and add a fully-wired Pi tool, after researching how Pi discovers skills and runs from the CLI. +**Inferred intent:** A clean tool swap that matches Pi's real on-disk and CLI behavior, with tests and docs kept consistent, not a half-migration. + +### What I did +Mapped the Antigravity footprint with grep across `/agr`, `/tests`, `/docs`, and +`/skills`, then read the central registry `/agr/tool.py`, the migration logic in +`/agr/commands/migrations.py`, `/agr/detect.py`, and `/agr/instructions.py`. +Researched Pi via its docs and the `earendil-works/pi` repo: project skills live +in `.pi/skills/` (with `.agents/skills/` as an alias), global skills in +`~/.pi/agent/skills/`, instructions come from `AGENTS.md` (also `CLAUDE.md`), and +the `pi` CLI supports one-shot `-p/--print`, auto-approve `-a/--approve`, and +resume `--continue`. Wrote a plan file and confirmed two genuine decisions with +the user. + +### Why +Antigravity is wired through many layers; a registry-only edit would leave +dangling references in migrations, detection, docs, and ~10 test files. The +research pinned down the exact paths and flags so the `ToolConfig` matches +reality instead of guesses. + +### What worked +The `ToolConfig` dataclass already exposes every field Pi needs (CLI flags, +`global_config_dir` for asymmetric global paths, `detection_signals`, +`instruction_file`), so Pi is purely declarative — no new machinery. + +### What didn't work +First attempt to dispatch an Explore subagent for the codebase sweep was +rejected by the user mid-call; I fell back to running the grep/read sweep +directly, which was fine. + +### What I learned +Pi deliberately reads the shared `.agents/skills/` path that Codex also uses, so +Pi is an "alias-compatible" tool rather than a fully isolated one — that shapes +the detection and duplication tradeoffs below. + +### What was tricky +The install-path decision. Pi reads both `.pi/skills/` and `.agents/skills/`, so +either works functionally. The user initially leaned toward `.agents` (shared, +no duplication) then chose the Pi-native `.pi/skills/` + `~/.pi/agent/skills/` +layout, accepting that a user running both Codex and Pi gets the skill written +to both trees. + +### What warrants review +`/agr/tool.py` — the `PI` `ToolConfig`: confirm `config_dir=".pi"`, +`global_config_dir=".pi/agent"`, flags `-p`/`-a`/`--continue`, +`detection_signals=(".pi", ".agents")`, and `instruction_file="AGENTS.md"` match +Pi's documented behavior. + +### Future work +Reconsider whether Pi should detect on `.pi` only (see Step 3's review finding +about `.agents/` auto-adding Pi to Codex-only repos). + +## Step 2: Implement the swap across code, docs, and tests + +**Author:** main + +### Prompt Context + +**Verbatim prompt:** (plan approved via ExitPlanMode) — implement the approved plan. +**Interpretation:** Apply the registry change, delete Antigravity migrations, rewrite docs/skill references, and convert the test suite from Antigravity to Pi. +**Inferred intent:** Land a green, internally-consistent change with no Antigravity residue in shipping code or docs. + +### What I did +Replaced the `ANTIGRAVITY` config with `PI` in `/agr/tool.py` and the +`_ALL_TOOLS` tuple. Removed the Antigravity import and both Antigravity +migration blocks from `/agr/commands/migrations.py`. Fixed the +`--canonical-instructions` help text in `/agr/main.py`. Updated `/README.md`, +`/docs/managing.md`, `/docs/reference.md`, and every `agr-cli` skill reference +(`SKILL.md`, `setup.md`, `configuration.md`, `running-skills.md`, `syncing.md`) +to list Pi and drop `GEMINI.md`. Added a CHANGELOG entry. On the test side: +deleted `/tests/cli/agr/test_antigravity.py`, added +`/tests/cli/agr/test_pi.py`, and updated `test_tool.py`, `test_detect.py`, +`test_init.py`, `test_run.py`, `test_tool_flag.py`, `test_sync.py`, +`test_instructions.py`, `test_migrations.py`, and `test_config.py`. + +### Why +Every layer that enumerated tools or instruction files needed Pi in and +Antigravity out to stay consistent — the registry drives detection, sync, +migrations, CLI help, and the docs tests. + +### What worked +After the edits, `uv run pytest` surfaced exactly the expected fallout in one +pass, and `ruff`/`ty` were clean (ruff reformatted a few files). + +### What didn't work +One test failed because `GEMINI.md` is no longer a derived valid instruction +file: + +``` +agr.exceptions.ConfigError: canonical_instructions must be one of: 'AGENTS.md', 'CLAUDE.md' +FAILED tests/test_config.py::TestAgrConfig::test_load_canonical_instructions_gemini +``` + +I updated that test to use `AGENTS.md` (later refined in Step 3 into a +coercion test). Two run-time tests that asserted "tool has no CLI configured" +no longer had a CLI-less tool to exercise (Antigravity was the only one), so I +removed one and converted the agrx one into a positive `pi` CLI-not-found check. + +### What I learned +`INSTRUCTION_FILES` and the canonical-instructions validator are derived +dynamically from the live `TOOLS` registry, so removing a tool silently changes +which instruction filenames are accepted — a non-obvious ripple. + +### What was tricky +Distinguishing Antigravity-specific tests from generic ones. The `GEMINI.md` +fixtures in `/tests/unit/test_instructions.py` only use that filename as +arbitrary test data for the generic file-sync helper, so they stay valid and +were left untouched, whereas the `test_config.py` one was a real validity +assertion that had to change. + +### What warrants review +`/agr/commands/migrations.py` — confirm dropping the Antigravity `.agent/`→ +`.gemini/` and global subdir migrations is safe (skills already in a user's +`.gemini/` just go unmanaged). `/tests/cli/agr/test_pi.py` — confirm the +asserted `.pi/skills/` paths. + +### Future work +The `cli_command is None` branches in `/agr/runner.py` are now unreachable since +every tool has a CLI — candidate for deletion or a synthetic unit test. + +## Step 3: Code review and follow-up fixes + +**Author:** main (review dispatched to two general-purpose sub-agents) + +### Prompt Context + +**Verbatim prompt:** "/code-review ... dispatch two subagents to carefully review the code changes ... look at both architecture and implementation." +**Interpretation:** Run a competitive two-agent review over the full diff and act on the genuine findings. +**Inferred intent:** Catch consistency gaps and breaking changes the author missed before shipping. + +### What I did +Dispatched two competing review sub-agents over the working-tree diff, then +verified each finding against the source. Acted on three substantive ones: +fixed `/README.md:83` (the "Invoke with" column showed `pi` instead of the +skill prefix `/pdf`); swept ~36 stale Antigravity/`GEMINI.md` references out of +the shipping SEO template `/docs/overrides/main.html` (mkdocs `custom_dir`), +including repurposing the false "Why can't I use agrx with Antigravity?" FAQ; +and added a legacy coercion in `/agr/config.py` mapping +`canonical_instructions = "GEMINI.md"` to `AGENTS.md` on load, with a regression +test and a CHANGELOG "Changed" note. + +### Why +The reviewers correctly flagged that `main.html` ships with the site and was +entirely missed, that the README column documents invocation syntax (not the CLI +name), and that existing `agr.toml` files pinned to `GEMINI.md` would otherwise +hard-error on every command with no upgrade path. + +### What worked +The two-agent setup produced complementary findings: one focused on the missed +`main.html` and the breaking config validation, the other on the README +invocation column. Verifying before acting filtered out the carried-over +non-issues. + +### What didn't work +A first repo-wide grep missed two lowercase `antigravity` strings in +`main.html` (lines 564, 1025) because they sat in different phrasing than the +title-case sweep; a follow-up grep caught them. No command errors. + +### What I learned +`/docs/overrides/main.html` is a hand-maintained JSON-LD/SEO file under mkdocs +`custom_dir` — easy to forget because it isn't Markdown and isn't surfaced by +the prose-doc tests. It contains 24 JSON-LD blocks that must stay valid JSON +after edits. + +### What was tricky +Editing JSON-LD by hand: a botched comma or quote silently breaks a block, so I +validated all 24 blocks parse with a small Python json.loads check after the +sweep rather than trusting the edits. + +### What warrants review +`/agr/config.py` — the `GEMINI.md`→`AGENTS.md` coercion on load (silent, with a +comment). `/docs/overrides/main.html` — the Pi tool card, the rewritten FAQ, and +the instruction-file FAQs. + +### Future work +Two acknowledged-but-deferred items: delete or unit-test the now-unreachable +`cli_command is None` branches in `/agr/runner.py`; and reconsider dropping +`.agents` from Pi's `detection_signals` so a Codex-only repo doesn't auto-add +`pi`. + +## Final verification + +`uv run pytest` — 1304 passed, 6 skipped. `uv run ruff check .` and +`uv run ty check` — clean. `uv run mkdocs build --strict` — succeeds. No +Antigravity/Gemini references remain outside intentional CHANGELOG history, the +legacy-coercion code comment, and the regression-test docstring.