Self-host QM
One AI teammate for the whole team, each person with their own computer.
Shelley handles the setup. About 15 minutes.
Prefer a terminal?
curl -fsSL https://exe.dev/deploy/qm/prompt.txt | ssh exe.dev new --prompt=/dev/stdinQM, from Y Combinator, is an open-source AI teammate for a whole company. Everyone gets their own agent with private memory, files, and a computer to run commands on, and people can also work with it together in shared rooms and projects. An admin console sets the models, security rules, and who can do what.
On exe.dev it runs on one VM that stays on, with every person's computer as a container beside it. The VM is private: only people you share it with can reach it at all, and QM signs them in again. Model usage is billed to your exe.dev account through the LLM integration, so there is no API key to find.
What you get#
- QM at
https://<vm>.exe.xyz/, behind your exe.dev login and QM's own sign-in, with you as its administrator. - Claude through exe.dev's LLM integration, with no API key to paste, and GPT models in the admin console.
- Agent computers that run commands and keep their files, each in its own container on the VM.
- A stack that comes back by itself after a reboot.
- Nightly backups of the database, settings, and agent computers in
~/backups/qm.
What's running, and where
https://my-qm.exe.xyz/
The QM web app and admin console, behind your exe.dev login and a QM sign-in
Deploy with Shelley#
Click Deploy and Shelley will set up QM on a new VM, then check that it works. No config-file wrangling required.
Prefer a terminal?
curl -fsSL \
https://exe.dev/deploy/qm/prompt.txt \
| ssh exe.dev new --prompt=/dev/stdinWhat Shelley is told
Set up QM on this VM by following the exe.dev recipe at https://exe.dev/deploy/qm.md from top to bottom.
The recipe's example VM name is my-qm. This VM's name is the output of `hostname`: use it wherever the recipe writes my-qm. Skip the step that creates the VM; you are on it.
You are done when all of these are true. Check each one yourself:
- QM at `https://<vm>.exe.xyz/`, behind your exe.dev login and QM's own sign-in, with you as its administrator.
- Claude through exe.dev's LLM integration, with no API key to paste, and GPT models in the admin console.
- Agent computers that run commands and keep their files, each in its own container on the VM.
- A stack that comes back by itself after a reboot.
- Nightly backups of the database, settings, and agent computers in `~/backups/qm`.
Read the whole recipe, including the closed details. For initial setup,
follow "Install by hand" first, skipping VM creation and SSH. The
opening walkthrough is for the owner. Do not run the restore or update
instructions.
Keep the VM private. Never run share set-public. On an existing VM, ask
before replacing anything already on ports 7999-8002 or a `~/qm` folder.
Skip `qm doctor`: it tests the placeholder key against Anthropic
directly and always fails here. Run `fix-local-sandbox.sh` after every
`qm up`.
Verify `qm check` passes, `{"ok":true}` from the health check, the
patch reports itself in place, the backup timer, and a backup archive.
Don't set up Slack unless the owner asks. Do not reboot.
Finish by running `npm exec qm -- admin-login` in `~/qm` and giving the
owner the link it prints, saying it works once and expires in five
minutes; this conversation is private to the owner.
Finish with the URLs I should open.
Also at /deploy/qm/prompt.txt. The recipe it follows is /deploy/qm.md.
Sign in#
Shelley's last message holds a one-time admin link. It works once and expires after five minutes; for a new one, on your computer:
ssh my-qm.exe.xyz "cd qm && npm exec qm -- admin-login"
Open the link, sign in to exe.dev if asked, and click Sign in. You land in the admin console. Back to home opens the chat.
Warning
Keep this VM private. QM's agents run commands, and the VM holds everyone's conversations. Don't run
share set-public; share it with people instead, as below.
Give it some work#
Start a New session and try:
On your computer, check which Python version you have, write a script that prints the ten largest files under /usr, and run it.
The first command takes a few seconds while QM starts your computer, a container of your own. Files you leave in it are still there next time. Then try something longer-lived:
Every weekday at 9:00, send me a summary of the top five Hacker News stories.
The model menu under the message box switches between Claude models. Models in the admin console sets the default and turns GPT models on.
Bring in your team#
People need two things: access to the VM, and a QM invitation.
On your computer, share the VM with each teammate's email. This gives them the web app only, not a shell:
ssh exe.dev share add my-qm teammate@example.com
Then in QM's admin console, open Users, click Invite teammate, enter the same email, and click Send invite. QM can't send email from this VM, so click Copy invite link and send it to them yourself; it works for 24 hours. Each person gets their own memory and computer; rooms and projects are where you work together.
Keep it safe#
Everything lives on the VM: the database, each person's computer, and
the settings and secrets in ~/qm/.env. A nightly backup puts all of
it in one archive in ~/backups/qm and keeps the newest 14. Copy them
off the VM, too. On your computer:
rsync -av my-qm.exe.xyz:backups/qm/ ./qm-backups/
Keep those copies private: they hold every conversation and the keys that sign people in.
Setup and upkeep#
No need to read on unless you're curious—or doing it yourself.
Install by hand
On your computer (pick another name if my-qm is taken):
ssh exe.dev new --name=my-qm
ssh my-qm.exe.xyz
All remaining installation commands run on the VM, as exedev. QM
needs about 12 GB of disk; a default VM has room.
Install Node.js and start Docker on boot#
QM's command-line tool needs Node.js 24.15 or later. Docker must start on boot, so QM comes back after a restart:
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo systemctl enable --now docker.service
node --version
Expect v24.15 or later.
Create the deployment#
QM keeps a deployment in a folder of its own: settings, secrets, and the
skills and tools its agents get. team names your organization inside
QM and its containers:
mkdir -p ~/qm && cd ~/qm
npm exec --yes --package=@yc-software/qm@latest -- \
qm init . --org team --target docker --model-provider anthropic
npm install
npm exec qm -- --version
Expect 0.1.15 or later. npm install pins that version in
package.json, so the deployment doesn't change under you.
Point it at exe.dev#
Replace the generated settings. The portal takes port 8000, the one the
HTTPS proxy serves at https://<vm>.exe.xyz/, and the
model base URLs send Claude and GPT through the LLM integration:
cat > qm.config.jsonc <<EOF
{
"contract": 1,
"orgId": "team",
"publicUrl": "https://$(hostname).exe.xyz",
"basePort": 7999,
"target": "docker",
"modelProvider": "anthropic",
"model": "claude-sonnet-5-5",
"services": ["core", "web-ui", "admin", "portal", "auth"],
"plugins": [],
"skills": [],
"env": {
"auth": { "AUTH_EMAIL_TRANSPORT": "smtp" },
"core": {
"HARNESS": "pi",
"ANTHROPIC_BASE_URL": "https://llm.int.exe.xyz/anthropic",
"OPENAI_BASE_URL": "https://llm.int.exe.xyz/openai/v1"
}
},
"secretEnv": { "core": { "ADMIN_GRANTS": "ADMIN_GRANTS" } },
"sandbox": { "backend": "local" }
}
EOF
basePort puts core on 7999, the portal on 8000, the web app on 8001,
and the admin console on 8002. Those ports are private too. The
local sandbox gives each person a Docker container on this VM as their
computer. The email setting is required, but no mail server is set, so
QM sends no email; you sign in with one-time links instead.
Add the secrets#
qm init generated most secrets in ~/qm/.env, which only you can read.
Add the rest: you as administrator (your exe.dev email, from the
reflection integration), placeholder
model keys (exe.dev supplies the real credentials outside the VM),
core's address for the agent computers, and the sign-in keys:
setenv() { (umask 077; grep -v "^$1=" .env > .env.new || true; printf '%s=%s\n' "$1" "$2" >> .env.new; mv .env.new .env); }
unset_or_empty() { ! grep -q "^$1=." .env; }
ADMIN_EMAIL=$(curl -fsS https://reflection.int.exe.xyz/email | jq -r .email | tr 'A-Z' 'a-z')
setenv ADMIN_GRANTS "$ADMIN_EMAIL:org_admin"
setenv AUTH_ALLOWED_EMAILS "$ADMIN_EMAIL"
setenv ANTHROPIC_API_KEY exe-llm-integration
setenv OPENAI_API_KEY exe-llm-integration
setenv PUBLIC_API_URL http://qm-team-core:8080
for k in AUTH_CLIENT_SECRET AUTH_TOKEN_SECRET PORTAL_SESSION_SECRET; do
unset_or_empty $k && setenv $k "$(openssl rand -hex 32)"
done
unset_or_empty AUTH_SIGNING_JWK && setenv AUTH_SIGNING_JWK "$(node -e "const {generateKeyPairSync}=require('node:crypto');process.stdout.write(JSON.stringify(generateKeyPairSync('ec',{namedCurve:'P-256'}).privateKey.export({format:'jwk'})))")"
echo "admin: $ADMIN_EMAIL"
npm exec qm -- check
Expect your email and a passing check. It notes that sign-in email is
off and points to qm admin-login; that's expected. Teammates you invite
later get in by invitation, whatever this allowlist says.
Start QM#
The first start downloads about 4 GB of images and builds the agent computer image, which takes a few minutes:
npm exec qm -- up
curl -fsS http://127.0.0.1:8000/healthz; echo
Expect ✓ stack up — team and {"ok":true}. The containers restart on
their own after a reboot.
Let core reach the agent computers#
QM 0.1.15 doesn't tell core which container it runs in, so core can't
reach the agent computers, and every command fails with exec daemon never became reachable. The fix is
upstream but not released.
fix-local-sandbox.sh
copies that one-line change into the running core container and
restarts it. Run it after every qm up; once a release has the fix, it
says so and does nothing:
curl -fsSL -o ~/qm/fix-local-sandbox.sh https://exe.dev/deploy/qm/fix-local-sandbox.sh
chmod +x ~/qm/fix-local-sandbox.sh
~/qm/fix-local-sandbox.sh
~/qm/fix-local-sandbox.sh
Expect qm-team-core patched and restarted (or, on a fixed release,
already passes its container name), then already passes its container name the second time.
Set up nightly backups#
backup.sh writes one private
archive: the ~/qm folder, the QM tool's state in ~/.config/qm, a
database dump, and every agent computer's files.
restore.sh puts one back.
Lingering keeps the timer running when you're logged out:
curl -fsSL -o ~/qm/backup.sh https://exe.dev/deploy/qm/backup.sh
curl -fsSL -o ~/qm/restore.sh https://exe.dev/deploy/qm/restore.sh
chmod +x ~/qm/backup.sh ~/qm/restore.sh
sudo loginctl enable-linger "$USER"
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/qm-backup.service <<'EOF'
[Unit]
Description=QM backup
[Service]
Type=oneshot
ExecStart=%h/qm/backup.sh team %h/qm %h/backups/qm
EOF
cat > ~/.config/systemd/user/qm-backup.timer <<'EOF'
[Unit]
Description=Nightly QM backup
[Timer]
OnCalendar=*-*-* 03:30:00
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now qm-backup.timer
systemctl --user start qm-backup.service
tar -tf "$(ls -t ~/backups/qm/*.tar | head -1)"
systemctl --user list-timers qm-backup.timer
Expect ./qm.dump, ./deployment.tgz, and ./volumes/qm-team-coredata.tgz
in the archive, and a scheduled next run.
Sign in#
Print a one-time admin link, good for five minutes:
cd ~/qm && npm exec qm -- admin-login
Open it, click Sign in, and go give it some work.
Back up and restore
On the VM, take a fresh backup:
~/qm/backup.sh
To restore on the same VM, pick an archive. QM stops for a few seconds, and everything since that backup is replaced:
~/qm/restore.sh ~/backups/qm/qm-team-YYYYMMDD-HHMMSS.tar
curl -fsS http://127.0.0.1:8000/healthz; echo
Expect restored … and {"ok":true}. Agent computers start again from
their restored files the next time someone uses them.
Moving to a new VM? The archive's settings must be in place before QM
first starts there, because they hold the database password. On the new
VM, install Node.js and Docker,
copy the archive over with scp, then:
mkdir -p ~/restore && tar -C ~/restore -xf qm-team-YYYYMMDD-HHMMSS.tar
tar -C ~ -xzf ~/restore/deployment.tgz
cd ~/qm && sed -i "s|https://[a-z0-9-]*\.exe\.xyz|https://$(hostname).exe.xyz|" qm.config.jsonc
npm install && npm exec qm -- up && ./fix-local-sandbox.sh
./restore.sh ~/qm-team-YYYYMMDD-HHMMSS.tar
Then set up the nightly backups again.
Update
On the VM, back up, move to the newest QM, restart with it, and patch core again:
cd ~/qm &&
./backup.sh &&
npm install @yc-software/qm@latest &&
npm exec qm -- --version &&
npm exec qm -- check &&
npm exec qm -- up &&
./fix-local-sandbox.sh
Expect the new version, ✓ stack up — team, and a line from the fix.
Check QM's releases first:
there is no automatic rollback, so the backup is how you go back.
Something stuck?
Ask Shelley, or check on the VM:
cd ~/qm
npm exec qm -- status
npm exec qm -- logs core
docker ps --format '{{.Names}} {{.Status}}'
exec daemon never became reachable, or the agent says its computer is broken? Run~/qm/fix-local-sandbox.sh; anyqm upundoes it until QM ships the fix. Then ask the agent to try again.qm doctorsays Anthropic rejectedANTHROPIC_API_KEY? It tests the placeholder against Anthropic directly. Ignore it if chats get replies.- 401 or a QM sign-in page instead of the chat? Get a fresh link with
npm exec qm -- admin-login; each one works once, for five minutes. - A teammate can't get in? They need both the exe.dev share and a QM invitation, under the same email.
- No model replies? Check
ANTHROPIC_BASE_URLinqm.config.jsoncagainst the settings above, and your LLM integration. - Nothing after a reboot?
sudo systemctl enable --now docker.service; the containers start with Docker. - Out of disk?
df -h /; QM's images take about 8 GB. Grow the disk from your computer withssh exe.dev resize my-qm --disk=50GB.
Frequently asked questions#
What is QM?
An open-source agent from Y Combinator, built for a whole company rather than one person. Each person, and each shared room or project, gets its own memory, files, permissions, scheduled jobs, and computer. People reach it from a web app or Slack, and an admin console sets the rules.
What does it cost?
Your VM plan plus model usage, billed through the LLM integration. QM's admin console has a Spend page per person and session.
Can I use GPT models or my own key?
GPT models are already wired to the LLM integration; pick them in the admin console's Models page. To bring your own key, change the LLM integration, or put a real ANTHROPIC_API_KEY or OPENAI_API_KEY in ~/qm/.env, remove the matching base URL from qm.config.jsonc, and run qm up again.
How many people can use one VM?
Each person's computer is a container that starts when they need it, so memory is the limit. A few people fit on a default VM; for a bigger team, give it more with resize, for example ssh exe.dev resize my-qm --memory=16GB.
Can it work in Slack?
Yes. QM connects to Slack outward, so the VM can stay private. Ask Shelley to follow "Add the Slack bot" in ~/qm/deployment.md, the guide QM wrote for your deployment; it takes a Slack app you create from the manifest it renders.
Does it keep working when my laptop is closed?
Yes. QM runs on the VM, so scheduled jobs and webhooks carry on, and the whole stack comes back after a reboot.
Updated Oct 28, 2026 · tested end to end Oct 28, 2026 · Markdown · manifest.json · Something wrong? Tell us