Skip to main content
   ██████╗██╗  ██╗ ██████╗ ██╗    ██╗██╗  ██╗██╗
  ██╔════╝██║  ██║██╔═══██╗██║    ██║██║ ██╔╝██║
  ██║     ███████║██║   ██║██║ █╗ ██║█████╔╝ ██║
  ██║     ██╔══██║██║   ██║██║███╗██║██╔═██╗ ██║
  ╚██████╗██║  ██║╚██████╔╝╚███╔███╔╝██║  ██╗██║
   ╚═════╝╚═╝  ╚═╝ ╚═════╝  ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝
  

chowki

Your agent crashed on step 9 of 10. chowki makes step 10 the only thing that runs again.

PyPI Python License: MIT CI

State savers restore state. chowki memoizes step results — so on resume, the LLM calls and API requests that already succeeded do not happen again.

Coming from LangGraph? Its SqliteSaver restores the graph state at a checkpoint, and its own docs say the nodes after it re-execute — "including any LLM calls, API requests, and interrupts". chowki records the result of every @chowki.step, so those calls are served from the record instead of re-issued.

  • No determinism tax — no replay-safe workflow body, no journal-mismatch errors. Your code may call random, time.time(), or an API directly; non-determinism is isolated at the step boundary.
  • Approval gates with cryptographic provenance — one single-use HMAC-SHA256 token per run and gate, four decisions (APPROVE / REJECT / EDIT as an RFC 6902 patch / ESCALATE), and an append-only audit log no adapter is permitted to delete from.
  • Secret redaction that cannot be switched off — key names, a combined provider-credential regex, and Shannon entropy over step arguments, state, and logs before anything is persisted.
  • Agent cost budgets — token and spend ceilings with an 80% soft warning re-seeded from persisted usage on resume, three tiers of loop detection, and max_steps_per_run.

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
Slack approvals (a channel, not a framework) slack_approvals.py Gate arrives in Slack; an HMAC-verified click resumes the run over HTTP

Slack is a worked example, not a shipped adapter. A first-party Slack gateway is roadmap Phase 4. slack_approvals.py is what you write today against extension points that exist now — ConsoleGateway implements the same protocol, and PauseNotice caps the token below Slack's button limit on purpose.

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 recover revives runs whose process was killed; chowki rerun finishes 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 are APPROVE, REJECT, EDIT (an RFC 6902 patch the reviewer applies to state), and ESCALATE. 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() and chowki runs show read 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.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chowki 0.2.0
File Size Uploaded
chowki-0.2.0.tar.gz 142.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for chowki 0.2.0
File Interpreter ABI Platform
chowki-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 225.1 kB

Release files / chowki-0.2.0.tar.gz

Download URL chowki-0.2.0.tar.gz
Size 142.4 kB
Tags Source
SHA-256 checksum
How to use checksums
4969d61f499ce9bf0cb3fd7114da40d011e90024b584a31595de5deaa20772ea
BLAKE2b-256 checksum
How to use checksums
8a0beaef50b52c22e180aca857e9c2761bdde8d88e2d66f29ab68f6433001205
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 13, 2026.

Transparency log

Release files / chowki-0.2.0-py3-none-any.whl

Download URL chowki-0.2.0-py3-none-any.whl
Size 82.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c39069de0d509e143960999a97b5e23837b7202e144999015ce6e111a2692183
BLAKE2b-256 checksum
How to use checksums
72c6a51f77d2ffdb0368f6f970507b21218ee18dfd04cfa0f0ad10ddd421591e
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 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release 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