Pure ECS agent framework: event-sourced via Redis Streams, semantic routing via GLiNER2, tool re-use via the Solution tier (ADR-010). Sub-package `agents` ships concrete LLM/cache/PII adapters over the framework.
Project description
kntgraph
A pure, event-sourced agent framework over Redis Streams.
Quality gates
The badges below mirror the nine gates in
scripts/ci.py — the single source of
truth for the project's quality bar. Each badge is a
Shields.io static image; the
values are pinned in docs/quality.md
(auto-generated by scripts/quality_report.py).
The current value of each badge is generated locally by
scripts/quality_report.py; the script reads each gate's output and updatesdocs/quality.mdon every CI run. Keep the snapshot in sync with this block when you remove badges or change the gate count.
A full breakdown of the current technical debt is in
DEBT.md. All pyright errors are resolved
(0 errors / 1043 warnings; the warning budget is
tracked separately under §4.2 and is out of scope for
the strict error budget).
kntgraph is the renamed and unified successor of
two internal packages (formerly fmh_backend and
fmh_agents). It provides the core abstractions
needed to build autonomous, replayable agents:
- Pure ECS —
Worldis a deterministic function of events. - Event Sourcing — Redis Streams is the single source of truth.
- Idempotency — replay produces the same
World;
idempotency_keyonToolmakes at-least-once delivery into at-most-once side effects. - Dual lifecycle — operational (framework) and
domain (application) lifecycles are orthogonal;
the same
Worldcarries both views. - Resilience — circuit breaker, retry, bulkhead, timeout, fallback, and a Dead Letter Queue for failed events.
- Durable checkpoints — the
ReactiveDispatchercommits a Redis checkpoint after the batch's emitted events are durably appended to the EventLog, so a crash between append and save replays the same events on restart (idempotency window). - Solution tier (ADR-010) — tool-call
re-use: when a tool call succeeds for a given
(problem, params)pair across multiple agents, the framework promotes the call into a reusable Solution node in FalkorDB, with per-tenant allow-list and man-in-the-loop review. - Semantic routing (ADR-013) — opt-in GLiNER2
intent classification and argument extraction
in the
agentssub-module.
Install
Currently, kntgraph is not published to PyPI. You can install it directly from GitHub:
uv add git+https://github.com/kinetgraph/kinetgraph.git
Optional extras (install only what you need):
uv add "kntgraph[cli]@git+https://github.com/kinetgraph/kinetgraph.git" # CLI Boilerplate Generator (ADR-038)
uv add "kntgraph[falkordb]@git+https://github.com/kinetgraph/kinetgraph.git" # graph projection + Cypher
uv add "kntgraph[ollama]@git+https://github.com/kinetgraph/kinetgraph.git" # local LLM / embeddings
uv add "kntgraph[gliner]@git+https://github.com/kinetgraph/kinetgraph.git" # NER-based PII redaction
uv add "kntgraph[api]@git+https://github.com/kinetgraph/kinetgraph.git" # HTTP gateway (FastAPI)
uv add "kntgraph[crypto]@git+https://github.com/kinetgraph/kinetgraph.git" # Ed25519 event signing
uv add "kntgraph[llm]@git+https://github.com/kinetgraph/kinetgraph.git" # LiteLLM adapter
uv add "kntgraph[all-runtime]@git+https://github.com/kinetgraph/kinetgraph.git" # everything above
Hello world
import asyncio
from kntgraph.core.event import Event
from kntgraph.core.world import World
async def main() -> None:
e1 = Event.create(
event_type="agent.spawned",
agent_id="a-1",
event_class="lifecycle",
)
e2 = Event.create(
event_type="document.received",
agent_id="a-1",
event_class="domain",
data={"doc_id": "NF-001"},
)
world = World.fold([e1, e2], tick=2)
print(world.agents["a-1"].operational_phase) # "spawned"
print(world.agents["a-1"].domain_phase) # "document.received"
asyncio.run(main())
The agents sub-module ships concrete LLM, cache,
and PII adapters on top of the framework:
from kntgraph.agents.tools import LiteLLMToolWorker
worker = LiteLLMToolWorker()
result = await worker.invoke(
system="You are a helpful assistant.",
user="What is the capital of France?",
idempotency_key="k1",
)
# ``result`` is a ``Result[dict, ToolError]``; the dict
# envelope carries ``text`` / ``model`` / ``usage`` /
# ``finish_reason`` / ``cost_usd`` / ``latency_ms``.
Run the tests
# Unit (fast, no Redis required)
uv run --package kntgraph pytest kntgraph/tests/unit/
# Integration (requires Redis on localhost:6379)
uv run --package kntgraph pytest kntgraph/tests/integration/
CLI Boilerplate Generator
Kinetgraph provides a first-party CLI (knt) to scaffold complete, ADR-compliant Modular Monoliths and Contexts.
Install the framework with the [cli] extra and initialize a new project:
# 1. Install Kinetgraph with the CLI extra globally or in your venv
uv pip install "kntgraph[cli]@git+https://github.com/kinetgraph/kinetgraph.git"
# 2. Scaffold a new application with the HTTP Gateway included
knt init project my_platform --use-intent-http
# or generate an intent-routing scaffold with an explicit mode
knt init project my_platform --routing-mode external
# supported values: external, autonomous, collaborate
# external: routes intents from outside the agent boundary
# autonomous: lets the agent resolve intents internally
# collaborate: coordinates multiple agents or roles for a shared intent
# 3. Enter the project and scaffold domain contexts
cd my_platform
knt new context weather
knt new system weather.WeatherRouter
knt new tool weather.OpenMeteoApi
For a comprehensive walkthrough on building an application from scratch using the CLI, refer to the CLI Guide.
Architecture
kntgraph/
├── src/kntgraph/
│ ├── core/ # Pure: ECS, Event, World, System
│ ├── stream/ # Redis Streams (EventLog, fold)
│ ├── runner/ # Side effects (Runner, ReactiveDispatcher)
│ ├── events/ # Dead Letter Queue
│ ├── resilience/ # Circuit breaker, retry, bulkhead, etc.
│ ├── infra/ # Config, Redis pool, hashing
│ ├── tools/ # Tool Protocol, registry, worker
│ ├── api/ # Optional HTTP gateway
│ ├── security/ # Ed25519 signing, principal, ACL
│ └── agents/ # LLM/cache/PII adapters, role_systems
│ ├── role_systems/ # ChatRoleSystem, PlannerRoleSystem, etc.
│ ├── tools/ # LiteLLMToolWorker, PiiRedactionTool
│ └── memory/ # Solution extractor/promoter
├── tests/
│ ├── unit/ # No external dependencies
│ ├── integration/ # Real Redis required
│ └── agents/ # agents sub-module tests
├── ADRs/ # Architecture Decision Records
├── docs/ # Public documentation
└── examples/ # Runnable end-to-end examples
Configuration
All settings live under the FMH_ env-var prefix
and are loaded via Pydantic v2 BaseSettings. The
canonical schema is Settings in
kntgraph.infra.config. Highlights:
| Env var | Default |
|---|---|
FMH_REDIS_URL |
redis://localhost:6379 |
FMH_FALKORDB_HOST |
localhost |
FMH_FALKORDB_PORT |
16379 |
FMH_STREAM_MAXLEN |
100_000 |
FMH_TICK_INTERVAL |
1.0 (seconds) |
FMH_ENV |
dev (set to prod in deploy) |
Documentation
- Getting Started — mental model and your first agent.
- Quick Start — 5-minute install and "hello world".
- Architecture — the three pillars (ECS, event sourcing, resilience) and how the pieces fit together.
- Zero Token Architecture — software handlers before LLM, read-side cache, hybrid dispatcher stack (ADR-049).
- API Reference — the public API map, env-var table, and common patterns.
- CLI Guide — walkthrough on scaffolding projects, contexts, systems, tools, and agents with the CLI.
- docs/ — full index of the docs.
- ADRs — Architecture Decision Records.
ADRs Accepted in v0.8.0 / v0.9.0 (closed in this cycle)
| ADR | Título | Status |
|---|---|---|
| ADR-042 | Memory Model Exposure in ECS Pattern (Systems vs. Tools) and CLI Support | Accepted (Implemented; CLI follow-up outstanding) |
| ADR-043 | LiteLLM worker migration + ToolInvoker deprecation | Accepted (Implemented; surpassed removal target) |
| ADR-044 | Tool-call Overlay Accumulation (slot persistence across ticks) | Accepted (Implemented) |
| ADR-046 | CLI Scaffold for Intent Routing Modes | Accepted (Implemented) |
| ADR-047 | Standardizing Tool Construction via Adapters | Draft (sync ToolWorker stable; §6 follow-ups open) |
ADRs Proposed in discussion
| ADR | Título | Status |
|---|---|---|
| ADR-035 | Sharding and Dispatcher Coordination for Horizontal Scaling | Proposed (Under Review) |
| ADR-040 | Messaging Adapter for Intent Ingestion | Proposed (Under Discussion) |
| ADR-048 | Observability Dashboard and Control Panel API | Proposed |
| ADR-049 | Zero Token Architecture support (RuleBasedChatSystem + SolutionLookupSystem) | Proposed (items 3 + 4 shipped in v0.10.0; Redis adapter shipped; FalkorDB adapter §6 still pending) |
| ADR-050 | CLI command consistency (sub-Typer, Typer Enum, template helper) | Accepted (v0.10.0) |
| ADR-051 | Release versioning via git tags + setuptools_scm |
Accepted (v0.10.0; PyPI publishing deferred to ADR-052) |
| ADR-052 | PyPI publishing via Trusted Publishing (PEP 740) | Proposed (workflow split: release.yml cuts the tag, publish.yml builds + uploads; 16 contract tests enforce the split) |
Project status
0.10.0— breaking: removes the_legacy_principalfallback in the API key verifier (ADR-017 §7.3). Plain-string bindings (pre-ADR-017) are now rejected asAuthError(kind="malformed", ...). Operators with legacy bindings MUST runscripts/migrate_principals.py --applybefore upgrading (the script is idempotent and safe to dry-run). The KNT_AUTH_MODE flag that ADR-017 §2.4 promised was never implemented; the wire-format detection inRedisAPIKeyVerifieris the only path that distinguished JSON from legacy, and that path is now closed. Adds Zero Token Architecture support (ADR-049):RuleBasedChatSystemshort-circuitsuser.intentevents with deterministic replies andSolutionLookupSystemsynthesises cachedtool.<name>.completedevents. The lookup system ships with twoSolutionStoreLikeadapters:InMemorySolutionStore(tests /09bexample) andRedisSolutionStore(production; one Hash per tool with the canonicalknt:solution:<tool_name>layout). Also fixes the dispatcher's drain contract so a synthetic completion queued byrun_pending_lookupsactually lands in the EventLog on the next tick. Seedocs/zta.md,examples/09b_solution_lookup_zta.py(in-memory) andexamples/09c_solution_lookup_zta_redis.py(Redis). Also adds release versioning via git tags (ADR-051): the project version is now derived from the git tag bysetuptools_scm(no morepyproject.toml::version); the new CI gatescheck_versionandbump_dry_runcatch drift before a release ships; theCONTRIBUTING.md::Release checklistis the 6-step ritual for cutting a release. Retroactive tags forv0.7.0,v0.8.0,v0.10.0are pushed sogit log v0.8.0..v0.10.0anduv syncwork today. PyPI publishing is deferred to ADR-052.0.9.0— predecessor release. Drops the legacyLiteLLMTool/ToolInvoker/kntgraph.agents.rolespaths (the canonical path isLiteLLMToolWorker+ theWorkerManager, and therole_systemsECS-shaped counterparts). Adds theHttpClientLikeProtocol and theHttpxHttpClientAdapterfor HTTP-boundToolWorkers(ADR-047). CLI tests ship aconftest.pyfor the optional[cli]extra (DEBT §2.25). CC refactor of 10 functions over the CC=10 ceiling (DEBT §2.26); thegate_complexityinscripts/ci.pynow flags new CC offenders that bypass the previous baseline-only check. Pyright errors down from 68 → 51 (17-error delta).0.7.0— public release under thekntgraphpackage name. Backwards-incompatible with the oldfmh_backend/fmh_agentsimports; the source is structurally the same (same modules, same tests).0.6.x— internal releases under thefmh_*package names (no longer distributed).
License
Apache License 2.0. See LICENSE.
Contributing
See CONTRIBUTING.md for development setup, the gate that runs in CI, and the pull request workflow. Bug reports and security disclosures follow SECURITY.md.
Project metrics
| Source modules | Test modules | ADRs | Docs |
|---|---|---|---|
| 243 (39,199 LOC) | 190 (42,076 LOC, 1,968 tests collected) | 51 | 24 pages |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kntgraph-0.11.0-py3-none-any.whl.
File metadata
- Download URL: kntgraph-0.11.0-py3-none-any.whl
- Upload date:
- Size: 525.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
78d11b48fbb9b775d17c72efca8fd23ca1a632f8cfc05132be68157e50ef6f35
|
|
| MD5 |
6bbae6a6cf690a9b4384f4606641ffff
|
|
| BLAKE2b-256 |
a04bb0f60a48d4fe0061352ff83e161c77a6568dcce75060c46f1c9f8424047c
|
Provenance
The following attestation bundles were made for kntgraph-0.11.0-py3-none-any.whl:
Publisher:
publish.yml on kinetgraph/kinetgraph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kntgraph-0.11.0-py3-none-any.whl -
Subject digest:
78d11b48fbb9b775d17c72efca8fd23ca1a632f8cfc05132be68157e50ef6f35 - Sigstore transparency entry: 2328799928
- Sigstore integration time:
-
Permalink:
kinetgraph/kinetgraph@609830e8d407b9b8ee2339e760cbca8cea3b4f91 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/kinetgraph
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@609830e8d407b9b8ee2339e760cbca8cea3b4f91 -
Trigger Event:
workflow_dispatch
-
Statement type: