Gemini CLI (gemini)
Set up this tool
agnostic-ai writes GEMINI.md, native subagents, commands, and skills under .gemini/, and merges MCP, hooks, and settings into .gemini/settings.json.
Gemini CLI's own docs say Antigravity CLI replaced it for unpaid-tier and Google One users on June 18, 2026. Gemini CLI still ships and this target is unchanged. To write for Antigravity, add the antigravity target.
First rule
Install the client using the official setup guide, then open your project in it.
Select gemini in agnostic-ai.yaml, then follow First rule to add the shared commit-prefix rule and sync it. With the default paths, it reaches GEMINI.md.
Directory-specific rules use nested GEMINI.md files. See scoped context before sharing file-pattern rules.
For existing files, check what import gemini reads before syncing.
Verify
Run agnostic-ai sync --check and inspect GEMINI.md for the commit-prefix rule. Start Gemini CLI from the project root and ask for a commit subject for a small fix; it should use fix:.
Next, add a skill.
Output
GEMINI.md # entry-point pointer body (written by sync)
.gemini/agents/<name>.md # one subagent per agent
.gemini/commands/<name>.toml # one per command
.gemini/skills/<name>/SKILL.md # one folder per skill, bundled assets included
.gemini/commands/skill-<name>.toml # extra command form, only when emit-skills-as-commands: true
.gemini/settings.json # when MCP, hook, or settings entries exist (merged with user config)
.geminiignore # when ignore entries exist
Native mappings
Field mappings, discovery, and compatibility
Rules
Rules without a directory scope go into the root GEMINI.md. scope: services/payments sends a rule to services/payments/GEMINI.md instead, and globs: tests/payments/** adds it to tests/payments/GEMINI.md. globs alone creates no directory scope. Directory documents cannot hold external file filters or root selectors with a scope, so those follow on-unsupported. Scoped rules need any legacy outputs.gemini.rules-file override removed. See scoped context for selector and runtime limits.
Agents
Native subagents in the project directory Gemini CLI scans. They get automatic delegation, their own context window, @name invocation, and a /agents listing. Frontmatter carries the required name and description (default: spec name), plus kind, model, temperature, max_turns, and timeout_mins when set. The portable maxTurns is written as max_turns, and a max_turns the spec sets wins. The body is the system prompt.
- Per-agent MCP servers have no agnostic-ai field. Set
x-gemini.mcp_servers, with snake_case keys such ashttp_urlandinclude_tools. Gemini rejects the documentedmcpServerskey and skips the agent, so sync renamesx-gemini.mcpServerstomcp_serverswith a note. - A generic
toolslist maps to Gemini's tool names:Read:read_file,Write:write_file,Edit:replace,Glob:glob,Grep:grep_search,Bash:run_shell_command,WebFetch:web_fetch,WebSearch:google_web_search. Other names drop with a sync note, because an unknown entry would limit the subagent to a tool that does not exist. Omittoolsto inherit all tools. x-gemini.toolsreplaces the translated list with Gemini's own names, including the wildcards*,mcp_*, andmcp_<server>_*.outputs.gemini.emit-agents-as-commands: truealso writes each agent as a<name>.tomlslash command, so you can type/name. With it off, sync removes earlier generated TOML files.
Skills
Native Agent Skills at .gemini/skills/<name>/SKILL.md, with bundled files copied as they are. Gemini CLI also reads .agents/skills/, which wins when a name appears in both. outputs.gemini.emit-skills-as-commands: true adds one skill-<name>.toml command per skill.
Commands
.gemini/commands/<name>.toml, the project slash-command directory. description becomes the TOML description and the body becomes prompt. A command and an agent can share a name. A command named git:commit is written as .gemini/commands/git/commit.toml, which Gemini runs as /git:commit. An agent keeps its name as one file, .gemini/agents/<name>.md, so on Windows sync refuses an agent named with a colon; see path semantics.
Settings
The portable model maps to model.name. Other model options and settings stay. x-gemini keys merge in. Portable permission rules raise a sync note.
At user scope, portable voice settings write the experimental experimental.voiceMode and experimental.voice.activationMode keys; Gemini has no dictation language key.
MCP
The mcpServers map. Streamable-HTTP servers (type: http) use httpUrl. SSE servers (type: sse) use url. Stdio servers also accept cwd. timeout (milliseconds), trust (skip tool-call confirmations), description, includeTools, and excludeTools are copied as written (configuration reference). Import reads httpUrl back as type: http and a bare url as type: sse.
Native OAuth options pass through x-gemini.oauth, including enabled, allowPrivateNetwork, and authorizationResponseIssParameterSupported. Import keeps this object Gemini-specific and leaves out servers with literal OAuth credentials; existing credential references remain references.
Hooks
The hooks map, keyed by event. Gemini documents 11 events: BeforeTool, AfterTool, BeforeAgent, AfterAgent, Notification, SessionStart, SessionEnd, PreCompress, BeforeModel, AfterModel, BeforeToolSelection. Each hook has a matcher and a nested hooks array of {type: "command", command} handlers (hook reference). With builtins: [memory], a SessionStart hook adds the shared memory index to the session.
- Timeouts convert from seconds to milliseconds (vendor default 60000 ms).
- A
commandlist becomes separate handlers in one hook.x-gemini.sequential: trueruns them in order. descriptionis copied to each handler,x-gemini.namesets its display name, andx-gemini.envsets its environment variables. Your existing keys stay.- Gemini runs
commandthroughbash -c(PowerShell on Windows) and has noargsfield. Sync foldsargsintocommand, each single-quoted (node 'guard.js').import geminireads it back as one shell-formcommand. agnostic-ai hook runtests aBeforeTool,AfterTool,BeforeAgent, orSessionStarthook before a session using the same behavior.
Ignore
Ignore specs are joined into .geminiignore (gitignore syntax), the file Gemini CLI reads. Override with outputs.gemini.ignore-file.
Folded args edge cases
PowerShell reads folded args the same way unless one holds an apostrophe. A quoted command path with a space runs in bash but not PowerShell, so use a shell-form command there. Gemini replaces $GEMINI_* path variables and $CLAUDE_PROJECT_DIR with its own quoted path, even inside those quotes. Such an argument splits when the project path has a space.
Old .aiexclude files
Older versions wrote .aiexclude, which Gemini CLI never reads. Sync removes a generated one.
Shared memory
Gemini CLI saves facts by editing its memory files itself, and has no setting to turn that off. On its own, it saves team facts to GEMINI.md, which sync writes over. With builtins: [memory], sync adds the gemini-memory-tiers rule to GEMINI.md. Gemini CLI keeps its own memory, with one change for the file sync owns:
| Gemini CLI tier | Saves to |
|---|---|
| Project instructions: team conventions, architecture rules, workflows | .agnostic-ai/memory/, after you confirm, instead of GEMINI.md |
| Private project memory: your machine and local setup | its own private memory (~/.gemini/tmp/<project>/memory/), plus a copy in your personal memory folder |
| Global personal memory: preferences for every project | ~/.gemini/GEMINI.md, outside the block sync --global writes, plus a copy in your personal memory folder |
The copies are how other tools read what Gemini CLI learns. If it edits GEMINI.md anyway, the next sync keeps the edit in GEMINI.md.bak and suggests saving it as a fact in .agnostic-ai/memory/.
When Gemini CLI's instructions file is one another target also reads, such as AGENTS.md, sync leaves the rule out of that file and prints a note. sync --global leaves it out too, because the global block reaches every tool. See shared memory.
Config keys
| Key | Default | Notes |
|---|---|---|
outputs.gemini.agents-dir | .gemini/agents | |
outputs.gemini.commands-dir | .gemini/commands | |
outputs.gemini.skills-dir | .gemini/skills | |
outputs.gemini.mcp-file | .gemini/settings.json | also holds hooks and settings |
outputs.gemini.emit-skills-as-commands | false | |
outputs.gemini.emit-agents-as-commands | false | |
outputs.gemini.rules-file | unset | writes legacy joined rules and skips the write of instructions that point to source specs |
outputs.gemini.ignore-file | .geminiignore |
Import
import gemini reads .gemini/agents/*.md, .gemini/commands/**/*.toml, .gemini/skills/<name>/, and the MCP, hooks, and default model in .gemini/settings.json.
- Instructions: the root
GEMINI.mdgoes to.agnostic-ai/AGNOSTIC_AI.md. Only the rules block thatsyncappends becomes rules. - Nested files: a hand-written
<dir>/GEMINI.mdbecomes one rule with the whole file andscope: <dir>, named after the scope:api.mdforservices/api/, orservices-api.mdwhen another scope also ends inapi. A directory with one rule syncs back unchanged. A nested file thatsyncwrote splits back into its rules. - Commands:
promptbecomes the body in either documented form (triple-quoted block or single-line string).descriptionstays in frontmatter. A file in a subfolder, such asgit/commit.toml, imports as the commandgit:commit. This also covers older agent-as-command files and theemit-agents-as-commandsandemit-skills-as-commandscopies, which sync back unchanged. - Hooks: nested hooks keep commands, matchers, names, descriptions, environment maps, timeouts, and sequential groups. Hooks with the same command and matcher import separately. A single handler's whole-second timeout imports in seconds. Otherwise
x-gemini.timeoutkeeps the native milliseconds. Multiple handlers stay together underx-gemini.hooks, which replacescommandfor Gemini. Old flat hook files still import.
Protected paths
Enforced (hook). Gemini CLI's policy engine can deny write_file and replace, but its workspace tier "is currently non-functional" (policy engine). So sync writes .gemini/hooks/agnostic-ai-protect.sh and a BeforeTool hook on ^(write_file|replace)$ in .gemini/settings.json. For a protected tool_input.file_path, the script exits 2 with the reason on stderr. Gemini CLI then blocks the call and shows the reason (hooks reference). The script needs only sh and awk.
Gemini CLI lets an edit through on exit 1 or a timeout, so the script blocks when it cannot run: no decision: ask also blocks and tells the agent to ask. Gemini CLI runs project hooks only in a trusted folder and reads .gemini/settings.json from the directory you start in, so start at the project root. The hook does not catch shell commands that write files.Script failures and odd paths
awk, an unreadable project root, or an awk failure. It ignores case, reads \ as a path separator, and checks a path with a leading @ both ways, because Gemini CLI strips the @. replace searches the workspace for a relative path that is missing from the project root, so the hook blocks that call and asks for the full path. On Windows it needs sh on PATH (Git for Windows has one), or the edit goes through.
See Protected paths.