Auto-Dreaming¶
sb brain dream synthesizes cross-session insights from episodic memory. By
default it runs only when you invoke it. Two automation hooks turn dreaming
into a background process so the Insight store stays fresh without manual
nudges.
Path 1 — Session-stop hook¶
brain/mcp/hooks/session_stop.py runs at the end of every Claude Code
session. After logging the session_end event it will, by default, kick off
a short-lookback dream cycle:
- Lookback: 1 day — just the last batch of activity.
- Throttle: 6 hours — a timestamp in
state_dir/.last_dream_atblocks back-to-back invocations across rapidly-closed sessions. - Failure mode: silent. The hook always lets the session exit.
The hook is registered with async: true in .claude/settings.json, so the
dream cycle never blocks the Claude Code UI.
Env flags¶
| Variable | Default | Effect |
|---|---|---|
SB_HOOK_DREAM |
on | Set to 0, false, no, or off to skip dream. |
SB_HOOK_DREAM_LOOKBACK_DAYS |
1 |
Days of episodic history to scan. |
SB_HOOK_DREAM_MIN_INTERVAL_HOURS |
6 |
Minimum gap between cycles. Set to 0 to disable throttling. |
SB_HOOK_DREAM_INSTRUCTIONS |
unset | Free-text steering (e.g. "focus on coding-style preferences; ignore one-off debugging notes"). Mirrors Anthropic Dreams' instructions field; capped at 4096 chars. |
Drop SB_HOOK_DREAM=0 into your shell rc to opt out without editing the
project settings.
Path 2 — Cron / launchd¶
scripts/sb-dream-cron.sh runs sb brain dream --lookback-days 7 --json and
appends results to logs/dream.log. The 7-day window catches medium-term
patterns that a 1-day session hook would miss.
Example crontab¶
# Dream daily at 03:00 local
0 3 * * * /opt/SecondBrain/scripts/sb-dream-cron.sh
# Custom lookback window
0 3 * * 0 /opt/SecondBrain/scripts/sb-dream-cron.sh 30 # weekly deep dream
# Steered cycle (lookback + free-text instructions)
0 3 * * * /opt/SecondBrain/scripts/sb-dream-cron.sh 7 "Focus on coding-style preferences; ignore one-off debugging notes"
Example launchd plist (macOS)¶
Drop into ~/Library/LaunchAgents/com.secondbrain.dream.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.secondbrain.dream</string>
<key>ProgramArguments</key>
<array>
<string>/opt/SecondBrain/scripts/sb-dream-cron.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key><integer>3</integer>
<key>Minute</key><integer>0</integer>
</dict>
<key>RunAtLoad</key><false/>
</dict>
</plist>
Then launchctl load ~/Library/LaunchAgents/com.secondbrain.dream.plist.
How they compose¶
The two paths are intentionally non-overlapping:
- The hook keeps short-term patterns hot — what happened today.
- The cron sweeps medium-term patterns — what's recurred this week.
- The manual
sb brain dream --lookback-days 30(or higher) remains the right tool for deep retrospectives.
Both paths write through the same Dreamer.dream() code, so insights
deduplicate against each other automatically (cosine threshold from
intelligence.dedup_threshold, default 0.85).
Steering a cycle¶
sb brain dream, the hook, and the cron wrapper all accept free-text
instructions that mirror Anthropic Dreams' instructions field. Use it to
bias what the synthesis pays attention to:
The string is normalized (stripped + truncated to 4096 chars) and folded
into the LLM synthesis prompt; the heuristic path records it on the
DreamReport and event log for auditability even without a provider.
Reorganizing the LTM (non-destructive rebuild)¶
sb brain dream surfaces cross-session insights. The companion
sb brain reorganize command rewrites the LTM itself, mirroring
Anthropic Dreams' core semantic:
each cycle produces a reviewable proposal of mutations (merge similar
entries, deprecate stale ones, supersede contradicted ones). The live
store is never touched until you explicitly accept the proposal.
sb brain reorganize # propose merges (stricter threshold)
sb brain reorganize --threshold 0.85 # cast a wider net
sb brain reorganize --instructions "focus on infra notes"
sb brain reorganize --dry-run # preview, do not save
sb brain reorganize list # pending proposals
sb brain reorganize show <proposal_id> # full mutation list
sb brain reorganize accept <proposal_id> # apply atomically
sb brain reorganize reject <proposal_id> --reason "false positives"
What the heuristic catches¶
- Merge clusters: groups of active LTMs with bag-of-words cosine
similarity ≥
--threshold(default0.92). All members of a cluster collapse into one new active LTM; originals becomedeprecatedwithmerged_intolinks pointing at the replacement. - Pinned + static LTMs are excluded unconditionally — they're treated as canonical and never proposed for merge.
Safety contract¶
- A new cycle always lands in
status='pending'. No mutation hits the live store until you accept. acceptapplies mutations independently; a mutation whose sources were deprecated since the proposal was created is recorded asskippedrather than failing the batch.- An accepted or rejected proposal can't be re-applied — generate a fresh proposal instead.
- Every proposal create / accept / reject lands in the event log with the proposal id and outcome.
The reorganize flow is not wired into the cron / hook automation
yet. Accepting mutations is a deliberate human decision; the
session-stop hook and cron continue to run insight-surfacing
sb brain dream cycles only.
Inspecting results¶
sb brain insights --status active --limit 20
sb brain insights --type gap # unresolved/blocked patterns
sb brain insights --query "<topic>" # search by text
tail -f logs/dream.log # watch cron output
The dream_after_session_end event in the event log records every
hook-triggered cycle (look it up via sb or query the event log table
directly).