RFC-0001: v0.1 implementation plan¶
Status: Accepted Author: Alex Nodeland Created: 2026-09-30 Discussion: derived from stackr RFC-0002, accepted on 2026-09-29 with its decisions D1 to D7 Siblings:
- stackr RFC-0002 is the design this plan builds. Its decisions are relayr's ADR-0001 to ADR-0007.
- reflexr RFC-0003 manages rules at runtime, which phase 5 installs rules through.
Summary¶
relayr is the bridge that stackr RFC-0002 designs between artifactr and reflexr: an inbound adapter that turns selected artifactr events into reflexr events, an outbound adapter that lets reflexr runs act back in artifactr, mostly as proposals and notices, and a ledger of its own. This RFC is relayr's plan for v0.1: RFC-0002's seven phases, after a foundation, with the packages each phase adds, where its work lands, and what it waits on. The design itself is RFC-0002's and is not repeated here.
Motivation¶
RFC-0002 is stackr's document, and its phases span three repositories: relayr, stackr's template, and the product repository generated from it. relayr needs a plan in its own repository that its pull requests reference and tick, that says which work is relayr's, and that records what has changed in the libraries since the design was accepted.
Design¶
Packages¶
| Package | Holds | Phase | Extra |
|---|---|---|---|
relayr.events |
The bridged event types, under a base declared with event_namespace="artifactr", and the projections applications register for their app_events and artifact kinds |
1 | |
relayr.ledger |
The ledger port and its in-memory adapter, with one contract test for every adapter | 1 | |
relayr.sql |
The ledger's SQL adapter: SQLAlchemy, Alembic migrations and relayr_-prefixed tables in the application's schema |
1 | sql, sqlite, postgres |
relayr.inbound |
One follower per workspace, with its lease, cursor and dead letters | 1 | |
relayr.outbound |
The pydantic-ai capability and the helpers for function actions, allowlists, derived ids, keyed patches, and chain continuation | 2 | |
relayr.telemetry |
Span links, the thread:, chain: and rule: tags, and the Langfuse user |
4 | otel, once needed |
relayr.rules |
The rule artifact type, its validation and replay preview, the install rule, and provenance |
5 | |
relayr.evals |
Proposal outcomes as feedback on the runs that proposed, and the measures | 6 |
Each package uses only the libraries' public APIs, as RFC-0002's table lists them. A package's name may change when it is built; the architecture's status table shows what exists.
Since RFC-0002¶
The libraries have moved since RFC-0002 was written, and three changes bear on this plan:
- Messages are idempotent by id in artifactr. artifactr ADR-0045 (from #61) refuses a used message id in a workspace, durably. A notice or message posted with an id derived from the run is posted once however often the run retries, so phase 2 derives message ids as it derives the others, and needs none of the ledger's read-back that RFC-0002 designed for the gap.
- Log consumers have durable cursors. artifactr's
Workspace.cursorandsave_cursor(#67, artifactr ADR-0046) keep a named consumer's position in the library's own storage, and only move forward. Phase 1 decides, in an ADR, whether the follower's cursor lives there or in the ledger, and how its lease is held. - Rule names are qualified, as event types are (reflexr #83), so a rule's actor is
reflexr:<namespace>:<name>.
Prerequisites¶
As of 2026-09-30:
| Prerequisite | Library | Issue | Needed by | State |
|---|---|---|---|---|
| Namespaced event types | reflexr | #45 | phase 1 | Done: reflexr ADR-0039, implemented in reflexr #83 |
| Durable message idempotency | artifactr | #61 | phase 2 | Done: artifactr ADR-0045 |
| Notices that don't start or steer a turn, marked as notices | artifactr | #63 | phase 2 | Open |
| Workspace discovery: list a tenant's workspaces | artifactr | #62 | phase 3 | Open |
| Telemetry that composes across both libraries, untraced polling, mirror cursors | reflexr, artifactr | reflexr #62, artifactr #50 | phase 4 | Done |
traceparent on artifactr envelopes |
artifactr | #60 | phase 4 | Done |
| Runtime rule management | reflexr | #21, reflexr RFC-0003 | phase 5 | Phases 1 to 4 merged; phase 5, docs and oncall, open |
| Reserved publishers | reflexr | #72 | phase 5 | Open |
Phases¶
| Phase | Deliverable | Lands in | Waits on | Exit criteria |
|---|---|---|---|---|
| 0. Foundation | Packaging, tooling, CI, the documentation site and brand, ADRs for D1 to D7, and this plan | relayr | Nothing | CI green at 100% coverage, and the site builds in strict mode |
| 1. Inbound adapter | relayr.events, relayr.ledger, relayr.sql and relayr.inbound: the bridged types, the follower with its lease, cursor and dead letters, and the ledger with both adapters |
relayr | Nothing: reflexr #45 is done | An artifactr message fires a reflexr rule exactly once, across a restart and a redelivery, on memory, SQLite and PostgreSQL |
| 2. Outbound adapter and loop control | relayr.outbound: the capability and helpers, allowlists, derived ids, keyed patches, and chain continuation |
relayr | artifactr #63 | Under forced retries, a rule's proposal and notice each appear once. Two rules that answer each other stop at the depth limit |
| 3. Template option, example and smoke test | The bridge question, the incident timeline example, and make smoke-app extended |
stackr's template | artifactr #62 | A generated application passes its CI, and the smoke test sees an event cross each way |
| 4. Telemetry links and tags | relayr.telemetry: span links, the tags, and the Langfuse user |
relayr | Nothing: its prerequisites are done | In Tempo, a turn started by a run links to the run's span. In Langfuse, each session carries the other's tag |
| 5. Rules from chat | relayr.rules: the rule artifact type, validation, preview, the install rule, and provenance |
relayr | reflexr RFC-0003's last phase, and reflexr #72 | A rule drafted in a thread goes live only after a person accepts it, and a forged artifactr:proposal_resolved installs nothing |
| 6. Evaluation | relayr.evals: proposal-outcome feedback and the measures; the combined experiment in the template's evals/ |
relayr and stackr's template | Phases 2 and 5 | The example's experiment reports acceptance, rewrite rate and time to resolution |
| 7. Docs, ADRs and the product repository | relayr's guides and ADRs, stackr's docs, and the product repository generated from the template | relayr, stackr and the product repository | Phases 1 to 6 | The product repository passes its CI on the stack |
Each phase is a series of small pull requests to main, and a phase that lands in relayr brings its guides, reference pages, architecture and ADRs with it.
Drawbacks¶
- It waits on the libraries. Phases 2, 3 and 5 can't finish until their prerequisites land, and relayr moves only as its pins do (ADR-0012).
- Half the plan lands elsewhere. Phases 3, 6 and 7 are largely stackr's and the product repository's, so this checklist tracks work its own pull requests don't contain.
Alternatives¶
RFC-0002 weighs where the bridge lives, and the alternatives to a bridge at all, in its Alternatives and decision D1 (ADR-0001). For the plan itself, tracking relayr's work in RFC-0002's checklist would keep one list, but in another repository, which relayr's pull requests couldn't tick.
Unresolved questions¶
RFC-0002's own open questions stand: who may accept a rule, how far a chat rule reaches, a combined session measure in evalr, whether thread_created belongs in the default set, how clients show a notice, and bridging across deployments. Two more are phase 1's to settle:
- Where the follower's cursor lives: in artifactr's consumer cursors, or in the ledger.
- How a follower holds its lease: through a mechanism the libraries' public APIs offer, or in the ledger.
Tracking¶
- Phase 0: foundation
- Phase 1: inbound adapter
- Phase 2: outbound adapter and loop control (waits on artifactr #63)
- Phase 3: template option, example and smoke test (waits on artifactr #62)
- Phase 4: telemetry links and tags
- Phase 5: rules from chat (waits on reflexr RFC-0003's last phase, and reflexr #72)
- Phase 6: evaluation
- Phase 7: docs, ADRs and the product repository (ADR-0001 to ADR-0007 recorded in phase 0)