Skip to content

m0nokey/cli-agents

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CLI Agents

Docker runners for terminal coding agents: Codex, Gemini, and future tools.

The goal is simple: run powerful agent CLIs without installing their runtimes, npm packages, caches, and auth files directly on your laptop.

Why

Coding agents can run commands and edit files. A bad prompt, tool bug, or compromised package can damage files on the host.

Installing agent CLIs directly on a laptop also spreads npm packages, caches, auth state, shell history, and temporary files across the user environment. This project keeps those runtimes disposable and per-agent.

This project reduces the blast radius:

  • only the per-agent workspace/ directory is mounted;
  • Dockerfile, compose.yml, and wrapper scripts stay outside /workspace;
  • auth/state is stored locally in .codex or .gemini;
  • containers run as non-root users;
  • Codex keeps its native approval/sandbox flow inside the container;
  • Linux capabilities are dropped;
  • Docker logs are disabled;
  • no Docker socket is mounted;
  • agent packages are installed inside images, not on the host.

This is not a perfect sandbox. The agent can still change files inside the mounted workspace/ directory.

Security Architecture

Each agent has its own runner directory:

agent/
  workspace/   mounted read-write as /workspace
  .codex/      or .gemini/ auth and local state
  .ssh/        per-agent deploy key, mounted read-only
  .secrets/    optional credentials, mounted read-only

The container boundary is intentionally narrow: non-root user, dropped Linux capabilities, no privileged mode, no Docker socket, no persistent Docker logs, and resource limits for CPU, memory, and process count. Codex additionally uses its native bubblewrap sandbox with a custom seccomp profile so write/delete operations still go through Codex approval.

Threat Model

This reduces host risk from accidental commands, malicious npm/Go/Rust packages, bad prompts, and tool bugs. The agent and code it runs execute inside a container without privileged mode, without a Docker socket, without access to the host home directory, and with a dedicated workspace mount.

The isolation limits blast radius to directories intentionally mounted into the container: workspace/, agent state, read-only .ssh, and read-only .secrets.

It does not protect against malicious code reading mounted files, secrets committed into workspace/, code abusing credentials available to the agent, or escape vulnerabilities in Docker, the Linux kernel, or Docker Desktop.

Tools

  • codex/ - OpenAI Codex CLI
  • gemini/ - Google Gemini CLI
  • claude/ - planned

Included Tools

Agent images include the practical local toolchain by default:

  • git, bash, curl, SSH, rsync
  • Python, pip, Node.js, npm
  • Terraform from the latest HashiCorp release at build time
  • Ansible from Alpine packages
  • Kubernetes clients: kubectl, Helm, Kustomize, kubectx/kubens, Stern
  • make, SOPS, age, and crane
  • OpenSSL CLI for certificate and TLS diagnostics
  • lint and hygiene tools: shfmt, ShellCheck, yamllint, ansible-lint, pre-commit
  • gitleaks for local secret scans
  • jq and yq

Cloud provider CLIs are intentionally not included. For Terraform and Ansible, keep projects in workspace/ and credentials outside it in .secrets/.

Requirements

  • Docker with Docker Compose plugin
  • Bash on the host

Containers are Alpine-based and include Bash because agent shell tools commonly spawn bash.

Quick Start

Codex

cd codex
./codex.sh

On first run Codex asks how to sign in:

1. Sign in with ChatGPT
2. Sign in with Device Code
3. Provide your own API key

Choose ChatGPT if your plan includes Codex, Device Code for login from another device, or API key for usage-based billing.

By default, Codex can edit only files inside:

codex/workspace/

The runner files stay outside that mount.

Useful commands:

./codex.sh --device-auth
OPENAI_API_KEY=... ./codex.sh --api
./codex.sh --resume last

Gemini

cd gemini
./gemini.sh

The default model is gemini-3.1-flash-lite. Override it when needed:

GEMINI_MODEL=other-model ./gemini.sh

On first run Gemini starts the Google login flow. If a browser does not open automatically, copy the printed URL into your host browser and finish auth there.

The container sets GEMINI_FORCE_FILE_STORAGE=true, so OAuth tokens are written to .gemini/gemini-credentials.json instead of a desktop keychain.

If Gemini asks:

Do you trust the files in this folder?

Choose:

1. Trust folder (workspace)

Do not trust the parent folder unless you intentionally want a broader trust scope.

By default, Gemini can edit only files inside:

gemini/workspace/

The runner files stay outside that mount.

Secrets

Do not put cloud credentials, Terraform backend secrets, Ansible vault passwords, or private keys into workspace/. Store them in per-agent .secrets/ directories instead:

codex/.secrets/
gemini/.secrets/

They are ignored by git and mounted read-only at /run/agent-secrets.

Examples:

.secrets/ansible/vault-password.txt
.secrets/aws/credentials
.secrets/gcp/service-account.json
.secrets/yc/authorized_key.json

Per-Agent SSH Keys

Do not mount your personal ~/.ssh directory into an agent container. Create a separate key for each agent and add only the public key to the repository as a deploy key:

cd codex
./codex.sh --init-ssh-key

cd ../gemini
./gemini.sh --init-ssh-key

The command prints the public key. Add it in GitHub/GitLab repository settings as a deploy key:

  • read-only for clone/pull;
  • write access only when the agent must push;
  • separate key per agent/project when possible.

Private keys stay in codex/.ssh/ or gemini/.ssh/, are ignored by git, and are mounted read-only into the container.

Security Defaults

  • alpine:3.23
  • non-root users
  • no-new-privileges where compatible
  • cap_drop: ALL
  • CPU, memory, and process limits
  • explicit DNS servers and empty DNS search domains
  • logging.driver: none
  • OTEL exporters disabled
  • no privileged mode
  • no Docker socket mount
  • Codex uses bubblewrap with a local seccomp profile for its inner sandbox

Scan Images

Codex:

docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v trivy-cache:/root/.cache/ \
  aquasec/trivy:latest image \
  --scanners vuln \
  --timeout 10m \
  --severity HIGH,CRITICAL \
  --ignore-unfixed \
  local/codex-rust:latest

Gemini:

docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v trivy-cache:/root/.cache/ \
  aquasec/trivy:latest image \
  --scanners vuln \
  --timeout 10m \
  --severity HIGH,CRITICAL \
  --ignore-unfixed \
  local/gemini-cli:latest

About

Docker runners for terminal coding agents: Codex, Gemini, and future tools.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors