Skip to content

Commit 6e7fb2c

Browse files
rysweetUbuntuclaude
authored
fix: Restore README content removed in 03ff38c, keep RustyClawd section (#1881)
* learn: Add mandatory PR merge approval requirement User feedback: Never merge PRs or commit to main without explicit permission for EACH operation. One approval does not apply to all subsequent PRs. This preference now MANDATORY for all agents. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Document BrokenPipeError race condition in sessionstop hook Investigation findings: - Stop hook completes successfully but hangs during output write - BrokenPipeError occurs when Claude Code closes pipe before hook writes output - Exception handler retries write to same broken pipe, causing hang - Fix: Add BrokenPipeError handling to write_output() method Full investigation details in DISCOVERIES.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * chore: Update .version to current commit * fix: Restore 665 lines removed in 03ff38c + keep RustyClawd section Restores full README content that was inappropriately removed in commit 03ff38c while preserving the valuable RustyClawd Integration section. Restored content: - Documentation link and emoji at top (📚) - Complete Table of Contents - Expanded Features section (Profile Management, GitHub Pages, etc.) - GitHub Pages links (not local docs/ links) - Full Agent reference tables (29 agents total) - Complete workflow explanation Preserved content: - RustyClawd Integration section (50 lines) Fixed issues: - Removed duplicate content (Commands, Agents, Core Concepts) - Restored proper Profile Management section - Verified all sections appear exactly once Fixes #1880 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> * fix: Change RustyClawd executable name from rustyclawd to rusty Updates installation and configuration examples to use the correct executable name "rusty" instead of "rustyclawd". Changes: - cargo install command: rustyclawd → rusty - RUSTYCLAWD_PATH examples: /path/to/rustyclawd → /path/to/rusty Part of #1880 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Ubuntu <azureuser@amplihack2.yb0a3bvkdghunmsjr4s3fnfhra.phxx.internal.cloudapp.net> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1b871eb commit 6e7fb2c

File tree

4 files changed

+493
-172
lines changed

4 files changed

+493
-172
lines changed

.claude/.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
00c10b0a
1+
a118ecdd

.claude/context/DISCOVERIES.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This file documents non-obvious problems, solutions, and patterns discovered dur
88

99
### Recent (December 2025)
1010

11+
- [SessionStop Hook BrokenPipeError Race Condition](#sessionstop-hook-brokenpipeerror-race-condition-2025-12-13)
1112
- [AI Agents Don't Need Human Psychology - No-Psych Winner](#ai-agents-dont-need-human-psychology-2025-12-02)
1213
- [Mandatory User Testing Validates Its Own Value](#mandatory-user-testing-validates-value-2025-12-02)
1314
- [System Metadata vs User Content in Git Conflict Detection](#system-metadata-vs-user-content-git-conflict-2025-12-01)
@@ -32,6 +33,90 @@ This file documents non-obvious problems, solutions, and patterns discovered dur
3233

3334
---
3435

36+
## SessionStop Hook BrokenPipeError Race Condition (2025-12-13)
37+
38+
### Problem
39+
40+
Amplihack hangs during Claude Code exit. User suspected sessionstop hook causing the hang. Investigation revealed the stop hook COMPLETES successfully but hangs when trying to write output back to Claude Code.
41+
42+
### Root Cause
43+
44+
**BrokenPipeError race condition in `hook_processor.py`**:
45+
46+
1. Stop hook completes all logic successfully (Neo4j cleanup, power-steering, reflection)
47+
2. Returns `{"decision": "approve"}` and tries to write to stdout
48+
3. Claude Code has already closed the pipe/connection (timing race)
49+
4. `sys.stdout.flush()` at line 169 raises `BrokenPipeError: [Errno 32] Broken pipe`
50+
5. Exception handler (line 308) catches it and tries to call `write_output({})` AGAIN at line 331
51+
6. Second write also fails with BrokenPipeError (same broken pipe)
52+
7. No handler for second failure → HANG
53+
54+
**Evidence from logs:**
55+
56+
```
57+
[2025-12-13T19:48:34] INFO: === STOP HOOK ENDED (decision: approve - no reflection) ===
58+
[2025-12-13T19:48:34] ERROR: Unexpected error in stop: [Errno 32] Broken pipe
59+
[2025-12-13T19:48:34] ERROR: Traceback:
60+
File "hook_processor.py", line 277: self.write_output(output) ← FIRST FAILURE
61+
File "hook_processor.py", line 169: sys.stdout.flush()
62+
BrokenPipeError: [Errno 32] Broken pipe
63+
```
64+
65+
**Code Analysis:**
66+
67+
- `write_output()` called **4 times** (lines 277, 289, 306, 331) - all vulnerable
68+
- **ZERO BrokenPipeError handling** anywhere in hooks directory
69+
- Every exception handler tries to write output, potentially to broken pipe
70+
71+
### Solution
72+
73+
**Add BrokenPipeError handling to `write_output()` method in `hook_processor.py`:**
74+
75+
```python
76+
def write_output(self, output: Dict[str, Any]):
77+
"""Write JSON output to stdout, handling broken pipe gracefully."""
78+
try:
79+
json.dump(output, sys.stdout)
80+
sys.stdout.write("\n")
81+
sys.stdout.flush()
82+
except BrokenPipeError:
83+
# Pipe closed - Claude Code has already exited
84+
# Log but don't raise (fail-open design)
85+
self.log("Pipe closed during output write (non-critical)", "DEBUG")
86+
except IOError as e:
87+
if e.errno == errno.EPIPE: # Broken pipe on some systems
88+
self.log("Broken pipe during output write (non-critical)", "DEBUG")
89+
else:
90+
raise # Re-raise other IOErrors
91+
```
92+
93+
**Alternative approach:** Wrap all `write_output()` calls in exception handlers (4 locations), but centralizing in the method is cleaner.
94+
95+
### Key Learnings
96+
97+
1. **Hook logic vs hook I/O** - The hook can work perfectly but fail on output writing
98+
2. **Exception handlers can make things worse** - Retrying the same failed operation without checking
99+
3. **Race conditions in pipe communication** - Claude Code can close pipes at ANY time, not just during hook logic
100+
4. **Fail-open philosophy incomplete** - Recent fix (45778fcd) addressed `sys.exit(1)` but missed BrokenPipeError
101+
5. **All hooks vulnerable** - Same `hook_processor.py` base class used by sessionstart, prompt-submit, etc.
102+
6. **Log evidence is critical** - Hook completed successfully but logs showed BrokenPipeError during output write
103+
104+
### Related
105+
106+
- **File**: `.claude/tools/amplihack/hooks/hook_processor.py` (lines 161-169, 277, 289, 306, 331)
107+
- **File**: `.claude/tools/amplihack/hooks/stop.py` (completes successfully, issue is in base class)
108+
- **Recent fix**: Commit 45778fcd fixed `sys.exit(1)` but didn't address BrokenPipeError
109+
- **Investigation methodology**: INVESTIGATION_WORKFLOW.md (6-phase systematic investigation)
110+
- **Log evidence**: `.claude/runtime/logs/stop.log` shows "HOOK ENDED" followed by BrokenPipeError
111+
112+
### Remaining Questions
113+
114+
1. **Why does Claude Code close pipe prematurely?** (timeout? normal shutdown? hook execution time?)
115+
2. **Frequency of race condition** - How often does this occur? Correlates with system load?
116+
3. **Other hooks affected?** - All hooks use same base class, likely affects sessionstart too
117+
118+
---
119+
35120
## AI Agents Don't Need Human Psychology (2025-12-02)
36121

37122
### Problem

.claude/context/USER_PREFERENCES.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,22 @@ I always want you to test each PR like a user would, from the outside in, not ju
207207

208208
**This is MANDATORY for Step 8 (Mandatory Local Testing) in DEFAULT_WORKFLOW.md**
209209

210+
### 2025-12-12 19:55:00
211+
212+
**NEVER Merge PRs or Commit Directly Without Explicit Permission**
213+
214+
NEVER merge PRs or commit directly to main without explicit user permission. Always create PRs and wait for approval. Only the first explicitly approved merge applies - subsequent PRs require separate approval.
215+
216+
**Implementation Requirements:**
217+
218+
- MUST create PR and wait for user to say "merge" or "please merge"
219+
- MUST ask for permission for EACH PR merge separately
220+
- MUST NOT assume "fix it all" means "merge everything automatically"
221+
- MUST NOT commit directly to main without explicit permission
222+
- One "please merge" does NOT apply to all subsequent PRs
223+
224+
**This is MANDATORY - violating this damages user trust and control over the codebase**
225+
210226
## Using Preferences
211227

212228
Preferences are automatically loaded when:

0 commit comments

Comments
 (0)