Memory & integrations

Memory across runs, and helpers for Slack, GitHub, and Linear.

A flow doesn't carry its own database or its own Slack client. Memory is what a step can recall from earlier runs. Slack, GitHub, and Linear are helpers on the flow.

Memory

A step declares what it needs from prior runs, and whatever comes back is charged to that step's own budget, itemized in its own journal entry. There's no shared pool it draws from:

import { flow } from '@relayflows/surface';

export default flow('triage', { memory: { script: true } }, async (f) => {
  const priorArt = await f.memory.recall('similar bugs in the billing module');   // HistoryEntry[]
  const why = await f.memory.why('fix the billing race condition');              // TrajectoryEntry[]

  const fix = await f.agent('fixer', {
    task: `Fix the race condition.\n\nRelevant history:\n${priorArt.map((e) => e.prompt).join('\n')}`,
  });

  // learn() is declared but refuses in 2.0.16, pending the journal-backed write.
  f.done('success');
});

A flow's memory reads the local session history already on the machine, so an agent step can cite a fix an engineer already worked out by hand.

What this feature is judged on is retrieval quality, not the plumbing: an agent visibly avoiding a mistake a prior run already made, citation included. In 2.0.16, recall and why read the local ai-hist SQLite database (AI_HIST_DB overrides the default path) with no journal step; learn and memory: { agent: true } refuse until the journal-backed write lands. The memory: { script: true } header makes the reachability check happen — but verified for real, that check runs at flows run time, not at flows check: a flow with an unreachable database passes flows check cleanly and only fails when actually run, with memory_unreachable: Script memory requires the ai-hist Node SDK and a readable SQLite database at AI_HIST_DB (or defaultDbPath()). Run ai-hist sync first.

Integrations

Reach Slack, GitHub, or Linear with a helper. Turn the tool on, then call it:

import { flow } from '@relayflows/surface';

export default flow('release-note', { tools: { slack: true } }, async (f) => {
  const diff = await f.run('git diff main');
  const note = await f.llm`One-line release note for: ${diff}`;

  const receipt = await f.slack.post('#releases', note);
  f.done('success');
});

f.slack, f.github, and f.linear are generated helpers. The receipt a helper returns is the journaled effect, so a retry that posts the same Slack message twice is deduped. Cloud provides a connected provider. Locally, flows check refuses helper_slack.mount_required until that provider is connected, and RELAYFLOWS_SLACK_MOCK=1 records the effect instead of sending it.

Next