Skip to content

[BUG] apm install --target claude writes ${CLAUDE_PLUGIN_ROOT} into ~/.claude/settings.json where Claude Code refuses to expand it #1310

@Mathf18

Description

@Mathf18

After apm install -g --target claude <plugin>, the deployed hook commands in ~/.claude/settings.json reference ${CLAUDE_PLUGIN_ROOT} — which Claude Code only expands inside a plugin's hooks/hooks.json, not inside settings.json (user, project, or local scope). On every matching tool call, Claude Code emits:

PostToolUse:Bash hook error — Hook command references ${CLAUDE_PLUGIN_ROOT} but the hook is not associated with a plugin. This variable is only available in hooks defined in a plugin's hooks/hooks.json file, not in settings.json files.

Net effect: every hook integrated by APM for --target claude is dead config from Claude Code's perspective, and the error message fires repeatedly for every Bash/Edit/Write tool call that matches a hook's if: clause.

This is a regression-class distinct from #1007 (which fixed wrong variable names — ${PLUGIN_ROOT}, ${CURSOR_PLUGIN_ROOT} — being emitted). The variable name written is now correct (${CLAUDE_PLUGIN_ROOT}), but it lives in the wrong file context for Claude Code to expand it.

To Reproduce

  1. apm init
  2. apm marketplace add data-goblin/power-bi-agentic-development (or any marketplace containing a plugin with a hooks/hooks.json that uses ${CLAUDE_PLUGIN_ROOT})
  3. apm install -g -t claude data-goblin/power-bi-agentic-development/plugins/pbi-desktop
  4. cat ~/.claude/settings.json — observe ${CLAUDE_PLUGIN_ROOT} in hook commands inside hooks.PostToolUse/hooks.PreToolUse blocks tagged with _apm_source: pbi-desktop
  5. Open Claude Code, run any Bash command that matches the hook's if: clause (e.g. bash <something.ps1> for Bash(* -File *.ps1*))
  6. Observe the Hook command references ${CLAUDE_PLUGIN_ROOT} error in the transcript

Expected behavior

After apm install --target claude, hooks deployed for an APM-installed plugin should actually fire when their if: clauses match, without emitting a Claude Code error. Either the variable should be resolvable in the context Claude Code reads it from, or the deployment should write the hooks to a file/location where Claude Code does resolve ${CLAUDE_PLUGIN_ROOT} correctly.

Environment

  • OS: Windows 11 Pro 10.0.26200 (the same pattern has been visible on macOS for related issues; not specific to Windows)
  • Python Version: bundled with APM 0.13.0 installer
  • APM Version: 0.13.0 (latest as of filing)
  • Claude Code Version: 4.7 (Opus)

Logs

Excerpt of ~/.claude/settings.json after apm install -g -t claude data-goblin/power-bi-agentic-development/plugins/pbi-desktop then …/pbip:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/pbi-hooks.sh\" refresh-cache",
            "timeout": 30,
            "if": "Bash(* -File *.ps1*)"
          },
          {
            "type": "command",
            "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/pbi-hooks.sh\" check-compat",
            "timeout": 10,
            "if": "Bash(* -File *.ps1*)"
          },
          {
            "type": "command",
            "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/pbi-hooks.sh\" check-ri",
            "timeout": 60,
            "if": "Bash(*SaveChanges*)"
          }
        ],
        "_apm_source": "pbi-desktop"
      },
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/validate-pbir.sh\"",
            "timeout": 10,
            "if": "Edit(**.Report/**)"
          }
        ],
        "_apm_source": "pbip"
      }
    ]
  }
}

Claude Code transcript on any matching Bash call:

PostToolUse:Bash hook error
Failed to run: Hook command references ${CLAUDE_PLUGIN_ROOT} but the hook is not associated with a plugin.
This variable is only available in hooks defined in a plugin's hooks/hooks.json file,
not in settings.json files.

The plugins themselves are well-formed Claude Code plugins (hooks/hooks.json under the plugin root using ${CLAUDE_PLUGIN_ROOT}, per the official Anthropic plugin spec). The bug is purely in APM's emit path for --target claude.

Additional context

Secondary observation — apm uninstall does not clean its own _apm_source blocks

While debugging, ran apm uninstall -g <plugin> then re-checked ~/.claude/settings.json. The hook blocks tagged "_apm_source": "<plugin>" were not removed from the file. The uninstall output reports Cleaned up N integrated hooks but this refers to deployed hook-script files on disk, not to the inlined entries in settings.json. This compounds the impact of the primary bug: even after a clean uninstall, the broken hooks keep firing on every tool call. Reporting here rather than as a separate issue since both behaviours stem from the same --target claude emit/cleanup path.

Related

Why it matters

Any APM-installed plugin that ships a hooks/hooks.json referencing ${CLAUDE_PLUGIN_ROOT} (i.e. any spec-compliant Claude Code plugin authored with the official template) silently emits a Claude Code error on every matching tool call after apm install --target claude. The integration appears successful at install time (N hook(s) integrated -> .claude/settings.json), but no hook ever fires. This affects data-goblin/power-bi-agentic-development (pbi-desktop, pbip) and likely most/all Claude-targeted plugins in the ecosystem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions