Your coding agent will eventually try to deploy before the tests pass, or approve its own pull request, or retry a flaky call and charge the customer twice. Your system prompt politely asks it not to. It does anyway. This post is about the layer that makes those moves not discouraged but unreachable — a call the model literally cannot place.
Praxec sits between the model and your tools as a single checkpoint, and the model only ever sees two tools through it: praxec.query for reads and praxec.command for writes. Everything below is the payload.
The controls that don’t fit in a tool definition
A tool definition can describe a tool: name, arguments, schema. It cannot say any of the things you actually want said about a dangerous action:
- only after the tests have passed
- never without a human in the loop
- at most three times, then stop
- and write down every attempt, including the refused ones
Those aren’t properties of a tool. They’re policy. And policy needs somewhere to live that every call has to pass through. That’s the kernel: a single checkpoint where the rules are enforced instead of hoped for.
What the kernel enforces before the executor runs
Three checks happen between a call arriving and a tool actually running. Each can stop the call cold.
- Schema validation. A transition’s
inputSchemais JSON Schema, and it runs before the executor. Malformed input, a missing required field, a value outside an enum — rejected withINPUT_SCHEMA_VIOLATION, and the tool never sees it. - Guards. Preconditions evaluated before the move is allowed to fire — permission, role, an expression over workflow state, or recorded evidence. Fail one and the move is refused with
GUARD_REJECTED. - Actor checks. Mark a move
actor: humanand the model is never offered the link; if it submits the move anyway, the kernel rejects it withACTOR_MISMATCH. Not a prompt it agrees to and ignores two turns later — a hard gate.
And the move it isn’t offered from this state at all? That returns INVALID_TRANSITION — the move doesn’t exist here, so there’s nothing to talk its way around.
Where the guarantees stop — the honest part
Most tools skip this section. Here it is. The permission and role guards assume a deployment with real identity wiring; the bundled binary treats every caller as anonymous, which is the right default for a developer on a laptop but is not a security boundary — wire in real identity before you lean on those guards for isolation. Links guide the model but don’t bind it; enforcement is the guards and actor checks, not the links. And how airtight the whole thing is depends on how you run the kernel: sitting behind an editor as a gateway, it governs every capability routed through it but not the host’s own built-in shell. The docs spell out each mode and what it enforces.
The point isn’t that the kernel makes your agent unhackable. It’s that the controls which don’t fit in a tool definition finally have a place to live — one checkpoint, every call passes through it, and the refusals are recorded whether or not the model tries to route around them.