Skip to content

feat: Antigravity CLI harness support — agent.json, native skills, install/uninstall workflow#562

Open
mhenke wants to merge 4 commits into
wshobson:mainfrom
mhenke:feature/antigravity-agents-one
Open

feat: Antigravity CLI harness support — agent.json, native skills, install/uninstall workflow#562
mhenke wants to merge 4 commits into
wshobson:mainfrom
mhenke:feature/antigravity-agents-one

Conversation

@mhenke

@mhenke mhenke commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Add Antigravity CLI as a sixth harness in the multi-harness adapter framework. Introduces a new adapter (tools/adapters/antigravity.py) that transpiles the canonical plugins/<name>/ source-of-truth into Antigravity-native formats, plus supporting infrastructure: install/uninstall workflow, drift detection, validation, and tests.

Impact: 15 files changed (+937/−37), 2 commits
Risk: 🟢 Low — isolated to new adapter + harness plumbing
Review: ~15 min

What Changed

Source — New Adapter

File Status Purpose
tools/adapters/antigravity.py NEW Emits agent.json per subagent, SKILL.md per skill. Maps Claude model aliases to Gemini model IDs
tools/adapters/capabilities.py Modified Registers Antigravity capability flags, tool-name map, model-alias resolution
tools/adapters/base.py Modified Adds AgentSource.model property
tools/generate.py Modified Registers in harness output targets, adapter lookup, prune, CLI help
tools/validate_generated.py Modified Adds validate_antigravity() — schema checks for agent.json, skill frontmatter
tools/doc_gardener.py Modified Adds drift detection for .antigravity/ artifacts

Install/Uninstall

File Status Purpose
tools/install_antigravity.py NEW Symlinks .antigravity/ into Antigravity CLI config dir; supports install/uninstall/list
Makefile Modified Adds install-antigravity/uninstall-antigravity targets + antigravity to HARNESSES

Tests

File Status Purpose
tools/tests/test_adapters.py Modified TestAntigravityAdapter — agent.json emission, tool rewriting, model aliases
tools/tests/test_round_trip.py Modified TestAntigravityRoundTrip — agent/skill counts match source
tools/tests/test_validate_generated.py Modified Validation rules for antigravity output
tools/tests/test_install_antigravity.py NEW Install/uninstall symlink workflow tests

Docs

File Status Purpose
docs/harnesses.md Modified Full capability matrix row, graceful degradation table, output paths
AGENTS.md Modified Mentions antigravity in make generate targets
.gitignore Modified Adds .antigravity/, .agents/, .agent/

Design

Follows the Copilot adapter pattern:

  1. Agent emission: plugins/<p>/agents/<a>.md -> .antigravity/agents/<p>__<a>/agent.json with Gemini model IDs, tool allowlists, customAgentSpec
  2. Skill emission: plugins/<p>/skills/<s>/SKILL.md -> .antigravity/skills/<p>__<s>/SKILL.md
  3. Command to skill: plugins/<p>/commands/<c>.md -> .antigravity/skills/<p>-<c>/SKILL.md (hyphen naming)
  4. Model mapping: opus/sonnet -> gemini-2.5-pro, haiku -> gemini-2.5-flash
  5. Tool mapping: Claude Code tool names -> Antigravity CLI lowercase equivalents (e.g. Read -> view_file, Bash -> run_command)

Checklist

  • Code follows project style (ruff, no unused imports)
  • agent.json schema matches Antigravity CLI spec
  • Tool names are lowercase (Antigravity convention)
  • Command to skill uses hyphen naming
  • All new code is covered by tests
  • Round-trip tests verify counts match source
  • Install script handles existing symlinks and missing dirs
  • No hardcoded paths
  • Backwards compatibility maintained

Test Plan

  • make validate STRICT=1
  • make garden
  • make test
  • make smoke-test
  • Ran ruff + ty in plugins/plugin-eval/
  • Spot-checked: make generate HARNESS=antigravity
  • Spot-checked: make install-antigravity
  • Spot-checked: agent/skill counts match source

Risk Assessment

Overall: Low

Factor Score Detail
Size 1/10 937 lines, well within reviewable range
Complexity 2/10 Follows established Copilot adapter pattern
Coverage 1/10 4 test files: adapter, round-trip, validation, install
Dependencies 1/10 No new external deps

Related issue(s)

Closes #560

Copilot AI review requested due to automatic review settings May 26, 2026 20:07
@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Antigravity CLI as a sixth harness: updates docs/Makefile/.gitignore, implements AntigravityAdapter to emit .antigravity artifacts, wires generator/pruner/validator, adds tools/install_antigravity CLI, and introduces tests for emission, install/uninstall, round-trip counts, and validation.

Changes

Antigravity CLI Harness Support

Layer / File(s) Summary
Documentation & Build Configuration
.gitignore, AGENTS.md, ARCHITECTURE.md, CONTRIBUTING.md, Makefile, README.md, docs/authoring.md, docs/harnesses.md, docs/round-trip-results.md
Add Antigravity to documentation, update harness count to six, document .antigravity/ outputs, add install-antigravity/uninstall-antigravity Makefile targets, and update gitignore and quickstart entries.
Adapter Framework & Capabilities
tools/adapters/base.py, tools/adapters/capabilities.py
Add CommandSource.aliases property; register Antigravity in CAPABILITIES, TOOL_NAME_MAPS, and MODEL_ALIASES.
AntigravityAdapter Implementation
tools/adapters/antigravity.py
Implement AntigravityAdapter to emit .antigravity/agents/*/agent.json, .antigravity/skills/*/SKILL.md, and .antigravity/workflows/*.md with YAML frontmatter, tool-name rewriting, model resolution, and mirrored compatibility outputs.
Generator Wiring & Orphan Pruning
tools/generate.py
Add Antigravity targets in _HARNESS_TARGETS, lazy-import AntigravityAdapter in get_adapter(), extend prune_orphans() to remove unwritten Antigravity artifacts, and update CLI help.
Doc Gardener Staleness Detection
tools/doc_gardener.py
Map generated Antigravity agents/skills/workflows back to source plugin files, add fallback resolution for hyphenated skill names, and include .agent/.agents mirrored trees in staleness checks.
Validation Rules & Registration
tools/validate_generated.py
Add validate_antigravity(report) validating SKILL.md frontmatter names, agent.json required/typed fields and nested customAgentSpec sections, workflows frontmatter/body, and register under _VALIDATORS.
Artifact Install/Uninstall CLI
tools/install_antigravity.py
New CLI to discover .antigravity/ artifacts, create idempotent symlinks into user config dirs, support --force replacement, list installed symlinks, and safely uninstall repo-owned symlinks with reporting.
Adapter, Install, Round-Trip & Validator Tests
tools/tests/test_adapters.py, tools/tests/test_install_antigravity.py, tools/tests/test_round_trip.py, tools/tests/test_validate_generated.py
Add TestAntigravityAdapter (emission and tool-name rewriting), TestInstallAntigravity (install/uninstall/force/idempotency), TestAntigravityRoundTrip (counts and JSON required fields), and TestAntigravityValidator (validation error cases); minor adapter test formatting adjustments.
Miscellaneous Refactoring
tools/yt-design-extractor/yt-design-extractor.py, minor formatting in tools/doc_gardener.py, tools/validate_generated.py
Use _rel for unused loop variable and small CLI/printing reformatting changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • wshobson/agents#555: Modifies tools/doc_gardener.py stale-artifact scanner with harness-specific generated↔source mappings.

Suggested reviewers

  • wshobson
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main feature: adding Antigravity CLI as a sixth harness with agent.json, skills, and install/uninstall workflows.
Description check ✅ Passed The PR description provides comprehensive context about the Antigravity CLI harness implementation, including scope, design patterns, test coverage, and risk assessment, all aligned with the changeset.
Linked Issues check ✅ Passed The PR implementation fully addresses all coding requirements from issue #560: agent.json emission [560], skill/command file generation [560], tool name rewriting [560], model mapping [560], installation workflow [560], validation [560], and comprehensive test coverage [560].
Out of Scope Changes check ✅ Passed All changes are within scope of implementing the Antigravity CLI harness. Documentation updates, .gitignore modifications, and infrastructure changes are all necessary and directly related to harness support. No unrelated refactoring or feature creep detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mhenke mhenke force-pushed the feature/antigravity-agents-one branch from de680eb to 1de2200 Compare May 26, 2026 20:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds Antigravity as a first-class harness alongside Codex/Copilot/Cursor/OpenCode/Gemini, including generation, validation, installation helpers, and test coverage.

Changes:

  • Introduces AntigravityAdapter and registers it in generation + capabilities.
  • Adds Antigravity artifact validation, round-trip tests, and install/uninstall symlink helper.
  • Updates docs/Makefile to expose the new harness workflows.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tools/validate_generated.py Adds Antigravity validator and registers it in _VALIDATORS.
tools/tests/test_validate_generated.py Adds unit tests for validate_antigravity.
tools/tests/test_round_trip.py Adds round-trip consistency checks for generated Antigravity artifacts.
tools/tests/test_install_antigravity.py Adds tests for Antigravity install/uninstall helper behavior.
tools/tests/test_adapters.py Adds adapter-level tests verifying Antigravity JSON/skill emission and tool rewriting.
tools/install_antigravity.py New helper CLI to symlink .antigravity artifacts into user config dirs.
tools/generate.py Registers antigravity harness and output paths; adds pruning support.
tools/doc_gardener.py Adds stale-artifact drift detection for .antigravity outputs.
tools/adapters/capabilities.py Adds Antigravity capability row + tool/model alias mappings.
tools/adapters/base.py Adds aliases accessor (used by Antigravity workflow emission).
tools/adapters/antigravity.py New Antigravity adapter emitting agent.json, SKILL.md, and workflows.
plugins/plugin-eval/tests/test_stats.py Import formatting tweak (no functional change).
plugins/plugin-eval/tests/test_parser.py Import cleanup/formatting (no functional change).
plugins/plugin-eval/tests/test_monte_carlo.py Removes unused AsyncMock import; formatting.
plugins/plugin-eval/tests/test_models.py Removes unused imports.
plugins/plugin-eval/tests/test_judge.py Removes unused AsyncMock import.
plugins/plugin-eval/tests/test_harness_portability.py Formatting + removes unused pytest import.
plugins/plugin-eval/tests/test_engine.py Removes unused pytest import.
plugins/plugin-eval/tests/test_corpus.py Removes unused pytest import.
plugins/backend-development/skills/api-design-principles/assets/rest-api-template.py Formatting + removes unused FastAPI imports.
docs/harnesses.md Adds Antigravity to harness list, matrix, and regeneration instructions.
Makefile Adds install-antigravity/uninstall-antigravity targets and adds harness to HARNESSES.
AGENTS.md Mentions Antigravity as a consumer + adds generation instructions.
.gitignore Adjusts generated/runtime ignores (Codex/.agent/.agents).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/generate.py Outdated
Comment thread tools/generate.py
Comment thread AGENTS.md Outdated
Comment thread AGENTS.md Outdated
Comment thread docs/harnesses.md Outdated
Comment thread docs/harnesses.md Outdated
Comment thread tools/doc_gardener.py Outdated
Comment thread tools/validate_generated.py Outdated
@mhenke mhenke force-pushed the feature/antigravity-agents-one branch from 618fc43 to 4c33f17 Compare May 26, 2026 20:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tools/tests/test_adapters.py (1)

8-25: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix import ordering to satisfy ruff.

The pipeline reports that the import block is un-sorted. The AntigravityAdapter import at line 25 should be moved before the base import (line 15) to maintain alphabetical order by module name.

📦 Proposed fix
 from __future__ import annotations
 
 import json
 import re
 from pathlib import Path
 
 # tools.adapters.* imports happen via the conftest sys.path injection
+from tools.adapters.antigravity import AntigravityAdapter
 from tools.adapters.base import PluginSource, parse_frontmatter
 from tools.adapters.codex import CodexAdapter, _split_body_if_oversized
 from tools.adapters.copilot import (
     CopilotAdapter,
     _build_tools_list,
     _needs_yaml_quoting,
 )
 from tools.adapters.cursor import CursorAdapter
 from tools.adapters.gemini import _INLINE_BODY_THRESHOLD, GeminiAdapter
 from tools.adapters.opencode import OpenCodeAdapter, _opencode_skill_id
-from tools.adapters.antigravity import AntigravityAdapter

As per coding guidelines: use ruff for linting and formatting Python code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/tests/test_adapters.py` around lines 8 - 25, The import block in
tools/tests/test_adapters.py is unsorted per ruff: move the local adapter import
for AntigravityAdapter (currently imported from tools.adapters.antigravity) so
it appears alphabetically among the other tools.adapters.* imports —
specifically place the "from tools.adapters.antigravity import
AntigravityAdapter" line before "from tools.adapters.base import PluginSource,
parse_frontmatter" (and ensure the entire tools.adapters.* group is
alphabetized), keeping grouping of stdlib/third-party vs local imports intact.
Makefile (1)

25-25: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update help header harness list to include Copilot and Antigravity.

The section title is now stale versus actual supported harnesses and targets in this file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` at line 25, Update the Makefile help header string that currently
echoes "Multi-harness adapter (Codex / Cursor / OpenCode / Gemini):" so it lists
all supported harnesses including Copilot and Antigravity; locate the echo line
(the `@echo` "Multi-harness adapter (...)" statement) and edit the text to include
", Copilot / Antigravity" (or equivalent ordering/format) so the header matches
the actual supported harnesses and targets.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.gitignore:
- Around line 45-53: Add the missing .copilot/ entry back into the
generated-artifact ignore section so generated Copilot outputs stay untracked:
update the .gitignore to include a line with ".copilot/" alongside the existing
".codex/" and ".agents/" entries (ensure the trailing slash is present and no
contradictory entries later in the file), preserving the invariant that
generated harness artifacts are not committed.

In `@AGENTS.md`:
- Line 64: The Antigravity artifact path examples in AGENTS.md use
hyphen-separated names (`.antigravity/skills/<plugin>-<skill>/SKILL.md` and
similar) which contradict the PR contract; update the documented examples to use
the proper namespacing with double underscores (`<plugin>__<skill>` and
`<plugin>__<agent>`) wherever the hyphenated forms appear (including the entries
around the shown line and the one reported at 76), and ensure the text
consistently references `.antigravity/skills/<plugin>__<skill>/SKILL.md` and
`.antigravity/agents/<plugin>__<agent>/AGENT.md`.
- Around line 48-49: Update the note for the make target so it reflects the new
harness count: change the text after "make generate-all" from "all five" to "all
six" to account for the added Antigravity harness (see the make generate
HARNESS=antigravity entry that emits .antigravity/agents/ and
.antigravity/skills/ and the make generate-all line).

In `@docs/authoring.md`:
- Around line 108-110: The markdown table in docs/authoring.md has a malformed
separator row with too many columns, so update the separator row that follows
the header line "| Source field | Codex | Cursor | OpenCode | Gemini | Copilot |
Antigravity CLI |" to contain exactly seven column separators (e.g.,
"|---|---|---|---|---|---|---|") so it matches the header and the data row
(e.g., the "`model: opus`" row) to restore correct table rendering.

In `@docs/harnesses.md`:
- Line 18: The Antigravity CLI capability entries are inconsistent about
slash-command emission and output locations; update the "Antigravity CLI" row in
the capability matrix and the related prose sections (the entries referenced
around lines 26-27, 53, and 65) so they express one unified contract: explicitly
state whether Antigravity emits slash-commands or not, where outputs are written
(e.g., `.antigravity/agents/`, `.antigravity/skills/`), and define
graceful-degradation behavior when a feature is unsupported; ensure the matrix,
the "Antigravity CLI" description, and any examples all match this single agreed
behavior and output path convention.

In `@docs/round-trip-results.md`:
- Around line 114-120: Update the docs snippet to reflect the actual emitted
artifacts and installer target: replace the commands path
`.antigravity/commands/` with `.antigravity/workflows/`, and change the install
comment/target from symlinking to `~/.antigravity/` to symlinking to
`~/.gemini/antigravity-cli/` (the `make install-antigravity` step should
reference that target); ensure the listing lines and the "Global install
(optional)" installer instruction use these corrected paths so the documentation
matches the PR behavior.

In `@README.md`:
- Line 145: Update the README table row that currently lists the Antigravity CLI
install path as `.antigravity/` so it matches the actual installer destination
used by make install-antigravity; replace `.antigravity/` with
`~/.gemini/antigravity-cli/` (and verify the adjacent text mentioning `make
install-antigravity` remains consistent with this path) so the documented global
install location reflects the real installer output.

In `@tools/adapters/antigravity.py`:
- Around line 36-41: The current _rewrite_body_lowercase_tools only replaces
backticked tool names; update it to also replace plain-word occurrences by
iterating TOOL_NAME_MAPS["antigravity"] and performing two replacements per
mapping: the existing backtick replacement and a word-boundary/plain replacement
(use regex word boundaries or equivalent) so strings like "use the Read tool"
are converted to the Antigravity name; preserve existing behavior for backticked
names and ensure you reference TOOL_NAME_MAPS["antigravity"] and the function
name _rewrite_body_lowercase_tools when making the change.
- Around line 20-33: The _antigravity_frontmatter function currently builds YAML
by concatenating unquoted scalars and list items which breaks on characters like
:, #, commas or newlines; replace the hand-rolled serializer with a proper YAML
emitter (e.g., use yaml.safe_dump) to render the frontmatter safely: import
yaml, build the frontmatter dict in _antigravity_frontmatter and call
yaml.safe_dump(fm, default_flow_style=False, sort_keys=False) (or dump
individual values with yaml.safe_dump for scalars/lists) so booleans, lists,
multiline strings and special characters are correctly quoted/escaped and then
wrap the emitted YAML with the leading/trailing --- markers.

In `@tools/doc_gardener.py`:
- Around line 253-269: The stale-check currently only maps hyphenated
antigravity skill IDs to plugin command markdown under PLUGINS_DIR but
Antigravity command outputs are stored as workflows; update the logic around
antigravity_skills / skill_md / name to also scan the antigravity_root /
"workflows" directory and match hyphenated names to plugin workflow artifacts:
for names with "-" iterate list_plugins() to find plugin_name and cmd_name (as
you already do), then look for a source workflow under PLUGINS_DIR / plugin_name
/ "workflows" (use a glob for common extensions like .yaml/.yml/.json or pattern
f"{cmd_name}.*") and if src.is_file() append (src, skill_md) to pairs; keep the
existing SKILL.md resolution (PLUGINS_DIR / plugin / "skills" / leaf /
"SKILL.md") for the "__" case.

In `@tools/generate.py`:
- Line 37: clean_output() and prune_orphans() currently ignore
.antigravity/workflows, leaving stale workflow artifacts; update the antigravity
target list (the "antigravity" entry in tools/generate.py that currently
contains ".antigravity/agents" and ".antigravity/skills") to also include
".antigravity/workflows", and likewise add ".antigravity/workflows" to the other
target arrays referenced in the same file (the block around lines 168-172) so
both clean_output() and prune_orphans() will remove/handle workflows.

In `@tools/install_antigravity.py`:
- Around line 13-16: ARTIFACT_GLOBS currently maps only "agents" and "skills",
causing workflows to be skipped; update the ARTIFACT_GLOBS constant to include a
"workflows" entry (e.g., "workflows": "*") and then ensure the install/uninstall
code paths that iterate these globs (such as the functions handling artifact
discovery/processing in install_antigravity.py) treat "workflows" the same as
"agents"/"skills" so workflow artifacts are discovered and managed during
install and uninstall.

In `@tools/validate_generated.py`:
- Around line 741-779: The code currently allows customAgentSpec = null because
only non-dict non-null values hit the existing error branch; update the
validation after spec = data.get("customAgentSpec") to explicitly treat spec is
None as an error: add a branch that calls report.add (using the same
harness="antigravity", path=agent_json_path, and an appropriate
message/remediation) when spec is None, and keep the existing elif spec is not
None branch for other wrong types; ensure you reference the same variables
(spec, custom_agent, customAgentSpec, agent_json_path, report.add) so behavior
is consistent with surrounding validations.
- Around line 690-790: validate_antigravity currently only checks skills_dir and
agents_dir; add a commands_dir check (e.g., commands_dir = WORKTREE /
".antigravity" / "commands") and validate generated command workflow artifacts
similarly to agents: for each workflow file (e.g., glob("*/workflow.json") or
"*.json" under each command dir) attempt JSON.parse and report JSONDecodeError
via report.add, ensure required top-level keys exist (suggest at minimum "id",
"name", and "steps") and that "id" or "name" matches the parent directory when
present, ensure "steps" is a list and that each step is an object with required
keys (e.g., "action" or "run" and "inputs"), and use the same report.add pattern
(severity, harness="antigravity", path=..., message=..., remediation=...) for
missing fields or structural type errors; follow the patterns in
validate_antigravity (json.loads, report.add messages, checks for dict/list) and
place this new validation after the agents_dir block.

---

Outside diff comments:
In `@Makefile`:
- Line 25: Update the Makefile help header string that currently echoes
"Multi-harness adapter (Codex / Cursor / OpenCode / Gemini):" so it lists all
supported harnesses including Copilot and Antigravity; locate the echo line (the
`@echo` "Multi-harness adapter (...)" statement) and edit the text to include ",
Copilot / Antigravity" (or equivalent ordering/format) so the header matches the
actual supported harnesses and targets.

In `@tools/tests/test_adapters.py`:
- Around line 8-25: The import block in tools/tests/test_adapters.py is unsorted
per ruff: move the local adapter import for AntigravityAdapter (currently
imported from tools.adapters.antigravity) so it appears alphabetically among the
other tools.adapters.* imports — specifically place the "from
tools.adapters.antigravity import AntigravityAdapter" line before "from
tools.adapters.base import PluginSource, parse_frontmatter" (and ensure the
entire tools.adapters.* group is alphabetized), keeping grouping of
stdlib/third-party vs local imports intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6110976e-71a8-47ce-a3ff-b39b5618b7fc

📥 Commits

Reviewing files that changed from the base of the PR and between 05231aa and 4c33f17.

📒 Files selected for processing (20)
  • .gitignore
  • AGENTS.md
  • ARCHITECTURE.md
  • CONTRIBUTING.md
  • Makefile
  • README.md
  • docs/authoring.md
  • docs/harnesses.md
  • docs/round-trip-results.md
  • tools/adapters/antigravity.py
  • tools/adapters/base.py
  • tools/adapters/capabilities.py
  • tools/doc_gardener.py
  • tools/generate.py
  • tools/install_antigravity.py
  • tools/tests/test_adapters.py
  • tools/tests/test_install_antigravity.py
  • tools/tests/test_round_trip.py
  • tools/tests/test_validate_generated.py
  • tools/validate_generated.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use uv as the package manager for Python projects, not pip

Use ruff for linting and formatting Python code, not black or other linters

Use ty for type checking Python code, not mypy

Files:

  • tools/tests/test_install_antigravity.py
  • tools/adapters/base.py
  • tools/doc_gardener.py
  • tools/adapters/capabilities.py
  • tools/validate_generated.py
  • tools/adapters/antigravity.py
  • tools/tests/test_round_trip.py
  • tools/generate.py
  • tools/tests/test_validate_generated.py
  • tools/install_antigravity.py
  • tools/tests/test_adapters.py
AGENTS.md

📄 CodeRabbit inference engine (CLAUDE.md)

AGENTS.md: Import the canonical AGENTS.md file following Anthropic's recommended cross-harness convention pattern for repository setup
Honor the tools: frontmatter verbatim in agent configurations for per-agent tool allowlist specification

Keep AGENTS.md file lean and under ~150 lines per OpenAI's harness-engineering practice; push procedural detail to skills and reference material to docs/

Files:

  • AGENTS.md
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T20:19:17.043Z
Learning: Generated artifacts are gitignored and must never be hand-edited; source-of-truth lives only under `plugins/`
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T20:19:17.043Z
Learning: Never commit secrets to the repository
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T20:19:17.043Z
Learning: Never run destructive git operations (force-push, `reset --hard`, `branch -D`) without explicit approval
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T20:19:17.043Z
Learning: Run `make validate STRICT=1`, `make garden`, `make test`, and `make smoke-test` before pushing code
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T20:19:17.043Z
Learning: Codex/Cursor/OpenCode/Gemini CLI/Antigravity CLI must read from a single Markdown source-of-truth for plugins, agents, and skills
🪛 GitHub Actions: Code Quality / 0_Python (ruff + ty).txt
tools/tests/test_adapters.py

[error] 8-25: Ruff check failed due to unsorted/unformatted imports. Ruff: "Import block is un-sorted or un-formatted". Run ruff check --fix (help: Organize imports).

🪛 GitHub Actions: Code Quality / Python (ruff + ty)
tools/tests/test_adapters.py

[error] 8-25: ruff check failed: Import block is un-sorted or un-formatted. (help: Organize imports)

🔇 Additional comments (6)
tools/tests/test_adapters.py (2)

1185-1309: LGTM!


1311-1323: LGTM!

tools/tests/test_install_antigravity.py (1)

1-96: LGTM!

tools/tests/test_round_trip.py (1)

334-366: LGTM!

tools/tests/test_validate_generated.py (1)

11-11: LGTM!

Also applies to: 422-497

CONTRIBUTING.md (1)

3-5: LGTM!

Also applies to: 48-59

Comment thread .gitignore Outdated
Comment thread AGENTS.md Outdated
Comment thread AGENTS.md Outdated
Comment thread docs/authoring.md
Comment thread docs/harnesses.md Outdated
Comment thread tools/doc_gardener.py Outdated
Comment thread tools/generate.py Outdated
Comment thread tools/install_antigravity.py
Comment thread tools/validate_generated.py
Comment thread tools/validate_generated.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tools/install_antigravity.py (1)

147-147: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the missing list subcommand to match the install helper contract.

Line 147 only allows install/uninstall, but the PR objective for issue #560 calls for install/uninstall/list support. Right now users can’t inspect what would be managed without performing install/uninstall.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/install_antigravity.py` at line 147, The CLI parser currently restricts
the "action" argument to only ("install", "uninstall") in the
parser.add_argument call; update that call to include "list" (e.g.,
choices=("install","uninstall","list")) so the script supports the list
subcommand required by the install helper contract, and ensure any
action-handling code in functions like the action dispatcher recognizes and
handles the "list" case.
♻️ Duplicate comments (1)
docs/harnesses.md (1)

18-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align Antigravity command support docs to a single contract.

Line 18 (and Line 65) documents workflow emission, but the matrix still says Antigravity has no slash commands (Line 26) and Line 53 says commands are “converted to skill.” Please make these sections consistent around workflow-based command emission.

Suggested doc patch
-| Slash commands | ✅ | converted to skills | ✅ | ✅ | TOML at `commands/` | — |
+| Slash commands | ✅ | converted to skills | ✅ | ✅ | TOML at `commands/` | ✅ via `.antigravity/workflows/` |
@@
-| Slash command (`commands/<x>.md`) | converted to skill | passed through | rewritten to `.opencode/commands/` | TOML at `commands/<plugin>/<x>.toml` | converted to skill |
+| Slash command (`commands/<x>.md`) | converted to skill | passed through | rewritten to `.opencode/commands/` | TOML at `commands/<plugin>/<x>.toml` | rewritten to `.antigravity/workflows/<plugin>-<x>.md` |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/harnesses.md` at line 18, Unify the Antigravity command support
documentation by making the matrix row for "Antigravity CLI" and the descriptive
paragraphs about command handling consistent: update the table cell that
currently lists `.antigravity/agents/, .antigravity/skills/,
.antigravity/workflows/` (the "Antigravity CLI" row) and the paragraphs
mentioning "workflow emission", "no slash commands", and "converted to skill" so
they all state the same contract (e.g., that Antigravity emits workflow-based
slash commands via `.antigravity/workflows/`), and adjust the wording in the
sections referencing "workflow emission" and "converted to skill" to reflect
that slash commands are emitted as workflows rather than absent or merely
converted to skills.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tools/doc_gardener.py`:
- Around line 275-281: The prefix-matching loop in tools/doc_gardener.py can
pick the wrong plugin when plugin names overlap because it breaks on the first
name.startswith(f"{plugin_name}-") match; change the logic to find the best
(longest) matching plugin name instead of breaking early: iterate over
list_plugins() and track the plugin with the longest matching prefix for the
given name, compute cmd_name and src from that selected plugin (using
PLUGINS_DIR, cmd_name, src, pairs as in the diff), and only append if the best
match yields src.is_file(); apply the same longest-prefix selection fix to the
analogous block around lines 293-299.

In `@tools/generate.py`:
- Line 37: The Antigravity clean targets list variable (the mapping that
includes the "antigravity" key) is missing the ".agent/skills" path while
prune_orphans() scans that directory; update the "antigravity" array to include
".agent/skills" so --clean removes those artifacts as well—locate the
"antigravity" list in generate.py (the entry currently containing
".antigravity/agents", ".antigravity/skills", ".antigravity/workflows",
".agent/workflows", ".agents/workflows", ".agents/skills") and add the missing
".agent/skills" string to that list.

In `@tools/validate_generated.py`:
- Around line 732-734: The validation currently lets a present-but-null
description pass because it only checks desc is not None before validating;
change the condition to treat a key present with None as invalid by checking
membership and content: use the presence of "description" in data (e.g., if
"description" in data and (not isinstance(desc, str) or not desc.strip())) so
that desc == None triggers report.add; update the check around desc, data, and
report.add accordingly.

---

Outside diff comments:
In `@tools/install_antigravity.py`:
- Line 147: The CLI parser currently restricts the "action" argument to only
("install", "uninstall") in the parser.add_argument call; update that call to
include "list" (e.g., choices=("install","uninstall","list")) so the script
supports the list subcommand required by the install helper contract, and ensure
any action-handling code in functions like the action dispatcher recognizes and
handles the "list" case.

---

Duplicate comments:
In `@docs/harnesses.md`:
- Line 18: Unify the Antigravity command support documentation by making the
matrix row for "Antigravity CLI" and the descriptive paragraphs about command
handling consistent: update the table cell that currently lists
`.antigravity/agents/, .antigravity/skills/, .antigravity/workflows/` (the
"Antigravity CLI" row) and the paragraphs mentioning "workflow emission", "no
slash commands", and "converted to skill" so they all state the same contract
(e.g., that Antigravity emits workflow-based slash commands via
`.antigravity/workflows/`), and adjust the wording in the sections referencing
"workflow emission" and "converted to skill" to reflect that slash commands are
emitted as workflows rather than absent or merely converted to skills.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f59095a2-7970-4331-a15f-b69cb97a9497

📥 Commits

Reviewing files that changed from the base of the PR and between 4c33f17 and ce23b59.

📒 Files selected for processing (8)
  • docs/harnesses.md
  • docs/round-trip-results.md
  • tools/adapters/antigravity.py
  • tools/adapters/capabilities.py
  • tools/doc_gardener.py
  • tools/generate.py
  • tools/install_antigravity.py
  • tools/validate_generated.py
✅ Files skipped from review due to trivial changes (2)
  • tools/adapters/capabilities.py
  • docs/round-trip-results.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use 'ruff' for linting and formatting (not black or other formatters)

Use 'ty' for type checking (not mypy)

Files:

  • tools/doc_gardener.py
  • tools/generate.py
  • tools/validate_generated.py
  • tools/adapters/antigravity.py
  • tools/install_antigravity.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T20:26:30.376Z
Learning: Never commit secrets to the repository
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T20:26:30.376Z
Learning: Never run destructive git operations (force-push, reset --hard, branch -D) without explicit ask
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T20:26:30.376Z
Learning: Generated artifacts are gitignored and must never be hand-edited; source-of-truth lives only under plugins/
🔇 Additional comments (1)
tools/adapters/antigravity.py (1)

156-160: LGTM!

Comment thread tools/doc_gardener.py Outdated
Comment thread tools/generate.py Outdated
Comment thread tools/validate_generated.py
mhenke pushed a commit to mhenke/agents that referenced this pull request May 26, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tools/adapters/antigravity.py (1)

3-18: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix import ordering to unblock CI (Ruff I001).

Ruff is failing on this import block, so this PR cannot merge until imports are normalized.

Suggested fix
 from __future__ import annotations
 
 import json
 import re
 from pathlib import Path
 
 from tools.adapters.base import (
     AgentSource,
     CommandSource,
     EmitResult,
     HarnessAdapter,
     PluginSource,
     SkillSource,
     h1_from_body,
 )
 from tools.adapters.capabilities import TOOL_NAME_MAPS, resolve_model

As per coding guidelines: "**/*.py: Use ... ruff for linting/formatting".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/adapters/antigravity.py` around lines 3 - 18, The import block in
antigravity.py must be reordered to satisfy Ruff (I001): keep the from
__future__ import at top, then standard-library imports (json, re, Path from
pathlib) grouped and alphabetized, then third-party (none here), then local
application imports; move the tools.adapters.base imports (AgentSource,
CommandSource, EmitResult, HarnessAdapter, PluginSource, SkillSource,
h1_from_body) together and alphabetize the names, and finally the
tools.adapters.capabilities imports (TOOL_NAME_MAPS, resolve_model) as the last
group so Ruff’s import-order rule passes.
♻️ Duplicate comments (1)
tools/doc_gardener.py (1)

280-287: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid breaking on first prefix match when source file does not exist.

Line 286 and Line 306 break on the first matching plugin prefix even when src is missing, which can miss valid mappings for overlapping names (e.g., data vs data-analysis) and hide stale artifacts.

Suggested fix
             for plugin_name in sorted(plugin_names, key=len, reverse=True):
                 if name.startswith(f"{plugin_name}-"):
                     cmd_name = name[len(plugin_name) + 1 :]
                     src = PLUGINS_DIR / plugin_name / "commands" / f"{cmd_name}.md"
                     if src.is_file():
                         pairs.append((src, workflow_md))
-                    break
+                        break
@@
                 for plugin_name in sorted(plugin_names, key=len, reverse=True):
                     if name.startswith(f"{plugin_name}-"):
                         cmd_name = name[len(plugin_name) + 1 :]
                         src = PLUGINS_DIR / plugin_name / "commands" / f"{cmd_name}.md"
                         if src.is_file():
                             pairs.append((src, f))
-                        break
+                            break

Also applies to: 300-307

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/doc_gardener.py` around lines 280 - 287, The loop over plugin_names
currently breaks on the first prefix match regardless of whether the constructed
source file exists, which skips checking longer/overlapping plugin prefixes;
update the logic in the block using plugin_names, name.startswith(...) and
constructing cmd_name/ src (the PLUGINS_DIR / plugin_name / "commands" /
f"{cmd_name}.md" path) so that you only break after appending to pairs
(pairs.append((src, workflow_md))) — i.e., if src.is_file() is false, continue
the loop to try other matching prefixes instead of breaking; apply the same fix
to the other identical block that builds src and appends to pairs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tools/install_antigravity.py`:
- Around line 155-160: In list_installed (tools/install_antigravity.py) the else
branch that prints foreign symlinks (the f"  foreign: {subdir}/{dst.name} ->
{target}" line) never updates the report counters; modify that branch to
increment the appropriate counter (report.skipped += 1) so _print_report()
reflects the foreign total correctly, keeping the print statement and report
variable as-is.

---

Outside diff comments:
In `@tools/adapters/antigravity.py`:
- Around line 3-18: The import block in antigravity.py must be reordered to
satisfy Ruff (I001): keep the from __future__ import at top, then
standard-library imports (json, re, Path from pathlib) grouped and alphabetized,
then third-party (none here), then local application imports; move the
tools.adapters.base imports (AgentSource, CommandSource, EmitResult,
HarnessAdapter, PluginSource, SkillSource, h1_from_body) together and
alphabetize the names, and finally the tools.adapters.capabilities imports
(TOOL_NAME_MAPS, resolve_model) as the last group so Ruff’s import-order rule
passes.

---

Duplicate comments:
In `@tools/doc_gardener.py`:
- Around line 280-287: The loop over plugin_names currently breaks on the first
prefix match regardless of whether the constructed source file exists, which
skips checking longer/overlapping plugin prefixes; update the logic in the block
using plugin_names, name.startswith(...) and constructing cmd_name/ src (the
PLUGINS_DIR / plugin_name / "commands" / f"{cmd_name}.md" path) so that you only
break after appending to pairs (pairs.append((src, workflow_md))) — i.e., if
src.is_file() is false, continue the loop to try other matching prefixes instead
of breaking; apply the same fix to the other identical block that builds src and
appends to pairs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c147d5a0-a87a-497e-ba80-afae86b9881a

📥 Commits

Reviewing files that changed from the base of the PR and between ce23b59 and 1562530.

📒 Files selected for processing (30)
  • .gitignore
  • AGENTS.md
  • Makefile
  • README.md
  • docs/authoring.md
  • docs/harnesses.md
  • tools/adapters/antigravity.py
  • tools/adapters/base.py
  • tools/adapters/codex.py
  • tools/adapters/copilot.py
  • tools/adapters/cursor.py
  • tools/adapters/gemini.py
  • tools/adapters/opencode.py
  • tools/check_agent_name_collisions.py
  • tools/doc_gardener.py
  • tools/generate.py
  • tools/install_antigravity.py
  • tools/install_opencode.py
  • tools/tests/conftest.py
  • tools/tests/test_adapters.py
  • tools/tests/test_cli_smoke.py
  • tools/tests/test_doc_gardener.py
  • tools/tests/test_install_antigravity.py
  • tools/tests/test_install_copilot.py
  • tools/tests/test_install_opencode.py
  • tools/tests/test_real_world.py
  • tools/tests/test_round_trip.py
  • tools/tests/test_validate_generated.py
  • tools/validate_generated.py
  • tools/yt-design-extractor/yt-design-extractor.py
✅ Files skipped from review due to trivial changes (18)
  • tools/tests/test_install_opencode.py
  • tools/adapters/cursor.py
  • tools/check_agent_name_collisions.py
  • tools/tests/conftest.py
  • tools/adapters/copilot.py
  • tools/tests/test_install_copilot.py
  • AGENTS.md
  • tools/adapters/gemini.py
  • docs/authoring.md
  • tools/tests/test_cli_smoke.py
  • tools/adapters/codex.py
  • tools/adapters/opencode.py
  • tools/yt-design-extractor/yt-design-extractor.py
  • tools/install_opencode.py
  • tools/tests/test_doc_gardener.py
  • tools/tests/test_real_world.py
  • .gitignore
  • README.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use uv for Python package management (not pip), ruff for linting/formatting (not black), and ty for type checking (not mypy)

Files:

  • tools/tests/test_install_antigravity.py
  • tools/adapters/base.py
  • tools/tests/test_round_trip.py
  • tools/generate.py
  • tools/install_antigravity.py
  • tools/validate_generated.py
  • tools/adapters/antigravity.py
  • tools/doc_gardener.py
  • tools/tests/test_validate_generated.py
  • tools/tests/test_adapters.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T21:27:56.295Z
Learning: Plugin names must use lowercase, hyphen-separated format; never use double underscores `__` (reserved for adapter namespace separator)
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T21:27:56.295Z
Learning: Never commit secrets; never run destructive git operations (force-push, reset --hard, branch -D) without explicit ask
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T21:27:56.295Z
Learning: Plugin source-of-truth lives only under plugins/; generated artifacts are gitignored and must never be hand-edited
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T21:27:56.295Z
Learning: Before pushing, run quality gates: make validate STRICT=1, make garden, make test, and make smoke-test
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-26T21:27:56.295Z
Learning: Read and follow portable-content style guide in docs/authoring.md before adding new plugins
🪛 GitHub Actions: Code Quality / 2_Python (ruff + ty).txt
tools/adapters/antigravity.py

[error] 3-18: ruff check failed (I001). Import block is un-sorted or un-formatted. Rule: I001. Tool: Ruff. Suggested: organize imports; 1 fixable with --fix.

🪛 GitHub Actions: Code Quality / Python (ruff + ty)
tools/adapters/antigravity.py

[error] 3-18: Ruff check failed: import block is un-sorted or un-formatted. File path reported: /home/runner/work/agents/agents/tools/adapters/antigravity.py:3:1. Help: Organize imports. (Found 1 error; 1 fixable with --fix.)

🔇 Additional comments (7)
docs/harnesses.md (1)

26-26: LGTM!

Also applies to: 53-53

Makefile (1)

25-25: LGTM!

tools/tests/test_install_antigravity.py (1)

72-75: LGTM!

tools/adapters/base.py (1)

102-104: LGTM!

Also applies to: 128-132, 359-361, 372-374, 382-384, 452-454, 464-466

tools/tests/test_round_trip.py (1)

83-85: LGTM!

Also applies to: 151-153, 181-183, 187-192, 201-203, 236-238, 273-278, 289-291, 295-297, 329-333, 345-347, 360-362, 385-392, 403-405

tools/generate.py (1)

37-45: LGTM!

Also applies to: 76-78

tools/validate_generated.py (1)

42-46: LGTM!

Also applies to: 125-127, 639-644, 661-666, 705-875, 880-882, 886-888, 914-916

Comment on lines +155 to +160
if _is_relative_to(target, generated_root):
print(f" linked: {subdir}/{dst.name} -> {target}")
report.linked += 1
else:
print(f" foreign: {subdir}/{dst.name} -> {target}")
return report

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Increment foreign count in list_installed.

Foreign symlinks are printed on Line 159, but report.skipped is never incremented, so _print_report() shows an incorrect foreign= total.

Suggested fix
             if _is_relative_to(target, generated_root):
                 print(f"  linked:  {subdir}/{dst.name} -> {target}")
                 report.linked += 1
             else:
                 print(f"  foreign: {subdir}/{dst.name} -> {target}")
+                report.skipped += 1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/install_antigravity.py` around lines 155 - 160, In list_installed
(tools/install_antigravity.py) the else branch that prints foreign symlinks (the
f"  foreign: {subdir}/{dst.name} -> {target}" line) never updates the report
counters; modify that branch to increment the appropriate counter
(report.skipped += 1) so _print_report() reflects the foreign total correctly,
keeping the print statement and report variable as-is.

@mhenke

mhenke commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

Need to clean up some extra files that were added in my last commit

mhenke pushed a commit to mhenke/agents that referenced this pull request May 27, 2026
@mhenke mhenke force-pushed the feature/antigravity-agents-one branch from 1562530 to f1c3abf Compare May 27, 2026 12:56

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tools/validate_generated.py (1)

710-721: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add frontmatter validation before accessing fm.get("name").

Unlike the workflow validation below (lines 841-849) and other validators in this file (e.g., Codex at line 167, OpenCode at line 481), the skills validation doesn't check for missing/invalid frontmatter before accessing fm.get("name"). This produces a misleading error message like "frontmatter name None != directory 'demo-skill'" instead of the clearer "missing or invalid frontmatter".

Suggested fix
     if skills_dir.is_dir():
         for skill_md in skills_dir.glob("*/SKILL.md"):
             content = skill_md.read_text(encoding="utf-8")
             fm, _ = parse_frontmatter(content)
+            if not fm:
+                report.add(
+                    severity="error",
+                    harness="antigravity",
+                    path=skill_md,
+                    message="missing or invalid frontmatter",
+                    remediation="SKILL.md must start with `---\\nname: ...\\n---`.",
+                )
+                continue
             if fm.get("name") != skill_md.parent.name:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/validate_generated.py` around lines 710 - 721, The skills validator
reads frontmatter via parse_frontmatter(skill_md.read_text()) then
unconditionally compares fm.get("name") to the directory name, which yields
confusing messages when frontmatter is missing or invalid. Before accessing
fm.get("name") in the loop over skills_dir.glob("*/SKILL.md"), validate that fm
is a dict and that "name" exists/non-empty; if not, call report.add (same
pattern/severity/harness/path/remediation used elsewhere) with a clear message
like "missing or invalid frontmatter" and skip the name comparison for that
file. Ensure you reference skill_md and use the existing report.add signature so
behavior is consistent with other validators.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tools/validate_generated.py`:
- Around line 763-771: The current validation treats missing `hidden` as error
because isinstance(None, bool) is False; change the check to allow the field to
be optional by replacing the condition with a nil-aware check such as: only call
report.add when `hidden is not None and not isinstance(hidden, bool)` so that
absent `hidden` passes, leaving the required fields tuple unchanged; locate the
validation block that uses `hidden`, `agent_json_path`, and `report.add` in
validate_generated.py and update the conditional accordingly.

---

Outside diff comments:
In `@tools/validate_generated.py`:
- Around line 710-721: The skills validator reads frontmatter via
parse_frontmatter(skill_md.read_text()) then unconditionally compares
fm.get("name") to the directory name, which yields confusing messages when
frontmatter is missing or invalid. Before accessing fm.get("name") in the loop
over skills_dir.glob("*/SKILL.md"), validate that fm is a dict and that "name"
exists/non-empty; if not, call report.add (same
pattern/severity/harness/path/remediation used elsewhere) with a clear message
like "missing or invalid frontmatter" and skip the name comparison for that
file. Ensure you reference skill_md and use the existing report.add signature so
behavior is consistent with other validators.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 976a5613-c2b9-4dd7-9735-faeed79e1a4c

📥 Commits

Reviewing files that changed from the base of the PR and between 1562530 and f1c3abf.

📒 Files selected for processing (13)
  • .gitignore
  • AGENTS.md
  • Makefile
  • README.md
  • docs/authoring.md
  • docs/harnesses.md
  • tools/adapters/antigravity.py
  • tools/doc_gardener.py
  • tools/generate.py
  • tools/install_antigravity.py
  • tools/tests/test_adapters.py
  • tools/validate_generated.py
  • tools/yt-design-extractor/yt-design-extractor.py
✅ Files skipped from review due to trivial changes (5)
  • AGENTS.md
  • .gitignore
  • docs/harnesses.md
  • README.md
  • tools/yt-design-extractor/yt-design-extractor.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • docs/authoring.md
  • tools/generate.py
  • Makefile
  • tools/adapters/antigravity.py
  • tools/tests/test_adapters.py
  • tools/doc_gardener.py
  • tools/install_antigravity.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use ruff for linting and formatting (not black or other formatters)

Use ty for type checking (not mypy)

Files:

  • tools/validate_generated.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T12:57:22.027Z
Learning: Never commit secrets to the repository
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T12:57:22.027Z
Learning: Never run destructive git operations (force-push, `reset --hard`, `branch -D`) without explicit ask
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T12:57:22.027Z
Learning: Run `make validate STRICT=1`, `make garden`, `make test`, and `make smoke-test` before pushing
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T12:57:22.027Z
Learning: Generated artifacts under harness-specific directories (`.codex/`, `.cursor/`, `.opencode/`, etc.) are gitignored and auto-generated—never hand-edit them
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T12:57:22.027Z
Learning: Document authoring conventions and plugin style guidelines in `docs/authoring.md` before adding new plugins
🔇 Additional comments (3)
tools/validate_generated.py (3)

42-46: LGTM!

Also applies to: 125-127, 639-666, 880-888, 914-916


723-834: LGTM!


836-876: LGTM!

Comment on lines +763 to +771
hidden = data.get("hidden")
if not isinstance(hidden, bool):
report.add(
severity="error",
harness="antigravity",
path=agent_json_path,
message="`hidden` must be a boolean",
remediation="Set `hidden` to false (or true) in agent.json.",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

hidden validation inconsistent with required fields list.

The hidden field is not in the required fields list (lines 737-743), but this validation reports an error if hidden is missing (since isinstance(None, bool) is False). Either add "hidden" to the required fields tuple, or make this check optional-aware.

Option A: Add to required fields
             for key in (
                 "name",
                 "displayName",
                 "description",
                 "model",
                 "customAgentSpec",
+                "hidden",
             ):
Option B: Allow optional hidden
             hidden = data.get("hidden")
-            if not isinstance(hidden, bool):
+            if hidden is not None and not isinstance(hidden, bool):
                 report.add(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
hidden = data.get("hidden")
if not isinstance(hidden, bool):
report.add(
severity="error",
harness="antigravity",
path=agent_json_path,
message="`hidden` must be a boolean",
remediation="Set `hidden` to false (or true) in agent.json.",
)
hidden = data.get("hidden")
if hidden is not None and not isinstance(hidden, bool):
report.add(
severity="error",
harness="antigravity",
path=agent_json_path,
message="`hidden` must be a boolean",
remediation="Set `hidden` to false (or true) in agent.json.",
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/validate_generated.py` around lines 763 - 771, The current validation
treats missing `hidden` as error because isinstance(None, bool) is False; change
the check to allow the field to be optional by replacing the condition with a
nil-aware check such as: only call report.add when `hidden is not None and not
isinstance(hidden, bool)` so that absent `hidden` passes, leaving the required
fields tuple unchanged; locate the validation block that uses `hidden`,
`agent_json_path`, and `report.add` in validate_generated.py and update the
conditional accordingly.

@mhenke mhenke force-pushed the feature/antigravity-agents-one branch from f1c3abf to d900f7d Compare May 27, 2026 15:42
- Add Antigravity CLI adapter, installer, and tests
- Add Antigravity CLI references to documentation
- Gitignore .agents/ (OpenCode) and .agent/ (Cursor) artifacts
@mhenke mhenke force-pushed the feature/antigravity-agents-one branch from d900f7d to 89beaec Compare May 27, 2026 15:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
docs/authoring.md (1)

108-110: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the model-alias table separator width.

Line 109 has one extra separator cell, so the table column count is inconsistent.

Suggested fix
-|---|---|---|---|---|---|---|---|
+|---|---|---|---|---|---|---|
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/authoring.md` around lines 108 - 110, The table's separator row has one
extra cell causing a column mismatch: replace the current separator row string
"|---|---|---|---|---|---|---|---|" with exactly seven separators to match the
header (e.g. "|---|---|---|---|---|---|---|") so the header row ("| Source field
| Codex | Cursor | OpenCode | Gemini | Copilot | Antigravity CLI |") and the
data row ("| `model: opus` | `gpt-5` | `inherit` | `anthropic/claude-opus-4-7` |
`gemini-2.5-pro` | `gpt-5` | `gemini-2.5-pro` |") all have the same number of
columns.
🧹 Nitpick comments (2)
tools/tests/test_validate_generated.py (1)

488-493: ⚡ Quick win

Make the name-mismatch fixture otherwise valid.

This test should fail only on the directory/name mismatch. Line 492 currently omits additional fields, which can couple it to unrelated validator behavior.

Suggested fix
         (tmp_path / ".antigravity" / "agents" / "demo-agent" / "agent.json").write_text(
-            '{"name": "wrong-agent", "displayName": "Demo", "description": "Desc", "customAgentSpec": {}}'
+            json.dumps(
+                {
+                    "name": "wrong-agent",
+                    "displayName": "Demo",
+                    "description": "Desc",
+                    "hidden": False,
+                    "model": "gemini-2.5-pro",
+                    "customAgentSpec": {},
+                }
+            )
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/tests/test_validate_generated.py` around lines 488 - 493, The
agent.json fixture in test_agent_name_mismatch_errors must be a valid agent
manifest except for the name mismatch so the test isolates that error; update
the JSON written to (.antigravity/agents/demo-agent/agent.json) in
test_agent_name_mismatch_errors to include the full minimal required manifest
fields (keep "name": "wrong-agent" to trigger the mismatch) such as
"displayName", "description", "customAgentSpec" and any required metadata like
"schemaVersion" and "version" (or other keys your validator expects) so the only
failing condition is the directory/name mismatch.
tools/tests/test_round_trip.py (1)

345-351: ⚡ Quick win

Add an explicit Antigravity workflow count assertion.

These tests validate agents and skills, but they don’t currently fail when .antigravity/workflows emission regresses.

Suggested addition
 class TestAntigravityRoundTrip:
@@
     def test_antigravity_skill_count_matches_source(self):
         n = len(list((WORKTREE / ".antigravity" / "skills").glob("*/SKILL.md")))
         expected = _source_skill_count() + _source_command_count()
         assert n == expected, (
             f"skill count mismatch: source_skills={_source_skill_count()} "
             f"source_commands={_source_command_count()} expected={expected} antigravity={n}"
         )
+
+    def test_antigravity_workflow_count_matches_source_commands(self):
+        n = len(list((WORKTREE / ".antigravity" / "workflows").glob("*.md")))
+        assert n == _source_command_count(), (
+            f"workflow count mismatch: source_commands={_source_command_count()} antigravity={n}"
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/tests/test_round_trip.py` around lines 345 - 351, Add an explicit
assertion that the emitted .antigravity/workflows count matches the source
workflow count: in or next to test_antigravity_skill_count_matches_source
compute n_workflows = len(list((WORKTREE / ".antigravity" /
"workflows").glob("*/WORKFLOW.md"))) (or similar pattern used for skills), get
expected_workflows = _source_workflow_count() (or add that helper if missing),
and assert n_workflows == expected_workflows with a clear message (e.g., include
values for _source_workflow_count() and n_workflows) so regression of emitted
workflows will fail the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/authoring.md`:
- Line 143: Update the docs table entry that currently lists Antigravity
emitting `.antigravity/commands/` so it shows the correct output path
`.antigravity/workflows/`; locate the table row containing "Slash commands |
Codex converts to skills. Gemini transpiles to TOML. Copilot emits
`.copilot/commands/` prompt files. Antigravity emits `.antigravity/commands/`
SKILL.md files." and change the Antigravity path fragment to
`.antigravity/workflows/`.

---

Duplicate comments:
In `@docs/authoring.md`:
- Around line 108-110: The table's separator row has one extra cell causing a
column mismatch: replace the current separator row string
"|---|---|---|---|---|---|---|---|" with exactly seven separators to match the
header (e.g. "|---|---|---|---|---|---|---|") so the header row ("| Source field
| Codex | Cursor | OpenCode | Gemini | Copilot | Antigravity CLI |") and the
data row ("| `model: opus` | `gpt-5` | `inherit` | `anthropic/claude-opus-4-7` |
`gemini-2.5-pro` | `gpt-5` | `gemini-2.5-pro` |") all have the same number of
columns.

---

Nitpick comments:
In `@tools/tests/test_round_trip.py`:
- Around line 345-351: Add an explicit assertion that the emitted
.antigravity/workflows count matches the source workflow count: in or next to
test_antigravity_skill_count_matches_source compute n_workflows =
len(list((WORKTREE / ".antigravity" / "workflows").glob("*/WORKFLOW.md"))) (or
similar pattern used for skills), get expected_workflows =
_source_workflow_count() (or add that helper if missing), and assert n_workflows
== expected_workflows with a clear message (e.g., include values for
_source_workflow_count() and n_workflows) so regression of emitted workflows
will fail the test.

In `@tools/tests/test_validate_generated.py`:
- Around line 488-493: The agent.json fixture in test_agent_name_mismatch_errors
must be a valid agent manifest except for the name mismatch so the test isolates
that error; update the JSON written to
(.antigravity/agents/demo-agent/agent.json) in test_agent_name_mismatch_errors
to include the full minimal required manifest fields (keep "name": "wrong-agent"
to trigger the mismatch) such as "displayName", "description", "customAgentSpec"
and any required metadata like "schemaVersion" and "version" (or other keys your
validator expects) so the only failing condition is the directory/name mismatch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cdd65842-28a3-48f3-b20f-50918fd25ab8

📥 Commits

Reviewing files that changed from the base of the PR and between f1c3abf and 89beaec.

📒 Files selected for processing (21)
  • .gitignore
  • AGENTS.md
  • ARCHITECTURE.md
  • CONTRIBUTING.md
  • Makefile
  • README.md
  • docs/authoring.md
  • docs/harnesses.md
  • docs/round-trip-results.md
  • tools/adapters/antigravity.py
  • tools/adapters/base.py
  • tools/adapters/capabilities.py
  • tools/doc_gardener.py
  • tools/generate.py
  • tools/install_antigravity.py
  • tools/tests/test_adapters.py
  • tools/tests/test_install_antigravity.py
  • tools/tests/test_round_trip.py
  • tools/tests/test_validate_generated.py
  • tools/validate_generated.py
  • tools/yt-design-extractor/yt-design-extractor.py
✅ Files skipped from review due to trivial changes (6)
  • CONTRIBUTING.md
  • AGENTS.md
  • docs/harnesses.md
  • ARCHITECTURE.md
  • docs/round-trip-results.md
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (9)
  • README.md
  • tools/yt-design-extractor/yt-design-extractor.py
  • tools/doc_gardener.py
  • tools/tests/test_install_antigravity.py
  • tools/adapters/capabilities.py
  • tools/install_antigravity.py
  • tools/validate_generated.py
  • tools/adapters/antigravity.py
  • tools/tests/test_adapters.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use ruff for linting and formatting instead of black/pylint

Use ty for type checking instead of mypy

Files:

  • tools/adapters/base.py
  • tools/generate.py
  • tools/tests/test_round_trip.py
  • tools/tests/test_validate_generated.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T15:47:48.243Z
Learning: Never commit secrets to the repository
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T15:47:48.243Z
Learning: Never run destructive git operations (force-push, `reset --hard`, `branch -D`) without explicit request
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T15:47:48.243Z
Learning: Generated artifacts in per-harness directories (`.codex/`, `.cursor/`, `.opencode/`, `.gemini/`, `.antigravity/`) are auto-generated and must never be hand-edited
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T15:47:48.243Z
Learning: Source-of-truth for all plugins, skills, and agents lives only under `plugins/` directory structure
Learnt from: CR
Repo: wshobson/agents

Timestamp: 2026-05-27T15:47:48.243Z
Learning: This repository should maintain a short, map-style README/AGENTS.md file (max ~150 lines) per OpenAI harness-engineering practices, with detail delegated to `docs/` and skills
🪛 checkmake (0.3.2)
Makefile

[warning] 21-21: Target body for "help" exceeds allowed length of 5 lines (11).

(maxbodylength)


[warning] 20-20: Required target "all" is missing from the Makefile.

(minphony)

🔇 Additional comments (3)
tools/adapters/base.py (1)

289-296: LGTM!

tools/generate.py (1)

37-45: LGTM!

Also applies to: 68-71, 76-78, 178-187, 220-220

Makefile (1)

19-19: LGTM!

Also applies to: 25-25, 34-35, 167-167, 237-243

Comment thread docs/authoring.md Outdated
web-flow added 3 commits May 27, 2026 11:05
- Add TestAntigravitySmoke in test_cli_smoke.py using agy plugin import
- Isolate HOME to temp dir to avoid polluting real config
- Update docs/round-trip-results.md: real CLI version, updated recipe
- Add agy install step to CI workflow via antigravity.google/cli/install.sh
…igravity adapter

The agy CLI reads from the Gemini-format (root skills/agents/commands + gemini-extension.json), not from .antigravity/, .agent/, or .agents/. These extra-write paths were duplicates/subsets meant for IDE/2.0 discovery only. Removed:

- tools/generate.py: simplify _HARNESS_TARGETS to 3 paths
- tools/adapters/antigravity.py: drop extra-write loops
- tools/doc_gardener.py: drop stale detection for extra paths
- tools/adapters/capabilities.py: update notes
- ARCHITECTURE.md: fix output path (.antigravity/workflows/, not /commands/)
- ARCHITECTURE.md: update CI job description (include Antigravity)
- AGENTS.md: add missing GitHub Copilot to harness list; update CI description
- CONTRIBUTING.md: include Antigravity in smoke-test comment
- Makefile: include agy in smoke-test CLI list; update CI description
- docs/authoring.md: fix Antigravity slash command output path
@wshobson

Copy link
Copy Markdown
Owner

Thanks — the adapter integration is solid and agy demonstrably runs in CI. To get this moving again:

  1. Rebase onto main — 5 files conflict, and main's feat: native plugin-install for Codex/Cursor/Gemini + CLAUDE.md→AGENTS.md symlink #563 changed the artifact-commit policy the docs hunks describe.
  2. Drop the 88-col reformatting of shared tools/ files (main is line-length 100 now) — that's most of the diff churn and will fail ruff format --check post-rebase.
  3. ruff check --fix clears the import-sort error at tools/adapters/antigravity.py:3.
  4. The smoke test needs cwd=WORKTREE at test_cli_smoke.py:193 and counts derived from source rather than hard-coded.
  5. Narrow the tool-name rewrite regex to exact backticked tool names (it currently rewrites prose like "Read the config" → "view_file the config").

Happy to re-review after a rebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add Google Antigravity CLI harness support

4 participants