Skillshare skillshare-devcontainer
git clone https://github.com/runkids/skillshare
T=$(mktemp -d) && git clone --depth=1 https://github.com/runkids/skillshare "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.skillshare/skills/skillshare-devcontainer" ~/.claude/skills/runkids-skillshare-skillshare-devcontainer && rm -rf "$T"
.skillshare/skills/skillshare-devcontainer/SKILL.mdExecute CLI commands and tests inside the devcontainer. The host machine is macOS but the project binary is Linux — running CLI commands on the host will silently produce wrong results or fail. This skill prevents that mistake.
When to Use This
- Running
/ss
commands for verificationskillshare - Running
,go test
,make testmake check - Reproducing a bug report
- Testing a feature you just implemented
- Starting the web UI dashboard
- Any command that needs the skillshare binary or Go toolchain
When NOT to Use This
- Editing source code (do that on host via Read/Edit tools)
- Running
commands (git works on host)git - Running
,make fmt
(host-safe Go toolchain commands; no container needed)make lint - E2E test runbooks → use
skill instead (it handles ssenv isolation)cli-e2e-test
Architecture: Two Layers of Isolation
Host (macOS) └─ Devcontainer (Linux, Debian-based) ├─ Default HOME: /home/developer (persistent volume) ├─ Source: /workspace (bind-mount of repo root) └─ ssenv environments: ~/.ss-envs/<name>/ (isolated HOME dirs)
Devcontainer = Linux environment with Go, git, pnpm, air (hot-reload). Source code is at
/workspace (bind-mount of the host repo). The ss / skillshare wrapper auto-builds from source on every invocation — no manual make build needed. Edit code on the host, then immediately docker exec to run it; the change is picked up automatically.
ssenv = Isolated HOME directories within the devcontainer. Each env gets its own
~/.config/skillshare/, ~/.claude/, etc. Use ssenv when you need a clean state (testing init, install, sync) without polluting the container's default HOME.
Zero-Rebuild Workflow
Source code is bind-mounted into the container at
/workspace. The ss wrapper runs go build transparently on every invocation:
- Edit files on host (Read/Edit tools)
— picks up your changes instantlydocker exec $CONTAINER ss <command>- No
, no restart, no rebuild stepmake build
This also applies to
go test — tests always compile against the latest source. The Web UI backend uses air for hot-reload (same zero-rebuild experience).
Entering the Devcontainer
The quickest way — one command builds, initialises, and enters the shell:
make devc # build + init + interactive shell (one step) make devc-up # start only (no shell) make devc-down # stop make devc-restart # restart + re-run start-dev.sh make devc-reset # full reset (remove volumes), then `make devc` to re-init make devc-status # show container status
Works with or without VS Code —
make devc handles the full lifecycle autonomously.
Programmatic access (for docker exec
workflows)
docker execCONTAINER=$(docker compose -f .devcontainer/docker-compose.yml ps -q skillshare-devcontainer 2>/dev/null)
If
$CONTAINER is empty, tell the user:
Devcontainer is not running. Start it with
.make devc-up
Then verify the binary:
docker exec $CONTAINER bash -c \ '/workspace/.devcontainer/ensure-skillshare-linux-binary.sh && ss version'
Running Commands
Simple command (uses container's default HOME)
docker exec $CONTAINER ss <command> [flags]
Good for:
ss version, ss status, ss list, ss check, ss audit.
Command with isolated HOME (clean state)
ENV_NAME="test-$(date +%s)" docker exec $CONTAINER ssenv create "$ENV_NAME" --init docker exec $CONTAINER ssenv enter "$ENV_NAME" -- ss status # Cleanup when done: docker exec $CONTAINER ssenv delete "$ENV_NAME" --force
Good for: testing
init, install, sync, uninstall — anything that modifies config/state.
Multi-command sequence
docker exec $CONTAINER ssenv enter "$ENV_NAME" -- bash -c ' ss install runkids/demo-skills --track --force ss list ss sync '
Always use
bash -c '...' for multi-command sequences inside ssenv enter.
Go tests
# All tests (unit + integration) docker exec $CONTAINER bash -c 'cd /workspace && make test' # Unit tests only docker exec $CONTAINER bash -c 'cd /workspace && make test-unit' # Integration tests only docker exec $CONTAINER bash -c 'cd /workspace && make test-int' # Specific test docker exec $CONTAINER bash -c 'cd /workspace && go test ./tests/integration -run TestInit_Fresh -count=1' # Specific package docker exec $CONTAINER bash -c 'cd /workspace && go test ./internal/install/... -count=1'
Always
cd /workspace before Go commands — ssenv changes HOME which can break module resolution.
Go tests with auth disabled
Some tests (e.g.,
TestResolveToken, TestAuthEnv) need auth credentials removed:
docker exec $CONTAINER bash -c ' eval "$(credential-helper --eval off)" cd /workspace go test ./internal/github -run TestResolveToken -count=1 eval "$(credential-helper --eval on)" '
Web UI Dashboard
# Start (global mode) docker exec $CONTAINER ui # Start (project mode — uses ~/demo-project) docker exec $CONTAINER ui -p # Stop docker exec $CONTAINER ui stop
Dashboard accessible at
http://localhost:5173 (Vite dev server with HMR).
API backend at http://localhost:19420.
Logs: /tmp/api-dev.log, /tmp/vite-dev.log.
ssenv Quick Reference
| Shortcut | Full form | Purpose |
|---|---|---|
| + enter | Create and enter isolated shell |
| | Enter existing isolated shell |
| | Delete environment |
| | List all environments |
| | Leave isolated context |
| | Show all devcontainer commands |
For automation (non-interactive), prefer
ssenv enter <name> -- <command> over ssnew/ssuse (which launch subshells).
Ports
| Port | Service | Notes |
|---|---|---|
| 5173 | Vite dev server | React dashboard with HMR |
| 19420 | Go API backend | server |
| 3000 | Docusaurus | command in devcontainer |
Common Mistakes to Avoid
- Running
on host — macOS binary won't match Linux container; alwaysssdocker exec - Forgetting
— Go tests fail if HOME was changed by ssenvcd /workspace - Using
on host — builds macOS binary, then tests run against wrong archmake test - Skipping
on ssenv create — env won't have config; most commands will fail--init - Not cleaning up ssenv —
after done; or ask userssenv delete <name> --force - Running from /workspace root without -g — the
wrapper auto-redirects toss
in project mode; use~/demo-project
for global or set-gSKILLSHARE_DEV_ALLOW_WORKSPACE_PROJECT=1 - Running
before testing — unnecessary; themake build
wrapper auto-builds from source every timess
Rules
- All CLI execution inside devcontainer — no exceptions
- Use ssenv for stateful tests — don't pollute default HOME
- Always verify — run the command and check output; never assume it worked
- Clean up — delete ssenv environments after use (or ask user)
- Report container ID — set
at the start and reuse throughout$CONTAINER