Skip to main content

Exactly-once effects for AI agents.

Project description

Sakrit

Exactly-once effects for AI agents.

Sakrit is a thin, framework-agnostic layer that sits between an AI agent and the tools it calls, guaranteeing that every action with real-world consequences — sending an email, charging a card, writing to a database — happens exactly once, even when the agent crashes, resumes, retries, or explores several plans in parallel.

Agent frameworks solved checkpointing — saving progress so a crashed run can resume. They did not solve idempotent side effects. When an agent resumes from a save point, it re-runs steps it already completed. The save point rewinds the agent but not the world. Sakrit closes that gap.

Quickstart

Wrap the tool that touches the world. Declare which arguments are identity (a different value means a different action) and which are content (the model may reword them on a retry). That's it.

from sakrit import Sakrit, SqliteLedger, EffectDecl
from sakrit.core import ArgClass
from sakrit.adapters.langgraph import LangGraphAdapter

sk = Sakrit(
    SqliteLedger("sakrit.db"),
    secret=b"<per-deployment secret>",
    adapter=LangGraphAdapter(),
)


@sk.effect(
    EffectDecl(
        "email.send",
        {
            "to": ArgClass.IDENTITY,  # a different recipient is a different email
            "subject": ArgClass.IDENTITY,
            "body": ArgClass.CONTENT,  # a reworded body is the *same* email
        },
    )
)
def send_email(to: str, subject: str, body: str) -> str:
    return smtp.send(to, subject, body)


# Crash, resume, or retry: send_email fires exactly once.
# A re-run returns the saved result instead of sending again.

The sequential-repeat trap. Calling the same guarded tool again at the same call site with the same identity args (e.g. deliberately sending one reminder twice) replays the recorded result — the effect does not re-fire. That is exactly right for a crash/resume retry, but a silent no-op for a deliberate repeat. To fire it again, give each call its own position:

for i, recipient in enumerate(recipients):
    with sk.step(occurrence=i):
        send_email(to=recipient, subject=..., body=...)

Every replay is logged at INFO (and fires the ledger's on_replay hook), so it is told, not silent. A concurrent overlapping second call is loud (EffectInFlightError); only the sequential same-args repeat swallows. Automatic occurrence handling is deferred — see the design notes.

Status

Pre-alpha — the Act II core works. Exactly-once for single-worker agents on LangGraph: positional identity, the coordinate ladder, a fingerprint over identity args, a write-ahead SQLite ledger, replay, and a startup recovery scan. Verified end-to-end (the guarded double-email sends once across a real interrupt/resume).

Not yet: multi-worker (leases/fencing, Postgres), the provider-cooperation ladder beyond L0/replay, the effect outbox / approval gating, and plan-epoch handling — these are Act III. See CONTRIBUTING.md to get involved (a signed CLA comes first).

Development

Requires Python ≥ 3.10. This project uses uv.

# Install dependencies (including dev tools)
uv sync

# Run the test suite
uv run pytest

# Lint and type-check
uv run ruff check .
uv run mypy

License

Apache-2.0.

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

sakrit-0.0.1.tar.gz (152.3 kB view details)

Uploaded Source

Built Distribution

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

sakrit-0.0.1-py3-none-any.whl (103.8 kB view details)

Uploaded Python 3

File details

Details for the file sakrit-0.0.1.tar.gz.

File metadata

  • Download URL: sakrit-0.0.1.tar.gz
  • Upload date:
  • Size: 152.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for sakrit-0.0.1.tar.gz
Algorithm Hash digest
SHA256 879d9f3f4b6ef423295cc66765840892ebc7263680c2a5493fed3687c385f888
MD5 eda4b65b3e5ab16f01cca0f51255bf39
BLAKE2b-256 af95592d04d7ecdf6739c9f0c27afccc50def7145b239cf57e194e8283cb8701

See more details on using hashes here.

File details

Details for the file sakrit-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: sakrit-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 103.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for sakrit-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 19d7d306de0a5fedbd8567deb9a1fd2b1deb3ba15dfe677505921be154f78c5e
MD5 36432ef9275a78acab5c87c37c160fbe
BLAKE2b-256 625705dd5fc59c3f308916ba4b6938b81362f47a3d0e7b29de7128bdff035dbe

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