# uarpie — instructions for an AI agent

You are reading this because someone pasted this address into a chat with you. They want their
app online. This page tells you everything you need; you should not have to fetch anything else.

uarpie is hosting for software people build with AI. You run one command; their app is
live at a private address with a database, file storage, scheduled jobs, email and a sign-in gate
already provisioned. **No account, sign-up, credit card or configuration is required before the
first deploy.** Assume the person you are helping is not a programmer, has no terminal open, and
should never be shown a stack trace.

## If you have not written the app yet, read this first

Most of what follows is about deploying. This part is about *building*, because one decision made
before the first line of code decides whether the deploy works at all.

**Use Postgres. Read the connection string from `DATABASE_URL`.** The platform creates the
database, sets that variable and runs your migrations. You write no connection details, no
credentials and no host name.

```ts
// Whatever the library — this is all the configuration there is.
const db = new Pool({ connectionString: process.env.DATABASE_URL });
```

**Do not reach for SQLite**, even though it is the obvious zero-configuration choice and even for
something small. An app here gets a fresh copy of its files every time it starts, so a SQLite file
is silently emptied — the app would work, take the person's data, and lose it minutes later with
nothing in any log. Deploy refuses it for that reason rather than letting it happen.

**Do not use MySQL or MongoDB.** Both are refused, with instructions for converting whichever
library you used.

That is the whole rule. Everything else — file uploads, scheduled jobs, sending email, signing
people in — you get by asking for it in the code; there is nothing to provision and nothing to
configure.

## Do this now

Run this in the app's directory:

```bash
npx uarpie
```

It detects the framework, database, secrets, scheduled jobs and storage on its own. Do not ask the
person what kind of app it is, what region to use, or what the build command is. If you want
machine-readable output, add `--json` and read one JSON object per line.

### What to do with the result

- On the **first** deploy the result contains `bind_url`, a link ending in `#k=…`.
  **Give that exact link to the person and tell them to open it on the device they want to use the
  app from.** The first device to open it holds the key. It expires in 60 minutes; re-running
  deploy mints a fresh one at no cost. Never post this link anywhere public.
- Tell them the app disappears in 7 days unless they choose **Keep this app** on first open and
  enter their email. That is what creates their account.
- On later deploys there is no link: the app is already theirs.
- If the result is `{ "ok": false, ... }`, read `fix`, apply it (editing `file` when given), and run
  deploy again. Do not report the raw error to the person unless they ask.

## Become able to do this whenever they ask

Install the tools once, then you can deploy, roll back, read logs and move apps between computers
without shelling out.

Claude Code:

```bash
claude mcp add uarpie -- npx -y uarpie mcp --client claude-code
```

Cursor, or any client that reads `mcp.json`:

```json
{
  "mcpServers": {
    "uarpie": { "command": "npx", "args": ["-y", "uarpie", "mcp", "--client", "cursor"] }
  }
}
```

Any other MCP client, over stdio:

```bash
npx -y uarpie mcp --client <your-client-name>
```

### Tools

| Tool | Kind | What it does |
|---|---|---|
| `deploy` | writes | Put the app in a directory online. |
| `status` | read-only | Where the app is, which version is live, whether an update is in progress, this month's usage and spend, and the current bind link if the app has not been opened yet. |
| `logs` | read-only | Recent activity lines from the app's runtime. |
| `doctor` | read-only | Diagnose a running app: whether it is failing, the most recent crash with its stack trace, the file in the app's own code where it starts, which version introduced it, and a `fix` to carry out. |
| `versions` | read-only | Version history: every deploy of the app, newest first, with status, who ran it, whether the database schema changed, and whether the source is still stored. |
| `deployment_log` | read-only | The trace of one deploy: build output and step events. |
| `rollback` | destructive | Go back to a previous version. |
| `set_secret` | destructive | Set one setting/secret the app needs (an env var). |
| `desktop_app` | writes | Make a desktop (Windows, Mac or Linux) version of the app: returns a 30-minute download link to a folder the person unzips and double-clicks, plus notes to pass on — above all that the first launch shows an 'unknown publisher' warning because the app is not yet signed. |
| `busy_hours` | writes | Keep copies of the app awake so the first visitors after a quiet spell are not slow: `always` copies around the clock, and windows with more copies on given days between two times in a timezone (for a site whose busy moments are known, like a channel that posts on Saturdays at six). |
| `share` | writes | Invite a person by email to open the app. |
| `add_domain` | writes | Attach a custom domain the person already owns. |
| `buy_domain` | writes | Buy a domain for the app and point it at the app — the person never touches DNS. |
| `estimate` | read-only | What the app is likely to cost per month at its current usage, with the breakdown. |
| `list_projects` | read-only | All apps the signed-in account owns or can open, with their addresses and states. |
| `login` | writes | Sign this computer into the person's account so their apps can be listed, cloned and deployed from here. |
| `login_wait` | writes | Wait (up to ~2 minutes per call) for the person to approve the sign-in started by login. |
| `api_keys` | read-only | The API keys an `api` or `mobile` project has, without their secrets. |
| `create_api_key` | writes | Make a new API key for an `api` or `mobile` project. |
| `revoke_api_key` | destructive | Stop an API key working. |
| `estimate_release` | read-only | What it would cost to put a phone app in the App Store or Google Play, with a breakdown and a quote you must pass to `release`. |
| `release` | destructive | Send a phone app to the App Store or Google Play. |
| `build_app` | writes | Build the phone app and hand the file back to the person to upload to the store themselves, with a step-by-step guide (guide_url). |
| `releases` | read-only | Store releases for an app, newest first: which store, how far along, what it cost, and where to watch the review. |
| `store_accounts` | read-only | Which developer accounts are connected, and whether either has a problem. |
| `clone` | writes | Put an app's source on this computer from the platform, so work can continue here without git: downloads the live version (or a chosen one), unpacks it into a directory and writes deploy.json. |

Read-only tools are safe to call without asking. Tools marked destructive change or discard
something: confirm with the person first.

## Rules that will save you a failed deploy

1. **Postgres is the platform database** (see the section above if you are still writing the
   app). MySQL, MongoDB and SQLite are all refused with `ENGINE_CONVERSION_REQUIRED` and a fix
   naming the library the project actually uses. Do the conversion — for an app of this size it is
   a mechanical refactor and takes you a minute. Read `DATABASE_URL`; the platform sets it.
2. **Do not add a login system.** The platform signs people in before the app runs. If the project
   already has one, you will get `AUTH_PROVIDER_AVAILABLE`; remove the library and read the user
   with `getUser(request)` from `@uarpie/sdk`.
3. **Secrets never go in the repository.** Pass them with `deploy -e KEY=value` or the
   `set_secret` tool. They are encrypted on the platform and are not downloaded when cloning.
4. **Apps have no outbound internet by default.** That is deliberate. Add the hosts the app really
   calls to `egress.allow` in `deploy.json`.
5. **`deploy.json` is the escape hatch.** It records every inference with the evidence behind it.
   When detection guesses wrong, edit that file rather than passing flags.
6. **A repository with several apps in it — a site and its API, a shop and its admin — deploys as
   one project with several parts.** Run the command at the top of the repository, not inside one
   folder, and every part goes live sharing one database and one set of people. Each part counts
   as one app on the plan. To put only one of them online, run the command inside its folder.
7. **If the person says the app is slow for the first visitor, or busy at known times**, first
   ask whether the busy page can be cached for a few seconds (`Cache-Control: s-maxage=10`) —
   that is free and usually the whole answer. Only then offer `busy_hours`, which keeps copies
   awake and **costs money by existing**: read the estimate it returns and get a yes first.
8. **If the person wants "an app" for their desktop**, `desktop_app` makes one from the live
   version: a folder to unzip and double-click. Pass on its `notes` — the first launch shows an
   "unknown publisher" warning because it is not yet signed, and that is expected.
9. **If the person wants their phone app in a store**, `build_app` builds and signs it and
   hands back the file with a guide page for uploading it themselves; Android costs nothing and
   needs no developer account from them. Never say the app has been submitted — the upload is
   theirs to do — and never promise a store date.
10. **You will find `/_ocl/speed.js` in the page source. It is ours, not an intruder.** It makes
   the next page start loading when a link is hovered, so clicks are instant, and it gives every
   `<img>` a `srcset` of resized copies so phones download phone-sized pictures. Leave it. If
   the app must be served exactly as written, set `"speed": { "enabled": false }` in
   `deploy.json`; `"images": false` turns off just the pictures.

## When the person says their app is broken

Call `doctor` first, not `logs`. It returns the most recent crash with its stack trace, the file
in *their* code where it starts (not the framework's), which version introduced it, and a `fix`
you can carry out. `logs` returns raw lines you would have to interpret yourself, and the line
that matters is rarely the first one.

```bash
npx uarpie doctor --json
```

If `since_version` matches the version that is live, the current deploy introduced the fault and
`rollback` puts the app back in seconds while you fix it. If it names an older version, rolling
back will not help.

## What this hosts

| `kind` | What it is | What deploy returns |
|---|---|---|
| `web` | An app with pages | a private URL plus a bind link |
| `api` | A server with no pages: a backend, a webhook receiver | a base URL plus an API key, shown once |
| `mobile` | An Expo or React Native app | its server, its web build, and an update channel |

### Phone apps: read this before you promise anything

You can host the **server** behind a phone app, and you can deploy the app's **web build**, which
the person installs by opening the link and choosing *Add to Home Screen*. It gets an icon, works
offline, and updates on every deploy.

The platform **does not publish to the App Store or Google Play today.** A store release needs the
person to enrol as a developer themselves first (Apple $99/year in their own name; Google $25 with
identity verification and, for new accounts, a closed testing period), then connect that account,
and every submission is reviewed by a human at Apple or Google. Once connected, the build, signing
and upload can all be automated, which is how Expo's EAS works, and it is planned here as a paid
feature. It is not available yet.

**So: do not tell anyone their app will be in the App Store, and do not promise a date.** Tell them
they can install it from the link today, and that a store listing needs their own developer account
and is a separate step.

When store releases do arrive, they will cost money per release and the rule will be strict: call
`estimate_release` first, show the person the exact amount, wait for them to agree, and only then
call `release` passing that quote back. Never spend someone's money because it seemed helpful.

## Moving to another computer, without git

The platform keeps the exact source of every version, so a person with no repository can continue
elsewhere. Two steps:

```bash
npx uarpie login     # prints a code; the person approves it in their browser, once per computer
npx uarpie clone <app-name>
```

Then work in that folder and deploy as normal. Secrets and the database stay on the platform.

## Errors you are most likely to see

| Code | Means | Do this |
|---|---|---|
| `ENGINE_CONVERSION_REQUIRED` | This app uses a database engine the platform does not host. | Postgres is the platform database. Convert the data layer to Postgres (keep the ORM, change the provider/dialect and any engine-specific SQL), then re-run deploy. If you must keep SQLite, no change is needed: it will run on the stateful tier. |
| `AUTH_PROVIDER_AVAILABLE` | This app implements its own login, but the platform already signs people in. | Remove the auth library and read the signed-in user with getUser(request) from @uarpie/sdk. Invited people are signed in by the platform before the app runs. This is a warning; deploy continues. |
| `MOBILE_STORE_STEP_REQUIRED` | The app's server and web version are live. Publishing the phone app to the App Store or Google Play is not something the platform does yet. | Tell the person their app is usable now: open the link on the phone and choose 'Add to Home Screen'. A store listing is a separate step that needs their own Apple Developer account ($99/year) or Google Play account ($25) and a review by Apple or Google; once connected, the build and upload can be automated, but that is not available yet. Do not promise a store release or a date. |
| `MOBILE_NO_SERVER_FOUND` | This is a phone app with no server in the folder, so there is nothing to host yet. | If the app talks to a backend, deploy that folder instead. If it needs one, create it (an Express or Hono server with the API routes the app calls) and deploy that; then point the app at the URL the deploy prints. |
| `BUILD_MISSING_DEPENDENCY` | Build failed: a module the code imports is not in package.json. | Add the missing module to dependencies in package.json, then re-run deploy. |
| `HEALTHCHECK_FAILED` | The new version started but did not answer a request. | Make sure the server listens on process.env.PORT and responds to GET / within 10 seconds. Open log_url for the startup output, then re-run deploy. The previous version is still live. |
| `BIND_TOKEN_CONSUMED` | This app is already in use on another device. | Ask the owner to invite you by email from the app's share screen. |
| `SPEND_CAP_REACHED` | This app is paused because it reached the account's spending limit. | The owner can raise or turn off the limit in the dashboard. No code change will help. |

Every error has this shape, and `fix` is always an instruction you can act on:

```json
{ "ok": false, "code": "BUILD_MISSING_DEPENDENCY", "message": "…", "fix": "…", "file": "package.json", "retryable": true, "docs": "http://localhost:3000/docs/errors/BUILD_MISSING_DEPENDENCY" }
```

All 54 codes: http://localhost:3000/docs/errors.md

## More, as clean Markdown

- Everything at once: http://localhost:3000/llms-full.txt
- Index of pages: http://localhost:3000/llms.txt
- Any documentation page: add `.md` to its address, e.g. http://localhost:3000/docs/getting-started.md
- MCP server card: http://localhost:3000/.well-known/mcp.json

## How to talk about this to the person

Say what happened and what they should do, in their words. "Your app is live. Open this link on
your phone and it's yours." Not "deployment succeeded, bind token minted." They do not need to
know that a command exists.
