Skip to main content
PercherPercher

Deploy instruction for AI agents

CLAUDE.md content for agentic deploys

Add this to your project's CLAUDE.md, cursor rules, or paste it when you start a new project. Your AI assistant will know how to build the app so it deploys correctly on Percher.

This app will be deployed on Percher (https://percher.app).

## Percher deployment requirements

- The app MUST expose an HTTP server on a configurable port (default 3000)
- The app MUST have a health check endpoint that returns HTTP 200, usually GET /health
- A percher.toml file must exist in the project root
- Percher uses Nixpacks to auto-detect and build — use standard project structures (package.json, requirements.txt, go.mod, etc.)

## Supported runtimes

Percher config uses runtime = "node", "bun", "python", "static", or "docker".
Use Dockerfile-based projects for Go, Rust, PHP, Ruby, Java, .NET, Elixir, and other runtimes.

## How to deploy

**Standard deploy:** `bunx percher publish` (or the percher_publish MCP tool).
Handles auth, config generation, packaging, and deploy in one call. Returns
structured errors with explanations and suggestions on failure — this is the
recommended path whether the deploy succeeds or fails. Supports `--dry-run`,
`--preview`, `-m "note"`, `--force`, `--no-cache`.

**Agentic happy path (MCP only):** the standard flow is

  publish (waitForLive: false) -> wait_for_deploy -> if recovery says so: doctor -> exact action

Call `percher_publish` with `waitForLive: false`. The tool returns
within a few seconds with `status: 'queued'` and a `deployId`,
instead of blocking for the 30-90s build. Then call
`percher_wait_for_deploy` (the args come back pre-filled in
`recovery.args`) to learn whether the deploy went `live` /
`failed` / `replaced`. For ambiguous failures wait_for_deploy
points at `percher_doctor` — call it and keep following its
`recovery.nextAction` until you reach a terminal state.

**Agent recovery contract:** every Percher MCP tool that can fail
returns a `recovery` field with a machine-readable next step. The
full action set:

  recovery.nextAction = "none" | "open_login" | "wait_deploy"
                      | "run_doctor" | "set_env_vars" | "fix_problems"
                      | "retry" | "fix_config" | "ask_user"
                      | "inspect_build_log"   (advisory, hand-off only)

Rules:

1. Always read `recovery.nextAction`. Don't regex-parse the
   suggestion text — that's for surfacing to the user.
2. Call EXACTLY the suggested tool with EXACTLY the suggested args
   (`recovery.args`). Don't strip `mode` or `deployId` —
   they're load-bearing.
3. If `recovery.nextAction` is `ask_user`, ask
   `recovery.prompt` verbatim and wait.
4. `run_doctor` means call `percher_doctor` with the supplied
   args; doctor is the recovery hub and will route to the right
   low-level tool.
5. Repeat until `recovery.nextAction` is `none` (success) or
   `ask_user` (needs the user).

**Build cache:** Percher caches built images keyed on a content hash of
percher.toml + package.json + lockfile + Dockerfile + build-time env vars +
every source file. Identical inputs produce a cache hit and skip
nixpacks/docker rebuild (typically <10s wall-clock). Every successful
publish prints either `Build cache: hit (reused image — re-run with
--no-cache if your changes aren't reflected)` or `Build cache: miss
(fresh build)` so you can tell at a glance which path ran. If your
changes don't seem to be live and the line says "hit", run
`bunx percher publish --no-cache` to force a fresh build — the new
image still gets cached, so future deploys benefit.

**Preview deploys (`--preview`):**
Deploy to a temporary URL like `my-app--p-<slug>.percher.run` without
replacing the live version. On the **free plan** there is one preview
slot per app — running `--preview` again automatically rotates the
existing preview out (no manual `percher preview discard` needed) and
the CLI prints a "replaced previous preview" note. On paid plans you
get up to `activePreviewsPerApp` parallel previews and the previous
ones are kept; once at the limit a new `--preview` returns 403 and
you discard explicitly. Either way, the live URL is untouched.

**Granular control / debugging:** `bunx percher login`, `bunx percher init`,
`bunx percher push` for stepwise execution. Use this only when you need to
isolate a single phase (e.g. validating the bundle without an upload, or
re-running a specific step). `push` errors point at `percher deploys
inspect <id>` for the full build log.

Either path hits the same server-side build pipeline; the choice is purely
about where the error surface lives.

## percher.toml

Generated by percher init. Key fields:

  [app]
  name = "my-app"          # becomes my-app.percher.run
  runtime = "node"         # auto-detected

  [web]
  port = 3000              # the port your app listens on
  health = "/health"       # health check path

## Database

For apps that need a database, add to percher.toml:

  [data]
  mode = "pocketbase"

A managed PocketBase instance is provisioned automatically.
Use the POCKETBASE_URL env var to connect from your app.

## Environment variables

Set via: bunx percher env set KEY=VALUE
Or MCP tool: percher_env_set

Available at runtime as standard environment variables.
Apps deploy to https://<app-name>.percher.run with automatic SSL.

### [env] contract in percher.toml

  [env]
  required = ["OPENAI_API_KEY"]   # must exist before deploy queues
  optional = ["SENTRY_DSN"]       # may be referenced; not required
  ignore   = ["NODE_ENV"]         # explicitly ignored by the scanner

Source code that references env keys not in any of these lists
blocks the deploy with `recovery.nextAction = "fix_config"`. Set
required keys via `percher env set` before publishing.

With this context, you can just say "build me an app that does X" and the agent will structure it correctly for Percher deployment.

PrevVersions and rollbackNextCrash diagnostics
Deploy instruction for AI agents — Percher docs