Skip to content
MCP Servers
Skill

/devcontainer-dev

Spin up and interact with ToolHive Studio's containerized dev environment (Xvfb + noVNC + DinD). Use when running, testing, or debugging the app in isolation — locally, in a git worktree, or in GitHub Codespaces; when touching `.devcontainer/*`, `scripts/devcontainer-*.sh`, or

From plugin
toolhive-studio
1639 skills
Install
$ npx -y skills add stacklok/toolhive-studio --skill devcontainer-dev --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/devcontainer-dev

Context preview

The summary Claude sees to decide when to auto-load this skill.

Spin up and interact with ToolHive Studio's containerized dev environment (Xvfb + noVNC + DinD). Use when running, testing, or debugging the app in isolation — locally, in a git worktree, or in GitHub Codespaces; when touching `.devcontainer/*`, `scripts/devcontainer-*.sh`, or

SKILL.md

devcontainer-dev.SKILL.md
name: devcontainer-dev
description: Spin up and interact with ToolHive Studio's containerized dev environment (Xvfb + noVNC + DinD). Use when running, testing, or debugging the app in isolation — locally, in a git worktree, or in GitHub Codespaces; when touching `.devcontainer/*`, `scripts/devcontainer-*.sh`, or the `devContainer:dev` npm script; or when debugging "blank white window", "Docker daemon failed to start", or "Missing X server" errors in the devcontainer. The container is fully isolated: no host pnpm install, no host Docker socket, no host X11/GPU — experiment freely without contaminating the host.
allowed-tools: Read, Grep, Glob, Bash

Containerized Dev Environment

An isolated, cross-platform test environment for ToolHive Studio. The whole Electron app — including its backend `thv` binary and the MCP-server containers it spawns — runs inside a single devcontainer. You interact with the UI via a noVNC browser tab.

The entire stack (Node, Electron, display server, window manager, VNC server, Docker-in-Docker, DBus, keyring) lives in the container. **Nothing is installed on the host.** That's the whole point: every worktree can have its own container and its own experiments, with zero risk of contaminating the user's global installs.

---

Entry point

pnpm devContainer:dev

runs `scripts/devcontainer-dev.sh` on the host. The script is "smart":

  • If executed on the host: runs `devcontainer up` to build/start the container, then `devcontainer exec` to run the entrypoint inside it.
  • If executed inside a container (detected via `/.dockerenv`): skips the build step and just runs the entrypoint directly. This path is used by GitHub Codespaces.

---

The three scripts

| Script | Runs on | Purpose | | ------------------------------------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `scripts/devcontainer-dev.sh` | host | Picks a host port, kills stale processes, starts readiness poller, opens browser when ready, `devcontainer exec`s the entrypoint. | | `scripts/devcontainer-entrypoint.sh` | in container | Cleans stale X/VNC state, starts Xvfb, fluxbox, x11vnc, websockify/noVNC, dbus, gnome-keyring, then runs `pnpm start`. | | `scripts/devcontainer-post-start.sh` | in container | `postStartCommand` in `devcontainer.json`. In Codespaces (detected via `$CODESPACES`) it `nohup`-launches the entrypoint in the background so the noVNC preview pane opens without user action. |

---

What the container runs

  • **Node 24** (matches `.nvmrc`)
  • **Electron + runtime deps** — GTK, NSS, X11, etc. (see `.devcontainer/Dockerfile`)
  • **Display stack** — Xvfb (virtual framebuffer at 1920×1200), fluxbox (window manager, auto-fullscreens windows with `WM_CLASS=ToolHive`), x11vnc (VNC server), noVNC + websockify (browser client on port 6080)
  • **Secret provider stack** — dbus + gnome-keyring. Required by ToolHive's secret API; without them the backend returns 500 on secrets endpoints. Mirrors the setup in `.github/workflows/_e2e.yml`.
  • **Docker-in-Docker** via the `docker-in-docker:2` devcontainer feature. Supplies `/var/run/docker.sock` inside the container so the bundled `thv` CLI can spawn MCP-server containers.

---

Finding the URL (the logs are very long)

`pnpm start` + electron-forge + Vite + Electron + HMR produce a **lot** of output. The terminal scrollback often exhausts. Three recovery mechanisms are built in:

1. **Written to a file** by the launcher: `~/.cache/toolhive-studio-url`. Survives any amount of output.

   cat ~/.cache/toolhive-studio-url

2. **Set as the terminal tab title** via OSC escape. Visible in the tab bar of most terminals regardless of scrollback state. 3. **Prominent banners** in the output — a green initial block right after `devcontainer up`, plus an inverse-video `✓ ToolHive ready — <URL>` banner that fires only once the app is actually usable.

If you're piping the output:

pnpm devContainer:dev 2>&1 | tee /tmp/dev.log
# later:
grep -E 'ToolHive ready|vnc\.html' /tmp/dev.log

The readiness banner is what you care about. It gates on **three** signals simultaneously:

  • noVNC's HTTP endpoint answers (the browser tab will actually load)
  • The Electron binary is running (matched via `pgrep -f 'electron/dist/electron'`)
  • `thv serve` is running (matched via `pgrep -f 'thv serve'` — _not_ `pgrep -x thv`, because the short-lived version-check invocation also matches on bare name)

Only once all three are true does the banner fire and the host's browser auto-open.

---

Per-worktree isolation

Each git worktree gets its own independent devcontainer:

  • **Container identity** — labelled with `devcontainer.local_folder=<absolute-worktree-path>`. The devcontainer CLI uses this to decide which container to reuse vs create fresh.
  • **Node modules** — volume named `toolhive-node-modules-<basename>`, scoped to the worktree's basename. No cross-worktree install pollution.
  • **Host port** — the primary clone uses `:6080`; additional worktrees try `:6080` first and fall back to a Docker-assigned random port if it's taken. So multiple worktrees can run simultaneously. The actual bound port is queried with `docker port "$CONTAINER_ID" 6080/tcp` and the URL is generated from that.
  • **DinD, display state, keyring, etc.** — all container-local. Tearing down a worktree's container removes all of it.

**The host is never touched** — no host-side `pnpm install`, no host-side `/tmp/.X11-unix` mount, n

Read more
Ships withtoolhive-studio

Run any Model Context Protocol (MCP) server — securely, instantly, anywhere. ToolHive is the easiest way to discover, deploy, and manage MCP servers. Launch any MCP server in a locked-down container with just a few clicks.

Get the whole plugin
Stats
163
Stars
22
Forks
Active
Maintenance
TypeScript
Language
Apache-2.0
License
6h ago
Last commit
1y ago
Created

Repo: stacklok/toolhive-studio