From light-process
Develop a light-process node inside a VS Code dev container that mirrors its production Docker image, with automatic `.env` loading. Use this skill whenever the user runs or asks about `light node dev`, wants to code a node in the same image used at runtime, generates or refreshes a `.devcontainer/devcontainer.json` from `.node.json`, hits "code command not found" when opening, needs to rebuild the container after changing `setup`, or wants environment variables loaded into the container without copy-pasting. Also trigger when the user mentions devcontainers, container-based development, "iterate on a node", `.env` files, `env-file`, auto-detect env vars, secrets in container, loading environment variables, or `${localEnv:...}` placeholders in this repo, even if they do not name the command explicitly.
How this skill is triggered — by the user, by Claude, or both
Slash command
/light-process:node-devThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
`light node dev <dir>` reads `<dir>/.node.json`, generates `<dir>/.devcontainer/devcontainer.json` from it, then opens VS Code on `<dir>`. The result: the node is edited and run inside the exact image used in production by light-run, with no host toolchain required.
light node dev <dir> reads <dir>/.node.json, generates <dir>/.devcontainer/devcontainer.json from it, then opens VS Code on <dir>. The result: the node is edited and run inside the exact image used in production by light-run, with no host toolchain required.
The point is parity. A node ships as a container, so coding in that container catches "works on my machine" bugs early: missing system libs, Node or Python version mismatch, native binding ABI, glibc/musl differences. Without this, the dev would need every node's toolchain installed locally.
light node dev <dir> # generate (if missing) and open VS Code
light node dev <dir> --force # regenerate even if devcontainer.json exists
light node dev <dir> --env-file <path> # use a specific .env file (override auto-detection)
When the prompt appears, press Enter or Space to open VS Code, or q / Esc to quit without opening. If a .env file is in play, the CLI prints its absolute path right before the prompt so the choice can be validated before VS Code spawns.
Every field is derived from .node.json plus the auto-detected .env. Nothing else is added.
| devcontainer field | source | notes |
|---|---|---|
name | .node.json:name | falls back to "node" |
image | .node.json:image | required, errors out if missing |
workspaceFolder | .node.json:workdir | falls back to /app |
workspaceMount | derived from workdir | bind mount of ${localWorkspaceFolder} to workdir |
postCreateCommand | .node.json:setup | joined with &&, omitted if setup is empty |
remoteEnv | .node.json:env | each name maps to ${localEnv:NAME} |
runArgs | first .env found walking up, or --env-file flag | ["--env-file", "<abs path>"], omitted when no file is found |
customizations.vscode.extensions | image prefix | auto-picked, see table below |
pickExtensions(image) matches the lowercased image string. Custom or registry-prefixed images (for example ghcr.io/org/python:3.12) do not match and produce no extensions. Add them by hand after generation if needed.
| Image pattern | Extension |
|---|---|
starts with node: or contains -node: / -node- | dbaeumer.vscode-eslint |
starts with python: | ms-python.python |
starts with openjdk:, eclipse-temurin:, maven:, gradle: | vscjava.vscode-java-pack |
starts with rust: | rust-lang.rust-analyzer |
starts with golang: or go: | golang.go |
| anything else | none |
Two mechanisms work side by side. Use them for different shapes of data.
.env auto-detection (bulk)The CLI walks up from the node folder, up to 5 levels (node dir, workflow root, parent, grandparent, great-grandparent), and picks the first .env it finds. The closest one wins, so a node-local .env overrides a workflow-root .env. When found, the generated devcontainer.json gets:
"runArgs": ["--env-file", "/abs/path/to/.env"]
Docker reads that file at container start and injects every variable into the container's environment. No host shell export required, no copy-pasting var names. Pass --env-file <path> to skip auto-detection and pin a specific file. The CLI errors out before doing anything else if the path does not exist.
The .env should be gitignored. Docker reads it on the host at runtime, so the secrets never enter the committed devcontainer.json.
.node.json:env array (host-shell vars)Names listed in .node.json's env array become ${localEnv:NAME} entries in remoteEnv. They are read from the host shell that launched VS Code, not from a file. Use this for one-off vars that live in your shell session (a fresh OAuth token, a CI-injected secret) but are not in any .env.
If both mechanisms target the same variable, the .env value wins because Docker applies --env-file to the container itself, while remoteEnv only scopes to the VS Code remote server process.
| State | Default behavior | With --force |
|---|---|---|
| File present and valid JSON | Open as-is, no overwrite | Overwrite from .node.json and current .env |
| File present but malformed JSON | Abort with parse error | Overwrite from .node.json and current .env |
| File missing | Generate from .node.json and current .env | Same as default |
Without --force, a stale devcontainer.json keeps using the env file recorded at the last generation. After moving or renaming a .env, regenerate with --force so the new path lands in runArgs. After regenerating, VS Code reuses the existing built container; pick up new setup or new env values by running Dev Containers: Rebuild Container from the VS Code Command Palette.
| Symptom | Fix |
|---|---|
No .node.json in <dir>. Run 'light init --node' first. | Run light init --node or change to the right folder. |
.node.json has no 'image'. | Add "image": "node:20-slim" (or similar) to .node.json. |
Failed to parse existing devcontainer.json | Re-run with --force to regenerate, or fix the JSON manually. |
--env-file: <path> not found. | The path passed to --env-file does not exist. Check spelling and absolute vs relative resolution. |
Container does not see vars from .env | Confirm the summary shows env-file: <path>. If (none), the file was not found in the 5-level walk; pass --env-file explicitly or move the file closer to the node. |
Vars updated in .env but container still has old values | VS Code is reusing the running container. Run Dev Containers: Rebuild Container. |
Wrong .env was picked (a parent one instead of node-local) | The closest one should win. Place the node-local .env directly in the node folder, or pass --env-file to override. |
'code' command not found on PATH. | In VS Code, run Shell Command: Install 'code' command in PATH from the Command Palette. |
Setup did not run after --force | VS Code reuses the existing container. Use Dev Containers: Rebuild Container. |
| Wrong or missing extensions for a custom image | Edit customizations.vscode.extensions in the generated file by hand. |
| Command | Purpose |
|---|---|
light init --node | Scaffold a new node folder with a starter .node.json. |
light node info <dir> | Show the node's metadata, schema, and incoming links. |
light node schema <dir> | Edit the input/output JSON Schema interactively. |
light node helpers <dir> | Regenerate lp.d.ts from the schema after editing .node.json by hand. |
light node register <dir> | Add the node folder to its parent workflow.json. |
Implementation reference: src/cli/node-dev.ts.
npx claudepluginhub enixcode/plugins --plugin light-processGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.