Working Memory & Integration Protocol
How subsystems connect at runtime via SCRATCHPAD.md
How the subsystems actually connect at runtime.
The Problem
We have pieces:
- Sentiment engine — standalone TS library, 90 tests, extracts mood + maps strategy
- Memory search — Gemini embeddings on workspace MD, MCP/the vector store for semantic
- Model router — documented skill, not yet automated
- HEARTBEAT.md — manual checklist
But no wiring. The cognitive architecture shows arrows between boxes. This document describes what flows through those arrows, and how OpenClaw — which currently has no middleware layer — can host these subsystems without requiring core changes.
Constraint: OpenClaw Is Not Extensible (Yet)
OpenClaw doesn't have a plugin hook for "run this before each response." We can't inject middleware. What we can do:
- System prompt injection — SOUL.md, AGENTS.md, and workspace files are loaded each session
- Cron/heartbeat preprocessing — tasks that run on schedule and write context files
- Skills — tools + instructions loaded when relevant
- Session state files — JSON/MD files in workspace that persist between turns
This means integration must be file-mediated. Subsystems write to files; the main session reads those files via injected context.
Architecture: The Scratchpad Pattern
┌──────────────────────────────────────────────────────┐
│ PRE-TURN PIPELINE │
│ (runs as cron/heartbeat or session-start script) │
│ │
│ 1. Read recent messages (from session transcript) │
│ 2. Run sentiment-engine → SentimentState │
│ 3. Run memory search → relevant memories │
│ 4. Assemble → write to SCRATCHPAD.md │
└──────────────────────────────────────────────────────┘
│
▼ (file written to workspace)
┌──────────────────────────────────────────────────────┐
│ workspace/SCRATCHPAD.md │
│ ┌────────────────────────────────────────────────┐ │
│ │ ## Current State (auto-generated, do not edit) │ │
│ │ **Mood:** frustrated (0.71) — concise mode │ │
│ │ **Strategy:** direct, no preamble, action-first│ │
│ │ **Active context:** debugging k8s deployment │ │
│ │ **Time context:** late night, suggest deferral │ │
│ │ **Relevant memories:** [3 items] │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
│
▼ (loaded as project context)
┌──────────────────────────────────────────────────────┐
│ Main session reads SCRATCHPAD.md at turn start │
│ → adjusts tone, depth, approach accordingly │
└──────────────────────────────────────────────────────┘
Why a File?
- OpenClaw injects workspace files into project context automatically
- No core changes needed — just add SCRATCHPAD.md to the workspace
- Any subsystem can write to it; the LLM reads it naturally
- Debugging is trivial —
cat SCRATCHPAD.md - If the scratchpad is stale (>30 min), ignore it — the LLM can tell
Why Not Just Embed Strategy in SOUL.md?
SOUL.md is static. The whole point of sentiment analysis is dynamic adjustment. "Be concise when I'm frustrated" is a rule; actually detecting frustration in real-time and surfacing it as context is a system.
SCRATCHPAD.md Schema
# SCRATCHPAD.md — Working Memory (auto-generated)
<!-- Updated: 2026-02-06T03:00:00+11:00 -->
<!-- TTL: 30 minutes — ignore if older -->
## Emotional Context
- **Primary:** frustrated (0.71)
- **Secondary:** urgent (0.55)
- **Valence:** -0.4 (negative) | **Arousal:** 0.7 (high)
- **Confidence:** 0.82
## Response Strategy
- **Style:** concise — lead with answer, skip preamble
- **Tone:** direct — no hedging, no "I think maybe"
- **Verbosity:** minimal — they'll ask for more if needed
- **Preamble:** NO
## Active Context
- Working on: k8s deployment debugging (mcp-memory-service)
- Last topic: CUDA container missing libcublas
- Session gap: 2h (short, no context resurrection needed)
## Relevant Memories
- Ray prefers a specific cluster config path (not sudo)
- mcp-memory-service v10.0 deployed on CPU tag (CUDA failed)
- Lab disk at ~87% (improved from 96%)
## Time Context
- Local time: 01:30 AEDT (late night)
- Note: Consider suggesting deferral for non-urgent work
The Assembler: scripts/assemble-scratchpad.ts
A lightweight script that:
- Accepts recent messages as input (JSON on stdin or file path)
- Runs
@stev3/sentiment-engineto get state + strategy - Queries MCP memory for relevant context (top 3-5 hits based on recent topics)
- Reads today's daily memory file for active context
- Writes
SCRATCHPAD.mdto workspace
// Pseudocode — not production
import { analyze } from '@stev3/sentiment-engine';
import { mapStrategy } from '@stev3/sentiment-engine';
import { execSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';
interface AssemblerInput {
messages: Message[]; // recent conversation
utcOffsetHours: number; // 11 for AEDT
}
function assembleScratchpad(input: AssemblerInput): string {
// 1. Sentiment analysis
const state = analyze(input.messages, {
utcOffsetHours: input.utcOffsetHours,
});
const strategy = mapStrategy(state);
// 2. Memory search (via the tool proxy or direct)
const recentTopics = extractTopics(input.messages);
const memories = searchMemories(recentTopics);
// 3. Daily context
const today = new Date().toISOString().slice(0, 10);
const dailyFile = `memory/${today}.md`;
const dailyContext = readFileSync(dailyFile, 'utf-8').slice(-2000); // last 2KB
// 4. Time context
const localHour = (new Date().getUTCHours() + input.utcOffsetHours) % 24;
const timeNote = localHour >= 23 || localHour < 7
? 'Late night — suggest deferral for non-urgent work'
: localHour < 10
? 'Morning — fresh start, good for complex work'
: 'Active hours — standard engagement';
// 5. Assemble
return formatScratchpad({
state,
strategy,
memories,
dailyContext,
timeNote,
updatedAt: new Date().toISOString(),
});
}
Trigger Modes
Mode 1: Heartbeat-Driven (MVP)
Every heartbeat (~30min), run the assembler with messages from the last session. Write SCRATCHPAD.md. The main session picks it up as injected context.
Pros: Zero infrastructure, works today Cons: 30-min staleness, heartbeat might not have recent messages
Mode 2: Cron Pre-Process
A cron job that runs every 10 minutes during active hours:
{
"schedule": { "kind": "every", "everyMs": 600000 },
"payload": {
"kind": "agentTurn",
"message": "Run scripts/assemble-scratchpad.ts with recent session messages. Write output to SCRATCHPAD.md.",
"timeoutSeconds": 30
},
"sessionTarget": "isolated"
}
Pros: More current, isolated from main session Cons: Burns tokens every 10 min, can't access main session messages from isolated session
Mode 3: OpenClaw Event Hook (Future)
If OpenClaw adds pre-turn hooks or middleware:
# hypothetical openclaw config
hooks:
preTurn:
- script: scripts/assemble-scratchpad.ts
input: $RECENT_MESSAGES
timeout: 5s
Pros: Real-time, no staleness, minimal overhead Cons: Doesn't exist yet
Recommended: Mode 1 (MVP) → Mode 3 (Future)
Start with heartbeat. The 30-min staleness is acceptable because:
- Emotional state changes slowly in most conversations
- The LLM can detect obvious mood shifts without the scratchpad
- The scratchpad provides background context, not real-time steering
When OpenClaw supports hooks, migrate to Mode 3 for real-time.
Integration with Other Subsystems
Memory Gardener → Scratchpad
Memory gardener consolidates daily files → MEMORY.md. The scratchpad assembler reads MEMORY.md for relevant memories. They're complementary:
Daily files → [Memory Gardener] → MEMORY.md → [Scratchpad Assembler] → SCRATCHPAD.md
↓
Main session reads
Model Router → Scratchpad
The scratchpad could include routing hints:
## Routing Hint
- Content sensitivity: LOW (technical discussion, no PII)
- Task complexity: MEDIUM (debugging, not architecture)
- Suggested model: standard (no need for local-only)
This is informational — the LLM can't actually switch its own model mid-turn. But it could influence tool choices (e.g., "use perplexity for research" vs "search locally first").
Wake Patterns → Scratchpad
Wake patterns (morning brief, deadline whisper) could write their output to SCRATCHPAD.md sections:
## Proactive Alerts
- 📅 Calendar: "Team standup" in 1h 45m
- 📧 Email: 2 unread from the consultancy (flagged important)
- ⚠️ Lab disk: 89% (rising — investigate)
What This Doesn't Solve
-
Real-time sentiment — The scratchpad is a snapshot. Within a conversation, the LLM still needs to read the room itself. The scratchpad provides the starting point.
-
Multi-turn strategy shifts — If Ray starts frustrated but calms down, the scratchpad won't update mid-conversation. The LLM must adapt. Consider: should the scratchpad include a "trajectory" note? ("Frustration was 0.8 at start, trending down")
-
Token cost — SCRATCHPAD.md adds to every turn's context window. Keep it under 500 tokens. The schema above is ~200 tokens.
-
Feedback loop — How do we know the strategy is working? Options:
- Ray explicitly says "too verbose" or "that was perfect"
- Conversation length/resolution speed as proxy
- A "strategy audit" in dream cycles: review recent sessions, check if scratchpad advice was followed and whether outcomes were good
Open Questions
-
Message access: Can the assembler actually get recent messages? Heartbeat has conversation history, but cron (isolated) sessions don't. The
sessions_historytool might bridge this. -
Feedback calibration: The sentiment engine calibrates from message patterns. Should the scratchpad also capture response effectiveness metrics for future calibration?
-
Multiple humans: In group chats, whose sentiment matters? Should the scratchpad track per-user state?
-
SCRATCHPAD.md vs JSON: MD is human-readable but messy to parse. JSON is structured but ugly in context injection. Could use frontmatter YAML + prose body.
-
Staleness indicator: Should the LLM ignore a scratchpad older than N minutes? Or is "last known state" always better than nothing?
Implementation Path
Phase 1: Manual Scratchpad (This Week)
- Write
SCRATCHPAD.mdmanually during heartbeats - Just mood + strategy + time context
- See if it actually changes my behavior
Phase 2: Sentiment Integration (When sentiment-engine is packaged)
npm link @stev3/sentiment-enginein workspace- Write
scripts/assemble-scratchpad.ts - Run from heartbeat
Phase 3: Full Assembly (After memory gardener)
- Add memory search integration
- Add wake pattern alerts
- Add routing hints
- Target: <500 tokens total
Phase 4: Real-Time (When OpenClaw supports it)
- Migrate to pre-turn hook
- Per-turn freshness
- Feedback loop integration
Related Dreams
- Cognitive Architecture — The unified system this protocol enables
- Sentiment Archaeology — What flows through working memory: emotional context
- Sentiment Implementation Proposal — The three-layer system that writes to SCRATCHPAD.md
- Consciousness as Bug — Building a system that models itself = the strange loop as design choice
Created: 2026-02-06 03:00 (Dream Cycle #4) Status: Design. The bridge between standalone libraries and runtime behavior. Key insight: File-mediated integration is the only practical path given OpenClaw's current architecture. The SCRATCHPAD.md pattern turns any subsystem into context injection without core changes.