Skip to content

RFC-0001: v0.1 implementation plan

Status: Accepted Author: Alex Nodeland Created: 2026-09-28 Discussion: #14

Summary

Rebuild Reflex as reflexr, a library for reactive agent workflows: tenant-scoped event streams, rules as typed and serializable data, exact per-rule evaluation over a pure core, at-least-once runs of pydantic-ai agents, pydantic-graph graphs and functions, and FastAPI, WebSocket, schedule and MCP surfaces. It is built in eight phases, each a series of small pull requests to main, and held to the same standards as artifactr: pyright strict with no suppressions, 100% branch coverage, conformance fixtures, RFCs, ADRs and evergreen documentation.

Motivation

Reflex began as a template for event-driven agents, and an audit found it could not be relied on as a base:

  • Correctness and security. Event ids from clients are interpolated into NOTIFY SQL. Distributed locks derive ids from Python's per-process hash(), take and release advisory locks on different pooled connections, and are ignored by the event loop, which builds its own in-memory locks. The loop never calls trigger functions, so every threshold in the examples is a no-op. BaseAgent passes result_type, which pydantic-ai 1.x rejects, and the examples' LLM calls use attributes that do not exist, inside broad except blocks that hide the failure.
  • Delivery. One acknowledgement covers every trigger of an event, so one failure re-runs all of them. Events left processing by a crash are never reclaimed, one unparseable payload stops the subscription, and nothing bounds the tasks the loop creates.
  • Structure. Importing the package reads the environment and creates a database engine. Registries are global. The agent layer wraps pydantic-ai in its own class hierarchy. Storage is PostgreSQL only, without a protocol or migrations, so the tests mock it. Coverage is 67%, lowest in the loop (13%) and the store (29%).
  • Name. reflex is the import and PyPI name of the Reflex web framework, so the two cannot be installed together.

Its ideas are sound (an event log in PostgreSQL, filters and triggers, retries with backoff, a dead-letter queue), and artifactr has since set the standard a library in this family should meet. A rebuild on artifactr's architecture keeps the ideas and fixes the foundations.

Design

architecture.md describes the design, and protocol.md the wire formats. Decisions are recorded in ADR-0001 to ADR-0015. In brief:

  • Streams are tenant-scoped, append-only logs with a gap-free seq, opened as scoped handles.
  • Rules are Pydantic models: a condition pipeline (filter, dedupe, pattern, throttle), a scope, and an action reference. They serialize to JSON with a checked-in schema.
  • Deciding is pure: core.evaluate folds envelopes into per-scope state, and the host saves state, cursor and firings in one transaction, so each envelope affects each rule exactly once.
  • Acting is at least once: runs are leased, retried with backoff, ordered per scope, and dead-lettered per rule. The firing id is the idempotency key.
  • Actions are pydantic-ai agents (with the EventContext capability), pydantic-graph graphs (checkpointed after each step) or async functions, all over one Reaction deps type.

Phases

Phase Deliverable Exit criteria
0. Foundation Remove the template. New packaging (reflexr, uv_build), tooling (ruff, pyright strict, pytest, coverage), CI on Python 3.12 to 3.14, conventional commits, changelog, pre-commit, Dependabot, contribution and design process, license CI green on the empty package at 100% coverage
1. Core reflexr.core: events, envelopes, actors, conditions and reducers, rules and their JSON Schema, evaluate, retry policy, schedules Conformance fixtures cover every condition kind and error; property tests show replay reproduces firings
2. Stream reflexr.stream: storage protocol, InMemoryStorage, Streams and Stream, the Reactor (evaluation and execution with leases), function actions, the schedule runner The stream behaviour suite passes against in-memory storage
3. Agent reflexr.agent: Reaction, AgentAction and the EventContext capability, GraphAction with checkpoints Scripted agent runs assert the events written; an interrupted graph run resumes at its next step
4. SQL reflexr.sql: SQLAlchemy 2 async storage and Alembic migrations The stream behaviour suite passes against SQLite and PostgreSQL; migrations do not drift from the models
5. Surfaces reflexr.fastapi (ingest, REST, WebSocket), reflexr.mcp; generated protocol and rule schemas Contract tests for every command, frame and endpoint; an MCP client round trip; schema drift checked in CI
6. Reference implementation examples/oncall: incident response with a triage agent, a runbook graph and a terminal client Smoke-tested end to end with a scripted model
7. Docs site and brand Documentation website with guides and API reference, a brand that is a sibling of artifactr's, a branded README, published at reflexr.alexnodeland.com The site builds in CI in strict mode

Package layout

src/reflexr/
    __init__.py        # the common public API, re-exported
    core/              # pure decisions; depends on pydantic only
    stream/            # streams, storage protocol, in-memory storage, Reactor, schedules
    agent/             # Reaction, agent and graph actions, EventContext
    sql/               # extra: SQLAlchemy storage and migrations
    fastapi/           # extra: ingest, REST, WebSocket
    mcp/               # extra: MCP server
tests/                 # mirrors src/; conformance fixtures under tests/conformance/
examples/oncall/       # the reference implementation, a uv workspace member
schemas/               # generated protocol and rule schemas

Removing the template

Phase 0 removes the template in one pull request, as artifactr removed its prototype: the reflex package, the Copier files (copier.yml, *.jinja), the Docker setup, Bruno collections, scripts, examples, the agent command files, and the old documentation pages. The work in progress at the start of the rebuild is preserved on the archive/pre-rebuild branch, and the history stays in git. The repository's "template" setting and description are updated to match.

Drawbacks

  • Nothing runs end to end until phase 6. Existing users of the template (it has a handful of stars and one fork) get no upgrade path; they keep the old code on its branch and tags.
  • Phases 1 to 3 settle most of the API before a real application exercises it. As with artifactr, the reference implementation may force late API changes, which are made in their own pull requests.
  • Serialized appends per stream bound throughput per stream. Applications with one very hot source need to split it across streams until partitioning exists.

Alternatives

  • Repair the template in place. Faster to start, but it keeps the global state, the custom agent wrapper, and the delivery model that causes the failures above.
  • Build reflexr on artifactr's workspace log. One stack, but it ties event processing to the chat and artifact model, and makes the two libraries release together (ADR-0003).
  • A durable execution engine (Temporal, DBOS, Prefect) for every action. Stronger guarantees for long workflows, at the cost of infrastructure most users do not have. Graph checkpoints cover the common case; a durable backend can be an action kind later.

Unresolved questions

  • Runtime rule management: storing versioned rules per tenant and installing them through the API. Rules are data from phase 1 so this stays additive; it is the likely first RFC after v0.1, because the third system needs it.
  • Cron parsing: which small, maintained library parses cron expressions, chosen in phase 2 behind the Schedule model.
  • Resuming inside parallel graph branches: settled by a spike in phase 3. Until then a run that fails inside a fork resumes from the checkpoint before it.
  • Pausing runs for approval and live token output from runs: after v0.1.
  • Retention and snapshots for long logs: after v0.1.

Tracking

  • [ ] Phase 0: foundation
  • [ ] Phase 1: core
  • [ ] Phase 2: stream
  • [ ] Phase 3: agent
  • [ ] Phase 4: SQL
  • [ ] Phase 5: surfaces
  • [ ] Phase 6: reference implementation
  • [ ] Phase 7: docs site and brand