Observed since 20 Oct, 21:55 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
agentflow-runtime
Real-time data platform serving context to AI agents
Event-native metrics layer: business metrics that move when events happen — measured 1.1 s p50 event-to-metric freshness on production defaults. Live entity lookups, typed contracts, dual-language SDKs, and release-gated delivery for people, dashboards, services, and AI agents alike.
BI on a replica answers yesterday's questions. Support, ops, and merch workflows need current orders, metrics, and health signals at the moment of decision — not a stale warehouse snapshot, not a pile of one-off service adapters, and not a cache that quietly serves 30-second-old numbers.
AgentFlow's axis is event → live metric: every metric declares which events move it (a contract-tested lineage graph), and the serving layer keeps reads fresh by invalidating its cache when events arrive — a measured behavior, not a slogan (docs/freshness-benchmark.md). One serving boundary on top of that axis:
Consumers are whoever needs the number now: humans, dashboards, downstream services, and AI agents — agents are one consumer, not the product.
GET /v1/metrics/* in 1.06 s p50 / 1.99 s p95 on production defaults (event-driven cache invalidation, no webhook registration), tunable to 238 ms p50; a plain TTL cache on the same pipeline sits at ~15 s. Reproducible via python scripts/benchmark_freshness.py → freshness benchmark/v1/catalog and /v1/contracts and pinned by tests against the actual write pathv1.6.0 on PyPI (agentflow-runtime, agentflow-client) and npm (@yuliaedomskikh/agentflow-client) via OIDC Trusted Publishers with SLSA provenance on every artifactas_of historical reads — over sub-second entity lookups (p50 38–55 ms, p99 167 ms on local hardware)sqlglot AST validation for NL-to-SQL, fail-closed auth, secret scrubbing, and a Bandit gate for new findingsUpgrading from v1.0.x? See the v1.1 migration guide before installing.
Prerequisites:
3.11+makemake demo starts Redis and the ClickHouse serving store)PowerShell 7+:
git clone https://github.com/brownjuly2003-code/agentflow.git
cd agentflow
. .\scripts\setup.ps1
make demo
macOS / Linux:
git clone https://github.com/brownjuly2003-code/agentflow.git
cd agentflow
source ./scripts/setup.sh
make demo
make demo starts Redis and ClickHouse, seeds demo data through the full pipeline (validated events land in the ClickHouse serving store), and serves the API on http://localhost:8000. Swagger UI is available at http://localhost:8000/docs.
Try it:
curl http://localhost:8000/v1/entity/order/ORD-20260404-1001
curl -X POST http://localhost:8000/v1/query \
-H "Content-Type: application/json" \
-d '{"question":"Show me top 3 products"}'
Local demo runs without API-key enforcement unless you explicitly configure AGENTFLOW_API_KEYS_FILE.
Event sources -> Kafka -> Flink -> Iceberg --------\
-> Semantic layer -> FastAPI -> Agent / SDK
Local demo -> local_pipeline -> ClickHouse ------/
(DuckDB stays the local lake / test store)
Stack:
final=1 reads), DuckDB the local-dev / test storeSee docs/architecture.md for the detailed design, trade-offs, and deployment topologies.
CDC source capture is standardized on Debezium/Kafka Connect; downstream consumers use the canonical AgentFlow CDC contract defined in ADR 0005.
| Area | Files |
|---|---|
| API core | src/serving/api/ |
| Semantic layer | src/serving/semantic_layer/ |
| Python SDK | sdk/agentflow/ |
| TypeScript SDK | sdk-ts/src/ |
| Agent integrations | integrations/agentflow_integrations/ (LangChain, LlamaIndex, CrewAI, MCP) |
| Flink jobs | src/processing/flink_jobs/ |
| Test suites | tests/ |
| Design decisions | docs/decisions/ (ADRs) |
| Public site | site/ |
| IaC | infrastructure/terraform/, infrastructure/dv2/, helm/, k8s/ |
| DV2.0 warehouse | warehouse/agentflow/dv2/ (hubs / links / satellites + real-dataset loader) |
Core
Deep dives
# verified release slice
python -m pytest tests/unit tests/integration tests/sdk -q
# benchmark and regression gate
python scripts/run_benchmark.py
python scripts/check_performance.py --baseline docs/benchmark-baseline.json --current .artifacts/load/results.json --max-regress 20
# benchmark trend: [.github/perf-history.json](.github/perf-history.json) is appended on every main push;
# render the history locally with `make perf-plot` (writes docs/perf/history.html).
# contracts and security
python scripts/generate_contracts.py --check
bandit -r src sdk --ini .bandit --severity-level medium -f json -o .tmp/bandit-current.json
python scripts/bandit_diff.py .bandit-baseline.json .tmp/bandit-current.json
v1.6.0 is the current release line — PyPI agentflow-runtime /
agentflow-client and npm @yuliaedomskikh/agentflow-client, all
published via OIDC Trusted Publishers with SLSA provenance attestations.
CI on main is green across all 13 required checks.
The v1.1.0 → v1.6.0 arc landed in six increments on top of a security
audit-closure sprint:
v1.1.0 — audit closure: tenant isolation across every read
surface, SQL guard centralized on sqlglot, entity allowlist
enforcement, fail-closed auth, secret rotation, Helm hardening,
OpenAPI drift gate, and the required status checks.v1.2.0 — DV2 multi-branch warehouse: 38 Data Vault 2.0 tables
(8 hubs / 8 links / 22+ satellites), an Argo Workflows dv2-refresh
template, a dbt project (3 mart models + 12 tests), and per-branch CDC
fan-out via ClickHouse MaterializedPostgreSQL.v1.3.0 — helm/kafka-connect hardening matched to helm/agentflow
(NetworkPolicy + PDB + securityContext), live Helm validation across both
charts, and the narrated DV2 demo (terminal + web-UI + dbt docs).v1.4.0 — maintenance: on-call runbooks, SECURITY.md, issue/PR
templates, contract/DORA CI hardening, repo hygiene, and a dependency
wave (mypy, Terraform AWS provider, TypeScript, GitHub Actions,
Vitest). No runtime API changes from v1.3.0.v1.5.0 — security & correctness hardening: argon2id key hashing
with an O(1) peppered lookup index (M-C4), an NL→SQL guard bypass fix
(typed read_csv / read_parquet scan functions now denied in
projection position), sqlglot control-byte and mutation-target
repairs, and a strict-mypy expansion across the orchestration and
freshness slices. No public API changes.v1.6.0 — the architecture-fixing release: ClickHouse becomes the
shipped serving engine (pipeline sink, ReplacingMergeTree row versions,
backend-routed event scan, a dedicated CI E2E lane against a real
ClickHouse), PII protection moves from the removed app-level string-parse
gate to engine-enforced vault governance (fail-closed column grants,
per-jurisdiction officer roles, row policies, SQL SECURITY DEFINER
views — every live adversarial probe green), plus the vendored NL→SQL
generation engine (LangGraph, routed through GraceKelly), the DV2 raw
vault on PostgreSQL with LISTEN/NOTIFY freshness, the MinIO-backed
PyIceberg catalog, and the OpenSSF Scorecard channel (5.8 → 7.0).The tagged line and main are in sync as of v1.6.0. See the
changelog for full detail.
This is a reference data-engineering project. The streaming, warehouse, and deployment artifacts (Flink, Iceberg, Helm, Terraform, k8s) are exercised against a local pipeline and a kind cluster in CI rather than a managed cloud. Wiring it to a live production source needs inputs that live outside the repo — CDC source onboarding (runbook ready in docs/operations/cdc-production-onboarding.md), a public benchmark on production-grade hardware, and an external pen-test attestation.
| Admin UI | API docs |
|---|---|
| Landing page | Benchmark run |
|---|---|
Capture notes and publish-time checks are listed in docs/publication-checklist.md.
MIT. See LICENSE.
Built as a data-engineering reference project. Initial release cycle
2026-04-10 → 2026-04-20, with post-audit hardening and the DV2
extension landing through v1.4.0. Architecture decisions are recorded as
ADRs in docs/decisions/.
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
argon2-cffiEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | argon2-cffi<26,>=23 | runtime |
bcryptEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | bcrypt<6,>=5 | runtime |
confluent-kafkaEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | confluent-kafka<3,>=2.5 | runtime |
dagsterEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | dagster<2,>=1.13.1 | runtime |
duckdbEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | duckdb<2,>=1.1 | runtime |
fastapiEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | fastapi<1,>=0.111 | runtime |
httpxEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | httpx<1,>=0.27 | runtime |
opentelemetry-exporter-otlp-proto-grpcEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | opentelemetry-exporter-otlp-proto-grpc<2,>=1.41 | runtime |
opentelemetry-instrumentation-fastapiEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | opentelemetry-instrumentation-fastapi<1,>=0.62b0 | runtime |
opentelemetry-instrumentation-httpxEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | opentelemetry-instrumentation-httpx<1,>=0.62b0 | runtime |
opentelemetry-sdkEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | opentelemetry-sdk<2,>=1.41 | runtime |
panderaEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pandera<1,>=0.20 | runtime |
prometheus-clientEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | prometheus-client<1,>=0.21 | runtime |
pyarrowEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pyarrow<25,>=17 | runtime |
pydantic-settingsEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pydantic-settings<3,>=2.5 | runtime |
pydanticEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pydantic<3,>=2.9 | runtime |
pyyamlEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pyyaml<7,>=6 | runtime |
sqlglotEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | sqlglot<31,>=30 | runtime |
structlogEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | structlog<27,>=24.4 | runtime |
uvicornEnvironment{
"extras": "standard",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | uvicorn[standard]<1,>=0.30 | runtime |
boto3Environment{
"extras": "",
"marker": "extra == \"cloud\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | boto3<2,>=1.35; extra == "cloud" | runtime |
pyicebergEnvironment{
"extras": "pyiceberg-core",
"marker": "extra == \"cloud\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pyiceberg[pyiceberg-core]<1,>=0.7; extra == "cloud" | runtime |
schemathesisEnvironment{
"extras": "",
"marker": "extra == \"contract\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | schemathesis==4.21.10; extra == "contract" | runtime |
banditEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | bandit<2,>=1.9; extra == "dev" | runtime |
buildEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | build<2,>=1.2; extra == "dev" | runtime |
hatchlingEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | hatchling<2,>=1.25; extra == "dev" | runtime |
hypothesisEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | hypothesis<7,>=6; extra == "dev" | runtime |
jsonschemaEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | jsonschema<5,>=4; extra == "dev" | runtime |
mypyEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | mypy<3,>=1.11; extra == "dev" | runtime |
pandasEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pandas<4,>=2.2; extra == "dev" | runtime |
pytest-asyncioEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest-asyncio<2,>=0.24; extra == "dev" | runtime |
pytest-covEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest-cov<8,>=5; extra == "dev" | runtime |
pytestEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest<10,>=8.3; extra == "dev" | runtime |
ruffEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | ruff<1,>=0.6; extra == "dev" | runtime |
testcontainersEnvironment{
"extras": "kafka",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | testcontainers[kafka]<5,>=4.9; extra == "dev" | runtime |
types-pyyamlEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | types-pyyaml<7,>=6; extra == "dev" | runtime |
types-redisEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | types-redis<6,>=4.6; extra == "dev" | runtime |
apache-flinkEnvironment{
"extras": "",
"marker": "extra == \"flink\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | apache-flink==2.3.0; extra == "flink" | runtime |
langchain-coreEnvironment{
"extras": "",
"marker": "extra == \"integrations\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | langchain-core<2,>=1.2.22; extra == "integrations" | runtime |
langchain-text-splittersEnvironment{
"extras": "",
"marker": "extra == \"integrations\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | langchain-text-splitters<2,>=1.1.2; extra == "integrations" | runtime |
langchainEnvironment{
"extras": "",
"marker": "extra == \"integrations\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | langchain<2,>=0.3.30; extra == "integrations" | runtime |
langgraphEnvironment{
"extras": "",
"marker": "extra == \"integrations\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | langgraph<2,>=1; extra == "integrations" | runtime |
langsmithEnvironment{
"extras": "",
"marker": "extra == \"integrations\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | langsmith<1,>=0.7.31; extra == "integrations" | runtime |
llama-index-coreEnvironment{
"extras": "",
"marker": "extra == \"integrations\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | llama-index-core<1,>=0.12; extra == "integrations" | runtime |
fakeredisEnvironment{
"extras": "",
"marker": "extra == \"load\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | fakeredis<3,>=2.21; extra == "load" | runtime |
locustEnvironment{
"extras": "",
"marker": "extra == \"load\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | locust<3,>=2.29; extra == "load" | runtime |
psycopgEnvironment{
"extras": "binary",
"marker": "extra == \"postgres\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | psycopg[binary]<4,>=3.2; extra == "postgres" | runtime |
bdist_wheel · 268.69 KB · Python py3
sdist · 256.56 KB · Python source
Observed since 20 Oct, 21:55 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:e789ef628d15136a6da45e3509b4cf84c0a07f021d781ce03a5b3004e916ea67