# Quickstart

From a repository to a running sandbox of your app in five commands.

## Create a project [#create-a-project]

Sign in at [console.parity.ninja](https://console.parity.ninja) with GitHub or Google and create a project from your repository. Parity installs its GitHub App on it (read access to code, pull requests and organization members; write access to checks) and reads `parity.yaml` from the default branch.

Then create a project token under **Settings → Agents and tokens** and set it in your shell:

```sh title="Terminal"
export PARITY_API=https://api.parity.ninja
export PARITY_TOKEN=ppt_t7acme-shop_…
```

A project token acts for you, with your role. Keep it out of the repository and out of agents: an agent gets a [sandbox token](/guides/agents) instead.

## Install the CLI [#install-the-cli]

```sh title="Terminal"
curl -fsSL https://parity.ninja/install | sh
```

See [Install](/install) for other platforms and how to verify the binary.

## Write parity.yaml [#write-parityyaml]

Put it at the root of the repository. A web app with a worker:

```yaml title="parity.yaml"
version: 1
project: shop

managed:
  db:    { type: postgres }
  cache: { type: redis }
  mail:  { type: email }

env_groups:
  common:
    APP_URL:        ${web.public_url}
    SESSION_SECRET: { generate: secret }

services:
  web:
    build: .
    command: npm start
    health: { http: /healthz }
    expose: true
    env_from: [common]
    depends_on: [db, cache, mail]
  worker:
    build: { from: web }
    command: npm run worker
    env_from: [common]
    depends_on: [db, cache, mail]

jobs:
  migrate: { service: web, command: npm run migrate, on: deploy }
```

In each sandbox this gives you:

- `web`, built from the repository's `Dockerfile`, listening on `PORT` (8080), and public.
- `worker`, on the same image with another command.
- `DATABASE_URL`, `REDIS_URL` and `SMTP_URL` in both, from `depends_on`.
- `SESSION_SECRET`, random per sandbox and shared by both services.
- `migrate`, run before the services take traffic and again on every update.

## Check it [#check-it]

```sh title="Terminal"
parity check
```

`parity check` runs offline. It reports every problem at once with "did you mean" suggestions, and for a valid file prints what each service gets: image, port, public URL, every variable and where its value comes from, and when each job runs.

## Start a sandbox [#start-a-sandbox]

```sh title="Terminal"
parity up
```

`parity up` uploads the working directory (without `.git` and what `.dockerignore` excludes), builds each image, creates the built-ins, runs the `deploy`, `seed` and `start` jobs, starts the services and waits until they are healthy. Progress goes to stderr; the sandbox goes to stdout as JSON, with each service's `public_urls`.

```json title="stdout"
{
  "id": "team-invites-3fa91c",
  "status": "ready",
  "expires_at": "2026-11-09T11:42:00Z",
  "services": [
    { "name": "web", "status": "running", "public_urls": ["https://web--team-invites-3fa91c--t7acme.env.parity.ninja"] },
    { "name": "worker", "status": "running", "public_urls": [] }
  ],
  "token": "pst_t7acme-team-invites-3fa91c_…"
}
```

On a git branch the sandbox is yours: its name is the branch plus a short code for you and the project, so `team-invites` gives the sandbox above, and a teammate on the same branch, or another project with a `team-invites` branch, gets its own. On a pull request (`--pr 123`, or a GitHub Actions `pull_request` run) it is the pull request's, `pr-123-<project>`, shared by everyone working on it. Every other command finds the sandbox the same way, so you rarely pass `--sandbox`.

## Work with it [#work-with-it]

```sh title="Terminal"
parity open -b                   # open the app
parity logs web --since 10m      # one service's logs
parity exec db -- psql -c 'select count(*) from users'
parity inbox list                # mail the app sent
parity run migrate               # run a job now
parity up                        # roll onto your latest changes
parity down                      # delete the sandbox and its data
```

`parity up` is safe to rerun. The sandbox keeps its data and generated secrets, rebuilds what changed, reruns `deploy` jobs and rolls the services. A sandbox lives 2 hours by default; `parity up --ttl 8h` and `parity sandbox extend 2h` change that, up to `sandbox.max_ttl`.
