Skip to main content

aflock

Cryptographically signed policies that constrain AI agent behavior.

Like package-lock.json locks dependencies, .aflock locks what an agent can do.

Vision

AI agents are increasingly autonomous. They run commands, access APIs, modify files, and spawn sub-agents. But how do you:

  1. Constrain what an agent can do? (spend limits, tool restrictions, file access)
  2. Prove the agent operated within bounds? (signed attestations)
  3. Verify after the fact? (cryptographic verification)
  4. Delegate to sub-agents with stricter constraints? (sublayouts)

aflock solves this with a policy file that:

  • Defines limits, grants, and constraints
  • Is cryptographically signed by a human (agent can't modify it)
  • Binds to agent identity (model + environment + tools)
  • Produces verifiable attestations for every action

Key Insight: Agent Identity

An agent's identity is derived from its configuration, not assigned:

AgentIdentity = SHA256(model || environment || tools || policyDigest || parent)
ComponentDiscovered From
Model--model flag, env var
EnvironmentPID introspection (UID, container ID, binary path)
ToolsMCP capabilities
Policy.aflock in agent's working directory
ParentParent agent identity (if sub-agent)

The agent connects to aflock via MCP. aflock gets the PID from the socket, introspects the process, and derives identity. The agent cannot lie about its identity.

Key Insight: JWT + Signing Key Separation

Agents receive a JWT for authorization, but attestations are signed by a key they cannot access:

┌─────────────────────┐    ┌─────────────────────────────────┐
│ JWT (Agent Holds) │ │ Signing Key (Server Holds) │
│ │ │ │
│ - Identity claims │ │ - Never exposed to agent │
│ - Granted scopes │ │ - Signs all attestations │
│ - Short-lived │ │ - Bound to agent identity │
└─────────────────────┘ └─────────────────────────────────┘

The agent presents the JWT but cannot sign attestations. All signatures go through the aflock server.

Architecture

┌──────────────────────┐          ┌───────────────────────┐
│ AI Agent │ MCP │ aflock Server │
│ (Claude Code) │◄────────►│ │
│ │ │ - PID introspection │
│ - Calls MCP tools │ │ - Identity derivation│
│ - Holds JWT │ │ - Policy enforcement │
│ - Never sees keys │ │ - Attestation signing│
└──────────────────────┘ └───────────────────────┘

Based on SPIRE architecture - battle-tested workload identity.

Example Policy

{
"version": "1.0",
"name": "feature-implementation",

"identity": {
"allowedModels": ["claude-opus-4-5-20251101"],
"allowedEnvironments": ["container:ghcr.io/org/*"]
},

"grants": {
"secrets": { "allow": ["vault:secret/data/readonly/*"] },
"apis": { "allow": ["https://api.anthropic.com/*"] }
},

"limits": {
"maxSpendUSD": { "value": 10.00, "enforcement": "fail-fast" },
"maxTokensIn": { "value": 500000, "enforcement": "fail-fast" },
"maxTurns": { "value": 50, "enforcement": "post-hoc" }
},

"tools": {
"allow": ["Read", "Edit", "Bash", "Glob", "Grep"],
"deny": ["Task"],
"requireApproval": ["Bash:rm -rf *", "Bash:git push --force"]
},

"files": {
"allow": ["src/**", "tests/**"],
"deny": ["**/.env", "**/secrets/**"]
},

"materialsFrom": {
"session": {
"path": "${CLAUDE_SESSION_PATH}",
"algorithm": "sha256"
},
"git": {
"treeHash": "${GIT_TREE_HASH}"
}
},

"evaluators": {
"rego": [{
"name": "spend-limit",
"policy": "deny contains msg if { sum_spend > input.limits.maxSpendUSD.value }"
}],
"ai": [{
"name": "quality-check",
"prompt": "PASS if code is production-ready. FAIL otherwise."
}]
},

"sublayouts": [{
"name": "research-agent",
"policy": "./policies/research.aflock",
"limits": { "maxSpendUSD": { "value": 2.00 } },
"inherit": ["domains", "functionaries"]
}]
}

Core Concepts

Limits (with Enforcement Modes)

LimitEnforcementDescription
maxSpendUSDfail-fastAbort immediately if exceeded
maxTokensInfail-fastAbort immediately if exceeded
maxTurnspost-hocVerify at completion
maxWallTimeSecondsfail-fastAbort immediately if exceeded

Grants (Resource Access)

{
"grants": {
"secrets": { "allow": ["vault:*"], "deny": ["vault:production/*"] },
"apis": { "allow": ["https://api.anthropic.com/*"] },
"storage": { "allow": ["s3://attestations/${RUN_ID}/*"] }
}
}

Materials (Ordering Proofs)

Session JSONL merkle tree proves:

  • Order: Turn 3 came after turns 0-2
  • Completeness: No turns skipped
  • Distance: Turns are contiguous

Sublayouts (Sub-Agent Delegation)

Inspired by in-toto sublayouts:

  • Sub-agent limits must be stricter than parent
  • Cumulative spend counts toward parent total
  • Attestations are namespaced with prefix
  • Verification recurses into sublayouts

Documentation

  • Specification - Full schema, verification algorithm, SPIRE reference
  • Examples - Compliance evaluation, todo app verification

Status

Private development. Specification phase.

License

Apache License 2.0 - See LICENSE for details.