Skip to main content

Claude Code

Status: 🟡 Documented, not yet verified end-to-end Setup is documented; the connect snippet is generated by /api/v1/connect/claude-code. Promote to ✅ once a maintainer has walked the Phase 5.5 loop with this client against a real private GitHub repo.

Topology

Claude Code is Topology B — both helmdeck and Claude Code run on the same host. Claude Code connects via either:

  • stdio bridge (universal path): Claude Code spawns helmdeck-mcp as a subprocess, the bridge forwards to http://localhost:3000.
  • streamable-http (recommended where supported, since T302a): Claude Code connects directly to http://localhost:3000/api/v1/mcp/sse via its --transport http flag.

Prerequisites

  • A running helmdeck stack on the host (./scripts/install.sh from a clone of tosin2013/helmdeck).
  • Helmdeck control-plane URL (http://localhost:3000) and a JWT from the API Tokens panel.
  • Claude Code installed.
  • A private GitHub repo plus an SSH deploy key loaded into the Credential Vault as type ssh-git.

1. Install Claude Code

# Native installer (macOS/Linux/WSL2 — recommended)
curl -fsSL https://claude.ai/install.sh | bash

# Or Homebrew on macOS
brew install --cask claude-code

Verify: claude --version. (The legacy npm install -g @anthropic-ai/claude-code is deprecated.)

Source: https://code.claude.com/docs/en/setup

2. Add helmdeck as an MCP server

JWT="<your helmdeck JWT>"
claude mcp add helmdeck \
--transport http \
--url http://localhost:3000/api/v1/mcp/sse \
--header "Authorization: Bearer $JWT"

2b. Stdio bridge path (universal fallback)

First install the helmdeck-mcp bridge binary:

brew install tosin2013/helmdeck/helmdeck-mcp # macOS/Linux
# OR
go install github.com/tosin2013/helmdeck/cmd/helmdeck-mcp@latest

Then register it:

claude mcp add helmdeck \
--transport stdio \
--command helmdeck-mcp \
--env HELMDECK_URL=http://localhost:3000 \
--env HELMDECK_TOKEN="$JWT"

Either path writes the entry into ~/.claude.json (user scope) or .mcp.json (project scope, committed to your repo).

Run claude and execute /mcphelmdeck should show as connected with the full pack catalog.

Source: https://code.claude.com/docs/en/mcp

3. (Optional) Route Claude Code's LLM through helmdeck — blocked on T201b

Claude Code reads ANTHROPIC_BASE_URL to point at an LLM gateway. The gateway must speak Anthropic's /v1/messages shape, not OpenAI's /v1/chat/completions. Helmdeck currently only exposes the OpenAI shape, so this path is blocked until T201b lands an Anthropic-compatible facade. Until then, Claude Code uses its own Anthropic credentials directly and helmdeck sees only the MCP tool calls (not the LLM dispatches).

Tracking: T201b in docs/MILESTONES.md.

4. Walk the Phase 5.5 code-edit loop

Prompt Claude Code:

Use the helmdeck packs to:

  1. repo.fetch git@github.com:<me>/<fixture-repo>.git using vault credential gh-deploy-key.
  2. fs.list the clone for *.md files.
  3. fs.read the README and propose a one-line edit.
  4. fs.patch to apply the edit (literal search-and-replace).
  5. cmd.run go test ./... (or any project check) in the clone.
  6. git.commit with message chore: helmdeck integration smoke.
  7. repo.push back to origin.

Pass criteria:

  • The new commit lands on the remote branch.
  • The Audit Logs panel in the helmdeck UI shows one entry per pack call, in order.
  • Grep the Claude Code session transcript — the SSH private key must not appear; only the ${vault:gh-deploy-key} placeholder.

Troubleshooting

  • /mcp shows helmdeck as failing — for stdio path, run helmdeck-mcp directly in a shell with the same env vars to see the error. For HTTP path, check curl -H "Authorization: Bearer $JWT" http://localhost:3000/api/v1/mcp/sse returns the SSE handshake frame.
  • unauthorized on every pack call — JWT expired or wrong scope. Mint a new one in the API Tokens panel.
  • repo.fetch returns invalid_input: ssh key not found — credential name must match the vault entry exactly (case-sensitive).
  • git.commit returns invalid_input: nothing to commitfs.patch was a no-op; check the search string matches the file contents byte-for-byte (literal, not regex).