google/sam is not Segment Anything. SAM here means Sovereign Agent Mesh, an Apache-2.0 networking project for autonomous AI agents. The problem it targets is concrete. Agents now run across cloud servers, on-prem datacenters, laptops, Raspberry Pis and Android devices. Letting them share tools usually means exposing internal scripts, LLM endpoints or private APIs to the public internet. SAM’s alternative is a zero-config, zero-trust P2P overlay — closer to a private VPN, but scoped to agent-to-agent tool sharing over the Model Context Protocol. Nodes discover each other automatically, survive NAT, and authorize every call cryptographically.
Note: The repo carries an explicit disclaimer: this is not an officially supported Google product.
Is it deployable?
Partially, the engineering is production-shaped, but the public mesh is still labelled a beta testnet.
- What ships now: Go binaries, an install script,
ghcr.ioDocker images, acharts/sam-meshHelm chart, a production Kubernetes guide, and Android/iOS support. The public testnet isbananas.sam-mesh.dev. For real workloads, self-host your control plane. The docs call this “DIY Mode” and it is the path to full data and policy control. - Company level: Best fit is mid-market and enterprise engineering orgs running agents across more than one network boundary. Startups inside a single VPC gain less; the value shows up once agents span cloud, datacenter and laptops.
- Industries: Financial services, healthcare, public sector and defense, and industrial or robotics edge fleets. Broadly, any regulated org that cannot publish internal tools to the internet.
- Applications: Cross-cloud MCP tool sharing, hybrid on-prem to cloud agent calls, brokered inference endpoints, sandboxed agents with credential injection, and pooled warm workers.
Architecture: three binaries
sam-control-plane— identity registration, token issuing, policy distribution.sam-router— libp2p bootstrap points and GossipSub routing overlays.sam-node— the P2P client providing mesh transport, self-healing connectivity, and a local MCP HTTP interface.
A node joins with sam-node join, then runs with sam-node run. libp2p uses 5001/udp and 5002/tcp; the local MCP API defaults to 8080.
Identity: OIDC in, Biscuit out
This is the interesting part. The control plane verifies an OIDC JWT. It then translates the claims into Datalog facts and seals them into a Biscuit token. sub becomes user(...), each group becomes group(...), and the peer ID binds in as client_peer_id(...).
The consequence: nodes authorize offline. A node evaluates the presented token against its own local rules without calling home.
Enforcement is strict default-deny. Access needs an explicit capability fact such as granted_service_exact(...). There are no built-in exceptions — even the discovery catalog system://sam.catalog must be granted. Services use a strict type://name convention with wildcard support (mcp://*, mcp://build-runner.*).
Every request runs a two-stage pipeline. Stage 1 gates the connection against ban and revocation caches. Stage 2 runs exactly two Biscuit authorizer passes. The first covers the node’s own identity token to emit target_fact assertions. The second covers the caller’s token. A baseline check blocks replay by requiring the connection peer ID to match the token.
Operators can attenuate locally, denying a write tool after 9 PM or blocking contractors. Local allows still cannot bypass control-plane check if constraints.
Interactive explainer
/* ———- pane 2 : default-deny ———- */
var GRANTS={
‘data-scientist’:[‘mcp://db-reader’,’inference://openrouter’],
‘developer’:[‘mcp://build-runner.ci’,’mcp://code-reviewer’,’mcp://git-helper’],
‘auditor’:[‘system://sam.catalog’],
‘unbound’:[]
};
var role=”data-scientist”,svc=”mcp://db-reader”;
$$(‘[data-r]’).forEach(function(c){c.addEventListener(‘click’,function(){
$$(‘[data-r]’).forEach(function(x){x.classList.remove(‘on’)});c.classList.add(‘on’);role=c.dataset.r;reset();});});
$$(‘[data-s]’).forEach(function(c){c.addEventListener(‘click’,function(){
$$(‘[data-s]’).forEach(function(x){x.classList.remove(‘on’)});c.classList.add(‘on’);svc=c.dataset.s;reset();});});
function reset(){
[0,1,2].forEach(function(i){root.querySelector(‘#st’+i).className=”stage”});
var v=$(‘#samVerdict’);v.className=”verdict”;
v.textContent=”Ready. Role “+role+’ \u2192 ‘+svc+’. Press send.’;
}
$(‘#samSend’).addEventListener(‘click’,function(){
[0,1,2].forEach(function(i){root.querySelector(‘#st’+i).className=”stage”});
var v=$(‘#samVerdict’);v.className=”verdict”;v.textContent=”Evaluating…”;
var allowed=GRANTS[role].indexOf(svc)>-1;
setTimeout(function(){root.querySelector(‘#st0’).className=”stage live”;},60);
setTimeout(function(){root.querySelector(‘#st0’).className=”stage pass”;
root.querySelector(‘#st1’).className=”stage live”;},560);
setTimeout(function(){root.querySelector(‘#st1’).className=”stage pass”;
root.querySelector(‘#st2’).className=”stage live”;},1120);
setTimeout(function(){
root.querySelector(‘#st2′).className=”stage “+(allowed?’pass’:’fail’);
if(allowed){v.className=”verdict ok”;
v.textContent=”ALLOW \u2014 the token carries granted_service_exact for “+svc+’. Request is proxied to the downstream service.’;
}else{v.className=”verdict no”;
v.textContent=”DENY \u2014 no granted_service fact for “+svc+’ under role ‘+role+’. Default-deny applies, so the node returns 403 Forbidden.’;}
resize();
},1700);
});
reset();
/* ———- pane 3 : gateway ———- */
var SEC={
‘api.openai.com’:{k:’Bearer’,v:’sk-proj-\u2022\u2022\u2022\u2022′},
‘api.anthropic.com’:{k:’CustomHeader x-api-key’,v:’sk-ant-\u2022\u2022\u2022\u2022′},
‘evil-exfil.example’:null
};
var host=”api.openai.com”;
$$(‘[data-h]’).forEach(function(c){c.addEventListener(‘click’,function(){
$$(‘[data-h]’).forEach(function(x){x.classList.remove(‘on’)});c.classList.add(‘on’);host=c.dataset.h;play();});});
function play(){
var log=$(‘#samLog’);log.innerHTML=”;
[0,1,2,3].forEach(function(i){root.querySelector(‘#bx’+i).classList.remove(‘live’)});
var s=SEC[host];
var steps=[
[0,’agent \u2192 GET http://’+host+’/v1/models (via HTTP_PROXY)’,”],
[1,’nano-init forwards raw bytes over Unix domain socket’,”]
];
if(s){
steps.push([2,’sam-box Biscuit verified \u2713′,’ok’]);
steps.push([2,’sam-box injecting ‘+s.k+’ = ‘+s.v,’warn’]);
steps.push([3,’upstream HTTPS GET https://’+host+’/v1/models \u2192 200′,’ok’]);
steps.push([0,’agent received response. Key never entered the sandbox.’,’ok’]);
}else{
steps.push([2,’sam-box Biscuit verified \u2713′,’ok’]);
steps.push([2,’sam-box no secrets.yaml entry for ‘+host,’bad’]);
steps.push([2,’sam-box request forwarded without credentials’,’bad’]);
}
steps.forEach(function(st,i){
setTimeout(function(){
[0,1,2,3].forEach(function(k){root.querySelector(‘#bx’+k).classList.remove(‘live’)});
root.querySelector(‘#bx’+st[0]).classList.add(‘live’);
var d=document.createElement(‘div’);
d.className=st[2];d.textContent=st[1];log.appendChild(d);resize();
},i*520);
});
}
$(‘#samPlay’).addEventListener(‘click’,play);
play();
/* ———- iframe auto-resize ———- */
function resize(){
try{
var h=(root.offsetHeight||600)+40;
if(window.parent&&window.parent!==window){
window.parent.postMessage({samMeshHeight:h},’*’);
}
}catch(e){}
}
window.addEventListener(‘load’,resize);
setTimeout(resize,120);setTimeout(resize,600);
window.addEventListener(‘resize’,resize);
})();
