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-mcpas a subprocess, the bridge forwards tohttp://localhost:3000. - streamable-http (recommended where supported, since T302a): Claude Code connects directly to
http://localhost:3000/api/v1/mcp/ssevia its--transport httpflag.
Prerequisites
- A running helmdeck stack on the host (
./scripts/install.shfrom a clone oftosin2013/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.
2a. Direct streamable-http path (T302a — recommended)
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 /mcp — helmdeck 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:
repo.fetchgit@github.com:<me>/<fixture-repo>.gitusing vault credentialgh-deploy-key.fs.listthe clone for*.mdfiles.fs.readthe README and propose a one-line edit.fs.patchto apply the edit (literal search-and-replace).cmd.rungo test ./...(or any project check) in the clone.git.commitwith messagechore: helmdeck integration smoke.repo.pushback toorigin.
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
/mcpshowshelmdeckas failing — for stdio path, runhelmdeck-mcpdirectly in a shell with the same env vars to see the error. For HTTP path, checkcurl -H "Authorization: Bearer $JWT" http://localhost:3000/api/v1/mcp/ssereturns the SSE handshake frame.unauthorizedon every pack call — JWT expired or wrong scope. Mint a new one in the API Tokens panel.repo.fetchreturnsinvalid_input: ssh key not found— credential name must match the vault entry exactly (case-sensitive).git.commitreturnsinvalid_input: nothing to commit—fs.patchwas a no-op; check the search string matches the file contents byte-for-byte (literal, not regex).