ArmorIQ LogoArmorIQ SDK
Concepts

Intent Plans

Understanding plan structure, lifecycle, and validation

Intent Plans

An Intent Plan is a structured document that declares all actions an agent intends to execute. Think of it as a "pre-approved checklist" that gets cryptographically signed.

What is an Intent Plan?

An intent plan is:

  • Declarative: States what to do, not how
  • LLM-Generated: Created dynamically by the agent's reasoning
  • Immutable: Cannot be changed once signed
  • Verifiable: Cryptographically bound to execution

Plan Structure

Basic Plan Format

{
  "steps": [
    {
      "action": "fetch_data",
      "mcp": "data-mcp",
      "description": "Get user data from database"
    },
    {
      "action": "analyze",
      "mcp": "analytics-mcp",
      "description": "Calculate risk score"
    }
  ]
}

Plan with Metadata

{
  "steps": [
    {
      "action": "process_payment",
      "mcp": "finance-mcp",
      "description": "Process customer payment",
      "metadata": {
        "priority": "high",
        "timeout_seconds": 30
      }
    }
  ],
  "metadata": {
    "purpose": "payment_processing",
    "version": "1.2.0",
    "tags": ["finance", "critical"]
  }
}

Plan Templates vs LLM Generation

# Agent uses LLM to generate plan from natural language
captured = client.capture_plan(
    llm="gpt-4",
    prompt="Fetch user data, calculate credit score, and store result"
)
# LLM autonomously decides which MCPs and actions to use

Benefits:

  • Maximum flexibility
  • Agent autonomy
  • Adapts to context
  • Natural language interface

Alternative: Plan Templates (Fixed Structure)

# For debugging, testing, or strict workflows
plan_template = {
    "steps": [
        {"action": "fetch_data", "mcp": "data-mcp"},
        {"action": "analyze", "mcp": "analytics-mcp"}
    ]
}

captured = client.capture_plan(
    llm="gpt-4",
    prompt="Execute predefined workflow",
    plan=plan_template  # Use fixed structure
)

Use Cases:

  • Testing and debugging
  • Regulatory compliance (fixed workflows)
  • Performance-critical scenarios (skip LLM planning)
  • Template-based execution

Note: Plan templates are more restrictive than LLM-generated plans. They're useful for specific scenarios but sacrifice agent flexibility.

Plan Validation

When you submit a plan, ArmorIQ validates:

1. Structure Validation

Checks:

  • Required fields present (action, mcp)
  • Field types correct (strings, objects)
  • No malformed JSON
  • Valid step ordering

Example Error:

{
  "error": "InvalidPlanError",
  "message": "Step 2 missing required field: 'action'",
  "details": {
    "step_index": 2,
    "missing_fields": ["action"]
  }
}

2. MCP Validation

Checks:

  • MCP exists in registry
  • Action is supported by MCP
  • Action schema matches
  • MCP is accessible to user/agent

Example Error:

{
  "error": "InvalidMCPError",
  "message": "MCP 'unknown-mcp' not found in registry",
  "details": {
    "requested_mcp": "unknown-mcp",
    "available_mcps": ["data-mcp", "analytics-mcp", "finance-mcp"]
  }
}

Plan Lifecycle

Phase 1: Capture

captured_plan = client.capture_plan(
    llm="gpt-4",
    prompt="Fetch and analyze data"
)

What Happens:

  • Prompt sent to ArmorIQ
  • Plan generated (by LLM or template)
  • Structure validated
  • Plan stored with unique ID
  • PlanCapture object returned

Phase 2: Canonicalization

token = client.get_intent_token(captured_plan)

What Happens:

  • Plan converted to canonical form (CSRG)
  • Deterministic hash generated
  • Hash signs the token
  • Token includes plan hash + policy + expiration

Canonical Form (CSRG):

{
  "nodes": [
    {"id": "n1", "action": "fetch_data", "mcp": "data-mcp"},
    {"id": "n2", "action": "analyze", "mcp": "analytics-mcp"}
  ],
  "edges": [
    {"from": "n1", "to": "n2"}
  ]
}

Phase 3: Verification

result = client.invoke(
    mcp="data-mcp",
    action="fetch_data",
    intent_token=token
)

What Happens:

  • Proxy receives request
  • Token signature verified
  • Plan hash extracted
  • Action checked against plan
  • If match: request forwarded to MCP
  • If mismatch: request rejected

Phase 4: Audit

Automatically Logged:

  • Plan creation time
  • Token generation time
  • All action invocations
  • Success/failure status
  • Execution times

Plan Examples

Example 1: Data Pipeline

# Natural language prompt
captured = client.capture_plan(
    llm="gpt-4",
    prompt="Fetch customer data, validate it, and store in warehouse"
)

# Generated plan:
{
  "steps": [
    {"action": "fetch_customers", "mcp": "data-mcp"},
    {"action": "validate_schema", "mcp": "validation-mcp"},
    {"action": "store_data", "mcp": "warehouse-mcp"}
  ]
}

Example 2: Financial Analysis

# Natural language prompt
captured = client.capture_plan(
    llm="gpt-4",
    prompt="Analyze Q4 revenue, compare with forecast, generate report"
)

# Generated plan:
{
  "steps": [
    {"action": "fetch_revenue", "mcp": "finance-mcp"},
    {"action": "fetch_forecast", "mcp": "finance-mcp"},
    {"action": "compare_metrics", "mcp": "analytics-mcp"},
    {"action": "generate_report", "mcp": "reporting-mcp"}
  ]
}

Example 3: Multi-Service Orchestration

# Complex workflow
captured = client.capture_plan(
    llm="gpt-4",
    prompt="Get user profile, check permissions, fetch data, apply transformations, send notification"
)

# Generated plan:
{
  "steps": [
    {"action": "get_profile", "mcp": "auth-mcp"},
    {"action": "check_permissions", "mcp": "auth-mcp"},
    {"action": "fetch_data", "mcp": "data-mcp"},
    {"action": "transform", "mcp": "etl-mcp"},
    {"action": "send_notification", "mcp": "notification-mcp"}
  ]
}

Best Practices

1. Use Descriptive Prompts

# ✓ Good: Specific and clear
prompt = "Fetch sales data for 2024, calculate YoY growth, and generate PDF report"

# ✗ Bad: Vague
prompt = "Do some data stuff"

2. Include Context in Metadata

captured = client.capture_plan(
    llm="gpt-4",
    prompt="Process refund",
    metadata={
        "transaction_id": "txn_123",
        "reason": "customer_request",
        "priority": "high"
    }
)

3. Validate Plans Before Execution

try:
    captured = client.capture_plan(llm="gpt-4", prompt=user_input)
    print(f"Plan has {len(captured.plan['steps'])} steps")
    
    # Review plan before getting token
    for step in captured.plan['steps']:
        print(f"- {step['mcp']}/{step['action']}")
    
    # Proceed if plan looks good
    token = client.get_intent_token(captured)
except InvalidPlanError as e:
    print(f"Plan validation failed: {e}")

4. Use Plan Templates for Critical Workflows

# For regulatory compliance or safety-critical operations
compliance_template = {
    "steps": [
        {"action": "verify_identity", "mcp": "kyc-mcp"},
        {"action": "check_sanctions", "mcp": "compliance-mcp"},
        {"action": "approve_transaction", "mcp": "approval-mcp"}
    ]
}

captured = client.capture_plan(
    llm="gpt-4",
    prompt="Execute compliance workflow",
    plan=compliance_template
)

Common Issues

Issue: Plan Too Large

Problem: Plan has > 100 steps, causing timeouts

Solution: Break into multiple plans

# Split large workflows
plan1 = client.capture_plan(llm="gpt-4", prompt="Fetch and validate data")
plan2 = client.capture_plan(llm="gpt-4", prompt="Transform and load data")

Issue: Action Not in Registry

Problem: MCP or action doesn't exist

Solution: Check available MCPs first

# Verify MCP exists
available_mcps = client.list_mcps()
print(available_mcps)

Issue: Plan Hash Mismatch

Problem: Token verification fails

Solution: Don't modify captured plan after getting token

# ✓ Good
captured = client.capture_plan(...)
token = client.get_intent_token(captured)
client.invoke(..., intent_token=token)

# ✗ Bad: Modifying plan
captured = client.capture_plan(...)
captured.plan['steps'].append(...)  # Don't do this!
token = client.get_intent_token(captured)  # Hash won't match

Next Steps

On this page