From e85465e7cc4b41068e2210876e4981fdd0f1085a Mon Sep 17 00:00:00 2001 From: Richard Knapp Date: Mon, 18 May 2026 18:24:17 +0200 Subject: [PATCH] fix(plugins): hooks.json must be {"hooks": {}}; add validator + CI guard The 4 vertical plugins (private-equity, financial-analysis, equity-research, wealth-management) had `hooks.json` written as `[]`, which the Claude Code plugin loader rejects with `expected: "record", path: ["hooks"], received: undefined`. Investment-banking already had the correct `{"hooks": {}}` shape. This corrects the 4 files, adds a hooks.json schema check to `scripts/check.py` (fails CI on any future regression of this shape), and wires `check.py` into a new `check` GitHub Actions workflow that runs on every PR + push to main. Supersedes the duplicate community PRs that have been queuing on this issue (#226, #225, #224, #221, #216, #206, #203, #200, #193, #192, #167, #163, #162, #146, #141, and others). Co-Authored-By: Claude Opus 4.7 --- .github/workflows/check.yml | 22 +++++++++++++++++++ .../.claude-plugin/plugin.json | 2 +- .../equity-research/hooks/hooks.json | 4 +++- .../.claude-plugin/plugin.json | 2 +- .../financial-analysis/hooks/hooks.json | 4 +++- .../private-equity/.claude-plugin/plugin.json | 2 +- .../private-equity/hooks/hooks.json | 4 +++- .../.claude-plugin/plugin.json | 2 +- .../wealth-management/hooks/hooks.json | 4 +++- scripts/check.py | 14 ++++++++++++ 10 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/check.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 00000000..9d50ce9f --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,22 @@ +name: check + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + manifests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.11' + - name: install deps + run: pip install pyyaml + - name: run check.py + run: python3 scripts/check.py diff --git a/plugins/vertical-plugins/equity-research/.claude-plugin/plugin.json b/plugins/vertical-plugins/equity-research/.claude-plugin/plugin.json index 7d0649ec..9cf5a1a7 100644 --- a/plugins/vertical-plugins/equity-research/.claude-plugin/plugin.json +++ b/plugins/vertical-plugins/equity-research/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "equity-research", - "version": "0.1.0", + "version": "0.1.1", "description": "Equity research tools: earnings analysis, initiating coverage reports, and research workflows", "author": { "name": "Anthropic FSI" diff --git a/plugins/vertical-plugins/equity-research/hooks/hooks.json b/plugins/vertical-plugins/equity-research/hooks/hooks.json index fe51488c..deffac97 100644 --- a/plugins/vertical-plugins/equity-research/hooks/hooks.json +++ b/plugins/vertical-plugins/equity-research/hooks/hooks.json @@ -1 +1,3 @@ -[] +{ + "hooks": {} +} diff --git a/plugins/vertical-plugins/financial-analysis/.claude-plugin/plugin.json b/plugins/vertical-plugins/financial-analysis/.claude-plugin/plugin.json index c3c39a33..8bb83a79 100644 --- a/plugins/vertical-plugins/financial-analysis/.claude-plugin/plugin.json +++ b/plugins/vertical-plugins/financial-analysis/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "financial-analysis", - "version": "0.1.0", + "version": "0.1.1", "description": "Core financial modeling and analysis tools: DCF, comps, LBO, 3-statement models, competitive analysis, and deck QC", "author": { "name": "Anthropic FSI" diff --git a/plugins/vertical-plugins/financial-analysis/hooks/hooks.json b/plugins/vertical-plugins/financial-analysis/hooks/hooks.json index fe51488c..deffac97 100644 --- a/plugins/vertical-plugins/financial-analysis/hooks/hooks.json +++ b/plugins/vertical-plugins/financial-analysis/hooks/hooks.json @@ -1 +1,3 @@ -[] +{ + "hooks": {} +} diff --git a/plugins/vertical-plugins/private-equity/.claude-plugin/plugin.json b/plugins/vertical-plugins/private-equity/.claude-plugin/plugin.json index 8972bac1..276b49e3 100644 --- a/plugins/vertical-plugins/private-equity/.claude-plugin/plugin.json +++ b/plugins/vertical-plugins/private-equity/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "private-equity", - "version": "0.1.0", + "version": "0.1.1", "description": "Private equity deal sourcing and workflow tools: company discovery, CRM integration, and founder outreach", "author": { "name": "Anthropic FSI" diff --git a/plugins/vertical-plugins/private-equity/hooks/hooks.json b/plugins/vertical-plugins/private-equity/hooks/hooks.json index fe51488c..deffac97 100644 --- a/plugins/vertical-plugins/private-equity/hooks/hooks.json +++ b/plugins/vertical-plugins/private-equity/hooks/hooks.json @@ -1 +1,3 @@ -[] +{ + "hooks": {} +} diff --git a/plugins/vertical-plugins/wealth-management/.claude-plugin/plugin.json b/plugins/vertical-plugins/wealth-management/.claude-plugin/plugin.json index e9c23274..117e5db6 100644 --- a/plugins/vertical-plugins/wealth-management/.claude-plugin/plugin.json +++ b/plugins/vertical-plugins/wealth-management/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "wealth-management", - "version": "0.1.0", + "version": "0.1.1", "description": "Wealth management and financial advisory tools: client reviews, financial planning, portfolio analysis, and client reporting", "author": { "name": "Anthropic FSI" diff --git a/plugins/vertical-plugins/wealth-management/hooks/hooks.json b/plugins/vertical-plugins/wealth-management/hooks/hooks.json index fe51488c..deffac97 100644 --- a/plugins/vertical-plugins/wealth-management/hooks/hooks.json +++ b/plugins/vertical-plugins/wealth-management/hooks/hooks.json @@ -1 +1,3 @@ -[] +{ + "hooks": {} +} diff --git a/scripts/check.py b/scripts/check.py index e8e93c7b..33c9e52b 100755 --- a/scripts/check.py +++ b/scripts/check.py @@ -88,6 +88,20 @@ def rel(p: Path) -> str: except json.JSONDecodeError as e: err(f"JSON parse: {rel(jf)}: {e}") +# --- 2b. hooks.json schema --- must be {"hooks": {...}}, never [] ---------- +for hjf in sorted(PLUGINS.glob("**/hooks/hooks.json")): + checked += 1 + try: + data = json.loads(hjf.read_text()) + except json.JSONDecodeError as e: + err(f"hooks.json parse: {rel(hjf)}: {e}") + continue + if not isinstance(data, dict) or "hooks" not in data: + err( + f'hooks.json: {rel(hjf)}: must be {{"hooks": {{...}}}}, ' + f"got {type(data).__name__}" + ) + # --- 3. agent.md frontmatter ----------------------------------------------- for md in sorted(PLUGINS.glob("agent-plugins/*/agents/*.md")): checked += 1