From f52f7f63aa11bdf7b9acd707d2a485cf15cfef4f Mon Sep 17 00:00:00 2001 From: Daniel Kantor Date: Fri, 6 Mar 2026 12:55:11 +0100 Subject: [PATCH 1/8] Add devcontainer setup with Claude Code, thv, and mermaid MCP --- .devcontainer/devcontainer.json | 21 +++++++++++++++++++++ .devcontainer/setup.sh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100755 .devcontainer/setup.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..28a5fff --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,21 @@ +{ + "name": "thv + Claude Code", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "lts" + } + }, + "postCreateCommand": "bash .devcontainer/setup.sh", + "mounts": [ + "source=claude-code-config,target=/home/vscode/.claude,type=volume" + ], + "customizations": { + "vscode": { + "extensions": [ + "GitHub.copilot", + "GitHub.copilot-chat" + ] + } + } +} diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100755 index 0000000..305669b --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Install Claude Code (Node.js provided via devcontainer feature) +npm install -g @anthropic-ai/claude-code + +# Install thv (ToolHive) to ~/.local/bin +mkdir -p "$HOME/.local/bin" +THV_VERSION=$(curl -s https://api.github.com/repos/stacklok/toolhive/releases/latest | grep '"tag_name"' | cut -d'"' -f4 | sed 's/^v//') +curl -fsSL "https://github.com/stacklok/toolhive/releases/download/v${THV_VERSION}/toolhive_${THV_VERSION}_linux_amd64.tar.gz" \ + | tar -xz -C "$HOME/.local/bin" thv + +export PATH="$HOME/.local/bin:$PATH" + +# Ensure Claude Code config exists so thv can register itself +if [ ! -f "$HOME/.claude.json" ]; then + echo '{}' > "$HOME/.claude.json" +fi + +# Ensure VS Code Server MCP config exists so thv can register itself +mkdir -p "$HOME/.vscode-server/data/User" +if [ ! -f "$HOME/.vscode-server/data/User/mcp.json" ]; then + echo '{}' > "$HOME/.vscode-server/data/User/mcp.json" +fi + +# Register clients +thv client register claude-code +thv client register vscode-server + +# Start mermaid MCP server +thv run mermaid From c9a26efc7ce503dab9f8ae2b99cd90cff02092d3 Mon Sep 17 00:00:00 2001 From: Daniel Kantor Date: Fri, 6 Mar 2026 13:01:40 +0100 Subject: [PATCH 2/8] Skip Claude Code onboarding prompt on first launch --- .devcontainer/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 305669b..9800abd 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -14,7 +14,7 @@ export PATH="$HOME/.local/bin:$PATH" # Ensure Claude Code config exists so thv can register itself if [ ! -f "$HOME/.claude.json" ]; then - echo '{}' > "$HOME/.claude.json" + echo '{"hasCompletedOnboarding": true}' > "$HOME/.claude.json" fi # Ensure VS Code Server MCP config exists so thv can register itself From f9d8d0844cca3589c07c6ddbebd37ac5fa26974b Mon Sep 17 00:00:00 2001 From: Daniel Kantor Date: Fri, 6 Mar 2026 13:07:57 +0100 Subject: [PATCH 3/8] Add Docker-in-Docker for thv runtime and fix ~/.claude volume permissions --- .devcontainer/devcontainer.json | 3 ++- .devcontainer/setup.sh | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 28a5fff..85a33e6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,7 +4,8 @@ "features": { "ghcr.io/devcontainers/features/node:1": { "version": "lts" - } + }, + "ghcr.io/devcontainers/features/docker-in-docker:2": {} }, "postCreateCommand": "bash .devcontainer/setup.sh", "mounts": [ diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 9800abd..41375df 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -12,6 +12,9 @@ curl -fsSL "https://github.com/stacklok/toolhive/releases/download/v${THV_VERSIO export PATH="$HOME/.local/bin:$PATH" +# Fix ~/.claude volume permissions (volume may be created as root) +sudo chown -R vscode:vscode "$HOME/.claude" 2>/dev/null || true + # Ensure Claude Code config exists so thv can register itself if [ ! -f "$HOME/.claude.json" ]; then echo '{"hasCompletedOnboarding": true}' > "$HOME/.claude.json" From fa844d342bb1a1d0e3335d96e311482fd424d87a Mon Sep 17 00:00:00 2001 From: Daniel Kantor Date: Fri, 6 Mar 2026 14:09:06 +0100 Subject: [PATCH 4/8] Add fetch, osv, and semgrep MCP servers --- .devcontainer/setup.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 41375df..ec445c9 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -30,5 +30,8 @@ fi thv client register claude-code thv client register vscode-server -# Start mermaid MCP server +# Start MCP servers thv run mermaid +thv run fetch +thv run osv +thv run semgrep From 65cdfcdd09ba16c77e55d265c0ea4ffd8a5ff42d Mon Sep 17 00:00:00 2001 From: Daniel Kantor Date: Fri, 6 Mar 2026 14:22:30 +0100 Subject: [PATCH 5/8] Fix thv install (hardcode version), remove volume mount that was causing root ownership issues --- .devcontainer/devcontainer.json | 3 --- .devcontainer/setup.sh | 19 +++++++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 85a33e6..5c2e939 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -8,9 +8,6 @@ "ghcr.io/devcontainers/features/docker-in-docker:2": {} }, "postCreateCommand": "bash .devcontainer/setup.sh", - "mounts": [ - "source=claude-code-config,target=/home/vscode/.claude,type=volume" - ], "customizations": { "vscode": { "extensions": [ diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index ec445c9..789a8ba 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -6,19 +6,26 @@ npm install -g @anthropic-ai/claude-code # Install thv (ToolHive) to ~/.local/bin mkdir -p "$HOME/.local/bin" -THV_VERSION=$(curl -s https://api.github.com/repos/stacklok/toolhive/releases/latest | grep '"tag_name"' | cut -d'"' -f4 | sed 's/^v//') +THV_VERSION="0.11.0" curl -fsSL "https://github.com/stacklok/toolhive/releases/download/v${THV_VERSION}/toolhive_${THV_VERSION}_linux_amd64.tar.gz" \ | tar -xz -C "$HOME/.local/bin" thv export PATH="$HOME/.local/bin:$PATH" -# Fix ~/.claude volume permissions (volume may be created as root) -sudo chown -R vscode:vscode "$HOME/.claude" 2>/dev/null || true - -# Ensure Claude Code config exists so thv can register itself +# Ensure Claude Code config exists and onboarding is marked complete if [ ! -f "$HOME/.claude.json" ]; then - echo '{"hasCompletedOnboarding": true}' > "$HOME/.claude.json" + echo '{}' > "$HOME/.claude.json" fi +python3 -c " +import json, sys +path = '$HOME/.claude.json' +with open(path) as f: + config = json.load(f) +config['hasCompletedOnboarding'] = True +config['lastOnboardingVersion'] = '99.99.99' +with open(path, 'w') as f: + json.dump(config, f) +" # Ensure VS Code Server MCP config exists so thv can register itself mkdir -p "$HOME/.vscode-server/data/User" From a077d6a654734dd2c6f93c8216ba94d7c1ff7a1e Mon Sep 17 00:00:00 2001 From: Daniel Kantor Date: Fri, 6 Mar 2026 14:27:20 +0100 Subject: [PATCH 6/8] Revert to minimal working state: just mermaid, no Docker-in-Docker, hardcoded thv version --- .devcontainer/devcontainer.json | 3 +-- .devcontainer/setup.sh | 8 ++------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5c2e939..1b0608f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,8 +4,7 @@ "features": { "ghcr.io/devcontainers/features/node:1": { "version": "lts" - }, - "ghcr.io/devcontainers/features/docker-in-docker:2": {} + } }, "postCreateCommand": "bash .devcontainer/setup.sh", "customizations": { diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 789a8ba..6a004b6 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -6,8 +6,7 @@ npm install -g @anthropic-ai/claude-code # Install thv (ToolHive) to ~/.local/bin mkdir -p "$HOME/.local/bin" -THV_VERSION="0.11.0" -curl -fsSL "https://github.com/stacklok/toolhive/releases/download/v${THV_VERSION}/toolhive_${THV_VERSION}_linux_amd64.tar.gz" \ +curl -fsSL "https://github.com/stacklok/toolhive/releases/download/v0.11.0/toolhive_0.11.0_linux_amd64.tar.gz" \ | tar -xz -C "$HOME/.local/bin" thv export PATH="$HOME/.local/bin:$PATH" @@ -17,7 +16,7 @@ if [ ! -f "$HOME/.claude.json" ]; then echo '{}' > "$HOME/.claude.json" fi python3 -c " -import json, sys +import json path = '$HOME/.claude.json' with open(path) as f: config = json.load(f) @@ -39,6 +38,3 @@ thv client register vscode-server # Start MCP servers thv run mermaid -thv run fetch -thv run osv -thv run semgrep From 1975fdc4a464744cfcd65e304dcc3f3ed1604878 Mon Sep 17 00:00:00 2001 From: Daniel Kantor Date: Fri, 6 Mar 2026 14:29:35 +0100 Subject: [PATCH 7/8] Use node instead of python3 to patch claude.json (python3-minimal lacks stdlib) --- .devcontainer/setup.sh | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 6a004b6..8abd481 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -15,15 +15,13 @@ export PATH="$HOME/.local/bin:$PATH" if [ ! -f "$HOME/.claude.json" ]; then echo '{}' > "$HOME/.claude.json" fi -python3 -c " -import json -path = '$HOME/.claude.json' -with open(path) as f: - config = json.load(f) -config['hasCompletedOnboarding'] = True -config['lastOnboardingVersion'] = '99.99.99' -with open(path, 'w') as f: - json.dump(config, f) +node -e " +const fs = require('fs'); +const path = '$HOME/.claude.json'; +const config = JSON.parse(fs.readFileSync(path, 'utf8')); +config.hasCompletedOnboarding = true; +config.lastOnboardingVersion = '99.99.99'; +fs.writeFileSync(path, JSON.stringify(config)); " # Ensure VS Code Server MCP config exists so thv can register itself From 9f0f3065e0429c1ff4a3882fe292a4ef5e2d61d4 Mon Sep 17 00:00:00 2001 From: Daniel Kantor Date: Fri, 6 Mar 2026 14:32:59 +0100 Subject: [PATCH 8/8] Split setup: install on create, start servers on start using docker-outside-of-docker --- .devcontainer/devcontainer.json | 4 +++- .devcontainer/setup.sh | 5 +---- .devcontainer/start-servers.sh | 10 ++++++++++ 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100755 .devcontainer/start-servers.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1b0608f..c64b78e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,9 +4,11 @@ "features": { "ghcr.io/devcontainers/features/node:1": { "version": "lts" - } + }, + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} }, "postCreateCommand": "bash .devcontainer/setup.sh", + "postStartCommand": "bash .devcontainer/start-servers.sh", "customizations": { "vscode": { "extensions": [ diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 8abd481..392d9c1 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -30,9 +30,6 @@ if [ ! -f "$HOME/.vscode-server/data/User/mcp.json" ]; then echo '{}' > "$HOME/.vscode-server/data/User/mcp.json" fi -# Register clients +# Register clients (Docker not needed for registration) thv client register claude-code thv client register vscode-server - -# Start MCP servers -thv run mermaid diff --git a/.devcontainer/start-servers.sh b/.devcontainer/start-servers.sh new file mode 100755 index 0000000..3bd9c94 --- /dev/null +++ b/.devcontainer/start-servers.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +export PATH="$HOME/.local/bin:$PATH" + +# Start MCP servers (requires Docker, runs on every Codespace start) +thv run mermaid 2>/dev/null || true +thv run fetch 2>/dev/null || true +thv run osv 2>/dev/null || true +thv run semgrep 2>/dev/null || true