Add first-class memory support for spawned sub-agents in OpenClaw, enabling them to maintain persistent context across sessions. This extends the existing session-memory pattern to the multi-agent workflow layer.
Sub-agents are stateless β they wake with zero context each spawn. This creates four critical inefficiencies:
Orchestrators spend 500-1000 tokens per spawn re-explaining:
- Project context and standards
- Role-specific patterns learned from previous sessions
- Past mistakes and their resolutions
- Team conventions and preferences
For a 10-session project, this is 5,000-10,000 wasted tokens on redundant context.
Sub-agents repeat mistakes because they have no recall:
- "We already tried that approach in session 3 β it failed because X"
- "You're the CTO agent β you prefer functional patterns, not OOP"
- "This project uses TypeScript strict mode, not loose"
Each session starts from scratch. No expertise compounds.
Current solution: manually orchestrated shell scripts (squad-memory skill).
Before every spawn:
MEMORY=$(./squad-memory.sh read squad --tokens 500)
openclaw sessions_spawn --task="$MEMORY\n\n$ACTUAL_TASK"After every spawn:
echo "$SESSION_OUTPUT" | extract-memory | ./squad-memory.sh write squad -This works, but it's brittle:
- Orchestrator must remember to inject memory (no enforcement)
- No automatic cleanup or distillation
- Token budget management is manual
- No integration with OpenClaw's context window logic
Because memory is bolted-on via skills, most multi-agent workflows don't use it. The 90% who need it don't know it exists.
Native memory lifecycle hooks in the session/spawn system, mirroring the existing session-memory pattern but for sub-agents.
The squad-memory skill has validated this architecture in production:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Process Memory (permanent, cross-program) β
β β’ How this team works β
β β’ Human's values and preferences β
β β’ Never flushed β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 150 tokens (always loaded)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Program Memory (project-specific expertise) β
β β’ Distilled patterns from session history β
β β’ Role-specific learnings β
β β’ Survives episodic flush β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 200 tokens (auto-distilled)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Episodic Memory (recent session logs) β
β β’ Last N sessions with full context β
β β’ Task-aware relevance filtering β
β β’ Auto-compressed after X days β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 150 tokens (rolling window)
Total default budget: 500 tokens (configurable)
When sessions_spawn creates a session with memory enabled:
// In sessions.ts spawn logic
if (config.subagents.memory.enabled) {
const memory = await loadSquadMemory(squadId, {
tokenBudget: config.subagents.memory.tokenBudget,
role: agentRole,
task: taskDescription // for relevance filtering
});
// Inject into system prompt or task context
systemPrompt = `${memory}\n\n---\n\n${systemPrompt}`;
}When a spawned session completes:
// In session cleanup
if (config.subagents.memory.autoCapture) {
const learnings = extractSessionMemory(sessionOutput);
if (learnings) {
await writeSquadMemory(squadId, learnings);
// Auto-distill every N sessions
if (shouldDistill(squadId)) {
await distillSemanticMemory(squadId);
}
}
}Extraction logic looks for structured output:
## Session Memory
- [ROLE] Learning statement
- [ALL] Cross-cutting patternBackground tasks (similar to session memory cleanup):
- Distillation: Every 3 sessions, extract patterns from episodic β program memory
- Compression: After 7 days, compress old sessions to single-line summaries
- Token enforcement: Warn when memory exceeds budget
{
"agents": {
"defaults": {
"subagents": {
"memory": {
"enabled": true,
"tokenBudget": 500,
"autoCapture": true,
"autoDistillEvery": 3, // sessions
"layers": {
"process": {
"path": "memory/squads/_process",
"tokenBudget": 150
},
"program": {
"enabled": true,
"tokenBudget": 200
},
"episodic": {
"maxSessions": 20,
"compressAfterDays": 7,
"tokenBudget": 150
}
},
"extraction": {
"pattern": "^## Session Memory$",
"roleTagPattern": "^- \\[([A-Z]+)\\] (.+)$"
},
"relevance": {
"taskFiltering": true, // filter by task keywords
"roleFiltering": true // filter by agent role
}
}
}
},
// Per-agent overrides
"family": {
"subagents": {
"memory": {
"tokenBudget": 700 // more context for family agent
}
}
}
}
}# List all squads with memory
openclaw memory squads list
# Read memory for a squad (same output as auto-inject)
openclaw memory squads read <squad-id> [--role ROLE] [--tokens N] [--task "desc"]
# Write memory manually (for testing or manual workflows)
openclaw memory squads write <squad-id> <file|->
# Distill semantic patterns
openclaw memory squads distill <squad-id>
# Compress old sessions
openclaw memory squads compress <squad-id> [--days N]
# Flush memory
openclaw memory squads flush <squad-id> [--keep-semantic]
# Stats
openclaw memory squads statsworkspace/
memory/
squads/
_process/ # Permanent, cross-program
standards.md
{squad-id}/ # Per-squad
history.md # Episodic (session logs)
semantic.md # Program (distilled patterns)
meta.json # Metadata (session count, etc.)
Same structure as squad-memory skill β seamless migration path.
Memory hooks need tight coupling with sessions_spawn lifecycle:
- Pre-spawn: inject before agent wakes
- Post-spawn: capture before session closes
- Context window: integrate with token budget calculations
Skills can't access these hooks cleanly.
OpenClaw already has session-memory for main sessions. This extends the same pattern:
| Feature | Main Session | Sub-Agent (This RFC) |
|---|---|---|
| Persistent memory | β
MEMORY.md |
β
semantic.md |
| Auto-injection | β on wake | β on spawn |
| Daily logs | β
memory/YYYY-MM-DD.md |
β
history.md |
| Config-driven | β | β |
Sub-agents deserve the same first-class support.
Memory consumption should integrate with OpenClaw's context window logic:
- Warn when memory + task exceeds model limits
- Dynamically adjust layer budgets based on available tokens
- Track memory overhead in session metrics
Skills can't access this infrastructure.
Every multi-agent workflow needs memory. Making it opt-out (not opt-in) means:
- 90% adoption vs. 10%
- Standardized memory format across all squads
- Better defaults out-of-the-box
8 commands, 450 lines of bash, tested in production:
- Validates the three-layer architecture
- Proves task-aware filtering reduces noise by 40%
- Shows auto-distillation creates useful patterns
- Demonstrates safe flush-and-archive workflows
This RFC inherits its design, adding:
- Native lifecycle hooks (auto-inject, auto-capture)
- TypeScript implementation (type-safe, maintainable)
- Config-driven behavior (no manual orchestration)
Link: https://github.com/clawbunny/squad-memory
Main sessions already have persistent memory via MEMORY.md:
- Auto-loaded on session start
- Agent can read/write freely
- Separate from daily logs
This RFC mirrors that pattern for sub-agents.
Other multi-agent frameworks have memory systems:
- AutoGen:
ConversableAgentmemory (single-layer, in-memory) - CrewAI:
memoryparameter (basic persistence) - LangGraph:
checkpointer(graph state, not semantic memory)
None have OpenClaw's three-layer architecture (process/program/episodic). This is a differentiator.
- Memory auto-injected on spawn (zero orchestrator changes)
- Session output auto-captured (structured
## Session Memorysection) - CLI commands match skill's API (migration path)
- Config schema documented and validated
- Task-aware filtering reduces token usage by 30%+
- Auto-distillation every 3 sessions (no manual trigger)
- Token budget warnings when memory exceeds limits
- Compression reduces episodic size by 50%+ after 7 days
- 50%+ of multi-agent workflows use memory (measured via telemetry opt-in)
- Zero reported bugs from squad-memory skill migrations
- Documentation includes "Getting Started with Squads" guide using memory
Step 1: Upgrade OpenClaw to version with native memory
Step 2: Move squad directories (same structure)
# Already in correct location β no move needed!
~/.openclaw/workspace/memory/squads/{squad-id}/Step 3: Update config to enable native memory
{
"agents": {
"defaults": {
"subagents": {
"memory": { "enabled": true }
}
}
}
}Step 4: Remove manual squad-memory.sh calls from orchestrator
- const memory = execSync('./squad-memory.sh read squad --tokens 500').toString();
- const task = `${memory}\n\n${actualTask}`;
- await sessions_spawn({ task });
+ await sessions_spawn({ task: actualTask, squadId: 'squad' });
// Memory auto-injected β¨Step 5: Deprecate skill, archive in ClawHub with migration notice
Enable in config (or use default true):
{ "agents": { "defaults": { "subagents": { "memory": { "enabled": true }}}}}Spawn with squadId:
await sessions_spawn({
task: "Design the API",
squadId: "api-team",
role: "architect"
});Memory automatically loads and persists. Zero manual steps.
Option A: Per-agent-id
memory/agents/{agent-id}/- Pro: True agent memory, follows agent across squads
- Con: Can't share knowledge between agents in a squad
Option B: Per-squad-label (proposed)
memory/squads/{squad-id}/- Pro: Squad collective memory, shared expertise
- Con: Same agent in different squads has separate memories
Recommendation: Start with Option B (matches skill design). Add Option A later if needed.
Heuristic (current skill approach):
- Extract lines matching
- [ROLE] pattern - Deduplicate by first 40 chars
- Group by role
- Fast, predictable, no API cost
LLM-powered:
- Send full history to LLM: "Extract key learnings"
- Generates semantic summary
- Better quality, slower, costs tokens
Recommendation: Start with heuristic (proven). Add LLM mode as opt-in later.
If OpenClaw runs in multi-user mode (future):
- Should squads be per-user or shared?
- How to prevent memory leakage between users?
Recommendation: Defer until multi-user support is designed. For now, assume single-user.
If two sessions write memory simultaneously:
- Append-only log (current skill): safe, no conflicts
- Last-write-wins: simple, can lose data
- Merge strategy: complex, overkill for MVP
Recommendation: Start append-only (safe), add locking if needed.
- Add config schema to
agents.defaults.subagents.memory - Implement
loadSquadMemory()in TypeScript (port from shell script) - Implement
writeSquadMemory()with structured extraction - Add pre-spawn injection hook to
sessions_spawn - Add post-spawn capture hook to session cleanup
- Write unit tests for memory layers (process/program/episodic)
- Add
openclaw memory squadsCLI commands - Implement auto-distillation trigger (every 3 sessions)
- Implement auto-compression (after 7 days)
- Add token budget warnings
- Integration tests with real spawns
- Write user guide: "Sub-Agent Memory 101"
- Document config options in README
- Create migration guide for squad-memory skill users
- Add example workflows to docs
- Deprecate squad-memory skill with notice
- Task-aware filtering performance tuning
- Role-based filtering optimization
- LLM-powered distillation (opt-in)
- Memory analytics dashboard
- Telemetry for adoption metrics
Rejected: Skills can't access lifecycle hooks. Manual orchestration is too fragile.
Deferred: Adds complexity and dependencies. File-based works for 90% of cases. Revisit if memory grows beyond 10MB per squad.
Rejected: Squads need shared collective memory. Individual sessions shouldn't be isolated.
Deferred: Useful, but orthogonal. Squad memory solves the multi-agent case. Agent memory can be added later.
| Risk | Impact | Mitigation |
|---|---|---|
| Memory bloat exceeds token limits | High | Token budget enforcement + warnings + auto-compression |
| Stale memory misleads agents | Medium | Flush commands + compression + distillation to keep relevant patterns |
| Migration breaks existing workflows | Medium | Backward-compatible file structure + migration guide + deprecation notice |
| Performance regression on spawn | Low | Memory load is fast (file I/O < 10ms) + async where possible |
Must Have (MVP):
- β Auto-inject memory on spawn (zero manual steps)
- β Auto-capture learnings from session output
- β Three-layer architecture (process/program/episodic)
- β CLI commands for manual control
- β Config-driven behavior
Should Have (V1):
- β Task-aware filtering (load only relevant memory)
- β Role-aware filtering (load only role-specific patterns)
- β Auto-distillation (every 3 sessions)
- β Auto-compression (after 7 days)
- β Migration guide for skill users
Nice to Have (V2+):
- β³ LLM-powered distillation (opt-in)
- β³ Memory analytics dashboard
- β³ Vector search for semantic similarity
- β³ Per-agent memory (in addition to squad memory)
Sub-agent memory is fundamental to useful multi-agent workflows. The current skill-based approach proves the concept works, but it's fragile and under-adopted.
Native support in OpenClaw would:
- Save 500-1000 tokens per spawn (50% reduction in context overhead)
- Enable learning across sessions (mistakes remembered, expertise compounds)
- Make memory the default (90% adoption vs. 10%)
- Extend existing patterns (mirrors
session-memoryfor main sessions)
The architecture is proven in production. The migration path is smooth. The benefit is clear.
This belongs in core.
Prior Art:
- squad-memory skill: https://github.com/clawbunny/squad-memory
- Tested in production by 5-agent squads across 20+ sessions
Questions? Open an issue or comment below.