In the first post in this series, we introduced a simple idea: The sandbox should contain the Actor. The Intent Container should contain why the Actor exists.
That distinction sounds conceptual until you try to build it. An agent begins with something decidedly unlike a kernel security policy:
Analyze quarterly revenue and prepare a board-ready report using internal financial data.
Eventually, however, that objective becomes very concrete. An Actor starts. It queries a database. It executes binaries. It opens files. It creates subprocesses. It connects to network endpoints.
Somewhere between those two worlds, “prepare a board-ready report” has to become a set of boundaries a machine can actually enforce. That is what we have been building with intentd.
Our first reference implementation follows a path from an ArmorIQ objective through Google Agent Substrate and into a Kata microVM running our KAP-enabled Linux kernel. The important part is not any individual component or vendor. It is that the objective remains connected to execution all the way down.
An objective is not a kernel policy
Suppose our revenue-analysis agent is allowed to query internal financial data, create aggregate reports, and save the results internally. It should not export raw transactions to an external API or suddenly acquire a new tool because that makes the task easier. ArmorIQ’s Purpose Assurance Plane, PAP, handles the first part of this problem.
PAP treats agent behavior as a sequence of refinements from human purpose toward increasingly executable behavior. Its authority model grounds what an agent can do in executable interfaces, constraints, and execution context. As the agent refines an objective into a plan, ambiguity can decrease, but authority should remain bounded.
That still leaves us with a plan. The Intent Assurance Plane, IAP, turns the accepted plan into something we can carry through execution. It canonicalizes the plan into a structured reasoning graph, commits that structure cryptographically, and binds it to identity and context. Delegation, re-anchoring, and revocation become explicit trust transitions rather than invisible changes inside an agent session.
At this point we know two useful things. We know what authority the objective should have, and we know which committed execution lineage that authority belongs to. Now we have to make a Linux process obey it.
This is where intentd enters the path
intentd sits between the assurance control plane and the agent runtime.
For every running objective, it maintains the state that needs to survive beyond an individual Actor: the objective identity, committed lineage root, current authority, authority epoch, delegation state, and lifecycle.
Conceptually, an Intent Container might therefore carry something like:
Objective
Analyze quarterly revenue
Intent ID
ic-4f2a9c
Authority
Read /finance
Execute /bin/ls
Execute /bin/cat
Connect api.ate-system.svc:443
Constraints
Internal only
No external calls
Lineage Root
7b3d...
Authority Epoch
1
This is where the Intent Container starts becoming more than metadata. intentd consumes the bounded authority produced by PAP and the committed lineage produced by IAP, reconciles them with current lifecycle state, and carries the resulting assurance state in a grant the execution environment can consume.
The expensive semantic and cryptographic work happens upstream. PAP interprets refinement and decides what authority is justified and bounded. IAP canonicalizes and commits the accepted plan, constructs its Merkle lineage, and signs or verifies trust transitions. intentd maintains the current Intent Container state across lifecycle changes and runtime boundaries. We deliberately do not want any of those operations on every syscall.
The first Agent Substrate adapter carries the grant, but does not need to understand it
The next question is how this authority reaches an Actor. In this reference implementation, we want the integration with Google’s Agent Substrate to remain intentionally boring. We do not want Agent Substrate to understand ArmorIQ. It should not need to know what an Intent Container is. It should not parse PAP authority lattices, understand IAP Merkle roots, or compile KAP predicates.
Instead, the Actor’s template carries a generic enforcement configuration and an opaque grant. Conceptually:
spec:
enforcement:
provider: kap
failClosed: true
grantRef:
name: revenue-analysis-grant
The assurance state relevant to execution remains inside the grant. This adapter’s job is simply to ensure that the enforcement material reaches the Actor and that the required enforcement step succeeds before the Actor becomes active. This separation matters because neither side needs to absorb the other’s semantics.
Google Agent Substrate manages the Actor lifecycle in this first adapter. intentd manages the objective lifecycle. The same separation can hold across AWS AgentCore, Microsoft agent runtimes, Kubernetes or Lynx, SaaS services, and local execution.
Kata puts the KAP reference backend where the Actor’s syscalls actually happen
For this reference path, our first instinct might be to enforce on the machine hosting Agent Substrate. That turns out to be the wrong place. The Actor executes inside a Kata guest running under Cloud Hypervisor. Its actual Linux processes live underneath the guest kernel, not the host kernel.
That is exactly where KAP needs to be. Fortunately, the guest kernel is already a configurable Kata runtime asset. Our KAP-enabled 6.18.35-kap kernel can therefore be selected through Kata configuration without requiring Agent Substrate itself to know that KAP exists.
The resulting separation is clean:
Human Purpose → PAP / IAP → intentd → Intent Container → Agent Substrate → Kata microVM → KAP guest kernel → Actor processes
The host needs KVM. The guest gets KAP. And because the Actor is a normal Linux workload inside that guest, KAP sees the operations we actually care about: execve, file access, socket connections, process creation, namespace transitions, and other kernel-visible effects.
Before the Actor runs, we bind it to the objective
Getting the right kernel underneath the Actor is only half the problem. The kernel still needs to know which objective this particular workload belongs to. For that, we use a small guest-side component called kap-bind.
Before the real Actor workload executes, kap-bind receives the objective grant, mounts the KAP interface, creates an intent group, installs the compiled authority, records the committed lineage root and authority epoch, and binds the workload into that group.
There is an important wrinkle here. kap-bind runs as an OCI prestart hook, but Kata’s current hook path logs a failed hook and allows startup to continue. Without another safeguard, a bind failure can therefore leave the workload running outside its intended KAP boundary. Our prototype closes that gap with a kernel-side setting, kap.default=closed, that causes execution without a successful bind to fail closed. The setting is explicit and defaults to off. The guest-side component remains intentionally small. We are not putting the ArmorIQ control plane into every guest, and we are not embedding a second policy engine beside the agent.
The assurance planes have already made the decision. The guest installs it. That gives us the architectural separation we care about: PAP decides and bounds. IAP commits and proves. intentd maintains and carries. KAP enforces in this reference backend.
The kernel doesn’t need to understand English
This is perhaps the most important implementation detail. KAP does not evaluate:
“Does executing /usr/bin/id seem consistent with analyzing quarterly revenue?”
That would simply move probabilistic reasoning into the kernel path, which is exactly what we do not want. By the time authority reaches KAP, the semantic work has already happened. The kernel receives typed predicates. The abbreviated policy below is useful for explaining the path, but it is not a complete container grant. KAP enforces twelve predicate families, and each family fails closed when it is missing. A startup grant therefore has to cover the less visible work that happens before the entrypoint like namespace changes, credential setup, procfs access, and the other required operations alongside exec, file, and network. We learned this the hard way when an early intentd grant stranded its own workload during startup. For example:
exec:
allow /bin/ls
allow /bin/cat
file:
allow /repo/**
network:
allow api.ate-system.svc:443
Now the enforcement decision is wonderfully dull. The Actor executes /bin/cat. Predicate matches.
ALLOW.
The Actor attempts /usr/bin/id. No matching execution authority.
DENY: EACCES.
./usr/bin/id remains a clean way to illustrate the decision, but it shows as a denied file access instead. The current container setup needs a broad exec wildcard to reach the entrypoint, which makes exec a poor place to show this particular denial. The principle is the same. The model may have an excellent explanation for why /usr/bin/id suddenly became useful. The kernel does not participate in that debate. That is the point.
Intent needs a kernel object
KAP represents this authority through what we call an igroup. The useful intuition is a cgroup, but for intent-derived authority rather than CPU or memory. The intent group carries the objective lineage root, current authority epoch, compiled authority, mode, process membership, and enforcement events. Membership follows the workload as execution creates subprocesses and moves through normal process transitions.
That matters because agent execution does not stop at the first process. A coding agent launches a shell. The shell launches Python. Python launches another binary. File descriptors move between processes. Namespaces change.
If intent exists only at the API gateway, it disappears exactly when execution becomes interesting. The igroup carries the boundary through the process tree.
From objective to syscall
The complete path now looks roughly like this:
→ Human Purpose
→ Bound the authority (PAP)
→ Commit the plan and lineage (IAP)
→ Create and maintain the Intent Container (intentd)
→ Create the Actor (Agent Substrate)
→ Provide the isolated execution environment (Kata microVM)
→ Bind the Actor to objective authority (kap-bind)
→ Enforce at the kernel (KAP) → execve / open / connect / ...
There is no single magical “intent security” decision in that chain. Different layers answer different questions. PAP asks whether refinement remains inside the authority implied by the objective. IAP asks whether execution belongs to the committed plan and lineage. intentd keeps that objective alive as a runtime object. KAP asks whether the concrete operation happening right now remains inside the authority installed for that objective. That is how a sentence eventually becomes EACCES.
And then the Actor goes to sleep
Getting from objective to syscall gave us the first Intent Container. Suspend and resume gave us the first really interesting systems problem. Agent Substrate is designed for Actors that do not necessarily run continuously. An Actor can be checkpointed while waiting and restored later.
With a whole-guest snapshot, something useful happens automatically: the guest kernel comes back too. The KAP intent group survives. The lineage survives. The authority epoch survives. Resume the Actor and its objective boundary is still there. That sounds perfect. Until the authority changes while the Actor is asleep.
Suppose the Actor is checkpointed at authority epoch 1. The user later revokes the objective, advancing the control plane to epoch 2. Now restore the old snapshot. The guest kernel wakes up at epoch 1. We have just discovered a wonderfully unpleasant distributed-systems problem:
the execution state is authentic, but its authority is obsolete.
This is why the Intent Container cannot simply be whatever happens to exist inside the VM. The objective needs an external, current source of truth. Before a restored Actor becomes active, intentd must reassert the current authority state. A snapshot from epoch 1 cannot resurrect authority after the objective has moved to epoch 2.
That gives us the invariant we introduced in Part 1: Execution state can travel backward in time. Authority cannot. And that deserves a post of its own.
Next: when an agent wakes up with yesterday’s authority
In Part 3, we’ll go deeper into the suspend/resume problem.
We’ll look at why checkpointing an autonomous Actor is different from checkpointing an ordinary workload, how stale authority can return with restored kernel memory, why identity cannot solve the problem, and how objective lineage and authority epochs let us reject stale execution before it becomes active.
Then we’ll show the entire path in the intentd demo:
Objective → commit → Actor → bind → allow → deny → suspend → resume → revoke → stale restore rejection.
For now, the important point is that an Intent Container is no longer just an idea. We can trace the objective all the way down to the syscall that either succeeds or doesn’t. PAP bounds it. IAP commits and proves it. intentd maintains and carries it. KAP enforces it in this reference path.
That is how we are building the first Intent Container.



