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_replayhook), 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
879d9f3f4b6ef423295cc66765840892ebc7263680c2a5493fed3687c385f888
|
|
| MD5 |
eda4b65b3e5ab16f01cca0f51255bf39
|
|
| BLAKE2b-256 |
af95592d04d7ecdf6739c9f0c27afccc50def7145b239cf57e194e8283cb8701
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19d7d306de0a5fedbd8567deb9a1fd2b1deb3ba15dfe677505921be154f78c5e
|
|
| MD5 |
36432ef9275a78acab5c87c37c160fbe
|
|
| BLAKE2b-256 |
625705dd5fc59c3f308916ba4b6938b81362f47a3d0e7b29de7128bdff035dbe
|