diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 17b4505a..8eeb1173 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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 } @@ -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 @@ -188,6 +190,7 @@ jobs: - { suffix: "-opencode" } - { suffix: "-cursor" } - { suffix: "-hermes" } + - { suffix: "-grok" } runs-on: ubuntu-latest permissions: contents: read diff --git a/Dockerfile.grok b/Dockerfile.grok new file mode 100644 index 00000000..4190b491 --- /dev/null +++ b/Dockerfile.grok @@ -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"] diff --git a/config.toml.example b/config.toml.example index 20ccff34..3e3c39d4 100644 --- a/config.toml.example +++ b/config.toml.example @@ -110,6 +110,16 @@ working_dir = "/home/agent" # # Supports 30+ providers (xAI Grok OAuth, Anthropic, OpenAI Codex, Gemini, etc.) # # Provider switching: kubectl exec -it -- 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 -- 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 diff --git a/docs/grok.md b/docs/grok.md new file mode 100644 index 00000000..b6d4d09c --- /dev/null +++ b/docs/grok.md @@ -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 . 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 -- 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 -- grok models +``` + +## Updating + +```bash +# Inside the container (one-shot upgrade): +kubectl exec -it -- 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.