AI CLI Setup & Usage¶
Every DevOps image ships four agentic AI coding assistants. Each one can read your project, edit files and run commands, and each has an interactive mode for you and a non-interactive mode for scripts and CI. This page shows how to sign in to each one inside the container and how to call it from a script.
-
Claude Code ·
claude
Anthropic's coding agent. Sign in with a Claude subscription or an Anthropic API key.
-
OpenAI Codex CLI ·
codex
OpenAI's coding agent. Sign in with ChatGPT or an OpenAI API key.
-
GitHub Copilot CLI ·
copilot
GitHub's standalone agentic terminal assistant (not the old
gh copilotextension). Needs a Copilot subscription. -
Google Antigravity CLI ·
agy
Google's coding agent, and the successor to Gemini CLI. Sign in with a Google account, a Gemini API key or ADC.
Gemini CLI has been replaced by Antigravity CLI
On 19 May 2026 Google announced that Gemini CLI is being replaced by Antigravity CLI. From 18 June 2026 Gemini CLI stopped serving free and Google AI Pro/Ultra individual users, so the images now ship agy instead of gemini.
Antigravity CLI shares its agent harness with the Antigravity 2.0 desktop app. It still keeps its state under ~/.gemini and still reads GEMINI.md context files, but the commands and the API-key setup are different (see below). Full docs: antigravity.google/docs.
At a glance¶
| Claude Code | Codex CLI | Copilot CLI | Antigravity CLI | |
|---|---|---|---|---|
| Command | claude |
codex |
copilot |
agy |
| Installed from | Native installer | npm @openai/codex |
npm @github/copilot |
Google installer (/usr/local/bin/agy) |
| Interactive sign-in | claude, then /login |
codex login (add --device-auth when headless) |
copilot, then /login |
agy, then sign in with Google |
| CI / headless auth | ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN |
CODEX_API_KEY |
COPILOT_GITHUB_TOKEN (fine-grained PAT) |
GEMINI_API_KEY + settings.json, or ADC + AGY_ADC_AUTH=true |
| Non-interactive | claude -p "..." |
codex exec "..." |
copilot -p "..." --allow-all-tools |
agy -p "..." |
| Config to mount | ~/.claude (+ ~/.claude.json) |
~/.codex |
~/.copilot |
~/.gemini |
| You need | Claude plan or Anthropic API key | ChatGPT plan or OpenAI API key | GitHub Copilot subscription | Google account or Gemini API key |
Plans and prices change often, so check each vendor directly: Claude, OpenAI API, GitHub Copilot and Antigravity.
How sign-in works in a container¶
The CLIs keep their login in a config directory under /root. Mount that directory from your host and you sign in once, then every new container reuses the login. In CI, where nothing is mounted, you pass a token as an environment variable instead.
sequenceDiagram
participant H as Host config dir<br/>~/.claude, ~/.codex,<br/>~/.copilot, ~/.gemini
participant C as CLI in container
participant V as Vendor API
H->>C: mounted at /root/...
alt no saved login yet
C->>V: start sign-in
V-->>C: login URL
Note over C: open the URL on your host,<br/>paste the code back
C->>H: token saved to mounted dir
end
C->>V: prompt + token
V-->>C: response, edits, commands
Start a container with all four logins mounted (you only need the ones you use):
[ -s ~/.claude.json ] || echo '{}' > ~/.claude.json
mkdir -p ~/.claude ~/.codex ~/.copilot ~/.gemini
docker run -it --rm \
-v "$PWD":/srv -w /srv \
-v ~/.claude:/root/.claude \
-v ~/.claude.json:/root/.claude.json \
-v ~/.codex:/root/.codex \
-v ~/.copilot:/root/.copilot \
-v ~/.gemini:/root/.gemini \
ghcr.io/jinalshah/devops/images/all-devops:latest
Create the paths first
If a mounted path doesn't exist on the host, Docker creates it as a root-owned directory. That breaks ~/.claude.json, which must be a file, so the first two lines above come first. Seed the file with {} rather than leaving it empty: Claude Code reports an empty ~/.claude.json as corrupted.
Host logins don't always carry over
Some CLIs keep tokens in the operating system's keychain on macOS and Windows, so mounting the directory doesn't bring the host login with it. Just sign in once inside the container: with the directory mounted, that login is saved and reused. Containers have no browser, so each CLI prints a URL (or a device code) for you to open on your host.
Claude Code¶
docker run -it --rm \
-v "$PWD":/srv -w /srv \
-v ~/.claude:/root/.claude \
-v ~/.claude.json:/root/.claude.json \
ghcr.io/jinalshah/devops/images/all-devops:latest \
claude
Type /login and pick your Claude subscription or Claude Console account. claude auth status shows who you're signed in as, and claude doctor checks the install.
Use an API key from the Claude Console, or create a long-lived subscription token with claude setup-token (needs a Claude subscription):
docker run --rm \
-v "$PWD":/srv -w /srv \
-e ANTHROPIC_API_KEY \
ghcr.io/jinalshah/devops/images/all-devops:latest \
claude -p "Summarise what this repository deploys"
Swap -e ANTHROPIC_API_KEY for -e CLAUDE_CODE_OAUTH_TOKEN to use the subscription token.
Non-interactive use: always pass -p (--print). Without it, claude opens the interactive UI even when you redirect the output. There are no --file or --stdin flags: pipe content in, or name files in the prompt and Claude reads them from the working directory.
# Review your uncommitted changes
git diff | claude -p "Review this diff for security issues and risky changes"
# Explain a failure
terraform plan 2>&1 | claude -p "Why did this plan fail, and how do I fix it?"
# Let Claude read files itself
claude -p "Explain what ansible/deploy.yml does, step by step" > deploy-explained.md
# Machine-readable output
claude -p "List the AWS resources in main.tf" --output-format json
Other handy flags: --model, -c/--continue (carry on from the last conversation) and --permission-mode acceptEdits (let a -p run edit files).
OpenAI Codex CLI¶
docker run -it --rm \
-v "$PWD":/srv -w /srv \
-v ~/.codex:/root/.codex \
ghcr.io/jinalshah/devops/images/all-devops:latest \
codex login --device-auth
--device-auth gives you a code to enter in your host browser, which suits containers. After that, run codex for the interactive agent, or check the login with codex login status.
To use an API key instead of ChatGPT sign-in, store it once:
Non-interactive use: use codex exec (alias codex e). Plain codex "..." starts the interactive UI. codex exec runs in a read-only sandbox by default. Add --sandbox workspace-write when you want it to create or edit files.
# Review a diff (piped input is added to the prompt)
git diff | codex exec "Review this diff for security issues"
# Let Codex write files in the project
codex exec --sandbox workspace-write \
"Create scripts/backup-postgres.sh that dumps a PostgreSQL database and uploads it to S3"
# JSONL event stream for tooling
codex exec --json "List the Terraform modules in this repo"
Settings live in ~/.codex/config.toml and credentials in ~/.codex/auth.json, which you should treat like a password. Set CODEX_HOME to move them. -m/--model picks a model, and codex resume reopens an earlier session.
GitHub Copilot CLI¶
copilot is GitHub's standalone agentic CLI. It is not IDE inline completion, and the old gh copilot suggest/explain extension isn't in the image.
docker run -it --rm \
-v "$PWD":/srv -w /srv \
-v ~/.copilot:/root/.copilot \
ghcr.io/jinalshah/devops/images/all-devops:latest \
copilot
Type /login. In a container it uses the GitHub device flow: open the URL on your host and enter the code.
Create a fine-grained personal access token with the Copilot Requests permission (classic ghp_ tokens are not supported), and pass it as COPILOT_GITHUB_TOKEN:
docker run --rm \
-v "$PWD":/srv -w /srv \
-e COPILOT_GITHUB_TOKEN \
ghcr.io/jinalshah/devops/images/all-devops:latest \
copilot -p "Summarise what this repository deploys" --allow-all-tools
Copilot checks COPILOT_GITHUB_TOKEN, then GH_TOKEN, then GITHUB_TOKEN.
Non-interactive use: copilot -p "..." needs --allow-all-tools (or COPILOT_ALLOW_ALL=true), because it can't stop to ask for permission. Add -s/--silent to print only the answer. There's no --file flag: name files in the prompt.
copilot -s --allow-all-tools \
-p "Review .github/workflows/deploy.yml for security issues and missing caching"
Other flags: --model and --output-format text|json. State lives in ~/.copilot (set COPILOT_HOME to move it).
Google Antigravity CLI¶
docker run -it --rm \
-v "$PWD":/srv -w /srv \
-v ~/.gemini:/root/.gemini \
ghcr.io/jinalshah/devops/images/all-devops:latest \
agy
Sign in with Google when prompted. With no browser available, agy prints a URL: open it on your host, then paste the code it shows you back into the terminal. This works in containers and over SSH. Use /login and /logout inside agy to switch accounts.
Setting GEMINI_API_KEY on its own is not enough, which is different from Gemini CLI. You also have to switch the model provider in ~/.gemini/antigravity-cli/settings.json:
mkdir -p ~/.gemini/antigravity-cli
echo '{"modelProvider": "gemini"}' > ~/.gemini/antigravity-cli/settings.json
docker run --rm \
-v "$PWD":/srv -w /srv \
-v ~/.gemini:/root/.gemini \
-e GEMINI_API_KEY \
ghcr.io/jinalshah/devops/images/all-devops:latest \
agy -p "Summarise what this repository deploys"
If you already have a settings.json, add the modelProvider key to it rather than overwriting the file.
Use Application Default Credentials from your host, or a service account key, and set AGY_ADC_AUTH=true. This needs Gemini 3 Flash or newer models.
gcloud auth application-default login # on the host
docker run --rm \
-v "$PWD":/srv -w /srv \
-v ~/.config/gcloud:/root/.config/gcloud \
-e AGY_ADC_AUTH=true \
ghcr.io/jinalshah/devops/images/gcp-devops:latest \
agy -p "Summarise what this repository deploys"
For a service account, mount the key and set GOOGLE_APPLICATION_CREDENTIALS to its path inside the container.
Non-interactive use: agy -p "..." (--print), with --output-format text|json|stream-json and --print-timeout 5m. When a headless run fails, agy exits with code 3 and prints AGY_ERROR: {json} on stderr, which is easy to catch in CI. There are no --file, --stdin or --image flags: pipe content in, or name files in the prompt.
git diff | agy -p "Review this diff for security issues"
trivy config --format json . | agy -p "Prioritise these findings and suggest fixes" > trivy-triage.md
# Let it edit files without asking
agy -p "Add descriptions to every variable in modules/vpc/variables.tf" --mode accept-edits
Other flags: --model, --effort low|medium|high, --mode plan, -c/--continue and --sandbox. Subcommands include agy models, agy mcp and agy update, and agy --version prints the version. The binary also updates itself in the background.
Where Antigravity keeps things
~/.gemini/antigravity-cli/:settings.json, conversations and logs~/.gemini/config/:mcp_config.json,hooks.json, skills and plugins- Tokens go in the OS keyring. Containers have no D-Bus, so there they fall back to files under
~/.gemini, which is why mounting~/.geminikeeps you signed in.~/.antigravityis not used. - Project context comes from
GEMINI.mdandAGENTS.md, and workspace customisations go in<repo>/.agents/(skills/,rules/,hooks.json).
Choosing an assistant¶
All four are capable agentic assistants: each reads and edits files and runs commands, and several accept images too. Pick based on what your team already pays for and signs in with:
- Already on a Claude plan or the Anthropic API? Use
claude. - Already on ChatGPT or the OpenAI API? Use
codex. - Already licensed for GitHub Copilot? Use
copilot, with no extra vendor account. - Google Workspace, a Gemini API key or Vertex AI? Use
agy.
A second assistant is also a cheap second opinion: generate with one, then review with another.
Good habits¶
Getting good results
- Pipe in the evidence.
git diff,terraform planoutput andtrivyJSON give the model the facts it needs. - Be specific. "Check IAM for
*actions and security groups for0.0.0.0/0" beats "review this". - Keep the checks. Run
terraform validate,tflint,ansible-lintandtrivyon anything an AI writes, then review it yourself.
Permissions and secrets
- Flags such as
--allow-all-tools,--dangerously-skip-permissionsand--sandbox danger-full-accesslet an agent run any command. Use them only in throwaway containers without production credentials mounted. - Pass API keys with
-e VAR(the value comes from your shell) rather than typing them on the command line, and keep them in your CI's secret store. ~/.codex/auth.json,~/.claudeand~/.geminihold live tokens. Never commit them or bake them into an image.
Troubleshooting¶
My script hangs or opens a full-screen UI
You started the interactive mode. Use claude -p, codex exec, copilot -p ... --allow-all-tools or agy -p.
I have to sign in every time I start a container
The config directory isn't mounted, or it's mounted at the wrong path. Check the table above; for Claude Code, also mount ~/.claude.json. Then check it's visible inside the container:
agy ignores my GEMINI_API_KEY
Add {"modelProvider": "gemini"} to ~/.gemini/antigravity-cli/settings.json. The environment variable alone doesn't switch agy away from Google sign-in.
Copilot rejects my token
Classic ghp_ tokens aren't supported. Create a fine-grained PAT with the Copilot Requests permission on an account that has a Copilot subscription.
Codex didn't write the file I asked for
codex exec is read-only by default. Add --sandbox workspace-write.
Next steps¶
- AI-assisted DevOps workflows: review, generate and troubleshoot, with CI examples
- Authentication guide: cloud, SSH and AI credentials in one place
- Multi-tool patterns: combine AI with Terraform, Trivy and friends