Image: kpericak/ai-agent-runtime:0.4
Source: infra/ai-agents/ai-agent-runtime/
Base: mcr.microsoft.com/playwright:v1.58.2-noble (Ubuntu, glibc)
Runtime environment for autonomous AI agent pods. Used by the agent controller to run Claude Code agents in Kubernetes Jobs.
| Tag | Base | Key changes |
|---|---|---|
| 0.2 | Node 22 Alpine | Initial: Claude Code + OpenCode |
| 0.3 | Playwright noble | Switched to glibc for Chromium/Playwright support |
| 0.4 | Playwright noble | Added jq, baked in Claude Code hooks + settings.json |
| Tool | Version | Purpose |
|---|---|---|
| Claude Code CLI | latest (npm) | Anthropic agent CLI |
| OpenCode | 0.0.55 | Alternative agent CLI |
| Playwright MCP | latest (npm) | Browser automation for QA |
| jq | system | JSON parsing in hooks |
| gh | latest | GitHub CLI |
| mcp[cli], httpx | pip | Python MCP server deps (Discord) |
| git | system | Version control |
| python3 | system | Script execution + MCP servers |
| bash, curl, openssh-client | system | Shell utilities |
Runs as non-root pwuser (UID 1001, from Playwright base).
The image bakes in a PostToolUse hook at
/home/pwuser/.claude/hooks/discord-log.sh that posts tool call
summaries to Discord #log. Configured in
/home/pwuser/.claude/settings.json.
What gets posted: Write, Edit, Bash, Agent, and MCP tool calls with a truncated param preview. Read/Glob/Grep are skipped (too noisy).
Rate limiting: File-based throttle at 1.2s between posts. Discord allows 5 messages per 5 seconds per channel.
Env vars needed: DISCORD_BOT_TOKEN, DISCORD_LOG_CHANNEL_ID,
RUN_ID (injected by controller).
The settings.json also includes wide permissions (Bash(*),
Edit, Write, etc.) to prevent permission prompts in headless
mode. The container is already sandboxed by K8s SecurityContext.
Claude Code .claude.json with {"hasCompletedOnboarding": true}
is baked into the image at /home/pwuser/.claude.json to skip the
interactive onboarding in headless mode.
Python deps (Discord MCP server) are installed in the image via pip:
mcp[cli]>=1.2.0 and httpx>=0.27.0.
Node.js deps (google-news MCP server) are no longer used by the controller. The journalist agent uses WebSearch instead.
Python deps (Discord MCP server) are installed in the image via pip:
mcp[cli]>=1.2.0 and httpx>=0.27.0.
Node.js deps (google-news MCP server) are no longer used by the controller. The journalist agent uses WebSearch instead.
The agent controller creates Jobs with this image. An init container
(alpine/git) clones the repo and chowns the workspace to UID 1001,
then the agent runs in this container.
The publisher agent uses apps/blog/bin/run-publisher.sh which creates
a branch, runs claude --agent publisher with --output-format stream-json --verbose --include-partial-messages, and reports the
result. The --include-partial-messages flag surfaces subagent events
(researcher, reviewer, QA) in the parent's stream for full visibility.
The controller injects these via a K8s Secret:
| Variable | Purpose |
|---|---|
CLAUDE_CODE_OAUTH_TOKEN |
Claude Max OAuth token (publisher) |
ANTHROPIC_BASE_URL |
OpenRouter API endpoint (journalist) |
ANTHROPIC_AUTH_TOKEN |
OpenRouter API key (journalist) |
DISCORD_BOT_TOKEN |
Discord bot token for MCP + hooks |
DISCORD_GUILD_ID |
Default Discord guild ID |
DISCORD_LOG_CHANNEL_ID |
Discord #log channel for hook posts |
RUN_ID |
UUID prefix for correlating Discord messages |
REPO_URL |
Git repo URL for init container |
REPO_BRANCH |
Branch to checkout (default: main) |
# Test MCP server startup
python3 apps/mcp-servers/discord/server.py
# If import error → pip deps missing from image, rebuild
# Check Claude Code version
claude --version
# Test a simple headless run
claude -p "echo hello" --output-format json --allowedTools Write --max-turns 3
The QA subagent needs a running web server to verify blog post rendering
with Playwright. next dev compiles pages on first request and is too
resource-heavy for K8s pods (hangs or OOMKills on a 4GB node).
Instead, the QA agent uses apps/blog/bin/start-static-server.sh:
bin/build-blog-files.sh (next build → out/)out/ with python3 -m http.server 3000next dev)The qa.md agent definition includes instructions to detect the
container environment and choose the right server.
infra/ai-agents/ai-agent-runtime/Dockerfileinfra/ai-agents/ai-agent-runtime/hooks/discord-log.sh — PostToolUse hookinfra/ai-agents/ai-agent-runtime/claude-settings.json — Permissions + hook configapps/blog/bin/start-static-server.sh — Container-friendly QA server