Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
- { suffix: "-opencode", dockerfile: "Dockerfile.opencode", artifact: "opencode" }
- { suffix: "-cursor", dockerfile: "Dockerfile.cursor", artifact: "cursor" }
- { suffix: "-hermes", dockerfile: "Dockerfile.hermes", artifact: "hermes" }
- { suffix: "-grok", dockerfile: "Dockerfile.grok", artifact: "grok" }
platform:
- { os: linux/amd64, runner: ubuntu-latest }
- { os: linux/arm64, runner: ubuntu-24.04-arm }
Expand Down Expand Up @@ -137,6 +138,7 @@ jobs:
- { suffix: "-opencode", artifact: "opencode" }
- { suffix: "-cursor", artifact: "cursor" }
- { suffix: "-hermes", artifact: "hermes" }
- { suffix: "-grok", artifact: "grok" }
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down Expand Up @@ -188,6 +190,7 @@ jobs:
- { suffix: "-opencode" }
- { suffix: "-cursor" }
- { suffix: "-hermes" }
- { suffix: "-grok" }
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
59 changes: 59 additions & 0 deletions Dockerfile.grok
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# --- Build stage ---
FROM rust:1-bookworm AS builder
WORKDIR /build
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo 'fn main() {}' > src/main.rs && cargo build --release && rm -rf src
COPY src/ src/
RUN touch src/main.rs && cargo build --release

# --- Runtime stage ---
FROM debian:bookworm-slim

# Create agent user first so WORKDIR gets correct ownership
RUN useradd -m -u 1000 agent

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl procps ripgrep tini git && \
rm -rf /var/lib/apt/lists/*

# Install Grok Build CLI — pinned version with SHA256 checksum verification.
# Binary sourced from xAI's public artifacts bucket (same source the official
# `https://x.ai/cli/install.sh` resolves to) so the build is reproducible.
ARG GROK_VERSION=0.1.211
ARG GROK_SHA256_AMD64=9245f9c921b1f91bfb34ee2ee27715000b65e947723541ff1a612eaece468bd0
ARG GROK_SHA256_ARM64=b283cb72fdc3143365e044fd7f8630e14845640d4d81404bb36905cc7209abc6
ARG TARGETPLATFORM
RUN set -eux; \
case "${TARGETPLATFORM:-linux/amd64}" in \
"linux/amd64") arch=x86_64; sha="${GROK_SHA256_AMD64}" ;; \
"linux/arm64") arch=aarch64; sha="${GROK_SHA256_ARM64}" ;; \
*) echo "Unsupported platform: ${TARGETPLATFORM}" >&2; exit 1 ;; \
esac; \
curl -fsSL "https://storage.googleapis.com/grok-build-public-artifacts/cli/grok-${GROK_VERSION}-linux-${arch}" \
-o /tmp/grok && \
echo "${sha} /tmp/grok" | sha256sum -c - && \
install -m 0755 /tmp/grok /usr/local/bin/grok && \
ln -sf /usr/local/bin/grok /usr/local/bin/agent && \
rm /tmp/grok

# Install gh CLI
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
-o /usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
> /etc/apt/sources.list.d/github-cli.list && \
apt-get update && apt-get install -y --no-install-recommends gh && \
rm -rf /var/lib/apt/lists/*

ENV HOME=/home/agent
WORKDIR /home/agent

COPY --from=builder --chown=1000:1000 /build/target/release/openab /usr/local/bin/openab

# Pre-create credential dir so a PVC mounted at ~/.grok inherits correct ownership
RUN mkdir -p /home/agent/.grok && chown -R agent:agent /home/agent

USER agent
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]
10 changes: 10 additions & 0 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ working_dir = "/home/agent"
# # Supports 30+ providers (xAI Grok OAuth, Anthropic, OpenAI Codex, Gemini, etc.)
# # Provider switching: kubectl exec -it <pod> -- hermes model

# [agent]
# command = "grok"
# args = ["agent", "stdio"]
# working_dir = "/home/agent"
# # Auth options:
# # 1. API key: env = { GROK_CODE_XAI_API_KEY = "${XAI_API_KEY}" }
# # 2. Device-code: kubectl exec -it <pod> -- grok login --device-auth
# # 3. Deployment key: env = { GROK_DEPLOYMENT_KEY = "${GROK_DEPLOYMENT_KEY}" }
# # See docs/grok.md for details.

[pool]
max_sessions = 10
session_ttl_hours = 24
Expand Down
134 changes: 134 additions & 0 deletions docs/grok.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Grok Build (xAI)

[Grok Build](https://x.ai/news/grok-build-cli) is xAI's official coding agent CLI. It speaks ACP natively via `grok agent stdio` — no wrapper required.

## Docker Image

```bash
docker build -f Dockerfile.grok -t openab-grok:latest .
```

The image pulls a pinned `grok` binary from xAI's public artifacts bucket and verifies its SHA256 checksum. Bump `GROK_VERSION`, `GROK_SHA256_AMD64`, and `GROK_SHA256_ARM64` in `Dockerfile.grok` to upgrade.

## Helm Install

```bash
helm install openab openab/openab \
--set agents.kiro.enabled=false \
--set agents.grok.discord.enabled=true \
--set agents.grok.discord.botToken="$DISCORD_BOT_TOKEN" \
--set-string 'agents.grok.discord.allowedChannels[0]=YOUR_CHANNEL_ID' \
--set agents.grok.image=ghcr.io/openabdev/openab-grok:latest \
--set agents.grok.command=grok \
--set-string 'agents.grok.args[0]=agent' \
--set-string 'agents.grok.args[1]=stdio' \
--set agents.grok.workingDir=/home/agent
```

> Set `agents.kiro.enabled=false` to disable the default Kiro agent.

## Manual config.toml

```toml
[agent]
command = "grok"
args = ["agent", "stdio"]
working_dir = "/home/agent"
```

## Authentication

Grok Build supports three credential sources. Pick whichever fits your deployment.

### Option A: API key (simplest, recommended for CI / bot deployments)

Set the environment variable in the pod / task definition:

```bash
export GROK_CODE_XAI_API_KEY="xai-..."
```

Get a key from <https://console.x.ai/>. No interactive login needed.

> ⚠️ **Security**: env vars listed under `[agent].env` are visible to the agent and can be leaked via prompt injection. Prefer mounting them via the platform's secret manager.

### Option B: Device-code OAuth (for SuperGrok subscriptions)

If you want to use a SuperGrok subscription instead of pay-per-token API billing:

```bash
kubectl exec -it <pod> -- grok login --device-auth
```

The CLI prints a short code and URL — open the URL on any device, enter the code, approve. The token is stored at `~/.grok/auth.json` inside the container.

This works in any headless environment (K8s exec, ECS exec, plain SSH) **without port-forwarding** — unlike loopback OAuth flows.

### Option C: Enterprise deployment key

```bash
export GROK_DEPLOYMENT_KEY="..."
```

A deployment key takes precedence over `auth.json`. The CLI fetches managed config from `cli-chat-proxy.grok.com/v1/deployment/config` on startup. Available to xAI enterprise customers; contact xAI sales for details.

## Credential Persistence

`grok login` stores OAuth credentials at `~/.grok/auth.json` and runtime config at `~/.grok/config.toml`. The OpenAB Helm chart's default persistence covers `workingDir` automatically (PVC mounted at `/home/agent`).

If deploying manually, mount persistent storage at `/home/agent/.grok`:

```yaml
volumes:
- name: grok-credentials
persistentVolumeClaim:
claimName: grok-credentials-pvc
volumeMounts:
- name: grok-credentials
mountPath: /home/agent/.grok
```

API-key-only deployments don't need persistence.

## Model Selection

The default model is whichever Grok Build CLI selects (currently `grok-code-fast-1` for the free tier; `grok-4.3` family for SuperGrok). To override:

```toml
[agent]
command = "grok"
args = ["agent", "stdio", "--model", "grok-4.3"]
working_dir = "/home/agent"
```

List available models inside the pod:

```bash
kubectl exec -it <pod> -- grok models
```

## Updating

```bash
# Inside the container (one-shot upgrade):
kubectl exec -it <pod> -- grok update

# Or rebuild the image with a new pinned version:
docker build -f Dockerfile.grok \
--build-arg GROK_VERSION=0.1.220 \
--build-arg GROK_SHA256_AMD64=... \
--build-arg GROK_SHA256_ARM64=... \
-t openab-grok:latest .
```

## Comparison with Hermes

| Property | `Dockerfile.grok` | `Dockerfile.hermes` |
|----------|-------------------|---------------------|
| Provider | xAI Grok only | xAI + 30 others via Nous gateway |
| ACP | Native (`grok agent stdio`) | Via `hermes-acp` wrapper |
| Headless auth | API key env or device-code | Loopback OAuth (needs port-forward / ECS curl trick) |
| Supply chain | xAI only | xAI + Nous Research install script |
| Image size | Smaller (single static binary, no Python venv) | Larger (Python + uv + ffmpeg) |

Pick `Dockerfile.grok` if Grok is the only model you need. Pick `Dockerfile.hermes` if you want multi-provider switching or fallback chains.
Loading