Skip to main content

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).

Code quality

cc mi pyright Version

Tests

coverage tests

Security

security audit

The current value of each badge is generated locally by scripts/quality_report.py; the script reads each gate's output and updates docs/quality.md on 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 ECSWorld is a deterministic function of events.
  • Event Sourcing — Redis Streams is the single source of truth.
  • Idempotency — replay produces the same World; idempotency_key on Tool makes at-least-once delivery into at-most-once side effects.
  • Dual lifecycle — operational (framework) and domain (application) lifecycles are orthogonal; the same World carries both views.
  • Resilience — circuit breaker, retry, bulkhead, timeout, fallback, and a Dead Letter Queue for failed events.
  • Durable checkpoints — the ReactiveDispatcher commits 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 agents sub-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_principal fallback in the API key verifier (ADR-017 §7.3). Plain-string bindings (pre-ADR-017) are now rejected as AuthError(kind="malformed", ...). Operators with legacy bindings MUST run scripts/migrate_principals.py --apply before 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 in RedisAPIKeyVerifier is the only path that distinguished JSON from legacy, and that path is now closed. Adds Zero Token Architecture support (ADR-049): RuleBasedChatSystem short-circuits user.intent events with deterministic replies and SolutionLookupSystem synthesises cached tool.<name>.completed events. The lookup system ships with two SolutionStoreLike adapters: InMemorySolutionStore (tests / 09b example) and RedisSolutionStore (production; one Hash per tool with the canonical knt:solution:<tool_name> layout). Also fixes the dispatcher's drain contract so a synthetic completion queued by run_pending_lookups actually lands in the EventLog on the next tick. See docs/zta.md, examples/09b_solution_lookup_zta.py (in-memory) and examples/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 by setuptools_scm (no more pyproject.toml::version); the new CI gates check_version and bump_dry_run catch drift before a release ships; the CONTRIBUTING.md::Release checklist is the 6-step ritual for cutting a release. Retroactive tags for v0.7.0, v0.8.0, v0.10.0 are pushed so git log v0.8.0..v0.10.0 and uv sync work today. PyPI publishing is deferred to ADR-052.
  • 0.9.0 — predecessor release. Drops the legacy LiteLLMTool / ToolInvoker / kntgraph.agents.roles paths (the canonical path is LiteLLMToolWorker + the WorkerManager, and the role_systems ECS-shaped counterparts). Adds the HttpClientLike Protocol and the HttpxHttpClientAdapter for HTTP-bound ToolWorkers (ADR-047). CLI tests ship a conftest.py for the optional [cli] extra (DEBT §2.25). CC refactor of 10 functions over the CC=10 ceiling (DEBT §2.26); the gate_complexity in scripts/ci.py now 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 the kntgraph package name. Backwards-incompatible with the old fmh_backend / fmh_agents imports; the source is structurally the same (same modules, same tests).
  • 0.6.x — internal releases under the fmh_* 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


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

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

kntgraph-0.11.0-py3-none-any.whl (525.5 kB view details)

Uploaded Python 3

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

Hashes for kntgraph-0.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 78d11b48fbb9b775d17c72efca8fd23ca1a632f8cfc05132be68157e50ef6f35
MD5 6bbae6a6cf690a9b4384f4606641ffff
BLAKE2b-256 a04bb0f60a48d4fe0061352ff83e161c77a6568dcce75060c46f1c9f8424047c

See more details on using hashes here.

Provenance

The following attestation bundles were made for kntgraph-0.11.0-py3-none-any.whl:

Publisher: publish.yml on kinetgraph/kinetgraph

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page