-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Problem
When Claude Code runs via Untether (Telegram), only the final assistant text message is visible to the user. Claude Code plugin hooks that fire at session end (Stop hooks) can cause Claude to waste its final response addressing hook concerns instead of outputting user-requested content.
Observed incident
In the BIP project chat, a user asked Claude to outline a document. Claude completed successfully (rc=0, 46.7s) but the user received only:
No files were modified in this interaction — I only read the backlinks doc and outlined it in the chat. The hook fired as a false positive. No context doc updates needed.
The actual document outline was generated in an intermediate assistant turn but was replaced by this hook-response message.
Root cause
Two compounding issues:
1. PitchDocs context-guard-stop.sh false positive
The hook checks git status --porcelain (ALL dirty files) rather than session-modified files. In BIP, freshly-installed PitchDocs infrastructure (.claude/rules/context-quality.md) was untracked and matched the structural pattern, triggering the hook even though no structural changes occurred in the current session.
2. Content displacement in Untether
When a Stop hook returns "decision": "block", Claude gets one more turn. In Untether's single-message model:
- Intermediate assistant text appears as progress edits (replaced by each new turn)
- The
result.resultfrom the finalCompletedEventbecomes the persistent message - If the final turn addresses a hook concern, that meta-commentary replaces the actual content
Cross-project comparison
Same hooks installed in 4 projects — only BIP triggers due to git state:
| Project | Structural dirty? | Context docs dirty? | Blocks? |
|---|---|---|---|
| BIP | YES (untracked hook infra) | NO (CLAUDE.md committed) | YES — false positive |
| Scout | NO | N/A | No |
| Brand Copilot | YES | YES (CLAUDE.md also dirty) | No |
| littlebearapps.com | N/A (no hooks) | N/A | N/A |
Proposed fixes
Untether side (this repo)
Preamble enhancement: Add hook-awareness guidance to the default preamble in runner_bridge.py:
- If hooks fire at session end, your final response MUST still contain the user's
requested content. Hook concerns are secondary — briefly note them AFTER the main
content, never instead of it.
PitchDocs side (separate repo)
- Untether detection: Check
$UNTETHER_SESSIONenv var and skip blocking - False positive fix: Exclude hook infrastructure files from structural check, or use
git diff --name-onlyinstead ofgit status --porcelain - Auto-commit on install: Commit hook infrastructure files during
/context-guard install
Audit document
Full analysis at docs/audits/pitchdocs-context-guard-interference.md