Skip to content

Commit 6e2e4c1

Browse files
duyetduyetbot
andcommitted
feat(agent-loop): make agent-loop available on Antigravity
- Add Antigravity manifest (.antigravity-plugin/plugin.json) with commands and skills mappings. - Add helper script scripts/install-antigravity.sh to install/symlink plugins to Antigravity config directory. - Update scripts/validate-plugins.sh to validate commands and agents. - Bump agent-loop version to 0.3.0. Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com>
1 parent e236d34 commit 6e2e4c1

9 files changed

Lines changed: 142 additions & 22 deletions

File tree

CLAUDE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,21 @@
99

1010
Alternative: `npx skills add duyet/codex-claude-plugins` ([skills.sh](https://skills.sh))
1111

12+
### Antigravity Installation
13+
14+
For Antigravity CLI, install/symlink a plugin locally for development:
15+
16+
```bash
17+
./scripts/install-antigravity.sh <plugin-name> # Or 'all' to install all
18+
```
19+
1220
## Plugin Metadata
1321

1422
Codex plugin metadata is maintained beside Claude metadata in each plugin:
1523

1624
- Claude manifest: `.claude-plugin/plugin.json`
1725
- Codex manifest: `.codex-plugin/plugin.json`
26+
- Antigravity manifest: `.antigravity-plugin/plugin.json`
1827
- Claude marketplace: `marketplace.json` and `.claude-plugin/marketplace.json`
1928
- Codex marketplace: `.agents/plugins/marketplace.json`
2029

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "agent-loop",
3+
"version": "0.3.0",
4+
"description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.",
5+
"author": { "name": "duyetbot" },
6+
"license": "MIT",
7+
"skills": "./skills/",
8+
"commands": "./commands/"
9+
}

agent-loop/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "agent-loop",
3-
"version": "0.2.0",
3+
"version": "0.3.0",
44
"description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.",
55
"author": { "name": "duyetbot" },
66
"license": "MIT"

agent-loop/.codex-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "agent-loop",
3-
"version": "0.2.0",
3+
"version": "0.3.0",
44
"description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.",
55
"author": { "name": "duyetbot" },
66
"license": "MIT",

agent-loop/CLAUDE.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ Continuous overnight/day repository maintenance with autonomous agent loops.
44

55
## Version
66

7-
0.2.0
7+
0.3.0
88

99
## Plugin Structure
1010

1111
```text
1212
agent-loop/
13+
├── .antigravity-plugin/
14+
│ └── plugin.json # Antigravity manifest (version 0.3.0)
1315
├── .claude-plugin/
14-
│ └── plugin.json # Manifest (version 0.2.0)
16+
│ └── plugin.json # Manifest (version 0.3.0)
1517
├── commands/ # Slash commands
1618
├── skills/ # Reusable knowledge
1719
│ ├── agent-loop-orchestrator/

agent-loop/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Wake every 5m ──► Triage repos ──► Dispatch threads ──► Track
88

99
## Version
1010

11-
0.2.0
11+
0.3.0
1212

1313
## Overview
1414

@@ -85,10 +85,12 @@ Sources adapted for the agent-loop plugin:
8585

8686
```text
8787
agent-loop/
88+
├── .antigravity-plugin/
89+
│ └── plugin.json # Antigravity manifest (version 0.3.0)
8890
├── .claude-plugin/
89-
│ └── plugin.json # Manifest (version 0.2.0)
91+
│ └── plugin.json # Manifest (version 0.3.0)
9092
├── .codex-plugin/
91-
│ └── plugin.json # Codex manifest
93+
│ └── plugin.json # Codex manifest (version 0.3.0)
9294
├── commands/ # Slash commands
9395
│ ├── start.md
9496
│ ├── stop.md

marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@
175175
"name": "agent-loop",
176176
"id": "agent-loop@duyet-claude-plugins",
177177
"description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.",
178-
"version": "0.2.0",
178+
"version": "0.3.0",
179179
"type": "skill",
180180
"category": "automation"
181181
},

scripts/install-antigravity.sh

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env bash
2+
# Install plugins to Antigravity CLI.
3+
# Usage: ./scripts/install-antigravity.sh [plugin-name | all]
4+
5+
set -euo pipefail
6+
7+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
8+
TARGET_DIR="$HOME/.gemini/config/plugins"
9+
10+
# Find plugins with Antigravity manifests
11+
find_antigravity_plugins() {
12+
find "$REPO_ROOT" -maxdepth 3 -path "*/.antigravity-plugin/plugin.json" -not -path "*/node_modules/*" | while read -r manifest; do
13+
basename "$(dirname "$(dirname "$manifest")")"
14+
done
15+
}
16+
17+
PLUGINS=($(find_antigravity_plugins))
18+
19+
if [ ${#PLUGINS[@]} -eq 0 ]; then
20+
echo "No plugins with .antigravity-plugin/plugin.json found in the repository."
21+
exit 0
22+
fi
23+
24+
# Check argument
25+
if [ $# -eq 0 ]; then
26+
echo "Available Antigravity plugins:"
27+
for p in "${PLUGINS[@]}"; do
28+
echo " - $p"
29+
done
30+
echo ""
31+
echo "Run: $0 <plugin-name> (or '$0 all' to install all)"
32+
exit 0
33+
fi
34+
35+
install_plugin() {
36+
local name="$1"
37+
local dir="$REPO_ROOT/$name"
38+
local manifest="$dir/.antigravity-plugin/plugin.json"
39+
40+
if [ ! -f "$manifest" ]; then
41+
echo "❌ Plugin '$name' does not have an Antigravity manifest (.antigravity-plugin/plugin.json)."
42+
return 1
43+
fi
44+
45+
local dest="$TARGET_DIR/$name"
46+
echo "Installing '$name' to '$dest'..."
47+
mkdir -p "$dest"
48+
49+
# Symlink manifest
50+
ln -sfn "$manifest" "$dest/plugin.json"
51+
echo " - Linked plugin.json"
52+
53+
# Read manifest using Python to parse JSON and output relative paths
54+
local fields
55+
fields=$(python3 - "$manifest" <<'PYEOF'
56+
import json, sys
57+
data = json.load(open(sys.argv[1]))
58+
for key in ["skills", "commands", "hooks", "mcpServers", "apps", "agents"]:
59+
if key in data and isinstance(data[key], str) and data[key].startswith("./"):
60+
print(f"{key}:{data[key]}")
61+
PYEOF
62+
)
63+
64+
for f in $fields; do
65+
local key="${f%%:*}"
66+
local rel_path="${f#*:}"
67+
# Normalize relative path
68+
local src_dir
69+
src_dir=$(cd "$dir" && cd "$rel_path" && pwd)
70+
ln -sfn "$src_dir" "$dest/$key"
71+
echo " - Linked $key -> $rel_path"
72+
done
73+
74+
echo "✅ Successfully installed '$name' to Antigravity!"
75+
echo "Restart your Antigravity session/CLI to load the plugin."
76+
}
77+
78+
if [ "$1" = "all" ]; then
79+
for p in "${PLUGINS[@]}"; do
80+
install_plugin "$p"
81+
done
82+
else
83+
install_plugin "$1"
84+
fi

scripts/validate-plugins.sh

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ if isinstance(skills, list):
6868
elif not os.path.isfile(os.path.join(plugin_dir, path_value)):
6969
errors.append(f"skills[{i}]: path '{path_value}' does not exist")
7070
71-
if mode == "codex":
72-
for field in ("skills", "hooks", "mcpServers", "apps"):
71+
if mode in ("codex", "antigravity"):
72+
for field in ("skills", "hooks", "mcpServers", "apps", "commands", "agents"):
7373
value = data.get(field)
7474
if value is None:
7575
continue
@@ -80,6 +80,7 @@ if mode == "codex":
8080
if not os.path.exists(target):
8181
errors.append(f"'{field}' path does not exist: {value}")
8282
83+
if mode == "codex":
8384
interface = data.get("interface")
8485
if not isinstance(interface, dict):
8586
errors.append("'interface' must be an object")
@@ -137,20 +138,27 @@ for plugin in plugin_dirs:
137138
if not os.path.isfile(claude_path):
138139
errors.append(f"{plugin}: missing .claude-plugin/plugin.json")
139140
continue
140-
if not os.path.isfile(codex_path):
141-
# No Codex manifest means the plugin doesn't support Codex — skip parity check
142-
continue
143-
144141
with open(claude_path) as f:
145142
claude = json.load(f)
146-
with open(codex_path) as f:
147-
codex = json.load(f)
148143
149-
for field in ("name", "version", "description"):
150-
if claude.get(field) != codex.get(field):
151-
errors.append(f"{plugin}: {field} differs between Claude and Codex manifests")
152-
if claude.get("author", {}).get("name") != codex.get("author", {}).get("name"):
153-
errors.append(f"{plugin}: author.name differs between Claude and Codex manifests")
144+
if os.path.isfile(codex_path):
145+
with open(codex_path) as f:
146+
codex = json.load(f)
147+
for field in ("name", "version", "description"):
148+
if claude.get(field) != codex.get(field):
149+
errors.append(f"{plugin}: {field} differs between Claude and Codex manifests")
150+
if claude.get("author", {}).get("name") != codex.get("author", {}).get("name"):
151+
errors.append(f"{plugin}: author.name differs between Claude and Codex manifests")
152+
153+
antigravity_path = os.path.join(repo_root, plugin, ".antigravity-plugin", "plugin.json")
154+
if os.path.isfile(antigravity_path):
155+
with open(antigravity_path) as f:
156+
antigravity = json.load(f)
157+
for field in ("name", "version", "description"):
158+
if claude.get(field) != antigravity.get(field):
159+
errors.append(f"{plugin}: {field} differs between Claude and Antigravity manifests")
160+
if claude.get("author", {}).get("name") != antigravity.get("author", {}).get("name"):
161+
errors.append(f"{plugin}: author.name differs between Claude and Antigravity manifests")
154162
155163
if errors:
156164
for error in errors:
@@ -258,7 +266,13 @@ while IFS= read -r -d '' manifest; do
258266
check "Codex manifest: $plugin_name" validate_manifest "$manifest" codex
259267
done < <(find "$REPO_ROOT" -path "*/.codex-plugin/plugin.json" -not -path "*/node_modules/*" -print0 | sort -z)
260268

261-
check "Claude/Codex manifest parity" validate_cross_manifest
269+
while IFS= read -r -d '' manifest; do
270+
plugin_dir="$(dirname "$(dirname "$manifest")")"
271+
plugin_name="$(basename "$plugin_dir")"
272+
check "Antigravity manifest: $plugin_name" validate_manifest "$manifest" antigravity
273+
done < <(find "$REPO_ROOT" -path "*/.antigravity-plugin/plugin.json" -not -path "*/node_modules/*" -print0 | sort -z)
274+
275+
check "Claude/Codex/Antigravity manifest parity" validate_cross_manifest
262276
check "Marketplace files" validate_marketplaces
263277

264278
echo ""

0 commit comments

Comments
 (0)