CapForge
Agent Capability Manifest (ACM) SDK — a standard for binding AI agent identity to authorized capabilities.
Version: 0.5.0 | Phase: 5 (Production Showcase) ✅ | Status: Alpha
CapForge is the OAuth for AI agents — a standard way for agents to declare who they are, what they're allowed to do, who is responsible for them, and what limits they operate within.
pip install capforge
capforge keygen --output my-key
capforge create --spiffe-id spiffe://org/agent/bot --sponsor user@org.com \
--capability knowledge_base:read --key-file my-key.pem
from capforge import ACM, Capability, Constraints
manifest = ACM.create(
spiffe_id="spiffe://org/agent/bot",
sponsor="user@org.com",
capabilities=[Capability(resource="kb", action="read")],
)
manifest.sign("my-key.pem").save("manifest.json")
loaded = ACM.load("manifest.json")
loaded.verify(trusted_keys=["my-key.pub"])
Why CapForge?
When an AI agent executes in production, there is no standard way to answer:
- Who is this agent? (identity)
- What is it allowed to do? (authorization scope)
- Who is responsible for its actions? (accountability)
- What are its limits? (constraints)
- Can I verify this cryptographically? (integrity)
Teams today solve this ad-hoc: hardcoded API keys, custom middleware, manual review. This doesn't scale to multi-agent, cross-organization, or regulated environments. CapForge fills this gap with the Agent Capability Manifest (ACM) — a lightweight, verifiable authorization document format.
Design Philosophy
- Minimal — Defines only what existing standards (SPIFFE, OPA, RATS, OTel) do not cover.
- Composable — Composes with existing infrastructure rather than replacing it.
- Verifiable — Every ACM document is cryptographically signed via Ed25519.
- Scopable — Delegation chains can only narrow scope, never expand it.
- Framework-agnostic — Works with LangGraph, CrewAI, AutoGen, or custom agents.
Documentation
| Document | Purpose |
|---|---|
| SPECIFICATION.md | ACM protocol specification v1.0 (canonical) |
| SPEC.md | Protocol specification (alias) |
| ARCHITECTURE.md | Module design, data flow, design principles |
| DECISIONS.md | 13 Architecture Decision Records |
| ROADMAP.md | Phased milestones through standardization |
| CHANGELOG.md | Version history (v0.1.0 → v0.5.0) |
| SECURITY.md | Security policy and vulnerability reporting |
| CONTRIBUTING.md | Contribution guidelines |
Quick Start
1. Install
pip install capforge
2. Generate a signing key
capforge keygen --output ./my-agent-key
# -> Private key: my-agent-key.pem
# -> Public key: my-agent-key.pub
3. Create and sign an ACM document
capforge create \
--spiffe-id spiffe://acme-corp.com/agent/support-bot \
--sponsor alice@acme-corp.com \
--capability knowledge_base:read \
--capability tickets:read \
--capability tickets:write \
--constraint max_cost_per_session=0.05 \
--constraint disallowed_tools=delete_user \
--key-file ./my-agent-key.pem \
--output manifest.json
4. Verify the signed document
capforge verify manifest.json --trusted-roots my-agent-key.pub
# -> Verification PASSED (signature valid)
# -> Agent: spiffe://acme-corp.com/agent/support-bot
# -> Sponsor: alice@acme-corp.com
# -> Capabilities: 3
# -> Expires at: 2026-07-22T12:00:00+00:00
5. Delegate scope to a sub-agent
capforge delegate \
--parent manifest.json \
--child-spiffe-id spiffe://acme-corp.com/agent/search-worker \
--capability knowledge_base:read \
--output delegated.json
Framework Integrations
CapForge provides tools to protect agent execution across multiple AI frameworks.
LangGraph
Wrap LangChain tools with ACM authorization checks:
from capforge_langgraph import ACMControlledTool, wrap_tools
wrapped = ACMControlledTool(
tool=search_kb,
acm=acm,
resource="knowledge_base",
action="read",
)
# Every call checks ACM validity + capability
result = wrapped.invoke({"query": "ACM protocol"})
Full example: examples/langgraph/
CrewAI
Wrap CrewAI tools with ACM authorization:
from capforge import ACM
from examples.crewai.acm_controlled_crew import ACMControlledCrewTool
safe_tool = ACMControlledCrewTool(
tool=SearchKnowledgeBase(),
acm=acm,
resource="knowledge_base",
action="read",
)
result = safe_tool(query="ACM protocol")
Full example: examples/crewai/
FastAPI
Protect API endpoints with ACM dependencies:
from fastapi import Depends
from typing import Annotated
@app.get("/agents/{agent_id}")
async def get_agent(
agent_id: str,
acm: Annotated[ACM, Depends(require_capability("agent", "read"))],
):
return {"agent_id": agent_id, "authorized_by": acm.sponsor}
Full example: examples/fastapi/
OpenAI Agents SDK
Wrap function tools with ACM checks:
class ACMControlledFunctionTool:
def __call__(self, *args, **kwargs):
if not self.acm.check(self.resource, self.action).allowed:
raise PermissionError("ACM denied")
return self.fn(*args, **kwargs)
Full example: examples/openai_agents/
Python SDK
from capforge import ACM, Capability, Constraints
from datetime import UTC, datetime, timedelta
# Create a new manifest
manifest = ACM.create(
spiffe_id="spiffe://org/agent/my-bot",
sponsor="dev@org.com",
capabilities=[Capability(resource="kb", action="read")],
constraints=Constraints(max_cost_per_session=0.05),
issuer="spiffe://org/user/dev",
)
# Sign it
manifest.sign("my-key.pem")
# Save to file
manifest.save("manifest.json")
# Load and verify
loaded = ACM.load("manifest.json")
loaded.verify(trusted_keys=["my-key.pub"])
print(f"Valid: {loaded.is_valid()}")
print(f"Agent: {loaded.spiffe_id}")
# Check capabilities
if loaded.has_capability("kb", "read"):
print("Agent can read the knowledge base")
# Delegate scope
child = loaded.delegate(
child_spiffe_id="spiffe://org/agent/sub-worker",
capabilities=[Capability(resource="kb", action="read")],
key="my-key.pem",
)
child.save("delegated.json")
SDK Reference
| Method | Description |
|---|---|
ACM.create(spiffe_id, sponsor, capabilities, ...) |
Create a new manifest |
ACM.load(source) |
Load from file or dict |
manifest.save(path) |
Save to file (returns JSON string) |
manifest.sign(key) |
Sign with Ed25519 key (PEM path or key object) |
manifest.verify(trusted_keys=...) |
Verify temporal validity + optional signature |
manifest.delegate(child_id, caps, ...) |
Create delegated manifest with narrowed scope |
manifest.check(resource, action, ...) |
Runtime authorization decision |
manifest.has_capability(resource, action) |
Check if a capability exists |
manifest.get_capability(resource, action) |
Get a capability by resource and action |
manifest.is_valid() |
Check if within temporal validity window |
manifest.to_dict() |
Export as dictionary |
manifest.to_json() |
Export as JSON string |
CLI Reference
| Command | Description |
|---|---|
capforge keygen --output <prefix> |
Generate Ed25519 key pair |
capforge create --spiffe-id --sponsor --capability ... |
Create and optionally sign an ACM |
capforge verify <file> --trusted-roots <pubkey> |
Verify ACM (temporal + crypto) |
capforge validate <file> |
Validate ACM (temporal + structural only) |
capforge info <file> |
Display human-readable ACM info |
capforge delegate --parent --child-spiffe-id --capability |
Create delegated ACM |
capforge --help |
Show help |
capforge --version |
Show version |
Full CLI workflow: examples/cli/
Runtime Policy Engine
CapForge includes a runtime authorization engine that evaluates "may this action execute right now?" — not just "does this capability exist?".
from capforge import ACM, Capability, Constraints
manifest = ACM.create(
spiffe_id="spiffe://org/agent/bot",
sponsor="user@org.com",
capabilities=[Capability(resource="github", action="search")],
constraints=Constraints(
max_cost_per_session=0.50,
max_tokens_per_session=100_000,
allowed_models=["gpt-5"],
disallowed_tools=["delete_repo"],
max_execution_seconds=300,
),
ttl=3600,
)
# Authorized action
result = manifest.check(
resource="github", action="search",
tool="search_code", cost=0.02,
session_cost=0.10, session_tokens=500,
model="gpt-5", execution_seconds=10,
)
if result.allowed:
print(f"Allowed. Remaining budget: {result.remaining_budget}")
else:
print(f"Denied: {result.reason} (constraint: {result.failed_constraint})")
# Unauthorized action
result = manifest.check(resource="github", action="delete_repo")
print(result.allowed) # False
Full example: examples/policy/
CI/CD Integration
Verify ACM documents as a deployment gate in GitHub Actions:
- name: Verify ACM signature
run: |
capforge verify manifests/agent-acm.json \
--trusted-roots manifests/trusted-roots.pub
- name: Check required capabilities
run: |
python -c "from capforge import ACM; m = ACM.load('manifest.json'); ...
Full workflow: examples/github_actions/
Benchmarks
Core operation performance at varying manifest sizes:
| Operation | n=1 | n=10 | n=100 | n=1000 |
|---|---|---|---|---|
| Manifest load | ~5 us | ~10 us | ~57 us | ~837 us |
| Signature verify | ~147 us | ~173 us | ~307 us | ~1838 us |
| ACM.check() | ~3 us | ~3 us | ~3 us | ~3 us |
| Delegation | ~80 us | ~81 us | ~89 us | ~160 us |
Run benchmarks: python benchmarks/acm_benchmarks.py
Features
| Feature | Status |
|---|---|
| Protocol specification (ACM v1.0) | ✅ |
| JSON Schema (Draft 2020-12) | ✅ |
| Ed25519 cryptographic signing | ✅ |
| Canonical JSON serialization | ✅ |
| Temporal validation (expiry, not-before) | ✅ |
| Delegation with scope narrowing | ✅ |
ACM.create() factory |
✅ |
ACM.load() from file or dict |
✅ |
manifest.save() to file |
✅ |
manifest.sign() with key or PEM path |
✅ |
manifest.verify() temporal + crypto |
✅ |
manifest.delegate() scope narrowing |
✅ |
Capability lookup (has_capability, get_capability) |
✅ |
Constraint access (constraints_obj property) |
✅ |
| Click CLI (6 commands) | ✅ |
| Core test suite (56 tests) | ✅ |
| ruff + mypy --strict | ✅ |
| CI pipeline (GitHub Actions) | ✅ |
LangGraph adapter (capforge_langgraph) |
✅ |
ACMControlledTool — ACM-checked tool wrapper |
✅ |
wrap_tools() — multi-tool wrapper |
✅ |
| Adapter tests (10 tests) | ✅ |
Runtime policy engine (ACM.check()) |
✅ |
PolicyDecision structured result |
✅ |
| Cost budget evaluation | ✅ |
| Token budget evaluation | ✅ |
| Model restriction checking | ✅ |
| Blocked tool checking | ✅ |
| Execution timeout checking | ✅ |
| Policy tests (34 tests) | ✅ |
| CrewAI example | ✅ |
| FastAPI example | ✅ |
| OpenAI Agents SDK example | ✅ |
| CLI workflow example | ✅ |
| GitHub Actions CI example | ✅ |
| Performance benchmarks | ✅ |
Project Structure
capforge/
├── __init__.py # Public API exports
├── _acm.py # ACM class (create, load, sign, verify, delegate)
├── _model.py # Pydantic models (Capability, Constraints)
├── _crypto.py # Ed25519 signing/verification
├── _policy.py # Runtime policy engine
├── _validator.py # Temporal + delegation validation
├── _delegation.py # Delegation scope narrowing
├── _exceptions.py # Exception hierarchy
├── _version.py # Package version
├── py.typed # PEP 561 type marker
└── cli/
├── __init__.py
└── main.py # Click CLI (6 commands)
tests/ # 100 tests total
├── test_acm.py # 30 tests
├── test_crypto.py # 14 tests
├── test_validator.py # 5 tests
├── test_model.py # 7 tests
├── test_policy.py # 34 tests
└── test_langgraph_adapter.py # 10 tests
capforge_langgraph/ # LangGraph adapter (separate package)
├── __init__.py
├── _tool_wrapper.py
└── pyproject.toml
examples/ # Production showcase
├── langgraph/ # LangGraph integration
│ ├── basic_acm_agent.py
│ ├── README.md
│ └── requirements.txt
├── crewai/ # CrewAI integration
│ ├── acm_controlled_crew.py
│ ├── README.md
│ └── requirements.txt
├── fastapi/ # FastAPI + ACM dependencies
│ ├── acm_protected_api.py
│ ├── README.md
│ └── requirements.txt
├── openai_agents/ # OpenAI Agents SDK integration
│ ├── acm_controlled_agent.py
│ ├── README.md
│ └── requirements.txt
├── cli/ # CLI workflow
│ ├── run_cli_examples.sh
│ └── README.md
├── github_actions/ # CI/CD verification
│ ├── verify_acm.yml
│ └── README.md
└── policy/ # Runtime policy engine
├── runtime_checks.py
├── README.md
└── requirements.txt
benchmarks/
├── acm_benchmarks.py # Performance benchmarks
└── README.md
spec/
├── acm-schema.json # JSON Schema (Draft 2020-12)
└── examples/
├── valid-acm.json
├── minimal-acm.json
└── expired-acm.json
Progress
| Area | Status |
|---|---|
| Protocol specification | ✅ 100% |
| JSON Schema | ✅ 100% |
| Pydantic data models | ✅ 100% |
| Ed25519 cryptography | ✅ 100% |
| Temporal validation | ✅ 100% |
| Delegation chain | ✅ 100% |
Public API (ACM.create, .sign, .verify, etc.) |
✅ 100% |
| Click CLI (6 commands) | ✅ 100% |
| Test suite (100 tests) | ✅ 100% |
| ruff + mypy strict | ✅ 100% |
| CI pipeline | ✅ 100% |
| LangGraph adapter | ✅ 100% |
| Runtime policy engine | ✅ 100% |
| Framework examples (CrewAI, FastAPI, OpenAI) | ✅ 100% |
| CLI workflow example | ✅ 100% |
| GitHub Actions CI example | ✅ 100% |
| Performance benchmarks | ✅ 100% |
Roadmap
Phase 1 ─── Foundation + Specification ✓ (v0.1.0)
Phase 2 ─── Cryptography + CLI Enhancement ✓ (v0.2.0)
Phase 3a ── CapForge SDK ✓ (v0.3.0)
Phase 3b ── LangGraph adapter ✓
Phase 4 ─── Runtime Policy Engine ✓ (v0.4.0)
Phase 5 ─── Production Showcase ✓ (v0.5.0) ← You are here
Phase 6 ─── Standardization ⬜
Contributing
See CONTRIBUTING.md for guidelines.
- Report bugs: GitHub Issues
- Discuss ideas: GitHub Discussions
- Security vulnerabilities: See SECURITY.md
License
Built for the AI agent ecosystem.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file capforge-0.4.0.tar.gz.
File metadata
- Download URL: capforge-0.4.0.tar.gz
- Upload date:
- Size: 90.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28e80960cf77441f97ef2695ac63ddb5b4d89f6a2cf5e15a7c46f423022583eb
|
|
| MD5 |
6b7afd25bbceac9354c1381618d92e67
|
|
| BLAKE2b-256 |
bbd11b312b4340a3391a81cbde4e6317113d9d25c7fe8a663a7f38d0cc002d8b
|
File details
Details for the file capforge-0.4.0-py3-none-any.whl.
File metadata
- Download URL: capforge-0.4.0-py3-none-any.whl
- Upload date:
- Size: 32.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fcaca4016473b99df4b3079ab3abb2965de2a5cd1adb4e63d7f19127844b0ca
|
|
| MD5 |
ef7b8821888e2e707ca13b9802ae0254
|
|
| BLAKE2b-256 |
a959f7b8fb1f9b13469f6a55aad38bdddb68a4cbb1c8092a3fd05f6c383b4782
|