YC Open-Sourced Its Internal Agent Harness. Read QM's SECURITY.md First.
QM gives every employee and every Slack room its own scoped memory, files, permissions, and sandbox. Its own threat model then lists thirteen places that scoping stops holding, and that list is more useful than the code.
Most agent repos ship a README that describes what the thing does and a SECURITY.md that says "please report vulnerabilities privately." Y Combinator open-sourced QM on July 31, the multiplayer agent harness its announcement says it uses internally across accounting, legal, events, and engineering. The README is good. The SECURITY.md runs about 160 lines, and a large part of it documents limitations, incomplete controls, trust assumptions, and places where the isolation model does not give a hard guarantee.
"Command policy is bypassable." "Sandbox credentials are plaintext while in use." "Audience-floor filtering has known gaps." "Admins can read sensitive content." "Durable data can outlive user expectations."
That is a company publishing, under its own name, the exact document a security reviewer would spend three weeks trying to reconstruct from the source. It is the most useful thing in the repo, and I suspect most people cloning it this weekend will not open it.
The design problem QM is actually solving
Start with what makes QM different from the harness you already run.
Many popular agent harnesses begin from a single-user mental model: one person, one workspace, one memory store, one set of credentials, one agent identity. You can stretch that across a company, and the README says so directly: "Most agents are designed like personal assistants. You can make one work for a whole company, but it quickly gets complex."
QM's organizing idea is that the unit of isolation is a scope. Most visibly a scope is a person or a shared room, with grants and scoped resources built around it. Each one gets its own memory, files, keychain view, permissions, crons, web apps, and a durable sandbox. Your agent in your DM knows your things. The agent in the #payments channel knows the channel's things. The same identity follows you between Slack and the web UI. Skills are scope-owned and shared by explicit grant, with admin-gated promotion to the whole org.
Underneath, the core is TypeScript on Node with Fastify, Postgres holds sessions and durable state, the Slack surface uses Bolt, and the web UI builds with Vite and renders with Lit. The agent has a small fixed tool surface, and one of those tools is execute, which runs commands inside that scope's own sandbox. Harness and model are pluggable: Pi, OpenCode, Codex, and Claude Code all drive the same core, so a deployment is not tied to one vendor. MIT license, and it runs in your own cloud account.
What happens when a dozen people share an agent that remembers things is a question single-user harnesses never had to answer, and "give each principal its own everything" is the right shape for it.
The honest part
Now the file I actually want you to read.
QM's SECURITY.md opens by refusing the obvious marketing move. "QM is designed to isolate each person's data and activity by scope. It is early, experimental software: that design goal is not a promise that data cannot leak, a certification, or a substitute for a deployment-specific security review."
Then it names thirteen limitations. A few that matter if you are thinking about deploying this:
Command policy is a speed bump. It classifies shell text and catches configured or common dangerous forms. The doc says obfuscation, encoding, or writing a script and then executing it can evade it, and calls it "a speed bump against mistakes and injection, not a sandbox boundary." Calling it a speed bump is the useful part, because it stops readers from mistaking command classification for a sandbox boundary.
Sandbox credentials are plaintext while in use. Credentials materialized into a sandbox as environment variables or files are readable by processes in that sandbox. Scope isolation and auditing limit exposure, and short-lived capabilities expire. None of that stops a compromised agent process from spending or exfiltrating a usable credential.
Credential purposes are not enforced authorization. This is the subtle one and I think it is the most important paragraph in the file. When you grant a credential with a stated purpose, core enforces the grant's owner, audience, mode, expiry, revocation, and audit. The purpose text travels with the credential as an instruction to the model and an audit field. Core does not evaluate whether a later command stays inside that purpose. So the guardrail that feels like a permission is a note, and the model is the thing reading it.
Browser actions sit outside some core gates. Actions inside the browser runner do not re-enter command policy or human-in-the-loop approval, and browser traffic exits through the browser provider rather than QM's egress proxy.
Admins can read sensitive content. A scope-authorized admin can read transcripts, captured provider requests, documents, memory, connector and keychain metadata, mirrored message bodies, ambient-judge inputs, user details, and skill bodies. The read is audited. It is not separately consent-gated. If you sell "everyone gets their own private workspace" to your team, that sentence is the one you have to say out loud during rollout.
Some governance and data-loss controls are absent. The thirteenth item is the one I would put in front of a compliance reviewer first: "Standing-instruction edits are not uniformly bounded by an org floor or human approval, governance changes are not uniformly versioned or revertible, provider-side token revocation and an org kill switch are incomplete, and secret scanning on file write is not implemented." No kill switch is a sentence with operational weight.
The README names three security postures, and names them with useful bluntness. In Strict, "every harness tool call pauses for human approval, except the two no-effect turn enders." In Auto, the default, "a classifier screens provenance-labelled external data and tool results before they reach the model," and a deployment can point that at its own screening proxy. The third is called Dangerous: "no content screening, no pauses between tool calls." Naming the permissive mode Dangerous instead of dressing it up as a performance setting makes the tradeoff harder for an operator to misread.
The doc is equally blunt about what a human click buys you: "an approval means a human accepted the displayed action under the information available at that time, not that the resulting behavior is safe."
One more detail I liked, unrelated to agents entirely. Newly published npm versions must age 7 days before they can enter a lockfile, enforced by min-release-age=7 in .npmrc. That is a direct response to compromised-maintainer supply chain attacks that get caught and yanked within hours. CI installs with npm ci from committed lockfiles and is unaffected.
Two mechanisms worth stealing even if you never deploy it
The thesis of the whole repo is one line from the threat model: "The agent and software it runs in a sandbox are not trusted to make authorization decisions." Two pieces of the implementation actually live up to that, and both are small enough to copy.
Consolidation is a diff, not a blob. QM does not put long-term memory in a vector store. Each scope gets a markdown notebook of atomic bullets in Postgres, with capture dates and a provenance suffix like (said in #engineering). Three strategies decide how facts get in: per-turn extraction by default, scratch-promote for buffering until something proves durable, or agent-only where the model manages its own notebook with explicit tool calls.
The interesting part is what happens when the notebook grows. After roughly ten new bullets accumulate below a <!-- consolidated: date --> marker, a background pass asks the model to clean up, and the reply format is constrained: UPDATE <n>: <revised fact>, DELETE <n>, ADD: <new fact>, or NONE. Not a rewritten notebook. A list of operations. The prompt also says "NEVER delete or weaken a fact the user explicitly asked to remember," and requires (said in …) suffixes to survive verbatim so facts from different sources never get merged into one.
Ask your own agent to "summarize and tidy your memory" and you get a new blob you cannot review. Ask it for UPDATE, DELETE, ADD, or NONE and you get a diff, which means an operator can see exactly what the agent decided to forget. That is a five-line change to most memory implementations and a large change to how auditable they are. QM does not apply the discipline everywhere: the scratch-promote path still asks the model to "Output the COMPLETE new notebook as markdown," which is the blob shape the consolidation prompt avoids.
The sandbox has no ambient network trust. Container isolation stops an agent from wrecking the host. It does nothing about a prompt injection that tells the agent to tar up its files and POST them somewhere. So sandbox traffic in QM goes through a standalone authorizing egress proxy. Every outbound request has to present a signed capability token in the proxy-authorization header, checked for the right audience before anything leaves, and untokened traffic is denied by default. A deployment can opt out of that with EGRESS_TOKENLESS=open, which is worth knowing before someone sets it during a debugging session and forgets. The proxy drops link-local and metadata addresses by range and by name: 169.254.0.0/16, fe80::/10, fd00:ec2::254, metadata.google.internal, metadata.goog. Blocking cloud metadata by hostname closes the path where a compromised agent trades a prompt injection for your instance IAM credentials. And after resolving a hostname, the proxy re-checks the resolved IP against the deny ranges before connecting, which is the standard defense against DNS rebinding. Every decision lands in an audit sink.
Then SECURITY.md tells you where that stops: "Force-through egress depends on backend network enforcement, and core does not yet reject every backend that is too coarse for the requested policy. Deployment-runtime egress enforcement is not built." The proxy is careful. Whether your deployment is actually forced through it depends on a backend that core does not fully verify yet. Both halves are in the repo, which is the point of this article.
Put this into practice
You do not need to deploy QM to get value from it this week. Three paths, in increasing order of effort.
1. Read SECURITY.md as a checklist against your own setup (30 minutes). Go through the thirteen limitations and answer, for whatever agent your team already shares: is this true of us too? Most will be. Almost none will be written down anywhere.
Make it produce an artifact. For each row, write Yes, No, or Unknown, then name the control, the evidence, and an owner. Every Unknown becomes a security-review task.
| QM question | Our answer | Existing control | Evidence | Owner |
|---|---|---|---|---|
| Can shell policy be bypassed? | Yes / No / Unknown | |||
| Can sandboxed processes read live credentials? | ||||
| Are credential purposes technically enforced? | ||||
| Do browser actions bypass approval gates? | ||||
| Can admins read user content, and is that disclosed? | ||||
| What data has no retention or deletion path? | ||||
| Is there a kill switch, and who can pull it? |
2. Draft your posture model in an afternoon. Implementing it takes longer. Three named postures, with the org setting a floor that narrower scopes can only tighten, plus a predeclared command policy of approval rules and hard denials that applies in every posture including the permissive one. That last clause is the design decision worth copying. Even in Dangerous mode, recursive deletes and destructive SQL still hit the policy. Most homegrown setups have one global "are we asking for confirmation" flag and nothing that survives turning it off. Writing the policy down is an afternoon. Wiring it into real authorization and approval plumbing is a project.
3. Stand up a deployment (a day or more, and real infrastructure). Initialization is one command plus an install. The README uses @latest:
npm exec --yes --package=@yc-software/qm@latest -- \
qm init . --org <slug> --target <fly-or-aws>
npm install
For a reproducible deployment I would pin the version instead, so a rerun next month materializes the same thing:
npm exec --yes --package=@yc-software/qm@<exact-version> -- \
qm init . --org <slug> --target <fly-or-aws>
npm install
That creates an organization-owned deployment repository, materializes a deployment skill for an agent, and walks through infrastructure, web sign-in, connector credentials, optional Slack access, deployment, and live verification. No source checkout needed. Everything company-specific lives in that deployment repo; core stays identical to upstream, which is what keeps your merges small later.
One trap worth naming before it bites you. If you want the whole codebase private rather than just a config layer, the docs tell you to make a private clone, not a GitHub fork, and they are right. A GitHub fork inherits the visibility of its parent, so a fork of a public repo cannot be made private, and forks share one object network, meaning commits you push stay fetchable by SHA from the public side. Use the bare-clone-and-mirror-push recipe in the README. The cost of the plain clone is that upstream's CI workflows run live in your account, so plan to supply secrets or disable the workflows you do not want.
Honest limitations
The repository is days old, and its visible history begins as a fresh source export rather than YC's internal development history. That matters more than the star count, which has moved a lot in its first days and will keep moving. You can inspect the current code. You cannot audit the evolution that produced it. The security policy is explicit that this is deliberate: "Public source releases must start from a fresh export; publishing a private repository's existing history is explicitly unsupported." The Hacker News thread picked at the same seam from a different angle, noting that the adrs/ directory the contribution model depends on was empty at launch.
A serious deployment still means owning cloud infrastructure, identity configuration, persistent storage, secrets, and an audit obligation, even though the initializer walks you through much of the setup. This is not npx and go.
QM's interactive surfaces assume one organization of authenticated internal users. The doc is explicit that this is not a hardened public or multi-tenant service boundary, with published apps as a deliberate exception where a capability link is bearer authorization: "Anyone who obtains a link can reach that app without establishing an identity, and the link is not bound to an intended recipient."
A harness YC tuned for accounting, legal, events, and its own engineering carries assumptions about how work flows that may not match yours. The permission model is portable. The workflow opinions baked into the seed skills probably are not.
And the deepest limitation is one QM cannot fix and says so. Core is supposed to enforce identity, scope, grants, and delivery around the model. Every place that enforcement is heuristic, you are relying on a model's judgment about text a stranger may have written, and the doc does not soften it: "Classifier approval is not authorization and cannot guarantee prompt-injection resistance."
What I would watch
The interesting question is not whether QM wins as a harness. It is whether publishing a thirteen-item known-limitations list becomes normal.
Right now it reads as unusual candor. It should read as the minimum. Any team running a shared agent has this list; the only variable is whether anyone wrote it down and whether the people using the agent got to see it. YC just made writing yours much cheaper, because you can open theirs and cross out the lines that do not apply.
If you deploy this and find a fourteenth limitation, the SECURITY.md tells you exactly where to send it, and not to a public issue. I would like to hear what it was.
Sources: yc-software/qm README, qm SECURITY.md, Y Combinator announcement, Hacker News discussion.