| name | neohaskell-code-review-ci |
| description | SCAFFOLDS the one-time CI pipeline file that runs neohaskell-code-review on every pull/merge request headlessly, with no third-party review SaaS. Use when SETTING UP automated PR review for a NeoHaskell project, wiring code review into CI, or making neohaskell-code-review run in GitHub Actions, GitLab CI, Azure DevOps, or Bitbucket Pipelines. Auto-detects the provider from repo layout (.github/, .gitlab-ci.yml, azure- pipelines.yml, bitbucket-pipelines.yml) and emits the native pipeline config, documenting ANTHROPIC_API_KEY and PR-write permissions. Do NOT use to actually RUN a review on the current diff right now (neohaskell-code-review), to set up general build/test CI or hurl/test-running workflows (neo-cli plus the provider's own docs), or to configure code review for a non-NeoHaskell (e.g. TypeScript) repo. One-time setup; does not run per commit. |
| metadata | {"model":"sonnet"} |
This is NeoHaskell, not vanilla Haskell. The .hs extension is shared between them — the CI pipeline you are wiring here reviews NeoHaskell source, which uses import Core (not Prelude), Task (not IO), and the custom trap table. The upstream neohaskell-code-review skill knows all of this; your job here is purely CI plumbing.
In Claude Code this skill runs inline at Sonnet tier. In Cursor or Codex the metadata.model is advisory; the template generation is straightforward enough to run in any host.
Inputs / Outputs / Next
- Input: the project root (to auto-detect the CI provider) + answers to three questions: (1) should the job post inline PR comments, post a summary comment, or summary-only? (2) should it fail the check on any blocker finding? (3) is there a non-default base branch (default:
main)?
- Output: one provider-native pipeline file, a required-secrets checklist, and a permissions setup note.
- Next: — (this is a one-time setup;
neohaskell-code-review handles the ongoing per-PR review logic).
Step 1 — Detect the CI provider
Check which of these exists in the project root:
| Path present | Provider |
|---|
.github/ directory | GitHub Actions |
.gitlab-ci.yml file | GitLab CI |
azure-pipelines.yml file | Azure DevOps |
bitbucket-pipelines.yml file | Bitbucket Pipelines |
| None of the above | Ask the user which provider they use |
Emit only the template for the detected provider. Do not emit all four; that creates confusion.
Step 2 — Required secrets and permissions
Before writing the pipeline file, tell the user exactly what to add. The list is short and non-negotiable:
Every provider:
| Secret | Where to add | Purpose |
|---|
ANTHROPIC_API_KEY | CI project secrets / repository secrets | Authenticates claude to the Anthropic API |
Provider-specific tokens and permissions — see the Per-Provider Setup note in each template below. GitHub Actions uses the built-in GITHUB_TOKEN with pull-requests: write in the workflow file; GitLab, Azure DevOps, and Bitbucket each need an additional personal-access token or pipeline variable with comment-post scope.
Step 3 — Emit the pipeline template
Pick the matching section. Every template follows the same logic:
- Trigger on PR/MR open and update.
- Checkout with full history (
fetch-depth: 0 or equivalent) — the diff requires both base and head commits.
- Install Node.js and
@anthropic-ai/claude-code.
- Compute the diff between base and head into a file.
- Build a prompt referencing
neohaskell-code-review and pipe the diff into claude -p.
- Post the review output as a PR/MR comment via the provider API.
- Exit non-zero if the review output contains the word "blocker" and
FAIL_ON_BLOCKERS is true.
Template A — GitHub Actions
File: .github/workflows/neohaskell-review.yml
Per-Provider Setup: GITHUB_TOKEN is automatically injected by Actions. Add pull-requests: write permission in the workflow (shown below). No extra token is needed. Add ANTHROPIC_API_KEY under Settings → Secrets and variables → Actions → Repository secrets.
name: NeoHaskell Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
env:
FAIL_ON_BLOCKERS: "true"
jobs:
neohaskell-review:
runs-on: ubuntu-latest
steps:
- name: Checkout (full history for diff)
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install Claude Code
run: npm
Template B — GitLab CI
File: append a new job to .gitlab-ci.yml
Per-Provider Setup: create a Project Access Token (or personal token) with api scope. Add it as a CI/CD variable named GITLAB_TOKEN (masked, protected). Also add ANTHROPIC_API_KEY as a masked variable. GitLab provides CI_PROJECT_ID and CI_MERGE_REQUEST_IID automatically.
neohaskell-review:
stage: test
image: node:20-slim
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
GIT_DEPTH: "0"
FAIL_ON_BLOCKERS: "true"
script:
- apt-get update -qq && apt-get install -y -qq git curl python3
- npm install -g @anthropic-ai/claude-code
- git fetch origin "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
- git diff "origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}...${CI_COMMIT_SHA}"
> /tmp/pr.diff
- |
cat > /tmp/prompt.txt << 'PROMPT'
Run the neohaskell-code-review skill on the diff below.
Emit severity-ranked findings (blocker/major/minor/nit) with
file:line citations and a concrete fix for each, then a one-line verdict.
PROMPT
cat /tmp/pr.diff
Template C — Azure DevOps
File: add a stage to azure-pipelines.yml
Per-Provider Setup: enable Allow scripts to access the OAuth token in the pipeline's Agent job settings (or set persistCredentials: true in the checkout step). This makes $(System.AccessToken) available, which has comment-post scope on the current PR. Add ANTHROPIC_API_KEY as a secret pipeline variable.
stages:
- stage: NeoHaskellReview
displayName: NeoHaskell Code Review
condition: eq(variables['Build.Reason'], 'PullRequest')
variables:
FAIL_ON_BLOCKERS: "true"
jobs:
- job: Review
pool:
vmImage: ubuntu-latest
steps:
- checkout: self
fetchDepth: 0
- task: NodeTool@0
inputs:
versionSpec: "20.x"
displayName: Set up Node.js
- script: npm install -g @anthropic-ai/claude-code
displayName: Install Claude Code
- script: |
git diff \
"origin/$(System.PullRequest.TargetBranchName)...$(Build.SourceVersion)" \
> /tmp/pr.diff
Template D — Bitbucket Pipelines
File: add a step to bitbucket-pipelines.yml
Per-Provider Setup: create a Repository Access Token (or app password) with pullrequest:write scope. Add it as a repository variable named BITBUCKET_TOKEN (secured). Also add ANTHROPIC_API_KEY as a secured repository variable. Bitbucket provides BITBUCKET_REPO_FULL_NAME and BITBUCKET_PR_ID automatically.
pipelines:
pull-requests:
'**':
- step:
name: NeoHaskell Code Review
image: node:20-slim
clone:
depth: full
script:
- apt-get update -qq && apt-get install -y -qq git curl python3
- npm install -g @anthropic-ai/claude-code
- export FAIL_ON_BLOCKERS="true"
- git diff
"origin/${BITBUCKET_PR_DESTINATION_BRANCH}...${BITBUCKET_COMMIT}"
> /tmp/pr.diff
- |
cat > /tmp/prompt.txt << 'PROMPT'
Run the neohaskell-code-review skill on the diff below.
Emit severity-ranked findings (blocker/major/minor/nit) with
file:line citations and a concrete fix for each, then a one-line verdict.
PROMPT
cat /tmp/pr.diff >> /tmp/prompt.txt
DO / DON'T
| You might do — DON'T | NeoHaskell-correct — DO | Why |
|---|
| Emit a GitHub-only template regardless of the project's CI provider | Auto-detect the provider from the repo layout and emit only the matching template | The skill is provider-agnostic by design; forcing GitHub Actions on a GitLab project breaks immediately |
Use fetch-depth: 1 (shallow clone) | fetch-depth: 0 (full history) or the provider equivalent | A shallow clone cannot compute a meaningful diff between base and head; git diff will fail or produce empty output |
Hard-code ANTHROPIC_API_KEY in the YAML | Inject it from CI secrets / masked variables | A plaintext key in a committed file is a security blocker; every provider has a secrets store |
| Depend on CodeRabbit, SonarCloud, or another third-party review SaaS | Invoke claude -p "..." using the project's own ANTHROPIC_API_KEY | The whole point of this skill is a self-hosted, no-SaaS reviewer |
Run neo build or neo test inside the review job | Only compute the diff and run claude -p; do not attempt to compile the project | The review is diff-scoped and static; building requires Nix and is a separate CI concern |
Use git diff HEAD~1...HEAD as the diff | Use the actual base and head SHAs provided by the PR event | HEAD~1 is one commit behind the merge commit, not the true base branch; it produces wrong diffs on multi-commit PRs |
| Post the review output as a commit status only | Post as a PR/MR comment (and optionally fail the check on blockers) | A comment is visible to reviewers immediately; a status check alone is easy to miss |
Omit the FAIL_ON_BLOCKERS guard | Add a grep for blocker and exit 1 when FAIL_ON_BLOCKERS=true | Without a failing exit code the check always passes green, even on correctness regressions |
Use String or [Char] in any Haskell you write | Text everywhere; import Core | Reminder: this pipeline reviews NeoHaskell; the reviewer knows the trap table — the CI just needs to call it |
Large-diff note
claude -p runs a single prompt. If the PR diff is very large (thousands of lines), it may exceed the model's context window. In that case, split the diff by file and run one claude -p call per file, then concatenate the findings. Example:
git diff "$BASE"..."$HEAD" --name-only | while read -r file; do
git diff "$BASE"..."$HEAD" -- "$file" > /tmp/file.diff
claude -p "Run the neohaskell-code-review skill on this single-file diff:
$(cat /tmp/file.diff)" >> /tmp/review.txt
done
This is only needed for unusually large PRs; the standard single-call template handles typical feature-slice diffs comfortably.
Verify
Trigger a test PR (even a trivial change) against the repository after adding the workflow file and the required secrets. Confirm:
- The CI job appears in the PR's check list.
- A review comment is posted by the CI bot on the PR.
- If
FAIL_ON_BLOCKERS=true and you plant a deliberate violation (e.g., add import Data.Text directly in a module), the check fails.
- On a clean diff the check passes green.
There is no neo build step here — the review is static. The only external dependency is ANTHROPIC_API_KEY being valid and the @anthropic-ai/claude-code package being installable from npm.