Skip to main content

Python SDK for the Lyhna governance API

Project description

lyhna

Python SDK for Lyhna — the execution authority boundary for AI systems. Every consequential action passes through bind() before it happens. The server returns a cryptographically signed receipt (Ed25519, LyhnaReceiptV2) that can be verified offline by any party — no network call, no API key required.

Install

pip install lyhna

Requires Python 3.8+.

Authentication

Set your API key as an environment variable:

export LYHNA_API_KEY=lyhna_dev_...

Get a key by signing up at https://www.lyhna.com/signup.

Endpoint Override

By default, the Python SDK sends requests to https://api.lyhna.com.

For staging, local testing, or self-hosted deployments, set LYHNA_ENDPOINT before constructing the client:

export LYHNA_ENDPOINT="https://staging.example.com"
from lyhna import LyhnaClient

client = LyhnaClient()
# client.base_url == "https://staging.example.com"

Resolution order (highest precedence first):

  1. base_url passed directly to LyhnaClient(...) or AsyncLyhnaClient(...).
  2. LYHNA_ENDPOINT environment variable.
  3. Default: https://api.lyhna.com.

LYHNA_API_KEY remains the authentication environment variable.

Quick start

import lyhna

receipt = lyhna.bind(
    action_type="deploy_service",
    action_payload={"service": "api", "version": "v3"},
    intent="release_v3",
    intent_version="1.0",
)

if receipt.outcome == "APPROVED":
    # Execute your action here
    print(f"Approved under authority tier {receipt.authority_tier}")
    print(f"Receipt: {receipt.receipt_id}")

# Verify the receipt offline — no network, no API key required
is_valid = lyhna.verify_receipt(receipt)
assert is_valid

API

bind(action_type, action_payload, intent, intent_version) -> Receipt

Call before any consequential action. All four parameters are required.

  • action_type (str) — canonical identifier, e.g. "deploy_service", "send_email", "transfer_funds"
  • action_payload (any) — JSON-serializable description of what will happen
  • intent (str) — high-level intent, e.g. "release_v3"
  • intent_version (str) — version of the intent, e.g. "1.0"

Returns a Receipt with one of three outcomes:

  • APPROVED — execute the action
  • ESCALATED — waiting on human authority; hold the action
  • REFUSED — do not execute

Authority tier is resolved server-side from your tenant's authority_rules — callers cannot self-classify.

verify_receipt(receipt) -> bool

Verify a receipt offline. Returns True if:

  • the receipt's canonical hash recomputes to its claimed value, AND
  • the Ed25519 signature validates against the public key embedded in the receipt

No network call. No API key required. Any party holding a Lyhna receipt can verify it independently.

Fail-closed: returns False on any error. Never raises.

verify_receipt_offline(receipt) -> bool

Alias for verify_receipt. Same behavior — explicit name for clarity in code that wants to emphasize the offline verification path.

Using the client directly

For multiple calls, instantiate a client explicitly to reuse connections:

from lyhna import LyhnaClient

with LyhnaClient() as client:
    for action in actions:
        receipt = client.bind(
            action_type=action.type,
            action_payload=action.payload,
            intent="batch_process",
            intent_version="1.0",
        )
        if receipt.outcome == "APPROVED":
            action.execute()

Async client available as AsyncLyhnaClient:

from lyhna import AsyncLyhnaClient

async with AsyncLyhnaClient() as client:
    receipt = await client.bind(
        action_type="deploy_service",
        action_payload={"service": "api"},
        intent="release_v3",
        intent_version="1.0",
    )
    is_valid = await client.verify_receipt(receipt)

Errors

Exception Raised when
LyhnaAuthError API key is missing, invalid, or unauthorized (401/403 from server on bind)
LyhnaTimeoutError Request to the enforcement boundary timed out
LyhnaError Other HTTP or network errors during bind

verify_receipt() never raises. It returns False on any failure — by design, to match the fail-closed guarantee that any cryptographic failure must deny rather than throw.

Receipt structure

A Receipt exposes common fields (receipt_id, outcome, action_type, authority_tier, bound_at, expires_at, canonical_hash, signature) and preserves the full server response in receipt.raw for offline verification.

Learn more

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lyhna-0.2.2.tar.gz (10.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lyhna-0.2.2-py3-none-any.whl (9.1 kB view details)

Uploaded Python 3

File details

Details for the file lyhna-0.2.2.tar.gz.

File metadata

  • Download URL: lyhna-0.2.2.tar.gz
  • Upload date:
  • Size: 10.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for lyhna-0.2.2.tar.gz
Algorithm Hash digest
SHA256 1f14a96f52b831d36cbee64600872dc76bbea8c549f7045e60326187b312ab19
MD5 03ce73be146357a27d65b99767d6be9f
BLAKE2b-256 7aa72aed4a7c1ed2f3a8dce3c1ee2320fd610769485495b891ffc48d7d1b08ac

See more details on using hashes here.

File details

Details for the file lyhna-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: lyhna-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 9.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for lyhna-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 84773cb86d7b25567e92d82f5048febef0e7db2db989e4547ca662b4a7b3dc4a
MD5 b444fa38b085bdca7ee5957963336c39
BLAKE2b-256 e736e5116a88a12b12f205727f0ce91901efe0e8c9caabf8c072fd517f0bb175

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page