claude-code-handoff 1.3.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -45,9 +45,12 @@ Instead of relying on lossy compression or starting from zero, **claude-code-han
45
45
  | `/save-handoff` | Save with options — choose where and how |
46
46
  | `/switch-context <topic>` | Switch between parallel workstreams |
47
47
  | `/delete-handoff` | Delete one or more saved handoffs |
48
+ | `/auto-handoff` | Enable/disable auto-handoff or adjust threshold |
48
49
 
49
50
  The workflow becomes: work until context is full → `/handoff` → `/clear` → `/resume` → continue with full context. No degradation, no amnesia. Just clean handoffs.
50
51
 
52
+ **New in v1.4:** Auto-handoff monitors your context usage and **automatically triggers a handoff** when the transcript reaches 90% capacity — so you never forget to save.
53
+
51
54
  Session state is stored in `.claude/handoffs/` (gitignored) — each developer keeps their own context, no conflicts.
52
55
 
53
56
  ---
@@ -152,13 +155,49 @@ graph TD
152
155
 
153
156
  ---
154
157
 
158
+ ## Auto-Handoff (Context Monitor)
159
+
160
+ The biggest risk with handoffs is **forgetting to save**. Auto-handoff eliminates this by monitoring your transcript size and forcing a save when context is running low.
161
+
162
+ ### How It Works
163
+
164
+ ```mermaid
165
+ flowchart TD
166
+ A[Claude responds] --> B[Stop hook fires]
167
+ B --> C{Transcript > 90%?}
168
+ C -->|No| D[Continue normally]
169
+ C -->|Yes| E{Already triggered?}
170
+ E -->|Yes| D
171
+ E -->|No| F[Create flag file]
172
+ F --> G["Block: force handoff save"]
173
+ G --> H[Claude saves _active.md]
174
+ H --> I["User: /clear → /resume"]
175
+ ```
176
+
177
+ - **Detection**: Measures transcript file size (default 90% of ~500KB max context)
178
+ - **One-shot**: Uses a flag file in `/tmp` to prevent infinite loops — triggers only once per session
179
+ - **Configurable**: Adjust threshold % via `CLAUDE_CONTEXT_THRESHOLD` env var or `/auto-handoff`
180
+ - **Disableable**: Run `/auto-handoff` to turn it off
181
+
182
+ ### Configuration
183
+
184
+ ```bash
185
+ # Change threshold (default: 90% of context)
186
+ export CLAUDE_CONTEXT_THRESHOLD=80 # trigger at 80% instead
187
+
188
+ # Or use the interactive toggle
189
+ /auto-handoff
190
+ ```
191
+
192
+ ---
193
+
155
194
  ## Install
156
195
 
157
196
  ### Option A: npx (recommended)
158
197
 
159
198
  ```bash
160
199
  cd your-project
161
- npx claude-code-handoff@1.3.0
200
+ npx claude-code-handoff@latest
162
201
  ```
163
202
 
164
203
  ### Option B: curl
@@ -182,22 +221,29 @@ cd your-project
182
221
  your-project/
183
222
  └── .claude/
184
223
  ├── commands/
185
- │ ├── handoff.md ← /handoff (auto-save)
186
- │ ├── resume.md ← /resume (interactive picker)
187
- │ ├── save-handoff.md ← /save-handoff (wizard)
188
- │ ├── switch-context.md ← /switch-context (workstream switch)
189
- └── delete-handoff.md ← /delete-handoff (remove handoffs)
224
+ │ ├── handoff.md ← /handoff (auto-save)
225
+ │ ├── resume.md ← /resume (interactive picker)
226
+ │ ├── save-handoff.md ← /save-handoff (wizard)
227
+ │ ├── switch-context.md ← /switch-context (workstream switch)
228
+ ├── delete-handoff.md ← /delete-handoff (remove handoffs)
229
+ │ └── auto-handoff.md ← /auto-handoff (on/off)
190
230
  ├── rules/
191
- └── session-continuity.md ← Auto-loaded behavioral rules
192
- └── handoffs/ Session state (gitignored)
193
- ├── _active.md ← Current workstream
194
- └── archive/ Paused workstreams
231
+ ├── session-continuity.md ← Auto-loaded behavioral rules
232
+ └── auto-handoff.md Auto-handoff trigger rules
233
+ ├── hooks/
234
+ │ ├── context-monitor.sh Stop hook (monitors context size)
235
+ │ └── session-cleanup.sh ← SessionStart hook (cleans old flags)
236
+ ├── settings.json ← Hook configuration
237
+ └── handoffs/ ← Session state (gitignored)
238
+ ├── _active.md ← Current workstream
239
+ └── archive/ ← Paused workstreams
195
240
  ```
196
241
 
197
242
  The installer also:
198
243
  - Creates the full `.claude/handoffs/archive/` directory structure
199
244
  - Adds `.claude/handoffs/` to `.gitignore`
200
245
  - Adds a `Session Continuity` section to `.claude/CLAUDE.md` (creates one if missing)
246
+ - Configures auto-handoff hooks in `.claude/settings.json`
201
247
 
202
248
  ---
203
249
 
@@ -338,12 +384,12 @@ graph TD
338
384
  style SW fill:#7c2d12,stroke:#fb923c,color:#fff
339
385
  ```
340
386
 
341
- | | `/handoff` | `/save-handoff` | `/resume` | `/switch-context` |
342
- |---|---|---|---|---|
343
- | **When** | Before `/clear` | When you need options | Start of session | Mid-session |
344
- | **Interactive** | No | Yes (wizard) | Yes (picker) | No (with arg) |
345
- | **Creates files** | Auto | User chooses | No | Auto |
346
- | **Reads files** | `_active.md` | `_active.md` + `archive/` | All handoffs | `_active.md` + target |
387
+ | | `/handoff` | `/save-handoff` | `/resume` | `/switch-context` | `/auto-handoff` |
388
+ |---|---|---|---|---|---|
389
+ | **When** | Before `/clear` | When you need options | Start of session | Mid-session | Anytime |
390
+ | **Interactive** | No | Yes (wizard) | Yes (picker) | No (with arg) | Yes (wizard) |
391
+ | **Creates files** | Auto | User chooses | No | Auto | Toggle file |
392
+ | **Reads files** | `_active.md` | `_active.md` + `archive/` | All handoffs | `_active.md` + target | Hook config |
347
393
 
348
394
  ---
349
395
 
@@ -418,7 +464,7 @@ rm -rf .claude/handoffs/ # ⚠️ deletes all session history
418
464
  A: Yes. Handoff files are gitignored, so each developer has their own session state. No conflicts.
419
465
 
420
466
  **Q: What happens if I forget to `/handoff` before `/clear`?**
421
- A: The context is lost for that session. The previous handoff is still there you just won't have the latest session recorded.
467
+ A: With auto-handoff enabled (default since v1.4), Claude will automatically save the handoff when the context reaches 90%. Without it, the context is lost for that session the previous handoff is still there, but you won't have the latest session recorded.
422
468
 
423
469
  **Q: Can I have unlimited workstreams?**
424
470
  A: Yes. The `archive/` folder has no limit. Each workstream is a single `.md` file.
package/cli.js CHANGED
@@ -36,27 +36,54 @@ function copyFile(src, dst) {
36
36
  }
37
37
 
38
38
  // 1. Create directories
39
- console.log(` ${YELLOW}[1/8]${NC} Creating directories...`);
39
+ console.log(` ${YELLOW}[1/10]${NC} Creating directories...`);
40
40
  ensureDir(path.join(CLAUDE_DIR, 'commands'));
41
41
  ensureDir(path.join(CLAUDE_DIR, 'rules'));
42
+ ensureDir(path.join(CLAUDE_DIR, 'hooks'));
42
43
  ensureDir(path.join(CLAUDE_DIR, 'handoffs', 'archive'));
43
44
 
44
45
  // 2. Copy commands
45
- console.log(` ${YELLOW}[2/8]${NC} Installing commands...`);
46
+ console.log(` ${YELLOW}[2/10]${NC} Installing commands...`);
46
47
  copyFile('commands/resume.md', path.join(CLAUDE_DIR, 'commands', 'resume.md'));
47
48
  copyFile('commands/save-handoff.md', path.join(CLAUDE_DIR, 'commands', 'save-handoff.md'));
48
49
  copyFile('commands/switch-context.md', path.join(CLAUDE_DIR, 'commands', 'switch-context.md'));
49
50
  copyFile('commands/handoff.md', path.join(CLAUDE_DIR, 'commands', 'handoff.md'));
50
51
  copyFile('commands/delete-handoff.md', path.join(CLAUDE_DIR, 'commands', 'delete-handoff.md'));
52
+ copyFile('commands/auto-handoff.md', path.join(CLAUDE_DIR, 'commands', 'auto-handoff.md'));
51
53
 
52
54
  // 3. Copy rules
53
- console.log(` ${YELLOW}[3/8]${NC} Installing rules...`);
55
+ console.log(` ${YELLOW}[3/10]${NC} Installing rules...`);
54
56
  copyFile('rules/session-continuity.md', path.join(CLAUDE_DIR, 'rules', 'session-continuity.md'));
57
+ copyFile('rules/auto-handoff.md', path.join(CLAUDE_DIR, 'rules', 'auto-handoff.md'));
58
+
59
+ // 4. Install hooks
60
+ console.log(` ${YELLOW}[4/10]${NC} Installing hooks...`);
61
+ copyFile('hooks/context-monitor.sh', path.join(CLAUDE_DIR, 'hooks', 'context-monitor.sh'));
62
+ copyFile('hooks/session-cleanup.sh', path.join(CLAUDE_DIR, 'hooks', 'session-cleanup.sh'));
63
+ fs.chmodSync(path.join(CLAUDE_DIR, 'hooks', 'context-monitor.sh'), 0o755);
64
+ fs.chmodSync(path.join(CLAUDE_DIR, 'hooks', 'session-cleanup.sh'), 0o755);
65
+
66
+ // 5. Configure hooks in settings.json
67
+ console.log(` ${YELLOW}[5/10]${NC} Configuring hooks in settings.json...`);
68
+ const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
69
+ const hooksConfig = {
70
+ Stop: [{ hooks: [{ type: 'command', command: '$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh', timeout: 10 }] }],
71
+ SessionStart: [{ hooks: [{ type: 'command', command: '$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh', timeout: 5 }] }]
72
+ };
73
+ if (fs.existsSync(settingsPath)) {
74
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
75
+ if (!JSON.stringify(settings).includes('context-monitor')) {
76
+ settings.hooks = hooksConfig;
77
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
78
+ }
79
+ } else {
80
+ fs.writeFileSync(settingsPath, JSON.stringify({ hooks: hooksConfig }, null, 2) + '\n');
81
+ }
55
82
 
56
83
  // 4. Create initial _active.md
57
84
  const activePath = path.join(CLAUDE_DIR, 'handoffs', '_active.md');
58
85
  if (!fs.existsSync(activePath)) {
59
- console.log(` ${YELLOW}[4/8]${NC} Creating initial handoff...`);
86
+ console.log(` ${YELLOW}[6/10]${NC} Creating initial handoff...`);
60
87
  fs.writeFileSync(activePath, `# Session Handoff
61
88
 
62
89
  > No active session yet. Use \`/handoff\` or \`/save-handoff\` to save your first session state.
@@ -83,11 +110,11 @@ if (!fs.existsSync(activePath)) {
83
110
  (none)
84
111
  `);
85
112
  } else {
86
- console.log(` ${YELLOW}[4/8]${NC} Handoff already exists, keeping it`);
113
+ console.log(` ${YELLOW}[6/10]${NC} Handoff already exists, keeping it`);
87
114
  }
88
115
 
89
- // 5. Update .gitignore
90
- console.log(` ${YELLOW}[5/8]${NC} Updating .gitignore...`);
116
+ // 7. Update .gitignore
117
+ console.log(` ${YELLOW}[7/10]${NC} Updating .gitignore...`);
91
118
  const gitignorePath = path.join(PROJECT_DIR, '.gitignore');
92
119
  if (fs.existsSync(gitignorePath)) {
93
120
  const content = fs.readFileSync(gitignorePath, 'utf-8');
@@ -98,8 +125,8 @@ if (fs.existsSync(gitignorePath)) {
98
125
  fs.writeFileSync(gitignorePath, '# claude-code-handoff (personal session state)\n.claude/handoffs/\n');
99
126
  }
100
127
 
101
- // 6. Update CLAUDE.md
102
- console.log(` ${YELLOW}[6/8]${NC} Updating CLAUDE.md...`);
128
+ // 8. Update CLAUDE.md
129
+ console.log(` ${YELLOW}[8/10]${NC} Updating CLAUDE.md...`);
103
130
  const claudeMdPath = path.join(CLAUDE_DIR, 'CLAUDE.md');
104
131
  const continuityBlock = `## Session Continuity (MANDATORY)
105
132
 
@@ -123,20 +150,23 @@ if (fs.existsSync(claudeMdPath)) {
123
150
  fs.writeFileSync(claudeMdPath, `# Project Rules\n\n${continuityBlock}\n`);
124
151
  }
125
152
 
126
- // 7. Verify
127
- console.log(` ${YELLOW}[7/8]${NC} Verifying installation...`);
153
+ // 9. Verify
154
+ console.log(` ${YELLOW}[9/10]${NC} Verifying installation...`);
128
155
  let installed = 0;
129
- for (const f of ['resume.md', 'save-handoff.md', 'switch-context.md', 'handoff.md', 'delete-handoff.md']) {
156
+ for (const f of ['resume.md', 'save-handoff.md', 'switch-context.md', 'handoff.md', 'delete-handoff.md', 'auto-handoff.md']) {
130
157
  if (fs.existsSync(path.join(CLAUDE_DIR, 'commands', f))) installed++;
131
158
  }
159
+ let hooksOk = 0;
160
+ if (fs.existsSync(path.join(CLAUDE_DIR, 'hooks', 'context-monitor.sh'))) hooksOk++;
161
+ if (fs.existsSync(path.join(CLAUDE_DIR, 'hooks', 'session-cleanup.sh'))) hooksOk++;
132
162
 
133
163
  console.log('');
134
- console.log(` ${YELLOW}[8/8]${NC} Done!`);
164
+ console.log(` ${YELLOW}[10/10]${NC} Done!`);
135
165
  console.log('');
136
- if (installed === 5) {
137
- console.log(`${GREEN} Installed successfully! (${installed}/5 commands)${NC}`);
166
+ if (installed === 6 && hooksOk === 2) {
167
+ console.log(`${GREEN} Installed successfully! (${installed}/6 commands, ${hooksOk}/2 hooks)${NC}`);
138
168
  } else {
139
- console.log(`${YELLOW} Partial install: ${installed}/5 commands${NC}`);
169
+ console.log(`${YELLOW} Partial install: ${installed}/6 commands, ${hooksOk}/2 hooks${NC}`);
140
170
  }
141
171
  console.log('');
142
172
  console.log(' Commands available:');
@@ -145,10 +175,16 @@ console.log(` ${CYAN}/resume${NC} Resume with wizard`);
145
175
  console.log(` ${CYAN}/save-handoff${NC} Save session state (wizard)`);
146
176
  console.log(` ${CYAN}/switch-context${NC} Switch workstream`);
147
177
  console.log(` ${CYAN}/delete-handoff${NC} Delete handoff(s)`);
178
+ console.log(` ${CYAN}/auto-handoff${NC} Toggle auto-handoff on/off`);
179
+ console.log('');
180
+ console.log(' Auto-handoff:');
181
+ console.log(' Context monitor hook installed (triggers at 90% of context)');
182
+ console.log(` Use ${CYAN}/auto-handoff${NC} to enable/disable or adjust threshold`);
148
183
  console.log('');
149
184
  console.log(' Files:');
150
- console.log(' .claude/commands/ 5 command files');
151
- console.log(' .claude/rules/ session-continuity.md');
185
+ console.log(' .claude/commands/ 6 command files');
186
+ console.log(' .claude/rules/ session-continuity.md, auto-handoff.md');
187
+ console.log(' .claude/hooks/ context-monitor.sh, session-cleanup.sh');
152
188
  console.log(' .claude/handoffs/ session state (gitignored)');
153
189
  console.log('');
154
190
  console.log(` ${YELLOW}Start Claude Code and use /resume to begin.${NC}`);
@@ -0,0 +1,37 @@
1
+ # Auto-Handoff
2
+
3
+ Toggle the automatic handoff context monitor on/off and configure the threshold.
4
+
5
+ ## Instructions
6
+
7
+ ### Step 1: Check current state
8
+
9
+ Check if `.claude/hooks/.auto-handoff-disabled` exists:
10
+ - If exists → currently DISABLED
11
+ - If not exists → currently ENABLED
12
+
13
+ Also read the current `THRESHOLD_PERCENT` value from `.claude/hooks/context-monitor.sh` (the default value in `THRESHOLD_PERCENT=${CLAUDE_CONTEXT_THRESHOLD:-XX}`).
14
+
15
+ ### Step 2: Present wizard
16
+
17
+ Use AskUserQuestion:
18
+ - Question: "Auto-handoff está [ATIVADO/DESATIVADO] (threshold: [XX]%). O que deseja fazer?"
19
+ - Options based on current state:
20
+ - If enabled: "Desativar" / "Ajustar threshold"
21
+ - If disabled: "Ativar" / "Ativar com threshold customizado"
22
+
23
+ ### Step 3: Execute
24
+
25
+ - Toggle: create or delete `.claude/hooks/.auto-handoff-disabled`
26
+ - Threshold: If user chose to adjust threshold, ask with AskUserQuestion:
27
+ - Question: "Qual threshold deseja usar?"
28
+ - Options:
29
+ - "90% (Recomendado)" — Padrão, maximiza o uso do contexto
30
+ - "80%" — Equilíbrio entre espaço e segurança
31
+ - "75%" — Para sessões curtas, salva handoff mais cedo
32
+ - The user can also type a custom value via "Other"
33
+ - Update the `THRESHOLD_PERCENT` default value in `context-monitor.sh` by changing `THRESHOLD_PERCENT=${CLAUDE_CONTEXT_THRESHOLD:-XX}` to the chosen value
34
+
35
+ ### Step 4: Confirm
36
+
37
+ Show current state after change.
@@ -0,0 +1,52 @@
1
+ #!/bin/bash
2
+ # Auto-Handoff Context Monitor
3
+ # Detecta quando o contexto está próximo do limite e força o salvamento do handoff.
4
+ # Usado como hook "Stop" do Claude Code.
5
+
6
+ # Check if auto-handoff is disabled
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ if [ -f "$SCRIPT_DIR/.auto-handoff-disabled" ]; then
9
+ exit 0
10
+ fi
11
+
12
+ # Contexto máximo estimado (bytes). 500KB ~ transcript máximo típico
13
+ MAX_CONTEXT_SIZE=500000
14
+ # Threshold configurável (% do contexto). 90% padrão — maximiza uso do contexto
15
+ THRESHOLD_PERCENT=${CLAUDE_CONTEXT_THRESHOLD:-90}
16
+ THRESHOLD=$((MAX_CONTEXT_SIZE * THRESHOLD_PERCENT / 100))
17
+
18
+ INPUT=$(cat)
19
+ TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty')
20
+ SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty')
21
+
22
+ # Validações
23
+ if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
24
+ exit 0
25
+ fi
26
+
27
+ if [ -z "$SESSION_ID" ]; then
28
+ exit 0
29
+ fi
30
+
31
+ # Verifica tamanho do transcript
32
+ SIZE=$(wc -c < "$TRANSCRIPT_PATH" 2>/dev/null || echo 0)
33
+ SIZE=$(echo "$SIZE" | tr -d ' ')
34
+
35
+ if [ "$SIZE" -lt "$THRESHOLD" ]; then
36
+ exit 0
37
+ fi
38
+
39
+ # Flag para não re-triggerar (prevenção de loop infinito)
40
+ FLAG="/tmp/claude_handoff_triggered_${SESSION_ID}"
41
+ if [ -f "$FLAG" ]; then
42
+ exit 0
43
+ fi
44
+ touch "$FLAG"
45
+
46
+ # Bloqueia e força handoff
47
+ cat <<HOOKEOF
48
+ {
49
+ "decision": "block",
50
+ "reason": "⚠️ AUTO-HANDOFF: O contexto atingiu ${THRESHOLD_PERCENT}% do limite. Você DEVE salvar o handoff AGORA.\n\nSiga estes passos IMEDIATAMENTE:\n1. Analise a conversa inteira e extraia: o que foi feito, próximos passos, arquivos-chave, decisões\n2. Escreva o handoff em .claude/handoffs/_active.md seguindo o template padrão\n3. Diga ao usuário: 'Handoff salvo automaticamente. Use /clear e depois /resume para continuar.'\n\nNÃO continue com outro trabalho até o handoff estar salvo."
51
+ }
52
+ HOOKEOF
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ # Session Cleanup
3
+ # Limpa flag files de sessões anteriores (> 24h) para não acumular lixo no /tmp.
4
+ # Usado como hook "SessionStart" do Claude Code.
5
+
6
+ find /private/tmp -maxdepth 1 -name "claude_handoff_triggered_*" -mmin +1440 -delete 2>/dev/null
7
+ exit 0
package/install.sh CHANGED
@@ -45,26 +45,155 @@ download_file() {
45
45
  }
46
46
 
47
47
  # 1. Create directories
48
- echo -e " ${YELLOW}[1/8]${NC} Creating directories..."
48
+ echo -e " ${YELLOW}[1/10]${NC} Creating directories..."
49
49
  mkdir -p "$CLAUDE_DIR/commands"
50
50
  mkdir -p "$CLAUDE_DIR/rules"
51
+ mkdir -p "$CLAUDE_DIR/hooks"
51
52
  mkdir -p "$CLAUDE_DIR/handoffs/archive"
52
53
 
53
54
  # 2. Download/copy commands
54
- echo -e " ${YELLOW}[2/8]${NC} Installing commands..."
55
+ echo -e " ${YELLOW}[2/10]${NC} Installing commands..."
55
56
  download_file "commands/resume.md" "$CLAUDE_DIR/commands/resume.md"
56
57
  download_file "commands/save-handoff.md" "$CLAUDE_DIR/commands/save-handoff.md"
57
58
  download_file "commands/switch-context.md" "$CLAUDE_DIR/commands/switch-context.md"
58
59
  download_file "commands/handoff.md" "$CLAUDE_DIR/commands/handoff.md"
59
60
  download_file "commands/delete-handoff.md" "$CLAUDE_DIR/commands/delete-handoff.md"
61
+ download_file "commands/auto-handoff.md" "$CLAUDE_DIR/commands/auto-handoff.md"
60
62
 
61
63
  # 3. Download/copy rules
62
- echo -e " ${YELLOW}[3/8]${NC} Installing rules..."
64
+ echo -e " ${YELLOW}[3/10]${NC} Installing rules..."
63
65
  download_file "rules/session-continuity.md" "$CLAUDE_DIR/rules/session-continuity.md"
66
+ download_file "rules/auto-handoff.md" "$CLAUDE_DIR/rules/auto-handoff.md"
64
67
 
65
- # 4. Create initial _active.md if not exists
68
+ # 4. Install hooks (auto-handoff context monitor)
69
+ echo -e " ${YELLOW}[4/10]${NC} Installing hooks..."
70
+ download_file "hooks/context-monitor.sh" "$CLAUDE_DIR/hooks/context-monitor.sh"
71
+ download_file "hooks/session-cleanup.sh" "$CLAUDE_DIR/hooks/session-cleanup.sh"
72
+ chmod +x "$CLAUDE_DIR/hooks/context-monitor.sh"
73
+ chmod +x "$CLAUDE_DIR/hooks/session-cleanup.sh"
74
+
75
+ # 5. Configure hooks in settings.json
76
+ echo -e " ${YELLOW}[5/10]${NC} Configuring hooks in settings.json..."
77
+ SETTINGS_FILE="$CLAUDE_DIR/settings.json"
78
+ if [ -f "$SETTINGS_FILE" ]; then
79
+ # Check if hooks already configured
80
+ if ! grep -q "context-monitor" "$SETTINGS_FILE" 2>/dev/null; then
81
+ # Merge hooks into existing settings.json using jq if available
82
+ if command -v jq &>/dev/null; then
83
+ HOOKS_JSON='{
84
+ "hooks": {
85
+ "Stop": [{"hooks": [{"type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh", "timeout": 10}]}],
86
+ "SessionStart": [{"hooks": [{"type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh", "timeout": 5}]}]
87
+ }
88
+ }'
89
+ jq --argjson hooks "$(echo "$HOOKS_JSON" | jq '.hooks')" '. + {hooks: $hooks}' "$SETTINGS_FILE" > "${SETTINGS_FILE}.tmp" && mv "${SETTINGS_FILE}.tmp" "$SETTINGS_FILE"
90
+ else
91
+ # Fallback: rewrite settings.json preserving existing keys
92
+ echo -e " ${YELLOW} ⚠ jq not found. Adding hooks config manually...${NC}"
93
+ # Read existing content, strip trailing brace, append hooks
94
+ EXISTING=$(cat "$SETTINGS_FILE")
95
+ # Remove trailing } and whitespace
96
+ EXISTING=$(echo "$EXISTING" | sed '$ s/}$//')
97
+ cat > "$SETTINGS_FILE" << 'SETTINGSEOF'
98
+ {
99
+ "hooks": {
100
+ "Stop": [
101
+ {
102
+ "hooks": [
103
+ {
104
+ "type": "command",
105
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh",
106
+ "timeout": 10
107
+ }
108
+ ]
109
+ }
110
+ ],
111
+ "SessionStart": [
112
+ {
113
+ "hooks": [
114
+ {
115
+ "type": "command",
116
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh",
117
+ "timeout": 5
118
+ }
119
+ ]
120
+ }
121
+ ]
122
+ }
123
+ }
124
+ SETTINGSEOF
125
+ # Merge with original using jq-less approach: just add hooks key
126
+ # Since we can't reliably merge JSON without jq, write a complete file
127
+ # preserving the language setting if it exists
128
+ LANG_SETTING=$(echo "$EXISTING" | grep '"language"' | head -1 | sed 's/,$//')
129
+ if [ -n "$LANG_SETTING" ]; then
130
+ cat > "$SETTINGS_FILE" << SETTINGSEOF
131
+ {
132
+ ${LANG_SETTING},
133
+ "hooks": {
134
+ "Stop": [
135
+ {
136
+ "hooks": [
137
+ {
138
+ "type": "command",
139
+ "command": "\$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh",
140
+ "timeout": 10
141
+ }
142
+ ]
143
+ }
144
+ ],
145
+ "SessionStart": [
146
+ {
147
+ "hooks": [
148
+ {
149
+ "type": "command",
150
+ "command": "\$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh",
151
+ "timeout": 5
152
+ }
153
+ ]
154
+ }
155
+ ]
156
+ }
157
+ }
158
+ SETTINGSEOF
159
+ fi
160
+ fi
161
+ fi
162
+ else
163
+ # Create new settings.json with hooks
164
+ cat > "$SETTINGS_FILE" << 'SETTINGSEOF'
165
+ {
166
+ "hooks": {
167
+ "Stop": [
168
+ {
169
+ "hooks": [
170
+ {
171
+ "type": "command",
172
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh",
173
+ "timeout": 10
174
+ }
175
+ ]
176
+ }
177
+ ],
178
+ "SessionStart": [
179
+ {
180
+ "hooks": [
181
+ {
182
+ "type": "command",
183
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh",
184
+ "timeout": 5
185
+ }
186
+ ]
187
+ }
188
+ ]
189
+ }
190
+ }
191
+ SETTINGSEOF
192
+ fi
193
+
194
+ # 6. Create initial _active.md if not exists
66
195
  if [ ! -f "$CLAUDE_DIR/handoffs/_active.md" ]; then
67
- echo -e " ${YELLOW}[4/8]${NC} Creating initial handoff..."
196
+ echo -e " ${YELLOW}[6/10]${NC} Creating initial handoff..."
68
197
  cat > "$CLAUDE_DIR/handoffs/_active.md" << 'HANDOFF'
69
198
  # Session Handoff
70
199
 
@@ -92,11 +221,11 @@ if [ ! -f "$CLAUDE_DIR/handoffs/_active.md" ]; then
92
221
  (none)
93
222
  HANDOFF
94
223
  else
95
- echo -e " ${YELLOW}[4/8]${NC} Handoff already exists, keeping it"
224
+ echo -e " ${YELLOW}[6/10]${NC} Handoff already exists, keeping it"
96
225
  fi
97
226
 
98
- # 5. Add to .gitignore
99
- echo -e " ${YELLOW}[5/8]${NC} Updating .gitignore..."
227
+ # 7. Add to .gitignore
228
+ echo -e " ${YELLOW}[7/10]${NC} Updating .gitignore..."
100
229
  GITIGNORE="$PROJECT_DIR/.gitignore"
101
230
  if [ -f "$GITIGNORE" ]; then
102
231
  if ! grep -q ".claude/handoffs/" "$GITIGNORE" 2>/dev/null; then
@@ -109,8 +238,8 @@ else
109
238
  echo ".claude/handoffs/" >> "$GITIGNORE"
110
239
  fi
111
240
 
112
- # 6. Add to CLAUDE.md
113
- echo -e " ${YELLOW}[6/8]${NC} Updating CLAUDE.md..."
241
+ # 8. Add to CLAUDE.md
242
+ echo -e " ${YELLOW}[8/10]${NC} Updating CLAUDE.md..."
114
243
  CLAUDE_MD="$CLAUDE_DIR/CLAUDE.md"
115
244
  CONTINUITY_BLOCK='## Session Continuity (MANDATORY)
116
245
 
@@ -150,20 +279,23 @@ Use `/handoff` before `/clear`. Use `/resume` to pick up. Use `/switch-context <
150
279
  CLAUDEMD
151
280
  fi
152
281
 
153
- # 7. Summary
154
- echo -e " ${YELLOW}[7/8]${NC} Verifying installation..."
282
+ # 9. Summary
283
+ echo -e " ${YELLOW}[9/10]${NC} Verifying installation..."
155
284
  INSTALLED=0
156
- for f in resume.md save-handoff.md switch-context.md handoff.md delete-handoff.md; do
285
+ for f in resume.md save-handoff.md switch-context.md handoff.md delete-handoff.md auto-handoff.md; do
157
286
  [ -f "$CLAUDE_DIR/commands/$f" ] && INSTALLED=$((INSTALLED + 1))
158
287
  done
288
+ HOOKS_OK=0
289
+ [ -f "$CLAUDE_DIR/hooks/context-monitor.sh" ] && HOOKS_OK=$((HOOKS_OK + 1))
290
+ [ -f "$CLAUDE_DIR/hooks/session-cleanup.sh" ] && HOOKS_OK=$((HOOKS_OK + 1))
159
291
 
160
292
  echo ""
161
- echo -e " ${YELLOW}[8/8]${NC} Done!"
293
+ echo -e " ${YELLOW}[10/10]${NC} Done!"
162
294
  echo ""
163
- if [ "$INSTALLED" -eq 5 ]; then
164
- echo -e "${GREEN} Installed successfully! ($INSTALLED/5 commands)${NC}"
295
+ if [ "$INSTALLED" -eq 6 ] && [ "$HOOKS_OK" -eq 2 ]; then
296
+ echo -e "${GREEN} Installed successfully! ($INSTALLED/6 commands, $HOOKS_OK/2 hooks)${NC}"
165
297
  else
166
- echo -e "${YELLOW} Partial install: $INSTALLED/5 commands${NC}"
298
+ echo -e "${YELLOW} Partial install: $INSTALLED/6 commands, $HOOKS_OK/2 hooks${NC}"
167
299
  fi
168
300
  echo ""
169
301
  echo -e " Commands available:"
@@ -172,10 +304,16 @@ echo -e " ${CYAN}/resume${NC} Resume with wizard"
172
304
  echo -e " ${CYAN}/save-handoff${NC} Save session state (wizard)"
173
305
  echo -e " ${CYAN}/switch-context${NC} Switch workstream"
174
306
  echo -e " ${CYAN}/delete-handoff${NC} Delete handoff(s)"
307
+ echo -e " ${CYAN}/auto-handoff${NC} Toggle auto-handoff on/off"
308
+ echo ""
309
+ echo -e " Auto-handoff:"
310
+ echo -e " Context monitor hook installed (triggers at 90% of context)"
311
+ echo -e " Use ${CYAN}/auto-handoff${NC} to enable/disable or adjust threshold"
175
312
  echo ""
176
313
  echo -e " Files:"
177
- echo -e " .claude/commands/ 5 command files"
178
- echo -e " .claude/rules/ session-continuity.md"
314
+ echo -e " .claude/commands/ 6 command files"
315
+ echo -e " .claude/rules/ session-continuity.md, auto-handoff.md"
316
+ echo -e " .claude/hooks/ context-monitor.sh, session-cleanup.sh"
179
317
  echo -e " .claude/handoffs/ session state (gitignored)"
180
318
  echo ""
181
319
  echo -e " ${YELLOW}Start Claude Code and use /resume to begin.${NC}"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-handoff",
3
- "version": "1.3.2",
3
+ "version": "1.5.0",
4
4
  "description": "Session continuity for Claude Code — 5 slash commands to save, resume, delete, and switch workstreams across /clear",
5
5
  "bin": {
6
6
  "claude-code-handoff": "./cli.js"
@@ -12,6 +12,7 @@
12
12
  "update.sh",
13
13
  "commands/",
14
14
  "rules/",
15
+ "hooks/",
15
16
  "LICENSE",
16
17
  "README.md"
17
18
  ],
@@ -0,0 +1,13 @@
1
+ # Auto-Handoff Rule
2
+
3
+ When you receive a message containing "AUTO-HANDOFF" from a hook, you MUST:
4
+
5
+ 1. IMMEDIATELY stop any current task
6
+ 2. Analyze the full conversation and extract all relevant information
7
+ 3. Write the handoff to `.claude/handoffs/_active.md` following the standard template
8
+ 4. Tell the user the handoff was auto-saved and they should `/clear` then `/resume`
9
+
10
+ Do NOT:
11
+ - Continue with previous work
12
+ - Ask the user for permission first
13
+ - Skip any section of the handoff template
package/uninstall.sh CHANGED
@@ -27,39 +27,61 @@ if [ ! -d "$CLAUDE_DIR" ]; then
27
27
  fi
28
28
 
29
29
  # 1. Remove commands
30
- echo -e " ${YELLOW}[1/4]${NC} Removing commands..."
30
+ echo -e " ${YELLOW}[1/6]${NC} Removing commands..."
31
31
  rm -f "$CLAUDE_DIR/commands/handoff.md"
32
32
  rm -f "$CLAUDE_DIR/commands/resume.md"
33
33
  rm -f "$CLAUDE_DIR/commands/save-handoff.md"
34
34
  rm -f "$CLAUDE_DIR/commands/switch-context.md"
35
35
  rm -f "$CLAUDE_DIR/commands/delete-handoff.md"
36
+ rm -f "$CLAUDE_DIR/commands/auto-handoff.md"
37
+ # Also remove legacy commands if present
38
+ rm -f "$CLAUDE_DIR/commands/auto-handoff-toggle.md"
36
39
  # Also remove legacy Portuguese commands if present
37
40
  rm -f "$CLAUDE_DIR/commands/retomar.md"
38
41
  rm -f "$CLAUDE_DIR/commands/salvar-handoff.md"
39
42
  rm -f "$CLAUDE_DIR/commands/trocar-contexto.md"
40
43
 
41
44
  # 2. Remove rules
42
- echo -e " ${YELLOW}[2/4]${NC} Removing rules..."
45
+ echo -e " ${YELLOW}[2/6]${NC} Removing rules..."
43
46
  rm -f "$CLAUDE_DIR/rules/session-continuity.md"
47
+ rm -f "$CLAUDE_DIR/rules/auto-handoff.md"
44
48
 
45
- # 3. Remove handoffs (with confirmation)
49
+ # 3. Remove hooks
50
+ echo -e " ${YELLOW}[3/6]${NC} Removing hooks..."
51
+ rm -f "$CLAUDE_DIR/hooks/context-monitor.sh"
52
+ rm -f "$CLAUDE_DIR/hooks/session-cleanup.sh"
53
+ rm -f "$CLAUDE_DIR/hooks/.auto-handoff-disabled"
54
+ rmdir "$CLAUDE_DIR/hooks" 2>/dev/null || true
55
+
56
+ # 4. Clean hooks from settings.json
57
+ echo -e " ${YELLOW}[4/6]${NC} Cleaning settings.json..."
58
+ SETTINGS_FILE="$CLAUDE_DIR/settings.json"
59
+ if [ -f "$SETTINGS_FILE" ] && grep -q "context-monitor" "$SETTINGS_FILE" 2>/dev/null; then
60
+ if command -v jq &>/dev/null; then
61
+ jq 'del(.hooks)' "$SETTINGS_FILE" > "${SETTINGS_FILE}.tmp" && mv "${SETTINGS_FILE}.tmp" "$SETTINGS_FILE"
62
+ else
63
+ echo -e " ${YELLOW}⚠ jq not found — remove hooks from .claude/settings.json manually${NC}"
64
+ fi
65
+ fi
66
+
67
+ # 5. Remove handoffs (with confirmation)
46
68
  if [ -d "$CLAUDE_DIR/handoffs" ]; then
47
69
  # Check if there's actual content
48
70
  ACTIVE_CONTENT=$(cat "$CLAUDE_DIR/handoffs/_active.md" 2>/dev/null || echo "")
49
71
  if echo "$ACTIVE_CONTENT" | grep -q "No active session yet\|not started"; then
50
- echo -e " ${YELLOW}[3/4]${NC} Removing handoffs (no session data)..."
72
+ echo -e " ${YELLOW}[5/6]${NC} Removing handoffs (no session data)..."
51
73
  rm -rf "$CLAUDE_DIR/handoffs"
52
74
  else
53
- echo -e " ${YELLOW}[3/4]${NC} ${RED}Handoffs contain session data!${NC}"
75
+ echo -e " ${YELLOW}[5/6]${NC} ${RED}Handoffs contain session data!${NC}"
54
76
  echo -e " Kept: .claude/handoffs/"
55
77
  echo -e " Remove manually with: rm -rf .claude/handoffs/"
56
78
  fi
57
79
  else
58
- echo -e " ${YELLOW}[3/4]${NC} No handoffs directory found"
80
+ echo -e " ${YELLOW}[5/6]${NC} No handoffs directory found"
59
81
  fi
60
82
 
61
- # 4. Clean .gitignore
62
- echo -e " ${YELLOW}[4/4]${NC} Cleaning .gitignore..."
83
+ # 6. Clean .gitignore
84
+ echo -e " ${YELLOW}[6/6]${NC} Cleaning .gitignore..."
63
85
  GITIGNORE="$PROJECT_DIR/.gitignore"
64
86
  if [ -f "$GITIGNORE" ]; then
65
87
  # Remove the handoff lines
package/update.sh CHANGED
@@ -45,20 +45,50 @@ download_file() {
45
45
  }
46
46
 
47
47
  # 1. Update commands
48
- echo -e " ${YELLOW}[1/3]${NC} Updating commands..."
48
+ echo -e " ${YELLOW}[1/5]${NC} Updating commands..."
49
49
  download_file "commands/handoff.md" "$CLAUDE_DIR/commands/handoff.md"
50
50
  download_file "commands/resume.md" "$CLAUDE_DIR/commands/resume.md"
51
51
  download_file "commands/save-handoff.md" "$CLAUDE_DIR/commands/save-handoff.md"
52
52
  download_file "commands/switch-context.md" "$CLAUDE_DIR/commands/switch-context.md"
53
+ download_file "commands/delete-handoff.md" "$CLAUDE_DIR/commands/delete-handoff.md"
54
+ download_file "commands/auto-handoff.md" "$CLAUDE_DIR/commands/auto-handoff.md"
53
55
 
54
56
  # 2. Update rules
55
- echo -e " ${YELLOW}[2/3]${NC} Updating rules..."
57
+ echo -e " ${YELLOW}[2/5]${NC} Updating rules..."
56
58
  download_file "rules/session-continuity.md" "$CLAUDE_DIR/rules/session-continuity.md"
59
+ download_file "rules/auto-handoff.md" "$CLAUDE_DIR/rules/auto-handoff.md"
57
60
 
58
- # 3. Remove legacy Portuguese commands if present
59
- echo -e " ${YELLOW}[3/3]${NC} Cleaning up legacy files..."
61
+ # 3. Update hooks
62
+ echo -e " ${YELLOW}[3/5]${NC} Updating hooks..."
63
+ mkdir -p "$CLAUDE_DIR/hooks"
64
+ download_file "hooks/context-monitor.sh" "$CLAUDE_DIR/hooks/context-monitor.sh"
65
+ download_file "hooks/session-cleanup.sh" "$CLAUDE_DIR/hooks/session-cleanup.sh"
66
+ chmod +x "$CLAUDE_DIR/hooks/context-monitor.sh"
67
+ chmod +x "$CLAUDE_DIR/hooks/session-cleanup.sh"
68
+
69
+ # 4. Ensure hooks are configured in settings.json
70
+ echo -e " ${YELLOW}[4/5]${NC} Checking settings.json hooks..."
71
+ SETTINGS_FILE="$CLAUDE_DIR/settings.json"
72
+ if [ -f "$SETTINGS_FILE" ]; then
73
+ if ! grep -q "context-monitor" "$SETTINGS_FILE" 2>/dev/null; then
74
+ if command -v jq &>/dev/null; then
75
+ HOOKS_JSON='{"Stop":[{"hooks":[{"type":"command","command":"$CLAUDE_PROJECT_DIR/.claude/hooks/context-monitor.sh","timeout":10}]}],"SessionStart":[{"hooks":[{"type":"command","command":"$CLAUDE_PROJECT_DIR/.claude/hooks/session-cleanup.sh","timeout":5}]}]}'
76
+ jq --argjson hooks "$HOOKS_JSON" '. + {hooks: $hooks}' "$SETTINGS_FILE" > "${SETTINGS_FILE}.tmp" && mv "${SETTINGS_FILE}.tmp" "$SETTINGS_FILE"
77
+ echo -e " Hooks added to settings.json"
78
+ else
79
+ echo -e " ${YELLOW}⚠ jq not found — add hooks to .claude/settings.json manually${NC}"
80
+ fi
81
+ else
82
+ echo -e " Hooks already configured"
83
+ fi
84
+ else
85
+ echo -e " ${YELLOW}⚠ settings.json not found — run install first${NC}"
86
+ fi
87
+
88
+ # 5. Remove legacy files if present
89
+ echo -e " ${YELLOW}[5/5]${NC} Cleaning up legacy files..."
60
90
  CLEANED=0
61
- for f in retomar.md salvar-handoff.md trocar-contexto.md; do
91
+ for f in retomar.md salvar-handoff.md trocar-contexto.md auto-handoff-toggle.md; do
62
92
  if [ -f "$CLAUDE_DIR/commands/$f" ]; then
63
93
  rm -f "$CLAUDE_DIR/commands/$f"
64
94
  CLEANED=$((CLEANED + 1))