Skip to main content

Event-sourced agent engine — CLI and Python bindings for auditable AI workflows

Project description

zymi-core

Event-sourced agent engine for auditable AI workflows in Rust, YAML, and Python.

zymi-core helps you build agent workflows you can inspect after the fact. Every run is recorded as an immutable event stream in SQLite, agent side effects are mediated through intentions and boundary contracts, and pipelines execute as DAGs with parallel steps when possible.

Highlights

  • Auditable by default: every state change is persisted as an event with hash-chain verification.
  • Safer side effects: agents emit intentions first; contracts and approvals decide what is allowed to execute.
  • Practical workflows: define agents and DAG pipelines in YAML, then run them from a small CLI.
  • Flexible integration points: use the Rust crate, Python bindings, or both.
  • LLM-provider ready: OpenAI-compatible providers, Anthropic support, Python tools, and LangFuse event services.

Installation

If you want to... Install with...
CLI + Python bindings pip install zymi-core
Rust crate only zymi-core = "0.1"

pip install zymi-core gives you both the zymi CLI command and the zymi_core Python module.

Quick Start

# Install
pip install zymi-core

# Create a demo project
mkdir zymi-demo
cd zymi-demo
zymi init --example research

# Add your LLM provider config to project.yml, then run the pipeline
zymi run research -i topic="event sourcing"

# Inspect what happened
zymi events --limit 20
zymi verify

For example, this is enough to get started with OpenAI:

llm:
  provider: openai
  model: gpt-4o
  api_key: ${env.OPENAI_API_KEY}

What this gives you:

  • project.yml for provider config, policies, contracts, and defaults
  • agents/ for agent definitions
  • pipelines/ for DAG workflows
  • .zymi/events.db for the append-only event log
  • output/ and memory/ directories in the research example

Common CLI commands

zymi init --name my-project
zymi init --example research

zymi run main -i task="Summarize the architecture"
zymi run research -i topic="Rust event sourcing"

# Long-running mode: react to PipelineRequested events from any process
zymi serve research

zymi events
zymi events --stream conversation-1
zymi events --kind LlmCallCompleted --json

zymi replay conversation-1 --from 1
zymi verify
zymi verify --stream conversation-1

Project Layout

A zymi project is just a directory with YAML files:

my-project/
  project.yml
  agents/
    default.yml
  pipelines/
    main.yml
  .zymi/
    events.db

The default scaffold created by zymi init is intentionally small:

# project.yml
name: my-project
version: "0.1"

defaults:
  timeout_secs: 30
  max_iterations: 10

policy:
  enabled: true
  allow: ["ls *", "cat *", "echo *"]
  deny: ["rm -rf *"]
# agents/default.yml
name: default
description: "Default agent"
tools:
  - web_search
  - read_file
  - write_memory
max_iterations: 10
# pipelines/main.yml
name: main

steps:
  - id: process
    agent: default
    task: "${inputs.task}"

input:
  type: text

output:
  step: process

Python Bindings

The same pip install zymi-core that gives you the CLI also exposes Event, EventBus, EventStore, Subscription, and ToolRegistry for programmatic use.

from zymi_core import ToolRegistry

registry = ToolRegistry()

@registry.tool
def search(query: str) -> str:
    return f"Results for: {query}"

result = registry.call("search", '{"query":"rust async"}')
intention_json = registry.to_intention("search", '{"query":"rust async"}')
definitions = registry.definitions()

For lower-level event primitives the same package gives you the event store and bus directly:

from zymi_core import Event, EventBus, EventStore

store = EventStore("./events.db")
bus = EventBus(store)
subscription = bus.subscribe()

event = Event(
    stream_id="conversation-1",
    kind={"type": "UserMessageReceived", "data": {
        "content": {"User": "Hello"},
        "connector": "python",
    }},
    source="python",
)

bus.publish(event)
received = subscription.try_recv()

Multi-Process Integration (Django, Celery, scripts)

The Python wrapper for EventStore opens the same SQLite file the Rust side uses. There is no second IPC channel — events written from one process are visible to every other process that opens the same store, and a long-running zymi serve picks them up via a polling tail watcher (see ADR-0012).

The canonical pattern: a web app publishes a PipelineRequested event, zymi serve runs the pipeline, and the result comes back as a PipelineCompleted event with the same correlation_id.

Terminal A — long-running Rust service:

cd my-zymi-project
zymi serve research

Terminal B — any Python process (e.g. a Django view):

import uuid
from zymi_core import Event, EventBus, EventStore

store = EventStore(".zymi/events.db")
bus = EventBus(store)

correlation_id = str(uuid.uuid4())
sub = bus.subscribe_correlation(correlation_id)

event = Event(
    stream_id=f"web-req-{correlation_id}",
    kind={"type": "PipelineRequested", "data": {
        "pipeline": "research",
        "inputs": {"topic": "rust event sourcing"},
    }},
    source="django",
)
event.with_correlation(correlation_id)
bus.publish(event)

# Block until the serve process publishes PipelineCompleted with the
# same correlation_id (timeout in seconds).
result = sub.recv(timeout_secs=300)
print(result.kind)  # {"type": "PipelineCompleted", "data": {...}}

Because the SQLite store is the single source of truth, you also get free auditing: zymi events --stream web-req-... shows everything that happened during the run, and zymi verify checks the hash chain.

Rust Crate

Add the crate to your Cargo.toml:

[dependencies]
zymi-core = "0.1"

Example:

use std::sync::Arc;
use zymi_core::{open_store, Event, EventBus, EventKind, Message, StoreBackend};

let store = open_store(StoreBackend::Sqlite { path: "events.db".into() })?;
let bus = EventBus::new(store.clone());

let mut rx = bus.subscribe().await;

let event = Event::new(
    "conversation-1".into(),
    EventKind::UserMessageReceived {
        content: Message::User("Hello".into()),
        connector: "cli".into(),
    },
    "cli".into(),
);

bus.publish(event).await?;
let received = rx.recv().await.unwrap();
assert_eq!(received.kind_tag(), "user_message_received");

let verified_count = store.verify_chain("conversation-1").await?;

For cross-process delivery in your own binary, spawn a StoreTailWatcher on the same store/bus — it polls for events written by other processes and fans them out into local subscribers without re-persisting them:

use std::time::Duration;
use zymi_core::StoreTailWatcher;

let watcher = StoreTailWatcher::new(store.clone(), bus.clone())
    .with_interval(Duration::from_millis(100))
    .spawn();

// ... later, on shutdown:
watcher.stop().await;

How It Works

zymi-core is built around a small set of ideas:

  1. Every meaningful state change becomes an event. The SQLite event store is the source of truth.
  2. Agents express intentions, not side effects. Intentions are evaluated against boundary contracts before execution.
  3. Pipelines are DAGs. Independent steps can run in parallel, while dependencies remain explicit.
  4. Runs stay replayable. You can inspect events, replay streams, and verify hash-chain integrity later.

Core intention types include ExecuteShellCommand, WriteFile, ReadFile, WebSearch, WebScrape, WriteMemory, SpawnSubAgent, and CallCustomTool.

Feature Flags (Rust crate)

The pip wheel ships with python and cli enabled. These flags are relevant when depending on the Rust crate directly.

Feature Description
python PyO3 bindings for the _zymi_core Python extension module
cli The zymi CLI binary
runtime Async runtime and HTTP dependencies used by runtime integrations
webhook HTTP approval handler built on Axum
services Event-bus services such as LangFuse

Development

cargo test
cargo test --features services,webhook

cargo clippy -- -D warnings
cargo clippy --features services -- -D warnings

maturin develop --features python,cli

License

MIT

Project details


Download files

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

Source Distribution

zymi_core-0.1.2.tar.gz (125.1 kB view details)

Uploaded Source

Built Distributions

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

zymi_core-0.1.2-cp311-cp311-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.11Windows x86-64

zymi_core-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.7 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64

zymi_core-0.1.2-cp311-cp311-macosx_11_0_arm64.whl (3.6 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

zymi_core-0.1.2-cp311-cp311-macosx_10_12_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.11macOS 10.12+ x86-64

zymi_core-0.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.0 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

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

File metadata

  • Download URL: zymi_core-0.1.2.tar.gz
  • Upload date:
  • Size: 125.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for zymi_core-0.1.2.tar.gz
Algorithm Hash digest
SHA256 355f87c66eaf56540aa6215de18cc67bad8271894136b15c35b0b8de2dbc2eda
MD5 0daf926564d76a889edce2ef64a12397
BLAKE2b-256 399d1ec86fbb3c4d4fc78d120580a84f3032e680b74fd1e8d8cb1c7bd5b2a936

See more details on using hashes here.

Provenance

The following attestation bundles were made for zymi_core-0.1.2.tar.gz:

Publisher: release.yml on metravod/zymi-core

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

File details

Details for the file zymi_core-0.1.2-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: zymi_core-0.1.2-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 4.0 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for zymi_core-0.1.2-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 d3ad066b248cd467fe094e859b6d08540f2381173012ef3fecdb65b199fdb5bc
MD5 87cf51200bd282ed41fcbe41882ab6e1
BLAKE2b-256 ae48e468993b0735135286070d335304c28048f85b5cfeb55f832147a2bcfd2c

See more details on using hashes here.

Provenance

The following attestation bundles were made for zymi_core-0.1.2-cp311-cp311-win_amd64.whl:

Publisher: release.yml on metravod/zymi-core

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

File details

Details for the file zymi_core-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for zymi_core-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 dd844f268e30a56b7e7003f90c9375b329389e4a597e8f2a612c2aff1d1ef0da
MD5 1d93c90abb2e698f8c8624e7adcca756
BLAKE2b-256 2e4c7cb4cba9d1340e1f563202134c5c69069abbb882ca4c9d604fd169dab711

See more details on using hashes here.

Provenance

The following attestation bundles were made for zymi_core-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on metravod/zymi-core

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

File details

Details for the file zymi_core-0.1.2-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for zymi_core-0.1.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f2f85da8128d753bda01a4dd45575c8b82ced8ac2ece91aa1040c20cb59c101e
MD5 6c72b95b5b1c0b1c237a758a465d83a6
BLAKE2b-256 8117cdf5c5ed23f3ee765d8f480c5284ef887770b8c3b71d97fa36dde7bb7f77

See more details on using hashes here.

Provenance

The following attestation bundles were made for zymi_core-0.1.2-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: release.yml on metravod/zymi-core

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

File details

Details for the file zymi_core-0.1.2-cp311-cp311-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for zymi_core-0.1.2-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 cf3840addba17673d6da88aab2540dcea391cb340b277ebee54df294c165f053
MD5 e28a3e89cda89bbc86ea858fe90880ef
BLAKE2b-256 bbbc8259abaf49fe046f6cd1f41e35c091e74114de3b34cbbf7d96a68081c8d2

See more details on using hashes here.

Provenance

The following attestation bundles were made for zymi_core-0.1.2-cp311-cp311-macosx_10_12_x86_64.whl:

Publisher: release.yml on metravod/zymi-core

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

File details

Details for the file zymi_core-0.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for zymi_core-0.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ca7b04e60842c7e5c4bf736ce491cf883c52a4225d1aed0a6fcf45efd4f70b0b
MD5 84c569bfcbd0a0791e17791661f2b340
BLAKE2b-256 30ec765f75bb4aa2e27fa2de803363e2b67e13c36777bff34b5ce19c76e2d676

See more details on using hashes here.

Provenance

The following attestation bundles were made for zymi_core-0.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on metravod/zymi-core

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