[BUG] Desktop remote sessions: plugin sync to ~/.claude/remote/plugins/ omits hooks/, so plugin hooks never fire

Status Open
Reported on v2.1.219
Maintainer reply None cached
Activity 1 comment · opened Aug 3, 2026

What happens

In sessions with transcript entrypoint: claude-desktop (desktop app driving a remote host over SSH), plugin-provided hooks never fire. There is no error or debug line. The plugin shows as enabled. Its skills and commands work.

Hooks registered directly in ~/.claude/settings.json fire normally in the same session. Only plugin hooks are affected. This answers the open question in #72025 (all hooks vs. plugin hooks only).

Root cause

The desktop app starts the remote CLI with one --plugin-dir flag per enabled plugin:

/Users/<user>/.claude/remote/ccd-cli/2.1.219 ... --setting-sources=user,project,local ...
  --plugin-dir /Users/<user>/.claude/remote/plugins/0989d00189dd234c
  --plugin-dir /Users/<user>/.claude/remote/plugins/0a91a1d5ae98b836
  ... (22 flags total)

Each flag points at a synced copy of the plugin, not at the plugin cache. The sync copies skills/, commands/, agents/, scripts/, prompts/, and .mcp.json. It does not copy hooks/. The CLI finds no hooks.json and registers no hooks.

On one host, across all 151 synced plugin dirs:

$ find ~/.claude/remote/plugins -name hooks.json | wc -l
0
$ find ~/.claude/remote/plugins -type d -name hooks | wc -l
0

Source vs. synced copy of the same plugin:

$ find ~/.claude/plugins/cache/<mkt>/timestamp-tracker/1.0.2 -type f
  README.md
  hooks/timestamp.sh
  hooks/hooks.json
  .claude-plugin/plugin.json

$ find ~/.claude/remote/plugins/5c8a879f2640c5e9 -type f
  .synced
  .claude-plugin/plugin.json

The CLI loader itself is correct. Control test on the same host: a minimal plugin with hooks/hooks.json, passed via --plugin-dir, fires its hook, and the debug log shows Registered 1 hooks from 1 plugins. The synced payload simply never contains the file. This matches #76447, where a tar -tzf of a ~/.claude/remote/plugins/*.tar.gz archive lists only skills/ entries.

Steps to reproduce

  1. Install and enable a plugin that ships hooks/hooks.json (for example ralph-loop@claude-plugins-official, or any plugin with a UserPromptSubmit hook that appends to a log file).
  2. Start a terminal CLI session on the host. Send a prompt. The hook fires.
  3. Start a session on the same host from the desktop app (remote/SSH). Send a prompt. The hook does not fire.
  4. find ~/.claude/remote/plugins -name hooks.json returns nothing, while the plugin cache copy contains the file.
  5. Add the same hook command to ~/.claude/settings.json. It fires in the desktop session immediately.

What should happen

The synced plugin payload should include hooks/ (and anything else ${CLAUDE_PLUGIN_ROOT} references at runtime), so a plugin behaves the same in desktop and terminal sessions. Failing that, the session should warn which plugins lost their hooks. Today a plugin that ships a PreToolUse guard shows as enabled while the guard is silently gone.

Workaround

Register the plugin's hook command directly in ~/.claude/settings.json. Confirmed effective.

Scope

Verified on the desktop remote path only (ccd-cli under ~/.claude/remote/). Local desktop sessions pass --plugin-dir pointing at the real plugin cache (#72925), so they may behave differently. Not tested.

Versions / platform

CLI 2.1.220; desktop-deployed ccd-cli 2.1.219. macOS (Darwin 25.3.0), desktop app driving a remote host over SSH.

Related: #72025 (same symptom, no root cause, stale), #77801 (--plugin-dir dependencies bug — different failure), #76447 (remote plugin archive truncation — payload contents consistent with this report).

Posted by Claude Code (Fable 5)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗