Summary
The Claude Code install path (./install.sh --agent claude-code --target-dir <workspace>) vendors a static copy of the hook bundle into each project's .claude/ directory and writes a .claude/settings.json entry with a relative path to run-hook.sh. There is no update mechanism — if the bundle is improved or fixed, users never find out. The relative path also breaks depending on Claude Code's working directory at hook-execution time, producing a non-blocking "No such file or directory" error on every Bash call.
By contrast, the Cursor install path ships as a proper plugin (/add-plugin 1password) that's managed by Cursor's plugin system. Claude Code has had an equivalent plugin/marketplace system (.claude-plugin/marketplace.json + plugin.json) since early 2025, and many plugins (agentmemory, honcho, parallel, axiom, etc.) are already published and auto-update via ~/.claude/settings.json extraKnownMarketplaces + enabledPlugins.
Filing as a feature request: publish the 1Password Environments validator as a Claude Code plugin so it auto-updates and resolves its own paths correctly.
The current install is fragile in two ways
1. No update path (vendored static copy)
install.sh copies bin/, lib/, adapters/, and hooks/ into <workspace>/.claude/claude-code-1password-hooks-bundle/ and commits them. The VERSION file says 1.0.0. If you ship a fix (e.g., for #28 or the path bug below), users have to:
- Notice the fix exists (no notification mechanism).
- Re-run
install.sh or manually copy files over.
- Commit the update per-project.
In practice, nobody does this. The vendored copy drifts forever.
2. Relative path breaks when Claude Code runs hooks from a non-root CWD
The generated .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/claude-code-1password-hooks-bundle/bin/run-hook.sh 1password-validate-mounted-env-files"
}
]
}
]
}
}
Claude Code does not always execute hook commands from the project root — it uses the current working directory of the session, which may be a subdirectory. When the CWD isn't the project root, the relative path .claude/claude-code-1password-hooks-bundle/bin/run-hook.sh doesn't resolve:
PreToolUse:Bash hook error
Failed with non-blocking status code: /bin/sh: .claude/claude-code-1password-hooks-bundle/bin/run-hook.sh: No such file or directory
The hook is fail-open (non-blocking), so the Bash call proceeds anyway — but the validator is silently skipped and the user sees error noise on every single command.
The fix for this specific symptom is to use $CLAUDE_PROJECT_DIR (or an absolute path), but that variable has its own bug (anthropics/claude-code#33815 — empty/unset in some versions). A plugin would sidestep both issues: Claude Code resolves ${CLAUDE_PLUGIN_ROOT} reliably for plugin hooks.
Reproducer (path bug)
- Run
./install.sh --agent claude-code --target-dir <workspace>.
- Open a Claude Code session in a subdirectory of
<workspace> (or just let the session change directories during work).
- Run any Bash command.
- Observe:
PreToolUse:Bash hook error: .claude/claude-code-1password-hooks-bundle/bin/run-hook.sh: No such file or directory on every Bash call. Hook is silently skipped.
Proposed direction
Publish the validator as a Claude Code plugin via a marketplace, mirroring the Cursor plugin approach:
- Add a
.claude-plugin/marketplace.json at the repo root (or a subdirectory) declaring the plugin.
- Add a
.claude-plugin/plugin.json with the plugin metadata.
- Add a
hooks/hooks.json using ${CLAUDE_PLUGIN_ROOT} for command paths — Claude Code resolves this reliably for plugin-scoped hooks, unlike the relative-path or $CLAUDE_PROJECT_DIR approaches.
- Users install once:
/plugin marketplace add 1Password/agent-hooks then /plugin install 1password@agent-hooks (or equivalent). Auto-update keeps the hook current.
This eliminates both problems: no per-project vendoring, no path resolution failures, and fixes propagate automatically.
Related
Summary
The Claude Code install path (
./install.sh --agent claude-code --target-dir <workspace>) vendors a static copy of the hook bundle into each project's.claude/directory and writes a.claude/settings.jsonentry with a relative path torun-hook.sh. There is no update mechanism — if the bundle is improved or fixed, users never find out. The relative path also breaks depending on Claude Code's working directory at hook-execution time, producing a non-blocking "No such file or directory" error on every Bash call.By contrast, the Cursor install path ships as a proper plugin (
/add-plugin 1password) that's managed by Cursor's plugin system. Claude Code has had an equivalent plugin/marketplace system (.claude-plugin/marketplace.json+plugin.json) since early 2025, and many plugins (agentmemory, honcho, parallel, axiom, etc.) are already published and auto-update via~/.claude/settings.jsonextraKnownMarketplaces+enabledPlugins.Filing as a feature request: publish the 1Password Environments validator as a Claude Code plugin so it auto-updates and resolves its own paths correctly.
The current install is fragile in two ways
1. No update path (vendored static copy)
install.shcopiesbin/,lib/,adapters/, andhooks/into<workspace>/.claude/claude-code-1password-hooks-bundle/and commits them. TheVERSIONfile says1.0.0. If you ship a fix (e.g., for #28 or the path bug below), users have to:install.shor manually copy files over.In practice, nobody does this. The vendored copy drifts forever.
2. Relative path breaks when Claude Code runs hooks from a non-root CWD
The generated
.claude/settings.json:{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": ".claude/claude-code-1password-hooks-bundle/bin/run-hook.sh 1password-validate-mounted-env-files" } ] } ] } }Claude Code does not always execute hook commands from the project root — it uses the current working directory of the session, which may be a subdirectory. When the CWD isn't the project root, the relative path
.claude/claude-code-1password-hooks-bundle/bin/run-hook.shdoesn't resolve:The hook is fail-open (non-blocking), so the Bash call proceeds anyway — but the validator is silently skipped and the user sees error noise on every single command.
The fix for this specific symptom is to use
$CLAUDE_PROJECT_DIR(or an absolute path), but that variable has its own bug (anthropics/claude-code#33815 — empty/unset in some versions). A plugin would sidestep both issues: Claude Code resolves${CLAUDE_PLUGIN_ROOT}reliably for plugin hooks.Reproducer (path bug)
./install.sh --agent claude-code --target-dir <workspace>.<workspace>(or just let the session change directories during work).PreToolUse:Bash hook error: .claude/claude-code-1password-hooks-bundle/bin/run-hook.sh: No such file or directoryon every Bash call. Hook is silently skipped.Proposed direction
Publish the validator as a Claude Code plugin via a marketplace, mirroring the Cursor plugin approach:
.claude-plugin/marketplace.jsonat the repo root (or a subdirectory) declaring the plugin..claude-plugin/plugin.jsonwith the plugin metadata.hooks/hooks.jsonusing${CLAUDE_PLUGIN_ROOT}for command paths — Claude Code resolves this reliably for plugin-scoped hooks, unlike the relative-path or$CLAUDE_PROJECT_DIRapproaches./plugin marketplace add 1Password/agent-hooksthen/plugin install 1password@agent-hooks(or equivalent). Auto-update keeps the hook current.This eliminates both problems: no per-project vendoring, no path resolution failures, and fixes propagate automatically.
Related
install.sh.