aboutsummaryrefslogtreecommitdiff
path: root/hooks/session-clear-resume.sh
blob: 56b7b2f5e005a28b8ec4ebcee2f5423a05bcef7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/usr/bin/env bash
# SessionStart(clear) hook: after /clear, point the fresh context at the
# session-context anchor so a "flush" resumes the same logical session
# instead of starting cold.
#
# Pairs with the /flush skill (rulesets flush/SKILL.md): the skill's
# pre-clear half refreshes .ai/session-context.org in place; this hook is the
# post-clear half that /clear's blank session can't run itself.
#
# General by design — not flush-specific:
#   - anchor present  -> resume (read it, say "flushed.", continue)
#   - anchor absent   -> run the startup workflow (covers a stray /clear)
#
# SessionStart hooks reach the model ONLY through
# hookSpecificOutput.additionalContext — plain stdout goes to the debug log.
# After /clear the injected context loads but the model still waits for the
# user's next message before it acts; that one keystroke is expected.
#
# Wire in ~/.claude/settings.json:
#
#   {
#     "hooks": {
#       "SessionStart": [
#         {
#           "matcher": "clear",
#           "hooks": [
#             { "type": "command",
#               "command": "~/.claude/hooks/session-clear-resume.sh" }
#           ]
#         }
#       ]
#     }
#   }
set -euo pipefail

# Resolve the AI_AGENT_ID-aware anchor path — mirror of
# .ai/scripts/session-context-path, evaluated against the project cwd the
# hook inherits. Fall back to the singleton path when the id is unset.
id="${AI_AGENT_ID:-}"
if [ -n "$id" ]; then
    safe=$(printf '%s' "$id" | tr -c 'A-Za-z0-9._-' '_')
    sc=".ai/session-context.d/${safe}.org"
else
    sc=".ai/session-context.org"
fi

if [ -f "$sc" ]; then
    # On resume, read notes.org standing knowledge (code-repo paths,
    # conventions, key contacts) BEFORE the anchor — the anchor carries
    # session state, notes.org carries the project context a resumed session
    # needs to act correctly. Same "key sections" scope startup uses. Only
    # when notes.org is present; otherwise resume from the anchor alone.
    if [ -f ".ai/notes.org" ]; then
        read_order="First read .ai/notes.org key sections (Project-Specific Context, Active Reminders, Pending Decisions; skip About This File) for the project's standing knowledge — code-repo paths, conventions, key contacts. Then read the session-context anchor at ${sc}"
    else
        read_order="Read the session-context anchor at ${sc}"
    fi
    ctx="A context flush just happened (/clear). ${read_order} — the * Summary (Active Goal, Next Steps) plus the most recent * Session Log entries. Then reply with 'flushed.' on its own line, followed by one line restating the Active Goal and the immediate Next Step, and resume that work. This is a mid-session resume, NOT a fresh start: do not run the startup workflow, do not re-pull rulesets or re-sync templates."
else
    ctx="Session started with no session-context anchor present (.ai/session-context.org absent). Run the startup workflow at .ai/workflows/startup.org."
fi

# Build the whole object in python3 so the additionalContext string is
# JSON-escaped correctly regardless of its content.
python3 -c 'import json,sys; print(json.dumps({"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":sys.argv[1]}}))' "$ctx"