Web・iOS・Androidの画面を、読み上げやキーボード操作に対応させ、ラベル、配色、操作対象の大きさなどをWCAG 2.2に沿って設計・点検するスキル。
- アイコンボタンの説明を付けたいとき
- キーボード操作とモーダルの点検
- コントラストや操作対象の大きさの確認
DockerとDocker Composeで開発環境を構成し、通信・データ保存・権限を見直すほか、元のファイルを変更せずにCLIの導入手順を検証するスキル。
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.
DockerとDocker Composeで、アプリ、データベース、Redisなどを組み合わせた開発環境を構成します。開発用と本番用のビルド分離、サービス間の通信、データを保持するボリューム、権限や秘密情報の扱いをレビューします。CLIというコマンド操作ツールの導入テストでは、元のファイルを読み取り専用にし、一時コピーで検証する手順も扱います。
ローカル開発に必要なサービスをまとめて起動したい人や、DockerfileとCompose設定を見直したい人に向いています。DebianとUbuntuで導入処理を試し、重複実行や変更先の範囲を確認する場面にも使えます。
DockerとDocker Composeが必要です。LinuxコンテナではmacOSやWindows固有の動作は検証できず、それぞれの実環境での確認が必要です。WindowsコンテナにはWindowsのDockerエンジンが必要です。紹介されるECC用テスト手順は、対応する付属ファイルを前提とします。
この紹介文は、公開されている SKILL.md をもとに AI(Claude Haiku)が作成しました。正確な仕様は下の原文を確認してください。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Docker and Docker Compose best practices for containerized development.
# docker-compose.yml
services:
app:
build:
context: .
target: dev # Use dev stage of multi-stage Dockerfile
ports:
- "3000:3000"
volumes:
- .:/app # Bind mount for hot reload
- /app/node_modules # Anonymous volume -- preserves container deps
environment:
- DATABASE_URL=postgres://postgres:postgres@db:5432/app_dev
- REDIS_URL=redis://redis:6379/0
- NODE_ENV=development
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
command: npm run dev
db:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: app_dev
volumes:
- pgdata:/var/lib/postgresql/data
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redisdata:/data
mailpit: # Local email testing
image: axllent/mailpit
ports:
- "8025:8025" # Web UI
- "1025:1025" # SMTP
volumes:
pgdata:
redisdata:
# Stage: dependencies
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Stage: dev (hot reload, debug tools)
FROM node:22-alpine AS dev
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
# Stage: build
FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build && npm prune --production
# Stage: production (minimal image)
FROM node:22-alpine AS production
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001
USER appuser
COPY --from=build --chown=appuser:appgroup /app/dist ./dist
COPY --from=build --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=build --chown=appuser:appgroup /app/package.json ./
ENV NODE_ENV=production
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]
# docker-compose.override.yml (auto-loaded, dev-only settings)
services:
app:
environment:
- DEBUG=app:*
- LOG_LEVEL=debug
ports:
- "9229:9229" # Node.js debugger
# docker-compose.prod.yml (explicit for production)
services:
app:
build:
target: production
restart: always
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
# Development (auto-loads override)
docker compose up
# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Services in the same Compose network resolve by service name:
# From "app" container:
postgres://postgres:postgres@db:5432/app_dev # "db" resolves to the db container
redis://redis:6379/0 # "redis" resolves to the redis container
services:
frontend:
networks:
- frontend-net
api:
networks:
- frontend-net
- backend-net
db:
networks:
- backend-net # Only reachable from api, not frontend
networks:
frontend-net:
backend-net:
services:
db:
ports:
- "127.0.0.1:5432:5432" # Only accessible from host, not network
# Omit ports entirely in production -- accessible only within Docker network
volumes:
# Named volume: persists across container restarts, managed by Docker
pgdata:
# Bind mount: maps host directory into container (for development)
# - ./src:/app/src
# Anonymous volume: preserves container-generated content from bind mount override
# - /app/node_modules
services:
app:
volumes:
- .:/app # Source code (bind mount for hot reload)
- /app/node_modules # Protect container's node_modules from host
- /app/.next # Protect build cache
db:
volumes:
- pgdata:/var/lib/postgresql/data # Persistent data
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql # Init scripts
# 1. Use specific tags (never :latest)
FROM node:22.12-alpine3.20
# 2. Run as non-root
RUN addgroup -g 1001 -S app && adduser -S app -u 1001
USER app
# 3. Drop capabilities (in compose)
# 4. Read-only root filesystem where possible
# 5. No secrets in image layers
services:
app:
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
- /app/.cache
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # Only if binding to ports < 1024
# GOOD: Use environment variables (injected at runtime)
services:
app:
env_file:
- .env # Never commit .env to git
environment:
- API_KEY # Inherits from host environment
# GOOD: Docker secrets (Swarm mode)
secrets:
db_password:
file: ./secrets/db_password.txt
services:
db:
secrets:
- db_password
# BAD: Hardcoded in image
# ENV API_KEY=sk-proj-xxxxx # NEVER DO THIS
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:
docker compose -f docker/plugin-setup/compose.yaml config --quiet
Build both real Linux images:
docker compose -f docker/plugin-setup/compose.yaml \
build real-cli real-cli-ubuntu
Run the safe default flow in each image:
docker compose -p ecc-plugin-debian-test \
-f docker/plugin-setup/compose.yaml \
run --rm -T real-cli dry-run
docker compose -p ecc-plugin-ubuntu-test \
-f docker/plugin-setup/compose.yaml \
run --rm -T real-cli-ubuntu dry-run
The dry run executes the current public command contract:
ecc install --profile core --target claude-project --dry-run --json
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:
docker compose -p ecc-plugin-session \
-f docker/plugin-setup/compose.yaml \
run --detach --name ecc-plugin-shell real-cli shell
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:
docker inspect --format '{{.State.Running}}' ecc-plugin-shell
node docker/plugin-setup/interactive-plan.js \
--container ecc-plugin-shell \
--workdir /workspace/project \
--json \
-- bash
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:
docker exec -it -w /workspace/project ecc-plugin-shell bash
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:
docker rm --force ecc-plugin-shell
docker compose -p ecc-plugin-session \
-f docker/plugin-setup/compose.yaml \
down --remove-orphans
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 -f docker/plugin-setup/compose.yaml --profile networked run --service-ports real-cli-networked shell. The
--service-ports flag publishes the service's loopback callback mapping.
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.
codex login binds its OAuth callback server to 127.0.0.1:1455 inside the
container. A Docker port publish forwards to the container interface, not
loopback, so the host browser's redirect to http://localhost:1455 is refused
without a bridge. The real-cli-networked service publishes host
127.0.0.1:1455 to container port 1456; bridge that port to loopback before
logging in:
(
set -e
npm install --global @openai/codex@0.162.0 # the harness image does not ship codex
node /ecc/docker/plugin-setup/codex-auth-relay.js &
relay_pid=$!
trap 'kill "$relay_pid" 2>/dev/null || true; wait "$relay_pid" 2>/dev/null || true' EXIT
codex login
)
The networked service sets NPM_CONFIG_PREFIX=/tmp/ecc-npm and adds its bin
directory to PATH. This keeps the pinned installation writable for UID 1000
on the executable /tmp mount while the root filesystem remains read-only.
Complete the sign-in in the host browser. Each attempt mints a fresh
state/code, so always follow the newest printed link. The token stays in
the disposable container's ~/.codex/auth.json; removing the named container
deletes that credential copy. The login block stops the relay on success or failure.
Only one container can hold host port 1455 at a time
because the OAuth redirect targets a fixed port.
The host publish is restricted to loopback. Inside the container, the relay listens on all interfaces so Docker can forward to it; other containers on the same bridge network can reach it while it runs. Use a dedicated network without untrusted peers for this login, and remove the exact named container after use. Idle callback connections close after 30 seconds.
Run the same focused suite natively on the host:
npm run test:plugin-setup-platform
Inspect the produced identity and environment before trusting the image:
docker image inspect ecc-plugin-setup:debian ecc-plugin-setup:ubuntu
Clean each named test project without deleting unrelated volumes or images:
docker compose -p ecc-plugin-debian-test \
-f docker/plugin-setup/compose.yaml down --remove-orphans
docker compose -p ecc-plugin-ubuntu-test \
-f docker/plugin-setup/compose.yaml down --remove-orphans
node_modules
.git
.env
.env.*
dist
coverage
*.log
.next
.cache
docker-compose*.yml
Dockerfile*
README.md
tests/
# View logs
docker compose logs -f app # Follow app logs
docker compose logs --tail=50 db # Last 50 lines from db
# Execute commands in running container
docker compose exec app sh # Shell into app
docker compose exec db psql -U postgres # Connect to postgres
# Inspect
docker compose ps # Running services
docker compose top # Processes in each container
docker stats # Resource usage
# Rebuild
docker compose up --build # Rebuild images
docker compose build --no-cache app # Force full rebuild
# Clean up
docker compose down # Stop and remove containers
docker compose down -v # Also remove volumes (DESTRUCTIVE)
docker system prune # Remove unused images/containers
# Check DNS resolution inside container
docker compose exec app nslookup db
# Check connectivity
docker compose exec app wget -qO- http://api:3000/health
# Inspect network
docker network ls
docker network inspect <project>_default
# BAD: Using docker compose in production without orchestration
# Use Kubernetes, ECS, or Docker Swarm for production multi-container workloads
# BAD: Storing data in containers without volumes
# Containers are ephemeral -- all data lost on restart without volumes
# BAD: Running as root
# Always create and use a non-root user
# BAD: Using :latest tag
# Pin to specific versions for reproducible builds
# BAD: One giant container with all services
# Separate concerns: one process per container
# BAD: Putting secrets in docker-compose.yml
# Use .env files (gitignored) or Docker secrets
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Web・iOS・Androidの画面を、読み上げやキーボード操作に対応させ、ラベル、配色、操作対象の大きさなどをWCAG 2.2に沿って設計・点検するスキル。
AIエージェントの不調を、指示・記憶・ツール実行・画面表示など12の層から調べるスキル。コードやログを根拠に原因を整理し、重要度順の指摘と修正案をまとめます。
実際の開発課題で複数のコーディングエージェントを比較するスキル。成功率、取得可能なAPI費用、所要時間、繰り返し実行の安定性を測り、選定や更新後の評価に使えます。
AIエージェントが使うツールの種類や入出力、エラーからの復帰手順を設計・見直します。文脈の情報量も整理し、作業完了率や再試行回数で改善を評価します。
AIエージェントの失敗や同じ操作の繰り返しを記録し、原因の切り分け、小さな復旧操作、結果の報告まで進める手順を示して、根拠のある再試行につなげるスキル。
AIエージェントが失敗や同じ操作を繰り返す原因を、エラーと実行状況から整理します。小さな復旧操作を試し、結果と根拠を引き継げる報告にまとめるスキルです。