# Deploy QM by YC Labs — Run YC Labs' multiplayer agent harness for your team on Render.

[QM](https://github.com/yc-software/qm) is an open-source, multiplayer agent harness from YC Labs. Your team works with it in Slack and on the web. Each person and each shared room (a channel, group message, or project) gets its own memory, files, credentials, scheduled jobs, published web apps, and durable agent computer.

Render is a built-in QM hosting target. A single `qm up` command provisions the entire stack in your Render workspace: QM's services, a Render Postgres database, object storage, a [Render Sandbox](sandboxes) for each agent computer, and a separate service for each app your agents publish.

> *QM's deployment guide is the source of truth.*
>
> This page explains how QM runs on Render and highlights the Render-specific steps. For the complete workflow, follow QM's [deployment guide](https://github.com/yc-software/qm/blob/main/cli/templates/deployment/deployment.md) and its [Render reference](https://github.com/yc-software/qm/blob/main/cli/templates/deployment/references/render.md). QM changes quickly, and `qm init` copies the guide that matches your CLI version into your deployment repository.

## What QM offers

- *Personal and shared scopes.* Each person customizes the agent to be their own, and still works with it in Slack channels, group messages, and projects.
- *Slack and web.* The same identity and configuration carry over between Slack and QM's web app.
- *Your models, your keys.* Choose Anthropic, OpenAI, or OpenRouter, and the Pi or Claude Code harness. QM isn't tied to one model vendor.
- *Admin control.* Admins set org-wide security and sharing postures and choose which harnesses and models are available.
- *Published web apps.* Agents build internal apps and publish them to the right people.
- *Background work.* Scheduled jobs, watches, and inbound webhooks keep running while you're away.

See the [QM README](https://github.com/yc-software/qm#readme) for the full feature list and [`SECURITY.md`](https://github.com/yc-software/qm/blob/main/SECURITY.md) for the threat model.

## Why run QM on Render

- *Builds from Git, with no image pipeline.* Render builds every QM service from a pinned commit of the QM source repository. You don't need Docker on your machine, a container registry, or a Render Blueprint.
- *Agent computers on Render Sandboxes.* Each agent computer is a [Render Sandbox](sandboxes). QM saves its state with native [snapshots](sandboxes-snapshots), so files and installed tools carry over when QM replaces a sandbox.
- *One project, managed by the CLI.* QM creates a single Render [project](projects) and reconciles the same resources on every `qm up`. You don't create or connect services by hand.
- *Isolated published apps.* Each app an agent publishes runs in its own [network-isolated environment](projects#blocking-cross-environment-traffic). Each app has a persistent disk, and Litestream continuously backs up its SQLite database.
- *Safe updates and rollbacks.* QM's core service deploys with [zero downtime](/deploys#zero-downtime-deploys) and gets up to 300 seconds to finish in-flight turns before shutdown. `qm rollback` redeploys an earlier release.
- *Managed HTTPS and custom domains.* The default `onrender.com` URLs work right away. When you set your own hostnames, QM adds them as [custom domains](custom-domains) and Render manages their TLS certificates.

## Architecture

```mermaid
flowchart TB
  people["People<br/>(browser)"]
  slack["Slack"]

  subgraph project["Render project: production environment"]
    portal["portal<br/>web service"]
    webui["web-ui<br/>private service"]
    core["core<br/>web service"]
    pg[("Render Postgres")]
    minio["MinIO<br/>web service + disk"]
  end

  subgraph sbx["Workspace sandbox group"]
    sandbox["Render Sandbox<br/>(one per agent computer)"]
  end

  subgraph apps["One environment per app"]
    app["Published app<br/>web service + disk"]
  end

  people --> portal
  portal --> webui
  portal --> core
  slack <--> core
  core --> pg
  core --> minio
  core <--> sandbox
  people --> app
  app -->|"Litestream backups"| minio
```

`qm up` creates and manages these Render resources:

| Component | Render resource | What it does | Config keys and defaults |
| --- | --- | --- | --- |
| *core* | Web service | QM's API, identity, policy, scheduler, and agent loop. The optional Slack bot runs inside this service. | `render.corePlan` (`2c-4g`) |
| *portal* | Web service | Public entry point and sign-in, including QM's built-in email sign-in. | `render.servicePlan` (`0.5c-512mb`) |
| *web-ui* | Private service | Web chat and the Admin page, served through the portal. | `render.servicePlan` |
| *Postgres* | Render Postgres | Sessions, memory, the run queue, and other durable state. | `render.postgresPlan`, `render.postgresDiskSizeGB` (10 GB) |
| *MinIO* | Web service with a persistent disk | S3-compatible storage for durable files, tool output, app bundles, and app backups. | `render.storage.plan` (`0.5c-512mb`), `render.storage.diskSizeGB` (10 GB) |
| *Agent computers* | [Render Sandboxes](sandboxes) | One isolated computer per scope, where the agent runs commands. | Created on demand in your workspace's default sandbox group |
| *Published apps* | Web service with a 1 GB disk at `/data` | Apps that agents publish. Each app gets its own environment in the same project. | `render.appRegion` (defaults to `render.region`) |

Each QM service runs as a single instance. If you add QM plugins that run as their own services, QM deploys them as private services in the same environment.

### Agent computers

> *Render Sandboxes is in public beta.*
>
> APIs, defaults, and limits might change during the beta period.

QM creates each sandbox with [idle suspension](sandboxes-creating#suspension-on-idle) turned off. Files and background processes stay in place between turns until the sandbox reaches its 24-hour lifetime. QM then starts a replacement sandbox from the latest snapshot. Files carry over, but background processes stop.

Keep these behaviors in mind:

- QM takes a checkpoint snapshot at most once every five minutes. Work done after the last checkpoint can be lost when a sandbox ends.
- [Snapshots expire](sandboxes-snapshots#snapshot-expiration). If both the sandbox and its snapshot are gone, QM refuses to start an empty replacement. Keep durable work in Git or in QM's Files.
- Sandboxes run in your workspace's default [sandbox group](sandboxes-creating#sandbox-groups). The `render.region` setting doesn't control where sandboxes run.

### Published apps

Each published app runs as a web service with its own 1 GB persistent disk mounted at `/data`. Apps use SQLite at `/data/app.db`. Litestream backs up that database to MinIO using credentials that only Litestream receives. If the local database file is missing, the app restores it from the backup before it starts.

Because each app has a persistent disk, app updates have brief downtime. Litestream backups are asynchronous, so the most recent writes can be lost if a disk fails. Other files under `/data` persist on the disk but aren't backed up.

## Deploy QM on Render

> *QM uses paid Render resources. Your workspace needs a payment method.*
>
> QM requires paid compute plans for its services, Render Postgres, and persistent disks. Agent computers and published apps add usage-based charges. Model usage is billed separately by your model provider.
>
> For details, see the [pricing page](/pricing).

### Prerequisites

- A Render workspace with a payment method, and its workspace ID (starts with `tea-` or `usr-`)
- A Render [API key](api#1-create-an-api-key) for that workspace
- An API key for your model provider: Anthropic, OpenAI, or OpenRouter
- On your machine: Node.js 24 or later, npm, Git, and `openssl`. You _don't_ need Docker.

### Let a coding agent deploy it

QM is built to be deployed by a coding agent. Tell your agent:

```text
Let's deploy https://github.com/yc-software/qm
```

When the agent asks for a hosting target, choose *Render*. The agent follows QM's deployment guide, asks you for each choice and credential, and runs the commands below.

### Deploy it yourself

1. Create an empty repository for your organization's QM deployment. Then initialize it with the Render target:

   ```bash
   npm exec --yes --package=@yc-software/qm@latest -- \
     qm init . --org <slug> --target render \
     --repo https://github.com/yc-software/qm --branch main \
     --model-provider anthropic
   npm install
   ```

   - `--repo` and `--branch` point to the QM source code that Render builds from. Use `yc-software/qm` or your own fork. Render must be able to read this repository.
   - `--model-provider` accepts `anthropic`, `openai`, or `openrouter`.

2. Add your Render API key to the generated `.env` file as `RENDER_API_KEY`. Keep this file private, and never commit it.

3. In `qm.config.jsonc`, set your workspace ID and region:

   ```json
   "render": {
     "workspaceId": "tea-...",
     "region": "oregon",
     "source": { "repo": "https://github.com/yc-software/qm", "branch": "main" }
   }
   ```

   Supported regions are `oregon`, `ohio`, `virginia`, `frankfurt`, and `singapore`. See [Render configuration](#render-configuration) for optional settings.

4. Set your first administrator and choose how people sign in. Follow [step 3 of QM's deployment guide](https://github.com/yc-software/qm/blob/main/cli/templates/deployment/deployment.md#3-configure-the-administrator-sign-in-and-the-base-model). Options include Slack sign-in, QM's built-in email sign-in, and another OIDC provider.

5. Run QM's Render deploy sequence:

   ```bash
   npm exec qm -- setup .
   npm exec qm -- slack render
   npm exec qm -- check
   npm exec qm -- secrets push
   npm exec qm -- plan
   npm exec qm -- up
   npm exec qm -- doctor
   npm exec qm -- check --live
   ```

   `qm up` creates the project, Postgres, MinIO, and QM's services. It initializes MinIO before it deploys core and applies database migrations. `qm check --live` runs a real agent turn as a one-off job on the core service to confirm the deployment works end to end.

6. Finish the remaining steps in QM's deployment guide, starting at [step 4](https://github.com/yc-software/qm/blob/main/cli/templates/deployment/deployment.md#4-deploy-and-prove-the-web-surface): sign in, send a test message, configure connectors, and optionally add the Slack bot.

7. Rerun `npm exec qm -- up` and confirm that it reconciles the same resources without creating new ones.

## Render configuration

Set these keys in the `render` block of `qm.config.jsonc`:

| Key | Description |
| --- | --- |
| `workspaceId` | *Required.* The ID of the Render workspace that owns the deployment. |
| `source.repo`, `source.branch` | *Required.* The QM source repository and branch. Each `qm up` resolves the branch to a single commit and builds every QM service from it. Auto-deploys are off, so `qm up` controls the update order. |
| `region` | The region for QM's services, Postgres, and MinIO. Defaults to `oregon`. |
| `appRegion` | The region for newly published apps. Defaults to `region`. Each app stays in the region it was created in. |
| `corePlan` | Compute plan for core. Defaults to `2c-4g`, which fits QM's default of 16 run workers. If you choose a smaller plan, also lower `env.core.WORKERS`. |
| `servicePlan` | Compute plan for the portal, web UI, and plugin services. Defaults to `0.5c-512mb`. |
| `postgresPlan`, `postgresDiskSizeGB` | Plan and storage size for Render Postgres. Storage defaults to 10 GB and must be 1 GB or a multiple of 5 GB. |
| `storage.plan`, `storage.diskSizeGB` | Compute plan and disk size for MinIO. The disk defaults to 10 GB and can't shrink. |

Use current compute plan IDs like `2c-4g`. QM rejects retired plan names like `standard`. See [Compute plans](compute-plans).

QM's core service gets 300 seconds to shut down after Render sends it `SIGTERM`. To change how long core lets in-flight turns finish, set `env.core.SHUTDOWN_DRAIN_MS` (default `10000`), and keep it below `290000`.

### Custom domains

The default `onrender.com` URLs work without any DNS changes. To use your own domains:

1. Set `publicUrl` and `apiUrl` in `qm.config.jsonc` to HTTPS origins with _different_ hostnames.
2. Run `npm exec qm -- up`. QM adds each hostname as a custom domain and prints the DNS records to create.
3. Create those DNS records. Until both domains are verified, sandboxes and published apps can't reach core, and `qm check --live` fails.
4. Run `npm exec qm -- slack render` to update your Slack app manifests with the new `publicUrl`.

QM doesn't remove hostnames that you delete from your config. Remove them from the service in the [Render Dashboard](https://dashboard.render.com).

## Operate your deployment

```bash
npm exec qm -- status                 # Services, resources, and recorded releases
npm exec qm -- logs core --follow     # Stream core logs
npm exec qm -- up                     # Apply config changes or deploy a new QM commit
npm exec qm -- up --upgrade-minio     # Also move MinIO to the current QM commit
npm exec qm -- rollback --to <release-label-commit-or-deploy-id>
npm exec qm -- down                   # Suspend QM's services
```

- *Make changes with `qm up`.* QM records resource IDs and every release in `render.resources.json`. Keep this file with your deployment repository so later commands act on the same resources. QM reconciles service settings on each `qm up`, so prefer changing `qm.config.jsonc` over editing QM's services in the Render Dashboard.
- *MinIO upgrades are explicit.* A normal `qm up` keeps MinIO on its current source commit. `--upgrade-minio` moves it to the current commit and can briefly interrupt storage access.
- *Rollbacks don't reverse data changes.* `qm rollback` redeploys earlier service builds with your current environment values. It doesn't reverse database migrations or SQLite schema changes in published apps.
- *Suspending doesn't stop all charges.* `qm down` suspends QM's services, but Postgres and the MinIO disk keep running and continue to incur charges.

> *`qm down --purge` permanently deletes your data.*
>
> It deletes QM's services, Postgres, the MinIO disk, and all stored objects, including app backups. Back up app data and delete published app services first; purge refuses to continue while app services remain. Purge keeps the Render project and any workspace sandboxes.

## Learn more

- [QM repository](https://github.com/yc-software/qm)
- [QM deployment guide](https://github.com/yc-software/qm/blob/main/cli/templates/deployment/deployment.md) and [Render reference](https://github.com/yc-software/qm/blob/main/cli/templates/deployment/references/render.md)
- [QM CLI reference](https://github.com/yc-software/qm/blob/main/cli/README.md)
- [Render Sandboxes](sandboxes)
- [Projects and environments](projects)

---

##### Appendix: Glossary definitions

###### Render Postgres

Fully managed PostgreSQL databases that support point-in-time recovery, read replicas, high availability, and more.

Related article: https://render.com/docs/postgresql.md

###### persistent disk

A high-performance SSD that you can attach to a service to preserve filesystem changes across deploys and restarts.

Disables [zero-downtime deploys](/deploys#zero-downtime-deploys) for the service.

Related article: https://render.com/docs/disks.md

###### web service

Deploy this *service type* to host a dynamic application at a public URL.

Ideal for full-stack web apps and API servers.

Related article: https://render.com/docs/web-services.md

###### private service

Deploy this *service type* to host a dynamic application that is not internet-reachable.

Ideal for internal apps that only your other Render services can access.

Related article: https://render.com/docs/private-services.md

###### instance

A containerized environment that runs your service's code on Render.

You can select from a range of *compute plans* with different CPU and RAM specs.

###### compute plan

Specifies the CPU and RAM available to your service's *instances*.

Common compute plans for a new web service include:

- *`free`*: 0.1 CPU / 512 MB RAM
- *`0.5c-512mb`*: 0.5 CPU / 512 MB RAM
- *`1c-2g`*: 1 CPU / 2 GB RAM

Compute plans were previously known as *instance types*.

Related article: https://render.com/docs/compute-plans.md

###### region

Each Render service runs in one of the following regions: *Oregon*, *Ohio*, *Virginia*, *Frankfurt*, or *Singapore*.

Services in the same region can communicate over their *private network*.

Related article: https://render.com/docs/regions.md