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

Tip: Helmdeck is published on the official MCP Registry as io.github.tosin2013/helmdeck. If you'd rather use the registry-aware install path that's identical across every MCP client, see Register helmdeck with your MCP client. The Claude-Code-specific steps below remain valid and produce the same end state.

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. Load the agent skills

Claude Code auto-loads a CLAUDE.md from the working directory on every invocation. The helmdeck pack catalog, schemas, error-handling rules, session-chaining contract, and freshness contract all live in SKILLS.md — drop them into your project's CLAUDE.md so the model has the full skill in context before its first turn:

# From the project where you'll run claude:
curl -fsSL https://raw.githubusercontent.com/tosin2013/helmdeck/main/docs/integrations/SKILLS.md \
> CLAUDE.md

If your project already has a CLAUDE.md you want to keep, append instead:

echo >> CLAUDE.md && curl -fsSL https://raw.githubusercontent.com/tosin2013/helmdeck/main/docs/integrations/SKILLS.md \
>> CLAUDE.md

For a project-wide skill that applies to every helmdeck-using repo, see Claude Code's --append-system-prompt flag.

Structured .claude/skills/ install (from a checkout)

If you have the helmdeck repo checked out, scripts/configure-claude.sh installs every skill as an invocable Claude Code skill under <project>/.claude/skills/<name>/SKILL.md (re-stamping helmdeckVersion from git HEAD), instead of pasting into CLAUDE.md:

# From the helmdeck checkout; --project defaults to $PWD:
./scripts/configure-claude.sh --project /path/to/your/project

This installs both helmdeck (the pack catalog/contracts) and helmdeck-debug (an integration debugger you can invoke to audit pipelines + draft GitHub issues — see helmdeck-debug.md). Restart Claude Code so it picks up .claude/skills/.

Verify: run claude in that directory and ask "what helmdeck packs do you know about?" — the model should list the full catalog (browser, web, repo, github, fs, cmd, git, http, doc, slides, vision, language). If it doesn't, the skill didn't load.

Refresh after pulling a new helmdeck release — the catalog grows over time.

4. (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.

5. 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).