Init
Scaffold a new Clusterbase project with ccp init.
ccp init creates a new project with everything you need to develop and deploy a function.
Usage
ccp init my-appccp 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
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:
ccp init my-app --template blank
ccp init my-app --template react
ccp init my-app --template static
ccp init my-app --template apiGenerated 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 remote function and organization |
CLUSTER.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
If you're logged in, ccp init will offer to create a function and link it to your project. This writes the function_id and organization_id to .ccp/config.json so that ccp deploy works without prompting.
Skipping Prompts
-y (or --yes) accepts all defaults — uses the blank template, skips linking, and still runs the dependency install:
ccp init my-app -yCombine with --no-install to also skip bun i / npm i:
ccp init my-app -y --no-installIf you skip linking during init, you can always link later:
ccp linkFor scripted and CI use, see Headless Mode.
Config File
The .ccp/config.json file ties your local project to a remote function:
{
"function_id": "abc-123",
"organization_id": "org-456",
"index": "index.ts",
"client": null,
"assets": null
}| Field | Description |
|---|---|
function_id | ID of the remote function (set by link or first deploy) |
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
.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)
recording index, client, assets, analytics, and oidc_callback_path,
and tells you to commit it:
[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 pointOnce 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
(function_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 a function (ccp remove) never deletes
cluster.toml — it describes the source tree, not the remote function.