Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

statejar (Python)

The Python client for the hosted StateJar memory API.

StateJar keeps conversational memory as structured, versioned state on the StateJar service. This package sends a message to the service, gets back the fields a question needs as memory_context, and hands that to your own model call. It never calls a language model and never sees your provider key.

What this package includes — and what it does not

Included Not included
StateJar, an HTTP client for /memory/ingest and /memory/query Any memory engine: extraction, canonicalization, handles and versioning all run on the StateJar service
Typed exceptions (StateJarError, StateJarAuthError, StateJarConnectionError) Any LLM client or provider integration
py.typed type information The StateJar backend, frontend or database code

The only runtime dependency is httpx. Until 0.4.1 this distribution also carried an embedded engine (statejar.LocalMemory); it was removed in 0.5.0 — see CHANGELOG.md.

Licence

Free to use with the StateJar service, under the StateJar SDK License in the LICENSE file included with this package. It is a proprietary licence, not an open-source one: you may install and use the unmodified package to access the service and redistribute unmodified copies; you may not distribute modified versions, use the package to build a competing service, or reverse engineer the service. Use of the service itself is governed by the terms at https://statejar.com/terms.

Install

pip install --pre statejar      # 0.5.0rc1, the current pre-release

Requires Python 3.10+. --pre is needed until 0.5.0 itself is published; without it pip finds no installable release.

Status and limits (0.5.0rc1, pre-release)

  • Tested: the client's unit tests (HTTP mocked with respx), a clean install on CPython 3.11 / Linux, and an end-to-end run of the installed wheel against a StateJar server run locally (MariaDB 10.4). The hosted API (api.statejar.com) was not exercised by an automated test for this release.
  • What the service extracts is the service's behaviour, not this client's. Extraction on the service is a deterministic rules tier that can misread a sentence; no accuracy figure is claimed in this package.

Quickstart

Get a key on the API Keys page of the console (keys look like sj_live_…). Then:

from statejar import StateJar

sj = StateJar(api_key="sj_live_...", session_tag="my-app")
turn = sj.turn("My name is Meera Nair and I prefer email")

turn["memory_context"]          # prompt-ready system message for YOUR model

memory_context goes into your own LLM call as the system message, with the user's text as the user message. With OpenAI, for example:

from openai import OpenAI

client = OpenAI()               # reads OPENAI_API_KEY — never sent to StateJar
reply = client.chat.completions.create(
    model="gpt-4o-mini",        # the example defaults to this via OPENAI_MODEL
    messages=[
        {"role": "system", "content": turn["memory_context"]},
        {"role": "user",   "content": "Book my delivery"},
    ],
)
print(reply.choices[0].message.content)

That is the whole integration.

Statements without questions

For a message that needs no answer, skip retrieval entirely:

turn = sj.turn("Budget is under 25000 and the deadline is 20 September", ask=False)
# one request made; turn["memory_context"] is None

Working with the turn payload

turn["handle"]           # the state handle this turn produced
turn["declined"]         # values extraction refused, with reasons (e.g. a
                         # quantity offered to a money field) — never guessed
turn["subset_keys"]      # exactly which fields were disclosed, e.g. ["facts.name"]
turn["retrieval_mode"]   # field_match | intent_map | full_state | …
turn["audit_id"]         # the disclosure is audited; replay it from the console

Lower-level access

stored = sj.ingest("I'm from Pune")                # full ingest response
got = sj.recall("Where am I from?", audit=False)   # subset + metadata;
                                                   # audit=True pins the
                                                   # disclosure to the trail

recall(audit=True) writes the disclosure to the server-side audit trail, so you can prove later what was sent — the same trail the console's Audit page shows. turn() audits by default; turn(text, audit=False) skips it.

API

Method Endpoint Returns
ingest(text) POST /memory/ingest handle, parent_handle, stored, state, conflicts, extraction_*
recall(query, audit=False) POST /memory/query memory_context, subset, handle_used, metadata, audit_id
turn(text, ask=True, audit=True) both, ingest first all of the above, plus declined, subset_keys, retrieval_mode

handle and handle_used are None while a session has no stored facts. Auth is sent as X-API-Key; use one session_tag per conversation thread. The client holds a connection pool — close it, or use it as a context manager:

with StateJar(api_key="sj_live_...", base_url="http://localhost:8000/api/v1") as sj:
    sj.turn("I prefer email")

How it works

Every turn is two API calls, in this order, then yours:

  1. Ingest — POST /memory/ingest commits the message's facts: extracted, canonicalized, sealed into SHA-256 content-addressed state.
  2. Recall — POST /memory/query returns the stored fields the question needs, formatted as memory_context. While a session's state is small (under the service's threshold) the whole state is returned instead — metadata.retrieval_mode says which.
  3. Your LLM call — memory_context as the system message. Your provider, your key, your code; StateJar is not in it.

Two guarantees live in that ordering:

  • BYOK — your key stays yours. The provider key is used inside your process, in step 3, and is never sent to StateJar. No transcript is stored either: the server sees one message at a time and keeps the facts it extracts, not the message.
  • Ingest commits before recall runs, so the context you send already contains the turn that asked the question. Reversing the order retrieves state from before that message existed — and the failure is invisible, because you still get a fluent answer, just one built on stale memory. turn() gets the order right by construction; call ingest() and recall() yourself only when you have a reason to.

Errors

Everything raised is a StateJarError:

from statejar import (StateJar, StateJarError,
                      StateJarAuthError, StateJarConnectionError)

try:
    turn = sj.turn("hi")
except StateJarAuthError:        # HTTP 401 — bad/revoked key
    ...
except StateJarConnectionError:  # unreachable host or timeout — nothing was
    ...                          # stored, so retrying ingest is safe
except StateJarError as e:       # anything else; e.status_code, e.body
    print(e.status_code, e.body)  # (decoded JSON or text) and e.response_text

A missing api_key raises at construction as a StateJarAuthError that is also a ValueError, so code written against either earlier client still catches it.

Pointing at a local instance

sj = StateJar(api_key="sj_live_...", base_url="http://localhost:8000/api/v1")

Development

cd sdk && pip install -e ".[dev]" && pytest     # ".[test]" is the same set

The tests mock HTTP with respx at the httpx client seam — no network, no server needed.

Copyright (c) 2026 StateJar. All rights reserved. The StateJar service implements the method described in Indian patent application No. 202621017626 (filed and published, not granted); see section 3 of LICENSE for the patent terms.

Metadata

Release files for statejar 0.5.0rc1

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

Source distribution (sdist)

Source distribution for statejar 0.5.0rc1
File Size Uploaded
statejar-0.5.0rc1.tar.gz 18.2 kB Details

Built distribution (wheel)

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

Total release size: 33.7 kB

Release files / statejar-0.5.0rc1.tar.gz

Download URL statejar-0.5.0rc1.tar.gz
Size 18.2 kB
Tags Source
SHA-256 checksum
How to use checksums
9f7fa2a9617c9b4b4d5c81aa13cd8d2b4464dca73f197b4be97505fd0f755409
BLAKE2b-256 checksum
How to use checksums
76f179b28d8d41be077f85212fa385d15dcc7f70fe969a0988286ccaebecaf48
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 Oct 6, 2026.

Transparency log

Release files / statejar-0.5.0rc1-py3-none-any.whl

Download URL statejar-0.5.0rc1-py3-none-any.whl
Size 15.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1d46ab29298f431bd453ecd9c25e4474cf2103c9515b94f6109ebab86b5f87bd
BLAKE2b-256 checksum
How to use checksums
17c966699c457bd898a7a257b6bc4b6f0c71b4c10dbef0217a4251cdcf49524d
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 Oct 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0rc1 This release

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