Skip to content

[BUG] apm install -g hook integration silently broken across claude, cursor, copilot #1499

@ThanosPourikis

Description

@ThanosPourikis

Describe the bug

After apm install -g, hooks declared in a package's .apm/hooks/ don't fire on any of the three hook-capable targets. The install log lies in every case: it reports an "integrated" count for writes that did not happen (claude, cursor) or that wrote unusable content (copilot). Users get no signal of failure.

Target Log says Actual
claude 1 hook(s) integrated -> .claude/settings.json ~/.claude/settings.json not modified
cursor 1 hook(s) integrated -> .cursor/hooks.json ~/.cursor/hooks.json not modified
copilot 1 hook(s) integrated -> .copilot/hooks/ File written, but Stop event not renamed to session.shutdown and ${PLUGIN_ROOT} left unexpanded

The canonical source ~/.apm/apm_modules/<pkg>/.apm/hooks/<file>.json is present after install but never merged into the user-scope harness config.

To Reproduce

Package with .apm/hooks/session-metrics.json:

{ "Stop": [ { "matcher": "", "hooks": [
  { "type": "command",
    "command": "python3 ${PLUGIN_ROOT}/scripts/example.py",
    "timeout": 20000 } ] } ] }
cd ~/.apm
apm install -g --target claude  --force
apm install -g --target cursor  --force
apm install -g --target copilot --force

cat ~/.claude/settings.json     # hooks: {}
cat ~/.cursor/hooks.json        # hooks: {}
cat ~/.copilot/hooks/*.json     # raw Claude payload, ${PLUGIN_ROOT} unresolved

Reproduces identically with a GitHub-fetched branch dep (owner/repo/path#branch); not specific to local paths.

Also reproduces with the --runtime <name> form, with a different log shape:

$ apm install -g <pkg> --runtime claude --force
...
|-- 3 hook(s) integrated -> 3 targets

i.e. asking for runtime claude still produces a -> 3 targets summary, and file inspection confirms cursor/copilot were also touched (or attempted).

Expected

  • claude/cursor: merge into user-scope settings.json / hooks.json
  • copilot: rename event per-target (Copilot hooks reference) and expand ${PLUGIN_ROOT} before writing

i.e. what project-scope already produces, applied to target.root_dir at user scope. The install log should accurately reflect what was written: no "integrated" claim for a file that wasn't modified, a count that reflects declared hooks rather than per-target deliveries, and --runtime <name> should restrict deployment to the named runtime.

Environment

APM 0.15.0, macOS, Claude Code 4.7, Cursor recent, Copilot CLI >= 1.0.44.

Additional notes

  • Install logs lie: report success on writes that didn't happen (claude, cursor) or wrote unusable content (copilot). This is the most impactful part of the bug because it eliminates the signal a user would otherwise use to debug.
  • --runtime claude doesn't filter; log shows -> 3 targets and cursor/copilot destination files are still touched.
  • N hook(s) integrated counts per-target deliveries, not declared hooks. One declared hook is reported as 1 -> <path> per --target X run, or 3 -> 3 targets from a single --runtime X run.

Related

Metadata

Metadata

Assignees

Labels

No labels
No 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