diff --git a/docs/agents.md b/docs/agents.md index 60d5f16aa..d2633b8a1 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -160,11 +160,12 @@ Kiro uses native custom agents in `~/.kiro/agents/`. `gentle-ai` writes phase ag ### Antigravity -- Skills at `~/.gemini/antigravity/skills/` (native Antigravity feature) -- MCP config at `~/.gemini/antigravity/mcp_config.json` +- Skills at `/skills/` where `` is the resolved Antigravity variant (IDE → Desktop → `~/.gemini/antigravity-cli/` fallback) +- Engram plugin at `/plugins/gentle-ai-engram/` +- MCP config at `~/.gemini/config/mcp_config.json` (shared global location) - System prompt appended to `~/.gemini/GEMINI.md` (shared with Gemini CLI — collision check warns if both are installed) - Mission Control handles built-in sub-agent delegation (Browser, Terminal) automatically -- Settings managed via the IDE's Agent settings UI, not via `settings.json` +- Settings initialized via `/settings.json` but primarily managed via the IDE's Agent settings UI ### Kimi Code diff --git a/internal/agents/antigravity/adapter.go b/internal/agents/antigravity/adapter.go index bad5a8298..1a44d1b1f 100644 --- a/internal/agents/antigravity/adapter.go +++ b/internal/agents/antigravity/adapter.go @@ -9,6 +9,13 @@ import ( "github.com/gentleman-programming/gentle-ai/internal/system" ) +// GlobalMCPConfigPath returns the absolute path to the shared global MCP +// configuration file under homeDir. Antigravity uses this single location +// across CLI, Desktop, and IDE variants. +func GlobalMCPConfigPath(homeDir string) string { + return filepath.Join(homeDir, ".gemini", "config", "mcp_config.json") +} + type statResult struct { isDir bool err error @@ -24,13 +31,19 @@ func NewAdapter() *Adapter { } } -// antigravityVariantDir returns the resolved variant directory under ~/.gemini. -// Prefers "antigravity-desktop" when it exists, falls back to "antigravity-cli". +// antigravityVariantDir returns the resolved variant directory. +// Checks OS-specific IDE paths, then legacy desktop, falls back to CLI. func (a *Adapter) antigravityVariantDir(homeDir string) string { - desktop := filepath.Join(homeDir, ".gemini", "antigravity-desktop") - if stat := a.statPath(desktop); stat.err == nil { + ideDir := filepath.Join(homeDir, ".gemini", "antigravity-ide") + if stat := a.statPath(ideDir); stat.err == nil && stat.isDir { + return ideDir + } + + desktop := filepath.Join(homeDir, ".gemini", "antigravity") + if stat := a.statPath(desktop); stat.err == nil && stat.isDir { return desktop } + return filepath.Join(homeDir, ".gemini", "antigravity-cli") } @@ -105,7 +118,7 @@ func (a *Adapter) MCPStrategy() model.MCPStrategy { // --- MCP --- func (a *Adapter) MCPConfigPath(homeDir string, _ string) string { - return filepath.Join(a.antigravityVariantDir(homeDir), "mcp_config.json") + return GlobalMCPConfigPath(homeDir) } // --- Optional capabilities --- diff --git a/internal/agents/antigravity/adapter_test.go b/internal/agents/antigravity/adapter_test.go index 3813b704d..e35fa7a77 100644 --- a/internal/agents/antigravity/adapter_test.go +++ b/internal/agents/antigravity/adapter_test.go @@ -31,32 +31,38 @@ func makeStatFn(existingDirs ...string) func(string) statResult { func TestAntigravityVariantDir(t *testing.T) { home := t.TempDir() cliDir := filepath.Join(home, ".gemini", "antigravity-cli") - desktopDir := filepath.Join(home, ".gemini", "antigravity-desktop") + desktopDir := filepath.Join(home, ".gemini", "antigravity") + ideDir := filepath.Join(home, ".gemini", "antigravity-ide") tests := []struct { name string existingDirs []string - wantSuffix string // last two path segments expected + wantDir string }{ { name: "only CLI dir exists resolves to CLI", existingDirs: []string{cliDir}, - wantSuffix: filepath.Join(".gemini", "antigravity-cli"), + wantDir: cliDir, }, { name: "only Desktop dir exists resolves to Desktop", existingDirs: []string{desktopDir}, - wantSuffix: filepath.Join(".gemini", "antigravity-desktop"), + wantDir: desktopDir, }, { - name: "both exist prefers Desktop", - existingDirs: []string{cliDir, desktopDir}, - wantSuffix: filepath.Join(".gemini", "antigravity-desktop"), + name: "only IDE dir exists resolves to IDE", + existingDirs: []string{ideDir}, + wantDir: ideDir, + }, + { + name: "all exist prefers IDE over Desktop over CLI", + existingDirs: []string{cliDir, desktopDir, ideDir}, + wantDir: ideDir, }, { name: "neither exists falls back to CLI", existingDirs: []string{}, - wantSuffix: filepath.Join(".gemini", "antigravity-cli"), + wantDir: cliDir, }, } @@ -64,9 +70,8 @@ func TestAntigravityVariantDir(t *testing.T) { t.Run(tt.name, func(t *testing.T) { a := &Adapter{statPath: makeStatFn(tt.existingDirs...)} got := a.antigravityVariantDir(home) - want := filepath.Join(home, tt.wantSuffix) - if got != want { - t.Fatalf("antigravityVariantDir() = %q, want %q", got, want) + if got != tt.wantDir { + t.Fatalf("antigravityVariantDir() = %q, want %q", got, tt.wantDir) } }) } @@ -77,7 +82,7 @@ func TestAntigravityVariantDir(t *testing.T) { func TestDetect(t *testing.T) { home := t.TempDir() cliDir := filepath.Join(home, ".gemini", "antigravity-cli") - desktopDir := filepath.Join(home, ".gemini", "antigravity-desktop") + desktopDir := filepath.Join(home, ".gemini", "antigravity") tests := []struct { name string @@ -174,14 +179,15 @@ func TestConfigPathsCLIOnly(t *testing.T) { if got := a.SettingsPath(home); got != filepath.Join(cliDir, "settings.json") { t.Fatalf("SettingsPath() = %q, want %q", got, filepath.Join(cliDir, "settings.json")) } - if got := a.MCPConfigPath(home, "ctx7"); got != filepath.Join(cliDir, "mcp_config.json") { - t.Fatalf("MCPConfigPath() = %q, want %q", got, filepath.Join(cliDir, "mcp_config.json")) + wantMCP := GlobalMCPConfigPath(home) + if got := a.MCPConfigPath(home, "ctx7"); got != wantMCP { + t.Fatalf("MCPConfigPath() = %q, want %q", got, wantMCP) } } func TestConfigPathsDesktopOnly(t *testing.T) { home := t.TempDir() - desktopDir := filepath.Join(home, ".gemini", "antigravity-desktop") + desktopDir := filepath.Join(home, ".gemini", "antigravity") a := &Adapter{statPath: makeStatFn(desktopDir)} if got := a.GlobalConfigDir(home); got != desktopDir { @@ -193,15 +199,16 @@ func TestConfigPathsDesktopOnly(t *testing.T) { if got := a.SettingsPath(home); got != filepath.Join(desktopDir, "settings.json") { t.Fatalf("SettingsPath() = %q, want %q", got, filepath.Join(desktopDir, "settings.json")) } - if got := a.MCPConfigPath(home, "ctx7"); got != filepath.Join(desktopDir, "mcp_config.json") { - t.Fatalf("MCPConfigPath() = %q, want %q", got, filepath.Join(desktopDir, "mcp_config.json")) + wantMCP := GlobalMCPConfigPath(home) + if got := a.MCPConfigPath(home, "ctx7"); got != wantMCP { + t.Fatalf("MCPConfigPath() = %q, want %q", got, wantMCP) } } func TestConfigPathsBothExistPrefersDesktop(t *testing.T) { home := t.TempDir() cliDir := filepath.Join(home, ".gemini", "antigravity-cli") - desktopDir := filepath.Join(home, ".gemini", "antigravity-desktop") + desktopDir := filepath.Join(home, ".gemini", "antigravity") a := &Adapter{statPath: makeStatFn(cliDir, desktopDir)} if got := a.GlobalConfigDir(home); got != desktopDir { diff --git a/internal/cli/run_engram_download_test.go b/internal/cli/run_engram_download_test.go index a38603586..04b773ee0 100644 --- a/internal/cli/run_engram_download_test.go +++ b/internal/cli/run_engram_download_test.go @@ -3,6 +3,7 @@ package cli import ( "os" "path/filepath" + "runtime" "strings" "testing" @@ -214,6 +215,9 @@ func TestRunInstallBetaEngramUsesMainGoInstallAndInstalledBinary(t *testing.T) { home := t.TempDir() gobin := filepath.Join(home, "go-bin") betaEngram := filepath.Join(gobin, "engram") + if runtime.GOOS == "windows" { + betaEngram += ".exe" + } restoreCommand := runCommand restoreLookPath := cmdLookPath diff --git a/internal/cli/sync.go b/internal/cli/sync.go index dc213799e..6f4ed582f 100644 --- a/internal/cli/sync.go +++ b/internal/cli/sync.go @@ -1060,7 +1060,11 @@ func RenderSyncReport(result SyncResult) string { if len(result.ChangedFiles) > 0 { for _, path := range result.ChangedFiles { - fmt.Fprintf(&b, " - %s\n", path) + suffix := "" + if strings.HasSuffix(path, filepath.Join(".gemini", "config", "mcp_config.json")) { + suffix = " (shared global configuration)" + } + fmt.Fprintf(&b, " - %s%s\n", path, suffix) } } diff --git a/internal/components/engram/inject.go b/internal/components/engram/inject.go index 46b11e82f..1056462cd 100644 --- a/internal/components/engram/inject.go +++ b/internal/components/engram/inject.go @@ -131,11 +131,6 @@ func engramOverlayJSON(agentID model.AgentID, cmd string) []byte { } } else { args := []string{"mcp", "--tools=agent"} - if agentID == model.AgentAntigravity { - // Antigravity should launch the default Engram MCP server without - // narrowing the exposed tool set. - args = []string{"mcp"} - } cfg = map[string]any{ "mcpServers": map[string]any{ "engram": map[string]any{ @@ -250,8 +245,8 @@ func ensureJSONFileIfMissing(path string) (filemerge.WriteResult, error) { return filemerge.WriteFileAtomic(path, []byte("{}\n"), 0o644) } -func installAntigravityEngramPlugin(homeDir, engramCommand string) (bool, []string, error) { - pluginDir := filepath.Join(homeDir, ".gemini", "antigravity-cli", "plugins", "gentle-ai-engram") +func installAntigravityEngramPlugin(variantDir, engramCommand string) (bool, []string, error) { + pluginDir := filepath.Join(variantDir, "plugins", "gentle-ai-engram") files := make([]string, 0, 3) changed := false @@ -360,7 +355,7 @@ func injectWithOptions(configHomeDir, promptDir string, adapter agents.Adapter, changed = changed || settingsWrite.Changed files = append(files, adapter.SettingsPath(configHomeDir)) - pluginChanged, pluginFiles, pluginErr := installAntigravityEngramPlugin(configHomeDir, engramCommand) + pluginChanged, pluginFiles, pluginErr := installAntigravityEngramPlugin(adapter.GlobalConfigDir(configHomeDir), engramCommand) if pluginErr != nil { return InjectionResult{}, pluginErr } diff --git a/internal/components/engram/inject_test.go b/internal/components/engram/inject_test.go index 488064f5e..1d2e75c43 100644 --- a/internal/components/engram/inject_test.go +++ b/internal/components/engram/inject_test.go @@ -557,9 +557,10 @@ func TestInjectGeminiToolsFlagPresent(t *testing.T) { } } -func TestInjectAntigravityWritesMCPToCLIConfig(t *testing.T) { +func TestInjectAntigravityWritesMCPToGlobalConfig(t *testing.T) { home := t.TempDir() + result, err := Inject(home, antigravityAdapter()) if err != nil { t.Fatalf("Inject(antigravity) error = %v", err) @@ -568,17 +569,22 @@ func TestInjectAntigravityWritesMCPToCLIConfig(t *testing.T) { t.Fatalf("Inject(antigravity) changed = false") } - cliMCPPath := filepath.Join(home, ".gemini", "antigravity-cli", "mcp_config.json") - content, err := os.ReadFile(cliMCPPath) + globalMCPPath := antigravity.GlobalMCPConfigPath(home) + content, err := os.ReadFile(globalMCPPath) if err != nil { - t.Fatalf("ReadFile(%q) error = %v", cliMCPPath, err) + t.Fatalf("ReadFile(%q) error = %v", globalMCPPath, err) + } + + oldCLIPath := filepath.Join(home, ".gemini", "antigravity-cli", "mcp_config.json") + if _, err := os.Stat(oldCLIPath); !os.IsNotExist(err) { + t.Fatalf("legacy CLI MCP path %q should not be written for antigravity; stat err = %v", oldCLIPath, err) } text := string(content) if !strings.Contains(text, `"args": [`) || !strings.Contains(text, `"mcp"`) { t.Fatalf("Antigravity MCP config must launch Engram MCP; got:\n%s", text) } - if strings.Contains(text, `--tools=`) { - t.Fatalf("Antigravity should use Engram's default MCP invocation without tool-profile flags; got:\n%s", text) + if !strings.Contains(text, `"--tools=agent"`) { + t.Fatalf("Antigravity should use Engram's MCP invocation with --tools=agent; got:\n%s", text) } pluginPath := filepath.Join(home, ".gemini", "antigravity-cli", "plugins", "gentle-ai-engram", "plugin.json") @@ -592,8 +598,8 @@ func TestInjectAntigravityWritesMCPToCLIConfig(t *testing.T) { t.Fatalf("ReadFile(%q) error = %v", pluginMCPPath, err) } pluginMCPText := string(pluginMCPContent) - if !strings.Contains(pluginMCPText, `"mcp"`) || strings.Contains(pluginMCPText, `--tools=`) { - t.Fatalf("Antigravity Engram plugin MCP config should expose default Engram MCP tools; got:\n%s", pluginMCPText) + if !strings.Contains(pluginMCPText, `"mcp"`) || !strings.Contains(pluginMCPText, `"--tools=agent"`) { + t.Fatalf("Antigravity Engram plugin MCP config should expose Engram MCP tools via --tools=agent; got:\n%s", pluginMCPText) } hooksPath := filepath.Join(home, ".gemini", "antigravity-cli", "plugins", "gentle-ai-engram", "hooks.json") @@ -626,9 +632,46 @@ func TestInjectAntigravityWritesMCPToCLIConfig(t *testing.T) { } } +func TestInjectAntigravityIDEVariantReceivesPlugin(t *testing.T) { + home := t.TempDir() + + // Create the IDE path on disk so the adapter's real os.Stat resolves to the IDE variant. + ideDir := filepath.Join(home, ".gemini", "antigravity-ide") + if err := os.MkdirAll(ideDir, 0o755); err != nil { + t.Fatalf("MkdirAll(%q) error = %v", ideDir, err) + } + + result, err := Inject(home, antigravity.NewAdapter()) + if err != nil { + t.Fatalf("Inject(antigravity-IDE) error = %v", err) + } + if !result.Changed { + t.Fatalf("Inject(antigravity-IDE) changed = false") + } + + // Plugin files must land inside the IDE variant directory. + for _, rel := range []string{ + filepath.Join("plugins", "gentle-ai-engram", "plugin.json"), + filepath.Join("plugins", "gentle-ai-engram", "mcp_config.json"), + filepath.Join("plugins", "gentle-ai-engram", "hooks.json"), + } { + p := filepath.Join(ideDir, rel) + if _, err := os.Stat(p); err != nil { + t.Fatalf("expected plugin file at IDE variant path %q; stat error = %v", p, err) + } + } + + // Legacy CLI directory must NOT be created. + legacyCLI := filepath.Join(home, ".gemini", "antigravity-cli") + if _, err := os.Stat(legacyCLI); !os.IsNotExist(err) { + t.Fatalf("legacy CLI directory %q should not exist when IDE variant is active; stat err = %v", legacyCLI, err) + } +} + func TestInjectAntigravityInitializesEmptySettingsWhenGeminiMissing(t *testing.T) { home := t.TempDir() + first, err := Inject(home, antigravityAdapter()) if err != nil { t.Fatalf("Inject(antigravity) first error = %v", err) diff --git a/internal/components/golden_test.go b/internal/components/golden_test.go index 2589cd7da..edca74d2d 100644 --- a/internal/components/golden_test.go +++ b/internal/components/golden_test.go @@ -886,6 +886,8 @@ func TestGoldenPersona_Antigravity_Gentleman(t *testing.T) { func TestGoldenEngram_Antigravity(t *testing.T) { home := t.TempDir() + + engram.SetLookPathForTest(t, "/opt/homebrew/bin/engram", "") result, err := engram.Inject(home, antigravityAdapter()) @@ -896,8 +898,8 @@ func TestGoldenEngram_Antigravity(t *testing.T) { t.Fatalf("engram.Inject(antigravity) changed = false") } - // MCP config written to ~/.gemini/antigravity-cli/mcp_config.json. - mcpJSON := readTestFile(t, filepath.Join(home, ".gemini", "antigravity-cli", "mcp_config.json")) + // MCP config written to ~/.gemini/config/mcp_config.json. + mcpJSON := readTestFile(t, antigravity.GlobalMCPConfigPath(home)) assertGolden(t, "engram-antigravity-mcp.golden", mcpJSON) // GEMINI.md must contain the engram-protocol section. diff --git a/internal/system/config_scan.go b/internal/system/config_scan.go index 11b5627bf..c62e07c8c 100644 --- a/internal/system/config_scan.go +++ b/internal/system/config_scan.go @@ -36,7 +36,7 @@ func knownAgentConfigDirs(homeDir string) []ConfigState { {Agent: "cursor", Path: filepath.Join(homeDir, ".cursor")}, {Agent: "vscode-copilot", Path: vscodeCopilotGlobalConfigDir(homeDir)}, {Agent: "codex", Path: filepath.Join(homeDir, ".codex")}, - {Agent: "antigravity", Path: filepath.Join(homeDir, ".gemini", "antigravity-cli")}, + {Agent: "antigravity", Path: antigravityConfigDir(homeDir)}, {Agent: "windsurf", Path: filepath.Join(homeDir, ".codeium", "windsurf")}, {Agent: "kimi", Path: filepath.Join(homeDir, ".kimi")}, {Agent: "qwen-code", Path: filepath.Join(homeDir, ".qwen")}, @@ -48,6 +48,26 @@ func knownAgentConfigDirs(homeDir string) []ConfigState { } } +// antigravityConfigDir mirrors antigravity.Adapter.antigravityVariantDir +// without importing the agents package (import cycle). Returns the first +// existing variant directory: IDE → Desktop → CLI fallback. +// +// TODO(follow-up): remove this shim once the system ← agents import cycle is +// resolved and ScanConfigs delegates directly to agents.DiscoverInstalled. +func antigravityConfigDir(homeDir string) string { + ideDir := filepath.Join(homeDir, ".gemini", "antigravity-ide") + if info, err := os.Stat(ideDir); err == nil && info.IsDir() { + return ideDir + } + + desktop := filepath.Join(homeDir, ".gemini", "antigravity") + if info, err := os.Stat(desktop); err == nil && info.IsDir() { + return desktop + } + + return filepath.Join(homeDir, ".gemini", "antigravity-cli") +} + // vscodeCopilotGlobalConfigDir returns ~/.copilot, the GlobalConfigDir used by // the vscode-copilot adapter across all platforms. The vscode adapter's // SystemPromptDir and SettingsPath are OS-dependent, but GlobalConfigDir is not. diff --git a/openspec/changes/antigravity-2.0-compatibility/design.md b/openspec/changes/antigravity-2.0-compatibility/design.md index e7266a69f..d21863bf8 100644 --- a/openspec/changes/antigravity-2.0-compatibility/design.md +++ b/openspec/changes/antigravity-2.0-compatibility/design.md @@ -9,12 +9,12 @@ Use the existing public `antigravity` agent ID for the new Antigravity implement | Purpose | Path | |---------|------| | Agent ID | `antigravity` | -| Config root | `~/.gemini/antigravity-cli/` | -| Settings | `~/.gemini/antigravity-cli/settings.json` | -| MCP config | `~/.gemini/antigravity-cli/mcp_config.json` | -| Skills | `~/.gemini/antigravity-cli/skills/` | +| Config root | `` (IDE → Desktop → CLI fallback) | +| Settings | `/settings.json` | +| MCP config | `~/.gemini/config/mcp_config.json` | +| Skills | `/skills/` | | Shared prompt/persona | `~/.gemini/GEMINI.md` | -| Engram plugin | `~/.gemini/antigravity-cli/plugins/gentle-ai-engram/` | +| Engram plugin | `/plugins/gentle-ai-engram/` | ## Runtime model @@ -26,7 +26,7 @@ The Go adapter does not install static subagent files. Instead, the SDD orchestr - `internal/assets/antigravity/sdd-orchestrator.md` owns the dynamic subagent prompt. - `internal/model/types.go` keeps only `AgentAntigravity` for this surface. - CLI and TUI validation accept `antigravity`; they do not expose `antigravity-cli`. -- Engram MCP uses the default `engram mcp` invocation and adds an Antigravity plugin hook for tool-hint injection. +- Engram MCP uses `engram mcp --tools=agent` (standard across all agents) and adds an Antigravity plugin hook for tool-hint injection. ## Compatibility diff --git a/openspec/changes/antigravity-2.0-compatibility/exploration.md b/openspec/changes/antigravity-2.0-compatibility/exploration.md index 073335519..6bd8d78e8 100644 --- a/openspec/changes/antigravity-2.0-compatibility/exploration.md +++ b/openspec/changes/antigravity-2.0-compatibility/exploration.md @@ -6,10 +6,10 @@ The new Antigravity implementation is compatible with the desktop product, not o ## Relevant surfaces -- CLI/Desktop config root: `~/.gemini/antigravity-cli/` +- Resolved config root: `` (IDE → Desktop → CLI fallback) - Shared prompt file: `~/.gemini/GEMINI.md` -- Skills root: `~/.gemini/antigravity-cli/skills/` -- MCP config: `~/.gemini/antigravity-cli/mcp_config.json` +- Skills root: `/skills/` +- MCP config: `~/.gemini/config/mcp_config.json` - Dynamic subagent tools: `define_subagent`, `invoke_subagent` ## Recommendation diff --git a/openspec/changes/antigravity-2.0-compatibility/tasks.md b/openspec/changes/antigravity-2.0-compatibility/tasks.md index 2b24a30b9..785303261 100644 --- a/openspec/changes/antigravity-2.0-compatibility/tasks.md +++ b/openspec/changes/antigravity-2.0-compatibility/tasks.md @@ -15,9 +15,9 @@ ## 3. Engram and SDD behavior -- [x] Write Antigravity MCP config to `~/.gemini/antigravity-cli/mcp_config.json`. -- [x] Install Antigravity Engram plugin hooks under `~/.gemini/antigravity-cli/plugins/gentle-ai-engram/`. -- [x] Use default `engram mcp` invocation without Antigravity-specific Pi assumptions. +- [x] Write Antigravity MCP config to `~/.gemini/config/mcp_config.json`. +- [x] Install Antigravity Engram plugin hooks under `/plugins/gentle-ai-engram/` (IDE → Desktop → CLI fallback). +- [x] Use `engram mcp --tools=agent` invocation (standard across all agents). - [x] Ensure Antigravity SDD instructions use dynamic subagents. ## 4. Verification diff --git a/openspec/specs/antigravity-support/spec.md b/openspec/specs/antigravity-support/spec.md index 6e992becc..269d69ee1 100644 --- a/openspec/specs/antigravity-support/spec.md +++ b/openspec/specs/antigravity-support/spec.md @@ -17,15 +17,17 @@ The system MUST expose Antigravity as `antigravity` and MUST NOT expose a separa ### Requirement: Antigravity writes to the supported config surface -The system MUST write Antigravity settings, MCP config, plugins, and skills under `~/.gemini/antigravity-cli/`. +The system MUST write Antigravity settings, plugins, and skills under the resolved variant directory (IDE → Desktop → CLI fallback) and MCP config to the shared global location. #### Scenario: Antigravity files are installed - GIVEN the installer runs for `antigravity` - WHEN SDD, Engram, or permission components are applied -- THEN settings are initialized at `~/.gemini/antigravity-cli/settings.json` -- AND MCP config is merged at `~/.gemini/antigravity-cli/mcp_config.json` -- AND skills are installed under `~/.gemini/antigravity-cli/skills/`. +- THEN settings are initialized at `/settings.json` +- AND MCP config is merged at `~/.gemini/config/mcp_config.json` +- AND skills are installed under `/skills/` +- AND Engram plugin is installed under `/plugins/gentle-ai-engram/` +- WHERE `` is the first existing directory among the OS-specific IDE path, `~/.gemini/antigravity-desktop/`, or `~/.gemini/antigravity-cli/` (fallback). ### Requirement: Antigravity uses dynamic subagents diff --git a/testdata/golden/engram-antigravity-mcp.golden b/testdata/golden/engram-antigravity-mcp.golden index 306b24ca2..4f1c5bdc2 100644 --- a/testdata/golden/engram-antigravity-mcp.golden +++ b/testdata/golden/engram-antigravity-mcp.golden @@ -2,7 +2,8 @@ "mcpServers": { "engram": { "args": [ - "mcp" + "mcp", + "--tools=agent" ], "command": "/opt/homebrew/bin/engram" } diff --git a/testdata/golden/skills-claude-skill-creator.golden b/testdata/golden/skills-claude-skill-creator.golden index 182ec091b..3bf998f60 100644 --- a/testdata/golden/skills-claude-skill-creator.golden +++ b/testdata/golden/skills-claude-skill-creator.golden @@ -20,7 +20,8 @@ Do not create a skill when the pattern is trivial, one-off, or better served by ## Hard Rules - When working in this repo, first follow `docs/skill-style-guide.md` as the normative source before creating or updating skills. -- If that guide is unavailable, use the compact inline rules below. +- For installed global skills, use `references/skill-style-guide.md` as the bundled local copy of that guide when `docs/skill-style-guide.md` is unavailable. +- If neither guide is available, use the compact inline rules below. - A skill is a runtime instruction contract for an LLM, not human documentation. - Do not add a `Keywords` section; preserve essential trigger words in `description`. - References must point to local files. @@ -37,9 +38,10 @@ Do not create a skill when the pattern is trivial, one-off, or better served by ## Execution Steps -1. Check whether `docs/skill-style-guide.md` exists; if it does, apply it before the inline fallback rules. -2. Confirm the skill does not already exist and the pattern is reusable. -3. Create or update `skills/{skill-name}/SKILL.md` using this required structure: +1. Check whether `docs/skill-style-guide.md` exists; if it does, apply it before the bundled local copy or inline fallback rules. +2. If the repo guide is unavailable, read `references/skill-style-guide.md` and apply it before the inline fallback rules. +3. Confirm the skill does not already exist and the pattern is reusable. +4. Create or update `skills/{skill-name}/SKILL.md` using this required structure: ``` skills/{skill-name}/ @@ -50,7 +52,7 @@ skills/{skill-name}/ └── references/ # Optional - links to local docs └── docs.md # Points to docs/developer-guide/*.mdx ``` -4. Use this frontmatter shape: +5. Use this frontmatter shape: ```markdown --- @@ -62,8 +64,8 @@ metadata: version: "1.0" --- ``` -5. Write sections in this order: Activation Contract, Hard Rules, Decision Gates, Execution Steps, Output Contract, References. -6. Register the skill in `AGENTS.md` when it is a project skill. +6. Write sections in this order: Activation Contract, Hard Rules, Decision Gates, Execution Steps, Output Contract, References. +7. Register the skill in `AGENTS.md` when it is a project skill. ## Inline Fallback Rules @@ -99,3 +101,4 @@ Return: ## References - `docs/skill-style-guide.md` — normative LLM-first skill style guide for this repo. +- `references/skill-style-guide.md` — bundled local copy for installed global skills when the repo doc is unavailable. diff --git a/testdata/golden/skills-kiro-skill-creator.golden b/testdata/golden/skills-kiro-skill-creator.golden index 182ec091b..3bf998f60 100644 --- a/testdata/golden/skills-kiro-skill-creator.golden +++ b/testdata/golden/skills-kiro-skill-creator.golden @@ -20,7 +20,8 @@ Do not create a skill when the pattern is trivial, one-off, or better served by ## Hard Rules - When working in this repo, first follow `docs/skill-style-guide.md` as the normative source before creating or updating skills. -- If that guide is unavailable, use the compact inline rules below. +- For installed global skills, use `references/skill-style-guide.md` as the bundled local copy of that guide when `docs/skill-style-guide.md` is unavailable. +- If neither guide is available, use the compact inline rules below. - A skill is a runtime instruction contract for an LLM, not human documentation. - Do not add a `Keywords` section; preserve essential trigger words in `description`. - References must point to local files. @@ -37,9 +38,10 @@ Do not create a skill when the pattern is trivial, one-off, or better served by ## Execution Steps -1. Check whether `docs/skill-style-guide.md` exists; if it does, apply it before the inline fallback rules. -2. Confirm the skill does not already exist and the pattern is reusable. -3. Create or update `skills/{skill-name}/SKILL.md` using this required structure: +1. Check whether `docs/skill-style-guide.md` exists; if it does, apply it before the bundled local copy or inline fallback rules. +2. If the repo guide is unavailable, read `references/skill-style-guide.md` and apply it before the inline fallback rules. +3. Confirm the skill does not already exist and the pattern is reusable. +4. Create or update `skills/{skill-name}/SKILL.md` using this required structure: ``` skills/{skill-name}/ @@ -50,7 +52,7 @@ skills/{skill-name}/ └── references/ # Optional - links to local docs └── docs.md # Points to docs/developer-guide/*.mdx ``` -4. Use this frontmatter shape: +5. Use this frontmatter shape: ```markdown --- @@ -62,8 +64,8 @@ metadata: version: "1.0" --- ``` -5. Write sections in this order: Activation Contract, Hard Rules, Decision Gates, Execution Steps, Output Contract, References. -6. Register the skill in `AGENTS.md` when it is a project skill. +6. Write sections in this order: Activation Contract, Hard Rules, Decision Gates, Execution Steps, Output Contract, References. +7. Register the skill in `AGENTS.md` when it is a project skill. ## Inline Fallback Rules @@ -99,3 +101,4 @@ Return: ## References - `docs/skill-style-guide.md` — normative LLM-first skill style guide for this repo. +- `references/skill-style-guide.md` — bundled local copy for installed global skills when the repo doc is unavailable. diff --git a/testdata/golden/skills-opencode-skill-creator.golden b/testdata/golden/skills-opencode-skill-creator.golden index 182ec091b..3bf998f60 100644 --- a/testdata/golden/skills-opencode-skill-creator.golden +++ b/testdata/golden/skills-opencode-skill-creator.golden @@ -20,7 +20,8 @@ Do not create a skill when the pattern is trivial, one-off, or better served by ## Hard Rules - When working in this repo, first follow `docs/skill-style-guide.md` as the normative source before creating or updating skills. -- If that guide is unavailable, use the compact inline rules below. +- For installed global skills, use `references/skill-style-guide.md` as the bundled local copy of that guide when `docs/skill-style-guide.md` is unavailable. +- If neither guide is available, use the compact inline rules below. - A skill is a runtime instruction contract for an LLM, not human documentation. - Do not add a `Keywords` section; preserve essential trigger words in `description`. - References must point to local files. @@ -37,9 +38,10 @@ Do not create a skill when the pattern is trivial, one-off, or better served by ## Execution Steps -1. Check whether `docs/skill-style-guide.md` exists; if it does, apply it before the inline fallback rules. -2. Confirm the skill does not already exist and the pattern is reusable. -3. Create or update `skills/{skill-name}/SKILL.md` using this required structure: +1. Check whether `docs/skill-style-guide.md` exists; if it does, apply it before the bundled local copy or inline fallback rules. +2. If the repo guide is unavailable, read `references/skill-style-guide.md` and apply it before the inline fallback rules. +3. Confirm the skill does not already exist and the pattern is reusable. +4. Create or update `skills/{skill-name}/SKILL.md` using this required structure: ``` skills/{skill-name}/ @@ -50,7 +52,7 @@ skills/{skill-name}/ └── references/ # Optional - links to local docs └── docs.md # Points to docs/developer-guide/*.mdx ``` -4. Use this frontmatter shape: +5. Use this frontmatter shape: ```markdown --- @@ -62,8 +64,8 @@ metadata: version: "1.0" --- ``` -5. Write sections in this order: Activation Contract, Hard Rules, Decision Gates, Execution Steps, Output Contract, References. -6. Register the skill in `AGENTS.md` when it is a project skill. +6. Write sections in this order: Activation Contract, Hard Rules, Decision Gates, Execution Steps, Output Contract, References. +7. Register the skill in `AGENTS.md` when it is a project skill. ## Inline Fallback Rules @@ -99,3 +101,4 @@ Return: ## References - `docs/skill-style-guide.md` — normative LLM-first skill style guide for this repo. +- `references/skill-style-guide.md` — bundled local copy for installed global skills when the repo doc is unavailable. diff --git a/testdata/golden/skills-windsurf-skill-creator.golden b/testdata/golden/skills-windsurf-skill-creator.golden index 182ec091b..3bf998f60 100644 --- a/testdata/golden/skills-windsurf-skill-creator.golden +++ b/testdata/golden/skills-windsurf-skill-creator.golden @@ -20,7 +20,8 @@ Do not create a skill when the pattern is trivial, one-off, or better served by ## Hard Rules - When working in this repo, first follow `docs/skill-style-guide.md` as the normative source before creating or updating skills. -- If that guide is unavailable, use the compact inline rules below. +- For installed global skills, use `references/skill-style-guide.md` as the bundled local copy of that guide when `docs/skill-style-guide.md` is unavailable. +- If neither guide is available, use the compact inline rules below. - A skill is a runtime instruction contract for an LLM, not human documentation. - Do not add a `Keywords` section; preserve essential trigger words in `description`. - References must point to local files. @@ -37,9 +38,10 @@ Do not create a skill when the pattern is trivial, one-off, or better served by ## Execution Steps -1. Check whether `docs/skill-style-guide.md` exists; if it does, apply it before the inline fallback rules. -2. Confirm the skill does not already exist and the pattern is reusable. -3. Create or update `skills/{skill-name}/SKILL.md` using this required structure: +1. Check whether `docs/skill-style-guide.md` exists; if it does, apply it before the bundled local copy or inline fallback rules. +2. If the repo guide is unavailable, read `references/skill-style-guide.md` and apply it before the inline fallback rules. +3. Confirm the skill does not already exist and the pattern is reusable. +4. Create or update `skills/{skill-name}/SKILL.md` using this required structure: ``` skills/{skill-name}/ @@ -50,7 +52,7 @@ skills/{skill-name}/ └── references/ # Optional - links to local docs └── docs.md # Points to docs/developer-guide/*.mdx ``` -4. Use this frontmatter shape: +5. Use this frontmatter shape: ```markdown --- @@ -62,8 +64,8 @@ metadata: version: "1.0" --- ``` -5. Write sections in this order: Activation Contract, Hard Rules, Decision Gates, Execution Steps, Output Contract, References. -6. Register the skill in `AGENTS.md` when it is a project skill. +6. Write sections in this order: Activation Contract, Hard Rules, Decision Gates, Execution Steps, Output Contract, References. +7. Register the skill in `AGENTS.md` when it is a project skill. ## Inline Fallback Rules @@ -99,3 +101,4 @@ Return: ## References - `docs/skill-style-guide.md` — normative LLM-first skill style guide for this repo. +- `references/skill-style-guide.md` — bundled local copy for installed global skills when the repo doc is unavailable.