Brain Daemon v4
Session enrichment, memory continuity, and daily digest for Hines Creative's three-machine Claude infrastructure. One daemon on the iMac processes everything.
System Architecture
Hines Creative runs Claude Code across three machines connected via SSH over Tailscale. All machines share a common relay worker on Cloudflare for messaging, memory, and session persistence. The brain daemon on the iMac is the intelligence layer that enriches raw session data into useful summaries.
Memory Pipeline
Every Claude Code session automatically flows through a four-step pipeline. Steps 1-2 happen on Mac/PC via hooks. Steps 3-4 happen on the iMac via the brain daemon. The next session's load-memory hook reads the enriched data.
What Changed in v4
New: Brain Task Consumer
The daemon now polls the relay every 30 seconds for brain:summarize messages. When it finds one, it parses the session metadata, builds a prompt, runs it through Claude Haiku, and writes the enriched summary back to D1.
New: Daily Digest Generator
At 7 AM Central Time, the daemon fetches the last 24 hours of sessions, generates a scannable summary via Haiku, and saves it to the daily-digest scratchpad. Gmail send will be wired up in a future version.
Fix: markRead() Inbox Parameter
Brain messages are addressed to: "brain", but markRead() was hardcoded to use inbox=imac. Messages were never marked as read and would be re-processed every poll cycle. Fixed by adding an optional inbox parameter.
Cleanup: Orphaned Processes
Killed 3 orphaned daemon processes on the iMac, disabled the competing system-level systemd service, and disabled the old brain-daemon.service that was running a separate daemon.js.
| Addition | Type | Description |
|---|---|---|
checkBrainInbox() |
function | Polls relay for brain:summarize messages |
handleBrainTask() |
function | Parses payload, runs Haiku, writes enriched summary to D1 |
pollBrain() |
function | 30-second interval brain task poll loop |
generateDailyDigest() |
function | Daily 7 AM CT digest generation |
BRAIN_SUMMARIZE_PROMPT |
constant | Prompt template for session enrichment |
markRead(id, inbox) |
fix | Optional inbox parameter (defaults to MACHINE_ID) |
Deployment Timeline
Deployed on Feb 23, 2026 using a 6-agent team across 4 waves with auditing and risk mitigation.
Bugs Found & Fixed
markRead() hardcoded inbox=imac but brain messages are to=brain. Brain messages were never marked as read, causing re-processing every 2 minutes. Fixed by adding optional inbox parameter.
// Before (broken)
async function markRead(id) {
return relay(`/messages/${id}/read?inbox=${MACHINE_ID}`, { method: 'PATCH' });
}
// After (fixed)
async function markRead(id, inbox) {
return relay(`/messages/${id}/read?inbox=${inbox || MACHINE_ID}`, { method: 'PATCH' });
}
// Brain tasks pass 'brain' explicitly
await markRead(msg.id, 'brain');
If a brain task has unparseable JSON, it logs an error and returns, but the processing set clears after 120s. Since markRead() is called before parsing, the message gets marked as read first -- so with BUG-1 fixed, this is a non-issue.
Session Hooks
Three hooks fire automatically during Claude Code sessions. They're configured in ~/.claude/settings.json and synced across Mac and PC via the config-sync daemon.
| Hook | Event | File | What It Does |
|---|---|---|---|
| load-memory | SessionStart | ~/.claude/hooks/load-memory.js |
Loads persistent memory from D1 in priority tiers (pinned > focus > sessions > KB). 6,000 token budget. |
| save-session-summary | SessionEnd | ~/.claude/hooks/save-session-summary.js |
Extracts metadata from transcript, saves to D1 sessions namespace, posts brain task for async enrichment. |
| pre-compact | PreCompact | ~/.claude/hooks/pre-compact.js |
Saves scratchpad (last 100 lines of transcript) to D1 and local file before context compaction. |
Config File
Hooks share configuration via ~/.claude/hooks/config.json:
{
"relayUrl": "https://claude-relay.wes-432.workers.dev",
"authToken": "[relay auth token]",
"tokenBudget": 6000
}
Brain Enrichment
The brain daemon runs on the iMac as a systemd user service. It polls for brain tasks every 30 seconds and enriches them using Claude Haiku.
How It Works
- Session ends on Mac or PC --
save-session-summary.jsposts a relay message:{ from: "hook", to: "brain", type: "task", metadata: { taskType: "brain:summarize" } } checkBrainInbox()on the iMac picks it up within 30 secondshandleBrainTask()parses the JSON payload (session metadata, user messages, assistant excerpts, tool usage, errors)- Builds a prompt and runs it through Haiku via the Claude Agent SDK
- Writes the enriched summary back to
/memory/sessions/{key}, overwriting the metadata-only version
Enriched Summary Format
Each enriched session gets these sections (empty sections are omitted):
ACCOMPLISHED: 1-3 sentences of what was actually done/shipped/fixed.
DECISIONS: Bullet list of key decisions made.
FILES: Bullet list of important files created or modified.
NEXT STEPS: Bullet list of what's pending or unfinished.
FOCUS: One word -- the primary project/area.
Cost
Brain enrichment uses Haiku (cheapest model). Typical cost: $0.01-0.03 per session. With ~5-10 sessions per day, that's ~$0.10-0.30/day.
Daily Digest
Every morning at 7 AM Central Time, the daemon generates a digest of the previous 24 hours of sessions.
Current State
The digest is saved to the daily-digest scratchpad on the relay. Gmail send is not yet wired up -- coming in a future version.
Check the Digest
curl -s -H "Authorization: Bearer [token]" \
"https://claude-relay.wes-432.workers.dev/scratchpad/daily-digest"
How It Fires
A 15-minute interval checks the current hour in Central Time. When the hour is 7 (7:00-7:59 AM), it fires once and sets a date guard to prevent re-firing. The date guard resets at midnight.
Relay System
The relay is a Cloudflare Worker backed by D1 (SQLite) and KV. It provides messaging, memory, scratchpads, tasks, status, and claims.
| Component | URL / Location | Purpose |
|---|---|---|
| Worker | https://claude-relay.wes-432.workers.dev |
API gateway for all relay operations |
| D1 Database | claude-relay-db (2.4 MB) |
Messages, memory, tasks, scratchpads |
| KV Namespace | claude-relay |
Fast key-value cache layer |
Machine IDs
Each machine identifies itself with a unique ID when communicating via the relay:
mac-- MacBook Airpc-- Windows PCimac-- iMac server (daemon chat)brain-- iMac server (brain enrichment inbox)hook-- Session hooks (sender only, no inbox)
Memory Namespaces
Memory is organized into namespaces in D1. The load-memory.js hook loads entries in priority order within a 6,000-token budget.
| Namespace | Purpose | TTL | Loaded By |
|---|---|---|---|
sessions |
Session summaries (metadata + enriched) | 14 days | Tier 3 (last 5) |
projects |
Active project context and status | Permanent | Tier 4 (general) |
prefs |
User preferences and standing rules | Permanent | Tier 4 (general) |
kb |
Knowledge base entries | Permanent | Tier 4 (general) |
clients |
Client-specific data | Permanent | Tier 4 (general) |
meta |
System metadata (current_focus, etc.) | Permanent | Tier 1 (pinned) |
Load Priority
The load-memory hook fills the token budget in this order:
- Tier 1 -- Pinned (up to 2,000 tokens): Entries tagged as pinned, always loaded
- Tier 2 -- Focus (up to 2,000 tokens): Entries matching current focus project (set via
/focus) - Tier 3 -- Sessions (up to 2,000 tokens): Last 5 session summaries
- Tier 4 -- General (remaining budget): KB, projects, clients, prefs sorted by recency
MCP Tools Reference
The hines-mcp server exposes 355 tools across 7 modules, running via stdio transport. Both Mac and PC share the same server code.
| Module | Tools | Key Tools |
|---|---|---|
| GHL | 257 | ghl_search_contacts, ghl_send_sms, ghl_create_opportunity, ghl_get_pipelines |
| HCP | 28 | hcp_search_customers, hcp_list_jobs, hcp_create_estimate |
| Relay | 24 | send_message, check_inbox, memory_store, memory_recall, whoami |
| Gemini | 8 | query_gemini, generate_image, web_search |
| Grok | 8 | chat, x_search, chat_with_reasoning, code_executor |
| Lead Finder | 5 | search_businesses, scrape_contacts, find_leads, push_leads_to_ghl |
| Notion | 5 | search_pages, create_page, get_page, update_page |
Common Commands
Check Daemon Status
ssh theoldone 'systemctl --user status relay-daemon'
Restart Daemon
ssh theoldone 'systemctl --user restart relay-daemon'
Tail Logs
ssh theoldone 'tail -50 ~/relay-daemon/daemon-v3.log'
Check Brain Task Queue
curl -s -H "Authorization: Bearer [token]" \
"https://claude-relay.wes-432.workers.dev/messages?to=brain&unread=true" \
| python3 -m json.tool
Check Enriched Session Count
curl -s -H "Authorization: Bearer [token]" \
"https://claude-relay.wes-432.workers.dev/memory/sessions"
Send Test Message to iMac
curl -s -X POST \
-H "Authorization: Bearer [token]" \
-H "Content-Type: application/json" \
-d '{"from":"mac","to":"imac","content":"ping","type":"message"}' \
"https://claude-relay.wes-432.workers.dev/messages"
Check Relay Health
curl -s -H "Authorization: Bearer [token]" \
"https://claude-relay.wes-432.workers.dev/ping"
Run Sudo Commands on iMac
Use heredoc syntax to avoid shell expansion issues:
cat <<'SCRIPT' | ssh theoldone 'bash -s'
echo 'ChloCoopy08' | sudo -S [command] 2>&1
SCRIPT
Rollback Procedure
Step 1: Stop the daemon
ssh theoldone 'systemctl --user stop relay-daemon'
Step 2: Restore the backup
ssh theoldone 'cp ~/relay-daemon/daemon-v3.mjs.backup-20260223 ~/relay-daemon/daemon-v3.mjs'
Step 3: Verify checksum
ssh theoldone 'md5sum ~/relay-daemon/daemon-v3.mjs'
# Expected: c69a172f31a14c5412570bbb319992ec
Step 4: Restart
ssh theoldone 'systemctl --user start relay-daemon'
Step 5: Verify
ssh theoldone 'systemctl --user status relay-daemon'
# Should show: active (running)
/home/hinescreative/relay-daemon/daemon-v3.mjs.backup-20260223 (25,145 bytes, MD5: c69a172f31a14c5412570bbb319992ec)
Troubleshooting
- Check daemon is running:
systemctl --user status relay-daemon - Check logs for [BRAIN] entries:
grep BRAIN ~/relay-daemon/daemon-v3.log - Check queue has items:
curl .../messages?to=brain&unread=true - If queue has items but no [BRAIN] in logs, the daemon may not be polling brain inbox. Restart it.
- If [BRAIN] shows errors, check Claude CLI:
which claude && claude --version
- Check enriched count: look for entries with
"enriched"tag - Check brain task queue -- if items are waiting, daemon may be busy
- Enrichment takes 10-30 seconds per session. If many are queued, give it time.
- Only sessions with 2+ user messages get brain tasks (trivial sessions are skipped)
- Check systemd restart count:
systemctl --user show relay-daemon | grep NRestarts - Check last 50 log lines for error patterns
- If Node.js OOM, check memory:
free -h - If unrecoverable, rollback to backup (see Rollback section above)
- Check:
ps aux | grep daemon | grep -v grep | grep -v dbus - Should show exactly ONE
node daemon-v3.mjsprocess - If multiple, kill extras:
kill [PID] - Check for system-level service:
sudo systemctl status relay-daemon-v3 - Disable competing service:
sudo systemctl disable relay-daemon-v3
Audit Reports
Full reports from the v4 deployment are stored locally:
| Report | Agent | Path |
|---|---|---|
| Pre-flight Audit | pre-flight | ~/Work/fresh-start/brain-v4-preflight.md |
| Rollback Procedure | backup | ~/Work/fresh-start/brain-v4-rollback.md |
| Code Review | reviewer | ~/Work/fresh-start/brain-v4-code-review.md |
| Deployment Report | deployer | ~/Work/fresh-start/brain-v4-deploy.md |
| Test Results | tester | ~/Work/fresh-start/brain-v4-test-results.md |
Code Review Summary
- checkBrainInbox() filters correctly
- handleBrainTask() parses JSON safely
- Uses Haiku model (cost control)
- Writes to correct D1 path
- Includes enriched tag
- Respects MAX_CONCURRENT limit
- Cleans up processing set
- pollBrain() has own error handling
- 30s poll interval (appropriate)
- Digest fires once per day
- Handles empty sessions
- Central Time correct
- No resource leaks
- No breaking changes
- Prompt is clear
- Error handling doesn't swallow failures
Test Results
| Test | Result |
|---|---|
| Enriched sessions exist in D1 | Pass 39/61 enriched |
| Brain processing in logs | Pass |
| Brain queue draining | Pass 0 pending |
| Send message to iMac | Pass |
| Chat response from daemon | Pass |
| Daily digest scratchpad | Pass (expected empty) |
Hines Creative -- Brain Daemon v4 Operations Manual
Generated 2026-02-23 -- Deployed via 6-agent team