Kognita
Prove an AI action was permitted, and evidence it.
Content guardrails check what an AI says. Kognita decides whether the agent was allowed to ask, before any data is retrieved, and writes a tamper-evident record of the decision and the rule behind it.
Your agent pulls a client's portfolio, summarises it, and sends it to a model API. Was it allowed to? With Kognita, that question has an answer you can show a regulator: which rule permitted it, which rules would have stopped it, and proof that the record hasn't been edited since.
from datetime import datetime, timezone
from sqlmodel import Session
from kognita import Envelope, Policy, decide, load_snapshot
from kognita.db import create_all, make_engine
engine = make_engine()
create_all(engine)
start = datetime(2026, 1, 1, tzinfo=timezone.utc)
with Session(engine) as session:
session.add_all([
Policy(regime="BOOKING_CENTRE", rule_type="ATTRIBUTE_ALLOWLIST",
rule={"allow": {"actor_location": ["SG"]}},
citation="Cross-border manual s3.2: SG-booked clients served from SG",
effective_from=start),
Policy(regime="INVESTOR_STATUS", rule_type="REQUIRES_FLAG",
rule={"flags": ["accredited_investor"]},
citation="Product governance policy s7: complex products",
effective_from=start),
])
session.commit()
evaluation = decide(
Envelope(principal="rm@bank.example", purpose="PRODUCT_DISCUSSION",
tool="discuss_product", actor_location="HK",
subject_type="client", subject_id="123"),
load_snapshot(session),
attributes={"actor_location": "HK", "accredited_investor": False},
purposes=["PRODUCT_DISCUSSION"],
)
print(evaluation.outcome.value)
for check in evaluation.basis():
print(f"{check.regime:16} {check.citation}")
DENY
BOOKING_CENTRE Cross-border manual s3.2: SG-booked clients served from SG
INVESTOR_STATUS Product governance policy s7: complex products
Two independent rules refused. Neither masked the other, each names its source, and nothing was retrieved. The policy names and citations above are illustrative; in a real deployment they come from your own policy set.
Install
pip install kognita
The core depends on four packages (pydantic, sqlmodel, numpy, python-dotenv) and runs with no network and no API key. Deciding whether a request is permitted should not require the machinery that answers it. import-linter contracts and a no-extras install test keep it that way.
Optional extras add provider-backed embedders (kognita[openai]), a SQLite vector index (kognita[vec]), local embeddings (kognita[local-embeddings]) and a knowledge-graph engine (kognita[graph], see below).
What it does today
Authorise before discovery. An agent's intent is described as an envelope (who, for what purpose, with which tool, about which subject, from where) and evaluated before anything is fetched. A denial returns no data, not filtered data.
Fail closed. Outcomes resolve as DENY > ESCALATE > HUMAN_APPROVAL > ALLOW. One failing check among a hundred passes still denies, so a policy set cannot be widened by adding permissive rules. A policy whose rule type has no evaluator escalates rather than being skipped.
Every decision cites its rule. Each check carries the regime and citation it came from. A check without a citation is an assertion, not a decision, and the conformance kit enforces it.
Agents are registered, and can be stopped. An agent that is not in the registry is denied. Each registered agent carries a version, an accountable owner and a materiality tier, and has a kill switch that denies its next request:
DENY Kill switch engaged — accountable owner: Head of Wealth Advisory
DENY Agent inventory — 'AGENT-UNKNOWN' is not registered
Decisions are pure and replayable. decide() writes nothing and takes the instant as a parameter. Policies are effective-dated rows, so "what would this have decided in March?" has an answer:
decide(envelope, load_snapshot(session, as_of=march), as_of=march, ...)
Evidence is tamper-evident. Each event carries the previous event's hash, so altering any payload breaks every hash after it:
$ kognita evidence verify --db store.db
BROKEN: evidence chain broken at sequence 2: payload does not match its hash
$ kognita evidence export --db store.db -o audit.json # portable, self-verifying
$ kognita evidence reconstruct <interaction_id> --db store.db -o report
# writes report.json and report.txt
Payloads hold hashes and references by default, because an append-only log full of personal data collides with erasure rights.
Humans approve what they actually reviewed. Through run_governed(), a HUMAN_APPROVAL decision holds the tool until approval is granted. Approvals bind to a hash of the envelope, attributes and checks, so an approval for one request cannot be replayed for a different one. Two-signature approval, where one person marks and a different person confirms, is built in.
Egress is guarded, not merely refused. The egress guard decides per classification and destination whether content may leave, must be redacted, or may not leave at all:
from kognita import Classification
from kognita.egress import EgressGuard, PatternRedactor
guard = EgressGuard(redactor=PatternRedactor(extra_terms=["Jane Tan"]))
result = guard.send("Jane Tan (jane.tan@example.com) holds account SG-PB-004417",
call_the_model, classification=Classification.C2,
destination="api.openai.com", destination_is_local=False)
result.decision # REDACT
# the provider saw: [TERM_1] ([EMAIL_1]) holds account [ACCOUNT_1]
# the caller got the real values back; evidence records the redaction
# manifest hash, never the content
PatternRedactoris a floor, not a guarantee. It catches the patterns it knows (emails, IBANs, card numbers, phone numbers and similar) plus terms you list, and it misses names in prose that you didn't list. Deployments handling real personal data should supply an NER-basedRedactor. The tests cover the plumbing, that nothing unredacted escapes the guard, not detection recall.
Governed tools and questions. run_governed() is the only path to a registered tool: decide, record, and only then execute, with tool-call and egress evidence. ask() answers a question from entitled, cited sources only, and when it refuses, the basis for refusing is the answer.
Continuous Learning and Drift
Kognita is designed to capture not just permissions but outcomes, so agents and workflows improve over time:
Outcome metrics per use case. Each workflow registers one primary metric (cycle time, decision quality, reliability) with a baseline and target. Kognita computes these from the evidence it records: how long from trigger to final decision, RM edit and rejection rates, exception handling. A Knowledge Lead owns the quality standard and approves improvements to it.
Autonomy earns its expansion. Raising an agent's autonomy level requires evidence thresholds on those metrics. An agent that maintains quality ≥ 95%, exceptions < 5% and full traceability can move to the next level; if metrics degrade, it steps back automatically. Quality is tracked as trends per agent and model version, so gradual drift is caught before a hard breach.
Institutional memory. A pattern in RM corrections or outcomes becomes a proposed change to the shared standard. The Knowledge Lead approves it; it becomes a new dated version. Each output records which version produced it, so learning is versioned and reproducible, never edited in place.
These close the loop: every correction and outcome feeds back into the next decision, so one RM's lesson improves all subsequent RMs' guidance.
Domain packs
The core is domain-blind. A pack supplies what it cannot know: what a request's attributes are, and how to load the subjects it refers to.
class MyPack:
name = "my-domain"
def load_subjects(self, envelope, session): ...
def resolve_attributes(self, envelope, subjects): ...
def rules(self): return build_registry(MY_EVALUATORS)
Policies are data: effective-dated rows with a JSON payload, interpreted by the evaluator registered for their rule_type. The core ships six primitives (allowlist, denylist, required flag, required human approval, two-signature approval, prohibited); a pack registers whatever its regimes need beyond them.
Conformance
The conformance kit is a set of assertions every domain pack must satisfy: whatever a pack's rules say, they are decided fail-closed, cited and evidenced.
pytest --pyargs kognita.testing.conformance # the kit against its bundled pack
from kognita.testing import ConformanceCase, Harness
class TestMyPack(ConformanceCase):
@pytest.fixture(autouse=True)
def _bind(self):
self.harness = Harness(pack=MyPack(), purposes=PURPOSES, seed=seed)
self.allow_envelope = Envelope(...)
self.deny_envelope = Envelope(...)
The invariants are importable, so external packs run them in their own repositories.
Known limitations
Kognita is alpha. These are known gaps in v0.2, each scheduled on the roadmap:
- The purpose check fails open when no purpose list is configured. Pass
purposes=explicitly until it fails closed. - Agent names are self-asserted. The registry denies unknown names, but nothing yet authenticates that a caller is the agent it claims to be. A request with no agent name skips the registry and is treated as a human.
- Reconstruction covers what 0.3 records.
kognita evidence reconstructanswers from pinned evidence and the retention store. Why this client, why this insight or product, what the RM saw and changed, who made the final decision, and what was communicated to the client are present and marked "not recorded" until the client-lifecycle records exist. - Gateway degraded mode is not implemented. If the evidence store is down the gateway refuses the call. A degraded path for local models is still open.
Where it's heading
The direction is supervisory examinability: a regulator should be able to pick one AI-assisted client interaction and reconstruct it from evidence alone. Why this client, why this product, what data the AI used, which model produced it, what the agent was authorised to do, which controls ran, what the human saw and changed, who decided, what the client was told, and whether all of that can be reproduced later.
The test every release is measured against:
Can the bank explain, control, stop and reconstruct every material AI action that affects a client?
Planned, not yet built:
- 0.3 still open: degraded gateway mode, and the remaining Tier 0 defects. The gateway, the MCP proxy, run budgets, suspend and resume, pinned evidence, and
kognita evidence reconstructare already in the tree. - 0.4: Ingestion, policy language and the client lifecycle. Passage-level citations, a YAML policy language with diff and validation, a use-case register, risk-based review, a circuit breaker.
- 0.5: Agents, authority and fleets. Authenticated agent identity, delegated authority, autonomy levels, evidence-gated promotion and automatic step-down on drift, blast-radius limits, containment.
- 0.6: Claims and institutional memory. Typed, sourced, current claims checked before an RM relies on them; approved-source grounding; supervised memory that turns lessons into shared standards; governed business definitions.
- 0.7: Trust and resilience. Signed evidence, external verification, provider and dependency registers.
The full plan is in docs/ROADMAP.md. How it maps to bank control frameworks for agentic AI is in docs/control-frameworks.md, which consolidates a 40-domain bank-grade framework and a 70-control wealth management framework, plus the EVOLVE framework's learning loop and institutional memory.
The design rule behind all of it: never rely on the LLM to enforce a control that can be enforced outside the LLM.
Optional: knowledge graph
kognita[graph] adds a Graphiti and Kuzu engine that turns documents into a bi-temporal knowledge graph:
from kognita.graph import GraphEngine, GraphConfig
async with GraphEngine(config) as kg:
await kg.ingest_text(document, source="policy-handbook")
hits = await kg.search("cross-border disclosure")
Its future is under review. It currently pins graphiti-core and caps openai below version 2, and the roadmap favours moving it to a separate package with structured document ingestion as the primary retrieval path. See docs/decisions/0001-kuzu-cotenancy.md for its design.
Layout
kognita the decision engine: decisions, evidence, approvals,
retrieval, egress, tools. Four dependencies, no network.
kognita.testing the conformance kit
kognita.adapters provider-backed embedders and clients [openai] …
kognita.graph Graphiti + Kuzu knowledge engine [graph]
import kognita never loads a graph database or a provider SDK, and tests/test_packaging.py asserts it.
Moved in 0.2.
kognita.Kognita→kognita.graph.GraphEngine,kognita.KognitaConfig→kognita.graph.GraphConfig,kognita.core.*→kognita.*. Touching a retired name raises anAttributeErrornaming its new home. Details: docs/decisions/0003-the-top-level-namespace.md.
Status
Alpha. v0.3.0 is on PyPI. See the changelog for what changed and CONTRIBUTING.md to get involved.
MIT licensed.
Metadata
Release files for kognita 0.3.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 | Provenance | Actions |
|---|---|---|---|---|
| kognita-0.3.0.tar.gz | 598.0 kB | With provenance | Details for kognita-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| kognita-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for kognita-0.3.0-py3-none-any.whl |
Total release size: 739.2 kB
Release files / kognita-0.3.0.tar.gz
| Download URL | kognita-0.3.0.tar.gz |
|---|---|
| Size | 598.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b9105dc41e0bdf93b2760382f341ba2f6791712571f81c26b02e09423b585026
|
|
BLAKE2b-256 checksum How to use checksums |
af7c72a11e9e52e4476be1c85bbe11260bcd8fd50d863361fcc100f74d8872ee
|
| 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 5, 2026.
Transparency logRelease files / kognita-0.3.0-py3-none-any.whl
| Download URL | kognita-0.3.0-py3-none-any.whl |
|---|---|
| Size | 141.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e157019a33ba4a454da66bc1a32f104f46961a7833418bb547adeaf316d1720d
|
|
BLAKE2b-256 checksum How to use checksums |
55af3724ea66ac778e474c6a5c9c6be84c1a0ae2ee381ab422f7a14b48ae3899
|
| 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 5, 2026.
Transparency logSecurity for kognita 0.3.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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for kognita-0.3.0.tar.gz
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 5, 2026.
Transparency logA 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.