Problem
Issue #127 landed the context-pressure handoff watchdog as:
- SDK library code in
Gradata/src/gradata/contrib/patterns/handoff.py (HandoffWatchdog, HandoffDoc, pick_latest_unconsumed, consume_handoff)
- Claude Code runtime wiring in two JS hooks:
.claude/hooks/user-prompt/handoff-watchdog.js + .claude/hooks/session-start/handoff-inject.js (commits f02fde5a + 89cd7fae)
The JS hooks are tracked in this repo via a .gitignore carve-out, but that only helps fresh clones of this repo on this machine. A user on a different machine who does pip install gradata gets the Python pattern but not the Claude Code wiring — the watchdog stays dormant because nothing in their .claude/hooks/ calls HandoffWatchdog.check() or reads the bridge file.
Proposed behavior
Extend Gradata/src/gradata/hooks/_installer.py so it can install Claude-Code-specific JS hooks alongside the existing Python hooks:
- Ship the JS hooks as package data. Move (or duplicate)
handoff-watchdog.js and handoff-inject.js into Gradata/src/gradata/hooks/assets/claude_code/ and include them in pyproject.toml [tool.setuptools.package-data].
- Installer copy step. Add a function in
_installer.py that, when the target project has a .claude/hooks/ directory, copies the JS assets into the correct subdirs (user-prompt/, session-start/). Preserve executable bit.
- Settings registration. The two hooks need to fire as
UserPromptSubmit and SessionStart entries in ~/.claude/settings.json. Since settings.json is already owned by _installer.generate_settings(), add new HOOK_REGISTRY-style entries for the JS hooks (probably a new type=js_asset variant, since the current registry only handles Python modules).
- CLI entrypoint.
gradata install-hooks --include-watchdog (or enabled by default at STANDARD profile) triggers the copy + settings update.
- Idempotent. Re-running the installer should not duplicate hook entries or clobber user edits — diff against the existing file first.
Out of scope
- Rewriting the JS hooks in Python (they intentionally read Claude Code's statusline bridge file, which is a JS/Node runtime thing)
- Cross-provider support (only Claude Code has the hook surface today; Cursor/Windsurf equivalents are a separate issue)
Acceptance
References
Problem
Issue #127 landed the context-pressure handoff watchdog as:
Gradata/src/gradata/contrib/patterns/handoff.py(HandoffWatchdog,HandoffDoc,pick_latest_unconsumed,consume_handoff).claude/hooks/user-prompt/handoff-watchdog.js+.claude/hooks/session-start/handoff-inject.js(commitsf02fde5a+89cd7fae)The JS hooks are tracked in this repo via a
.gitignorecarve-out, but that only helps fresh clones of this repo on this machine. A user on a different machine who doespip install gradatagets the Python pattern but not the Claude Code wiring — the watchdog stays dormant because nothing in their.claude/hooks/callsHandoffWatchdog.check()or reads the bridge file.Proposed behavior
Extend
Gradata/src/gradata/hooks/_installer.pyso it can install Claude-Code-specific JS hooks alongside the existing Python hooks:handoff-watchdog.jsandhandoff-inject.jsintoGradata/src/gradata/hooks/assets/claude_code/and include them inpyproject.toml[tool.setuptools.package-data]._installer.pythat, when the target project has a.claude/hooks/directory, copies the JS assets into the correct subdirs (user-prompt/,session-start/). Preserve executable bit.UserPromptSubmitandSessionStartentries in~/.claude/settings.json. Since settings.json is already owned by_installer.generate_settings(), add newHOOK_REGISTRY-style entries for the JS hooks (probably a newtype=js_assetvariant, since the current registry only handles Python modules).gradata install-hooks --include-watchdog(or enabled by default at STANDARD profile) triggers the copy + settings update.Out of scope
Acceptance
Gradata/src/gradata/hooks/assets/claude_code/and are included as package data_installer.pyhas ainstall_js_hooks(project_dir)function (or similar) that copies them into.claude/hooks/when invokedHOOK_REGISTRYextended to include the two JS hooks at the appropriate profile tiergradata install-hooks(or existing install command) copies both files and registers them in settings.json.claude/, invoke the watchdog by simulating a bridge file, confirm the hook emits the expected directiveGRADATA_HANDOFF_THRESHOLD) and a note that the hooks require Claude Code (not provider-agnostic yet)References
f02fde5a(Sprites Work branchfeat/token-optimization-autoresearch)