██████╗██╗ ██╗ ██████╗ ██╗ ██╗██╗ ██╗██╗ ██╔════╝██║ ██║██╔═══██╗██║ ██║██║ ██╔╝██║ ██║ ███████║██║ ██║██║ █╗ ██║█████╔╝ ██║ ██║ ██╔══██║██║ ██║██║███╗██║██╔═██╗ ██║ ╚██████╗██║ ██║╚██████╔╝╚███╔███╔╝██║ ██╗██║ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝
chowki
Your agent crashed on step 9 of 10. chowki makes step 10 the only thing that runs again.
chowki (Urdu چوکی — a checkpost, a place where things are stopped and inspected) is an
in-process control plane for LLM agents. It adds durable state, approval gates, secret
redaction, and runaway-loop guardrails to agent code you have already written — as
decorators, with no server, no worker pool, and no sidecar.
It is not an agent framework. It goes underneath the one you already use.
Why
An LLM agent is an expensive, non-deterministic, side-effecting loop. Four things go wrong, and every one of them costs money or trust:
| Problem | Without chowki | With chowki |
|---|---|---|
| Process dies at step 9 of 10 | Re-run from scratch, re-pay for all 9 LLM calls | Completed steps are memoised; only step 10 runs |
| Agent is about to email a customer | You find out afterwards | chowki.pause() suspends the run and mints a signed approval token |
| An API key lands in the agent's state | It is now in your logs and your database | Redacted to [REDACTED:api_key:9f2c…] before it is persisted |
| Agent loops on the same tool call forever | You notice on the bill | Loop detection raises after N repeats; token budgets pause the run |
Install
pip install chowki
Optional OpenTelemetry span export:
pip install "chowki[otel]"
Requires Python 3.11+. Runtime dependencies are msgspec, jsonpatch, jsonpointer,
cryptography, structlog, and opentelemetry-api.
60-second quickstart
import chowki
@chowki.step
def fetch_invoice(invoice_id: str) -> dict[str, object]:
return {"id": invoice_id, "amount": 4_200}
@chowki.step(idempotent=False) # can pause -> must be re-enterable
def pay_invoice(invoice: dict[str, object]) -> str:
chowki.pause(
reason="Payment over $1,000 needs a human",
payload=invoice,
permitted_actions=("APPROVE", "REJECT", "EDIT"),
)
return _transfer(invoice) # only runs after approval
@chowki.step # the real side effect: exactly-once
def _transfer(invoice: dict[str, object]) -> str:
return f"paid {invoice['amount']} for {invoice['id']}"
@chowki.workflow
def billing_agent(invoice_id: str = "inv-1") -> str:
return pay_invoice(fetch_invoice(invoice_id))
Run it, and it stops at the gate:
try:
billing_agent(invoice_id="inv-1", run_id="run-1")
except chowki.WorkflowPaused as paused:
token = paused.token # single-use, HMAC-signed, bound to this run + gate
Approve it — from this process, another process, a web handler, or the CLI:
chowki.resume(run_id="run-1", token=token, decision=chowki.Decision.APPROVE)
fetch_invoice is not called again. Neither is anything else that already completed.
chowki runs list # what is paused right now
chowki runs show run-1 # full state, history, audit log
chowki resume run-1 --token '<token>' --decision APPROVE
The one rule
Every side effect belongs inside a @chowki.step. resume() re-executes the workflow
body from the top, and only steps are memoised — anything outside one runs again.
The one gotcha
A step whose body can reach chowki.pause() must be declared idempotent=False. The
idempotency claim is taken before the body runs and a pause does not release it, so a
default step that pauses cannot be re-entered on resume. Keep the actual side effect in a
nested default step, as _transfer above — it keeps exactly-once protection while the gate
stays re-enterable.
Works with the framework you already use
chowki wraps tools, so it composes with any framework that calls plain Python functions.
The framework decorator goes on the outside; @chowki.step goes underneath it, so the
framework builds its schema from your signature and chowki intercepts the call:
@tool # LangChain / CrewAI / OpenAI Agents SDK / PydanticAI
@chowki.step # chowki sees every invocation
def issue_refund(order_id: str, amount: float) -> str: ...
Runnable examples for each, in
examples/python/integrations/:
| Framework | Example | What chowki adds |
|---|---|---|
| LangChain / LangGraph | langgraph_refund_agent.py |
Tools memoised across a crash; approval gate before the refund |
| CrewAI | crewai_refund_crew.py |
Per-agent budgets; the crew resumes instead of restarting |
| OpenAI Agents SDK | openai_agents_refund.py |
@function_tool + durable steps; usage reported per turn |
| Pydantic AI | pydantic_ai_refund.py |
Typed tools stay typed; gate rides on RunContext deps |
| No framework | anthropic_tool_loop.py |
A hand-written Claude tool loop, made durable |
Scope, honestly: chowki memoises what you decorate. Model calls made inside a framework's own loop are re-issued on resume unless you wrap them too — each example shows where that hook goes for that framework.
What you get
- Warm resume & crash recovery — top-down re-execution with step memoisation.
chowki recoverrevives runs whose process was killed;chowki rerunfinishes them without repeating completed work. - Human-in-the-loop gates —
chowki.pause()mints a single-use HMAC-SHA256 token bound to one run and one gate. Decisions areAPPROVE,REJECT,EDIT(an RFC 6902 patch the reviewer applies to state), andESCALATE. Every decision is written to an audit log. - Always-on secret redaction — regex patterns plus Shannon-entropy scanning, applied to step arguments, state snapshots, and logs before anything is persisted. Placeholders are stable HMAC digests, so diffs stay readable without exposing the secret.
- Guardrails — token/cost budgets with soft-warning thresholds, and three tiers of loop
detection: repeated tool-call hashes, Levenshtein-similar text (
chowki.record_text), and cycles in the delegation graph (chowki.record_transition). - Encryption at rest — optional AES-256-GCM over snapshot payloads, keyed from
CHOWKI_MASTER_KEY, with the tenant and run bound in as AAD. - Inspection —
chowki.inspect_run()andchowki runs showread full state, step history, and the audit trail without disturbing a live run. - Storage you already have — SQLite by default (a file, created on first use), in-memory for tests, or your own adapter.
Configuration
import chowki
from chowki.guardrails import GuardrailConfig
from chowki.hitl.console import ConsoleGateway
chowki.configure(
db_path="./agent.db",
resume_secret=b"...", # 32+ bytes; without it tokens die on restart
gateway=ConsoleGateway(), # or your own Slack / web gateway
encrypt_at_rest=True, # reads CHOWKI_MASTER_KEY
guardrails=GuardrailConfig(max_token_budget=100_000, soft_budget_threshold=0.8),
)
Set resume_secret in production. Without it chowki signs with an ephemeral per-process
key and warns — tokens minted before a restart will not verify after it.
Limits worth knowing before you adopt
chowki is single-process, single-writer per run. Two processes writing the same run to one SQLite file is not supported, and it says so rather than corrupting your state. Distributed workers, Postgres/Redis adapters, and multi-region leasing are roadmap, not shipped.
Full detail: Limits & Operational Boundaries.
Documentation
| User Guide | Start here |
| Core Concepts | Runs, steps, state, base/delta snapshots |
| Warm Resume | Re-execution, memoisation, the R4 rule, crash recovery |
| Guardrails | Budgets, loop detection, provider usage recipes |
| HITL | Gates, tokens, decisions, CLI walkthrough |
| Configuration & Security | ChowkiConfig, secrets, encryption, multi-tenancy |
| Production Resumes | FastAPI / Flask, async, HTTP status mapping |
Status
Alpha, and honest about it: the API may shift before 1.0. The Python SDK is the reference implementation; a Node/TypeScript SDK is next, built against a shared conformance spec.
MIT licensed. Issues and PRs: https://github.com/Git-Uzair/chowki.
Metadata
Release files for chowki 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| chowki-0.1.0.tar.gz | 129.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chowki-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 206.9 kB
Release files / chowki-0.1.0.tar.gz
| Download URL | chowki-0.1.0.tar.gz |
|---|---|
| Size | 129.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f7b11ad9e75345c76f405a7acccabea8f4d2950d526d20199177f689f13f508b
|
|
BLAKE2b-256 checksum How to use checksums |
5cb857a311af0948e1331e5f0e8b226e99bd847dd79b9a1678bff64463c37ba3
|
| 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 Aug 12, 2026.
Transparency logRelease files / chowki-0.1.0-py3-none-any.whl
| Download URL | chowki-0.1.0-py3-none-any.whl |
|---|---|
| Size | 77.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
61b192e97bad244e6cfc4737cbcefced4868328d2dc201018261ad83e3a37675
|
|
BLAKE2b-256 checksum How to use checksums |
ba54aca117957a596bd89ae7ebd71c9685e52447342103a68310206e98ac81b5
|
| 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 Aug 12, 2026.
Transparency log