Quickstart
From a repository to a running sandbox of your app in five commands.
Create a project
Sign in at 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:
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 instead.
Install the CLI
curl -fsSL https://parity.ninja/install | shSee Install for other platforms and how to verify the binary.
Write parity.yaml
Put it at the root of the repository. A web app with a worker:
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'sDockerfile, listening onPORT(8080), and public.worker, on the same image with another command.DATABASE_URL,REDIS_URLandSMTP_URLin both, fromdepends_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
parity checkparity 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
parity upparity 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.
{
"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
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 dataparity 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.