Operations Manual

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.

Deployed 2026-02-23
Status Active
Host iMac (theoldone)
Model Haiku 4.5
39
Sessions Enriched
61
Total in D1
0
Queue Backlog
6/6
Tests Passing

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.

Mac
Primary workstation (MacBook Air)
SSH: wess-macbook-air
IP: 100.68.110.67
MCP: ~/mcp-servers/hines-mcp
Role: Development, client work
PC
Secondary workstation (Windows i9)
SSH: hinesy-pc
IP: 100.127.152.1
MCP: C:\...\mcp-servers\hines-mcp
Role: Development, design
iMac
Always-on server (Ubuntu 24.04)
SSH: theoldone
IP: 100.108.57.10
Daemon: relay-daemon.service
Role: Brain daemon, enrichment

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.

Step 1
Session Ends
save-session-summary.js extracts metadata from transcript
Step 2
Post Brain Task
Hook sends relay message (from: hook, to: brain) with session data
Step 3
Brain Enriches
iMac daemon pipes metadata through Haiku for semantic summary
Step 4
D1 Updated
Enriched summary overwrites metadata-only entry in sessions namespace
Zero config required Both Mac and PC use the same hooks, same relay, same memory pool. The brain daemon is the only new component -- everything else was already wired up.

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.

Wave 1 -- 1:27 PM CT
Pre-flight Audit + Backup
Two agents in parallel. Found 3 orphaned processes and disabled systemd unit. Full backup created with MD5 checksum verification.
Wave 2 -- 1:30 PM CT
Code Implementation
Builder agent killed orphans, wrote all code changes locally, SCP'd to iMac. Clean compile confirmed.
Wave 3 -- 1:33 PM CT
Code Review
16-item checklist: all PASS. Found BUG-1 (markRead inbox). Team lead fixed it before deployment.
Wave 4 -- 1:36 PM CT
Deploy + Test
Deployer restarted daemon. Tester verified 6/6 tests passing. 39/61 sessions enriched, queue drained to 0.

Bugs Found & Fixed

BUG-1: markRead() wrong inbox for brain messages 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');
BUG-2: Invalid payloads retry indefinitely Low / Won't Fix

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

  1. Session ends on Mac or PC -- save-session-summary.js posts a relay message: { from: "hook", to: "brain", type: "task", metadata: { taskType: "brain:summarize" } }
  2. checkBrainInbox() on the iMac picks it up within 30 seconds
  3. handleBrainTask() parses the JSON payload (session metadata, user messages, assistant excerpts, tool usage, errors)
  4. Builds a prompt and runs it through Haiku via the Claude Agent SDK
  5. 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.

Known limitation If the daemon restarts during the 7-8 AM window, the digest may fire twice. This is harmless since the scratchpad write is idempotent (PUT overwrites), but it wastes a few cents of Haiku. Will be fixed by persisting the date guard to scratchpad.

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 Air
  • pc -- Windows PC
  • imac -- 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:

  1. Tier 1 -- Pinned (up to 2,000 tokens): Entries tagged as pinned, always loaded
  2. Tier 2 -- Focus (up to 2,000 tokens): Entries matching current focus project (set via /focus)
  3. Tier 3 -- Sessions (up to 2,000 tokens): Last 5 session summaries
  4. 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

Emergency rollback If the daemon is crashing or behaving erratically, follow these steps to restore the pre-v4 state.

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)
Backup location /home/hinescreative/relay-daemon/daemon-v3.mjs.backup-20260223 (25,145 bytes, MD5: c69a172f31a14c5412570bbb319992ec)

Troubleshooting

Brain tasks not being processed
  • 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
Sessions not appearing enriched
  • 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)
Daemon keeps crashing
  • 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)
Duplicate daemon processes
  • Check: ps aux | grep daemon | grep -v grep | grep -v dbus
  • Should show exactly ONE node daemon-v3.mjs process
  • 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