Skip to main content

Allem Python SDK

Check AI agent actions before execution. Log actions for compliance.

This is the governance SDK — Tier 1 in Allem's connection-tier model: check_action() before the action happens, log_action() after, a durable spool so nothing is lost, and local enforcement of hard gates when Allem is unreachable. It is a different package from allem-api (a convenience client for the REST admin surface) and from allem-cli (the Tier 2 coding-agent hooks). Only this one blocks locally during an outage.

Install

pip install allem

Quick start

from allem import AllemClient

allem = AllemClient(
    api_key="alm_sk_test_...",
    endpoint="http://localhost:8000",
)

verdict = allem.check_action(
    agent_id="my_agent",
    action_type="send_email",
    parameters={"to": "client@example.com"},
    affects_external=True,
)

if verdict:
    send_email(...)
else:
    print(f"Blocked: {verdict.explanation}")

Verdict is truthy when the action is allowed, so if verdict: works directly. Inspect .severity, .recommended_action, .event_id, and .freeze for richer detail.

Fire-and-forget logging

For events that already happened (webhooks, retroactive logs):

allem.log_action(
    agent_id="my_agent",
    action_type="send_email",
    parameters={"to": "client@example.com"},
)

log_action never raises — logging must never break the agent.

Fail-open design

If the Allem API is unreachable, check_action returns Verdict(allowed=True, ...). An Allem outage will not block the customer's agent. The condition is recorded in verdict.explanation so calling code can log it.

Only two things ever produce allowed=False: a verdict Allem actually returned, and the local hard gate below. An auth failure, a 500, or a response body the client cannot parse is an absence of a verdict, not a denial, and fails open like any other outage.

Hard gates: the one thing that fails closed (Tier 1 only)

A scope rule the customer marks hard_gate: true is their fail-closed exception to the rule above, and setting it means Allem's availability becomes your availability for those actions. On this package the gate holds even when we are unreachable — a gate that only holds while Allem is up opens during exactly the incident it was bought for.

The SDK keeps a cached list of which action types are hard-gated for each agent (GET /agents/{id}/scopes/hard-gates, resolved through GET /agents/me), refreshed off the latency path after a successful check. When the platform does not answer:

Situation Outcome
Action is not hard-gated allowed — fail-open, unchanged
Action is on the cached list denied locally
Cached list is stale hard-gated entries still block
No list has ever been fetched allowed, and warned on every check

A stale cache does not relax the gate. Age makes the list less complete — a rule added during the outage is unknown to the SDK — not less binding on what it already holds.

The never-fetched row is the honest limit: the SDK cannot enforce a list it has never seen, so it proceeds and says so through the allem.client logger, every time, naming the endpoint and the reason. Watch for that warning; it means hard gates are not being enforced locally.

A locally-denied action still reaches the chain. It is spooled like any other event, annotated with which gate blocked it, the scope_version the list came from, and how stale the cache was — so an auditor can tell a gate that worked from a gate that guessed.

Configuration. The cache lives under ALLEM_HOME (default ~/.allem/state/, owner-only), with a 300s staleness bound overridable by ALLEM_HARD_GATE_TTL_S. On a read-only filesystem — a container or a Lambda — it falls back to memory for the process lifetime and logs once; the gate still blocks, it just has to be refetched on each cold start. check_action is never failed because a cache file could not be written.

Tier 2 is different, deliberately. The coding-agent hooks in allem-cli do not block during an outage: a hook that broke a developer's session would be uninstalled within the hour, and the agent could reach the same result through another tool path anyway. If you read "hard gates fail closed", it is true of this package and not of that one.

Authentication

The SDK sends the API key in the X-API-Key header. Use a test-mode key (alm_sk_test_...) when developing against a non-production endpoint.

Completeness: sequences and the durable spool

Every event the SDK emits carries a client-generated sequence block — {run_id, client_seq, signature, signature_method} — numbered 1, 2, 3, … per agent per process. The server can therefore prove not only that stored records were never altered (the hash chain), but that no record is missing: a sequence number that never arrives is a detectable gap.

Before any network attempt, each event is written to a local SQLite spool (default ~/.allem/spool.db, override with ALLEM_SPOOL_DIR or the spool_path argument). A background thread delivers spooled events and retries forever — backoff 1s → 32s, then every 60s. If the process exits with events undelivered, the next process replays them. Nothing is ever silently lost, and fail-open behaviour is unchanged: an Allem outage never blocks your agent.

Signing the sequence (optional, recommended)

The sequence number is a claim your agent makes. Signing it lets Allem check that claim — and, because your agent holds the private key and Allem holds only the public half, Allem cannot manufacture a claim on your behalf.

pip install 'allem[signing]'
python -m allem.sequence --out ~/.allem/agent.key   # private key, written 0600
# register the PUBLIC key printed by that command:
#   POST /v1/agents/{agent_id}/signing-keys
export ALLEM_SIGNING_KEY_PATH=~/.allem/agent.key

Or AllemClient(api_key=..., signing_key_path="~/.allem/agent.key").

The signature covers a digest of the event body, not just its position, so a signature cannot be lifted from one event onto another. Your private key is never sent to Allem, and the registration endpoint refuses anything that looks like one.

If a signature fails to verify, Allem records the failure and raises a critical finding — it still accepts the event. Enforcement fails open; that does not change.

Full details: docs/completeness-signing.md.

ALLEM_SIGNING_SECRET (HMAC-SHA256) is still accepted so existing deployments keep running, but Allem has never held that secret and therefore cannot verify those signatures: they are recorded as unverified. The SDK warns once at construction. Use a key path instead.

Run lifecycle and heartbeats

client.start_run("billing-bot")   # run_start (client_seq 1), then a beat every 60s
...
client.close()                     # run_end

Heartbeats make silence mean something specific. Without them, "the agent did nothing" and "the agent stopped reporting" are the same observation. With them, the server opens a blackout window when an agent goes quiet past three missed beats, and closes it when your spool replays — so an outage becomes a bounded, recorded fact instead of a hole in the log.

A heartbeat consumes a client_seq like any other event, which is the point: a missing heartbeat is itself a detectable gap.

start_run is an explicit call because run_start must take client_seq = 1 — any log_action for that agent would consume that number first. run_end is also emitted on atexit and SIGTERM (chained onto your own handler, never replacing it).

Call client.flush(timeout=...) before process exit to drain the spool if you want delivery confirmation; it is never required for correctness.

v1 limitations (stated openly)

  • Spool encryption: the spool file is not encrypted at rest in v1. It is created with restrictive permissions (0700 directory, 0600 file), but it may contain sensitive action parameters. If you operate under regulatory requirements (healthcare, financial services), place ALLEM_SPOOL_DIR on an encrypted volume until spool encryption ships.
  • One run per process: sequence state lives in memory, so serverless / one-shot agents produce many short runs (seq 1–2 each). Completeness still holds within each run, but gap detection is nearly vacuous for such workloads. Cross-process sequence persistence is deliberately not attempted in v1.
  • Completeness covers instrumented call sites only. Code paths that never call the SDK reserve no sequence numbers and are outside the guarantee.

Download files

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

Source Distribution

allem-0.1.0.tar.gz (53.4 kB view details)

Uploaded Source

Built Distribution

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

allem-0.1.0-py3-none-any.whl (36.4 kB view details)

Uploaded Python 3

File details

Details for the file allem-0.1.0.tar.gz.

File metadata

  • Download URL: allem-0.1.0.tar.gz
  • Upload date:
  • Size: 53.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for allem-0.1.0.tar.gz
Algorithm Hash digest
SHA256 991c3b1ccfa0e9e9d101997f00582efa5db69e80b782be7b460775dbd09fe9d3
MD5 fa3a4aba66ae4718b039aeff5c9c6ff2
BLAKE2b-256 9da7ac654385b4f387e90c038079a7c7e86c94a254baa8c7b7299d6defd26f84

See more details on using hashes here.

Provenance

The following attestation bundles were made for allem-0.1.0.tar.gz:

Publisher: publish.yml on Allemai/allem-platform

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file allem-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: allem-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 36.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for allem-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a31508fbabbc931371334536c33f26a3c9479bc7585828f7b58a9a3304595e69
MD5 a05095c7a72935e409fe8c55c2de3ba2
BLAKE2b-256 2b3b9cdff7f7de290b5afbc237f14348c88d13be0bffa43109c8528e0e66d7c7

See more details on using hashes here.

Provenance

The following attestation bundles were made for allem-0.1.0-py3-none-any.whl:

Publisher: publish.yml on Allemai/allem-platform

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 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