Files
roboco/docker/agent-grok.Dockerfile
T
Renn F eac065e504 fix(grok): deliver intake draft via the relay + correct opencode-mechanism docs
Live end-to-end verification (opencode 1.17.8 + grok-build-0.1) of the WHOLE
integration, then fixes for what it surfaced:

1) Intake draft card (FUNCTIONAL): opencode's synchronous serve reply
   (POST /session/:id/message) returns only [step-start, text, step-finish] — it
   does NOT include tool-call parts, so the driver could never extract the
   propose_draft draft. intake-tools.js now POSTs the draft straight to the
   prompter-live relay (/api/prompter/live/{session}/events, the same endpoint
   the driver's relay sink uses), so the panel renders the card regardless.
   Verified live: grok calls propose_draft -> the relay receives the draft.

2) Correct misattributed opencode "bugs" (DOCS): earlier comments asserted as
   general opencode behavior that a provider.xai block / npm override / config
   plugin:-array "break" registration. Re-testing showed those were artifacts of
   a PROJECT-level .opencode/opencode.json; from the GLOBAL config (which
   opencode_config writes) the built-in provider, model resolution, the plugin
   array AND the auto-discovery dir all work, and MCP gateway verbs register
   (delivery agents verified). Reframed the comments as design choices (built-in
   provider + XAI_API_KEY env + plugins baked in the auto-discovery dir with
   named exports) and dropped the false claims.

3) Reasoning --variant: passing it does not error, but whether opencode applies a
   named reasoning variant to grok-build-0.1 (no provider-defined variants) is
   UNVERIFIED — comment softened from a "~54% cut" claim to best-effort,
   measure-on-NAS.

Verified live this session: one-shot delivery (model + MCP verbs + plugins +
hooks), secretary tools (read_company_state + submit_directive -> backend with
token), intake draft (relay), grok built-in-provider tool-calling. Remaining
NAS-only: full container assembly (SDK :9000 startup, entrypoint hooks, 429
parking) + the --variant cost measurement. Gate green (ruff/mypy + 51 tests;
node --check the plugins).
2026-06-18 21:59:25 +02:00

53 lines
2.8 KiB
Docker

# Grok (xAI) Agent Image
# =============================================================================
# Runs grok-build-0.1 through the opencode CLI (OpenAI protocol) instead of
# Claude Code, while reusing the base image's roboco venv + uv + the RoboCo MCP
# gateway servers. The entrypoint renders opencode.json from the spawn env +
# mounted mcp-config.json (see roboco.llm.providers.opencode_config) and runs
# opencode. One runtime image serves every role — role behaviour comes from the
# mounted system prompt / manifest / mcp-config, exactly as on the Claude path.
# =============================================================================
FROM roboco-agent-base
USER root
# opencode — the OpenAI-protocol agent runtime. grok-build-0.1 runs on opencode's
# BUILT-IN xai provider (no custom provider block / npm needed), so only
# opencode-ai is installed; it resolves the provider SDK at runtime.
RUN npm install -g opencode-ai \
&& npm cache clean --force \
&& rm -rf /root/.npm /tmp/*
# opencode plugins, baked into the AUTO-DISCOVERY dir (~/.config/opencode/plugin/)
# rather than referenced by a config `plugin:` path — the dir is the simplest
# registration route. Each plugin uses a NAMED export (opencode's convention).
# secret-scrub — bash-guard parity (PAT/credential deny on tool.execute.before)
# budget-feed — POSTs budget/loop/terminal counters to the in-container SDK
# server (tool.execute.{before,after}); the entrypoint starts
# that server (roboco.agent_sdk.server) for Claude-parity.
COPY docker/grok/secret-scrub.js /home/agent/.config/opencode/plugin/secret-scrub.js
COPY docker/grok/budget-feed.js /home/agent/.config/opencode/plugin/budget-feed.js
# Entrypoint: render opencode.json, then run opencode (overrides base's `claude`).
COPY docker/scripts/grok-agent-entrypoint.sh /app/scripts/grok-agent-entrypoint.sh
RUN chmod 0755 /app/scripts/grok-agent-entrypoint.sh
# opencode persists data under ~/.local/share and state under ~/.local/state, and
# reads config + plugins from ~/.config/opencode. When the orchestrator
# bind-mounts the opencode store at ~/.local/share/opencode, docker creates the
# intermediate ~/.local AS ROOT, so the non-root agent can no longer create its
# siblings and opencode EACCESes at boot. Pre-create the trees agent-owned so the
# mount leaves the parents writable (complements the orchestrator's 0777
# host-source pre-create), and so the baked plugin dir is agent-owned.
RUN mkdir -p /home/agent/.local/share/opencode /home/agent/.local/state \
/home/agent/.config/opencode/plugin \
&& chown -R agent:agent /home/agent/.local /home/agent/.config
USER agent
LABEL role="grok-runtime"
LABEL description="Grok (xAI) agent runtime — grok-build-0.1 via opencode (OpenAI protocol)"
ENTRYPOINT ["/app/scripts/grok-agent-entrypoint.sh"]