Skip to content

fix: plugin hooks always invoke deepwork via uvx#390

Merged
nhorton merged 4 commits intomainfrom
fix/hook-deepwork-fallback
Apr 20, 2026
Merged

fix: plugin hooks always invoke deepwork via uvx#390
nhorton merged 4 commits intomainfrom
fix/hook-deepwork-fallback

Conversation

@nhorton
Copy link
Copy Markdown
Contributor

@nhorton nhorton commented Apr 20, 2026

Summary

Follow-up to #386 (shipped in v0.13.9). The fallback-based approach in #386 only covered the "deepwork not on PATH" failure mode. In practice a second failure mode is common: a user-level uv tool install deepwork pinned to an older release (observed: 0.10.0) wins PATH lookup outside the project's direnv/nix shell and lacks the hook modules the plugin is asking for — producing Error: Hook 'post_commit_reminder' not found on every Bash tool use.

This PR switches plugin hook scripts to always invoke the CLI via uvx deepwork, matching the MCP server launch in plugins/claude/.mcp.json. Hooks now resolve against the same uvx cache the MCP server populated, so they are guaranteed to match the server's version.

Changes

  • plugins/claude/hooks/post_commit_reminder.sh, deepschema_write.sh, post_compact.sh: remove command -v deepwork guard; always use uvx deepwork …. Also adds set -euo pipefail and fills out header comments on the two scripts that lacked them.
  • plugins/claude/.deepreview: tightens the claude_plugin_hook_deepwork_invocation rule from "must have a uvx deepwork fallback" to "must invoke via uvx deepwork".
  • New PLUG-REQ-001.15: Hook Script CLI Invocation requirement in doc/specs/deepwork/cli_plugins/PLUG-REQ-001-claude-code-plugin.md.
  • flake.nix: drops uv tool install -e from the dev shell — the editable user-level install is redundant now that hooks go through uvx, and it was the mechanism causing the stale ~/.local/bin/deepwork observed on one developer machine.
  • doc/platforms/claude/cli_configuration.md: updates the plugin structure tree to list all five files under plugins/claude/hooks/ (was listing only two). Surfaced by the update_documents_relating_to_src_deepwork review rule.
  • CHANGELOG.md: entries under [Unreleased].

Test plan

  • uv run pytest tests/unit/test_post_commit_reminder_hook.py tests/unit/test_hook_cli.py tests/unit/plugins/test_claude_plugin.py — 68 passed
  • Hook runs cleanly with PATH stripped of deepwork but including uvx — returns {} / exit 0 for non-commit Bash invocations
  • Validated both .deepreview files against deepreview_schema.json
  • Validated PLUG-REQ-001.15 against requirements_file/deepschema.yml (RFC 2119 keywords on every numbered item)
  • Ran the DeepWork /review loop iteratively; all in-scope reviews PASS

🤖 Generated with Claude Code

nhorton and others added 3 commits April 20, 2026 13:33
Switches plugin hook scripts to `uvx deepwork ...` unconditionally,
matching how the MCP server is launched in plugins/claude/.mcp.json.

Rationale: a `command -v deepwork` fallback was not enough. A user-level
`uv tool install deepwork` pinned to an older release (observed: 0.10.0
on a system where the plugin MCP server uses 0.13.8) still wins PATH
lookup outside the project's nix/direnv shell, and that stale binary
lacks newer hook modules — producing "Hook '...' not found" errors on
every Bash tool use, which Claude Code surfaces as a failed hook.

By always using `uvx deepwork`, hooks resolve against the same uvx
cache the MCP server populated, so the hook version is guaranteed to
match the server.

Also adds formal requirement PLUG-REQ-001.15 (Hook Script CLI
Invocation) and tightens the `claude_plugin_hook_deepwork_invocation`
review rule to enforce `uvx deepwork` (not just presence of a fallback).
Fills out header comments and adds `set -euo pipefail` to the two
hook scripts that lacked them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The editable uv tool install is unnecessary now that plugin hooks
invoke deepwork via uvx directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The plugin structure tree only listed hooks.json and
post_commit_reminder.sh, missing deepschema_write.sh, post_compact.sh,
and startup_context.sh. Surfaced by the
update_documents_relating_to_src_deepwork review rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nhorton nhorton force-pushed the fix/hook-deepwork-fallback branch from 7350035 to 7332b2d Compare April 20, 2026 19:36
@nhorton nhorton changed the title fix: plugin hooks fall back to uvx, remove uv tool install fix: plugin hooks always invoke deepwork via uvx Apr 20, 2026
@nhorton nhorton added this pull request to the merge queue Apr 20, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 20, 2026
The reviewer subagent's `tools:` frontmatter used
`mcp__deepwork-dev__*` and `mcp__plugin_deepwork_deepwork__*` wildcards.
Runtime observation (PR #390 e2e merge-queue run): the wildcards are
accepted at parse time but do not reliably match deferred MCP tools
when the subagent tries to invoke them — the runtime responds with
`Error: No such tool available: mcp__deepwork-dev__mark_review_as_passed`
even though the parent agent could call other tools from the same
MCP server.

Replace the wildcards with the single MCP tool the reviewer actually
uses (`mark_review_as_passed`) under both prefixes.

Also add a root `.deepreview` rule `agent_tools_fully_qualified` that
flags any Claude Code agent definition file (`**/agents/*.md`) whose
`tools:` frontmatter contains a wildcard, so the same footgun cannot
regress.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nhorton nhorton added this pull request to the merge queue Apr 20, 2026
Merged via the queue into main with commit 410bb54 Apr 20, 2026
5 checks passed
@nhorton nhorton deleted the fix/hook-deepwork-fallback branch April 20, 2026 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant