Steadybase
Temporal Workflows

Memory Store Workflow

Long-running durable key-value store workflow for hierarchical memory management.

Memory Store Workflow

The Memory Store is a long-running Temporal workflow that implements Steadybase's hierarchical durable memory system. Unlike the other workflows which execute a sequence of steps, the Memory Store runs continuously, accepting signals to read, write, and compress memory entries.

How It Works

The Memory Store workflow starts once and runs indefinitely, maintaining an in-memory key-value store across four scopes. Temporal's durable execution guarantees that the store survives crashes and restarts.

┌─────────────────────────────────────────────┐
│           Memory Store Workflow              │
│           (long-running)                     │
│                                             │
│  ┌─────────┐  ┌─────────┐  ┌────────────┐  │
│  │  Write   │  │  Read   │  │ Compress   │  │
│  │ Signal   │  │ Query   │  │  Signal    │  │
│  └────┬─────┘  └────┬────┘  └─────┬──────┘  │
│       │              │             │         │
│       ▼              ▼             ▼         │
│  ┌─────────────────────────────────────────┐ │
│  │           In-Memory KV Store            │ │
│  │                                         │ │
│  │  org/     team/    worker/   session/   │ │
│  │  ├─icp    ├─west   ├─sarah   ├─ctx-001 │ │
│  │  ├─pipe   ├─camp   ├─mike    └─ctx-002 │ │
│  │  └─strat  └─rules  └─brian             │ │
│  └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘

Signals

writeMemory

Stores or updates a memory entry:

await handle.signal('writeMemory', {
  scope: 'worker',
  key: 'acme-corp-research',
  value: 'Champion Sarah Kim confirmed Q2 renewal interest...',
  pinned: false
});

Each write increments the entry's version number and updates the lastUpdated timestamp.

compressMemory

Triggers manual compression of stale entries:

await handle.signal('compressMemory', {
  scope: 'worker',           // Optional: compress specific scope
  maxAgeHours: 24            // Optional: override default threshold
});

Compression behavior:

  • Entries older than the threshold (default: 24h) are candidates
  • Pinned entries are never compressed
  • Related entries are merged to reduce count
  • Redundant information is removed

pinMemory

Toggles pin status on an entry:

await handle.signal('pinMemory', {
  scope: 'org',
  key: 'icp-definition',
  pinned: true               // true to pin, false to unpin
});

Queries

readMemory

Read a specific entry by scope and key:

const value = await handle.query('readMemory', {
  scope: 'org',
  key: 'icp-definition'
});
// Returns: { value, version, pinned, lastUpdated }

getAllMemories

List all entries, optionally filtered by scope:

const memories = await handle.query('getAllMemories', {
  scope: 'worker'  // Optional filter
});
// Returns: [{ scope, key, value, version, pinned, lastUpdated }, ...]

getHealth

Memory health metrics:

const health = await handle.query('getHealth');
// Returns: {
//   totalEntries: 847,
//   byScope: { org: 12, team: 34, worker: 645, session: 156 },
//   pinnedCount: 28,
//   compressionRatio: 0.73,
//   oldestEntry: "2026-01-15T...",
//   averageVersion: 3.2
// }

Memory Entry Schema

interface MemoryEntry {
  scope: 'org' | 'team' | 'worker' | 'session';
  key: string;
  value: string;
  pinned: boolean;
  version: number;
  lastUpdated: string;  // ISO 8601 timestamp
}

Auto-Compression

The Memory Store runs periodic compression to prevent unbounded memory growth:

  1. Every 6 hours, scan for entries older than 24 hours
  2. Skip pinned entries
  3. Merge related entries within the same scope
  4. Remove entries that are superseded by newer versions
  5. Log compression results to the activity feed

On this page