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:

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:

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.