Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions about.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ description: "Cycles is an open-source runtime authority layer for AI agents —

# About Cycles

Cycles is the [runtime authority](/blog/what-is-runtime-authority-for-ai-agents) layer for AI agents. It sits between an agent's decision to act and the action itself, and it answers one question on every tool call, for every agent, in every delegation chain: *is this agent allowed to do this, right now, given what it's already done?*
Cycles is a [runtime authority](/blog/what-is-runtime-authority-for-ai-agents) layer for AI agents. When an application puts it on a mandatory execution boundary, Cycles answers a narrower, enforceable question before each protected action: *does the configured budget have enough capacity for the amount and scope the caller submitted?*

If the answer is no, the action doesn't happen. Not "gets logged for later review." Not "triggers an alert." **Doesn't happen.**
If the integration requires a successful reservation before execution, a rejected reservation blocks the action instead of merely logging or alerting after the fact. Application authorization still decides whether the agent may use a specific tool or set of arguments.

## Who's building this

Expand All @@ -21,11 +21,11 @@ The full origin story — including the overnight agent loop that burned through

Three convictions shape every design decision in Cycles. They aren't new ideas — they're battle-tested patterns from distributed-systems engineering, applied to autonomous agents.

**Enforcement must be atomic.** A half-applied budget is worse than no budget. Cycles uses a reserve-commit lifecycle: budget is atomically reserved before an agent acts, actual usage is committed after, and unused capacity is released. No race conditions. No [time-of-check-to-time-of-use](https://dev.to/amavashev/your-ai-agent-budget-check-has-a-race-condition-33ei) gaps.
**Budget enforcement must be atomic.** A half-applied budget is worse than no budget. Cycles uses a reserve-commit lifecycle: budget is atomically reserved before an agent acts, actual usage is committed after, and unused capacity is released. This closes the [time-of-check-to-time-of-use](https://dev.to/amavashev/your-ai-agent-budget-check-has-a-race-condition-33ei) overspend gap at the budget boundary; the host remains responsible for executing only after a successful reservation.

**Authority must attenuate, not propagate.** When an agent spawns a sub-agent, the sub-agent gets a carved-out sub-budget and a restricted action mask. [Authority can only decrease with depth, never increase](/blog/agent-delegation-chains-authority-attenuation-not-trust-propagation).
**Authority should attenuate, not propagate.** When an agent spawns a sub-agent, the orchestrator can provision a smaller Cycles budget and separately restrict the sub-agent's tools, data, and credentials. Cycles enforces the submitted budget dimensions; the application enforces the action policy. Together, those controls can make [authority decrease with depth](/blog/agent-delegation-chains-authority-attenuation-not-trust-propagation).

**Control must be structural, not semantic.** You can't rely on an LLM to respect a system prompt that says "don't spend more than $10." That's a suggestion to a probabilistic system. Structural controls operate outside the LLM, at the infrastructure layer, and enforce boundaries deterministically. One is a hope. The other is an engineering guarantee.
**Control must be structural, not semantic.** You can't rely on an LLM to respect a system prompt that says "don't spend more than $10." A mandatory control outside the model can enforce that configured budget even when the model would continue. The guarantee applies to protected calls that the host routes through the boundary.

## What Cycles is not

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "26 Integrations for One AI Budget Protocol"
date: 2026-04-02
author: Albert Mavashev
tags: [announcement, integrations, langchain, langgraph, autogen, openai, anthropic, groq, django, nextjs, flask, anyagent, runtime-authority]
description: "Cycles ships 26 integrations across Python, TypeScript, Java, and Rust. See how one protocol coordinates runtime budget controls across diverse agent stacks."
description: "At launch, Cycles documented 26 integrations across Python, TypeScript, Java, and Rust. See how one protocol coordinates runtime budget controls across stacks."
blog: true
sidebar: false
head:
Expand Down
6 changes: 3 additions & 3 deletions blog/429-classification-gap-why-retry-logic-lying.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "HTTP 429: Why Retry Logic Lies"
date: 2026-04-10
author: Brenton Williams
tags: [ai-agents, retry-logic, retry-storms, rate-limits, http-429, 429, agent-infrastructure, runtime-authority]
tags: [agents, retry-logic, retry-storms, rate-limits, http-429, 429, agent-infrastructure, runtime-authority]
description: "HTTP 429 can mean wait, cap, or stop. Learn how classifying each response before retrying prevents retry storms and unsafe AI agent behavior in production."
blog: true
sidebar: false
Expand Down Expand Up @@ -111,7 +111,7 @@ And once that happens, everything downstream inherits the wrong decision.

## The failure cascade

This is not theoretical. The [retry storm incident pattern](/incidents/retry-storms-and-idempotency-failures) and the [$1,800 CRM outage retry storm](/blog/ai-agent-failures-budget-controls-prevent) — are exactly this failure mode.
This is not theoretical as a failure pattern. The [retry-storm incident pattern](/incidents/retry-storms-and-idempotency-failures) and a [$33.86 illustrative CRM retry model](/blog/ai-agent-failures-budget-controls-prevent) show how layered retries multiply calls.

**What this looks like in a real run**
```text
Expand Down Expand Up @@ -327,7 +327,7 @@ Until that is resolved, every layer above it is operating on a lie.
## Further reading

- [Retry Storms and Idempotency Failures](/incidents/retry-storms-and-idempotency-failures) — the dedicated incident pattern this post describes
- [5 AI Agent Failures Budget Controls Would Prevent](/blog/ai-agent-failures-budget-controls-prevent) — includes a $1,800 retry storm incident from a CRM outage
- [5 Agent Cost Failures Runtime Budgets Can Bound](/blog/ai-agent-failures-budget-controls-prevent) — includes a checked $33.86 retry-storm model
- [The State of AI Agent Incidents](/blog/state-of-ai-agent-incidents-2026) — Category A4 catalogues retry-storm cost multiplication
- [How Reserve-Commit Works in Cycles](/protocol/how-reserve-commit-works-in-cycles) — the enforcement model referenced throughout this post
- [Degradation Paths in Cycles](/how-to/how-to-think-about-degradation-paths-in-cycles-deny-downgrade-disable-or-defer) — deny, downgrade, disable, or defer strategies for the STOP case
Expand Down
2 changes: 1 addition & 1 deletion blog/a-200-ok-is-not-an-audit-trail.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ It is the difference between "trust me, the budget said no" and handing someone

Three properties, each doing a specific job:

- **Content-addressed.** The `evidence_id` is the SHA-256 of the envelope's [RFC 8785](https://www.rfc-editor.org/rfc/rfc8785) (JCS) canonical bytes — computed with the `evidence_id` and `signature` fields themselves left blank. The id *is* the integrity check: change one byte of a decision and it no longer matches.
- **Content-addressed.** The `evidence_id` is the SHA-256 of the envelope's [RFC 8785](https://www.rfc-editor.org/info/rfc8785/) (JCS) canonical bytes — computed with the `evidence_id` and `signature` fields themselves left blank. The id *is* the integrity check: change one byte of a decision and it no longer matches.
- **Signed.** An Ed25519 signature then covers a second canonical pass — the same envelope with the `evidence_id` now filled in and `signature` still blank — proving origin. Forge the contents and the signature fails.
- **In-band, then fetchable.** Cycles computes the `evidence_id` *synchronously* and returns it on the response (`cycles_evidence: { evidence_id, cycles_evidence_url }`); the expensive signing and storage happen asynchronously, off the request path. A consumer records the id and later fetches the signed envelope from the public `GET /v1/evidence/{id}` capability URL — and verifies it on its own. (Because signing is async, a fetch immediately after the response can return a transient `404` until the envelope lands — retry.)

Expand Down
2 changes: 1 addition & 1 deletion blog/action-authority-demo-support-agent-walkthrough.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "Block Agent Emails Before Execution"
date: 2026-03-22
author: Albert Mavashev
tags: [action-authority, demo, agents, runtime-authority, walkthrough, action-control, side-effects]
description: "A support agent can use CRM, notes, and email — but should every run send? Cycles blocks the customer email before execution. Three decorators, one exception."
description: "See a support-agent demo where a mandatory decorator requests a Cycles reservation and a zero-allocation toolset ledger prevents the attempted email call."
blog: true
sidebar: false
head:
Expand Down
94 changes: 44 additions & 50 deletions blog/agent-budget-patterns-visual-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ These patterns aren't mutually exclusive — most production systems combine two

## Pattern 1: Tenant Isolation Budgets

**When to use:** Multi-[tenant](/glossary#tenant) platforms where each customer or team gets their own AI agent access and you need hard spend isolation between them.
**When to use:** Multi-[tenant](/glossary#tenant) platforms where each customer or team gets their own AI agent access and you need separate runtime budget ceilings.

The simplest and most common starting point. Each tenant gets an independent budget that cannot be exceeded, regardless of what other tenants are doing.
The simplest and most common starting point. Each tenant gets an independent budget, so one tenant's submitted reservations do not consume another tenant's allocation. The ceiling applies to operations routed through the mandatory integration boundary and to the estimates the caller submits.

```python
# Tenant isolation: each tenant has a completely independent budget
Expand All @@ -48,7 +48,7 @@ async def run_agent_for_tenant(tenant_id, task):
```

**Trade-offs:**
- Provides complete blast-radius isolation — one tenant's runaway agent cannot affect others
- Provides separate ledgers, so one tenant's protected calls cannot consume another tenant's allocation
- Simple to reason about and explain to customers
- Can lead to underutilization: if Tenant A uses 10% of their budget and Tenant B hits 100%, there's no sharing
- Requires careful initial sizing — set too low and legitimate workloads get blocked
Expand Down Expand Up @@ -103,12 +103,12 @@ async def research_with_degradation(query, budget_dollars=10.00):
remaining = budget.remaining()
if remaining > 5.00:
result = await budget.execute(
agent.run(query, model="claude-opus-4-20250514")
agent.run(query, model="claude-opus-4-8")
)
# Phase 2: Fall back to a cheaper model
elif remaining > 1.00:
result = await budget.execute(
agent.run(query, model="claude-sonnet-4-20250514")
agent.run(query, model="claude-sonnet-4-6")
)
# Phase 3: Return cached/partial results
else:
Expand All @@ -128,9 +128,9 @@ We cover degradation strategies in detail in [How to Think About Degradation Pat

## Pattern 4: Shared Pool with Priority Tiers

**When to use:** When you want to maximize utilization of a fixed budget across multiple agents or users, with guarantees for high-priority work.
**When to use:** When you want to maximize utilization of a fixed budget across multiple agents or users while preferring high-priority work.

Instead of giving each consumer a fixed allocation, you share a pool but enforce priority ordering when the pool runs low.
Instead of giving each consumer a fixed allocation, you share a pool and have the application defer lower-priority work when the pool runs low. Cycles does not natively order reservations by priority. A read-then-act threshold is advisory and can race under concurrency; if capacity for critical work must be guaranteed, provision a separate protected ledger for that work.

```python
# Shared pool with priority tiers
Expand All @@ -140,7 +140,8 @@ pool = cycles.create_budget(
period="monthly"
)

# Priority tiers determine who gets denied first
# Application policy decides which work to submit as the pool gets low.
# This pre-check is a scheduling hint, not an atomic priority guarantee.
PRIORITY_THRESHOLDS = {
"critical": 0.0, # Only denied at $0 remaining
"high": 0.10, # Denied below 10% remaining
Expand All @@ -164,7 +165,7 @@ async def execute_with_priority(task, priority="normal"):

**Trade-offs:**
- Higher overall utilization — no budget sits idle while another is exhausted
- Critical work is protected even under heavy load
- Application scheduling can preserve more headroom for critical work
- Harder to predict per-team or per-user costs for billing purposes
- Requires agreement on what constitutes "critical" vs. "low" priority
- Risk of low-priority work getting permanently starved in busy periods
Expand All @@ -176,33 +177,31 @@ async def execute_with_priority(task, priority="normal"):
This is less a budget _structure_ and more a deployment pattern, but it's essential for any team that isn't starting from scratch. Shadow mode tracks what _would_ have been denied without actually denying anything.

```python
# Shadow mode: log but don't enforce
budget = cycles.create_budget(
scope=f"tenant:{tenant_id}",
limit_dollars=100.00,
period="daily",
mode="shadow" # Track but don't enforce
# Evaluate the same request without creating a reservation.
decision = await cycles.reserve(
subject={"tenant": tenant_id, "workflow": workflow_id},
estimate=estimated_microcents,
unit="USD_MICROCENTS",
dry_run=True,
)

# In shadow mode, execute() always succeeds but logs violations
result = await budget.execute(agent.run(task))

# After a validation period, check the shadow logs
shadow_report = cycles.get_shadow_report(
scope=f"tenant:{tenant_id}",
period="last_7_days"
)
# Output: "23 calls would have been denied. Peak overage: $47.30."
# Now you can tune the limit before switching to enforce mode.
# Dry run creates no reservation or balance mutation. The application records
# every decision and actual outcome; denied evaluations may also emit
# reservation.denied from the current reference server.
app_log.write({
"decision": decision,
"estimate": estimated_microcents,
"actual": await run_and_measure(task),
})
```

**Trade-offs:**
- Zero risk of breaking production workflows during rollout
- The budget result does not block the workflow; the application still owns logging, execution, and other failure handling
- Generates real data for sizing budgets accurately
- Adds latency (the budget check still happens, just without enforcement)
- Teams sometimes stay in shadow mode too long, delaying the value of enforcement

Our [shadow mode rollout guide](/how-to/shadow-mode-in-cycles-how-to-roll-out-budget-enforcement-without-breaking-production) walks through the full process, including how to analyze shadow logs and choose enforcement cutover criteria.
Our [shadow mode rollout guide](/how-to/shadow-mode-in-cycles-how-to-roll-out-budget-enforcement-without-breaking-production) walks through the full process, including how to retain and analyze dry-run responses and choose enforcement cutover criteria.

## Pattern 6: Hybrid Model (Tokens + Dollars)

Expand All @@ -211,36 +210,31 @@ Our [shadow mode rollout guide](/how-to/shadow-mode-in-cycles-how-to-roll-out-bu
Token counts and dollar costs diverge when you use multiple models, when pricing changes, or when non-LLM tools (web search, code execution) are part of the agent's toolkit.

```python
# Hybrid budget: track both dimensions
budget = cycles.create_budget(
scope=f"run:{run_id}",
limits={
"tokens": 500_000, # Hard cap on token consumption
"dollars": 15.00, # Hard cap on dollar spend
},
on_exhausted="reject"
)

async def execute_hybrid(task):
# Both limits are checked atomically
result = await budget.execute(
agent.run(task),
estimated={
"tokens": estimate_tokens(task),
"dollars": estimate_cost(task),
}
# Cycles budgets and reservation amounts each use one unit. Provision separate
# ledgers for TOKENS and USD_MICROCENTS, then have the application acquire both
# reservations before execution. If the second reserve fails, release the first.
token_hold = await reserve(unit="TOKENS", estimate=estimate_tokens(task))
try:
cost_hold = await reserve(
unit="USD_MICROCENTS",
estimate=estimate_cost_microcents(task),
)
return result

# Useful for cases where a cheap model uses many tokens
# or an expensive model uses few
except Exception:
await token_hold.release("cost_budget_not_available")
raise

# Execute only after both holds succeed, then settle each measured amount.
result, actual_tokens, actual_microcents = await run_and_measure(task)
await token_hold.commit(actual_tokens)
await cost_hold.commit(actual_microcents)
```

**Trade-offs:**
- Catches scenarios that a single-dimension budget misses (e.g., a cheap model looping uses few dollars but millions of tokens)
- Useful for capacity planning beyond just cost
- More complex to configure and explain to users
- Requires accurate estimation for both dimensions
- The two unit-specific reservations are coordinated by the application; Cycles does not make them one cross-unit atomic transaction

## Combining Patterns

Expand All @@ -251,7 +245,7 @@ Most production systems layer two or three of these patterns. A common combinati
3. **[Graceful degradation](/glossary#graceful-degradation)** (Pattern 3) within each workflow run
4. **Shadow mode** (Pattern 5) for rollout

This gives you hard isolation between customers, right-sized limits per use case, user-friendly behavior at the limits, and a safe path to enforcement.
For instrumented paths, this gives you separate customer ceilings, right-sized limits per use case, user-friendly behavior at the limits, and a measured path to enforcement.

```
Tenant Budget ($500/mo)
Expand Down
Loading