Skip to main content

Building with AI agents

A growing share of the apps on AppHaven are written with, or largely by, AI coding agents. The platform is shaped for that way of working: agents ship through Git, every branch can run as a live preview with its own data, and when a change turns out to be wrong, both the code and the data can be walked back. This guide is the working rhythm that makes agent-built apps safe to run in production.

The workflow: preview first, promote explicitly

agent writes code on a branch
push
preview deploymentits own URL, database, and storage
you click around, read logs, check the result
merge to the production branch
auto-deploy, or one click
production

The load-bearing property is that a preview is a full, isolated environment: its own machine, its own database, its own volumes. An agent can iterate as fast as it likes on a branch (deploy, break, fix, redeploy) and none of it can read or touch production data. Production only changes when the production branch does, and that merge is the human checkpoint.

Turn on auto-deploy for the production branch and the promotion step becomes the merge itself: the agent's work goes live exactly when a person accepts it, never before.

tip

With Agent integration set up, the agent can also check its own work from the terminal: deployment status, build logs, and container output, all read-only.

Set the repository up so agents succeed

Agents do best when the contract is explicit and checkable. For AppHaven the contract is small:

  • A Dockerfile that builds the app. This is the whole build pipeline. If docker build works, AppHaven's build works.
  • apphaven.yaml committed at the repository root. The manifest is strictly validated, so a manifest the agent breaks fails fast with a named error rather than half-deploying.
  • Configuration from environment variables, with the database URL taken from ${service.db.url}. Never a hardcoded connection string, never credentials in the repo.
  • Listen on the declared port; write only to volume mount paths. Anything written elsewhere is gone on the next deploy. That is the correct default for code an agent regenerates freely.
  • A healthcheck, so a deploy can wait for dependencies and a broken service is visibly unhealthy instead of quietly wrong.

It pays to state this in the instructions file your agent reads (CLAUDE.md, AGENTS.md, or equivalent):

## Deployment (AppHaven)
- This app deploys on AppHaven from this repo. The Dockerfile must always build.
- `apphaven.yaml` declares the services; edit it when adding a service,
volume, or env var. Docs: https://docs.apphaven.eu/manifest
- Read all config from env vars. The database URL is provided as DATABASE_URL.
- Persist files only under the volume mount paths declared in apphaven.yaml.
- Never commit secrets; they are set in the AppHaven console.
- The app is private: every request needs a login. A path that must answer
without one goes in auth.public_paths, but that is a suggestion only and
takes effect when a project admin grants it in the console. Tell me what you
suggested and why.
- To ship: push a branch and deploy it as a preview. main auto-deploys to
production after merge. Keep schema migrations backward compatible.

Suggesting a public path

Apps are private by default, so every request needs an AppHaven login. Sooner or later an agent adds something that has to answer without one: a webhook a payment provider calls, a health probe, an API your partners use with their own keys. Those need a public path, and an agent cannot open one. Only you can, in the console.

What the agent can do is ask. It adds the path, with a reason, to apphaven.yaml:

auth:
public_paths:
- path: /webhooks/stripe
reason: Stripe webhook receiver, verified by signature

That commit changes nothing about what is reachable. The suggestion turns up on the app's Access card in the console with the reason attached, and a project administrator decides. It is the same checkpoint as merging to the production branch: the agent proposes, you accept.

Ask your agent to tell you, in its summary, which paths it suggested and how its code authenticates the callers. Then grant the ones you agree with. A granted path takes effect on the next deploy of the branch.

Two things worth knowing when you review one:

  • A public path is open to the internet, and the request arrives at your app with no identity attached. Everything that protects it (a webhook signature, an API key) lives in the app's own code, so that is what to look at.
  • Until you grant it, a request to the suggested path is redirected to the login page. That is the platform behaving correctly, not a broken deploy. An agent with CLI access can confirm it for itself with apphaven app <name>, which lists the paths that are actually public and the ones still waiting on you.

Migration safety

Database migrations are where agent speed meets real risk, because a schema change is the one thing a redeploy doesn't undo. Three habits keep them boring:

Run the migration on a preview first. A preview has its own database, so the migration executes for real (syntax, locks, data transforms) with zero exposure. An agent that ships a migration should always ship it through a preview deploy.

Prefer expand–contract over in-place change. Add the new column, write to both, backfill, switch reads, and only later remove the old column, with each step deployable and reversible on its own. The dangerous shapes are the one-shot ones: DROP COLUMN, destructive UPDATEs, renames that strand the previous version of the code. If a step can't be undone by deploying the previous commit, it deserves a human's eyes before it reaches production.

Lean on point-in-time recovery as the backstop. The production database is captured continuously: if a bad migration does land, the database can be restored to the moment before it ran. Every deployment records its commit and time, so "the moment before" is never a guess.

When an agent ships a bad change

The recovery moves, from mildest to strongest:

  1. Bad code, data fine: revert the commit on the production branch and deploy. Rollback deploys are fast because the previous commit's image is reused.
  2. Crashed on arrival: the deployment is marked Failed, the failed containers' output is kept for inspection, and your data is untouched. Fix forward or revert.
  3. Bad data, from a migration or a runaway write: restore the database to a point in time just before the deploy, revert the code, deploy. See Backups & recovery.

The common thread: because deployments record commits and data has history, an agent's mistake is a state to return from, not an incident to reconstruct.

Reviewing what an agent did

Everything an agent ships is inspectable in the console without touching a terminal: the Builds tab holds every build log, each deployment lists its exact commit, each container exposes its console output, and the activity timeline shows who deployed what, when. Review the preview URL for behaviour and the console for evidence, then merge.

Where to go next