paranoid_
Integrate

Integrations

Ways to wire paranoid into a workflow: the GitHub Action, a pre-commit hook, and Claude Code (a Stop hook plus an MCP server). All run the same binary you use locally; none is a separate product.

GitHub Action

The composite action at alainrk/paranoid/action@main runs verify on the pull request range, uploads the report as an artifact, appends it to the job summary, optionally posts a sticky PR comment, and sets the check status from the verdict. Full inputs, outputs, and the SARIF upload example are on the Exit codes & CI page.

- uses: alainrk/paranoid/action@main
  with:
    sandbox: none # or auto, when the runner has docker
    claims: summary.md # optional

pre-commit

This repository ships .pre-commit-hooks.yaml with one hook, paranoid-verify. Add it to a target project's .pre-commit-config.yaml:

repos:
  - repo: https://github.com/alainrk/paranoid
    rev: main # pin a tag or commit
    hooks:
      - id: paranoid-verify

Then, in the target project:

pre-commit install --hook-type pre-commit --hook-type pre-push
pre-commit run paranoid-verify --all-files # try it once by hand

What the hook runs

paranoid verify --sandbox none --offline --base HEAD

What "the commit range" means at each stage

stages: [pre-commit, pre-push] runs the exact same command at both points, and --base HEAD means different things depending on when it runs.

Why language: golang

pre-commit's golang language builds the hook's own repository with go install ./... inside an isolated Go environment it manages itself. Since this repo has a go.mod at the root and its command lives at cmd/paranoid, that install produces a binary named paranoid (Go names the binary after the directory holding package main), which lands on PATH inside pre-commit's environment and matches the hook's entry line. No manual install step or wrapper script is needed; the only prerequisite is a Go toolchain, which pre-commit's golang language can provide on its own.

There is no GitLab CI component or merge-request comment integration.

Claude Code

A settings.json hook config, and an MCP server. Neither needs extra Go code; the hook is pure configuration. Full docs, the settings snippet, and the security notes: integrations/claude-code/README.md.

Stop hook and PreToolUse variant

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "paranoid verify --sandbox none --offline --format text --fail-under 80 --strict 1>&2"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(git commit *)",
            "command": "paranoid verify --sandbox none --offline --format text --fail-under 80 --strict 1>&2"
          }
        ]
      }
    ]
  }
}

Copy the hooks block into .claude/settings.json (committed, shared) or .claude/settings.local.json (personal). Claude Code's Stop hook contract blocks the session only on exit code 2, with the command's stderr fed back as the reason; the trailing 1>&2 redirects verify's report (stdout by default) to stderr so Claude actually sees it, and --strict maps a warn verdict onto exit 2 too, since a plain exit 1 does not block. The PreToolUse variant uses Claude Code's if field to gate on the Bash tool's command text (Bash(git commit *)), the real mechanism for scoping a hook to one command; matcher alone only matches the tool name.

MCP server

paranoid mcp runs a Model Context Protocol server over stdio: newline-delimited JSON-RPC 2.0, hand-rolled on the standard library, no SDK dependency. It implements initialize, tools/list, and tools/call for one tool, verify (arguments: path, base, head, claims, session, offline, sandbox), which runs the same pipeline as paranoid verify and returns the JSON report as the tool result. Wire it into Claude Code as an MCP server, for example:

{
  "mcpServers": {
    "paranoid": {
      "command": "paranoid",
      "args": ["mcp"]
    }
  }
}

Trust boundary

Both integrations are only as trustworthy as the binary they run and the files that configure them. If the agent under audit can edit the installed paranoid binary, .paranoid-baseline.json, or the hook configuration, it can make paranoid say pass. Install paranoid outside the repository the agent can write to, and point the hook at that installed binary on PATH, never a repo-local build. SF006 watches .paranoid-baseline.json and hook configuration files for exactly this: it does not prevent the edit, it surfaces it as a finding in the next run a human reads.