Execute 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.
Before acting, run python3 scripts/ai-context.py testing and follow that topic. The topic is the source of truth for repository execution boundaries and test rules; this skill retains the interactive workflow and command recipes.
When to Use This
- Running
ss / skillshare commands for verification
- Running
go test, make test, make 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
git commands (git works on host)
- Running
make fmt, make lint (host-safe Go toolchain commands; no container needed)
- E2E test runbooks → use
cli-e2e-test skill instead (it handles ssenv isolation)
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)
docker exec $CONTAINER ss <command> — picks up your changes instantly
- No
make build, no restart, no rebuild step
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)
CONTAINER=$(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
Token-resolution tests (TestResolveToken, TestAuthEnv in internal/install) need auth credentials removed:
docker exec $CONTAINER bash -lc '
eval "$(credential-helper --eval off)"
cd /workspace
go test ./internal/install -run "TestResolveToken|TestAuthEnv" -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:45173 (Vite dev server with HMR).
API backend at http://localhost:49420.
Logs: /tmp/api-dev.log, /tmp/vite-dev.log.
ssenv Quick Reference
| Shortcut | Full form | Purpose |
|---|
ssnew <name> | ssenv create <name> + enter | Create and enter isolated shell |
ssuse <name> | ssenv enter <name> | Enter existing isolated shell |
ssrm <name> | ssenv delete <name> --force | Delete environment |
ssls | ssenv list | List all environments |
ssback | ssenv reset | Leave isolated context |
sshelp | help | Show all devcontainer commands |
For automation (non-interactive), prefer ssenv enter <name> -- <command> over ssnew/ssuse (which launch subshells).
Ports
| Port | Service | Notes |
|---|
| 45173 | Vite dev server | React dashboard with HMR |
| 49420 | Go API backend | skillshare ui server |
| 48888 | Docusaurus | docs command in devcontainer |
Common Mistakes to Avoid
- Running
ss on host — macOS binary won't match Linux container; always docker exec
- Forgetting
cd /workspace — Go tests fail if HOME was changed by ssenv
- Using
make test on host — builds macOS binary, then tests run against wrong arch
- Skipping
--init on ssenv create — env won't have config; most commands will fail
- Not cleaning up ssenv —
ssenv delete <name> --force after done; or ask user
- Running from /workspace root without -g — the
ss wrapper auto-redirects to ~/demo-project in project mode; use -g for global or set SKILLSHARE_DEV_ALLOW_WORKSPACE_PROJECT=1
- Running
make build before testing — unnecessary; the ss wrapper auto-builds from source every time
Rules
Apply the testing topic. If a command recipe here conflicts with that topic or current repo configuration, verify the current configuration and update both in the same change.