Skip to content

Commit ce23b59

Browse files
committed
fix: resolve 11 antigravity implementation gaps found in audit
- generate.py: add workflow/extra-dir paths to _HARNESS_TARGETS and prune_orphans for complete --clean and orphan pruning - antigravity.py: symmetric extra-writes (skills go to both .agent/skills/ and .agents/skills/, matching workflow pattern) - install_antigravity.py: add workflows to ARTIFACT_GLOBS - validate_generated.py: add agent description non-empty check, add workflow frontmatter/body validation - doc_gardener.py: add stale detection for .antigravity/workflows/ and all extra-write paths (.agent/workflows/, .agents/workflows/, .agents/skills/) - capabilities.py: update notes to mention workflow emission - docs/harnesses.md: fix agent separator (- -> __), add workflow output path, add install-antigravity/uninstall-antigravity to sections - docs/round-trip-results.md: fix incorrect commands/ path, fix install description
1 parent 4c33f17 commit ce23b59

8 files changed

Lines changed: 105 additions & 18 deletions

File tree

docs/harnesses.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ as Claude Code markdown. Per-harness artifacts are generated by adapters under `
1515
| **Cursor** (2.5+) | supported | `.cursor-plugin/`, `.cursor/rules/` (curated) |
1616
| **OpenCode** (`sst/opencode`) | supported | `.opencode/agents/`, `.opencode/commands/`, `.opencode/skills/`, `opencode.json` |
1717
| **Gemini CLI** | supported | `skills/`, `agents/`, `commands/` (at extension root) |
18-
| **Antigravity CLI** | supported | `.antigravity/agents/`, `.antigravity/skills/` |
18+
| **Antigravity CLI** | supported | `.antigravity/agents/`, `.antigravity/skills/`, `.antigravity/workflows/` |
1919

2020
## Capability matrix
2121

@@ -49,7 +49,7 @@ rules to write portable content.
4949
| `model: opus` (agent) | mapped to `gpt-5` | rewritten to `inherit` | rewritten to `anthropic/claude-opus-4-7` | mapped to `gemini-2.5-pro` | mapped to `gemini-2.5-pro` |
5050
| `TodoWrite` in body | no equivalent — leave as-is | no equivalent — leave as-is | works as-is | no equivalent | no equivalent |
5151
| Skill body > 8 KB | split into `references/details.md` | passed through | passed through | passed through | passed through |
52-
| Agent named `worker` | namespaced to `<plugin>__worker` | passed through | passed through | passed through | namespaced to `<plugin>-<agent>` |
52+
| Agent named `worker` | namespaced to `<plugin>__worker` | passed through | passed through | passed through | namespaced to `<plugin>__<agent>` |
5353
| Slash command (`commands/<x>.md`) | converted to skill | passed through | rewritten to `.opencode/commands/` | TOML at `commands/<plugin>/<x>.toml` | converted to skill |
5454

5555
## Output paths (all gitignored)
@@ -62,7 +62,7 @@ GEMINI.md, AGENTS.md* # context files (committed/generated)
6262
.cursor-plugin/, .cursor/rules/ # generated by Cursor adapter
6363
.opencode/agents/, .opencode/commands/, .opencode/skills/, opencode.json # generated by OpenCode adapter
6464
skills/, agents/, commands/ # generated by Gemini adapter (at extension root)
65-
.antigravity/agents/, .antigravity/skills/ # generated by Antigravity adapter
65+
.antigravity/agents/, .antigravity/skills/, .antigravity/workflows/ # generated by Antigravity adapter
6666
```
6767

6868
## Regenerating
@@ -76,9 +76,11 @@ make generate HARNESS=antigravity
7676
# Or all at once:
7777
make generate-all
7878

79-
# Optional global OpenCode install:
79+
# Optional global install:
8080
make install-opencode
81+
make install-antigravity
8182
make uninstall-opencode
83+
make uninstall-antigravity
8284
```
8385

8486
## External Pensyve integrations
@@ -97,17 +99,21 @@ For generated harnesses, use Pensyve's upstream harness-native integration:
9799

98100
## Global install
99101

100-
OpenCode and Copilot support installing generated artifacts globally for user-level discovery:
102+
OpenCode, Copilot, and Antigravity CLI support installing generated artifacts globally for user-level discovery:
101103

102104
```bash
103-
make install-opencode # symlink .opencode/ → ~/.config/opencode/
105+
make install-opencode # symlink .opencode/ → ~/.config/opencode/
104106
make uninstall-opencode
105107

106-
make install-copilot # symlink .copilot/ → ~/.copilot/
108+
make install-copilot # symlink .copilot/ → ~/.copilot/
107109
make uninstall-copilot
108110

111+
make install-antigravity # symlink .antigravity/ → ~/.gemini/antigravity-cli/
112+
make uninstall-antigravity
113+
109114
# Force-replace conflicting symlinks:
110115
make install-copilot FORCE=1
116+
make install-antigravity FORCE=1
111117
```
112118

113119
> Copilot discovers agents from `.copilot/agents/` and skills from `.copilot/skills/` at the repo level, and from `~/.copilot/agents/` and `~/.copilot/skills/` at the user level. The adapter emits to `.copilot/`; use `make install-copilot` for user-level discovery.

docs/round-trip-results.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ make generate HARNESS=antigravity
111111
make validate
112112

113113
# Verify artifact tree
114-
ls .antigravity/agents/ # 191 agent.json profiles
115-
ls .antigravity/skills/ # 155 skill dirs (each with SKILL.md)
116-
ls .antigravity/commands/ # 25 command SKILL.md files
114+
ls .antigravity/agents/ # 191 agent.json profiles
115+
ls .antigravity/skills/ # 155 skill dirs (each with SKILL.md) + command-derived skills
116+
ls .antigravity/workflows/ # 25 workflow .md files (command-as-workflow)
117117

118118
# Global install (optional)
119-
make install-antigravity # symlinks .antigravity/ -> ~/.antigravity/
119+
make install-antigravity # symlinks artifacts to ~/.gemini/antigravity-cli/
120120
```
121121

122122
Antigravity CLI currently lacks a CLI verification tool. Manual testing requires

tools/adapters/antigravity.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,11 @@ def _emit_command_as_skill(self, plugin: PluginSource, command: CommandSource, r
153153
content = _antigravity_frontmatter(fm) + "\n\n" + body
154154
result.written.append(self.write(skill_dir / "SKILL.md", content))
155155

156-
# Also write to workspace-level .agents/skills/ for IDE/2.0 discovery
157-
# (mirrors the workflow approach which writes to both .antigravity/ and .agent/.agents/)
158-
agents_skill_dir = Path(".agents") / "skills" / skill_id
159-
result.written.append(self.write(agents_skill_dir / "SKILL.md", content))
156+
# Also write to workspace-level .agent/skills/ and .agents/skills/ for IDE/2.0 discovery
157+
# (mirrors the workflow approach which writes to both .agent/ and .agents/)
158+
for skill_parent in (Path(".agent"), Path(".agents")):
159+
extra_skill_dir = skill_parent / "skills" / skill_id
160+
result.written.append(self.write(extra_skill_dir / "SKILL.md", content))
160161

161162
def _emit_command_as_workflow(self, plugin: PluginSource, command: CommandSource, result: EmitResult) -> None:
162163
"""Emit one command as an Antigravity workflow (``.md``) for IDE/2.0 slash command support."""

tools/adapters/capabilities.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class Capability:
187187
skill_body_max_bytes=_NO_CAP,
188188
tool_name_case="lowercase",
189189
bare_model_aliases=False,
190-
notes="Emits agent.json to .antigravity/agents/<name>/ and SKILL.md to .antigravity/skills/<name>/.",
190+
notes="Emits agent.json to .antigravity/agents/<name>/, SKILL.md to .antigravity/skills/<name>/, and workflow .md to .antigravity/workflows/ (plus extra-writes to .agent/ and .agents/ for IDE/2.0 discovery).",
191191
),
192192
}
193193

tools/doc_gardener.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,36 @@ def check_stale_artifacts(report: Report) -> None:
268268
pairs.append((src, skill_md))
269269
break
270270

271+
antigravity_workflows = antigravity_root / "workflows"
272+
if antigravity_workflows.is_dir():
273+
for workflow_md in antigravity_workflows.glob("*.md"):
274+
name = workflow_md.stem
275+
for plugin_name in list_plugins():
276+
if name.startswith(f"{plugin_name}-"):
277+
cmd_name = name[len(plugin_name) + 1 :]
278+
src = PLUGINS_DIR / plugin_name / "commands" / f"{cmd_name}.md"
279+
if src.is_file():
280+
pairs.append((src, workflow_md))
281+
break
282+
283+
# Stale detection for extra-write paths (.agent/workflows/, .agents/workflows/, .agents/skills/)
284+
for extra_root in (WORKTREE / ".agent", WORKTREE / ".agents"):
285+
for sub in ("workflows", "skills"):
286+
extra_dir = extra_root / sub
287+
if not extra_dir.is_dir():
288+
continue
289+
for f in extra_dir.rglob("*"):
290+
if not f.is_file():
291+
continue
292+
name = f.stem if sub == "workflows" else f.parent.name
293+
for plugin_name in list_plugins():
294+
if name.startswith(f"{plugin_name}-"):
295+
cmd_name = name[len(plugin_name) + 1 :]
296+
src = PLUGINS_DIR / plugin_name / "commands" / f"{cmd_name}.md"
297+
if src.is_file():
298+
pairs.append((src, f))
299+
break
300+
271301
for src, gen in pairs:
272302
if src.stat().st_mtime > gen.stat().st_mtime + 1: # 1s grace
273303
# Derive the plugin name correctly regardless of source layout.

tools/generate.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"cursor": [".cursor", ".cursor-plugin"],
3535
"opencode": [".opencode", "opencode.json"],
3636
"gemini": ["commands", "agents", "skills"],
37-
"antigravity": [".antigravity/agents", ".antigravity/skills"],
37+
"antigravity": [".antigravity/agents", ".antigravity/skills", ".antigravity/workflows", ".agent/workflows", ".agents/workflows", ".agents/skills"],
3838
"copilot": [".copilot/agents", ".copilot/skills", ".copilot/commands"],
3939
}
4040

@@ -166,10 +166,15 @@ def prune_orphans(harness_id: str, output_root: Path, written: set[Path]) -> lis
166166
if d.is_dir():
167167
candidates.extend(p for p in d.rglob("*") if p.is_file())
168168
elif harness_id == "antigravity":
169-
for sub in ("agents", "skills"):
169+
for sub in ("agents", "skills", "workflows"):
170170
d = output_root / ".antigravity" / sub
171171
if d.is_dir():
172172
candidates.extend(p for p in d.rglob("*") if p.is_file())
173+
for extra in (".agent", ".agents"):
174+
for sub in ("workflows", "skills"):
175+
d = output_root / extra / sub
176+
if d.is_dir():
177+
candidates.extend(p for p in d.rglob("*") if p.is_file())
173178
elif harness_id == "copilot":
174179
for sub in ("agents", "skills"):
175180
d = output_root / ".copilot" / sub

tools/install_antigravity.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
ARTIFACT_GLOBS = {
1414
"agents": "*",
1515
"skills": "*",
16+
"workflows": "*.md",
1617
}
1718

1819

@@ -54,6 +55,8 @@ def _generated_artifacts(repo_root: Path) -> list[tuple[str, Path]]:
5455
for src in sorted(source_dir.glob(pattern)):
5556
if subdir in {"agents", "skills"} and not src.is_dir():
5657
continue
58+
if subdir == "workflows" and not src.is_file():
59+
continue
5760
artifacts.append((subdir, src.resolve()))
5861
if not artifacts:
5962
raise FileNotFoundError(

tools/validate_generated.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,16 @@ def validate_antigravity(report: Report) -> None:
729729
remediation=f"Add a `{key}` field to the custom agent config.",
730730
)
731731

732+
desc = data.get("description")
733+
if desc is not None and (not isinstance(desc, str) or not desc.strip()):
734+
report.add(
735+
severity="error",
736+
harness="antigravity",
737+
path=agent_json_path,
738+
message="`description` must be a non-empty string",
739+
remediation="Set a non-empty description in agent.json.",
740+
)
741+
732742
if "name" in data and data["name"] != agent_json_path.parent.name:
733743
report.add(
734744
severity="error",
@@ -788,6 +798,38 @@ def validate_antigravity(report: Report) -> None:
788798
remediation="Antigravity uses Gemini models (e.g. 'gemini-2.5-pro').",
789799
)
790800

801+
workflows_dir = WORKTREE / ".antigravity" / "workflows"
802+
if workflows_dir.is_dir():
803+
for workflow_md in workflows_dir.glob("*.md"):
804+
content = workflow_md.read_text(encoding="utf-8")
805+
fm, body = parse_frontmatter(content)
806+
if not fm:
807+
report.add(
808+
severity="error",
809+
harness="antigravity",
810+
path=workflow_md,
811+
message="missing or invalid frontmatter",
812+
remediation="Regenerate via `make generate HARNESS=antigravity`.",
813+
)
814+
continue
815+
description = fm.get("description")
816+
if not isinstance(description, str) or not description.strip():
817+
report.add(
818+
severity="error",
819+
harness="antigravity",
820+
path=workflow_md,
821+
message="missing required `description` field in frontmatter",
822+
remediation="Antigravity workflow files need a non-empty description.",
823+
)
824+
if not body.strip():
825+
report.add(
826+
severity="warning",
827+
harness="antigravity",
828+
path=workflow_md,
829+
message="workflow body is empty",
830+
remediation="Keep the prompt body in the source command markdown.",
831+
)
832+
791833
_VALIDATORS = {
792834
"antigravity": validate_antigravity,
793835
"codex": validate_codex,

0 commit comments

Comments
 (0)