Skip to main content

Anlyon Python SDK

Governed execution for AI agents. Official Python SDK for Anlyon. Your agent invokes a named action. Anlyon holds the credentials, evaluates policy, waits for approval when required, and makes the production call itself.

Installation

pip install anlyon

Quick start

Define the action once, from an operator key. That is the one place your credential appears. This example uses the Stripe refund adapter with a Stripe test key. The adapter takes "mode": "live" or "mode": "test" and a key that matches it:

import os
from anlyon import Client

ops = Client(api_key=os.environ["ANLYON_OPERATOR_KEY"])

ops.secrets.put(
    "STRIPE_TEST_KEY",
    value=os.environ["STRIPE_TEST_KEY"],  # sk_test_... The key must match the action's mode.
    allowed_hosts=["api.stripe.com"],  # Anlyon will not send this key to any other host
)

ops.actions.create(
    name="refund-order",
    requires_approval=True,
    adapter={
        "type": "stripe.refund",
        "config": {"account": "acct_1Nxyz", "mode": "test", "currency": "usd"},
        "credentialSecret": "STRIPE_TEST_KEY",
    },
)

From then on, this is all your agent sees. No URL, no header, no key:

anlyon = Client(api_key=os.environ["ANLYON_AGENT_KEY"])

# Successful calls expose the canonical response envelope.
refund = {"paymentIntent": "pi_3Pabc", "amount": 1250, "currency": "usd"}  # $12.50 in minor units
result = anlyon.actions.invoke("refund-order", refund)

if result.data["pendingApproval"]:
    print("Parked for a human:", result.data["approvalId"])
else:
    print("Receipt grade:", result.data["grade"])

anlyon.close()

For an API with no adapter, create() takes url_template and headers with {{secret:NAME}} instead.

status on an invocation distinguishes failed (the call did not happen, safe to retry) from unknown (it may have reached the destination, so reconcile before retrying). Anlyon does not retry an action invocation.

The client does retry its own HTTP request to Anlyon after a network error or a timeout, or when Anlyon answers 429, 500, 502, 503 or 504, up to RetryConfig.max_attempts (3 by default). The SDK sends an idempotency key on every invoke. When you do not pass an idempotency_key, it generates one for that call and sends the same key on each resend. A resend is answered from the recorded invocation and is not executed again.

A generated key covers one call to invoke. Two calls are two keys, and two keys are two invocations. Pass your own idempotency_key when your code may call invoke twice for the same business operation, for example after a restart or from a job that runs again.

A generated key is not returned in the response. If a resend arrives while the original request is still running, the API can answer 409 idempotency_request_in_progress. The SDK does not resend that. The error names the key in its message and in details["idempotency_key"]. Call invoke again with that key to get the result of the original. A call without it is a new invocation.

This covers actions routed through Anlyon. A tool your own code calls directly, with a credential your own process holds, is not routed through Anlyon and is not governed by it.

Declare impact and verify

Any action can say how much one invocation changes and how to read the result back. Declaring either one makes the action governed.

ops.actions.declare(
    "send-email",
    impact={"dimension": "emails", "amount": "count(input.to)", "bound": "exact"},
    verify={
        "url": "https://api.example.com/v1/messages/{{response.id}}",
        "status": 200,
        "match": [{"path": "status", "equals": "sent"}],
    },
)

# One limit, shared by every agent, session and key in the environment.
# It counts governed actions routed through Anlyon.
ops.impact_limits.create(name="Daily emails", dimension="emails", period="day", amount=500)

dimension is money, resource_mutations, or a unit you name, such as emails. amount is an expression over the input: an integer, input.<path> or count(input.<path>), with one optional * <integer>. create() and update() take the same impact, verify and governed arguments. None removes a declaration. An argument you leave out keeps what is there. governed=False removes every declaration.

Every governed invocation answers with a receipt grade:

result = anlyon.actions.invoke("send-email", {"to": ["a@example.com"], "subject": "Hi"})
print(result.data["grade"])  # "confirmed" once the read-back matches

for effect in anlyon.actions.effects(grade="unknown").data:
    print(effect["id"], effect["grade"])
Grade Meaning
confirmed A read-back matched the request. An adapter reads the provider's own record.
acknowledged The provider accepted the request. Nothing read it back.
unknown No usable response. Anlyon does not send it again. It stays unknown until a read-back or an operator settles it.
failed The provider rejected the request, or it never left Anlyon.
refused Anlyon refused it at dispatch. An exhausted limit is one cause.
denied The approval was denied.
pending No receipt yet.

An action with no declaration and no adapter is not governed. It creates no effect and returns no grade. Anlyon evaluates the amount you declare. It does not check that the expression describes what the provider will do. A declared action has no provider idempotency, so a lost response stays unknown until a read-back or an operator settles it.

Async

import asyncio
import os
from anlyon import AsyncClient

async def main():
    async with AsyncClient(api_key=os.environ["ANLYON_AGENT_KEY"]) as client:
        refund = {"paymentIntent": "pi_3Pabc", "amount": 1250, "currency": "usd"}
        result = await client.actions.invoke("refund-order", refund)
        print(result.data["status"])

asyncio.run(main())

Configuration

from anlyon import Client, RetryConfig

client = Client(
    api_key="anlyon_live_xxx",       # falls back to ANLYON_API_KEY
    base_url="http://localhost:4000",  # falls back to ANLYON_BASE_URL
    timeout=10.0,
    retry=RetryConfig(max_attempts=5),
)

Resources

The governed execution path:

  • client.actions: create, import_openapi, list, get, update, declare, delete, invoke, invocations, invocation, versions, preview, effects, effect (hosted execution)
  • client.impact_limits: list, get, create, update, archive (shared limits in money, resource mutations or a declared unit)
  • client.secrets: put, list, get, delete (write-only vault, no method returns a value)
  • client.approvals, client.approval_policies: approval requests, decisions and the policies that route them
  • client.budgets: monthly caps per agent key on Anlyon operations. They do not cap model tokens or the money an action moves
  • client.environment: get, halt, resume
  • client.runs: traces of what an agent did

Also on the client:

  • client.events: publish, list, get, topics CRUD, subscriptions
  • client.analytics, client.logs: usage, delivery analytics, redacted execution history, exports
  • client.billing, client.notifications: billing state and notification preferences
  • client.integrations: Slack and Discord delivery

Most write operations accept an idempotency_key. The same key and the same request return the recorded result instead of writing twice:

client.actions.invoke("refund-order", refund, idempotency_key="refund:ord_42")

Error handling

Successful calls return ApiResponse with success, data, pagination, stats, and request_id, matching the HTTP contract and TypeScript SDK. For compatibility with the 0.1 release, indexing, iteration, get(), len(), and equality delegate to response.data. New code should use response.data explicitly. That shortcut is deprecated for removal in the next major release.

Failed requests raise typed exceptions (never return an error envelope):

from anlyon import Client, NotFoundError, RateLimitError

client = Client(api_key="anlyon_live_xxx")
try:
    client.actions.get("act_missing")
except NotFoundError:
    print("Not found")
except RateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after}s")

Earlier namespaces remain available through the API for existing workspaces. See the billing docs.

Metadata

Release files for anlyon 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for anlyon 0.5.0
File Size Uploaded
anlyon-0.5.0.tar.gz 80.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for anlyon 0.5.0
File Interpreter ABI Platform
anlyon-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 152.8 kB

Release files / anlyon-0.5.0.tar.gz

Download URL anlyon-0.5.0.tar.gz
Size 80.5 kB
Tags Source
SHA-256 checksum
How to use checksums
3ab32735f42cfc5d21fa354eddb21433069b85576bedf2fd0f3bf05782e8e1c2
BLAKE2b-256 checksum
How to use checksums
d79bc06d78c2a790904bd515419a0a7608dd9ed74a97e3339a54100d0e75a596
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / anlyon-0.5.0-py3-none-any.whl

Download URL anlyon-0.5.0-py3-none-any.whl
Size 72.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f8b0dc2c97936c818c1142fccd73886824c5f20991d4b5403c70dacf59596dc6
BLAKE2b-256 checksum
How to use checksums
09a244aefbeae3be420f6f37b0936e8db270d11015c0496073a6147665412ce0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page