Quick Start

What is Tenuo?

Tenuo is a warrant-based authorization library for AI agent workflows. A warrant is a signed token specifying which tools an agent can call, under what constraints, and for how long.

Agent: "restart staging-web"
        │
        ▼
Tenuo:  Does this warrant allow "restart" on "staging-web"?
        Is the delegation chain valid?
        │
        ▼
IAM:    Does this service account have permission?

Tenuo adds a delegation layer on top of your existing IAM. If an LLM is prompt-injected, it can request anything, but the warrant only allows what you scoped. The injection succeeds at the LLM level; authorization stops the action.

Core invariant: when a warrant is delegated, its capabilities can only narrow, never widen. Enforced cryptographically.

Install

Install the SDK for your language:

uv pip install tenuo              # Python
npm install @tenuo/core@beta      # TypeScript (Node 20+)
cargo add tenuo --features sdk    # Rust

Python framework extras (quotes required in zsh):

uv pip install "tenuo[openai]"      # OpenAI Agents SDK
uv pip install "tenuo[temporal]"    # Temporal workflows
uv pip install "tenuo[langchain]"   # LangChain / LangGraph
uv pip install "tenuo[crewai]"      # CrewAI
uv pip install "tenuo[google_adk]"  # Google ADK
uv pip install "tenuo[mcp]"         # MCP (Python ≥3.10)
uv pip install "tenuo[a2a]"         # A2A inter-agent delegation
uv pip install "tenuo[fastapi]"     # FastAPI
uv pip install "tenuo[autogen]"     # AutoGen AgentChat (Python ≥3.10)
uv pip install "tenuo[fastmcp]"     # FastMCP (TenuoMiddleware / FastMCP servers)
uv pip install "tenuo[langgraph]"   # LangGraph (includes LangChain)
uv pip install "tenuo[cloud]"       # Tenuo Cloud SDK (proprietary control-plane client)

Try It (Copy-Paste, Runs Immediately)

from tenuo import configure, mint_sync, Capability, Subpath, SigningKey, guard
from tenuo.exceptions import AuthorizationDenied

# 1. Configure once at startup
configure(issuer_key=SigningKey.generate(), dev_mode=True, audit_log=False)

# 2. Protect tools with @guard
@guard(tool="read_file")
def read_file(path: str) -> str:
    return f"Contents of {path}"

# 3. Scope authority to tasks
with mint_sync(Capability("read_file", path=Subpath("/data"))):
    print(read_file("/data/reports/q3.pdf"))  # Allowed

    try:
        read_file("/etc/passwd")  # Blocked
    except AuthorizationDenied as e:
        print(f"Blocked: {e}")

What happened:

  • @guard(tool="read_file") marks the function as requiring authorization
  • mint_sync(...) creates a warrant scoped to /data/ (using Subpath for path traversal protection)
  • The second call fails because /etc/passwd is not under /data/

Choose Your Integration

What framework or SDK are you using?

Framework / SDK Language Integration Getting Started
Python SDK Python uv pip install tenuo Python API
TypeScript SDK TypeScript npm install @tenuo/core@beta TypeScript Guide
Rust SDK Rust cargo add tenuo --features sdk Rust API
OpenAI SDK Python from tenuo.openai import guard OpenAI Guide
Temporal Python from tenuo.temporal import TenuoTemporalPlugin Temporal Guide
LangChain Python from tenuo.langchain import auto_protect LangChain Guide
LangGraph Python from tenuo.langgraph import guard_node LangGraph Guide
CrewAI Python from tenuo.crewai import ... CrewAI Guide
Google ADK Python from tenuo.google_adk import TenuoGuard ADK Guide
MCP Python from tenuo.mcp import SecureMCPClient MCP Guide
FastAPI Python from tenuo.fastapi import SecureAPIRouter FastAPI Guide
AutoGen Python from tenuo.autogen import ... AutoGen Guide
Hermes Agent Python hermes plugins install hermes-tenuo Hermes Guide
A2A Python from tenuo.a2a import ... A2A Guide
Custom Python from tenuo import Warrant, SigningKey API Reference

Do you have agents communicating across processes? Add A2A alongside your runtime integration.

Quick Examples

OpenAI: wrap the client, tools are automatically protected:

from tenuo.openai import guard
client = guard(openai.OpenAI(), warrant=warrant, signing_key=key)

LangGraph: scope authority per graph node:

from tenuo.langgraph import guard_node, TenuoToolNode
graph.add_node("agent", guard_node(my_agent, key_id="worker"))
graph.add_node("tools", TenuoToolNode([search, write_file]))

MCP: verify tool calls between client and server:

from tenuo.mcp import SecureMCPClient
client = SecureMCPClient(server_url, warrant=warrant, signing_key=key)

Temporal: one plugin, zero workflow changes:

from temporalio.client import Client
from tenuo.temporal import TenuoTemporalPlugin, TenuoPluginConfig, EnvKeyResolver

# issuer_pubkey is the public key that mints your warrants —
# e.g. ``control_key.public_key`` from the snippets above.
plugin = TenuoTemporalPlugin(TenuoPluginConfig(
    key_resolver=EnvKeyResolver(), trusted_roots=[issuer_pubkey],
))
client = await Client.connect("localhost:7233", plugins=[plugin])

For a copy-paste local workflow with one allowed Activity and one denied Activity, see the Temporal Quickstart.

Each framework guide includes a full working example, production configuration, and troubleshooting.

Debugging Authorization Failures

When something is denied, use why_denied() for diagnostics:

result = warrant.why_denied("read_file", {"path": "/etc/passwd"})
if result.denied:
    print(f"Denied: {result.deny_code}")
    print(f"Field: {result.field}")
    print(f"Suggestion: {result.suggestion}")

Or inspect a warrant interactively in the Explorer Playground. Warrants contain only signed claims, not secrets, so they’re safe to share.

Next Steps