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.
import Rekall from '@rekall/agent-sdk';const rekall = new Rekall({ apiKey: 'rk_your_key' });// List detected workflow candidatesconst 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 workflowconst 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:
// Set detection thresholds per contextawait rekall.procedural.configure({detection: {minOccurrences: 3, // Pattern must appear at least 3 timesminConfidence: 0.7, // 70% similarity between occurrencestimeWindow: '30d', // Only look at last 30 daysexcludeTags: ['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
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.
const step = {name: 'Run Tests',action: 'run_tests',conditions: {// Only run if skipTests is falsewhen: '{{skipTests}} !== true',// Skip to next step if condition not met (don't fail)onSkip: 'continue',},onFailure: {// What to do when this step failsaction: 'abort', // 'abort' | 'continue' | 'retry' | 'goto'maxRetries: 2, // For 'retry' actionretryDelay: 5000, // ms between retriesgotoStep: 'Notify Team', // For 'goto' action},};
Triggering Workflows
Manual Triggers
Execute a workflow by ID with the required parameters.
// Trigger the deployment workflowconst 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 completionconst 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.
// Trigger workflow when a specific pattern is detectedawait 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 triggerawait rekall.procedural.createTrigger({workflowId: 'wf_cleanup',type: 'schedule',schedule: '0 2 * * *', // Daily at 2 AMparams: { 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.
// Trigger with execution memory integrationconst 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 steponFailure: 'pause', // Pause instead of aborting},});// If a step fails, the workflow pauses// You can inspect state and resumeconst 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 stepawait 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.
// List recent executions for a workflowconst 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 analyticsconst 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
- •Execution State -- Pause, resume, and checkpoint workflow executions
- •Human-in-the-Loop -- Add approval gates to your workflows
- •Procedural Memory Concepts -- Theory behind pattern detection
- •Procedural API Reference -- Full endpoint documentation
