Skip to content
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ A run executes in one of **three execution modes** behind the one `LLMProvider`
engine is identical across all three. See [ADR-0012](docs/decisions/0012-managed-inference-dual-mode.md) to [ADR-0015](docs/decisions/0015-managed-mode-data-handling-and-compliance.md)
and [docs/architecture/managed-inference.md](docs/architecture/managed-inference.md).

**Status:** Phase 1 in progress — milestone M1 (LLM seam proven) reached (PR #9, 2026-06-07); the `FallbackChain` runner (1.K) landed, completing 1.m2 with the cost tracker (PR #13, 2026-06-11); the run loop (1.N — `WorkflowEngine` + `RunEventBus`) landed (PR #17, 2026-06-13) **completing 1.m3** (parse → DAG → run loop emits the canonical event stream), with the built-in `ToolRegistry` (1.T, a 1.m4 component) landing alongside it as the other `AgentRunner` (1.O) join prerequisite; the **`AgentRunner` (1.O) — per-node LLM execution behind the seam — landed (PR #18, 2026-06-14)**; and the **node-type handlers (1.P) — the six non-agent `NodeExecutor` arms (condition / transform / fan_out / fan_in / input / output) behind a dispatching executor — landed (PR #20, 2026-06-14)**; and **checkpoint/resume (1.R) + the human gate (1.Q) landed (PR #22, 2026-06-15)** — the derived `Checkpointer` + cross-process `resumeFromCheckpoint`, and the `human_in_the_loop` gate with the one-shot timeout port; and **node retry (1.S) — the above-chain whole-node retry budget ([ADR-0040](docs/decisions/0040-node-retry-budget-above-the-chain.md), amending ADR-0038) — landed (PR #24, 2026-06-15)**, re-dispatching a whole node on a retryable failure up to `retry.max` attempts (with `node:retrying`, abort-aware backoff, and `retry_on` filtering), with retry-from-node (ADR-0040 Part B) deferred to Phase-2; and the **pre-egress budget governor (1.AC, [ADR-0028](docs/decisions/0028-workflow-resource-governance.md)) + the `AgentSession` agent-first entry point (1.V, [ADR-0024](docs/decisions/0024-agent-first-entry-point-agentsession.md)) landed together (PR #26, 2026-06-16)** — 1.AC was the last 1.m4 component, so **1.m4 is complete** (the full engine stack: node handlers, gate, checkpoint/resume, retry, tools, sandbox, budget governor), and 1.V opens the Lane-C agent-first sub-spine (1.m5); then the **end-to-end Node harness (1.U) landed (PR #27, 2026-06-16), reaching 🎯 M2** — the engine runs end-to-end (live streaming + per-node-boundary checkpointing + cross-process resume + node retry + provider failover, gap-free), **completing the Phase-1 engine critical path**. The remaining Phase-1 work is additive and off the critical path (Lane C: the **`session:*` namespace (1.W) has since landed (PR #28, 2026-06-17)** — the `SessionEventSink`→`RunEventBus` adapter + per-session `sequenceNumber`, the `SessionHandle`, and the combined `RunOrSessionEventSchema` gate — leaving persistence 1.X next ‖ 1.Y/1.Z/1.AA; the 1.m6 multimodal sub-spine); **Phase 2 (CLI, M3) is unblocked**.
**Status:** Phase 1 in progress — milestone M1 (LLM seam proven) reached (PR #9, 2026-06-07); the `FallbackChain` runner (1.K) landed, completing 1.m2 with the cost tracker (PR #13, 2026-06-11); the run loop (1.N — `WorkflowEngine` + `RunEventBus`) landed (PR #17, 2026-06-13) **completing 1.m3** (parse → DAG → run loop emits the canonical event stream), with the built-in `ToolRegistry` (1.T, a 1.m4 component) landing alongside it as the other `AgentRunner` (1.O) join prerequisite; the **`AgentRunner` (1.O) — per-node LLM execution behind the seam — landed (PR #18, 2026-06-14)**; and the **node-type handlers (1.P) — the six non-agent `NodeExecutor` arms (condition / transform / fan_out / fan_in / input / output) behind a dispatching executor — landed (PR #20, 2026-06-14)**; and **checkpoint/resume (1.R) + the human gate (1.Q) landed (PR #22, 2026-06-15)** — the derived `Checkpointer` + cross-process `resumeFromCheckpoint`, and the `human_in_the_loop` gate with the one-shot timeout port; and **node retry (1.S) — the above-chain whole-node retry budget ([ADR-0040](docs/decisions/0040-node-retry-budget-above-the-chain.md), amending ADR-0038) — landed (PR #24, 2026-06-15)**, re-dispatching a whole node on a retryable failure up to `retry.max` attempts (with `node:retrying`, abort-aware backoff, and `retry_on` filtering), with retry-from-node (ADR-0040 Part B) deferred to Phase-2; and the **pre-egress budget governor (1.AC, [ADR-0028](docs/decisions/0028-workflow-resource-governance.md)) + the `AgentSession` agent-first entry point (1.V, [ADR-0024](docs/decisions/0024-agent-first-entry-point-agentsession.md)) landed together (PR #26, 2026-06-16)** — 1.AC was the last 1.m4 component, so **1.m4 is complete** (the full engine stack: node handlers, gate, checkpoint/resume, retry, tools, sandbox, budget governor), and 1.V opens the Lane-C agent-first sub-spine (1.m5); then the **end-to-end Node harness (1.U) landed (PR #27, 2026-06-16), reaching 🎯 M2** — the engine runs end-to-end (live streaming + per-node-boundary checkpointing + cross-process resume + node retry + provider failover, gap-free), **completing the Phase-1 engine critical path**. The remaining Phase-1 work is additive and off the critical path (Lane C: the **`session:*` namespace (1.W) landed (PR #28, 2026-06-17)** — the `SessionEventSink`→`RunEventBus` adapter + per-session `sequenceNumber`, the `SessionHandle`, and the combined `RunOrSessionEventSchema` gate — and **session persistence (1.X) landed (PR #29, 2026-06-17)** — the `agent_sessions`/`session_messages` tables + migration, `SessionMessageSchema`/`AgentSessionSchema`, and the `SessionStore` + domain↔row mappers (data-layer only; the per-turn `AgentSession`→store wiring + resume are 1.Y/1.AA) — leaving 1.Y/1.Z/1.AA next ‖ the 1.m6 multimodal sub-spine); **Phase 2 (CLI, M3) is unblocked**.
Phase 0 (M0, 2026-06-04) landed the monorepo, strict toolchain + CI, `@relavium/shared` (the
full Zod contract set), the no-vendor-type seam fence, and `@relavium/db`. Phase 1 has since
landed `@relavium/llm` — the `LLMProvider` seam + all three adapters (Anthropic, OpenAI/DeepSeek,
Expand All @@ -63,8 +63,8 @@ plus the one-shot `setTimer` timeout port — `approve` auto-resolves, `reject`
The pre-egress budget governor (1.AC) + the agent-first `AgentSession` (1.V) landed together (PR #26)
**completing 1.m4**; then the end-to-end Node harness (1.U) landed (PR #27, 2026-06-16) **reaching M2** —
the Phase-1 engine critical path is complete. Active work is now the additive Lane-C sub-spine (session
events **1.W ✅ Done (PR #28, 2026-06-17)**; persistence 1.X next) and the multimodal sub-spine; Phase 2
(CLI) is unblocked. See
events **1.W ✅ Done (PR #28)** + persistence **1.X ✅ Done (PR #29, 2026-06-17)**; 1.Y/1.Z/1.AA next) and
the multimodal sub-spine; Phase 2 (CLI) is unblocked. See
[docs/roadmap/current.md](docs/roadmap/current.md). See [README.md](README.md) for the public overview.

## Non-negotiable rules for AI agents
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ both landed in **PR #26 (2026-06-16)**. With the budget governor in, **milestone
**end-to-end Node harness** (1.U) landed (**PR #27, 2026-06-16**) — **🎯 reaching milestone M2**: the engine runs
end-to-end (live streaming + checkpoint + cross-process resume + retry + provider failover), completing the
Phase-1 engine critical path. The remaining Phase-1 work is additive (the agent-first sub-spine — **session
events 1.W ✅ (PR #28, 2026-06-17)**, persistence 1.X next, … — and the multimodal sub-spine); **Phase 2 (the
CLI) is unblocked**. See
events 1.W ✅ (PR #28)** + **persistence 1.X ✅ (PR #29, 2026-06-17)**, 1.Y/1.Z/1.AA next … — and the
multimodal sub-spine); **Phase 2 (the CLI) is unblocked**. See
[docs/roadmap/current.md](docs/roadmap/current.md) for live status.
34 changes: 34 additions & 0 deletions docs/reference/contracts/agent-session-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,40 @@ The export **produces** the format owned by [workflow-yaml-spec.md](workflow-yam
**mapping** (session turn → `agent` node, transcript → metadata) is the contract owned here. The
desktop "Export to Canvas" affordance and the CLI `relavium chat-export` both drive this one contract.

**Precise mapping (1.Z).** Given a loaded `AgentSessionRecord` + its ordered `SessionMessage[]`, the
exporter builds a `WorkflowDefinition` deterministically (no wall-clock / randomness, so the artifact is
reproducible and round-trips):

- **Nodes** — a single `input` node (`id: input`), then **one `agent` node per COMPLETED logical turn** in
`sequenceNumber` order (`id: turn-1`, `turn-2`, … — 1-based), then one `output` node (`id: output`). A
*logical turn* is the contiguous `user` message(s) plus the assistant/tool messages answering them (a host
may persist a single turn as split rows — `user → assistant(tool_call) → tool → assistant(text)`); it is one
node, not one per assistant message. A turn is *completed* only if it produced final assistant **text** — an
unanswered or interrupted-mid-tool-loop turn (no final text) is **omitted from the chain** (kept verbatim in
`metadata`), so export and `reconstructSessionState`'s rollback (1.Y) agree on what a turn is. Each `agent`
node carries: `agent_ref` = the session's `agentSlug`; `prompt_template` = the **text** of the turn's
`user` message(s), with interpolation openers neutralized (omitted if empty); `tools` = the deduped union of
tool names invoked across the turn's assistant messages (the `tool_call` parts), omitted when none. No
`model`/`temperature`/`max_tokens`/`retry`/`output_schema` are emitted — those are authoring concerns the
user adds on the canvas, not replay fields.
- **Edges** — a straight linear chain `input → turn-1 → … → turn-n → output` (just `{ from, to }`); when a
session has no completed turn the chain is `input → output`. No parallel/conditional/loop edges (ADR-0026).
- **Workflow `id`** — a deterministic kebab slug of the title (ASCII alphanumerics only, matching
`kebabIdSchema`; non-ASCII is stripped), falling back to `exported-session`. The scaffold's id is
human-reviewed and renameable on the canvas.
- **`agents`** — the session's frozen `agentSnapshot` (an inline `Agent`) is emitted as the sole `agents[]`
entry so `agent_ref` resolves; when no snapshot was captured, `agents` is omitted and `agent_ref` resolves
against the workspace agent registry at author time (the file still parses — `agent_ref` resolution is the
engine's job, not the schema's).
- **`metadata`** — the full transcript under a single reserved key: `metadata.relaviumExport = { source:
'session', sessionId, agentSlug, title?, createdAt, updatedAt, messages: SessionMessage[] }`. It is a real
schema field (`z.record`), so it survives parse → serialize round-trips.
- **Determinism + exclusions** — the YAML emitter (1.Z, `serializeWorkflow`; 1.L is parse-only) sorts map
keys alphabetically and preserves array order, so `parse → serialize` is byte-stable. No `secret` value can
appear (secrets never enter a message — [ADR-0029](../../decisions/0029-tool-policy-hardening.md)) and no
reasoning `signature` can appear (the transcript is `DurableContentPart`, which structurally omits it —
[ADR-0030](../../decisions/0030-llm-seam-shape-amendment-reasoning-response-format-provider-executed.md)).

## Validation and persistence

- Validated against `AgentSessionSchema` / `SessionMessageSchema` / `SessionContextSchema` (Zod, in
Expand Down
13 changes: 9 additions & 4 deletions docs/roadmap/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,10 @@ the H3 approve-continues bypass, the per-attempt `FallbackChain` enforcement)
emission via an injected `SessionEventSink`) **then landed together — ✅ Done (PR #26, 2026-06-16)**. 1.AC closed
**1.m4** (the full engine stack), so the critical path now reaches **1.U — the end-to-end Node harness (the M2
milestone)**, now unblocked; in parallel, **Lane C** (the 1.m5 sub-spine) continued from 1.V through **1.W**
(the `SessionEventSink`→`RunEventBus` wiring + per-session `sequenceNumber`/`SessionHandle` — ✅ Done, PR #28) to
**1.X** (session persistence, next), with cost-event persistence still a tracked deferral.
(the `SessionEventSink`→`RunEventBus` wiring + per-session `sequenceNumber`/`SessionHandle` — ✅ Done, PR #28)
and **1.X** (session persistence — the `agent_sessions`/`session_messages` tables + `SessionMessageSchema` +
`SessionStore`, data-layer only — ✅ Done, PR #29), leaving **1.Y/1.Z/1.AA** next on Lane C, with cost-event
persistence still a tracked deferral.

> **Multimodal I/O — the shape is landed (1.AD ✅ Done, PR #11, 2026-06-10).** First-class
> image/audio/video I/O (input **and** output, incl. generate-media-by-rule) was decided on 2026-06-08:
Expand Down Expand Up @@ -204,8 +206,11 @@ milestone)**, now unblocked; in parallel, **Lane C** (the 1.m5 sub-spine) contin
> end-to-end). **The Phase-1 engine critical path is complete.** On the additive Lane C, the **`session:*`
> namespace (1.W) is ✅ Done (PR #28, 2026-06-17)** — the `SessionEventSink`→`RunEventBus` adapter (per-session
> `sequenceNumber`, `next`/`emit` overloads keeping the engine run-precise), the `SessionHandle`, and the
> combined `RunOrSessionEventSchema` gate. The remaining Phase-1 work is **additive and off the critical
> path**: Lane C (1.X persistence ‖ 1.Y/1.Z/1.AA) and the 1.m6 multimodal sub-spine (1.AE–1.AH). **Phase 2
> combined `RunOrSessionEventSchema` gate — and **session persistence (1.X) is ✅ Done (PR #29, 2026-06-17)** —
> the `agent_sessions`/`session_messages` tables + migration, `SessionMessageSchema`/`AgentSessionSchema`, and
> the `SessionStore` + domain↔row mappers (data-layer only; engine wiring is 1.Y/1.AA). The remaining Phase-1
> work is **additive and off the critical path**: Lane C (1.Y/1.Z/1.AA) and the 1.m6 multimodal sub-spine
> (1.AE–1.AH). **Phase 2
> (CLI, milestone M3) is unblocked.**

Carry-over hardening is tracked in [deferred-tasks.md](deferred-tasks.md) — pick items up as Phase 1
Expand Down
Loading
Loading