npx skills add ...
npx skills add affaan-m/ecc --skill docker-patterns
Docker and Docker Compose patterns for local development, hardened CLI installer harnesses, container security, networking, volumes, and multi-service orchestration. Use when creating or reviewing Dockerfiles and Compose services, testing installers across Linux distributions, or planning accurate native macOS and Windows validation.
npx skills add affaan-m/ecc --skill docker-patterns
Docker and Docker Compose best practices for containerized development.
Services in the same Compose network resolve by service name:
Use containers to test installer behavior against disposable project copies without allowing the test to mutate the source checkout.
Do not claim that a Linux container validates macOS or Windows behavior.
tmpfs workspace before any mutation./workspace with noexec, UID/GID 1000, and mode=0700 so only the
container user can inspect project data.NPM_CONFIG_CACHE=/tmp/npm-cache on
the executable /tmp mount. Its default size is 2 GiB and can be adjusted
with ECC_TMPFS_SIZE; ECC_WORKSPACE_SIZE separately controls the private
workspace mount.read_only: true, no-new-privileges:true, cap_drop: [ALL], and a finite pids_limit.network_mode: none. Add network access
only through a visibly named opt-in service for an authenticated provider
session; never make it an accidental environment-driven default.dry-run, install,
plugin, and shell modes.spawnSync(..., { shell: false }) for cross-platform runners. Never interpolate project paths into a shell command.Use docker/plugin-setup/compose.yaml as the reference implementation. It provides:
fixture-tests for the focused install manifest, target, and executor suite.real-cli for the pinned Debian-based generic Linux image.real-cli-ubuntu for the pinned Ubuntu image.Validate the Compose model before building:
Build both real Linux images:
Run the safe default flow in each image:
The dry run executes the current public command contract:
Before that command runs, the container creates a locally packed npm artifact
from the read-only checkout with npm pack --ignore-scripts. It extracts the
self-created tarball under /tmp, validates the ecc-universal package name,
required install manifests, and the confined package.json bin.ecc mapping,
then invokes the extracted ecc executable. The runtime stays on
network_mode: none, does not execute package lifecycle scripts, and does not
rely on host node_modules; its exact pinned production dependencies are
already present in the image.
The harness rejects an empty plan, a non-claude-project target, any operation
outside /workspace/project/.claude, or any dry run that creates the target
directory. install performs the isolated apply twice, checks its managed
install state, lists the installed target, and runs doctor.
Start a detached container without --rm so leaving a terminal does not remove
the session:
The container copies the read-only fixture to the stable private directory
/workspace/project. Confirm it is running, then emit the Docker side of the
terminal-opener v1 data contract:
The JSON result has exactly an executable and argv boundary (plus
contractVersion: 1): the executable is docker, and argv begins with
exec, -it, and -w. Pass that data to the separate terminal-opener skill
when it is installed. This Docker harness deliberately does not import a
terminal adapter, interpolate a shell command, or manage a host GUI process.
Until then, open the same PTY in the current host terminal directly:
Exit the shell without stopping the detached container. Reconnect with the
same docker exec -it command. When finished, remove the exact named container
and its Compose project resources:
Host credentials are absent by default and credential directories are never
mounted. The default service also has no network access. When an authenticated
provider session genuinely needs a network, build real-cli first and then opt
in visibly with docker compose --profile networked run real-cli-networked shell. Prefer authenticating inside that disposable session. If a CI run must
inherit a host environment credential, make that opt-in at invocation with an
explicit Compose --env NAME flag, understand that the value is inspectable
and can be exfiltrated for the container lifetime, and remove the exact named
container immediately after.
Run the same focused suite natively on the host:
Inspect the produced identity and environment before trusting the image:
Clean each named test project without deleting unrelated volumes or images: