Skip to main content

cilow — Python

The Python client for Cilow, the verifiable context layer for AI agents. Point it at a running cilow-serve and call four core verbs — ingest, context_pack, forget, explain — the same four the MCP core profile advertises. The headline feature is calibrated deferral: every read tells you when the engine doesn't know instead of fabricating an answer.

Install

cd sdk/python && pip install -e .

Python 3.9+. Zero required dependencies — the client uses only the standard library (urllib + json). httpx is an optional extra (pip install 'cilow[httpx]') for users who want pooling/async; it is not needed for the default client.

Point it at a server

cargo build --profile fast --features serve --bin cilow-serve
CILOW_DB=/tmp/cilow.log CILOW_TOKENS="demo:1:1" ./target/fast/cilow-serve
# listening on http://0.0.0.0:8080  ·  bearer token "demo"

The token maps to a tenant scope that the server stamps onto every request — a client can never read another tenant's memory, and a client-supplied scope is ignored over HTTP.

Five lines

from cilow import CilowClient

cilow = CilowClient(base_url="http://localhost:8080", token="demo")
cilow.ingest(facts=[{"subject": "Maya", "predicate": "employer", "object": "Acme"}])
r = cilow.context_pack("where does Maya work", anchor="Maya", attribute="employer")
print(r.reason if r.abstained else r.pack)      # the injectible pack, citations on r.citations
print(cilow.explain(r.trace_id).report.grounded)  # why it surfaced, vs the tenant threshold

The four core verbs

Verb Signature Returns What it does
ingest ingest(*, facts= | text= | url= | content_base64=, mime=, subject_hint=, metadata=, source=, raw_context=, branch=, scope=, source_id=, observed_at=) IngestResponse The one write door. Never rejects: known kinds extract, unknown kinds are retained and recallable. A new value for an exclusive attribute supersedes the old one (history stays queryable).
context_pack context_pack(query, *, scope=, now=, as_of=, anchor=, attribute=) ContextPackResponse The product read: a ready-to-inject pack, structured citations / claims with is_current, and the faithfulness fields abstained / reason_code / grounding / pack_sufficient / as_of / trace_id. No free-form synthesis.
forget forget(entity, *, attribute=, value=, erase=, scope=, at=) ForgetResponse Withdraw, not erase history: recall stops returning it; as-of-T reads before at still see it. erase=True is the destructive right-to-be-forgotten path.
explain explain(trace_id, *, scope=) ExplainResponse Why a pack/recall surfaced what it surfaced: the cited claims (labels resolved, inclusion probability each), best_nonconformity vs the tenant threshold q_hat, and report.grounded. found=False + error is in-band.

Plus health() (liveness probe, no auth). All responses are frozen dataclasses.

ingest takes exactly one content form. source_id (the idempotency key the wire requires) defaults to a content hash — ingest_source_id(...) — so re-sending the same payload is a no-op; the key actually sent is echoed on .source_id. .kind tells you which server path ran ("facts" → the remember receipt on .remember; "content" → the raw-durable receipt on .content with blob_id / detected / reader_error).

anchor (an entity surface form like "Maya") + attribute (a predicate like "employer") take the exact-key fast path. Omit them for free-text semantic reads — same response shape.

Full profile / legacy aliases

The engine's full tool profile (CILOW_MCP_PROFILE=full) also advertises the older verbs, and the client keeps them as aliases with their original receipts:

Alias Signature Returns
remember remember(facts, *, scope=, source=, source_id=, observed_at=, raw_context=, branch=) RememberResponse
recall recall(query, *, scope=, as_of=, now=, anchor=, attribute=, branch=) RecallResponse
answer answer(query, *, scope=, now=, anchor=, attribute=, branch=) AnswerResponse
timeline timeline(entity, *, scope=, at=, t_from=, t_to=) list[TimelineEntry]
track_entity track_entity(name, *, scope=, at=) TrackEntityResponse

Also available: remember_text, ingest_image / ingest_audio / ingest_pdf / ingest_structured, save / ingest_any, feedback, consolidate, fork / branch_list, blob_get / blob_meta / blob_list, and the client.memories.* id-based REST surface.

Time is in microseconds

Every time field (observed_at, as_of, now, at, t_from, t_to, and the valid_from / valid_until on timeline entries) is epoch microseconds (µs), matching the engine. They default to "now". Use the exported now_micros() helper:

from cilow import now_micros
t = now_micros()
cilow.remember(facts, observed_at=t)
past = cilow.recall("...", as_of=t - 86_400_000_000, now=t)  # a day ago

The deferral contract

context_pack (and the recall / answer aliases) never raise for a deferral — they return a normal response with a boolean flag. When abstained is True, the pack / claims / citations are empty and reason_code says why: below_threshold / no_candidates are a calibrated abstain (memory genuinely lacks grounded context — do not fabricate past it), while provider_unavailable is an infrastructure abstain (retry when the provider recovers). Branch with r.is_calibrated_abstain / r.is_infrastructure_abstain rather than matching strings.

On answer / context_pack an abstain also names which layer stopped it — r.terminal_layer (structural | gate | provider | reader | verifier; r.stopped_at is the same thing gated on abstained). Only provider is retryable. Both surfaces also carry r.evidence: the claim, span, and verbatim lanes collapsed into one list ordered by fused cross-lane rank (Evidence.origins says which lanes agreed; Evidence.structure is present when a typed claim backs the unit). It is present on abstains too — the raw lanes have no standing at the gate, but you may still read them.

r = cilow.context_pack("what is Maya's salary", anchor="Maya", attribute="salary")
if r.abstained:
    # r.pack is empty; r.reason explains the configured gate decision.
    return f"I don't have that in memory ({r.reason})."
return r.pack

Every read carries a trace_id. Hand it to explain for the audit trail — the cited claims, the tenant's conformal threshold q_hat, the best candidate's best_nonconformity, and the margin (q̂ − n, ≥0 grounded, <0 a gap) — or to feedback so memory learns from the outcome. This is the difference between "I don't know" and a confident wrong answer.

Errors

CilowError is raised for genuine failures — auth (401 / JSON-RPC -32001), bad params, transport errors, malformed responses. A deferral is not an error.

from cilow import CilowError
try:
    cilow.recall("...")
except CilowError as e:
    if e.is_unauthorized:  # bad/expired token
        ...

Develop

pip install -e .
python3 -m pytest -q tests             # mocks the HTTP layer (no server needed)
python examples/quickstart.py          # runs against a live server

Metadata

Release files for cilow 0.1.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 cilow 0.1.0
File Size Uploaded Provenance Actions
cilow-0.1.0.tar.gz 53.6 kB Without provenance Details for cilow-0.1.0.tar.gz

Built distribution (wheel)

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

Total release size: 96.7 kB

Release files / cilow-0.1.0.tar.gz

Download URL cilow-0.1.0.tar.gz
Size 53.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9ceda263601355e655f224d59deaf0f944ea36f08593feb8d4a7ffd761f83a29
BLAKE2b-256 checksum
How to use checksums
070ef597c06367db600be6f82482643fe555386c46af776af0b27d646f448a35
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Release files / cilow-0.1.0-py3-none-any.whl

Download URL cilow-0.1.0-py3-none-any.whl
Size 43.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ef9015fa19586dd681a9f6c64da5812631089ce589f66cd5d1cca444bacb0dd9
BLAKE2b-256 checksum
How to use checksums
820b449570319ba32147d82b37c0d4d08a0ed355be634672a8215ddf472582c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Security for cilow 0.1.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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