Summary
A Qubes-isolated sandbox for AI agents — FastMCP server in a dedicated
mcp-control qube — that lets autonomous AI workflows provision qubes,
build templates, run pentests, and move files between them, all inside a
tag-scoped subset of the system. Untagged qubes remain structurally
invisible to the agent.
Stages A and B (below) are tested. Stages C–H are designed in CLAUDE.md.
Design summary
- Trust boundary = the qrexec tag
ai-managed. Tag mutation is
hard-denied to AI at the policy layer; only the operator (in dom0) and
the create-time wrapperqmcp.SpawnAIManagedQubeapply tags. - Dom0-mediated wrappers (
qmcp.*). State-changing calls route through
small Python scripts in/etc/qubes-rpc/that enforce invariants in
dom0 before touching qubesd: forced tagging on creation, cross-reference
validation ontemplate/netvm/default_dispvm, opaque error responses. - Wrapped reads hide existence.
qmcp.GetPropertyAIManagedreturns
"not found"indistinguishably whether the qube doesn’t exist or simply
isn’t tagged. The MCP-side helper normalises all qrexec failures (policy
deny, no-such-VM, transport error) to the same opaque error so the
lifecycle path doesn’t leak either.
Status
- Stage A (tested) — tag-scoped lifecycle, spawn (atomic tag-on-create
with rollback + post-condition check), wrapped property read/write,
existence hiding. - Stage B (tested) — root command execution and inter-qube file
transfer inside ai-managed qubes via custom qrexec services installed
in ai-managed templates. - Stages C–H (designed) — network sandbox + tag-validated netvm cascade,
template cloning + DispVMs, device attach between ai-managed qubes,
feature.Setwrapper + filtered event stream, mcp-control hardening +
Tor hidden service for sshd, FastMCP HTTP/SSE transport bound to a
second .onion for mobile-app reach.
Three review questions
For anyone familiar with the Admin API and qrexec policy R4.2+:
-
Wrapped-reads existence-hiding. Is returning a uniform
"not found"
from a dom0 wrapper a robust primitive against existence oracles, or
are there qrexec-layer leaks (timing, error chains, side effects)
I’m missing? -
qubes.Filecopybetween@tag:ai-managedqubes. Stage B adds a
policy line bypassing the defaultaskdialog for transfers between
ai-managed qubes. Are there assumptions inqubes.Filecopy’s
implementation that depend on the dialog being present? -
target=@adminvmdocumentation gap. Without that clause on
tag-scoped admin allows, qrexec attempts to start the target VM during
read-only operations. Subtle, easy to miss, not surfaced in current
docs. Worth a docs PR? Happy to write it.
Disclosure
AI-assisted implementation, human-designed boundaries. Not classical-engineer
credentialed but seriously trying to get the threat model right. Review
will find things I missed — that’s why this post is here.
— alex-schose