Agent Intent Manifests¶
An intent manifest is a structured declaration of what an agent is permitted to do, submitted at deployment time by the engineer who owns the agent. The manifest defines the boundaries of expected behavior: which systems the agent may access, which actions it may perform, which data types it may handle, and how frequently it may operate.
Intent manifests serve as the reference baseline for behavioral drift detection (INV-003). At runtime, every agent action is compared against the declared intent. Actions that fall outside the manifest are flagged as drift events and may trigger automated responses including throttling or suspension.
Manifest Schema¶
The intent manifest is defined by the AgentDeclaredIntent model:
| Field | Type | Required | Description |
|---|---|---|---|
permitted_systems |
list[string] |
Yes | Connector identifiers the agent is allowed to interact with (e.g., ["crowdstrike", "jira", "slack"]). |
permitted_actions |
list[string] |
Yes | Operation strings the agent is allowed to perform. Supports glob patterns (e.g., ["detection:*", "ticket:read", "ticket:create"]). |
permitted_data_types |
list[string] |
Yes | Data classifications the agent is allowed to access (e.g., ["alert", "ticket", "host_metadata"]). |
max_frequency |
object or null |
No | Rate limits for agent invocations (e.g., {"per_hour": 100}). |
All list fields are required but may contain wildcard entries ("*") to indicate unrestricted access for that dimension.
Setting the Intent Manifest¶
Submit the manifest via the agent intent API:
PUT /v1/agents/{agent_id}/intent
Authorization: Bearer <token>
Content-Type: application/json
{
"permitted_systems": ["crowdstrike", "jira", "slack"],
"permitted_actions": [
"detection:list",
"detection:read",
"ticket:create",
"ticket:update",
"message:write"
],
"permitted_data_types": ["alert", "detection", "ticket"],
"max_frequency": {
"per_hour": 200
}
}
The manifest is stored in the declared_intent JSONB column on the agents table. Setting a new manifest overwrites the previous one entirely; partial updates are not supported.
Manifest Fields in Detail¶
permitted_systems¶
A list of connector identifiers. The drift detector compares each connector call's target connector against this list. If the agent calls a connector not in the list (and "*" is not present), a drift event of type unauthorized_system is recorded.
Valid connector identifiers match those used in connector configurations: crowdstrike, splunk, jira, slack, wiz, servicenow, okta, palo_alto, pagerduty, sentinel.
permitted_actions¶
A list of operation strings, optionally using glob patterns. The policy engine validates each operation against this list using fnmatch matching. For example, "detection:*" permits detection:list, detection:read, and detection:update.
The drift detector also checks this list but uses a two-tier match: first an exact match, then a prefix wildcard match (e.g., if the operation is host:isolate, it checks for host:* in the list).
permitted_data_types¶
A list of data type classifications the agent is expected to handle. This field is used for compliance documentation and data governance auditing. Current enforcement is at the manifest validation level; future releases will integrate with connector-level data classification.
max_frequency¶
An optional rate limit object. Currently supports per_hour as the only key. The drift detector's check_frequency() method counts the agent's audit log entries in the current clock hour and compares against this limit. Exceeding the limit produces a drift event of type frequency_exceeded with medium severity.
Example:
{
"per_hour": 100
}
If max_frequency is null or omitted, no frequency-based drift detection is performed.
Versioning and Storage¶
The intent manifest is stored as a JSONB column on the agent record. The agents table includes a version integer that is incremented on each update, and updated_at is set to the current timestamp. The agent's AgentResponse schema exposes both declared_intent and version fields.
Historical manifests are not retained in the agent record itself. However, drift events include a declared_intent_snapshot field that captures the full manifest at the time drift was detected. Combined with the audit log entries for agent updates, this provides a reconstructable history of manifest changes over time.
Cryptographic Signing¶
Intent manifests support cryptographic signing to establish non-repudiation. When an authorized deployer submits a manifest, the system records:
signed_by: The user ID of the deployer who submitted the manifest.signed_at: The UTC timestamp of submission.
These fields are set automatically by the API based on the authenticated user's identity. The deployer must hold the admin or deployer role. This creates an auditable chain of responsibility: every manifest is attributable to a specific human who authorized the agent's declared scope.
Relationship to Policy Rules¶
Intent manifests and policy rules serve complementary purposes:
- Intent manifests define what an agent is supposed to do -- the positive declaration of expected behavior. They are set once at deployment time and updated only when the agent's scope changes.
- Policy rules define what an agent is allowed to do -- the enforcement mechanism that governs each individual call. They can be modified at any time by organization admins.
During policy evaluation, the intent manifest is checked in Step 2 (before risk scoring and policy rule matching). If the action violates the manifest, the verdict is DENY with a risk score of 100, regardless of any permissive policy rules.
This means policy rules cannot override intent manifest restrictions. The manifest acts as an outer boundary; policy rules operate within that boundary.
Example Manifest¶
A security triage agent that reads CrowdStrike detections, creates Jira tickets, and sends Slack notifications:
{
"permitted_systems": ["crowdstrike", "jira", "slack"],
"permitted_actions": [
"detection:list",
"detection:read",
"detection:get",
"ticket:create",
"ticket:update",
"ticket:read",
"message:write"
],
"permitted_data_types": [
"detection",
"alert",
"ticket",
"notification"
],
"max_frequency": {
"per_hour": 500
}
}
If this agent attempts to call host:isolate on CrowdStrike, the policy engine will deny the call because host:isolate does not match any entry in permitted_actions. A drift event of type unauthorized_action will also be recorded.