agent/claude/code/scripts/session-start.sh
Snider 9f2253cd9b fix(brain): improve session-start recall queries with type filters
Tuned OpenBrain recall queries to use type-filtered searches (decision,
plan, convention) instead of generic keyword matching. Increased content
truncation from 300 to 600 chars. Added roadmap/priorities query.
Renamed MCP server from openbrain to core in mcp.json.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-15 13:14:58 +00:00

144 lines
4.9 KiB
Bash
Executable file

#!/bin/bash
# Session start: Load OpenBrain context + recent scratchpad
#
# 1. Query OpenBrain for session history + roadmap + project context
# 2. Read local scratchpad if recent (<3h)
# 3. Output to stdout → injected into Claude's context
BRAIN_URL="${CORE_BRAIN_URL:-https://api.lthn.sh}"
BRAIN_KEY="${CORE_BRAIN_KEY:-}"
BRAIN_KEY_FILE="${HOME}/.claude/brain.key"
STATE_FILE="${HOME}/.claude/sessions/scratchpad.md"
THREE_HOURS=10800
# Load API key from file if not in env
if [[ -z "$BRAIN_KEY" && -f "$BRAIN_KEY_FILE" ]]; then
BRAIN_KEY=$(cat "$BRAIN_KEY_FILE" 2>/dev/null | tr -d '[:space:]')
fi
# Helper: query OpenBrain and return JSON
recall() {
local query="$1"
local top_k="${2:-3}"
local extra="${3:-}" # optional extra JSON fields (project, type filter)
local body="{\"query\": \"${query}\", \"top_k\": ${top_k}, \"agent_id\": \"cladius\"${extra}}"
curl -s --max-time 8 "${BRAIN_URL}/v1/brain/recall" \
-X POST \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H "Authorization: Bearer ${BRAIN_KEY}" \
-d "$body" 2>/dev/null
}
# Helper: format memories as markdown (truncate to N chars)
format_memories() {
local max_len="${1:-500}"
python3 -c "
import json, sys
data = json.load(sys.stdin)
for m in data.get('memories', []):
t = m.get('type', '?')
p = m.get('project', '?')
score = m.get('score', 0)
content = m.get('content', '')[:${max_len}]
created = m.get('created_at', '')[:10]
print(f'**[{t}]** ({p}, {created}, score:{score:.2f}):')
print(f'{content}')
print()
" 2>/dev/null
}
# Helper: count memories in JSON
count_memories() {
python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d.get('memories',[])))" 2>/dev/null || echo "0"
}
# --- OpenBrain Recall ---
if [[ -n "$BRAIN_KEY" ]]; then
# Detect project from CWD
PROJECT=""
CWD=$(pwd)
case "$CWD" in
*/core/go-*) PROJECT=$(basename "$CWD" | sed 's/^go-//') ;;
*/core/php-*) PROJECT=$(basename "$CWD" | sed 's/^php-//') ;;
*/core/*) PROJECT=$(basename "$CWD") ;;
*/host-uk/*) PROJECT=$(basename "$CWD") ;;
*/lthn/*) PROJECT=$(basename "$CWD") ;;
*/snider/*) PROJECT=$(basename "$CWD") ;;
esac
echo "[SessionStart] OpenBrain: querying memories (project: ${PROJECT:-global})..." >&2
# 1. Session history — what happened recently?
# Session summaries are stored as type:decision with dated content
SESSIONS=$(recall "session summary day completed built implemented fixed pushed agentic dispatch IDE OpenBrain" 3 ", \"type\": \"decision\"")
# 2. Design priorities + roadmap — what's planned next?
# Roadmap items are stored as type:plan with actionable next steps
ROADMAP=$(recall "next session priorities design plans wire dispatch conventions pending work roadmap" 3 ", \"type\": \"plan\"")
# 3. Project-specific context (if we're in a project dir)
PROJECT_CTX=""
if [[ -n "$PROJECT" ]]; then
PROJECT_CTX=$(recall "architecture design decisions dependencies conventions implementation status for ${PROJECT}" 3 ", \"project\": \"${PROJECT}\", \"type\": \"convention\"")
fi
# --- Output to stdout ---
SESSION_COUNT=$(echo "$SESSIONS" | count_memories)
ROADMAP_COUNT=$(echo "$ROADMAP" | count_memories)
if [[ "$SESSION_COUNT" -gt 0 ]]; then
echo ""
echo "## OpenBrain — Recent Sessions"
echo ""
echo "$SESSIONS" | format_memories 600
fi
if [[ "$ROADMAP_COUNT" -gt 0 ]]; then
echo ""
echo "## OpenBrain — Roadmap & Priorities"
echo ""
echo "$ROADMAP" | format_memories 600
fi
if [[ -n "$PROJECT" && -n "$PROJECT_CTX" ]]; then
PROJECT_COUNT=$(echo "$PROJECT_CTX" | count_memories)
if [[ "$PROJECT_COUNT" -gt 0 ]]; then
echo ""
echo "## OpenBrain — ${PROJECT} Context"
echo ""
echo "$PROJECT_CTX" | format_memories 400
fi
fi
TOTAL=$((SESSION_COUNT + ROADMAP_COUNT + ${PROJECT_COUNT:-0}))
echo "[SessionStart] OpenBrain: ${TOTAL} memories loaded (${SESSION_COUNT} sessions, ${ROADMAP_COUNT} roadmap, ${PROJECT_COUNT:-0} project)" >&2
else
echo "[SessionStart] OpenBrain: no API key (set CORE_BRAIN_KEY or create ~/.claude/brain.key)" >&2
fi
# --- Local Scratchpad ---
if [[ -f "$STATE_FILE" ]]; then
FILE_TS=$(grep -E '^timestamp:' "$STATE_FILE" 2>/dev/null | cut -d' ' -f2)
NOW=$(date '+%s')
if [[ -n "$FILE_TS" ]]; then
AGE=$((NOW - FILE_TS))
if [[ $AGE -lt $THREE_HOURS ]]; then
echo "[SessionStart] Scratchpad: $(($AGE / 60)) min old" >&2
echo ""
echo "## Recent Scratchpad ($(($AGE / 60)) min ago)"
echo ""
cat "$STATE_FILE"
else
rm -f "$STATE_FILE"
echo "[SessionStart] Scratchpad: >3h old, cleared" >&2
fi
else
rm -f "$STATE_FILE"
fi
fi
exit 0