feat: ship a Claude Code plugin marketplace - #37
Conversation
Adds .claude-plugin/marketplace.json and .claude-plugin/plugin.json so
this repo can be installed as a proper Claude Code plugin via
`/plugin marketplace add 1Password/agent-hooks` +
`/plugin install 1password@agent-hooks`, instead of only the
copy-paste install.sh bundle.
Adds hooks/hooks.json using ${CLAUDE_PLUGIN_ROOT} for the hook
command path, which Claude Code resolves to an absolute path
reliably for plugin-scoped hooks. This sidesteps the two problems
described in 1Password#34: the vendored install.sh bundle has no update
mechanism, and its generated .claude/settings.json uses a path
relative to the project root that breaks with a "No such file or
directory" hook error when Claude Code runs hooks from a non-root
working directory.
Verified: `claude plugin validate .` and `claude plugin validate
./.claude-plugin/plugin.json` both pass (including --strict); a
manual simulation invoking bin/run-hook.sh via an absolute
CLAUDE_PLUGIN_ROOT-style path from an unrelated cwd exits 0 with no
path-resolution error, confirming the fix for the reported bug.
Documents the new install flow in README.md as the recommended path
for Claude Code, alongside (not replacing) the existing
`install.sh --agent claude-code` flow for other agents and for users
who prefer a vendored copy.
- Added: .claude-plugin/marketplace.json, .claude-plugin/plugin.json, hooks/hooks.json
- Modified: README.md (Available Hooks table + new "Claude Code plugin (recommended)" section)
- Out of scope (left untouched): adapters/claude-code.sh, .claude/settings.json template logic — overlaps with 1Password#28, being worked concurrently
- Tested: JSON syntax validated; `claude plugin validate` clean with --strict; manual run-hook.sh path-resolution simulation from a non-root cwd
Closes 1Password#34
"Replaces" read as contradicting the next paragraph, which says the install.sh bundle flow still works and is unaffected. Reworded to "in place of" to make clear the plugin is the recommended path without implying the bundle option is being removed.
|
Self-review: re-read the diff after opening this PR. Found and fixed one issue in a follow-up commit (81c7dda): the new "Claude Code plugin (recommended)" README section originally said the plugin "replaces" the copy-paste bundle for Claude Code, but the very next paragraph said the Everything else checked out:
|
|
Closing — this was opened as part of an automated exploration and isn't something I should be maintaining upstream. Apologies for the noise. |
Closes #34
Summary
Ships the 1Password validator as a proper Claude Code plugin, distributed from a marketplace hosted in this repo, alongside (not replacing) the existing
install.sh --agent claude-codecopy-paste bundle..claude-plugin/marketplace.json— declares anagent-hooksmarketplace with one plugin (1password) sourced from the repo root..claude-plugin/plugin.json— plugin metadata (name, version, author, license, etc). Nohooksfield needed sincehooks/hooks.jsonis auto-discovered at its default path.hooks/hooks.json— thePreToolUse/Bashhook entry, using"${CLAUDE_PLUGIN_ROOT}"/bin/run-hook.sh 1password-validate-mounted-env-filesinstead of a project-root-relative path.README.md— documents the new install flow (/plugin marketplace add 1Password/agent-hooks+/plugin install 1password@agent-hooks) as the recommended path for Claude Code, and links to it from the Available Hooks table.Why
Fixes both problems from #34:
install.shbundle vendors a static copy ofbin/,lib/,adapters/, andhooks/into.claude/with no way to know it's stale. Plugin installs update via/plugin marketplace update..claude/settings.jsonuses a path relative to the project root, which breaks withNo such file or directorywhen Claude Code runs hooks from a non-root cwd.${CLAUDE_PLUGIN_ROOT}resolves to an absolute path reliably for plugin-scoped hooks, sidestepping this and the separate$CLAUDE_PROJECT_DIRbug referenced in the issue ([BUG] $CLAUDE_PROJECT_DIR is empty/unset in hook and Bash tool execution (v2.1.74) anthropics/claude-code#33815).No changes to
adapters/claude-code.sh,install.sh, or the.claude/settings.jsontemplate logic — kept scoped to the new plugin files and docs since #28 (in progress) touches the adapter and hook-matcher code for a different reason.Testing
claude plugin validate .andclaude plugin validate ./.claude-plugin/plugin.jsonboth pass, including with--strict.bin/,lib/,adapters/,hooks/,VERSIONto a temp dir, setCLAUDE_PLUGIN_ROOTto that dir, ranbin/run-hook.shvia the absolute${CLAUDE_PLUGIN_ROOT}path from an unrelated working directory. Exits 0 with no path-resolution error — confirms the fix for the reported bug.batsisn't installed in this environment so the existing suite wasn't run locally; changes are additive only (new files + README) and don't touch any script the existing tests exercise, so I'd expect CI'stests.ymlto pass unchanged.Not in this PR
install.shor the bundle flow — still supported for other agents (Cursor, GitHub Copilot, Windsurf) and for Claude Code users who prefer a vendored copy.lib/telemetry.sh'sdetect_install_method(plugin-cache installs currently fall through tomanualthere); the README's telemetry section already anticipates plugin distributions reporting installs separately, but wiring that up felt like a separate, telemetry-focused change rather than part of shipping the plugin scaffolding itself. Happy to file a follow-up issue if maintainers agree it's worth tracking.