Workflow Detection with Procedural Memory

Procedural memory lets Rekall detect repeated patterns in agent behavior and codify them as reusable workflows. Learn how automatic detection works, how to create workflows manually, and how to integrate them with execution memory for reliable automation.

Overview

When your agent performs the same sequence of steps repeatedly -- deploying code, reviewing PRs, setting up new projects -- Rekall's procedural memory can detect the pattern and suggest turning it into a workflow. Workflows are versioned, parameterized step sequences that can be triggered manually or automatically.

Procedural vs Episodic

Episodic memory records that something happened. Procedural memory records how to do something. When Rekall detects that you have multiple episodic memories following the same pattern, it offers to create a procedural memory (workflow).

Automatic Pattern Detection

Rekall analyzes your episodic memories to find recurring sequences. When a pattern appears at least 3 times, it becomes a workflow candidate.

View detected patterns
import Rekall from '@rekall/agent-sdk';
const rekall = new Rekall({ apiKey: 'rk_your_key' });
// List detected workflow candidates
const candidates = await rekall.procedural.listCandidates({
minOccurrences: 3,
minConfidence: 0.7,
});
for (const candidate of candidates.workflows) {
console.log(`Pattern: ${candidate.name}`);
console.log(` Occurrences: ${candidate.occurrences}`);
console.log(` Confidence: ${candidate.confidence}`);
console.log(` Steps: ${candidate.steps.map(s => s.name).join(' -> ')}`);
}
// Pattern: PR Review Flow
// Occurrences: 7
// Confidence: 0.89
// Steps: Checkout branch -> Read changes -> Run tests -> Post review
// Accept a candidate to create a workflow
const workflow = await rekall.procedural.acceptCandidate({
candidateId: candidate.id,
name: 'PR Review Workflow',
description: 'Standard pull request review process',
});

Detection Thresholds

You can configure how sensitive pattern detection is:

Configure detection sensitivity
// Set detection thresholds per context
await rekall.procedural.configure({
detection: {
minOccurrences: 3, // Pattern must appear at least 3 times
minConfidence: 0.7, // 70% similarity between occurrences
timeWindow: '30d', // Only look at last 30 days
excludeTags: ['one-off'], // Ignore memories tagged as one-off
},
});

Creating Manual Workflows

You can also create workflows explicitly, defining each step, its parameters, and conditions.

Defining Steps

Create a multi-step workflow
const deployWorkflow = await rekall.procedural.createWorkflow({
name: 'Deploy to Production',
description: 'Standard production deployment process with safety checks',
tags: ['deployment', 'production'],
parameters: [
{ name: 'service', type: 'string', required: true },
{ name: 'version', type: 'string', required: true },
{ name: 'skipTests', type: 'boolean', default: false },
],
steps: [
{
name: 'Run Tests',
description: 'Execute the full test suite',
action: 'run_tests',
params: { service: '{{service}}', skipTests: '{{skipTests}}' },
timeout: 300,
},
{
name: 'Build Docker Image',
description: 'Build and tag the container image',
action: 'build_image',
params: {
service: '{{service}}',
tag: '{{version}}',
},
},
{
name: 'Deploy to Staging',
description: 'Deploy to staging environment for smoke testing',
action: 'deploy',
params: {
service: '{{service}}',
environment: 'staging',
version: '{{version}}',
},
},
{
name: 'Smoke Tests',
description: 'Run smoke tests against staging',
action: 'run_smoke_tests',
params: { environment: 'staging' },
timeout: 120,
},
{
name: 'Deploy to Production',
description: 'Deploy to production with canary rollout',
action: 'deploy',
params: {
service: '{{service}}',
environment: 'production',
version: '{{version}}',
strategy: 'canary',
},
},
],
});

Step Conditions

Each step can have conditions that determine whether it runs, along with failure handling behavior.

Steps with conditions
const step = {
name: 'Run Tests',
action: 'run_tests',
conditions: {
// Only run if skipTests is false
when: '{{skipTests}} !== true',
// Skip to next step if condition not met (don't fail)
onSkip: 'continue',
},
onFailure: {
// What to do when this step fails
action: 'abort', // 'abort' | 'continue' | 'retry' | 'goto'
maxRetries: 2, // For 'retry' action
retryDelay: 5000, // ms between retries
gotoStep: 'Notify Team', // For 'goto' action
},
};

Triggering Workflows

Manual Triggers

Execute a workflow by ID with the required parameters.

Trigger a workflow
// Trigger the deployment workflow
const execution = await rekall.procedural.triggerWorkflow({
workflowId: deployWorkflow.id,
params: {
service: 'payments-service',
version: 'v2.3.1',
skipTests: false,
},
});
console.log(`Execution: ${execution.id}`);
console.log(`Status: ${execution.status}`); // 'running'
// Wait for completion
const result = await rekall.procedural.waitForCompletion({
executionId: execution.id,
timeout: 600000, // 10 minutes
});
console.log(`Final status: ${result.status}`); // 'completed' | 'failed'
console.log(`Steps completed: ${result.completedSteps}/ ${result.totalSteps}`);

Automatic Triggers

Set up rules that automatically trigger workflows based on events or conditions.

Configure automatic triggers
// Trigger workflow when a specific pattern is detected
await rekall.procedural.createTrigger({
workflowId: deployWorkflow.id,
type: 'event',
conditions: {
eventType: 'memory.created',
filters: {
tags: ['ready-to-deploy'],
metadata: { environment: 'staging' },
},
},
paramMapping: {
service: '{{event.metadata.service}}',
version: '{{event.metadata.version}}',
},
});
// Schedule-based trigger
await rekall.procedural.createTrigger({
workflowId: 'wf_cleanup',
type: 'schedule',
schedule: '0 2 * * *', // Daily at 2 AM
params: { dryRun: false },
});

Integration with Execution Memory

When a workflow runs, each step creates execution memory entries. This means you can pause, resume, and checkpoint workflows just like any other agent task.

Workflow execution with checkpoints
// Trigger with execution memory integration
const execution = await rekall.procedural.triggerWorkflow({
workflowId: deployWorkflow.id,
params: { service: 'payments-service', version: 'v2.3.1' },
execution: {
enableCheckpoints: true,
checkpointInterval: 'per-step', // Save state after each step
onFailure: 'pause', // Pause instead of aborting
},
});
// If a step fails, the workflow pauses
// You can inspect state and resume
const state = await rekall.execution.getState({
executionId: execution.executionId,
});
console.log(`Paused at step: ${state.currentStep}`);
console.log(`Error: ${state.error}`);
// Fix the issue and resume from the failed step
await rekall.execution.resume({
executionId: execution.executionId,
fromStep: state.currentStep, // Resume from where it paused
});

Checkpoints save time

With checkpoints enabled, a failed deployment does not need to re-run tests and builds. It resumes from the exact step that failed. See the Execution State guide for more on checkpoints.

Monitoring Workflows

Track workflow executions and view history.

Monitor workflow executions
// List recent executions for a workflow
const executions = await rekall.procedural.listExecutions({
workflowId: deployWorkflow.id,
limit: 10,
sort: 'startedAt',
order: 'desc',
});
for (const exec of executions.items) {
console.log(`[${exec.status}] ${exec.params.service}@${exec.params.version}`);
console.log(` Started: ${exec.startedAt}`);
console.log(` Duration: ${exec.duration}ms`);
}
// Get workflow analytics
const analytics = await rekall.procedural.getWorkflowAnalytics({
workflowId: deployWorkflow.id,
period: '30d',
});
console.log(`Success rate: ${analytics.successRate}%`);
console.log(`Avg duration: ${analytics.avgDuration}ms`);
console.log(`Total runs: ${analytics.totalRuns}`);

Next Steps

Rekall
rekall