Metadata-Version: 2.4
Name: capforge
Version: 0.6.1
Summary: Policy-as-Code SDK for AI agents with signed capability manifests and runtime authorization.
Author-email: Shashank R <shashank.r2005@gmail.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/shashank123r/capforge
Project-URL: Source, https://github.com/shashank123r/capforge
Project-URL: Specification, https://github.com/shashank123r/capforge/blob/main/SPEC.md
Keywords: capforge,acm,agent,capability,manifest,authorization,security,ai,trust
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=2.0
Requires-Dist: cryptography>=42.0
Requires-Dist: click>=8.0
Provides-Extra: cli
Requires-Dist: click>=8.0; extra == "cli"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: ruff>=0.5.0; extra == "dev"
Requires-Dist: mypy>=1.10.0; extra == "dev"
Dynamic: license-file

# CapForge

**Policy-as-Code SDK for AI agents — signed capability manifests with runtime authorization.**

[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
[![Python 3.12+](https://img.shields.io/badge/Python-3.12%2B-blue)](pyproject.toml)
[![Ruff](https://img.shields.io/badge/code_style-Ruff-000000)](pyproject.toml)
[![Mypy](https://img.shields.io/badge/type_checker-mypy--strict-blue)](pyproject.toml)
[![CI](https://img.shields.io/badge/CI-GitHub_Actions-green)](.github/workflows/ci.yml)

**Version:** 0.6.1 | **Status:** Alpha

> CapForge lets you wrap any AI agent tool with a signed, expiring
> permission slip. Before every tool invocation, the agent must present a
> cryptographically verifiable manifest declaring who it is, what it's
> allowed to do, and what limits it operates within.

```bash
pip install capforge
```

```python
from capforge import ACM, Capability, Constraints

# Create a signed permission slip for your agent
manifest = ACM.create(
    spiffe_id="spiffe://org/agent/support-bot",
    sponsor="alice@org.com",
    capabilities=[Capability(resource="knowledge_base", action="read")],
)
manifest.sign("my-key.pem")

# At runtime: may this agent execute this action right now?
result = manifest.check(resource="knowledge_base", action="read")
print(result.allowed)   # True
print(result.reason)    # "Action authorized"
```

No framework dependencies. No external services. Works with LangGraph, CrewAI,
OpenAI Agents SDK, FastAPI, or any custom agent runtime.

---

## Why CapForge?

When you give an AI agent a tool — a database query, an API call, a shell
command — how do you know the agent won't use it beyond what you intended?

Today, teams solve this ad-hoc: hardcoded API keys, fragile conditionals
scattered across tool code, and manual review that doesn't scale.

**CapForge answers five questions that every production agent deployment needs:**

| Question | How CapForge Answers |
|:---------|:---------------------|
| Who is this agent? | Cryptographically signed identity (SPIFFE ID) |
| What is it allowed to do? | Resource:action capability pairs |
| Who is responsible? | Human sponsor field |
| What are its limits? | Constraints (cost, tokens, models, tools, time) |
| Can I verify this? | Ed25519 signature + canonical JSON |

### When should you use CapForge?

- You're deploying **multi-agent systems** in production
- Multiple teams build agents that access **shared infrastructure**
- You need **audit trails** for agent actions
- Your agents interact across **organizational boundaries**
- You operate in **regulated environments** (fintech, healthcare, government)

### When should you NOT use CapForge?

- **Single-agent, no-tool setup** — You don't need capability manifests for a
  chatbot that summarises notes
- **Simple API key scoping** — If a single static key is good enough, it's
  simpler
- **Early prototyping** — ACM shines at production scale, not during rapid
  iteration

---

## Quick Start (under 5 minutes)

### 1. Install

```bash
pip install capforge
```

### 2. Create a manifest and check authorization

```python
from capforge import ACM, Capability, Constraints

# This is the core value of CapForge — runtime authorization decisions
manifest = ACM.create(
    spiffe_id="spiffe://acme-corp.com/agent/support-bot",
    sponsor="alice@acme-corp.com",
    capabilities=[
        Capability(resource="knowledge_base", action="read"),
        Capability(resource="tickets", action="read"),
    ],
    constraints=Constraints(max_cost_per_session=0.05),
)

# Before every tool call: may this action execute?
result = manifest.check(resource="knowledge_base", action="read")
if result.allowed:
    print("✅ Authorized — executing tool")
    print(f"   Remaining budget: ${result.remaining_budget['cost']:.2f}")
else:
    print(f"❌ Denied: {result.reason}")
    print(f"   Failed constraint: {result.failed_constraint}")
```

### 3. Cryptographically sign and persist

```bash
capforge keygen --output ./my-agent-key
```

```python
# Sign
manifest.sign("./my-agent-key.pem")
manifest.save("manifest.json")

# Later: load and verify
loaded = ACM.load("manifest.json")
loaded.verify(trusted_keys=["./my-agent-key.pub"])
print(f"Agent: {loaded.spiffe_id}")    # spiffe://acme-corp.com/agent/support-bot
print(f"Valid: {loaded.is_valid()}")   # True
```

### 4. Delegate scope to a sub-agent

```python
child = manifest.delegate(
    child_spiffe_id="spiffe://acme-corp.com/agent/search-worker",
    capabilities=[Capability(resource="knowledge_base", action="read")],
    key="./my-agent-key.pem",
)
child.save("delegated.json")
# Child can only read — cannot write tickets or escalate scope
```

---

## Framework Integrations

CapForge provides tools to protect agent execution across popular frameworks.

### LangGraph

Wrap LangChain tools with ACM authorization checks:

```python
from capforge_langgraph import ACMControlledTool, wrap_tools

wrapped = ACMControlledTool(
    tool=search_kb,
    acm=manifest,
    resource="knowledge_base",
    action="read",
)
result = wrapped.invoke({"query": "ACM protocol"})
# → ACM.check() runs before every invocation
```

📖 [`examples/langgraph/`](examples/langgraph/) — runnable example

### CrewAI

Wrap CrewAI tools with ACM authorization:

```python
from examples.crewai.acm_controlled_crew import ACMControlledCrewTool

safe_tool = ACMControlledCrewTool(
    tool=SearchKnowledgeBase(),
    acm=manifest,
    resource="knowledge_base",
    action="read",
)
result = safe_tool(query="ACM protocol")
```

📖 [`examples/crewai/`](examples/crewai/) — runnable example

### FastAPI

Protect API endpoints with ACM dependency injection:

```python
from fastapi import Depends

@app.get("/agents/{agent_id}")
async def get_agent(
    agent_id: str,
    acm: Annotated[ACM, Depends(require_capability("agent", "read"))],
):
    """Returns agent info only if the request carries a valid ACM."""
    return {"agent_id": agent_id, "authorized_by": acm.sponsor}
```

📖 [`examples/fastapi/`](examples/fastapi/) — runnable server + curl test commands

### OpenAI Agents SDK

Wrap function tools with ACM checks:

```python
class ACMControlledFunctionTool:
    def __call__(self, *args, **kwargs):
        result = self.acm.check(self.resource, self.action)
        if not result.allowed:
            raise PermissionError(f"ACM denied: {result.reason}")
        return self.fn(*args, **kwargs)
```

📖 [`examples/openai_agents/`](examples/openai_agents/) — runnable example

---

## CLI Reference

```bash
capforge --help
capforge --version
```

| Command | Description |
|:--------|:------------|
| `capforge keygen --output <prefix>` | Generate an Ed25519 key pair (`.pem` + `.pub`) |
| `capforge create` | Create and sign an ACM document |
| `capforge verify <file> --trusted-roots <pubkey>` | Verify temporal validity + cryptographic signature |
| `capforge validate <file>` | Validate temporal + structural correctness (no crypto) |
| `capforge info <file>` | Display human-readable ACM information |
| `capforge delegate` | Create a delegated ACM with narrowed scope |

### CLI Example

```bash
# Generate keys
capforge keygen --output ./my-key

# Create and sign a manifest
capforge create \
  --spiffe-id spiffe://acme-corp.com/agent/support-bot \
  --sponsor alice@acme-corp.com \
  --capability knowledge_base:read \
  --capability tickets:read \
  --constraint max_cost_per_session=0.05 \
  --key-file ./my-key.pem \
  --output manifest.json

# Verify
capforge verify manifest.json --trusted-roots ./my-key.pub
# → Verification PASSED (signature valid)
# → Agent:   spiffe://acme-corp.com/agent/support-bot
# → Sponsor: alice@acme-corp.com
```

📖 [`examples/cli/`](examples/cli/) — full end-to-end CLI workflow

---

## Python SDK API

```python
from capforge import ACM, Capability, Constraints, PolicyDecision

# Create
manifest = ACM.create(
    spiffe_id="spiffe://org/agent/bot",
    sponsor="user@org.com",
    capabilities=[Capability(resource="kb", action="read")],
    constraints=Constraints(max_cost_per_session=0.05),
    ttl=3600,
)

# Sign & persist
manifest.sign("key.pem")
manifest.save("manifest.json")

# Load & verify
loaded = ACM.load("manifest.json")
loaded.verify(trusted_keys=["key.pub"])

# Runtime authorization
result: PolicyDecision = loaded.check(
    resource="kb", action="read",
    cost=0.01, session_cost=0.03,
    model="gpt-5",
)
print(result.allowed, result.reason, result.remaining_budget)

# Delegate scope
child = loaded.delegate(
    child_spiffe_id="spiffe://org/agent/sub",
    capabilities=[Capability(resource="kb", action="read")],
)
```

### Full Method Reference

| Method | Returns | Description |
|:-------|:--------|:------------|
| `ACM.create(...)` | `ACM` | Factory: create a new manifest |
| `ACM.load(source)` | `ACM` | Factory: load from file path or dict |
| `manifest.sign(key)` | `ACM` | Sign with Ed25519 (PEM path or key object) |
| `manifest.verify(trusted_keys=...)` | `None` | Temporal + optional crypto verification (raises on failure) |
| `manifest.save(path)` | `str` | Save JSON to file, returns JSON string |
| `manifest.check(...)` | `PolicyDecision` | Runtime authorization decision |
| `manifest.delegate(...)` | `ACM` | Create delegated ACM with narrowed scope |
| `manifest.has_capability(r, a)` | `bool` | Check if capability exists |
| `manifest.get_capability(r, a)` | `Capability\|None` | Get capability by resource/action |
| `manifest.is_valid()` | `bool` | Check temporal validity window |
| `manifest.to_dict()` | `dict` | Export as dictionary |
| `manifest.to_json()` | `str` | Export as pretty-printed JSON |

### Error Handling

```python
from capforge import ACMError
from capforge._exceptions import ACMExpiredError, ACMSignatureError

try:
    manifest.verify(trusted_keys=["root.pub"])
except ACMExpiredError:
    print("Manifest has expired — renew it")
except ACMSignatureError:
    print("Signature invalid — tampered or wrong key")
except ACMError:
    print("Other ACM error")
```

---

## Runtime Policy Engine

Beyond simple capability lookup, `ACM.check()` evaluates whether an action
is authorized *right now* considering:

| Check | Field | Example |
|:------|:------|:--------|
| Temporal validity | `expires_at`, `not_before` | Block expired manifests |
| Capability presence | `resource:action` | Is `knowledge_base:read` granted? |
| Cost budget | `max_cost_per_session` | Limit spend per session |
| Token budget | `max_tokens_per_session` | Limit LLM token usage |
| Model restriction | `allowed_models` | Only allow specific models |
| Blocked tools | `disallowed_tools` | Forbid dangerous operations |
| Execution timeout | `max_execution_seconds` | Prevent runaway agents |

```python
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. Budget remaining: ${result.remaining_budget['cost']:.2f}")
else:
    print(f"❌ Denied: {result.reason} (constraint: {result.failed_constraint})")
```

📖 [`examples/policy/`](examples/policy/) — 7 scenarios with expected output

---

## CI/CD Integration

Verify ACM documents as a deployment gate in GitHub Actions:

```yaml
- name: Verify ACM signature
  run: capforge verify manifests/agent-acm.json --trusted-roots manifests/trusted-roots.pub

- name: Check capabilities
  run: python -c "
from capforge import ACM;
m = ACM.load('manifest.json');
m.check('knowledge_base', 'read')
print('✅ All checks passed')
"
```

📖 [`examples/github_actions/`](examples/github_actions/) — full workflow

---

## Benchmarks

Core operation performance at varying manifest sizes (100 iterations each):

| 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 locally: `python benchmarks/acm_benchmarks.py`

---

## FAQ

### What problem does CapForge solve?

When an AI agent calls a tool in production, there is no standard way to
verify the agent is authorized to make that call. CapForge provides a
lightweight, cryptographically verifiable "permission slip" that agents must
present before executing tools.

### How is it different from RBAC / IAM?

IAM systems (AWS IAM, Kubernetes RBAC) control human or service access to
resources. CapForge controls **AI agent** access to **tools and functions**
within an agent runtime — a problem IAM systems don't address. ACM is
complementary: you can use IAM for infrastructure access and ACM for agent
tool authorization.

### How does it work with MCP (Model Context Protocol)?

MCP defines how agents connect to external tools and data sources. ACM defines
what each agent is allowed to do with those connections. An MCP server can
require an ACM before executing a tool — the MCP handshake conveys identity,
the ACM conveys authorization scope.

### How does it work with LangGraph?

CapForge's LangGraph adapter (`capforge-langgraph`) wraps LangChain tools with
`ACM.check()` calls. Every `tool.invoke()` first verifies the ACM is valid,
the capability is granted, and all constraints are met — before the inner tool
executes.

### How does signing work?

CapForge uses **Ed25519** (Curve25519) for signing. Before signing, the ACM
document is canonicalized (sorted keys, compact JSON, `signature` field
removed). The canonical bytes are signed, and the base64 signature is stored
in the `signature` field. Verification re-canonicalizes and checks the
signature against trusted public keys.

### What happens when a manifest expires?

The agent can no longer execute authorized actions. The `ACM.check()` method
returns `PolicyDecision(allowed=False, reason="ACM manifest is expired")`.
You must issue a new ACM with a fresh `expires_at`. Short-lived ACMs (TTL of
hours) are recommended for production.

### Can I revoke a manifest before it expires?

Not directly — ACMs are self-contained documents with no central authority.
Revocation is handled by:
1. **Short TTLs** — Manifests expire quickly (hours, not days)
2. **Revocation lists** — Maintain an external list of revoked signature keys
3. **Key rotation** — Rotate trusted root keys, making old signatures invalid

### What does a manifest look like?

```json
{
  "acm_version": "1.0",
  "agent": {
    "spiffe_id": "spiffe://acme-corp.com/agent/support-bot"
  },
  "human_sponsor": "alice@acme-corp.com",
  "capabilities": [
    {"resource": "knowledge_base", "action": "read"},
    {"resource": "tickets", "action": "write",
     "constraints": {"status": "resolved_only"}}
  ],
  "issuer": "spiffe://acme-corp.com/user/alice",
  "expires_at": "2026-08-22T00:00:00Z",
  "signature": "base64_encoded_signature..."
}
```

Full specification: [`SPECIFICATION.md`](SPECIFICATION.md)

---

## Documentation

| Document | Purpose |
|:---------|:--------|
| **[SPECIFICATION.md](SPECIFICATION.md)** | ACM protocol specification v1.0 (canonical) |
| **[SPEC.md](SPEC.md)** | Protocol specification (alias) |
| **[ARCHITECTURE.md](ARCHITECTURE.md)** | Module design, data flow, design principles |
| **[DECISIONS.md](DECISIONS.md)** | Architecture Decision Records |
| **[ROADMAP.md](ROADMAP.md)** | Phased milestones through standardization |
| **[CHANGELOG.md](CHANGELOG.md)** | Version history (v0.1.0 → v0.6.1) |
| **[SECURITY.md](SECURITY.md)** | Security policy and vulnerability reporting |
| **[CONTRIBUTING.md](CONTRIBUTING.md)** | Contribution guidelines |

---

## Project Structure

```
capforge/                       # Core SDK (zero framework dependencies)
├── __init__.py                 # Public API: ACM, Capability, Constraints
├── _acm.py                     # Main ACM class
├── _model.py                   # Pydantic data models
├── _crypto.py                  # Ed25519 signing/verification
├── _policy.py                  # Runtime policy engine (ACM.check())
├── _validator.py               # Temporal + delegation validation
├── _delegation.py              # Delegation scope narrowing
├── _exceptions.py              # Exception hierarchy
├── _version.py                 # Package version (dynamic)
├── py.typed                    # PEP 561 type marker
└── cli/
    ├── __init__.py
    └── main.py                 # Click CLI (6 commands)

tests/                          # 103 tests
├── test_acm.py                 # 30 tests
├── test_crypto.py              # 14 tests
├── test_policy.py              # 34 tests
├── test_langgraph_adapter.py   # 10 tests
├── test_model.py               # 7 tests
├── test_validator.py           # 5 tests
└── test_version.py             # 3 tests

capforge_langgraph/             # LangGraph adapter (separate package)
├── __init__.py
├── _tool_wrapper.py
└── pyproject.toml

examples/                       # Production showcase
├── langgraph/                  # LangGraph integration
├── crewai/                     # CrewAI integration
├── fastapi/                    # FastAPI + ACM dependencies
├── openai_agents/              # OpenAI Agents SDK integration
├── cli/                        # CLI workflow
├── github_actions/             # CI/CD verification
└── policy/                     # Runtime policy engine

benchmarks/                     # Performance benchmarks
└── acm_benchmarks.py

spec/                           # Protocol specification
├── 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 class) | ✅ 100% |
| Click CLI (6 commands) | ✅ 100% |
| Test suite (216 tests) | ✅ 100% |
| ruff + mypy strict | ✅ 100% |
| CI pipeline | ✅ 100% |
| LangGraph adapter | ✅ 100% |
| Runtime policy engine | ✅ 100% |
| MCP adapter | ✅ 100% |
| Audit logging | ✅ 100% |
| Remote policy distribution | ✅ 100% |
| Policy server (REST API) | ✅ 100% |
| Framework examples (6 frameworks) | ✅ 100% |
| Performance benchmarks | ✅ 100% |
| Repository stabilization | ✅ 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)
Phase 6 ─── MCP Integration                         ✓  (v0.6.0)
Phase 7 ─── Audit Logging                           ✓  (v0.6.0)
Phase 8 ─── Remote Policy Distribution              ✓  (v0.6.0)
Phase 9 ─── Policy Server                           ✓  (v0.6.0)
Phase 9.1 ─ Repository Stabilization                ✓  (v0.6.0)
Phase 9.2 ─ Packaging Fix & CI Stabilization        ✓  (v0.6.1)  ← You are here
```

See [ROADMAP.md](ROADMAP.md) for details on upcoming phases.

---

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding standards,
and pull request process.

- **Report bugs:** [GitHub Issues](https://github.com/shashank123r/capforge/issues)
- **Discuss ideas:** [GitHub Discussions](https://github.com/shashank123r/capforge/discussions)
- **Security vulnerabilities:** See [SECURITY.md](SECURITY.md)

---

## License

[Apache License 2.0](LICENSE)

---

*Built for the AI agent ecosystem. Not another chatbot. Not another agent
framework. Infrastructure for agent authorization.*
