diff --git a/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/phase-5.md b/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/phase-5.md index c6448f792..50726156e 100644 --- a/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/phase-5.md +++ b/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/phase-5.md @@ -1,5 +1,5 @@ --- -status: pending +status: done --- diff --git a/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/plan.md b/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/plan.md index f634dcd76..3a67151d4 100644 --- a/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/plan.md +++ b/aidd_docs/tasks/2026_10/2026_10_02_antigravity-flat-host/plan.md @@ -1,6 +1,6 @@ --- objective: "`aidd setup --ai antigravity` and `aidd translate --to antigravity --as flat` write AIDD skills, the memory hook and agents under `.agents/`, which `agy` loads, without touching files AIDD did not write." -status: in-progress +status: implemented --- diff --git a/cli/README.md b/cli/README.md index 0c8a17445..a0d93a103 100644 --- a/cli/README.md +++ b/cli/README.md @@ -4,7 +4,7 @@ | | | | --- | --- | -| AI tools | Claude Code, Cursor, GitHub Copilot, Codex, OpenCode, Kilo Code | +| AI tools | Claude Code, Cursor, GitHub Copilot, Codex, OpenCode, Kilo Code, Antigravity CLI | | IDE | VS Code | | Requires | Node.js 22.12 or later | | Requires for marketplace plugins | `git` | @@ -169,6 +169,7 @@ The token resolves from the first hit: | `codex` | yes | yes | `.codex/` | | `opencode` | no | yes | `.opencode/` | | `kilo` | no | yes | `.kilo/` | +| `antigravity` | no | yes | `.agents/` | ## Environment variables diff --git a/cli/package.json b/cli/package.json index f70e110b4..58d2105c7 100644 --- a/cli/package.json +++ b/cli/package.json @@ -55,6 +55,7 @@ "smoke:full": "pnpm build && SMOKE_REMOTE=1 bash scripts/smoke-tools.sh", "smoke:real": "pnpm build && bash scripts/smoke-real.sh", "smoke:collision": "pnpm build && bash scripts/smoke-collision.sh", + "smoke:antigravity": "pnpm build && bash scripts/smoke-antigravity.sh", "typecheck": "tsc --noEmit", "lint": "biome check .", "format": "biome format --write .", diff --git a/cli/scripts/smoke-antigravity.sh b/cli/scripts/smoke-antigravity.sh new file mode 100755 index 000000000..1709a7463 --- /dev/null +++ b/cli/scripts/smoke-antigravity.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash +# Runtime smoke against a real, logged-in `agy`: after `aidd setup --ai antigravity`, the host +# loads and fires the project memory hook, expands an AIDD skill, and lists an AIDD agent. +# Local only, never in CI or lefthook: a turn needs a Google login. `pnpm smoke:antigravity`. +# +# The hook sessions run interactive under a pty, killed after a bound: older `agy` fired no hook in +# print mode (`-p`), and a print turn waits on every user MCP server. Its log and the files it +# touched are the evidence. HOME stays real for the login; `AIDD_USER_CONFIG_DIR` is relocated so +# setup never touches the real aidd profile. +set -uo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +FRAMEWORK="$(cd "$ROOT/.." && pwd)" +CLI="$ROOT/dist/cli.js" +TURN_SECONDS="${SMOKE_AGY_TIMEOUT:-60}" + +SKILL="aidd-context-11-explore" +AGENT="aidd-orchestrator-executor" +GHOST_AGENT="aidd-orchestrator-ghost" + +command -v agy >/dev/null 2>&1 || { echo "FATAL: agy not on PATH — install Antigravity CLI and log in"; exit 1; } +[[ -f "$CLI" ]] || { echo "FATAL: $CLI missing — run 'pnpm build' first"; exit 1; } + +TMP="$(mktemp -d)" +WS="$TMP/project" +SESSION_PID="" +cleanup() { + if [[ -n "$SESSION_PID" ]]; then + pkill -P "$SESSION_PID" 2>/dev/null + kill "$SESSION_PID" 2>/dev/null + fi + rm -rf "$TMP" +} +trap cleanup EXIT + +export AIDD_USER_CONFIG_DIR="$TMP/aidd-config" +export AIDD_SKIP_UPDATE_CHECK=1 + +# Under a pseudo-terminal: util-linux script(1) takes the command as one -c string, BSD as arguments. +pty_run() { + if script --version >/dev/null 2>&1; then + script -qec "$(printf '%q ' "$@")" /dev/null + else + script -q /dev/null "$@" + fi +} + +# How many named hooks agy loads, from its log: user-global hooks included. +hook_count() { grep -Eo 'loaded [0-9]+ named hooks' "$1" 2>/dev/null | head -1 | grep -Eo '[0-9]+'; } + +FAIL=0 +pass() { echo " PASS $1"; echo " $2"; } +fail() { echo " FAIL $1"; FAIL=$((FAIL + 1)); } + +echo "agy $(agy --version 2>&1 | head -1), $(date '+%Y-%m-%d %H:%M %Z')" + +# A project with a memory bank and an empty memory block, so the hook has something to fill. +mkdir -p "$WS/aidd_docs/memory" +printf '# Architecture\n' >"$WS/aidd_docs/memory/architecture.md" +printf '# Project\n\n## Memory Management\n\n\n\n' >"$WS/AGENTS.md" +git -C "$WS" init -q +git -C "$WS" -c user.email=smoke@aidd -c user.name=smoke commit -q --allow-empty -m init + +if ! (cd "$WS" && node "$CLI" setup --source local --path "$FRAMEWORK" --ai antigravity --plugins recommended --yes) >"$TMP/setup.log" 2>&1; then + echo "FATAL: aidd setup failed"; tail -5 "$TMP/setup.log"; exit 1 +fi +for f in ".agents/skills/$SKILL/SKILL.md" ".agents/hooks.json" ".agents/agents/$AGENT/agent.md"; do + [[ -f "$WS/$f" ]] || { echo "FATAL: setup did not write $f"; exit 1; } +done + +# One interactive session logging to $1, killed once `$2…` succeeds or the bound runs out. +session() { + local log="$1"; shift + (cd "$WS" && pty_run agy -i "reply OK" --mode plan --add-dir "$WS" --log-file "$log") >"$log.out" 2>&1 & + SESSION_PID=$! + for ((i = 0; i < TURN_SECONDS; i++)); do + "$@" && break + sleep 1 + done + pkill -P "$SESSION_PID" 2>/dev/null + kill "$SESSION_PID" 2>/dev/null + wait "$SESSION_PID" 2>/dev/null + SESSION_PID="" +} + +LOG="$TMP/agy-session.log" +session "$LOG" grep -q 'aidd_docs/memory/architecture.md' "$WS/AGENTS.md" + +# Startup logs "not logged into Antigravity" before the stored login is read, so only a missing +# success line means no login. +if ! grep -q "OAuth: authenticated successfully" "$LOG" 2>/dev/null; then + echo "FATAL: agy is not logged in — run 'agy' once and sign in"; exit 1 +fi + +# The log never names a hook, and user-global hooks count too, so the project's own are proven by +# difference: the same session, in the same mode, without .agents/hooks.json must load fewer. +BASE_LOG="$TMP/agy-baseline.log" +[[ -f "$WS/.agents/hooks.json" ]] && mv "$WS/.agents/hooks.json" "$TMP/hooks.json" +session "$BASE_LOG" grep -qs 'named hooks' "$BASE_LOG" +[[ -f "$TMP/hooks.json" ]] && mv "$TMP/hooks.json" "$WS/.agents/hooks.json" +with="$(hook_count "$LOG")" +without="$(hook_count "$BASE_LOG")" +if [[ -n "$with" && -n "$without" && "$with" -gt "$without" ]]; then + pass "project hooks loaded" "$with named hooks with .agents/hooks.json, $without without" +else + fail "hooks: .agents/hooks.json adds no loaded hook (${with:-?} with, ${without:-?} without)" +fi + +line="$(grep -m1 'aidd_docs/memory/architecture.md' "$WS/AGENTS.md")" +[[ -n "$line" ]] && pass "memory refreshed at the repo root" "AGENTS.md: $line" || fail "memory: AGENTS.md block still empty, the SessionStart hook did not run at the repo root" + +# The expansion is logged before the model answers, so a short bound is enough. +SKILL_LOG="$TMP/agy-skill.log" +(cd "$WS" && agy --add-dir "$WS" --mode plan --print-timeout 20s --log-file "$SKILL_LOG" -p "/$SKILL") >/dev/null 2>&1 +line="$(grep -o "expanded slash command \"$SKILL\" (skill)" "$SKILL_LOG" 2>/dev/null | head -1)" +[[ -n "$line" ]] && pass "skill expanded" "$line" || fail "skill: no 'expanded slash command \"$SKILL\"' line in the agy log" + +# Print mode answers /agents without the model. +AGENTS_JSON="$TMP/agents.json" +(cd "$WS" && agy --add-dir "$WS" --output-format json --print-timeout "${TURN_SECONDS}s" -p "/agents") >"$AGENTS_JSON" 2>&1 +line="$(grep -o "\"$AGENT\"" "$AGENTS_JSON" | head -1)" +if [[ -n "$line" ]] && ! grep -q "\"$GHOST_AGENT\"" "$AGENTS_JSON"; then + pass "agent listed" "/agents: $line, $GHOST_AGENT absent" +else + fail "agents: /agents does not list \"$AGENT\" (or lists the invented $GHOST_AGENT)" +fi + +echo +[[ "$FAIL" -eq 0 ]] && { echo "smoke-antigravity: all passed"; exit 0; } +echo "smoke-antigravity: $FAIL failed"; exit 1 diff --git a/docs/FAQ.md b/docs/FAQ.md index faca5cb70..e834bf28a 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -4,7 +4,7 @@ | Question | Answer | | --- | --- | -| Why AIDD instead of my own skills? | You skip what every team rebuilds: the plan, build and review loop, the packaging, and support for six tools. | +| Why AIDD instead of my own skills? | You skip what every team rebuilds: the plan, build and review loop, the packaging, and support for several tools. | | Does it cost money? | No, it is free (MIT). Model calls use your own plan or API balance. | | Where do I start? | `/aidd-context:00-onboard`, or pick a goal in the [guides](GUIDES.md). | | Which plugins should I install? | The stable ones: see the [README](../README.md#plugins). | diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 2dc24f085..c13c9e2a3 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -3,7 +3,7 @@ ## Requirements - [Node](https://nodejs.org) 22.12 or later (`node --version`). -- An AI coding tool: Claude Code, Cursor, GitHub Copilot, Codex, OpenCode or Kilo Code. +- An AI coding tool: Claude Code, Cursor, GitHub Copilot, Codex, OpenCode, Kilo Code or Antigravity CLI. ## Pick a method @@ -111,7 +111,7 @@ cp -r aidd-framework-cursor-marketplace-/plugins/aidd-* ~/.cursor/plugi -*OpenCode and Kilo Code have no marketplace: use flat files.* +*OpenCode, Kilo Code and Antigravity CLI use flat files.* ## Flat files @@ -122,7 +122,9 @@ git clone https://github.com/ai-driven-dev/framework.git npx @ai-driven-dev/cli@latest translate ./framework --to cursor --as flat --out . ``` -Replace `cursor` with your tool: `claude`, `cursor`, `copilot`, `codex`, `opencode` or `kilo`. +Replace `cursor` with your tool: `claude`, `cursor`, `copilot`, `codex`, `opencode`, `kilo` or `antigravity`. + +For an Antigravity archive, follow the [Antigravity steps](#antigravity-cli) to preserve existing hooks.
Without Node @@ -136,6 +138,15 @@ cp -R aidd-framework--flat-/. .
+### Antigravity CLI + +1. Extract `antigravity-flat` into an empty directory. Find `.agents/` inside the extracted archive's enclosing folder. +2. Copy its skills, agents and hook scripts into the matching `.agents/` paths in your project. Resolve any existing-file conflicts before replacing files. +3. If your project has no `.agents/hooks.json`, copy the archive's file. Otherwise merge its named top-level entries into the existing JSON, preserving user entries. Resolve any same-name conflict explicitly; extraction does not merge JSON files. +4. Start `agy` in the project. + +Codex flat also uses `.agents/skills/`. Removing either tool can delete skills the other still uses. + ## Update | Installed with | Run | diff --git a/docs/MAINTAINERS.md b/docs/MAINTAINERS.md index d6e07578c..15e33bbe7 100644 --- a/docs/MAINTAINERS.md +++ b/docs/MAINTAINERS.md @@ -85,6 +85,10 @@ Release rules: [Release](../RELEASE.md#rules). | `next` is missing | `git push origin main:next` | | Change the protection | Edit `.github/rulesets/main.json`, then an admin runs `gh api -X PUT repos/ai-driven-dev/framework/rulesets/ --input .github/rulesets/main.json` | +## Check Antigravity CLI + +Before releasing a change to its profile, run `cd cli && pnpm smoke:antigravity` with `agy` logged in. The local smoke checks skills, agents and the memory hook in a throwaway project. It needs a Google login and does not run in CI. + ## Do not edit by hand | What | Generated by | diff --git a/plugins/aidd-context/hooks/update_memory.js b/plugins/aidd-context/hooks/update_memory.js index 2cfb4ba01..2f7677272 100644 --- a/plugins/aidd-context/hooks/update_memory.js +++ b/plugins/aidd-context/hooks/update_memory.js @@ -42,6 +42,7 @@ const TOOL_FILES = { codex: "AGENTS.md", cursor: "AGENTS.md", opencode: "AGENTS.md", + antigravity: "AGENTS.md", copilot: ".github/copilot-instructions.md", }; diff --git a/plugins/aidd-context/skills/00-onboard/references/state/detection.md b/plugins/aidd-context/skills/00-onboard/references/state/detection.md index f66011153..8897ab262 100644 --- a/plugins/aidd-context/skills/00-onboard/references/state/detection.md +++ b/plugins/aidd-context/skills/00-onboard/references/state/detection.md @@ -2,7 +2,7 @@ Which AI tools the project uses, and whether each has its memory wired. For the state block's AI-tools line. -A tool is used when its own dir exists, or when a file only that tool reads exists. A file several tools read (`AGENTS.md`) is a wiring target, never a detection signal. +Prefer the project's declared tools and AIDD manifest. Use tool-specific paths as hints; shared `AGENTS.md` and `.agents/` paths are not proof of a host. Ask before wiring an ambiguous target. | Tool | Used when | Wired when this file has the block | | -------- | ------------------------------------------------------------------------------------ | ---------------------------------- | @@ -10,6 +10,7 @@ A tool is used when its own dir exists, or when a file only that tool reads exis | codex | `.codex/` | `AGENTS.md` | | cursor | `.cursor/` or `.cursorrules` | `AGENTS.md` | | opencode | `.opencode/` | `AGENTS.md` | +| antigravity | `.agents/agents/`, `.agents/rules/` or `.agents/hooks.json` | `AGENTS.md` | | copilot | `.github/copilot-instructions.md` or `.github/{instructions,agents,skills,prompts}/` | `.github/copilot-instructions.md` | - Detected tools only. An unused optional tool is omitted, never crossed. diff --git a/plugins/aidd-context/skills/02-project-memory/references/tools.md b/plugins/aidd-context/skills/02-project-memory/references/tools.md index 4b90d76d1..74245872a 100644 --- a/plugins/aidd-context/skills/02-project-memory/references/tools.md +++ b/plugins/aidd-context/skills/02-project-memory/references/tools.md @@ -8,9 +8,11 @@ The AI tools a project can use. | codex | `.codex/` | `AGENTS.md` | | cursor | `.cursor/` or `.cursorrules` | `AGENTS.md` | | opencode | `.opencode/` | `AGENTS.md` | +| antigravity | `.agents/agents/`, `.agents/rules/` or `.agents/hooks.json` | `AGENTS.md` | | copilot | `.github/copilot-instructions.md` or `.github/{instructions,agents,skills,prompts}/` | `.github/copilot-instructions.md` | - A shared `AGENTS.md` is a wiring target, never a detection signal. +- Resolve shared `.agents/` paths from declared project tools or the AIDD manifest; otherwise ask which tool to wire. - Tools sharing a context file wire it once; the block serves them all. - A context file carries the block under a `## Memory Management` section, shaped like `assets/templates/AGENTS.md`. - An existing context file keeps everything else: add only what is missing. diff --git a/plugins/aidd-context/skills/04-skill-generate/references/tool-detect.md b/plugins/aidd-context/skills/04-skill-generate/references/tool-detect.md index 286dbc7a3..c2795a218 100644 --- a/plugins/aidd-context/skills/04-skill-generate/references/tool-detect.md +++ b/plugins/aidd-context/skills/04-skill-generate/references/tool-detect.md @@ -9,5 +9,6 @@ Which AI tools a project has installed. | OpenCode | `.opencode/` | | GitHub Copilot | `.github/copilot-instructions.md` | | Codex CLI | `.codex/` | +| Antigravity CLI | `.agents/agents/`, `.agents/rules/` or `.agents/hooks.json` | -A bare `AGENTS.md` means Cursor, OpenCode, or Codex. Several signals can coexist. +Use the project's declared tools or AIDD manifest before directory hints. Shared `AGENTS.md` and `.agents/` paths do not identify a host. Ask when the target remains ambiguous; several tools can coexist. diff --git a/plugins/aidd-context/skills/04-skill-generate/references/tool-write.md b/plugins/aidd-context/skills/04-skill-generate/references/tool-write.md index 2863f4ccd..852aa9f06 100644 --- a/plugins/aidd-context/skills/04-skill-generate/references/tool-write.md +++ b/plugins/aidd-context/skills/04-skill-generate/references/tool-write.md @@ -11,6 +11,7 @@ Where a skill tree is written, per tool. | OpenCode | `.opencode/skills//` | | GitHub Copilot | `.github/skills//` | | Codex CLI | `.agents/skills//` | +| Antigravity CLI | `.agents/skills//` | | Plugin source | `plugins//skills//` | ## Frontmatter @@ -23,3 +24,4 @@ Emit `description` always, `name` only where listed, drop the rest. | Cursor, GitHub Copilot | `name`, `description`, opt `allowed-tools` | | OpenCode | `description`, opt `permission` map | | Codex CLI | `name`, `description` (strips the rest) | +| Antigravity CLI | `name`, `description` | diff --git a/plugins/aidd-context/skills/05-rule-generate/references/rule-discovery.md b/plugins/aidd-context/skills/05-rule-generate/references/rule-discovery.md index 1e84e8f9e..fdf9c246c 100644 --- a/plugins/aidd-context/skills/05-rule-generate/references/rule-discovery.md +++ b/plugins/aidd-context/skills/05-rule-generate/references/rule-discovery.md @@ -20,4 +20,4 @@ ## Contracts -[Claude](https://code.claude.com/docs/en/memory), [Cursor](https://cursor.com/docs/rules), [Cursor CLI](https://cursor.com/docs/cli/using#rules), [Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-custom-instructions), [Copilot support](https://docs.github.com/en/copilot/reference/custom-instructions-support), [Codex](https://learn.chatgpt.com/docs/agent-configuration/agents-md), [OpenCode V1](https://opencode.ai/docs/rules/), [OpenCode V2](https://opencode.ai/v2/docs/instructions/). +[Claude](https://code.claude.com/docs/en/memory), [Cursor](https://cursor.com/docs/rules), [Cursor CLI](https://cursor.com/docs/cli/using#rules), [Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-custom-instructions), [Copilot support](https://docs.github.com/en/copilot/reference/custom-instructions-support), [Codex](https://learn.chatgpt.com/docs/agent-configuration/agents-md), [OpenCode V1](https://opencode.ai/docs/rules/), [OpenCode V2](https://opencode.ai/v2/docs/instructions/), [Antigravity](https://antigravity.google/docs/rules). diff --git a/plugins/aidd-context/skills/05-rule-generate/references/rule-publication.md b/plugins/aidd-context/skills/05-rule-generate/references/rule-publication.md index af89c4aaf..0a7c070cc 100644 --- a/plugins/aidd-context/skills/05-rule-generate/references/rule-publication.md +++ b/plugins/aidd-context/skills/05-rule-generate/references/rule-publication.md @@ -9,9 +9,12 @@ | Copilot / `copilot` | `.github/instructions/-.instructions.md` | comma-joined `applyTo`; all-files `**` | | Codex / `codex` | root `AGENTS.md` | shared signed `aidd_rules`, textual scope | | OpenCode / `opencode` | root `AGENTS.md` | same contribution | +| Antigravity / `antigravity` | `.agents/rules/.md` | with paths: `trigger: glob`, `description`, comma-joined `globs`; all-files: `trigger: always_on`, `description`, no `globs` | Copilot `` drops the slug's numeric prefix: category `01-standards`, slug `1-local-names` → `01-local-names.instructions.md`. +The writer refuses raw rendered Antigravity output over 24,000 bytes; the host applies its limit after expanding includes, so the writer's check does not guarantee their expanded size fits. Scoped activation remains unverified in the host. + ## Operations Writer: absolute `scripts/write-rule.cjs` beside the loaded installed `SKILL.md`. Assume no checkout, project-relative or CLI path. diff --git a/plugins/aidd-context/skills/05-rule-generate/scripts/write-rule.cjs b/plugins/aidd-context/skills/05-rule-generate/scripts/write-rule.cjs index ba341479d..b168f7075 100644 --- a/plugins/aidd-context/skills/05-rule-generate/scripts/write-rule.cjs +++ b/plugins/aidd-context/skills/05-rule-generate/scripts/write-rule.cjs @@ -6,7 +6,7 @@ const fs = require("node:fs"); const path = require("node:path"); const { createHash, randomUUID } = require("node:crypto"); -const TOOLS = ["claude", "cursor", "copilot", "codex", "opencode"]; +const TOOLS = ["claude", "cursor", "copilot", "codex", "opencode", "antigravity"]; const CATEGORIES = ["architecture", "standards", "programming-languages", "frameworks-and-libraries", "tooling", "testing", "design-patterns", "quality", "domain", "other"]; const SHARED = ["codex", "opencode"]; const SOURCE = "aidd_docs/rules"; @@ -37,7 +37,7 @@ function options(args) { function tools(value) { const selected = typeof value === "string" ? value.split(",") : value; - if (!Array.isArray(selected) || !selected.length || new Set(selected).size !== selected.length || selected.some((tool) => !TOOLS.includes(tool))) fail("Targets must be distinct confirmed tools: claude,cursor,copilot,codex,opencode."); + if (!Array.isArray(selected) || !selected.length || new Set(selected).size !== selected.length || selected.some((tool) => !TOOLS.includes(tool))) fail("Targets must be distinct confirmed tools: claude,cursor,copilot,codex,opencode,antigravity."); return [...selected].sort(); } @@ -108,6 +108,8 @@ function nativePath(rule, tool) { const id = identity(rule.category, rule.slug); if (tool === "claude") return `.claude/rules/${id}.md`; if (tool === "cursor") return `.cursor/rules/${id}.mdc`; + // Antigravity loads only direct children; the slug's category digit keeps the flat name unique. + if (tool === "antigravity") return `.agents/rules/${rule.slug}.md`; return `.github/instructions/${rule.category.slice(0, 2)}-${rule.slug.slice(2)}.instructions.md`; } @@ -117,9 +119,12 @@ function renderNative(rule, tool, signed = true) { if (tool === "claude") fields = rule.paths.length ? `paths:\n${rule.paths.map((glob) => ` - ${quote(glob)}\n`).join("")}` : ""; if (tool === "cursor") fields = `description: ${quote(rule.description)}\n${rule.paths.length ? `globs: ${quote(rule.paths.join(","))}\n` : ""}alwaysApply: ${!rule.paths.length}\n`; if (tool === "copilot") fields = `applyTo: ${quote(rule.paths.length ? rule.paths.join(",") : "**")}\n`; + if (tool === "antigravity") fields = `trigger: ${rule.paths.length ? "glob" : "always_on"}\ndescription: ${quote(rule.description)}\n${rule.paths.length ? `globs: ${quote(rule.paths.join(","))}\n` : ""}`; const text = (fields ? `---\n${fields}---\n` : "") + rule.body; safeText(text); - return signed ? `${text}\n\n` : text; + const output = signed ? `${text}\n\n` : text; + if (tool === "antigravity" && Buffer.byteLength(output) > 24000) fail("Antigravity rule exceeds its 24,000-byte per-file limit."); + return output; } function ownedNative(existing, prior, tool, relative) { diff --git a/plugins/aidd-context/skills/06-agent-generate/references/tool-paths.md b/plugins/aidd-context/skills/06-agent-generate/references/tool-paths.md index 386902675..4d806c791 100644 --- a/plugins/aidd-context/skills/06-agent-generate/references/tool-paths.md +++ b/plugins/aidd-context/skills/06-agent-generate/references/tool-paths.md @@ -11,8 +11,9 @@ The per-tool agent path and the gate every run executes before writing. Agent sl | OpenCode | `.opencode/agents/.md` | markdown + frontmatter | | GitHub Copilot | `.github/agents/.agent.md` | markdown + frontmatter | | Codex CLI | `.codex/agents/.toml` | TOML (converted) | +| Antigravity CLI | `.agents/agents//agent.md` | markdown + frontmatter | -Agents are supported on all five tools. +Agents are supported on all six tools. User-level agents, for every project of the user: Claude Code `~/.claude/agents/` (`CLAUDE_CONFIG_DIR`), Codex `~/.codex/agents/` (`CODEX_HOME`), OpenCode `~/.config/opencode/agents/` (`XDG_CONFIG_HOME`), Copilot `~/.copilot/agents/.agent.md` (`COPILOT_HOME`). Cursor documents `~/.cursor/agents/`; prefer the project path. Sources: [Claude](https://code.claude.com/docs/en/sub-agents), [Codex](https://developers.openai.com/codex/subagents), [OpenCode](https://opencode.ai/docs/agents), [Copilot](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-config-dir-reference), [Cursor](https://cursor.com/docs/subagents). @@ -29,6 +30,7 @@ The canonical agent carries `name` and `description` and no tool list: every hos | OpenCode V2 | `description`, `mode: subagent`, optional `model` as `provider/model#variant`. No `name`: the file path is the ID | | GitHub Copilot | `name`, `description`, optional `model`, `reasoningEffort`, `include-custom-instructions` | | Codex CLI | `name`, `description`, optional `model`, `model_reasoning_effort` | +| Antigravity CLI | `name`, `description`, `model: inherit`, optional `tools` as a YAML list | Write OpenCode agents for V2 only: V2 still loads V1 definitions, and treats their `tools` and `permission` fields as legacy. @@ -45,6 +47,8 @@ Codex agents are TOML, not markdown. Convert: ## Detect (which tools are installed) +Resolve tools from project declarations or the AIDD manifest before using directory hints. Shared `AGENTS.md` and `.agents/` paths require host confirmation. + | Signal | Tool(s) | | --------------------------------- | ------------------------------------- | | `.claude/` or `CLAUDE.md` | Claude Code | @@ -52,7 +56,7 @@ Codex agents are TOML, not markdown. Convert: | `.opencode/` | OpenCode | | `.codex/` | Codex CLI | | `.github/copilot-instructions.md` | GitHub Copilot | -| `AGENTS.md` | Cursor, OpenCode, or Codex (list all) | +| `.agents/agents/`, `.agents/rules/` or `.agents/hooks.json` | Antigravity CLI | ## Write targets diff --git a/plugins/aidd-context/skills/08-hook-generate/references/tool-paths.md b/plugins/aidd-context/skills/08-hook-generate/references/tool-paths.md index 32c7ad946..41ad98636 100644 --- a/plugins/aidd-context/skills/08-hook-generate/references/tool-paths.md +++ b/plugins/aidd-context/skills/08-hook-generate/references/tool-paths.md @@ -11,6 +11,7 @@ Per-tool hook support, event names, file formats, and scopes. Hook slice only: n | Cursor | yes | JSON config + script. | | GitHub Copilot | yes | JSON config + script. Also reads Claude's `.claude/` config. | | OpenCode | no | Hooks are JS/TS plugin modules, not config. Skip with the reason below. | +| Antigravity CLI | yes | JSON config + script. Project scope only here, see below. | **OpenCode skip reason.** OpenCode hooks are code, not a config entry plus a script. Point the user to write a plugin under `.opencode/plugins/` (project) or `~/.config/opencode/plugins/` (user), per `https://opencode.ai/docs/plugins`. This skill does not generate it. @@ -18,18 +19,18 @@ Per-tool hook support, event names, file formats, and scopes. Hook slice only: n Each tool names the same moment differently and supports a different subset. Core moments, with the canonical event name per tool. A `-` means the tool does not expose that moment. -| Moment | Claude Code | Codex CLI | Cursor | GitHub Copilot | -| ------------------ | ------------------ | --------------- | -------------------- | ------------------ | -| session start | `SessionStart` | `SessionStart` | `sessionStart` | `SessionStart` | -| prompt submitted | `UserPromptSubmit` | `UserPromptSubmit` | `beforeSubmitPrompt` | `UserPromptSubmit` | -| before a tool runs | `PreToolUse` | `PreToolUse` | `preToolUse` | `PreToolUse` | -| after a tool runs | `PostToolUse` | `PostToolUse` | `postToolUse` | `PostToolUse` | -| before compaction | `PreCompact` | `PreCompact` | `preCompact` | `PreCompact` | -| subagent stop | `SubagentStop` | `SubagentStop` | `subagentStop` | `SubagentStop` | -| turn stop | `Stop` | `Stop` | `stop` | `Stop` | -| session end | `SessionEnd` | `SessionEnd` | `sessionEnd` | `SessionEnd` | +| Moment | Claude Code | Codex CLI | Cursor | GitHub Copilot | Antigravity CLI | +| ------------------ | ------------------ | --------------- | -------------------- | ------------------ | --------------- | +| session start | `SessionStart` | `SessionStart` | `sessionStart` | `SessionStart` | `SessionStart` | +| prompt submitted | `UserPromptSubmit` | `UserPromptSubmit` | `beforeSubmitPrompt` | `UserPromptSubmit` | - | +| before a tool runs | `PreToolUse` | `PreToolUse` | `preToolUse` | `PreToolUse` | `PreToolUse` | +| after a tool runs | `PostToolUse` | `PostToolUse` | `postToolUse` | `PostToolUse` | `PostToolUse` | +| before compaction | `PreCompact` | `PreCompact` | `preCompact` | `PreCompact` | - | +| subagent stop | `SubagentStop` | `SubagentStop` | `subagentStop` | `SubagentStop` | - | +| turn stop | `Stop` | `Stop` | `stop` | `Stop` | `Stop` | +| session end | `SessionEnd` | `SessionEnd` | `sessionEnd` | `SessionEnd` | - | -Each tool exposes more moments than these. For the full list, read the tool's docs: Claude `https://code.claude.com/docs/en/hooks`, Codex `https://developers.openai.com/codex/hooks`, Cursor `https://cursor.com/docs/hooks`, Copilot `https://docs.github.com/en/copilot/reference/hooks-configuration`. Confirm a moment exists before wiring it. Copilot also accepts the camelCase names (`sessionStart`, `preToolUse`). +Each tool exposes more moments than these. For the full list, read the tool's docs: Claude `https://code.claude.com/docs/en/hooks`, Codex `https://developers.openai.com/codex/hooks`, Cursor `https://cursor.com/docs/hooks`, Copilot `https://docs.github.com/en/copilot/reference/hooks-configuration`, Antigravity `https://antigravity.google/docs/hooks`. Confirm a moment exists before wiring it. Copilot also accepts the camelCase names (`sessionStart`, `preToolUse`). ## File and format per tool @@ -39,21 +40,24 @@ Each tool exposes more moments than these. For the full list, read the tool's do | Codex CLI | `~/.codex/hooks.json` or `[hooks]` in `config.toml` | same entry shape as Claude. | | Cursor | `.cursor/hooks.json` | `{ "version": 1, "hooks": { "": [ { "command": "..." } ] } }` | | GitHub Copilot | `.github/hooks/*.json` or a `hooks` block in `.github/copilot/settings.json` | `{ "version": 1, "hooks": { "": [ { "type": "command", "command": "..." } ] } }` | +| Antigravity CLI | `.agents/hooks.json` | `{ "": { "SessionStart": [ { "command": "..." } ] } }` | A Claude `settings.json` and a plugin or standalone `hooks/hooks.json` both wrap the event map under a top-level `hooks` key, so the file is `{ "hooks": { "": [ ... ] } }`. A Codex `config.toml` uses a `[hooks]` table instead. +Antigravity `PreToolUse` and `PostToolUse` use `{ "matcher": "", "hooks": [ { "command": "..." } ] }` groups; other events contain handlers directly. Matchers use Antigravity tool names. Commands run from `/.agents`; prefix root-relative paths with `cd .. && `. + ## Scopes per tool -Ask the user which scope, then write the matching file. A `-` means the tool has no such scope. +Ask which supported scope to target, then use its path below. A `-` means this skill does not generate that scope. -| Scope | Claude Code | Codex CLI | Cursor | GitHub Copilot | -| ---------------- | ------------------------------ | -------------------------- | ---------------------------- | ------------------------ | -| user / global | `~/.claude/settings.json` | `~/.codex/` (`hooks.json` or `config.toml`) | `~/.cursor/hooks.json` | `~/.copilot/hooks/` | -| project, shared | `.claude/settings.json` | `/.codex/` (trust-gated) | `.cursor/hooks.json` | `.github/hooks/` | -| project, local | `.claude/settings.local.json` | - | - | - | -| component / agent | skill or agent frontmatter | - | - | `.agent.md` frontmatter | -| plugin | plugin `hooks/hooks.json` | plugin `hooks.json` | - | - | -| enterprise / team | managed policy settings | managed policy | team or enterprise path | `policy.d/` or registry | +| Scope | Claude Code | Codex CLI | Cursor | GitHub Copilot | Antigravity CLI | +| ---------------- | ------------------------------ | -------------------------- | ---------------------------- | ------------------------ | --------------- | +| user / global | `~/.claude/settings.json` | `~/.codex/` (`hooks.json` or `config.toml`) | `~/.cursor/hooks.json` | `~/.copilot/hooks/` | - | +| project, shared | `.claude/settings.json` | `/.codex/` (trust-gated) | `.cursor/hooks.json` | `.github/hooks/` | `.agents/hooks.json` | +| project, local | `.claude/settings.local.json` | - | - | - | - | +| component / agent | skill or agent frontmatter | - | - | `.agent.md` frontmatter | - | +| plugin | plugin `hooks/hooks.json` | plugin `hooks.json` | - | - | - | +| enterprise / team | managed policy settings | managed policy | team or enterprise path | `policy.d/` or registry | - | Never pick a scope silently. State the resolved file and confirm it. @@ -65,6 +69,7 @@ The shared `command` handler: a script the tool runs at the moment. It reads the - **Claude / Codex / Copilot.** Exit `0` is success (stdout may carry a JSON object or, on some moments, context). Exit `2` blocks on a moment that honors it (stderr surfaces to the model). Any other code is a non-blocking error. After a tool, the model reads context only from stdout, and each host reads a different key: Claude Code and Codex read `{ "hookSpecificOutput": { "hookEventName": "PostToolUse", "additionalContext": "..." } }`, Copilot CLI reads a top-level `{ "additionalContext": "..." }`. Codex fails the hook on any other key, so a hook meant for every tool writes the one each host reads, chosen by the payload (Copilot's carries `tool_result`). - **Cursor.** Exit `0` success, exit `2` blocks (same as `permission: "deny"`), any other code fails open. Set `failClosed: true` on the entry to make a crash block instead. Gating moments return `{ "permission": "allow" | "deny" | "ask" }` on stdout. +- **Antigravity.** Stdin uses `conversationId`, `workspacePaths` and `toolCall.{name,args}`. Write JSON on stdout: `PreToolUse` requires `decision` (`allow`, `deny` or `ask`) with optional `reason`; `Stop` uses `decision: continue` and `reason` to resume; `PostToolUse` returns `{}`. Session/invocation events can return `injectSteps`. Replace the scaffold's exit-2 comment with this contract. Per-tool stdout schemas and which moments can block live in each tool's docs (linked above). Codex also has a `notify` mechanism (user scope only, single turn-complete event, JSON on argv not stdin) for a simple turn-complete notification. @@ -74,11 +79,11 @@ Written as `${VAR}` inside a command: `CLAUDE_PROJECT_DIR` (project root), `CLAU ## Write targets -- **Host project.** Merge the entry into the resolved scope's file for each confirmed supported tool. The script goes in a `hooks/` dir beside the config by default, or another dir the user names, referenced by absolute path or an approved `${VAR}`. +- **Host project.** Merge the entry into the resolved scope's file for each confirmed supported tool. Put the script in a `hooks/` dir beside the config, or where the user names, using the host's path rules above. - **Plugin source.** Merge into `plugins//hooks/hooks.json` (the bare hooks object), with the script under `plugins//hooks/scripts/`. ## Safety checks - **Asset-access precheck.** Before writing, confirm this reference is readable. If not, stop: the plugin is not installed in this host. - **Merge check.** Before writing, read the target file and confirm the new entry is appended to the moment's list, never overwriting a sibling. -- **Write-target validation.** After writing, confirm the file is valid and every handler path is an approved `${VAR}` or an absolute path under the workspace (a hook command runs from an arbitrary cwd, so an absolute path or `${VAR}` is expected, not a relative one). Otherwise stop and report. +- **Write-target validation.** Confirm valid config and workspace-confined paths. Resolve Antigravity's relative paths from its cwd above; other hosts use absolute paths or approved `${VAR}`. Stop on failure. diff --git a/plugins/aidd-context/skills/10-learn/references/sync-arguments.md b/plugins/aidd-context/skills/10-learn/references/sync-arguments.md index 5c3bc2e9a..f2f9f08b5 100644 --- a/plugins/aidd-context/skills/10-learn/references/sync-arguments.md +++ b/plugins/aidd-context/skills/10-learn/references/sync-arguments.md @@ -8,6 +8,7 @@ Arguments accepted by `hooks/update_memory.js`. The hook maps tool names to cont | `codex` | `AGENTS.md` | | `cursor` | `AGENTS.md` | | `opencode` | `AGENTS.md` | +| `antigravity` | `AGENTS.md` | | `copilot` | `.github/copilot-instructions.md` | Rules: diff --git a/plugins/aidd-context/skills/11-explore/references/ai-mapping.md b/plugins/aidd-context/skills/11-explore/references/ai-mapping.md index 5e0a7065d..a45c2d0c1 100644 --- a/plugins/aidd-context/skills/11-explore/references/ai-mapping.md +++ b/plugins/aidd-context/skills/11-explore/references/ai-mapping.md @@ -4,7 +4,7 @@ Where to look for each artifact type per AI tool. Scan-only: the paths and forma ## Presence signal -A tool is present only when one of its own mapped surfaces below holds a file. A shared parent directory is never a signal by itself. +Identify tools from project declarations or the AIDD manifest first. The surfaces below are scan hints, not host identity: shared `.agents/` paths may serve several tools. Report ambiguous ownership instead of assigning those files to a host. ## AI quick map - content artifacts @@ -15,6 +15,7 @@ A tool is present only when one of its own mapped surfaces below holds a file. A | OpenCode | `.opencode/agents/` | `.opencode/commands/` | `aidd_docs/rules/` (canonical sources); shared `aidd_rules` contribution in root `AGENTS.md` | `.opencode/skills/` | `AGENTS.md` | | GitHub Copilot | `.github/agents/*.agent.md` | `.github/prompts/*.prompt.md` | `.github/instructions/*.instructions.md` | `.github/skills/` | `.github/copilot-instructions.md` | | Codex CLI | `.codex/agents/{name}.toml` | **Not supported** | `aidd_docs/rules/` (canonical sources); shared `aidd_rules` contribution in root `AGENTS.md`, not execution policies | `.agents/skills/aidd-{name}/SKILL.md` | `AGENTS.md` | +| Antigravity CLI | `.agents/agents/{name}/agent.md` | Not mapped | `.agents/rules/.md`, flat | `.agents/skills/aidd-{name}/SKILL.md` | `AGENTS.md` | ## AI quick map - hooks, plugins @@ -25,6 +26,7 @@ A tool is present only when one of its own mapped surfaces below holds a file. A | OpenCode | JS/TS module under `.opencode/plugins/` (parse as JS, not JSON) | Not supported | | GitHub Copilot | `.github/hooks/*.json` (workspace), `~/.copilot/hooks` (user), `/hooks.json` or `/hooks/hooks.json` (plugin) | `plugin.json` at plugin root | | Codex CLI | `.codex/hooks.json` (project / user) OR `[hooks]` table in `.codex/config.toml` | `.codex-plugin/plugin.json` | +| Antigravity CLI | `.agents/hooks.json` (project), keyed by hook name | Not mapped | ## MCP config per tool @@ -57,3 +59,4 @@ Where to scan when enumerating installed plugins (not the plugin manifest path i | OpenCode | `~/.config/opencode/plugins/` (global JS/TS modules); `~/.cache/opencode/node_modules/` (npm-installed); project `.opencode/plugins/` | | GitHub Copilot | macOS: `~/Library/Application Support/Code/agentPlugins/` ; Linux: `~/.config/Code/agentPlugins/` ; Windows: `%APPDATA%\Code\agentPlugins\` ; CLI-installed: `~/.copilot/installed-plugins/` | | Codex CLI | `~/.codex/plugins/cache/$MARKETPLACE/$PLUGIN/$VERSION/` | +| Antigravity CLI | Not mapped | diff --git a/scripts/__tests__/check-referenced-paths.test.js b/scripts/__tests__/check-referenced-paths.test.js index 7dc00079c..f6eca37ca 100644 --- a/scripts/__tests__/check-referenced-paths.test.js +++ b/scripts/__tests__/check-referenced-paths.test.js @@ -47,6 +47,13 @@ test("referencedPaths skips a path the reader creates, never this repository's o assert.deepEqual(referencedPaths(content, new Set([".aidd"])), []); }); +test("referencedPaths skips the Antigravity hooks file an install writes into the reader's project", () => { + // This repository tracks `.agents/` for its own skills, which makes `.agents` an anchor. + const content = "Unzip the archive: the memory hook lands in `.agents/hooks.json`."; + + assert.deepEqual(referencedPaths(content, new Set([".agents"])), []); +}); + test("deadReferences names the file, the line and the path", () => { const tempDir = fs.mkdtempSync(path.join(root, "scripts/__tests__/.tmp-check-referenced-paths-")); diff --git a/scripts/__tests__/rule-generation.test.js b/scripts/__tests__/rule-generation.test.js index dd6d1ac0b..ce7fec27c 100644 --- a/scripts/__tests__/rule-generation.test.js +++ b/scripts/__tests__/rule-generation.test.js @@ -65,11 +65,12 @@ for (const paths of [[], ["src/domain/**/*.ts", 'tests/quoted"name/**/*.ts']]) t const f = fixture(t); const description = 'Review "domain": naïve \\ conventions #1'; const body = "# Review\r\n\r\n- Preserve exact text: café ⚙.\r\n"; - assert.equal(f.run({ ...rule, description, paths, body }, "claude,cursor,copilot").status, 0); + assert.equal(f.run({ ...rule, description, paths, body }, "claude,cursor,copilot,antigravity").status, 0); const documents = [ [".claude/rules/01-standards/1-naming.md", paths.length ? { paths } : null], [".cursor/rules/01-standards/1-naming.mdc", { description, ...(paths.length ? { globs: paths.join(",") } : {}), alwaysApply: !paths.length }], [".github/instructions/01-naming.instructions.md", { applyTo: paths.length ? paths.join(",") : "**" }], + [".agents/rules/1-naming.md", paths.length ? { trigger: "glob", description, globs: paths.join(",") } : { trigger: "always_on", description }], ]; for (const [name, expected] of documents) { const text = f.read(name); @@ -309,6 +310,13 @@ for (const target of ["aidd_docs/rules", ".claude/rules", "AGENTS.md"]) test(`sy assert.deepEqual(f.snapshot(), before); }); +test("Antigravity's 24,000-byte rule file limit refuses prospective writes", (t) => { + const f = fixture(t); + const before = f.snapshot(); + assert.notEqual(f.run({ ...rule, body: "x".repeat(24000) }, "antigravity").status, 0); + assert.deepEqual(f.snapshot(), before); +}); + test("Codex override and local 32 KiB limit refuse prospective writes", (t) => { const f = fixture(t); f.put("AGENTS.override.md", "override"); diff --git a/scripts/__tests__/update-memory.test.js b/scripts/__tests__/update-memory.test.js index fc9440cf4..2f38a170f 100644 --- a/scripts/__tests__/update-memory.test.js +++ b/scripts/__tests__/update-memory.test.js @@ -167,6 +167,17 @@ test("an unknown tool name is rejected", () => { assert.match(result.stderr, /unknown tool emacs/u); }); +test("antigravity refreshes AGENTS.md, the context file agy reads", () => { + const result = run({ + context: `${OPEN}\n${CLOSE}\n`, + contextAt: "AGENTS.md", + args: ["antigravity"], + }); + + assert.equal(result.status, 0); + assert.match(result.content, /^\[aidd_docs\/memory\/architecture\.md\]\(aidd_docs\/memory\/architecture\.md\)$/mu); +}); + test("a new-marker pair quoted in prose above the block does not hijack the splice", () => { const quote = `Upgrade note: the block now uses \`${OPEN}\` and \`${CLOSE}\`.`; const result = run({ context: `${quote}\n\n${OPEN}\n${CLOSE}\n` }); diff --git a/scripts/check-referenced-paths.js b/scripts/check-referenced-paths.js index 4511453bc..16459003f 100644 --- a/scripts/check-referenced-paths.js +++ b/scripts/check-referenced-paths.js @@ -31,8 +31,10 @@ function topLevelEntries() { * `.aidd/config.json` is the telemetry opt-in switch a repository commits to turn measurement on; * this one has not, so that absence is the state the prose describes. The anchor appears as soon * as a contributor runs the CLI in this checkout, which is what turned a page into a refusal. + * `.agents/hooks.json` is the hooks file an Antigravity install writes into the reader's project; + * this repository tracks `.agents/` for its own skills only. */ -const READER_CREATED = new Set([".aidd/config.json"]); +const READER_CREATED = new Set([".aidd/config.json", ".agents/hooks.json"]); const BACKTICKED = /`([^`\n]+)`/gu;