# Init



`ccp init` creates a new project with everything you need to develop and deploy a function.

## Usage [#usage]

```bash
ccp init my-app
```

`ccp init <name>` creates `./<name>/`, scaffolds the chosen template, and runs `bun i` (or `npm i` if Bun isn't installed) to install dependencies. The target directory must not already exist.

In a TTY, omitting `<name>` prompts you for one. In headless mode (`CCP_HEADLESS=1` or when stdout isn't a TTY), the positional argument is required.

`ccp init` errors if you're already inside a Cluster project — it walks up to `$HOME` looking for a `.ccp/config.json` or a committed `cluster.toml` and stops you before nesting a project inside another. A fresh clone has no `.ccp/` at all, so `cluster.toml` is what marks it as an existing project.

## Templates [#templates]

You'll be prompted to choose a template:

| Template   | Description                            |
| ---------- | -------------------------------------- |
| **blank**  | Minimal `Request → Response` handler   |
| **react**  | React single-page app (Vite)           |
| **static** | Static site with a `public/` directory |
| **api**    | JSON API with route matching           |

You can also pass `--template` directly:

```bash
ccp init my-app --template blank
ccp init my-app --template react
ccp init my-app --template static
ccp init my-app --template api
```

## Generated Files [#generated-files]

| File               | Purpose                                           |
| ------------------ | ------------------------------------------------- |
| `index.ts`         | Your handler function                             |
| `package.json`     | Scripts for `dev` and `deploy`                    |
| `tsconfig.json`    | TypeScript config (ESNext, strict)                |
| `.ccp/config.json` | Links to your App, Project, and organization      |
| `AGENTS.md`        | Quick reference for commands and available APIs   |
| `.gitignore`       | Ignores `.ccp/`, `node_modules/`, `dist/`, `.env` |

The **static** template also generates:

| File                | Purpose                                   |
| ------------------- | ----------------------------------------- |
| `public/index.html` | Starter HTML page                         |
| `globals.d.ts`      | TypeScript types for the `__pages` global |

## Linking [#linking]

If you're logged in, `ccp init` will offer to create an App and link it to your project. This writes the `app_id`, `project_id`, and `organization_id` to `.ccp/config.json` so that `ccp deploy` works without prompting.

## Skipping Prompts [#skipping-prompts]

`-y` (or `--yes`) accepts all defaults — uses the **blank** template, skips linking, and still runs the dependency install:

```bash
ccp init my-app -y
```

Combine with `--no-install` to also skip `bun i` / `npm i`:

```bash
ccp init my-app -y --no-install
```

If you skip linking during init, you can always link later:

```bash
ccp link
```

For scripted and CI use, see [Headless Mode](/docs/ccp/headless).

## Config File [#config-file]

The `.ccp/config.json` file ties your local project to its App:

```json
{
  "app_id": "abc-123",
  "project_id": "proj-789",
  "organization_id": "org-456",
  "index": "index.ts",
  "client": null,
  "assets": null
}
```

| Field             | Description                                                |
| ----------------- | ---------------------------------------------------------- |
| `app_id`          | ID of the App (set by link or first deploy)                |
| `project_id`      | ID of the [Project](/docs/ccp/projects) the App belongs to |
| `organization_id` | ID of the owning organization                              |
| `index`           | Entry point file                                           |
| `client`          | Client-side script path (optional)                         |
| `assets`          | Public directory for static assets (e.g., `"public"`)      |

## Committed Shape: `cluster.toml` [#committed-shape-clustertoml]

`.ccp/config.json` is gitignored, so on its own it can't be the source of
truth for what your project *is* — two clones of the same commit could
disagree about the entry point after a rename. The first time any command
loads the project config after this file exists, ccp writes a `[serverless]`
section to `cluster.toml` (the same file used by [Cluster Compute](/docs/ccp/compute#project-shape-clustertoml))
recording `index`, `client`, `assets`, `analytics`, and `oidc_callback_path`,
and tells you to commit it:

```toml
[serverless]
index = "index.tsx"
client = "src/main.tsx"
assets = "public"
analytics = "server"
oidc_callback_path = "/auth/callback"
```

```
wrote this project's shape to cluster.toml — commit it, so every clone agrees on the entry point
```

Once committed, `cluster.toml`'s `[serverless]` section is authoritative for
shape — a fresh clone builds from it even before `.ccp/config.json` exists
locally. `.ccp/config.json` keeps only the link and secrets
(`app_id`, `project_id`, `organization_id`, and similar per-machine fields). If the
entry point in your gitignored config is stale and a same-named `.ts`/`.tsx`
file exists, ccp uses that file instead of committing a stale entry, and
prints a warning saying so; unrelated renames still fail with a normal
"file is not a file" error. Unlinking (`ccp remove`) never deletes
`cluster.toml` — it describes the source tree, not the App.
