ci: dogfood git-mind suggest action with Claude CLI#294
ci: dogfood git-mind suggest action with Claude CLI#294flyingrobots wants to merge 2 commits intomainfrom
Conversation
Wires up the composite action (action.yml) to run on every PR against main, using Claude CLI as the suggestion agent. Includes guards for draft PRs, bot authors, and missing ANTHROPIC_API_KEY. Non-blocking via continue-on-error so suggest failures never prevent merge.
Summary by CodeRabbit
WalkthroughThis PR introduces a GitHub Actions workflow for Changes
Sequence DiagramsequenceDiagram
actor Dev as Developer
participant Git as Git Pre-Push Hook
participant PM as git-mind<br/>process-commit
participant SG as git-mind<br/>suggest
participant Agent as Claude Agent
Dev->>Git: git push (new/updated branch)
activate Git
Git->>Git: Compute commit range<br/>(new branch vs. update)
loop For each commit SHA
Git->>PM: npx git-mind process-commit [SHA]
activate PM
PM->>PM: Process commit directives
deactivate PM
end
alt GITMIND_AGENT is set
Git->>SG: npx git-mind suggest
activate SG
SG->>Agent: Request review (Claude)
activate Agent
Agent-->>SG: Suggestions JSON
deactivate Agent
deactivate SG
end
Git-->>Dev: exit 0
deactivate Git
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~28 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cbf4b9dea4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| uses: ./ | ||
| with: | ||
| agent: 'claude -p --output-format json' | ||
| env: | ||
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} |
There was a problem hiding this comment.
Run trusted action code when exposing repository secrets
This step executes the local action from the PR checkout (uses: ./) while injecting ANTHROPIC_API_KEY, and on pull_request events that action code is sourced from the PR head. A contributor can modify action.yml or scripts it runs (including npm ci lifecycle hooks in the composite action) to exfiltrate the secret during CI, so this workflow should run trusted code from the base branch when secrets are present (for example via pull_request_target + trusted checkout) or avoid passing secrets to PR-head code.
Useful? React with 👍 / 👎.
…ggest (#293) Post-commit fires on every rebase replay, creating orphan edges. Pre-push runs once before commits leave the machine — processes directives via git rev-list and runs suggest when GITMIND_AGENT is set. Always exits 0.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/cli/commands.js (1)
309-311:⚠️ Potential issue | 🟡 MinorStale JSDoc:
processCommitCmdstill documents the old post-commit hook context.-/** - * Process a commit's directives (called by post-commit hook). + * Process a commit's directives (called by pre-push hook).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/cli/commands.js` around lines 309 - 311, The JSDoc above processCommitCmd is stale — it still says "called by post-commit hook" and doesn't reflect the function's current behavior/parameters; update the JSDoc for processCommitCmd to accurately describe its purpose, real invocation context, and parameters (e.g., cwd) and any return value or side effects so the comment matches the implementation; locate the comment immediately above the processCommitCmd function declaration and replace the outdated hook-specific text with a concise, accurate description of when and how processCommitCmd is used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/gitmind-suggest.yml:
- Around line 18-20: The current GitHub Actions workflow if condition only
excludes 'dependabot[bot]' which allows other automation actors to trigger the
job and consume API quota; update the if condition used in the workflow (the if:
> block) to also exclude known automation actors such as 'renovate[bot]' and
'github-actions[bot]' (and any organization-specific bot names you use)
alongside 'dependabot[bot]' so that those actors are skipped when evaluating the
job run.
- Around line 18-20: The workflow currently only excludes 'dependabot[bot]';
update the if conditional in the gitmind-suggest.yml workflow (the "if:"
expression) to broadly exclude bot actors by replacing or extending the
github.actor check with a suffix test such as !endsWith(github.actor, '[bot]')
(e.g. use "!github.event.pull_request.draft && !endsWith(github.actor,
'[bot]')") so renovate[bot], github-actions[bot], and other bot actors are
skipped as well.
- Around line 54-56: The workflow currently installs `@anthropic-ai/claude-code`
without a fixed version; update the install step so the global npm install pins
the package to the exact safe version (e.g., change the command that currently
reads npm install -g `@anthropic-ai/claude-code` to install the exact release,
such as npm install -g `@anthropic-ai/claude-code`@1.0.108) to prevent
unintentionally running unvetted code and allow Dependabot to manage future
updates.
- Around line 54-56: Replace the deprecated and unpinned npm installation in the
"Install Claude CLI" step (currently using `npm install -g
`@anthropic-ai/claude-code``) with the native installer and pin to a known stable
release; specifically, remove the npm command and invoke the native installer
with the correct syntax `bash -s VERSION`, using a pinned VERSION (for example
`1.0.108`) instead of `--version` so the workflow installs a fixed, auditable
Claude CLI release.
In `@src/cli/commands.js`:
- Around line 259-263: When remote_sha is all zeros (new branch) the code
currently sets RANGE="HEAD~10..HEAD" which picks commits from the checked-out
branch; change that to use the pushed tip instead so we run against the branch
being pushed. Replace the HEAD-based range with
RANGE="${local_sha}~10..${local_sha}" (use the existing local_sha variable) so
process-commit and suggest operate on the last 10 commits ending at local_sha;
keep the else branch for the normal "${remote_sha}..${local_sha}" case.
In `@test/hooks.test.js`:
- Around line 130-138: The test causes installHooks to set process.exitCode = 1
and never restores it; wrap the call to installHooks (or capture
process.exitCode before the call) and restore it after the assertion so the
global exit code is not leaked. Specifically, in the test case that calls
installHooks, save const originalExitCode = process.exitCode (or undefined), run
installHooks(tempDir), perform the existing assertions on the hook file, then
reset process.exitCode = originalExitCode (or delete it) — alternatively assert
that process.exitCode === 1 and then reset it — to ensure no side-effect remains
after the test.
- Line 108: Remove the redundant explicit mkdir call that creates join(tempDir,
'.git', 'hooks') after running git init; instead rely on git init to create the
hooks dir and replace the mkdir invocation with an assertion that the directory
exists (or let the test fail if it does not) so missing directories in the test
environment are surfaced—update the test to reference the same tempDir and check
that join(tempDir, '.git', 'hooks') exists rather than creating it with mkdir.
---
Outside diff comments:
In `@src/cli/commands.js`:
- Around line 309-311: The JSDoc above processCommitCmd is stale — it still says
"called by post-commit hook" and doesn't reflect the function's current
behavior/parameters; update the JSDoc for processCommitCmd to accurately
describe its purpose, real invocation context, and parameters (e.g., cwd) and
any return value or side effects so the comment matches the implementation;
locate the comment immediately above the processCommitCmd function declaration
and replace the outdated hook-specific text with a concise, accurate description
of when and how processCommitCmd is used.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
.github/workflows/gitmind-suggest.ymlbin/git-mind.jssrc/cli/commands.jstest/hooks.test.js
| if: > | ||
| !github.event.pull_request.draft && | ||
| github.actor != 'dependabot[bot]' |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Bot guard only excludes dependabot[bot] — other automation actors will consume API quota.
renovate[bot], github-actions[bot], and custom bots are not excluded. Unless intentional, tighten the guard.
🤖 Proposed fix
if: >
!github.event.pull_request.draft &&
- github.actor != 'dependabot[bot]'
+ github.actor != 'dependabot[bot]' &&
+ !endsWith(github.actor, '[bot]')📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if: > | |
| !github.event.pull_request.draft && | |
| github.actor != 'dependabot[bot]' | |
| if: > | |
| !github.event.pull_request.draft && | |
| github.actor != 'dependabot[bot]' && | |
| !endsWith(github.actor, '[bot]') |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/gitmind-suggest.yml around lines 18 - 20, The current
GitHub Actions workflow if condition only excludes 'dependabot[bot]' which
allows other automation actors to trigger the job and consume API quota; update
the if condition used in the workflow (the if: > block) to also exclude known
automation actors such as 'renovate[bot]' and 'github-actions[bot]' (and any
organization-specific bot names you use) alongside 'dependabot[bot]' so that
those actors are skipped when evaluating the job run.
🧹 Nitpick | 🔵 Trivial
Bot guard only excludes dependabot[bot] — other automation actors will consume API credits.
renovate[bot], github-actions[bot], and any custom bot actors are not excluded. Unless intentional, add a broader guard.
🤖 Proposed fix
if: >
!github.event.pull_request.draft &&
- github.actor != 'dependabot[bot]'
+ github.actor != 'dependabot[bot]' &&
+ github.actor != 'renovate[bot]' &&
+ !endsWith(github.actor, '[bot]')🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/gitmind-suggest.yml around lines 18 - 20, The workflow
currently only excludes 'dependabot[bot]'; update the if conditional in the
gitmind-suggest.yml workflow (the "if:" expression) to broadly exclude bot
actors by replacing or extending the github.actor check with a suffix test such
as !endsWith(github.actor, '[bot]') (e.g. use "!github.event.pull_request.draft
&& !endsWith(github.actor, '[bot]')") so renovate[bot], github-actions[bot], and
other bot actors are skipped as well.
| - name: Install Claude CLI | ||
| if: steps.check-key.outputs.skip != 'true' | ||
| run: npm install -g @anthropic-ai/claude-code |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
@anthropic-ai/claude-code npm package latest version
💡 Result:
The latest published version of @anthropic-ai/claude-code on npm is 1.0.108. [1]
Source: npm package “Versions” tab shows Version 1.0.108 and “Last publish 5 hours ago.” [1]
References
Pin @anthropic-ai/claude-code to an exact version; unpinned global installs are indefensible.
Line 56: npm install -g @anthropic-ai/claude-code`` fetches whatever the registry serves on the next run. One semver bump (malicious or accidental) and your workflow executes unknown code with ANTHROPIC_API_KEY access. No audit trail, no rollback, silent failure. Current stable is `1.0.108` — pin it and let Dependabot handle updates.
Fix
- run: npm install -g `@anthropic-ai/claude-code`
+ run: npm install -g `@anthropic-ai/claude-code`@1.0.108📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Install Claude CLI | |
| if: steps.check-key.outputs.skip != 'true' | |
| run: npm install -g @anthropic-ai/claude-code | |
| - name: Install Claude CLI | |
| if: steps.check-key.outputs.skip != 'true' | |
| run: npm install -g `@anthropic-ai/claude-code`@1.0.108 |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/gitmind-suggest.yml around lines 54 - 56, The workflow
currently installs `@anthropic-ai/claude-code` without a fixed version; update the
install step so the global npm install pins the package to the exact safe
version (e.g., change the command that currently reads npm install -g
`@anthropic-ai/claude-code` to install the exact release, such as npm install -g
`@anthropic-ai/claude-code`@1.0.108) to prevent unintentionally running unvetted
code and allow Dependabot to manage future updates.
🧩 Analysis chain
🌐 Web query:
Anthropic Claude CLI npm deprecated official documentation
💡 Result:
Anthropic’s official Claude Code (Claude CLI) docs state that “NPM installation is deprecated” and recommend using the native installation method instead; to migrate an existing npm install to native, run claude install. The same page still shows the legacy command npm install -g @anthropic-ai/claude-code`` under “NPM installation (deprecated)”. [1]
Recent Claude CLI release notes also mention an added deprecation notification for npm installations, pointing users to run claude install and to the same “getting started” documentation page. [2]
Sources:
[1] Anthropic Claude Code Docs – “Set up Claude Code” → “NPM installation (deprecated)”
[2] Claude CLI Release Notes (notes referencing npm-install deprecation notice)
🌐 Web query:
@anthropic-ai/claude-code npm package latest version
💡 Result:
The latest published version of the @anthropic-ai/claude-code npm package is 1.0.108 (last published ~5 hours ago). [1]
Source: npm package “Versions” tab. [1]
🌐 Web query:
Anthropic Claude CLI native installer setup github
💡 Result:
- Official GitHub repo (Claude Code CLI):
anthropics/claude-code(README includes install commands and project details). [1] - Native (binary) installer setup (Beta): Anthropic’s official setup docs recommend installing via the hosted installer scripts (not a GitHub “native installer” release asset): [2]
- macOS / Linux / WSL:
curl -fsSL https://claude.ai/install.sh | bash - Windows (PowerShell):
irm https://claude.ai/install.ps1 | iex - You can also pin a version (e.g.,
... | bash -s 1.0.58) and, if you already have Claude Code installed, start native install viaclaude install. [2]
- macOS / Linux / WSL:
- Alternative install path (Node):
npm install -g@anthropic-ai/claude-code`` (also documented in the repo + docs). [1][2]
🌐 Web query:
Claude CLI binary path installation $HOME/.claude/bin official documentation
💡 Result:
Anthropic’s official Claude Code docs do not state that the CLI binary installs to $HOME/.claude/bin. In the official docs, ~/.claude/ is used for Claude Code’s user configuration, while the claude executable comes from your install method. (docs.anthropic.com)
Official install methods & where the claude binary comes from:
-
Global npm install (standard):
- Install:
npm install -g@anthropic-ai/claude-code`` (docs.anthropic.com) - Binary path is your global npm “bin” directory (varies by system). To see the exact location:
which claude npm prefix -g ls -l "$(npm prefix -g)/bin/claude"
- Install:
-
Native binary install (beta):
- Install via the official script (macOS/Linux/WSL):
curl -fsSL https://claude.ai/install.sh | bash(docs.anthropic.com) - After install, Anthropic recommends running:
to verify the installation type/version. (docs.anthropic.com)
claude doctor
- Install via the official script (macOS/Linux/WSL):
Citations:
- 1: https://docs.anthropic.com/en/docs/claude-code/setup?utm_source=openai
- 2: https://docs.anthropic.com/en/docs/claude-code/setup?utm_source=openai
- 3: https://docs.anthropic.com/en/docs/claude-code/setup?utm_source=openai
- 4: https://docs.anthropic.com/en/docs/claude-code/setup?utm_source=openai
npm install -g @anthropic-ai/claude-code`` is deprecated AND unpinned — this step will break.
"Installation via npm is deprecated. Use one of the recommended methods below." Anthropic's official documentation and release notes are explicit about this. The package itself now ships with a deprecation notification for npm installations.
Beyond deprecation, the install is unpinned — every run silently picks up whatever the registry serves, with no auditability or rollback path if a breaking release lands.
🚑 Proposed fix — switch to the native installer at the current version
- name: Install Claude CLI
if: steps.check-key.outputs.skip != 'true'
- run: npm install -g `@anthropic-ai/claude-code`
+ run: curl -fsSL https://claude.ai/install.sh | bash -s 1.0.108(The proposed fix in the original comment uses an incorrect version number 2.1.52 and malformed syntax --version; the correct native installer syntax is bash -s VERSION where VERSION is the pinned release like 1.0.108.)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/gitmind-suggest.yml around lines 54 - 56, Replace the
deprecated and unpinned npm installation in the "Install Claude CLI" step
(currently using `npm install -g `@anthropic-ai/claude-code``) with the native
installer and pin to a known stable release; specifically, remove the npm
command and invoke the native installer with the correct syntax `bash -s
VERSION`, using a pinned VERSION (for example `1.0.108`) instead of `--version`
so the workflow installs a fixed, auditable Claude CLI release.
| if [ "$remote_sha" = "$ZERO" ]; then | ||
| RANGE="HEAD~10..HEAD" # new branch — use last 10 | ||
| else | ||
| RANGE="\${remote_sha}..\${local_sha}" | ||
| fi |
There was a problem hiding this comment.
HEAD~10..HEAD is the wrong range for new branch pushes — it processes the wrong commits.
When remote_sha is all-zeros (new branch), HEAD is the currently checked-out ref, which is NOT necessarily the branch being pushed. A user can do git push origin feature-branch while sitting on main; every process-commit call and the suggest invocation will run against main's last 10 commits, not feature-branch's.
local_sha is the exact tip being pushed and is always available at this point in the loop.
🐛 Proposed fix
- RANGE="HEAD~10..HEAD" # new branch — use last 10
+ RANGE="${local_sha}~10..${local_sha}" # new branch — use last 10🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/cli/commands.js` around lines 259 - 263, When remote_sha is all zeros
(new branch) the code currently sets RANGE="HEAD~10..HEAD" which picks commits
from the checked-out branch; change that to use the pushed tip instead so we run
against the branch being pushed. Replace the HEAD-based range with
RANGE="${local_sha}~10..${local_sha}" (use the existing local_sha variable) so
process-commit and suggest operate on the last 10 commits ending at local_sha;
keep the else branch for the normal "${remote_sha}..${local_sha}" case.
| beforeEach(async () => { | ||
| tempDir = await mkdtemp(join(tmpdir(), 'gitmind-test-')); | ||
| execSync('git init', { cwd: tempDir, stdio: 'ignore' }); | ||
| await mkdir(join(tempDir, '.git', 'hooks'), { recursive: true }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Redundant mkdir — git init already creates .git/hooks.
git init at line 107 unconditionally creates .git/hooks. The mkdir with { recursive: true } is a no-op in the happy path and masks any scenario where the directory is unexpectedly absent (which would be a test-environment signal worth catching, not silently creating).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/hooks.test.js` at line 108, Remove the redundant explicit mkdir call
that creates join(tempDir, '.git', 'hooks') after running git init; instead rely
on git init to create the hooks dir and replace the mkdir invocation with an
assertion that the directory exists (or let the test fail if it does not) so
missing directories in the test environment are surfaced—update the test to
reference the same tempDir and check that join(tempDir, '.git', 'hooks') exists
rather than creating it with mkdir.
| it('does not overwrite existing hook', async () => { | ||
| const existingContent = '#!/bin/sh\necho "existing hook"'; | ||
| await writeFile(join(tempDir, '.git', 'hooks', 'pre-push'), existingContent); | ||
|
|
||
| await installHooks(tempDir); | ||
|
|
||
| const prePush = await readFile(join(tempDir, '.git', 'hooks', 'pre-push'), 'utf-8'); | ||
| expect(prePush).toBe(existingContent); | ||
| }); |
There was a problem hiding this comment.
process.exitCode side-effect leaks out of this test and will poison the runner's exit code.
installHooks sets process.exitCode = 1 when a hook already exists (see src/cli/commands.js line 296). This test deliberately triggers that path but never restores process.exitCode afterward. Any subsequent test — or the Vitest process itself — will inherit exit code 1, making the suite appear failed even when every assertion passes.
Fix: capture and restore process.exitCode around the call, or assert + reset it explicitly.
🔥 Proposed fix
it('does not overwrite existing hook', async () => {
const existingContent = '#!/bin/sh\necho "existing hook"';
await writeFile(join(tempDir, '.git', 'hooks', 'pre-push'), existingContent);
+ const prevExitCode = process.exitCode;
await installHooks(tempDir);
+ expect(process.exitCode).toBe(1);
+ process.exitCode = prevExitCode;
const prePush = await readFile(join(tempDir, '.git', 'hooks', 'pre-push'), 'utf-8');
expect(prePush).toBe(existingContent);
});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/hooks.test.js` around lines 130 - 138, The test causes installHooks to
set process.exitCode = 1 and never restores it; wrap the call to installHooks
(or capture process.exitCode before the call) and restore it after the assertion
so the global exit code is not leaked. Specifically, in the test case that calls
installHooks, save const originalExitCode = process.exitCode (or undefined), run
installHooks(tempDir), perform the existing assertions on the hook file, then
reset process.exitCode = originalExitCode (or delete it) — alternatively assert
that process.exitCode === 1 and then reset it — to ensure no side-effect remains
after the test.
Summary
.github/workflows/gitmind-suggest.ymlto rungit mind suggeston every PR againstmainclaude -p --output-format json) as the suggestion agentaction.yml) and review workflow (gitmind-review.yml)Problem Statement
The composite action and review workflow exist but are never exercised on this repo. Adding the suggest trigger closes the loop — PRs get automated graph-relationship suggestions, and
/gitmind accept|rejectcommands work via the existing review workflow.ADR Compliance (Required)
Relevant ADR(s)
Compliance Declaration
Architecture Laws Checklist (Hard Gates)
Canonical Truth & Context
--at,--observer,--trust) or deterministically defaulted.Determinism & Provenance
Artifact Hygiene
Contracts & Compatibility
Extension/Effects Safety (if applicable)
Scope Control
Backward Compatibility
Test Plan (Required)
Unit
Integration
Determinism
Contract/Schema
npm run lintPolicy Gates
npm test && npm run lintSecurity / Trust Impact
ANTHROPIC_API_KEYsecret (never exposed in logs)continue-on-error: true)Performance Impact
Observability / Debuggability
Operational Notes
ANTHROPIC_API_KEYsecret — no key = skipgh secret set ANTHROPIC_API_KEYto activateLinked Issues / Milestones
Reviewer Quick Verdict Block (for maintainers)
MUST (Hard Gates)
SHOULD (Quality)
Verdict