Discover, decide, approve, contain, prove.
Finders map who is running. Logs replay what already happened. PyxGrant is the decision in the middle: the path to the sink, dual-control holds, a freeze that reaches every plane, and a receipt a skeptic can check without us. One Go binary. No vendor cloud in the path. Tools, models, other agents, browsers, and payments go through the same engine.
- Discover
- Decide
- Approve
- Contain
- Prove
Agents on the left, systems on the right, one decision in the middle.
Callers
PyxGrant
Systems
Find the agents nobody registered.
Read-only scans of each machine list the coding agents, the MCP servers they load, and plaintext secrets in their configs. Exports from your proxy, IdP, and SaaS tenants fill in the rest.
agents scan finds Claude Code, Codex, Gemini, Copilot, Cursor, and Windsurf. discover flags MCP servers not routed through PyxGrant, and lists local model ports (Ollama, LM Studio, vLLM-style) as [UNVERIFIED] — an open port is not proof the runtime is ungoverned. discover -grants classifies an OAuth or enterprise-app export.processes lists agent and MCP processes and whether each is behind a gateway, including ones started outside any config.shadow ingest classifies proxy, DNS, extension, process, and OAuth signals: sanctioned, shadow, personal tenant, or imitation.sanctioned enterprise ChatGPT personal-tenant chatgpt.com shadow meeting notetaker (Fireflies) imitation lookalike host shadow browser extension (Grammarly) found local model (Ollama), by process 4 signal families seen · 6 of 6 checks pass
One decision per call — and on the path that led here.
Each call is checked against your policy file: who is asking, which tool, what the arguments would do, and what the session has already read. The answer is allow, allow with redactions, hold for a person, or refuse. If the engine can't decide, it refuses.
pyxgrant laptop -apply installs the managed hook and starts hook-daemon -engine -profile hardened; it does not pass -admin-approval. A bare subprocess is still a smaller PEP. Pinning, path taint, the blast-radius gate, and a human hold sit behind the score. pyxgrant demo -consequence-close is the miss→stop walk on the Go binary. -guardrail-preset lakera is an opt-in request shape, not a certified integration.resources or prompts read, or a notification, taints that path the same way a tool result does. The finding names which source tainted the path. Off by default outside hardened.pyxgrant laptop (or egress-cage alone) can launch the agent or IDE under a Linux 6.7+ Landlock TCP lock to the sensor port — opt-in, UDP uncaged, not Windows or macOS. Windows child bounds are pyxgrant launch -confine / -confine-fs / -deny-net, not Landlock. Doctor FAILs an installed hook with the cage off. OS egress default-deny is still a separate MDM step.integrity.deny_unadvertised_tools is on (Hardened sets it), a tools/call for a name the server never listed is refused. Separately, tools/list is filtered to the tools the bound grant allows — the agent never sees a capability it was not granted.path untrusted ingest · no human break sink hostile/send_email · egress source tool-injection decision HOLD path:taint-source:tool-injection $ pyxgrant approve … human break · path cleared for later hops
Risky calls wait for a person, and silence means no.
A held tool call, model request, agent message, or browser step waits in one queue. An approver signs the decision with their own Ed25519 key. If nobody answers in ten minutes by default, the call is refused. The wait is configurable.
require_approvers: N waits for N distinct Ed25519 approver keys, each signing the exact payload — including on the coding-agent hook. A shared-secret HMAC name does not count toward a quorum. Signing twice as one key counts once. The first valid deny refuses the call. One approver is still the default.pyxgrant desk lists irreversible actions that landed and have no runnable undo, so they do not close silently.HOLD pay/wire dual-control:2-of-m · shown_hash bound ops Ed25519 · payload + what they saw sec Ed25519 · same payload · same shown released · both bound the bytes that run
Freeze, resume, revoke, or contain with two people.
Freeze pauses calls in flight and holds new ones until you resume — on the tool plane, the model plane, A2A, and AG-UI, including sampling and elicitation responses already returning, and mid-stream, tool-result, and A2A-response legs. Freezing a parent grant expands over the grant lineage on every plane, so a child-bound model or A2A call is held with the tool subtree. It can cover every session, one session, a workflow run, a grant, or a whole class of action such as payments or sending, while read-only work carries on.
pyxgrant grants revoke|verify re-reads the provider afterward: TARGET_VERIFIED means the grant is gone; TARGET_FAILED means the provider still shows it live after a self-reported OK. pyxgrant residual probes named targets; a probe error is UNPROVEN, not clean.session-replay — verify the chain, never re-run tools), run a recovery drill that seals a compensation plan without executing undos, show standing-access discover for dormant or over-privileged grants, and present the offline evidence pack path. Revoke-with-proof and pack export stay deliberate operator actions.contain act records pause and isolate with a 15-minute undo. Panic and kill_fleet need a second, different operator on -confirm, and they kill the target grant on the store, the revocation file, and the signed death stream. Break-glass dual-control is single-use: a replayed nonce is refused.hitl.risk_ladder (flag → hold → block → freeze) when you turn it on. Resume is always manual.$ pyxgrant freeze -grant g_root… lineage · all planes $ pyxgrant freeze -class pay payments only $ pyxgrant session-replay s_… $ pyxgrant recover s_… drill · no undo run $ pyxgrant grants revoke g_9ec3… --apply killed · then re-read provider TARGET_VERIFIED · gone on the IdP TARGET_FAILED · still live after “OK”
A record that holds up without trusting us.
Each decision is written to a hash-chained log, and the chain head is sealed with Ed25519. No plaintext secret is written to it. With the post-quantum driver enabled, receipts also carry an ML-DSA-65 co-signature over the same bytes. Anyone with the public key can verify offline.
pyxgrant evidence prove exports a self-contained pack, verifies it against a pinned published key, prints re-derived prevented-spend and closed-loop counts, then flips one byte of a copy so you see FAIL. The pack carries grant-kill certificates. A confirming read-back can mint a signed PhaseVerified receipt. Verify binds principal, grant, and verdict. evidence export|verify is the same pack without the walk. Embedded-key verify is integrity and re-derivation — not authenticity — until you pin an external key.pyxgrant noninclusion signs that a declared action did not occur across a run. Absent is refused unless every chain for the run verifies. A forged “absent” fails re-derivation.ediscovery searches by person, session, tool, or decision, and places legal holds.disclosures lists every record where PHI, PII, or a secret was found, and whether it was sent, redacted, or refused. showback totals debit and prevented spend from the signed ledger.prove -anchor must live in a tree that does not overlap the pack. witness enroll packs an external public key so a seal can be checked off this host. compliance -export writes assessor evidence with authorization_status=not-authorized.$ pyxgrant evidence export -out pack.json pack.json · receipts · chains · JWKS · closed-loop $ pyxgrant evidence verify pack.json -require-pq PASS hybrid PQ + Ed25519 · re-derived offline FAIL one flipped byte $ pyxgrant demo -killchain 15/15 monitor → … → prove $ pyxgrant demo -consequence-close CLEAN post forwards MISS scorer finds nothing · path tainted STOP same sink refused PROVE pack verifies offline
What the security owner sees.
These are screenshots of pyxgrant console, taken on a test machine while an agent's calls were waiting. Three calls are held for a person, each bound to the exact payload it will run with. Every row carries a signed receipt. Fleet search and paging sit in the same console. Host-sensor rows are shown with chain_verified:false until verified. Governed model-route can advise or enforce. Configuration and administration screens write through a versioned config store — append-only history, rollback as a new version, fail-closed on a bad document — so operators are not editing live policy files by hand.
/config in the same console; the store defaults to files on disk, or Postgres when you build and point it there.Mapped to OWASP, including the gaps.
This is the product's own map, printed by pyxgrant compliance. It marks what a runtime gateway covers, what it covers in part, and what sits outside it.
LLM Top 10 · 5 covered
resultsredactsanitiseholdbudgetLLM Top 10 · partial or none
partialpartialnonenonenoneAgentic Top 10 · 8 covered
coveredcoveredcoveredcoveredcoveredcoveredcoveredcoveredAgentic Top 10 · 2 partial
partialpartialRun it on your own machines.
One Go binary, your policy file, and no vendor cloud in the decision path.