commit c2a31b81cdf6935a9a7ff75199a89ea2cc29f66d
parent 8c3f52e91a837a91917070421dbf6238139b08c7
Author: andrewlaack-collab <andrew.laack@imbue.com>
Date: Tue, 17 Feb 2026 06:47:49 +0000
Updated action to unpin version / make setup easier. (#93)
* Updated action
* Refactoring
* Refactored
* build local version in vet repo
* Updated messaging
* Remove useless information
* send keys differently
* Added anthropic key messaging
---------
Co-authored-by: Andrew Laack <andrew@laack.co>
Diffstat:
7 files changed, 177 insertions(+), 123 deletions(-)
diff --git a/.github/workflows/vet-agentic.yml b/.github/workflows/vet-agentic.yml
@@ -12,45 +12,14 @@ jobs:
vet:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
+ env:
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- - uses: actions/setup-python@v5
+ - uses: ./
with:
- python-version: "3.11"
- - uses: actions/setup-node@v4
- with:
- node-version: "20"
- - run: npm install -g @anthropic-ai/claude-code
- # we want to run the current version of vet against the PR, not necessarily the deployed / main version.
- - run: pip install .
- - name: Run vet (agentic)
- if: github.event.pull_request.head.repo.full_name == github.repository
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- BASE_REF: ${{ github.event.pull_request.base.ref }}
- VET_GOAL: |
- ${{ github.event.pull_request.title }}
-
- Additional context (not necessarily part of the goal):
- ${{ github.event.pull_request.body }}
- run: |
- set +e
- MERGE_BASE=$(git merge-base "origin/$BASE_REF" "${{ github.event.pull_request.head.sha }}")
- vet "$VET_GOAL" --quiet --output-format github \
- --agentic --base-commit "$MERGE_BASE" \
- > "$RUNNER_TEMP/review.json"
- status=$?
- if [ "$status" -ne 0 ] && [ "$status" -ne 10 ]; then exit "$status"; fi
-
- jq --arg sha "${{ github.event.pull_request.head.sha }}" \
- '. + {commit_id: $sha}' "$RUNNER_TEMP/review.json" > "$RUNNER_TEMP/review-final.json"
-
- gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews" \
- --method POST --input "$RUNNER_TEMP/review-final.json" > /dev/null || \
- gh pr comment "${{ github.event.pull_request.number }}" \
- --body "$(jq -r '[.body] + [.comments[] | "**\(.path):\(.line)**\n\n\(.body)"] | join("\n\n---\n\n")' "$RUNNER_TEMP/review-final.json")"
- exit 0
+ agentic: true
+ build-from-source: true
diff --git a/.github/workflows/vet.yml b/.github/workflows/vet.yml
@@ -12,42 +12,13 @@ jobs:
vet:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
+ env:
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- - uses: actions/setup-python@v5
+ - uses: ./
with:
- python-version: "3.11"
- # we want to run the current version of vet against the PR, not necessarily the deployed / main version.
- # this is the only difference between this vet.yml and the recommended one in the readme.
- - run: pip install .
- - name: Run vet
- if: github.event.pull_request.head.repo.full_name == github.repository
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- BASE_REF: ${{ github.event.pull_request.base.ref }}
- VET_GOAL: |
- ${{ github.event.pull_request.title }}
-
- Additional context (not necessarily part of the goal):
- ${{ github.event.pull_request.body }}
- run: |
- set +e
- MERGE_BASE=$(git merge-base "origin/$BASE_REF" "${{ github.event.pull_request.head.sha }}")
- vet "$VET_GOAL" --quiet --output-format github \
- --base-commit "$MERGE_BASE" \
- > "$RUNNER_TEMP/review.json"
- status=$?
- if [ "$status" -ne 0 ] && [ "$status" -ne 10 ]; then exit "$status"; fi
-
- jq --arg sha "${{ github.event.pull_request.head.sha }}" \
- '. + {commit_id: $sha}' "$RUNNER_TEMP/review.json" > "$RUNNER_TEMP/review-final.json"
-
- gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews" \
- --method POST --input "$RUNNER_TEMP/review-final.json" > /dev/null || \
- gh pr comment "${{ github.event.pull_request.number }}" \
- --body "$(jq -r '[.body] + [.comments[] | "**\(.path):\(.line)**\n\n\(.body)"] | join("\n\n---\n\n")' "$RUNNER_TEMP/review-final.json")"
- exit 0
+ build-from-source: true
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
@@ -63,8 +63,8 @@ Current workflows:
- `test-unit.yml` (`Test / Unit`, job: `unit`) — pytest suite (lint + unit tests)
- `test-pkgbuild.yml` (`Test / PKGBUILD`, job: `pkgbuild`) — Arch Linux package build + smoke test
-- `vet.yml` (`Vet`, job: `vet`) — Self-review via vet on PRs
-- `vet-agentic.yml` (`Vet (Agentic)`, job: `vet`) — Agentic self-review via vet on PRs
+- `vet.yml` (`Vet`, job: `vet`) — Self-review via vet on PRs (uses the reusable action via `uses: ./`)
+- `vet-agentic.yml` (`Vet (Agentic)`, job: `vet`) — Agentic self-review via vet on PRs (uses the reusable action via `uses: ./`)
- `publish-pypi.yml` (`Publish / PyPI`, job: `pypi`) — Build and publish to PyPI on tag push
- `publish-github-release.yml` (`Publish / GitHub Release`, job: `github-release`) — Create a GitHub Release on tag push
@@ -77,23 +77,15 @@ Vet is published to PyPI via the `publish-pypi.yml` GitHub Actions workflow. Dep
1. Create and checkout a branch to bump the version
2. Update the version in `pyproject.toml`
3. Update `pkgver` in `pkg/arch/PKGBUILD`
-4. Update the recommended GitHub action pinned version in the `README.md`
- ```yaml
- - run: pip install verify-everything==0.2.0
- ```
-5. Commit and push the changes
-6. Tag the commit and push the tag:
+4. Commit and push the changes
+5. Tag the commit and push the tag:
```bash
git tag v0.2.0 -m "v0.2.0: Updated XYZ"
git push origin v0.2.0
```
-7. Create a PR for the new branch
-8. The `Publish / PyPI` workflow will automatically build and publish the package
-9. Merge PR into main.
-
-### Why pin the version in the README?
-
-The README contains a sample GitHub Actions workflow that users copy into their repos. The `pip install verify-everything==X.Y.Z` line in that sample should always reference the latest stable release so that new adopters get a known-good version. Vet is very much experimental. While we give guarantees about it working in a barebones sense, it is not guaranteed that breaking changes won't be made over time so pinning a version for CI makes sense for most use cases.
+6. Create a PR for the new branch
+7. The `Publish / PyPI` workflow will automatically build and publish the package
+8. Merge PR into main.
## Development Notes
diff --git a/README.md b/README.md
@@ -81,7 +81,7 @@ The `--history-loader` option executes the specified shell command as the curren
## GitHub PRs (Actions)
-Vet can run on pull requests.
+Vet can run on pull requests using the reusable GitHub Action.
Create `.github/workflows/vet.yml`:
@@ -100,50 +100,17 @@ jobs:
vet:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
+ env:
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- - uses: actions/setup-python@v5
- with:
- python-version: "3.11"
- - run: pip install verify-everything==0.1.7
- - name: Run vet
- if: github.event.pull_request.head.repo.full_name == github.repository
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- BASE_REF: ${{ github.event.pull_request.base.ref }}
- VET_GOAL: |
- ${{ github.event.pull_request.title }}
-
- Additional context (not necessarily part of the goal):
- ${{ github.event.pull_request.body }}
- run: |
- set +e
- MERGE_BASE=$(git merge-base "origin/$BASE_REF" "${{ github.event.pull_request.head.sha }}")
- vet "$VET_GOAL" --quiet --output-format github \
- --base-commit "$MERGE_BASE" \
- > "$RUNNER_TEMP/review.json"
- status=$?
- if [ "$status" -ne 0 ] && [ "$status" -ne 10 ]; then exit "$status"; fi
-
- jq --arg sha "${{ github.event.pull_request.head.sha }}" \
- '. + {commit_id: $sha}' "$RUNNER_TEMP/review.json" > "$RUNNER_TEMP/review-final.json"
-
- gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews" \
- --method POST --input "$RUNNER_TEMP/review-final.json" > /dev/null || \
- gh pr comment "${{ github.event.pull_request.number }}" \
- --body "$(jq -r '[.body] + [.comments[] | "**\(.path):\(.line)**\n\n\(.body)"] | join("\n\n---\n\n")' "$RUNNER_TEMP/review-final.json")"
- exit 0
+ - uses: imbue-ai/vet@main
```
-NOTE: This will not fail in CI if Vet finds an issue.
-
-#### Environment variables
-
-- `ANTHROPIC_API_KEY` is required for the default model configuration.
+The action handles Python setup, vet installation, merge base computation, and posting the review to the PR. `ANTHROPIC_API_KEY` must be set as a repository secret when using Anthropic models (the default). See [`action.yml`](https://github.com/imbue-ai/vet/blob/main/action.yml) for all available inputs.
## How it works
diff --git a/action.yml b/action.yml
@@ -0,0 +1,111 @@
+name: "Vet: Verify Everything"
+description: "LLM-based code review that finds issues tests and linters miss"
+author: "Imbue"
+
+branding:
+ icon: "check-circle"
+ color: "blue"
+
+inputs:
+ agentic:
+ description: "Enable agentic mode (requires Claude Code; Node.js will be installed automatically)"
+ required: false
+ default: "false"
+ model:
+ description: "LLM model to use"
+ required: false
+ default: ""
+ confidence-threshold:
+ description: "Minimum confidence for reported issues (0.0-1.0)"
+ required: false
+ default: ""
+ max-workers:
+ description: "Maximum number of parallel workers"
+ required: false
+ default: ""
+ max-spend:
+ description: "Maximum API spend in dollars"
+ required: false
+ default: ""
+ temperature:
+ description: "Model temperature (0.0-2.0)"
+ required: false
+ default: ""
+ enabled-issue-codes:
+ description: "Space-separated list of issue codes to enable"
+ required: false
+ default: ""
+ disabled-issue-codes:
+ description: "Space-separated list of issue codes to disable"
+ required: false
+ default: ""
+ config:
+ description: "Named config preset from .vet/configs.toml"
+ required: false
+ default: ""
+ extra-context:
+ description: "Space-separated paths to extra context files"
+ required: false
+ default: ""
+ fail-on-issues:
+ description: "Fail the workflow when vet finds issues"
+ required: false
+ default: "false"
+ build-from-source:
+ description: "Build and install vet from the checked-out source tree instead of PyPI"
+ required: false
+ default: "false"
+
+runs:
+ using: "composite"
+ steps:
+ - name: Setup Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.11"
+
+ - name: Setup Node.js
+ if: inputs.agentic == 'true'
+ uses: actions/setup-node@v4
+ with:
+ node-version: "20"
+
+ - name: Install Claude Code
+ if: inputs.agentic == 'true'
+ shell: bash
+ run: npm install -g @anthropic-ai/claude-code
+
+ - name: Install vet
+ shell: bash
+ run: |
+ if [[ "${{ inputs.build-from-source }}" == "true" ]]; then
+ pip install .
+ else
+ pip install verify-everything
+ fi
+
+ - name: Run vet
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ shell: bash
+ env:
+ GH_TOKEN: ${{ github.token }}
+ INPUT_AGENTIC: ${{ inputs.agentic }}
+ INPUT_MODEL: ${{ inputs.model }}
+ INPUT_CONFIDENCE_THRESHOLD: ${{ inputs.confidence-threshold }}
+ INPUT_MAX_WORKERS: ${{ inputs.max-workers }}
+ INPUT_MAX_SPEND: ${{ inputs.max-spend }}
+ INPUT_TEMPERATURE: ${{ inputs.temperature }}
+ INPUT_ENABLED_ISSUE_CODES: ${{ inputs.enabled-issue-codes }}
+ INPUT_DISABLED_ISSUE_CODES: ${{ inputs.disabled-issue-codes }}
+ INPUT_CONFIG: ${{ inputs.config }}
+ INPUT_EXTRA_CONTEXT: ${{ inputs.extra-context }}
+ INPUT_FAIL_ON_ISSUES: ${{ inputs.fail-on-issues }}
+ INPUT_BASE_REF: ${{ github.event.pull_request.base.ref }}
+ INPUT_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
+ INPUT_PR_NUMBER: ${{ github.event.pull_request.number }}
+ INPUT_GOAL: |
+ ${{ github.event.pull_request.title }}
+
+ Additional context (not necessarily part of the goal):
+ ${{ github.event.pull_request.body }}
+ run: ${{ github.action_path }}/action/run.sh
diff --git a/action/run.sh b/action/run.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+set +e
+
+MERGE_BASE=$(git merge-base "origin/${INPUT_BASE_REF}" "${INPUT_HEAD_SHA}")
+if [ $? -ne 0 ]; then
+ echo "::error::Failed to compute merge base between origin/${INPUT_BASE_REF} and ${INPUT_HEAD_SHA}"
+ exit 1
+fi
+
+ARGS=("${INPUT_GOAL}" --quiet --output-format github --base-commit "${MERGE_BASE}")
+
+[[ "${INPUT_AGENTIC}" == "true" ]] && ARGS+=(--agentic)
+[[ -n "${INPUT_MODEL}" ]] && ARGS+=(--model "${INPUT_MODEL}")
+[[ -n "${INPUT_CONFIDENCE_THRESHOLD}" ]] && ARGS+=(--confidence-threshold "${INPUT_CONFIDENCE_THRESHOLD}")
+[[ -n "${INPUT_MAX_WORKERS}" ]] && ARGS+=(--max-workers "${INPUT_MAX_WORKERS}")
+[[ -n "${INPUT_MAX_SPEND}" ]] && ARGS+=(--max-spend "${INPUT_MAX_SPEND}")
+[[ -n "${INPUT_TEMPERATURE}" ]] && ARGS+=(--temperature "${INPUT_TEMPERATURE}")
+[[ -n "${INPUT_CONFIG}" ]] && ARGS+=(--config "${INPUT_CONFIG}")
+
+[[ -n "${INPUT_ENABLED_ISSUE_CODES}" ]] && ARGS+=(--enabled-issue-codes ${INPUT_ENABLED_ISSUE_CODES})
+[[ -n "${INPUT_DISABLED_ISSUE_CODES}" ]] && ARGS+=(--disabled-issue-codes ${INPUT_DISABLED_ISSUE_CODES})
+[[ -n "${INPUT_EXTRA_CONTEXT}" ]] && ARGS+=(--extra-context ${INPUT_EXTRA_CONTEXT})
+
+vet "${ARGS[@]}" > "${RUNNER_TEMP}/review.json"
+status=$?
+
+if [ "$status" -ne 0 ] && [ "$status" -ne 10 ]; then
+ echo "::error::Vet failed with exit code ${status}"
+ exit "$status"
+fi
+
+jq --arg sha "${INPUT_HEAD_SHA}" \
+ '. + {commit_id: $sha}' "${RUNNER_TEMP}/review.json" > "${RUNNER_TEMP}/review-final.json"
+
+gh api "repos/${GITHUB_REPOSITORY}/pulls/${INPUT_PR_NUMBER}/reviews" \
+ --method POST --input "${RUNNER_TEMP}/review-final.json" > /dev/null || \
+ gh pr comment "${INPUT_PR_NUMBER}" \
+ --body "$(jq -r '[.body] + [.comments[] | "**\(.path):\(.line)**\n\n\(.body)"] | join("\n\n---\n\n")' "${RUNNER_TEMP}/review-final.json")"
+
+if [[ "${INPUT_FAIL_ON_ISSUES}" == "true" ]] && [ "$status" -eq 10 ]; then
+ exit 1
+fi
+
+exit 0
diff --git a/uv.lock b/uv.lock
@@ -1511,7 +1511,7 @@ wheels = [
[[package]]
name = "verify-everything"
-version = "0.1.6"
+version = "0.1.7"
source = { editable = "." }
dependencies = [
{ name = "anthropic" },