Y Combinator team has open-sourced QM (quartermaster), the multi-agent harness it uses internally. QM is described as a multiplayer agent harness for work, running in Slack and on the web. YC team runs QM across accounting, legal, events, and engineering, including building QM itself. The whole project ships under the MIT license. YC frames the release as an experiment that is early and has bugs.
Is QM Deployable
Yes. QM is deployable today, but it is org software, not a desktop app. Deployment assumes a cloud account, Postgres, and someone comfortable with infrastructure. The best fit is a startup or mid-sized company, roughly 10 to 500 people, with at least one platform engineer. Larger enterprises can run it, but should review the security posture first.
Realistic industries include venture and professional services, fintech and accounting operations, legal operations, events, and B2B SaaS internal tooling. Applications named in the repository include searching internal notes, email, documents, databases, and the web together; triaging an inbox on a schedule with labels and reply drafts; working in an existing repository to run tests, open PRs, and monitor CI; and tracking a project in a shared channel.
Deploying QM does not require cloning the repository. An org-owned deployment repo depends on @yc-software/qm, then runs qm init with an org slug and a Fly.io or AWS target. Initialization materializes a deployment skill that walks through infrastructure, web sign-in, connectors, optional Slack access, and live verification. Sign-in defaults to a built-in broker that emails a one-time link, and an external identity provider can replace it. Each deployment runs in the operator’s own cloud account, and initialization does not create deployment CI. Teams that want core and customizations in one tree keep a private fork made by a plain clone, never GitHub’s Fork button. Details are in deployment.md and getting-started.md.
What is QM
Most agents are designed as personal assistants. The YC team argues that stretching one assistant across a whole company gets complex quickly. QM instead gives each employee an isolated workspace that others cannot affect. People also collaborate with the agent in channels, group messages, and projects.
Each person and each room gets its own scoped memory, files, keychain view, permissions, crons, web apps, and durable sandbox. The same identity and configuration carries between Slack and the web app. Skills are scope-owned and shareable by grant, with admin-gated promotion to the whole org. Skill packs can be imported from git repositories. Crons and watches run background work unattended.
/* ———- scene 1: turn ———- */
var steps=[
{w:’#w1′, from:[104,120], to:[150,76], box:’#n-core’,
t:[‘core’,’request arrives from Slack or web; identity and policy resolve’]},
{w:’#w2′, from:[225,106], to:[225,132], box:’#n-loop’,
t:[‘agent loop’,’the selected harness generates the response’]},
{w:’#w3′, from:[300,158], to:[348,125], box:’#n-sbx’,
t:[‘execute’,’a command runs in this scope’s isolated sandbox’]},
{w:’#w4′, from:[225,184], to:[225,206], box:’#n-db’,
t:[‘postgres’,’session history, memory, and queue state persist’]}
];
var dot=$(‘#qmDot’), running=false;
function moveDot(a,b,ms,done){
var t0=null;
dot.setAttribute(‘opacity’,’1′);
function step(ts){
if(!t0)t0=ts;
var p=Math.min((ts-t0)/ms,1), e=p<.5?2*p*p:-1+(4-2*p)*p;
dot.setAttribute(‘cx’,a[0]+(b[0]-a[0])*e);
dot.setAttribute(‘cy’,a[1]+(b[1]-a[1])*e);
if(p<1)requestAnimationFrame(step); else done&&done();
}
requestAnimationFrame(step);
}
$(‘#qmRun’).addEventListener(‘click’,function(){
if(running)return; running=true;
$$(‘#qmTurnList .qmw-li’).forEach(function(n){n.remove()});
$(‘#qmTurnList’).innerHTML=”;
$$(‘.bx’,$(‘.qmw-scene[data-scene=”1″]’)).forEach(function(b){b.classList.remove(‘hot’)});
$(‘#n-surf’).classList.add(‘hot’);
var i=0;
(function next(){
if(i>=steps.length){
dot.setAttribute(‘opacity’,’0′); running=false;
$(‘#qmTurnNote’).innerHTML=’Turn complete. The web UI, admin panel, and public portal are optional plugins over the core’s HTTP API; Slack is an optional in-process plugin.’;
resize(); return;
}
var s=steps[i];
$(s.w).classList.add(‘hot’);
moveDot(s.from,s.to,650,function(){
$(s.box).classList.add(‘hot’);
var d=document.createElement(‘div’);
d.className=”qmw-li”;
d.innerHTML=’‘+s.t[0]+’‘+s.t[1]+’‘;
$(‘#qmTurnList’).appendChild(d);
resize(); i++; setTimeout(next,320);
});
})();
});
/* ———- scene 2: harness ———- */
$$(‘#qmHarnessBtns .qmw-btn’).forEach(function(b){
b.addEventListener(‘click’,function(){
$$(‘#qmHarnessBtns .qmw-btn’).forEach(function(x){x.classList.remove(‘act’)});
b.classList.add(‘act’);
var h=b.dataset.h;
var el=$(‘#qmHName’); el.style.opacity=’0′;
setTimeout(function(){el.textContent=h; el.style.transition=’opacity .25s’; el.style.opacity=’1′;},120);
$(‘#qmLoopModel’).textContent=h;
$(‘#qmHNote’).innerHTML=’‘+h+’ selected. Memory, sandboxes, skills, and policy are unchanged by the swap.’;
});
});
/* ———- scene 3: postures ———- */
var postures={
strict:{
name:’Strict’,
note:’Strict. Every harness tool call pauses for human approval, except the two no-effect turn enders.’,
list:[[‘gate’,’human approval before each tool call’],[‘use’,’highest friction, highest control’],[‘scope’,’narrower scopes may only tighten, never loosen’]],
gate:’pause’
},
auto:{
name:’Auto’,
note:’Auto. A classifier screens provenance-labelled external data and tool results before they reach the model. A deployment can point that at its own screening proxy.’,
list:[[‘screen’,’classifier checks external data and tool results’],[‘default’,’the posture an org gets out of the box’],[‘proxy’,’point screening at your own service if you prefer’]],
gate:’screen’
},
danger:{
name:’Dangerous’,
note:’Dangerous. No content screening and no pauses between tool calls. The predeclared command policy still applies.’,
list:[[‘open’,’no screening, no pauses between calls’],[‘still on’,’hard denials for destructive commands remain’],[‘use’,’only where the operator accepts the risk’]],
gate:’open’
}
};
function drawChain(mode){
var g=$(‘#qmChain’); g.innerHTML=”;
var labels=[‘read email’,’query db’,’run script’,’post update’];
for(var i=0;i<4;i++){
var x=16+i*124;
var r=document.createElementNS(NS,’rect’);
r.setAttribute(‘x’,x);r.setAttribute(‘y’,44);r.setAttribute(‘width’,96);r.setAttribute(‘height’,44);
r.setAttribute(‘rx’,’6′);r.setAttribute(‘class’,’bx’);
r.style.animation=’qmin .3s ease both’; r.style.animationDelay=(i*0.09)+’s’;
g.appendChild(r);
var t=document.createElementNS(NS,’text’);
t.setAttribute(‘x’,x+48);t.setAttribute(‘y’,70);t.setAttribute(‘text-anchor’,’middle’);
t.setAttribute(‘class’,’tm’);t.setAttribute(‘font-size’,’10’);t.textContent=labels[i];
g.appendChild(t);
if(i<3){
var w=document.createElementNS(NS,’path’);
w.setAttribute(‘d’,’M’+(x+96)+’ 66 L’+(x+124)+’ 66′);
w.setAttribute(‘class’,’wire’+(mode===’open’?’ hot dash’:”));
g.appendChild(w);
var gx=x+110, badge=document.createElementNS(NS,’g’);
if(mode===’pause’){
var c=document.createElementNS(NS,’circle’);
c.setAttribute(‘cx’,gx);c.setAttribute(‘cy’,66);c.setAttribute(‘r’,9);
c.setAttribute(‘fill’,’#0E0E11′);c.setAttribute(‘stroke’,’var(–yc)’);c.setAttribute(‘stroke-width’,’1.5′);
c.setAttribute(‘class’,’pulse’); badge.appendChild(c);
var b1=document.createElementNS(NS,’rect’);
b1.setAttribute(‘x’,gx-3.5);b1.setAttribute(‘y’,62);b1.setAttribute(‘width’,2.2);b1.setAttribute(‘height’,8);b1.setAttribute(‘fill’,’var(–yc)’);
var b2=document.createElementNS(NS,’rect’);
b2.setAttribute(‘x’,gx+1.3);b2.setAttribute(‘y’,62);b2.setAttribute(‘width’,2.2);b2.setAttribute(‘height’,8);b2.setAttribute(‘fill’,’var(–yc)’);
badge.appendChild(b1);badge.appendChild(b2);
} else if(mode===’screen’){
var s=document.createElementNS(NS,’path’);
s.setAttribute(‘d’,’M’+gx+’ 56 l9 4 v6 c0 5 -4 9 -9 11 c-5 -2 -9 -6 -9 -11 v-6 z’);
s.setAttribute(‘fill’,’rgba(255,102,0,.18)’);s.setAttribute(‘stroke’,’var(–yc)’);s.setAttribute(‘stroke-width’,’1.3′);
s.setAttribute(‘class’,’pulse’); badge.appendChild(s);
}
g.appendChild(badge);
}
}
var cap=document.createElementNS(NS,’text’);
cap.setAttribute(‘x’,16);cap.setAttribute(‘y’,26);cap.setAttribute(‘class’,’tm’);
cap.setAttribute(‘font-size’,’9.5′);cap.setAttribute(‘letter-spacing’,’1.3′);
cap.textContent=mode===’pause’?’EACH CALL PAUSES FOR APPROVAL’:(mode===’screen’?’INBOUND DATA AND TOOL RESULTS ARE SCREENED’:’CALLS CHAIN WITHOUT PAUSES’);
g.appendChild(cap);
}
drawChain(‘screen’);
$$(‘#qmPostureBtns .qmw-btn’).forEach(function(b){
b.addEventListener(‘click’,function(){
$$(‘#qmPostureBtns .qmw-btn’).forEach(function(x){x.classList.remove(‘act’)});
b.classList.add(‘act’);
var p=postures[b.dataset.p];
drawChain(p.gate);
$(‘#qmPName’).textContent=p.name;
$(‘#qmPNote’).innerHTML=p.note;
var box=$(‘#qmPList’); box.innerHTML=”;
p.list.forEach(function(o,i){
var d=document.createElement(‘div’); d.className=”qmw-li”;
d.style.animationDelay=(i*0.06)+’s’;
d.innerHTML=’‘+o[0]+’‘+o[1]+’‘;
box.appendChild(d);
});
resize();
});
});
(function(){
var box=$(‘#qmPList’);
postures.auto.list.forEach(function(o,i){
var d=document.createElement(‘div’); d.className=”qmw-li”;
d.style.animationDelay=(i*0.06)+’s’;
d.innerHTML=’‘+o[0]+’‘+o[1]+’‘;
box.appendChild(d);
});
})();
/* ———- scene 4: deploy ———- */
var deploys={
dir:{
name:’Deployment directory’,
cmd:’$ qm init . –org
core:[‘@yc-software/qm’,’published package’,’no source checkout needed’],
org:[‘deploy/layers/<org>/’,’config · sandbox · skills’,’plugin images · infra’,’never travels upstream’],
list:[[‘who’,’teams that want config, not code’],[‘how’,’an org-owned repo depends on the package’],[‘then’,’a deployment skill walks through infra, sign-in, connectors, Slack, and live checks’]],
note:’Operator-owned. Each deployment runs in the operator’s own cloud account. Initialization does not generate or enable deployment CI.’
},
fork:{
name:’Private fork’,
cmd:’$ git clone –bare git@github.com:yc-software/qm # then push –mirror’,
core:[‘core stays byte-identical’,’to upstream’,’which keeps merges small’],
org:[‘deploy/layers/<org>/’,’private customizations’,’update-qm merges upstream in’,’upstream-pr sends fixes back’],
list:[[‘who’,’engineers who want core and customizations in one tree’],[‘method’,’a plain clone, never GitHub’s Fork button’],[‘why’,’a fork of a public repo cannot be made private’]],
note:’Trade-off. The clone is an ordinary repository, so upstream CI workflows run in your own account. Supply their secrets or disable them.’
}
};
function renderDeploy(k){
var d=deploys[k];
$(‘#d-cmd’).textContent=d.cmd;
[‘d-core-l1′,’d-core-l2′,’d-core-l3’].forEach(function(id,i){$(‘#’+id).textContent=d.core[i]||”});
[‘d-org-l1′,’d-org-l2′,’d-org-l3′,’d-org-l4’].forEach(function(id,i){
var el=$(‘#’+id); el.innerHTML=d.org[i]?d.org[i]:”;
});
$(‘#qmDName’).textContent=d.name;
$(‘#qmDNote’).innerHTML=d.note;
var box=$(‘#qmDList’); box.innerHTML=”;
d.list.forEach(function(o,i){
var el=document.createElement(‘div’); el.className=”qmw-li”;
el.style.animationDelay=(i*0.06)+’s’;
el.innerHTML=’‘+o[0]+’‘+o[1]+’‘;
box.appendChild(el);
});
resize();
}
renderDeploy(‘dir’);
$$(‘#qmDeployBtns .qmw-btn’).forEach(function(b){
b.addEventListener(‘click’,function(){
$$(‘#qmDeployBtns .qmw-btn’).forEach(function(x){x.classList.remove(‘act’)});
b.classList.add(‘act’); renderDeploy(b.dataset.d);
});
});
/* ———- auto-resize ———- */
function resize(){
try{
var h=document.querySelector(‘.qmw’).offsetHeight+40;
parent.postMessage({qmHeight:h,frameHeight:h},’*’);
}catch(e){}
}
window.addEventListener(‘load’,resize);
setTimeout(resize,150); setTimeout(resize,600); setTimeout(resize,1400);
window.addEventListener(‘resize’,resize);
})();
” style=”width:100%;border:0;overflow:hidden;display:block;background:#0B0B0D;border-radius:12px;” height=”900″ scrolling=”no” loading=”lazy” title=”How Y Combinator’s QM harness works”>
Architecture
Every turn runs through a central headless core. The core handles API, identity, policy, and scheduling, and drives an agent loop. A Postgres layer holds user data, session history, and other durable state. The agent has a small, fixed tool surface. One of those tools is execute, which runs commands in the scope’s own isolated sandbox, where installed tools stay installed.
QM is harness-agnostic. Pi, OpenCode, Codex, and Claude Code all drive the same core, so a deployment is not tied to one vendor. The core runs TypeScript directly on Node and uses Fastify for HTTP. The Slack plugin uses Bolt; the web UI builds with Vite and renders with Lit. The web UI, admin panel, and public portal are optional plugins over the core’s HTTP API.
Security Model
QM follows the pattern of local coding agents. The agent acts as the person it works for, with their credentials and permissions, and everything is audited. An org picks one posture, which narrower scopes can only tighten. Strict pauses every harness tool call for human approval, except two no-effect turn enders. Auto, the default, screens provenance-labelled external data and tool results with a classifier before they reach the model. A deployment can point that classifier at its own screening proxy. Dangerous removes content screening and pauses. A predeclared command policy, with hard denials for things like recursive deletes and destructive SQL, applies in every posture including Dangerous. The threat model and known limitations are in SECURITY.md.
Key Takeaways
- YC open-sourced QM under an MIT license, for Slack and web.
- Every person and every room gets isolated memory, files, keychain view, permissions, crons, and sandbox.
- Pi, OpenCode, Codex, and Claude Code all drive the same core, so deployments avoid vendor lock-in.
- Three org security postures gate tool calls, and destructive-command denials apply in all three.
- YC runs it across accounting, legal, events, and engineering, and calls it early and buggy.
Check out the GitHub Repo and Project Page. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks. Also, feel free to follow us on Twitter and don’t forget to join our 100k+ ML SubReddit and Subscribe to our Newsletter.
Asif Razzaq is the CEO of Marktechpost Media Inc.. As a visionary entrepreneur and engineer, Asif is committed to harnessing the potential of Artificial Intelligence for social good. His most recent endeavor is the launch of an Artificial Intelligence Media Platform, Marktechpost, which stands out for its in-depth coverage of machine learning and deep learning news that is both technically sound and easily understandable by a wide audience. The platform boasts of over 2 million monthly views, illustrating its popularity among audiences.
