setup
Interactive first-time project setup that fills missing env values, starts required services, runs migrations and seeds, and verifies the app starts.
SKILL.mdskills/setup/SKILL.md
GitHubOverview
First-time project setup that detects the stack, installs dependencies, configures the environment, starts required services, runs database migrations and seeds, and verifies the application starts. Interactive: prompts for missing non-secret environment values in chat, hands secret values to a script the user runs, and confirms before starting services.
When to use
- When cloning a new project and setting it up for the first time.
- When onboarding to a project and the README setup steps are unclear or incomplete.
- When returning to a project after a long time and the environment may be stale.
- When a teammate asks "how do I get this running?"
Neighbouring work has its own skill:
- For managing production infrastructure, use
/infra. - For deploying to staging or production, use
/deploy. - For generating a README, use
/readme. - For updating dependencies, use
/audit deps.
Arguments
This skill takes no arguments. Run /setup and it walks through everything interactively.
Steps
Detect the project type. Read the root directory for manifest files. Check for these in order:
package.json: Node.js project. Check forpnpm-lock.yaml,yarn.lock, orpackage-lock.jsonto determine the package manager.go.mod: Go project.Cargo.toml: Rust project.pyproject.tomlorrequirements.txt: Python project.Makefile: check for language-specific targets.docker-compose.ymlorcompose.yml: containerized services.- If multiple manifest files exist, report all detected project types.
Check prerequisites. For each detected project type, verify the required runtime is installed. If
which misefindsmiseand the project has a.mise.toml,.tool-versions,.node-version,.nvmrc,.python-version,.ruby-version, or.terraform-versionfile, runmise installonce to install every pinned runtime, thenmise currentto verify resolution. After that, the per-runtime checks below confirm the right version is active:- Node.js:
node --version. Compare against.node-version,.nvmrc,.tool-versions,.mise.toml, or theenginesfield inpackage.json. - Go:
go version. Compare against.tool-versionsor.mise.toml. - Rust:
rustc --versionandcargo --version. Compare againstrust-toolchain.toml. - Python:
python3 --version. Compare against.python-version,.tool-versions,.mise.toml, orpyproject.tomlrequires-python. - Docker:
docker --versionanddocker compose version. - If a prerequisite is missing and
misecannot resolve it, report it and stop. Do not install runtimes manually.
- Node.js:
Install dependencies.
- Node.js with pnpm:
pnpm install. - Node.js with yarn:
yarn install. - Node.js with npm:
npm ci. - Go:
go mod download. - Rust:
cargo build. - Python with
uv.lockor apyproject.toml:uv sync, perrules/lang/python.md. Never a barepip install. - Python with only
requirements.txt:uv venvthenuv pip install -r requirements.txt. - Python with poetry:
poetry install. - Report the result: success or failure with the error output.
- Node.js with pnpm:
Environment setup. Check for
.env.exampleor.env.templatein the project root; the commands below name.env.example, so substitute the template file when that is the one present. Never read.envvalues into the conversation; work with key names only.If
.envdoes not exist, create it from the example with owner-only permissions:(umask 077 && cp .env.example .env).List the keys that are missing, empty, or still equal to the example value. This prints names, never values:
awk -F= 'NR == FNR && /^[A-Za-z_][A-Za-z0-9_]*=/ { example[$1] = substr($0, length($1) + 2); next } NR == FNR { next } $1 in example { present[$1] = 1; value = substr($0, length($1) + 2); if (value == "" || value == example[$1]) { print $1 } } END { for (key in example) { if (!(key in present)) { print key } } }' .env.example .envClassify each listed key. A key is secret-shaped when its name contains
KEY,SECRET,TOKEN,PASSWORD,PASS,PWD,PRIVATE,CREDENTIAL,AUTH,SALT, orDSN, or when it holds a connection string that can carry credentials, such asDATABASE_URLorREDIS_URL. When unsure, treat the key as secret-shaped.For each non-secret key, ask in chat: show the variable name, the description from comments in
.env.exampleif available, and the default value if one exists. Accept the default if the user presses enter, and write the answer to.env.For the secret-shaped keys, generate a wizard script so the values never pass through the conversation. Write it to the project workspace as
setup-env.sh, resolving the root withhooks/_lib/project_workspace.pythe same way/checkpointdoes, or to the scratchpad directory outside a git repository. FillKEYSwith the secret-shaped names and leave the rest of the template unchanged:#!/usr/bin/env bash set -euo pipefail ENV_FILE="${ENV_FILE:-.env}" MAX_ATTEMPTS=3 KEYS=(DATABASE_URL STRIPE_SECRET_KEY) has_value() { [[ -f "$ENV_FILE" ]] && grep -qE "^${1}=.+" "$ENV_FILE" } write_env() { local key="$1" value="$2" tmp sq="'\\''" [[ -e "$ENV_FILE" ]] || (umask 077 && : >"$ENV_FILE") tmp=$(umask 077 && mktemp) grep -vE "^${key}=" "$ENV_FILE" >"$tmp" || true printf "%s='%s'\n" "$key" "${value//\'/$sq}" >>"$tmp" cat "$tmp" >"$ENV_FILE" rm -f "$tmp" } ask_secret() { local key="$1" value attempt rc for ((attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)); do value="" rc=0 if has_value "$key"; then printf '%s [Enter keeps the saved value]: ' "$key" else printf '%s: ' "$key" fi IFS= read -rs value || rc=$? printf '\n' if [[ -z "$value" ]] && has_value "$key"; then printf 'Kept %s.\n' "$key" return 0 fi if [[ -n "$value" ]]; then write_env "$key" "$value" printf 'Saved %s.\n' "$key" return 0 fi if ((rc != 0)); then printf 'Input closed before %s was entered.\n' "$key" >&2 return 1 fi printf '%s is required.\n' "$key" >&2 done return 1 } main() { local key missing="" for key in "${KEYS[@]}"; do ask_secret "$key" || missing="$missing $key" done if [[ -n "$missing" ]]; then printf 'Still missing:%s\n' "$missing" >&2 return 1 fi printf 'Every value is saved in %s.\n' "$ENV_FILE" } main "$@"Check the script with
bash -nandshellcheck, then tell the user to runbash <path>from the project root in their own terminal window. Never suggest the!prefix: a!command gets no terminal input, soread -rshits end of file and every key is reported missing. Input is hidden withread -rs, a new.envis created underumask 077, a re-run offers each saved value as the Enter default without showing it, a closed input stream ends the loop instead of spinning, and no value is ever echoed.After the user reports the script finished, rerun the key-name listing above to confirm every key now has a value. The script holds key names only, so it may stay in the workspace for a later re-run.
Never overwrite values the user has already set in
.env.
Detect required services. Scan these sources for service dependencies:
docker-compose.ymlorcompose.yml: list all services defined..env.example: look for connection strings or host variables that imply services:DATABASE_URL,REDIS_URL,MONGODB_URI,ELASTICSEARCH_URL,RABBITMQ_URL,KAFKA_BROKERS.- For each detected service, check if it is already running:
- PostgreSQL:
pg_isready -h localhostor check the port. - Redis:
redis-cli ping. - MongoDB:
mongosh --eval "db.runCommand({ping:1})"or check the port. - Docker services:
docker compose ps.
- PostgreSQL:
Offer to start services. For each service that is not running:
- If a docker-compose file defines the service, offer to start it:
docker compose up -d <service>. - Wait for health checks to pass before proceeding. Use
docker compose psto verify the service reports as healthy. - If the service is not in docker-compose, inform the user that the service needs to be started manually and provide the typical connection details from the env vars.
- If a docker-compose file defines the service, offer to start it:
Run database setup. Detect the ORM or migration tool:
- Prisma:
pnpm exec prisma migrate devorpnpm exec prisma db pushdepending on the project stage. Thenpnpm exec prisma db seedif a seed script exists. - Knex:
pnpm exec knex migrate:latestthenpnpm exec knex seed:runif seeds exist. - TypeORM:
pnpm exec typeorm migration:run. - Django:
python manage.py migratethenpython manage.py loaddataif fixtures exist. - SQLAlchemy with Alembic:
alembic upgrade head. - If no ORM is detected but
DATABASE_URLexists, inform the user that manual database setup may be needed.
- Prisma:
Verify the application starts. Detect the start command:
- Node.js: check
package.jsonscripts fordev,start:dev, orstart. - Go:
go run .or check a Makefile target. - Python: check for a
main.py,app.py, or framework-specific entry point. - Start the application. Wait up to 15 seconds for a health check endpoint or for the process to stabilize.
- If the app starts and responds to a health check, report success.
- If the app crashes, capture the error output and report it with diagnostic suggestions.
- Stop the application after verification. This is a setup check, not a long-running process.
- Node.js: check
Present the setup report.
## Setup Complete **Project:** <detected type and framework> **Runtime:** <version> **Package manager:** <name and version> ### Dependencies Installed successfully. ### Environment - .env created from .env.example - N variables configured ### Services | Service | Status | |---------|--------| | PostgreSQL | running on localhost:5432 | | Redis | running on localhost:6379 | ### Database - Migrations applied: N - Seed data loaded: yes/no ### Application Started successfully on http://localhost:3000 ### Next steps - Run `pnpm dev` to start development - Run `pnpm test` to verify tests pass
Rules
- Never overwrite an existing
.envfile. Merge missing values only. - Never read, print, or ask in chat for a secret-shaped value. The wizard script collects it in the user's terminal, per
rules/security.md. - Always check if services are already running before attempting to start them. Starting a second instance on the same port causes errors.
- Always verify the application actually starts. "Dependencies installed" is not "setup complete."
- Never install runtimes or system-level tools automatically. Report what is missing and let the user decide how to install.
- When a step fails, report the error clearly and continue with the remaining steps where possible. A failed database migration should not prevent reporting what else was configured.
- Use
pnpmfor every JavaScript and TypeScript project. A project withpackage-lock.jsonoryarn.lockis converted:pnpm import, delete the old lockfile, and pinpackageManager. - When docker-compose starts a service, wait for its health check before running migrations. A started container is not a ready service.
Common Rationalizations
- "Pasting the API key in chat is faster than running a script": a value in chat is in the transcript and counts as disclosed. The wizard script reads it with
read -rsin the user's terminal. - "The key name looks harmless, so ask for it in chat": the classification in step 4 decides, and an unsure call counts as secret-shaped.
- "Dependencies installed, so setup is done": setup is done when the app starts and answers its health check in step 8.
- "The container is up, so run the migrations":
docker compose psmust report the service healthy first. - "The runtime is missing, so install it quickly": runtimes come from
miseor from the user. Report the gap and let the user choose.
Red Flags
- Stop and switch to the wizard script when the next message would ask for, print, or echo a secret-shaped value.
- Stop and merge only missing keys when the next write would replace a value already set in
.env. - Stop and report the missing prerequisite when
misecannot resolve a pinned runtime. - Stop and report the crash output with diagnostic suggestions when the app exits during step 8.
Verification
- The key-name listing from step 4 prints nothing after the wizard script finishes.
- No secret-shaped value appears anywhere in the conversation.
- Every detected service reports healthy or running before migrations ran.
- The app started, answered a health check or stayed up for the 15-second window, and was stopped afterward.
- The setup report lists every step, with the error output for any step that failed.
Related skills
/onboard- Understand the codebase structure and architecture./infra- Manage infrastructure for local development./test- Run the suite, coverage, and lint once setup is complete.