Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/docker-smoke-test-unified.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,41 @@ jobs:

- name: Verify agent CLI exists
run: docker run --rm --entrypoint which openab-unified-${{ matrix.target.name }}:test ${{ matrix.target.agent }}

- name: Verify Codex runtime versions
if: matrix.target.name == 'codex'
run: |
# Expected versions come from the Dockerfile ARG defaults (single
# source of truth) so a version bump only touches the Dockerfiles.
CODEX_ACP_VERSION=$(awk -F= '$1 == "ARG CODEX_ACP_VERSION" {print $2; exit}' Dockerfile.unified)
CODEX_VERSION=$(awk -F= '$1 == "ARG CODEX_VERSION" {print $2; exit}' Dockerfile.unified)
test -n "$CODEX_ACP_VERSION" && test -n "$CODEX_VERSION"
docker run --rm --entrypoint codex-acp openab-unified-codex:test --version \
| grep -F "@agentclientprotocol/codex-acp ${CODEX_ACP_VERSION}"
docker run --rm --entrypoint codex openab-unified-codex:test --version \
| grep -F "codex-cli ${CODEX_VERSION}"

- name: Verify Codex agent command is a single token
if: matrix.target.name == 'codex'
run: |
# Regression guard: OPENAB_AGENT_COMMAND must stay a plain binary.
# Packing env-var prefixes (e.g. "/usr/bin/env K=V codex-acp") breaks
# configs that override [agent].args only — OAB keeps token 1 as the
# command and replaces the rest, yielding "/usr/bin/env <user args>".
docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' openab-unified-codex:test \
| grep -Fx 'OPENAB_AGENT_COMMAND=codex-acp'

- name: Verify Codex ACP handshake
if: matrix.target.name == 'codex'
run: |
INIT='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1,"clientCapabilities":{},"clientInfo":{"name":"ci-test","version":"0.0.1"}}}'
CID=$(docker run -d -i --entrypoint codex-acp openab-unified-codex:test)
echo "$INIT" | docker attach --no-stdin=false "$CID" &
sleep 5
RESPONSE=$(docker logs "$CID" 2>/dev/null | grep -m1 '^{' || true)
docker rm -f "$CID" >/dev/null 2>&1

echo "Response: $RESPONSE"
echo "$RESPONSE" | jq -e \
'.result.agentInfo.name == "@agentclientprotocol/codex-acp"' \
>/dev/null
32 changes: 31 additions & 1 deletion .github/workflows/docker-smoke-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,36 @@ jobs:
- name: Verify agent CLI exists
run: docker run --rm --entrypoint which openab-test${{ matrix.variant.suffix }} ${{ matrix.variant.agent }}

- name: Verify Codex runtime versions
if: matrix.variant.suffix == '-codex'
run: |
# Expected versions come from the Dockerfile ARG defaults (single
# source of truth) so a version bump only touches the Dockerfiles.
CODEX_ACP_VERSION=$(awk -F= '$1 == "ARG CODEX_ACP_VERSION" {print $2; exit}' Dockerfile.codex)
CODEX_VERSION=$(awk -F= '$1 == "ARG CODEX_VERSION" {print $2; exit}' Dockerfile.codex)
test -n "$CODEX_ACP_VERSION" && test -n "$CODEX_VERSION"
docker run --rm --entrypoint codex-acp openab-test-codex --version \
| grep -F "@agentclientprotocol/codex-acp ${CODEX_ACP_VERSION}"
docker run --rm --entrypoint codex openab-test-codex --version \
| grep -F "codex-cli ${CODEX_VERSION}"

- name: Verify Codex agent command is a single token
if: matrix.variant.suffix == '-codex'
run: |
# Regression guard: OPENAB_AGENT_COMMAND must stay a plain binary.
# Packing env-var prefixes (e.g. "/usr/bin/env K=V codex-acp") breaks
# configs that override [agent].args only — OAB keeps token 1 as the
# command and replaces the rest, yielding "/usr/bin/env <user args>".
docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' openab-test-codex \
| grep -Fx 'OPENAB_AGENT_COMMAND=codex-acp'

- name: Verify agent responds
run: |
INIT='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","clientCapabilities":{},"clientInfo":{"name":"ci-test","version":"0.0.1"}}}'
if [ "${{ matrix.variant.suffix }}" = "-codex" ]; then
INIT='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1,"clientCapabilities":{},"clientInfo":{"name":"ci-test","version":"0.0.1"}}}'
else
INIT='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","clientCapabilities":{},"clientInfo":{"name":"ci-test","version":"0.0.1"}}}'
fi

# Start agent in background, send init, capture output with timeout
CID=$(docker run -d -i --entrypoint sh openab-test${{ matrix.variant.suffix }} -c 'exec ${{ matrix.variant.agent }} ${{ matrix.variant.agent_args }} 2>/dev/null')
Expand All @@ -70,6 +97,9 @@ jobs:
if [ -n "$RESPONSE" ] && echo "$RESPONSE" | jq -e '.result.agentInfo.name' > /dev/null 2>&1; then
AGENT_NAME=$(echo "$RESPONSE" | jq -r '.result.agentInfo.name')
echo "✅ ACP handshake ok — agent=$AGENT_NAME"
elif [ "${{ matrix.variant.suffix }}" = "-codex" ]; then
echo "❌ Codex ACP handshake failed"
exit 1
else
echo "⚠️ ACP handshake returned no response — falling back to CLI check"
docker run --rm --entrypoint ${{ matrix.variant.agent }} \
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.codex
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ FROM node:22-trixie-slim
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl procps ripgrep tini bubblewrap unzip && rm -rf /var/lib/apt/lists/*

# Pre-install codex-acp and codex CLI globally
ARG CODEX_ACP_VERSION=0.16.0
ARG CODEX_VERSION=0.141.0
RUN npm install -g @zed-industries/codex-acp@${CODEX_ACP_VERSION} @openai/codex@${CODEX_VERSION} --retry 3
ARG CODEX_ACP_VERSION=1.1.2
ARG CODEX_VERSION=0.144.1
RUN npm install -g @agentclientprotocol/codex-acp@${CODEX_ACP_VERSION} @openai/codex@${CODEX_VERSION} --fetch-retries=3

# Install gh CLI
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.package
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ CMD ["openab", "run", "-c", "/etc/openab/config.toml"]
# Target: codex
# =============================================================================
FROM base-node AS codex
ARG CODEX_ACP_VERSION=0.16.0
ARG CODEX_VERSION=0.141.0
RUN npm install -g @zed-industries/codex-acp@${CODEX_ACP_VERSION} @openai/codex@${CODEX_VERSION} --retry 3
ARG CODEX_ACP_VERSION=1.1.2
ARG CODEX_VERSION=0.144.1
RUN npm install -g @agentclientprotocol/codex-acp@${CODEX_ACP_VERSION} @openai/codex@${CODEX_VERSION} --fetch-retries=3
ENV HOME=/home/node
WORKDIR /home/node
COPY --from=bins --chown=node:node /openab /usr/local/bin/openab
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.unified
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="kiro-cli acp --trust-all-tools"
ENV OPENAB_AGENT_AUTH_COMMAND="kiro-cli login --use-device-flow"

Check warning on line 113 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (kiro, kiro-cli)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -130,7 +130,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="claude"
ENV OPENAB_AGENT_AUTH_COMMAND="claude auth login"

Check warning on line 133 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (claude, claude)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -138,9 +138,9 @@
# Target: codex
# =============================================================================
FROM base-node AS codex
ARG CODEX_ACP_VERSION=0.16.0
ARG CODEX_VERSION=0.141.0
RUN npm install -g @zed-industries/codex-acp@${CODEX_ACP_VERSION} @openai/codex@${CODEX_VERSION} --retry 3
ARG CODEX_ACP_VERSION=1.1.2
ARG CODEX_VERSION=0.144.1
RUN npm install -g @agentclientprotocol/codex-acp@${CODEX_ACP_VERSION} @openai/codex@${CODEX_VERSION} --fetch-retries=3
ENV HOME=/home/node
WORKDIR /home/node
COPY --from=builder --chown=node:node /build/target/release/openab /usr/local/bin/openab
Expand All @@ -149,7 +149,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="codex-acp"
ENV OPENAB_AGENT_AUTH_COMMAND="codex login --device-auth"

Check warning on line 152 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (codex, codex-acp)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -167,7 +167,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="copilot --acp --stdio"
ENV OPENAB_AGENT_AUTH_COMMAND="copilot login"

Check warning on line 170 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (copilot, copilot)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -192,7 +192,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="cursor-agent acp"
ENV OPENAB_AGENT_AUTH_COMMAND="cursor-agent login"

Check warning on line 195 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (cursor, cursor-agent)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -210,7 +210,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="gemini --acp"
ENV OPENAB_AGENT_AUTH_COMMAND="gemini auth"

Check warning on line 213 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (gemini, gemini)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand Down Expand Up @@ -241,7 +241,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="grok agent stdio"
ENV OPENAB_AGENT_AUTH_COMMAND="grok login --device-auth"

Check warning on line 244 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (grok, grok)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand Down Expand Up @@ -276,7 +276,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="hermes-acp"
ENV OPENAB_AGENT_AUTH_COMMAND="hermes auth add"

Check warning on line 279 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (hermes, hermes-acp)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -294,7 +294,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="mimo acp"
ENV OPENAB_AGENT_AUTH_COMMAND="mimo auth login --provider mimo --method \"MiMo Auto (free)\""

Check warning on line 297 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (mimocode, mimo)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -312,7 +312,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="opencode acp"
ENV OPENAB_AGENT_AUTH_COMMAND="opencode auth login"

Check warning on line 315 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (opencode, opencode)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand Down Expand Up @@ -344,7 +344,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="devin acp"
ENV OPENAB_AGENT_AUTH_COMMAND="devin auth login --force-manual-token-flow"

Check warning on line 347 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (devin, devin)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand Down Expand Up @@ -372,7 +372,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="agy-acp"
ENV OPENAB_AGENT_AUTH_COMMAND="agy auth"

Check warning on line 375 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (antigravity, agy-acp)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -391,7 +391,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="openab-agent"
ENV OPENAB_AGENT_AUTH_COMMAND="pi /login"

Check warning on line 394 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (pi, pi-acp)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand All @@ -408,7 +408,7 @@
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENV OPENAB_AGENT_COMMAND="openab-agent"
ENV OPENAB_AGENT_AUTH_COMMAND="openab-agent auth codex-oauth --no-browser"

Check warning on line 411 in Dockerfile.unified

View workflow job for this annotation

GitHub Actions / smoke-test-unified (native, openab-agent)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAB_AGENT_AUTH_COMMAND") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ The bot creates a thread. After that, just type in the thread — no @mention ne
|-------|-----|-------------|-------|
| Kiro (default) | `kiro-cli acp` | Native | [docs/kiro.md](docs/kiro.md) |
| Claude Code | `claude-agent-acp` | [@agentclientprotocol/claude-agent-acp](https://github.com/agentclientprotocol/claude-agent-acp) | [docs/claude-code.md](docs/claude-code.md) |
| Codex | `codex-acp` | [@zed-industries/codex-acp](https://github.com/zed-industries/codex-acp) | [docs/codex.md](docs/codex.md) |
| Codex | `codex-acp` | [@agentclientprotocol/codex-acp](https://github.com/agentclientprotocol/codex-acp) | [docs/codex.md](docs/codex.md) |
| Gemini | `gemini --acp` | Native | [docs/gemini.md](docs/gemini.md) |
| OpenCode | `opencode acp` | Native | [docs/opencode.md](docs/opencode.md) |
| MiMo-Code | `mimo acp` | Native | [docs/mimocode.md](docs/mimocode.md) |
Expand Down
2 changes: 1 addition & 1 deletion README.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ bot 會建立一個討論串。之後只要直接在討論串中輸入即可,
|-------|-----|-------------|------|
| Kiro(預設) | `kiro-cli acp` | Native | [docs/kiro.md](docs/kiro.md) |
| Claude Code | `claude-agent-acp` | [@agentclientprotocol/claude-agent-acp](https://github.com/agentclientprotocol/claude-agent-acp) | [docs/claude-code.md](docs/claude-code.md) |
| Codex | `codex-acp` | [@zed-industries/codex-acp](https://github.com/zed-industries/codex-acp) | [docs/codex.md](docs/codex.md) |
| Codex | `codex-acp` | [@agentclientprotocol/codex-acp](https://github.com/agentclientprotocol/codex-acp) | [docs/codex.md](docs/codex.md) |
| Gemini | `gemini --acp` | Native | [docs/gemini.md](docs/gemini.md) |
| OpenCode | `opencode acp` | Native | [docs/opencode.md](docs/opencode.md) |
| MiMo-Code | `mimo acp` | Native | [docs/mimocode.md](docs/mimocode.md) |
Expand Down
6 changes: 4 additions & 2 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,12 @@ working_dir = "/home/agent"
# inherit_env = ["API_BASE_URL", "MODEL_NAME"]

# [agent]
# command = "codex"
# args = ["--acp"]
# command = "codex-acp"
# working_dir = "/home/node"
# env = { OPENAI_API_KEY = "${OPENAI_API_KEY}" }
# Recommended for containerized deployments (outer container = security boundary):
# [pool]
# default_config_options = { mode = "agent-full-access" }

# [agent]
# command = "gemini"
Expand Down
4 changes: 2 additions & 2 deletions crates/openab-core/src/setup/wizard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ fn section_agent() -> (String, String, bool) {
"",
"claude: npm install -g @anthropic-ai/claude-code",
"kiro: npm install -g @koryhutchison/kiro-cli",
"codex: npm install -g openai-codex (requires OpenAI API key)",
"codex: npm install -g @openai/codex @agentclientprotocol/codex-acp",
"gemini: npm install -g @google/gemini-cli",
"",
"Make sure the agent is in your PATH before continuing.",
Expand Down Expand Up @@ -518,7 +518,7 @@ fn print_next_steps(agent: &str, output_path: &Path, is_local: bool) {
}
"codex" => {
cprintln!(C.cyan, " 1. Install Codex CLI + ACP adapter:");
println!(" npm install -g @openai/codex @zed-industries/codex-acp");
println!(" npm install -g @openai/codex @agentclientprotocol/codex-acp");
cprintln!(C.cyan, " 2. Authenticate:");
println!(" codex login --device-auth");
}
Expand Down
114 changes: 101 additions & 13 deletions docs/codex.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Codex

Codex uses the [@zed-industries/codex-acp](https://github.com/zed-industries/codex-acp) adapter for ACP support.
Codex uses the [@agentclientprotocol/codex-acp](https://github.com/agentclientprotocol/codex-acp) adapter for ACP support.
The recommended working directory for the Codex image is `/home/node`; this is
also the container `HOME`, so Codex auth, sessions, generated images, and skills
live under `/home/node/.codex/`.
Expand All @@ -11,7 +11,14 @@ live under `/home/node/.codex/`.
docker build -f Dockerfile.codex -t openab-codex:latest .
```

The image installs `@zed-industries/codex-acp` and `@openai/codex` globally via npm.
The image installs `@agentclientprotocol/codex-acp` and `@openai/codex`
globally in the same npm transaction. The global Codex CLI keeps
`codex login --device-auth` available, while npm deduplicates the adapter's
compatible Codex dependency to the pinned CLI version.

For containerized deployments where the outer container or VM is the security
boundary, set `[pool] default_config_options = { mode = "agent-full-access" }`
— see [ACP Modes and Migration](#acp-modes-and-migration).

## Helm Install

Expand All @@ -21,7 +28,6 @@ helm install openab openab/openab \
--set agents.codex.discord.enabled=true \
--set agents.codex.discord.botToken="$DISCORD_BOT_TOKEN" \
--set-string 'agents.codex.discord.allowedChannels[0]=YOUR_CHANNEL_ID' \
--set agents.codex.command=codex-acp \
--set agents.codex.workingDir=/home/node \
--set image.tag=beta
```
Expand Down Expand Up @@ -51,7 +57,7 @@ To override a single agent's image instead of the global tag:

```toml
[agent]
# command defaults from OPENAB_AGENT_COMMAND="codex"
# command defaults from the image's OPENAB_AGENT_COMMAND
# Only override if you need non-default behavior
```

Expand All @@ -67,6 +73,78 @@ Follow the device code flow in your browser, then restart the pod:
kubectl rollout restart deployment/openab-codex
```

## ACP Modes and Migration

The adapter exposes three ACP modes. The selected mode controls the sandbox
and approval policy for each ACP turn:

| Mode | Sandbox | Approval policy | Network |
|------|---------|-----------------|---------|
| `read-only` | read-only | on-request | disabled |
| `agent` (adapter default) | workspace-write | on-request | disabled |
| `agent-full-access` (recommended for OpenAB deployments) | danger-full-access | never | enabled |

The adapter defaults to `agent`. For OpenAB deployments the outer container or
VM is normally the intended security boundary, and Codex's inner sandbox needs
`bubblewrap` (user namespaces) that containers typically don't grant — so the
**recommended deployment default** is `agent-full-access`, set through the
standard ACP config option mechanism:

```toml
[pool]
default_config_options = { mode = "agent-full-access" }
```

OpenAB sends this after `session/new` on the ACP session, so it is explicit,
visible in config, and overridable per deployment — nothing is baked into the
image. `agent-full-access` removes Codex's inner sandbox and approval prompts;
it can read or modify mounted files and use the container's network. Use it
only with a dedicated outer isolation boundary. Avoid host filesystem and
Docker socket mounts, and scope mounted credentials, persistent volumes,
service accounts, and network access to the agent's actual needs. Select
`agent` or `read-only` when those conditions are not met.

> The adapter also honors an `INITIAL_AGENT_MODE` environment variable, but
> OpenAB spawns agents with a cleared environment, and packing it into
> `OPENAB_AGENT_COMMAND` via `/usr/bin/env` breaks configs that override
> `[agent].args` only. Prefer the `[pool]` mechanism above; if you need the
> env route, deliver it with `[agent] env = { INITIAL_AGENT_MODE = "…" }`.

> [!WARNING]
> **Breaking change — mode IDs renamed.** The previous Zed adapter used `auto`
> and `full-access`; this adapter uses `agent` and `agent-full-access`. OpenAB
> does **not** translate the old values: a `[pool].default_config_options`
> entry like `mode = "full-access"` fails to apply on upgrade (OpenAB logs
> `failed to set default config option` and the session stays on the adapter's
> conservative `agent` default — it fails safe, never escalates). Update your
> config to the new IDs:
>
> ```text
> auto -> agent
> full-access -> agent-full-access
> ```

> [!WARNING]
> **Breaking change — `-c` CLI overrides are silently ignored.** The Zed
> adapter accepted Codex-style `-c key=value` arguments (e.g.
> `[agent] args = ["-c", "model=\"gpt-5.5\""]` to pin a model). This adapter's
> CLI only recognizes `--version`, `login`, and `cli` — anything else is
> ignored without error, so a carried-over model pin silently stops applying.
> Pin the model through the ACP config option instead:
>
> ```toml
> [pool]
> default_config_options = { mode = "agent-full-access", model = "gpt-5.5" }
> ```

Custom ACP clients that call `session/set_config_option` directly must also send
the new mode IDs. If canary validation finds a regression, roll back to the
previous OpenAB Codex image tag; existing Codex credentials and session data
remain under `/home/node/.codex/`.

For preview-image validation, mode-matrix checks, evidence reporting, and
post-merge rollout, follow [Canary Testing Pull Requests](canary-tests.md).

### Persisted Paths (PVC)

| Path | Contents |
Expand Down Expand Up @@ -166,7 +244,7 @@ itself, explicitly expose an upload token to the agent:

```toml
[agent]
# command defaults from OPENAB_AGENT_COMMAND="codex"
# command defaults from the image's OPENAB_AGENT_COMMAND
# Only override if you need non-default behavior
env = { DISCORD_FILE_BOT_TOKEN = "${DISCORD_FILE_BOT_TOKEN}" }
```
Expand Down Expand Up @@ -204,7 +282,12 @@ Example user prompt after creating such a skill:
Use $discord-imagegen-deliver to generate a warm hand-painted sky with birds and send it back to this Discord thread.
```

## Approval Policy & Auto-review
## Direct Codex CLI Approval Policy & Auto-review

The settings in this section apply to direct Codex CLI commands such as
`codex exec`. For OpenAB ACP turns, select an ACP mode as described in
[ACP Modes and Migration](#acp-modes-and-migration); the adapter supplies the
turn's sandbox and approval policy.

Codex separates **when** to ask for approval (`approval_policy`) from **who**
reviews the request (`approvals_reviewer`):
Expand All @@ -214,9 +297,10 @@ reviews the request (`approvals_reviewer`):
| `approval_policy` | `untrusted`, `on-failure` (deprecated), `on-request`, `granular`, `never` | When Codex must request approval before acting |
| `approvals_reviewer` | `"user"` (default), `"auto_review"` | Who handles the approval — human or GPT-5.4 Thinking reviewer |

For OpenAB deployments, **Auto-review is the recommended mode**. OpenAB agents
run as long-lived background processes with no human watching the terminal, so
manual approval is impractical and `"never"` removes all guardrails.
For unattended direct CLI commands, **Auto-review is the recommended mode**.
OpenAB agents run as long-lived background processes with no human watching the
terminal, so manual approval is impractical and `"never"` removes all
guardrails.

Enable Auto-review in `/home/node/.codex/config.toml`:

Expand Down Expand Up @@ -290,8 +374,12 @@ This commonly happens in OpenAB deployments where Codex already runs inside an
isolated container or VM — the outer runtime provides the desired isolation, so
the inner sandbox is redundant.

**Solution — Disable Codex's inner sandbox** (recommended when the outer OpenAB
runtime already provides isolation):
**For ACP sessions**, set `agent-full-access` through
`[pool].default_config_options` as described in
[ACP Modes and Migration](#acp-modes-and-migration).

**For direct Codex CLI commands**, disable Codex's inner sandbox when the outer
OpenAB runtime already provides isolation:

```toml
# /home/node/.codex/config.toml
Expand All @@ -313,7 +401,7 @@ approvals_reviewer = "auto_review"
> and OpenAB agents have no terminal attached — every tool call hangs in
> `in_progress` until openab's 1800 s hard timeout fires. Use
> `approvals_reviewer = "auto_review"` (recommended, see
> [§Approval Policy](#approval-policy--auto-review)) or
> [§Direct Codex CLI Approval Policy](#direct-codex-cli-approval-policy--auto-review)) or
> `approval_policy = "never"` for trusted and already-isolated pods (`"never"`
> removes all per-call guardrails — the outer pod isolation is the only
> remaining boundary).
Expand All @@ -324,7 +412,7 @@ Or launch with:
codex --sandbox danger-full-access
```

Or seed via `kubectl cp` (see [above](#approval-policy--auto-review) for why
Or seed via `kubectl cp` (see [above](#direct-codex-cli-approval-policy--auto-review) for why
ConfigMap mounts should not be used for `.codex/config.toml`):

```bash
Expand Down
6 changes: 6 additions & 0 deletions docs/config-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ command = "codex-acp"
working_dir = "/home/node"
env = { OPENAI_API_KEY = "${OPENAI_API_KEY}" }

# Recommended for containerized OpenAB deployments: the outer container is the
# security boundary; Codex's inner sandbox needs user namespaces containers
# typically don't grant. See docs/codex.md §ACP Modes and Migration.
[pool]
default_config_options = { mode = "agent-full-access" }

# Gemini CLI
[agent]
command = "gemini"
Expand Down
Loading