Skip to main content

Kenning Continuity

Enterprise knowledge that accumulates instead of degrading.

An MCP server that lets LLM agents accumulate organizational knowledge across sessions, scoped by domain, backed by Neo4j. Every structural invariant is enforced by a tool rather than asked for in an instruction, and no raw Cypher write is exposed — so the graph cannot corrupt itself no matter what the model decides to do.

It is in production at an enterprise scale: 37 domains, 376 sessions, and 3,000+ knowledge entities accumulated over four months of daily use.

Why this does not degrade as it fills

Most accumulating memory systems fail in one of two ways. They confabulate from the first day, because nothing distinguishes a thing that was observed from a thing that was inferred by a model trying to be helpful. Or they survive the demo and then degrade under mass, because every write is an unconstrained append and the store slowly fills with near-duplicates, silent overwrites, and claims nobody can trace to an author.

Four commitments, all enforced structurally:

Nothing is overwritten. There is no update_knowledge and no retype_knowledge. Changing what is known about an entity creates a new node linked to its predecessor by EVOLVED_FROM. The prior understanding is still there, still readable, still attributable. Being wrong earlier is a fact about the record, not something to be erased from it.

Every claim reaches its author in two hops. A knowledge entity is discovered by a Session; a Session is directed by a Person. Both edges are written by tools that refuse to run without a real director. So "who said this, and when, and toward what purpose" is always answerable — not by convention, but because there is no code path that creates knowledge without it.

Identity is never inferred from a string. Seventeen nodes named "Alice Example" across eleven domains are seventeen acts of reference, correctly distinct. Asserting that two of them are one person is a claim someone makes, in a session, recorded as a REFERENT_CLAIM that can carry the value distinct — because a system with nowhere to record the answer no will re-ask the same question forever. String-matching identity is where most knowledge graphs quietly begin lying.

Structure carries facts; properties do not duplicate them. A knowledge entity holds no domain property. It is placed in a domain by the session that discovered it and reached from there by a walk. The property that preceded this had drifted, which is what denormalizations do: 21 entities carried a domain string naming a real domain that had no path to them at all. A fact held as text beside a structure, rather than by it, is a fact that will disagree with the structure eventually.

There is no confidence field, deliberately. Someone's confidence on an occasion is a fact about their experience and does not transmit; a later reader derives their own from the description against what they know. What confidence scores reach for is carried instead by edges any reader can adjudicate: VALIDATION, INVALIDATING, and a Challenge with no paired Solution.

If you have run an accumulating memory system at scale and hit these walls yourself, we want to hear from you.

Architecture

Process layer (immutable) — Person → Session, within Domain → Session. NEXT_SESSION always points forward in time, enforced by the tool. Membership in this layer is the capacity to hold possible futures and measure them toward actualization; nothing here is a referent.

Knowledge layer (append-only) — 11 ontological types and 7 sub-labels, connected by 13 connection types, every node marked :Knowledge. Description changes create a new chain node linked by EVOLVED_FROM.

See HOWTO.xml for the operator-facing teaching to give an LLM as invariant scaffolding, and docs/design/ for the reasoning behind each commitment. HOWTO.xml is installed alongside the package, so a pip install reaches it at kenning_continuity/HOWTO.xml inside site-packages.

Prerequisites

  • Python 3.10+
  • Neo4j 5.x instance (local or remote)
  • uv (for development; not needed to install)

Quick start

pip install kenning-continuity

kenning-continuity --db-url bolt://localhost:7687

Or from source:

uv sync
uv run kenning-continuity --db-url bolt://localhost:7687

Configuration

CLI flags take precedence over environment variables, which take precedence over defaults.

CLI flag Env var Default Description
--db-url NEO4J_URI or NEO4J_URL bolt://localhost:7687 Neo4j connection URL
--username NEO4J_USERNAME neo4j Neo4j username
--password NEO4J_PASSWORD password Neo4j password
--database NEO4J_DATABASE neo4j Neo4j database name
--transport NEO4J_TRANSPORT stdio stdio, sse, or streamable-http
--namespace NEO4J_NAMESPACE (none) Tool name prefix (e.g. myappmyapp-begin_session)
--read-timeout NEO4J_READ_TIMEOUT 30 Read query timeout, seconds
--server-host NEO4J_MCP_SERVER_HOST 127.0.0.1 HTTP host (non-stdio transports)
--server-port NEO4J_MCP_SERVER_PORT 8000 HTTP port (non-stdio transports)
--server-path NEO4J_MCP_SERVER_PATH /mcp/ HTTP path (non-stdio transports)
--allow-origins NEO4J_MCP_SERVER_ALLOW_ORIGINS (none) Comma-separated CORS origins
--allowed-hosts NEO4J_MCP_SERVER_ALLOWED_HOSTS (none) Comma-separated hosts, DNS-rebinding protection

MCP client configuration

Claude Desktop / Claude Code

{
  "mcpServers": {
    "temporal-knowledge": {
      "command": "kenning-continuity",
      "args": ["--db-url", "bolt://localhost:7687"]
    }
  }
}

HTTP transport

kenning-continuity \
  --db-url bolt://localhost:7687 \
  --transport streamable-http \
  --server-host 0.0.0.0 \
  --server-port 8000 \
  --allow-origins "http://localhost:3000" \
  --allowed-hosts "localhost,127.0.0.1"

Tool surface (23 tools)

A session runs: create_domain (once) → begin_session → create / evolve / confirm / connect knowledge → end_session.

The server is stateless. begin_session returns a session_id that the client passes to every subsequent knowledge tool. A session never closed stays active — by design.

Process (4)

Tool Description
list_domains All domains with session counts and last activity
create_domain Create a knowledge domain (idempotent)
begin_session Start a session; returns session_id. domain, purpose, director and director_key are all required — the director's Person node is created here and nowhere else
end_session Close a session with a summary of what was learned

begin_session returns a count by type, not the domain state. Returning the state inline was 600,820 characters on one production domain — roughly 150k tokens spent before the session had asked a question. Call get_domain_state with types and limit for the part you actually need.

Knowledge mutation (6)

Tool Description
create_knowledge Create entities. Refuses on collision, refuses process types, and refuses unknown fields rather than dropping them
evolve_knowledge The only way to change a description. Creates a new chain node preserving the prior one via EVOLVED_FROM; keeps the ontological type, replaces the sub-label set
confirm_knowledge Record that entities were reviewed and found unchanged
merge_knowledge Compact an EVOLVED_FROM chain into one canonical node. Destructive — cannot be undone
create_connections Link entities. Takes a session_id and records it on every edge — an edge is an assertion and reaches its author
claim_referent Claim two referents are the same thing, with a required resolution: proposed, confirmed, or distinct

Query (5)

Tool Description
search_knowledge Fulltext across names and descriptions, head-of-chain only
get_domain_state Current entities for a domain; optional types, limit, descriptions
get_session_history Who worked on what, when, and toward what purpose
get_chain_history Walk EVOLVED_FROM backward — what was previously understood
read_cypher Read-only Cypher escape hatch; writes are rejected

Taxonomy (2)

Tool Description
list_knowledge_types 11 ontological types and 7 sub-labels, with the lattice
list_connection_types 13 knowledge and 5 process edge types

Graph analytics (6)

Tool Description
gds_create_projection Create a GDS graph projection
gds_drop_projection Drop a projection
gds_pagerank PageRank centrality
gds_betweenness Betweenness centrality — bridge nodes
gds_louvain Louvain community detection
gds_wcc Weakly connected components

Type system

Every knowledge node carries :Knowledge, exactly one ontological label, an ont_type property naming that label deterministically, and zero or more sub-labels via Neo4j multi-labeling.

Ontological type What it is
Actor That which acts; has agency
Structure Arrangement without agency; persistent shape
Artifact Produced thing that persists and can be referenced
Place A site, campus, region or extent — always a referent, never a referrer
Event Temporally-located happening
Insight A realization, discovery, breakthrough
Pattern Recurring structure recognized across instances
Challenge Present-tense obstacle
Solution Resolution that worked; pairs with Challenge
Lesson Rule derived from experience
Rationale The reason behind something

Sub-labels are a lattice, not a flat map

PersonReferent → Actor          System        → Structure
Organization   → Actor          Process       → Structure
Team           → Organization → Actor         Configuration → Structure
                                              Service       → Structure

create_knowledge accepts either an ontological type (Actor) or a sub-label (Team), and applies the whole chain: :Knowledge:Actor:Organization:Team. A query for organizations therefore finds teams. A flat map would emit :Actor:Team, silently dropping the middle level, and nothing would report it.

Connection types (13)

EVOLVED_FROM, ENABLING, REQUIRING, INFORMING, CAUSING, COMPOSING, EXTENDING, RECOGNITION, VALIDATION, INVALIDATING, ASSOCIATED_WITH, SITUATED_AT, REFERENT_CLAIM.

Process edges — HAS_SESSION, NEXT_SESSION, DIRECTED, DISCOVERED, CONFIRMED — are written only by process tools and cannot be created through create_connections.

What a description should say

A description says what the entity is, not what happened to or around it. Temporal observations belong on Event nodes reached by edges.

  • Correct, for an Actor:PersonReferent: "Founder of Example Corp. Largest individual shareholder (8.4%). Filed under Schedule 13D — not passive."
  • Wrong: "SCHEDULE 13D/A Amendment No. 10 filed Oct 8, 2025. FOUNDER GOES PUBLIC…"

The filing is an Event. Alice Example is the founder. The filing revealing something about them is an INFORMING edge. Their description should survive any number of future filings unchanged, unless their identity itself changes.

Development

uv sync --group dev

./.venv/bin/pytest tests/unit          # mocked substrate, no database
./.venv/bin/pytest tests/integration   # real Neo4j via testcontainers; needs Docker
./.venv/bin/pyright

A defect that lives in a Cypher query is invisible to the unit tests — they mock the substrate, and an edge-fabrication bug once passed every one of them identically before and after the fix. Anything touching a query belongs in tests/integration/.

License and attribution

Licensed under the Apache License, Version 2.0. Use it, modify it, run it in production, commercially or otherwise.

The work here is the ontology — the type lattice, the resolution-by-walk, the placement of epistemic standing in edges, the principle that every invariant lives in a tool. That is given away freely, and Apache-2.0 asks only that attribution travel with it: keep LICENSE and NOTICE, and mark what you changed.

The Kenning AI name is not part of that grant (Apache-2.0 §6). See TRADEMARKS.md for what you may do without asking — which is nearly everything, including saying what your software is built on.

Contact

contact@kenningai.com — no form, no funnel, it reaches us directly.

We are especially interested in hearing from anyone who has run an accumulating memory system at scale and formed a view on why they fail. That failure mode is the reason for nearly every decision in this repository, and disagreement from someone who has hit it themselves is worth more to us than agreement from anyone who hasn't.


Kenning AI · kenningai.com

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kenning_continuity-0.1.2.tar.gz (96.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kenning_continuity-0.1.2-py3-none-any.whl (72.6 kB view details)

Uploaded Python 3

File details

Details for the file kenning_continuity-0.1.2.tar.gz.

File metadata

  • Download URL: kenning_continuity-0.1.2.tar.gz
  • Upload date:
  • Size: 96.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for kenning_continuity-0.1.2.tar.gz
Algorithm Hash digest
SHA256 9e02f3074e719cf3836ca15b4c3b6cf426a7e6bd07c6c4059035f15a25c4b57e
MD5 ca6076f3c330ad3f055022153b018d46
BLAKE2b-256 66a3fa8044d19ddd5f5dc2e529514e6e0be56f00731db1f6ec932c07fb602936

See more details on using hashes here.

File details

Details for the file kenning_continuity-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: kenning_continuity-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 72.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for kenning_continuity-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 5768c0d9fcab4129d37281846641113349d159422137195bcfc5cba8ff09aaa4
MD5 daf1dc7be8b6743bee1d8d6a972c1bb4
BLAKE2b-256 057d727b581fcb7487309bb18f269e47412ea571ceaca9c5c8439e7c055b91a4

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 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