# Start a new project from the terminal with Claude Code

URL: https://developertoolkit.ai/en/claude-code/plan/project-init/
Description: Bootstrap a new service with Claude Code: plan the scaffold, generate it, and prove it runs with one verify script, a Stop hook and a CLAUDE.md.

To bootstrap a project with Claude Code, commit an empty repository, approve a plan in plan mode, let Claude run the framework's generator and customize the output, then make it prove the scaffold works with one `verify` script that CI also runs. A fast subset gates every reply through a `Stop` hook, and `/init` records the conventions in `CLAUDE.md`.

This page is for developers starting a service from an empty directory, and for tech leads who want every new repository on the team to start from the same gate. The situation: the product manager describes a service in one sentence — "a REST API for user preferences, PostgreSQL, auth, rate limiting, structured logs" — and the usual answer is a day of wiring before any business logic exists. Claude Code writes that wiring quickly. The hard part is that a folder tree proves nothing, so this workflow ends in evidence you can check, not in a tree you hope compiles. You need Claude Code installed and signed in ([installation](/en/claude-code/quick-start/installation/)), plus Git and Docker for the walkthrough.

## What a verified bootstrap gives you

- A plan you approved before a single file existed: stack, file tree, dependencies, and the acceptance checklist.
- A scaffold generated by the framework's own tool where one exists, customized by Claude to your conventions.
- One command, `scripts/verify.sh`, that lints, type-checks, tests, boots the service and hits `/health`. You run it before commits and CI runs it on every push; its fast half, `scripts/verify-fast.sh`, runs in a `Stop` hook before Claude may declare the work done.
- A `CLAUDE.md` under the vendor's 200-line target, plus a recorded launch recipe for the bundled `/run` and `/verify` skills.
- Copy-paste prompts for Express with Drizzle, Next.js, FastAPI, and Phoenix.

## Which scaffolding route should Claude take?

Decide this before the first prompt. It changes how much of the output you have to check.

| Route | Use it when | What you verify |
| ----- | ----------- | --------------- |
| Claude runs the official generator (`create-next-app`, `mix phx.new`), then customizes | The framework has a maintained generator | The diff between the generator output and Claude's changes, plus the verify script |
| Claude writes the project from scratch | No generator fits (an Express API, a small worker) | Every file is agent-written, so the verify script and the acceptance checklist carry the whole load |
| Claude copies your team's template repository | Your team already has a golden path | Only the project-specific delta; the template's own gate is already trusted |

The generator route is the default because the boilerplate is deterministic and maintained by the framework authors. Claude's contribution shrinks to the part that is specific to your project.

## Bootstrap a new service from an empty directory

The walkthrough builds the user-preferences API from the scenario above. The same steps apply to any stack in the next section.

1. **Create the repository and commit before Claude touches it**

   ```bash
   mkdir prefs-api && cd prefs-api
   git init
   git commit --allow-empty -m "chore: empty root"
   claude --permission-mode plan
   ```

   The empty commit matters more than it looks. Claude Code checkpoints do not track files changed by Bash commands, and a generator or `npm install` runs through Bash. Esc Esc and `/rewind` therefore cannot undo a bad scaffold; `git` can.

   `--permission-mode plan` starts the session in plan mode, so Claude explores and proposes without writing files.

2. **Ask for a plan with an acceptance checklist**

   A vague prompt such as "create a web app" returns a generic template. Name the stack, the layout, the conventions, and what "done" means.

   **Copy-paste prompt: plan a production Node API scaffold**

   ```text
   Plan (do not write files yet) a Node.js Express API in TypeScript strict
   mode for a user-preferences service:

   - src/ with routes/, middleware/, services/, db/, lib/
   - Drizzle ORM against PostgreSQL with a migrations/ folder
   - Zod request validation middleware; JWT auth middleware (access + refresh)
     reading secrets from env only
   - express-rate-limit at 100 req/min per IP; pino JSON logs with request IDs
   - Vitest with a separate test database; docker-compose.yml for local Postgres
   - Multi-stage Dockerfile running as a non-root user
   - GitHub Actions CI that runs ./scripts/verify.sh
   - .env.example only, never a real .env

   First resource: GET /health and CRUD for "preferences", with error-handling
   middleware. Before listing dependencies, check each current version with
   `npm view <pkg> version` instead of guessing.

   Your plan must include: the file tree, the dependency list with versions,
   the commands you will run, and an acceptance checklist of 6-10 observable
   checks (for example "POST /preferences without a token returns 401").
   ```

   Read the plan, not the code that does not exist yet. Check that the acceptance checklist describes behavior you care about. Edit it in the conversation until it does. This checklist is what you sign off later, instead of reading every generated line.

3. **Approve the plan and let Claude scaffold**

   Accept the plan and choose the permission mode for the build. With Claude Code v2.1.283 or later (both release channels on 2026-10-12), auto mode is the starting mode for interactive terminal sessions: a classifier reviews each action and only risky ones reach you. Before v2.1.283 it was the starting mode only on Pro, Max, and Team plans; Enterprise, API and cloud-provider sessions started in Manual, so expect more prompts on an older build. Commit when the files are in place:

   ```bash
   git add -A && git commit -m "chore: scaffold prefs-api"
   ```

4. **Make Claude build the gate and prove the scaffold runs**

   **Copy-paste prompt: one verify script, run and proven**

   ```text
   Write scripts/verify.sh (bash, set -euo pipefail) that:
   1. runs the linter and the TypeScript type check
   2. starts Postgres with docker compose, applies the migrations, runs Vitest
   3. boots the dev server, curls /health until it returns 200 (30 s timeout),
      then stops the server and exits non-zero on any failure
   Put step 1 plus the unit tests (no Docker, no server) in
   scripts/verify-fast.sh, and have verify.sh call it first.

   Run verify.sh and fix everything until it passes. Then prove the gate can fail:
   temporarily break one assertion in a preferences test, run verify.sh, show
   me that it exits non-zero, and revert the change. Finish with a table that
   maps each acceptance-checklist item from the plan to the test or command
   that proves it, and list any item that has no proof yet.
   ```

   The final table is your review surface. A checklist item with no test next to it is a gap, whatever the code looks like. Claude is also at its best with a real error in front of it: a failing migration or a version conflict in stderr gives it something precise to fix.

5. **Correct one real gap**

   Scaffolds usually miss something specific to how you work. Name it; do not re-describe the whole project.

   ```text
   The CRUD handlers call Drizzle directly. Put a preferences service layer
   between routes and db so business logic is testable without HTTP, move the
   Zod schemas to src/schemas/, and run ./scripts/verify.sh again.
   ```

6. **Record the conventions and the launch recipe**

   ```text
   /init
   ```

   `/init` analyzes the project and writes a starting `CLAUDE.md` with build commands, test instructions and the conventions it detects; if a `CLAUDE.md` already exists, it suggests improvements instead of overwriting it. Add the rules it cannot infer — "service layer between routes and db", "never hand-edit migrations" — and keep the file under 200 lines, the target in Anthropic's memory documentation. The anatomy of a good file lives in [Project initialization: CLAUDE.md and project context](/en/claude-code/quick-start/project-initialization/).

   Then run `/run-skill-generator`. This bundled skill gets the app running from a clean environment and writes the recipe as a per-project skill at `.claude/skills/run-<name>/` (commit it with the scaffold), so the bundled `/run` and `/verify` skills start the service correctly next time instead of guessing how to bring up Postgres.

After step 6 you have a repository whose claims are checkable: a plan you approved, a gate that has been seen to fail and to pass, and a mapping from each acceptance item to its proof.

## How do you keep the gate running without slowing every reply?

`CLAUDE.md` instructions are advisory; hooks run every time. A `Stop` hook fires when Claude finishes responding, and exit code 2 prevents Claude from stopping and feeds stderr back to it. The hook fires after every response, including plan-mode answers and plain questions, so wire in only `verify-fast.sh` (lint, type check, unit tests). Claude then cannot report "done" while that gate is red, and a reply does not wait on Docker. Add it to `.claude/settings.json` once the scripts exist:

```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "cd \"$CLAUDE_PROJECT_DIR\" && { [ -z \"$(git status --porcelain)\" ] && exit 0; ./scripts/verify-fast.sh 1>&2 || exit 2; }"
          }
        ]
      }
    ]
  }
}
```

`Stop` takes no matcher. The `git status --porcelain` guard skips the gate when the working tree is clean, so a question asked after you commit costs nothing; while changes are uncommitted, every reply runs the fast gate, which is why it must stay fast. It counts new, untracked files too; `git diff --quiet HEAD` would not, and a bootstrap turn that only adds files would end without running the gate. Claude Code caps stop-hook continuations at eight in a row and then ends the turn, so a gate that can never pass does not loop forever. The cap is adjustable with `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`, and the hook input's `stop_hook_active` field tells your script it is already in a forced continuation. The [hooks guide](/en/claude-code/automate/hooks-automation/) covers `PostToolUse` formatters and `PreToolUse` blocks.

The full `verify.sh` (the fast half plus Docker, migrations and the `/health` boot) runs before each commit and in CI. Because it calls `verify-fast.sh`, the Stop-hook gate is a strict subset of the merge gate and the two cannot drift. Because an agent that can edit the gate can also weaken it, route changes to `scripts/verify*.sh` and `.claude/settings.json` through human review; [protecting the oracle](/en/workflows/test/protect-the-oracle/) shows how. **Who signs off:** the developer approves the acceptance checklist and reads the evidence table, not every line. The tech lead owns the stack prompt and the verify contract, so every new repository starts from the same gate.

## Scaffold prompts for other stacks

Each prompt has the same shape as the Express one: generator first, then layout, conventions, a first resource, and the same verify contract.

**Next.js**

**Copy-paste prompt: Next.js App Router scaffold**

```text
Run `npx create-next-app@latest web --help` first, then create the app
non-interactively with TypeScript, Tailwind CSS, ESLint, the App Router and a
src/ directory. Then add:

- Prisma with PostgreSQL, User and Session models; docker-compose.yml for Postgres
- a proxy.ts (Next.js 16 renamed middleware to proxy) that protects /app/*
- .env.example only, never a real .env
- scripts/verify.sh: lint, type check, tests, `next build`, boot and curl /

Server components by default, client components only for interactivity.
Named exports except page.tsx and layout.tsx. Run verify.sh until it passes.
```

**FastAPI**

**Copy-paste prompt: FastAPI service scaffold**

```text
Create a FastAPI service with Python 3.13 and uv (pyproject.toml + uv.lock):

- src/ layout with routers/, models/, schemas/, services/
- SQLAlchemy 2.0 async sessions and Alembic migrations; Pydantic v2 schemas
- pytest with async fixtures and httpx for API tests
- ruff for lint and format, mypy for type checks
- multi-stage Dockerfile; docker-compose.yml for PostgreSQL
- scripts/verify.sh: ruff, mypy, pytest, boot uvicorn and curl /health

First resource: /health and CRUD for "projects" (list, detail, create, patch).
Run verify.sh until it passes and show me the output.
```

**Phoenix**

**Copy-paste prompt: Phoenix LiveView scaffold**

```text
Generate the app with `mix phx.new acme` (Phoenix 1.8, PostgreSQL, LiveView
on by default), then run `mix phx.gen.auth Accounts User users --live`. Add:

- an Organization schema with a many-to-many to User in the Accounts context
- a LiveView dashboard that updates in real time via Phoenix.PubSub
- ExUnit tests for the context modules
- docker-compose.yml for PostgreSQL
- scripts/verify.sh: mix format --check-formatted, mix compile
  --warnings-as-errors, mix test, boot the server and curl /

Keep LiveView modules thin and put data access in contexts. Run verify.sh
until it passes.
```

## Make configuration refuse to boot on a bad value

A scaffold that emits config files is not done until you have seen the config reject something. Config validation that has never rejected a value is validation you do not have.

**Copy-paste prompt: validated, environment-aware config**

```text
Add environment-aware config (development/staging/production) chosen by
NODE_ENV, exposed as one typed config object. Validate at startup with Zod:
PORT is a valid port, DATABASE_URL is a URL, JWT_SECRET is at least 32 chars.
On a missing or invalid value, exit with an error that names the key.

Then prove it: start the app with JWT_SECRET unset, show me it refuses to
boot with a clear error, set it, show a clean start, and add both cases to
the test suite so verify.sh covers them.
```

## Choose permissions for a bootstrap or a throwaway prototype

A bootstrap runs many commands: package installs, generators, Docker, migrations. Pick the mode deliberately:

- **Plan mode** (`--permission-mode plan`) for step 2, so nothing is written before you approve.
- **Auto mode** for the build on v2.1.283 or later, or earlier on Pro, Max and Team. Set `"defaultMode": "auto"` under `permissions` in `~/.claude/settings.json` (user settings); Claude Code ignores `auto` and `bypassPermissions` as `defaultMode` in project settings.
- **`--dangerously-skip-permissions`** only inside a disposable container with restricted network egress. The CLI's own help text recommends it "only for sandboxes with no internet access". A bootstrap needs the package registry, so allow that host and nothing else, for example in a [dev container](/en/claude-code/team/devcontainer-setup/). Never use it in a repository or on a machine you care about.

**Copy-paste prompt: throwaway prototype in a sandbox**

```text
Build a minimal real-time collaborative whiteboard: Next.js + Socket.io + the
Canvas API. In-memory state, no auth, no database. Core only: draw, see other
cursors, clear the board. Start the dev server, open two clients with a
Playwright script to prove strokes sync between them, and tell me the URL.
```

Validate the idea in the sandbox, then rebuild the version you keep with the full workflow above. The [permissions and sandboxing guide](/en/workflows/harness/permissions-and-sandboxing/) compares the modes across tools.

## Connect the database and share team recipes

Two extensions remove guessing during a bootstrap, and they solve different problems. An MCP server is a live connection to a system. A skill is a reusable recipe.

**Postgres MCP Pro** lets Claude read the live local schema and explain plans instead of guessing column names. It is a Python package, so it runs through `uvx`, and `--access-mode=restricted` keeps it to read-only transactions. Point it at the local Docker database, never at production. Its release cadence has stalled — the latest PyPI upload is 0.3.0 from 2025-05-16 (checked 2026-09-26) — so re-check the repository before you build it into a team template:

```bash
claude mcp add postgres -e DATABASE_URI="$DATABASE_URL" -- uvx postgres-mcp --access-mode=restricted
```

For GitHub, `gh repo create` from Claude's Bash tool covers creating the repository and opening the first pull request without loading any MCP tool definitions into context. Add the [GitHub MCP server](/en/ecosystem/mcp/github-mcp/) when the agent must read Actions logs or review threads. Other options are in [database MCP servers](/en/ecosystem/mcp/database-mcp/).

A project skill turns your team's "add a resource" routine into one command. Save it as `.claude/skills/new-resource/SKILL.md`:

```markdown
---
name: new-resource
description: Scaffold a CRUD resource with route, service, schema and tests
---
Create the resource $ARGUMENTS following CLAUDE.md:

1. src/routes/$ARGUMENTS.ts, thin, calling the service only
2. src/services/$ARGUMENTS.service.ts with the business logic
3. src/schemas/$ARGUMENTS.schema.ts with Zod request and response schemas
4. src/services/$ARGUMENTS.service.test.ts covering 401, 404, 422 and the happy path
5. Run ./scripts/verify.sh and report the result
```

Run it with `/new-resource notifications`. For skills other people publish, see [installing and managing skills](/en/ecosystem/skills/installing-managing/).

## Joining an existing codebase instead?

When the repository already exists, skip the scaffold and start with `/init`. To get an interactive flow, set `CLAUDE_CODE_NEW_INIT=1` before you run `/init` (checked on Claude Code 2.1.283): Claude then asks which artifacts to set up (`CLAUDE.md` files, skills, hooks), explores with a subagent, asks follow-up questions, and shows a reviewable proposal before writing anything. If the repository already has an `AGENTS.md` and no `CLAUDE.md`, Claude Code v2.1.277 or later reads `AGENTS.md` as the project instructions (v2.1.281 on Bedrock, Google Cloud, Foundry and LLM gateways; toggle under Project instructions in `/config`).

Then map the code with [codebase analysis](/en/claude-code/plan/codebase-analysis/). If the real task is moving a legacy app onto a new toolchain, follow the phased approach in [database and code migrations](/en/claude-code/build/migrations/).

## When a Claude Code bootstrap goes wrong

**The output is a generic template.** The prompt was underspecified. Add the layout, the conventions and the acceptance checklist, or switch to the generator route so the framework owns the boilerplate.

**Dependencies conflict, or a version does not exist.** A model's knowledge of versions lags the registry. Tell Claude to read versions with `npm view <pkg> version` (or `pip index versions`, `mix hex.info`), commit the lockfile, and let `verify.sh` surface the conflict. Paste the real stderr rather than describing it.

**`/rewind` did not undo the scaffold.** Checkpoints do not track files written by Bash commands, so generator and install output survives a rewind. Run `git status` to see what changed, then `git stash -u` or `git reset --hard` to the empty-root or scaffold commit.

**The gate is green but proves nothing.** Tests that assert nothing, or a `/health` route that returns 200 without touching the database, pass forever. This is why step 4 breaks an assertion on purpose. Ask for `/health` to run a `SELECT 1`, and repeat the break-it check whenever the gate changes.

**The Stop hook keeps Claude running.** The gate fails for a reason Claude cannot fix, such as Docker not running. Claude Code ends the turn after eight consecutive continuations (`CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` changes the cap); fix the environment, or remove the hook while you debug the script. If Docker is the cause, check that the hook calls `verify-fast.sh`, not the full `verify.sh`.

**Claude drifts from early instructions in a long session.** An instruction given only in chat, such as "named exports only", can drop out as context fills. Move it into `CLAUDE.md` or a path-scoped rule in `.claude/rules/`; see the [memory system guide](/en/claude-code/build/memory-system/).

**`uvx: command not found` when the Postgres MCP server starts.** Install uv, restart the session, and confirm the server with `claude mcp list`.

## Where to go next after the scaffold passes its gate

- [Feature planning](/en/claude-code/plan/feature-planning/) — Turn the next requirement into an implementation plan in plan mode
- [Executable acceptance criteria](/en/workflows/plan/acceptance-criteria/) — Turn the acceptance checklist into failing tests before the agent writes code
- [API development](/en/claude-code/build/api-development/) — Build endpoints on top of the scaffold with Claude Code driving the tests
- [Making a codebase agent-ready](/en/workflows/harness/agent-ready-codebase/) — The harness that keeps later agent sessions productive in this repository

Using a different tool? The same workflow for other agents is in [starting a new project with Cursor](/en/cursor-ide/plan/new-project/) and [starting a new project with Codex](/en/codex/plan/new-project/).
