Back to the catalog

code-ferret

Diff-scoped semantic code review: bug hunting across logic, security, concurrency, performance, and API-contract vectors.

Open source Open in the app JSON README (API)

About

Diff-scoped semantic code review: bug hunting across logic, security, concurrency, performance, and API-contract vectors.

Details

Kind
Plugins
Topic
Developer tools
Publisher
musicofthings
Origin
gemini
Category
ferramentas
Version
0.4.0
Last push
2026-08-09T16:27:18Z
Repository state
ativo
Language
JavaScript
Added
2026-08-30 14:13:39
Updated
2026-08-30 14:13:39
Origin id
musicofthings/code-ferret

README

# CodeFerret ๐Ÿฆก

Autonomous code review and bug-hunting plugin, model-agnostic across the
frontier AI stack: [Claude Code](https://claude.com/claude-code) and Claude
Desktop, OpenAI Codex, Gemini CLI, and any other MCP client.
Diff-scoped semantic review across five detection vectors โ€” logic, security,
concurrency, performance, and API contracts โ€” with confidence scoring,
linter deduplication, a false-positive suppression cache, interactive triage,
and a pre-commit secret guard.

**CodeFerret runs entirely on your machine.** There is no CodeFerret service,
account, or API key: the review is performed by a coding agent you already have
installed, and your code never leaves your computer through anything CodeFerret
does. That is the deliberate difference from hosted reviewers like CodeRabbit.
The one setting that can make a network call โ€” dependency auditing โ€” is off by
default and documented below.

## Install

### Claude Code (plugin)

```bash
# From a local clone
/plugin marketplace add ~/projects/code-ferret
/plugin install code-ferret@code-ferret-marketplace

# Or from GitHub
/plugin marketplace add musicofthings/code-ferret
/plugin install code-ferret
```

### Claude Desktop (MCP Bundle)

```bash
bash mcp-server/build-mcpb.sh   # produces dist/code-ferret.mcpb
```

Double-click the bundle (or drag it into Claude Desktop) to install. See
`packaging/claude-desktop/README.md`.

### OpenAI Codex

Register the MCP server in `~/.codex/config.toml` and copy the
`/ferret-review`, `/ferret-precommit`, `/ferret-triage` custom prompts. See
`packaging/codex/README.md`.

### Gemini CLI (extension)

```bash
gemini extensions install https://github.com/musicofthings/code-ferret
cd ~/.gemini/extensions/code-ferret/mcp-server && npm install
```

The repo root is a Gemini CLI extension (`gemini-extension.json`): it wires up
the MCP server, `GEMINI.md` context, and `/ferret:review`, `/ferret:precommit`,
`/ferret:triage` commands.

### Any other MCP client (Cursor, Grok desktop, ...)

Run `npm install` in `mcp-server/`, then point the client at
`node mcp-server/server/index.js` (stdio). The host's model does the semantic
analysis, so CodeFerret works with whichever frontier model the client runs.

## Model compatibility

CodeFerret never calls a model API itself. The semantic analysis is done by
whatever model your host application already runs โ€” Claude Code, Claude
Desktop, Codex, Gemini CLI, or any other MCP client โ€” so it is model-agnostic
by construction, with no provider registry, no key to configure, and no model
for CodeFerret to keep up to date.

The standalone CLI works the same way: it shells out to an installed `claude`,
`codex`, or `gemini` and reads back the findings file. See [CLI](#cli).

## Commands

| Command | What it does |
|---|---|
| `/code-ferret:review [staged\|head\|<base>]` | Full semantic review of the diff. Writes findings to `.ferret/last-review.json` and prints a report with clickable `file:line:col` locations, severity tiers, confidence ratings, and ready-to-apply patches. |
| `/code-ferret:triage` | Steps through findings one by one: **Accept & apply patch**, **Ignore pattern** (suppresses it in future runs), **Discuss**, or **Skip**. |
| `/code-ferret:precommit` | Fast staged-only check. Reports only CRITICAL + HIGH-confidence blockers and secrets. First line is `FERRET: PASS` or `FERRET: BLOCK`. |

## CLI

CodeFerret also ships a standalone CLI that runs reviews from any terminal by
delegating to a coding agent you already have installed (`claude`, `codex`, or
`gemini`) โ€” no API key and no CodeFerret account.

```bash
cd cli && npm link      # or, from the repo root: npm install -g ./cli
ferret doctor           # verify the setup first
ferret                  # review committed + staged + unstaged changes
```

| Command | What it does |
|---|---|
| `ferret [review]` | Review the current diff; plain-text report |
| `ferret review --agent` | Structured JSONL for coding agents and automation |
| `ferret review --light` | Fast policy: no analyzers, `-U10` context, LOGIC + SECURITY only |
| `ferret review findings` | Replay the last review without re-analyzing |
| `ferret review --show-prompts` | Print the prompts from the last review |
| `ferret doctor` | Verify setup and connectivity; exit 1 on failure |
| `ferret stats [--rebuild]` | Review statistics from `.ferret/history.jsonl` |

Scope flags: `--committed`, `--uncommitted`, `--include-untracked`,
`--base <branch>`, `--base-commit <sha>`, `--dir <path>`, `-c/--config <file>`.
Contradictory combinations are rejected before a review starts, as is a base
ref that does not resolve โ€” a review that cannot run always exits non-zero,
never "no changes found".

### Agent output (`--agent`)

One JSON object per line on stdout, and nothing else โ€” anything a human would
read goes to stderr.

| `type` | When |
|---|---|
| `review_context` | Once, first: target, branch, base ref, file count, agent, light |
| `status` | Phase change: `collecting_context`, `reviewing`, or `review_skipped` |
| `heartbeat` | Every 15s while the agent is running |
| `finding` | One per finding; severity on the wire is `critical`/`major`/`minor` |
| `prompts` | `--show-prompts` only: the saved prompts from the last review |
| `complete` | Once, last, on success โ€” including the empty-diff case |
| `error` | Once, last, on any failure |

Every failure path emits an `error` event, including ones that occur before a
review starts (bad flags, unresolvable base ref, no agent, a blocked lock), so
a consumer never has to distinguish "failed" from "produced nothing".

### Concurrent reviews

Reviews are serialized per repository through a `.ferret/review.lock`. A second
`ferret review` against the same repo fails immediately, naming the process
that holds the lock, rather than queueing or letting two agents overwrite each
other's results. A lock left behind by a killed process is reclaimed
automatically โ€” either its process is gone, or it has aged out.

The MCP review prompt takes the same lock through the `ferret_review_lock`
tool, so a prompt-driven review and a terminal `ferret review` cannot run
against one repository at once. That path holds a **30-minute lease** rather
than a process-lifetime lock: the MCP server stays alive between tool calls, so
its process being up says nothing about whether a review is still going, and
only an expiry can free one that was abandoned mid-conversation. Use
`ferret_review_lock` with `status` to see the holder, or `release` with `force`
to clear an abandoned lock without waiting out the lease.

Because the agent writes `.ferret/last-review.json` with its own file tools
rather than through the server, this lock is **cooperative** โ€” it is honored by
the shipped review prompt, not enforced against an agent that ignores it.

Every `ferret review` spawns a real agent session against your existing
subscription. Use `--light` for the cheap path, and keep the git pre-commit
hook on the pure-bash secret scan rather than a full review.

## What gets reviewed

Only the diff plus its surrounding lexical scope, never the whole repo. Each
hunk is shown with its **complete enclosing function** (`git -W`), not a fixed
number of context lines โ€” a small edit deep inside a 600-line function still
arrives with the whole function attached, which a fixed `-U` window cannot do.
Standard `.gitignore` rules apply automatically; add a `.ferretignore`
(gitignore syntax) at the repo root to also skip generated files, schemas,
minified assets, etc.

Lockfile *hunks* (`package-lock.json`, `Cargo.lock`, `go.sum`, and nine others)
are omitted by default โ€” thousands of machine-generated lines no semantic
vector can find a bug in. Their names still appear in the changed-file and
dependency-manifest lists, so version-bump analysis is unaffected. Set
`FERRET_INCLUDE_LOCKFILES=1` to include them.

Detection vectors:

- **LOGIC** โ€” off-by-one, boundary conditions, null/undefined flow, unhandled promises, resource leaks, infinite loops
- **SECURITY** โ€” hardcoded secrets, SQL injection, XSS, unsafe deserialization, OWASP Top 10
- **CONCURRENCY** โ€” races, deadlocks, non-atomic read-modify-write, unsynchronized shared state
- **PERFORMANCE** โ€” O(Nยฒ) on unbounded data, N+1 queries, redundant allocations
- **API** โ€” breaking public contract changes, type-safety violations, SDK misuse

Style and lint issues are explicitly out of scope โ€” findings matching an
existing linter rule are deduplicated away.

Before semantic analysis, full reviews run known analyzers that are already
installed: ESLint, Ruff, ShellCheck, TypeScript, Semgrep with a checked-in
configuration, and the CodeFerret secret scanner. Tools are never installed
automatically or invoked through arbitrary package scripts. Normalized,
secret-scrubbed results are saved to `.ferret/tool-results.json`. Analyzers run
in the current environment and may load repository-owned configuration or
plugins, so run them only in a checkout you trust.

Dependency auditing (`npm audit`, `pip-audit`) is **off by default**: it is the
only analyzer group that contacts the network, sending your dependency tree to
the npm registry or the advisory API. Your source is never sent, but the call
happens, so enabling it is a deliberate choice โ€” set `tools.dependencies: true`
in `.codeferret.yaml`. Everything else runs offline.

## Configuration

Copy `.codeferret.example.yaml` to `.codeferret.yaml` to configure review
behavior. Supported controls include:

- `reviews.profile`: `chill`, `balanced`, or `assertive`
- `reviews.minimum_severity`: `critical`, `warning`, or `suggestion`
- `reviews.ignore`: repository-relative glob patterns
- `reviews.path_instructions`: focused review policy for matching paths
- `guidelines`: automatic discovery of `AGENTS.md`, `CLAUDE.md`,
  `.cursorrules`, or additional repository policy files
- `reports`: PR summary, walkthrough, risk assessment, and linked-issue
  validation controls
- `tools`: installed linter, type-checker, security, dependency, and CI-context
  controls with bounded execution time

`/code-ferret:review` runs use the working tree configuration and root-level
guideline context from `collect-context.sh`.

### Collector environment variables

`collect-context.sh` is tuned through the environment. Defaults are chosen so a
review is cheap without losing the context needed to trace a failure.

| Variable | Default | Effect |
|---|---|---|
| `FERRET_FUNCTION_CONTEXT` | `1` (`0` in light mode) | Show each hunk's complete enclosing function via `git -W`. `0` falls back to a fixed line count. |
| `FERRET_CONTEXT_LINES` | `12` (`6` light) | Fixed context lines when function context is off. |
| `FERRET_OUT` | unset | Write the payload to this path and print only a compact index of section line ranges. Keeps a large diff out of the agent's transcript. |
| `FERRET_FILES` | unset | Colon- or newline-separated file subset. Scopes a batch when working a large diff in sequence. |
| `FERRET_SKIP_GUIDELINES` | `0` | Omit `AGENTS.md`/`CLAUDE.md`/`.cursorrules` bodies when the host agent already has them. |
| `FERRET_INCLUDE_LOCKFILES` | `0` | Include lockfile hunks in the diff. |
| `FERRET_LIGHT` | `0` | Speed over depth: fixed `-U6`, no per-file history. |
| `FERRET_DIR_PATHSPEC` | `.` | Restrict everything to one subtree. |
| `FERRET_BASE_REF` | `main` | Base ref for `all` mode. |
| `FERRET_INCLUDE_UNTRACKED` | mode-dependent | Force untracked files in. |
| `FERRET_MAX_TOOL_OUTPUT` | `8000` | Per-analyzer output cap, head+tail truncated so summary lines survive. |

### Sharding a large review

`scripts/plan-shards.sh <target> <n>` prints `n` colon-joined file lists,
balanced by diff size rather than file count, ready to pass as `FERRET_FILES`:

```bash
bash scripts/plan-shards.sh main 5
```

Collect once with `FERRET_OUT`, then give each reviewer one shard and the
shared context file. Collecting per-agent instead multiplies a review's cost by
the number of agents.

## Noise control

- Every finding carries a **confidence** rating (HIGH/MEDIUM/LOW) based on
  structural proof, independent of **severity** (CRITICAL/WARNING/SUGGESTION).
- Choosing **Ignore pattern** during triage records a structural hash in
  `.ferret/review-cache.json`; matching findings are silently suppressed in
  future reviews. Manage the cache with:

  ```bash
  python3 scripts/fp_cache.py list
  python3 scripts/fp_cache.py add <file> <vector> "<message>" "<reason>"
  ```

  Commit `.ferret/review-cache.json` to share suppressions with your team.

## Pre-commit guard (hook)

The plugin ships a `PreToolUse` hook: whenever Claude Code runs `git commit`,
staged changes are regex-scanned for credentials (GitHub/AWS/Anthropic/Slack
tokens, private keys, generic high-entropy assignments) and the commit is
blocked if any are found. It is fast (pure bash/grep, no LLM call).

For commits made outside Claude Code, install the native git hook:

```bash
cp examples/git-pre-commit-hook .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
git config codeferret.root "$(pwd)"
```

If the target repository is not the CodeFerret checkout, set
`codeferret.root` to CodeFerret's absolute installation path instead.

## Privacy guardrails

- Reviews run on your machine, through a coding agent you already installed.
  There is no CodeFerret service or account, and no telemetry.
- Code payloads are regex-scrubbed for credentials (`[REDACTED_SECRET]`) before
  reaching the model.
- Secret *locations* are reported, never secret values.
- Nothing CodeFerret runs contacts the network, with one opt-in exception:
  dependency auditing (`tools.dependencies`, off by default) calls the npm
  registry / advisory API. Your source is never transmitted.
- `.ferret/` state stays in your working tree; only the shareable
  false-positive cache (`review-cache.json`) is intended to be committed.

## Tests

```bash
# Shell collectors, secret scanner, commit guards, and the analyzer runner
bash tests/run.sh

# Analyzer runner and model checks
python3 -m pytest tests/ -v

# CLI unit tests
cd cli && npm test
```

`tests/run.sh` covers the context-collection controls that determine what a
reviewer actually sees: `FERRET_OUT` indexing, `FERRET_FILES` sharding (both
ends of the list), guideline omission, lockfile suppression and opt-in,
function context on/off/light, and shard partitioning.

## Layout

```
code-ferret/
โ”œโ”€โ”€ .claude-plugin/plugin.json      # Claude Code plugin manifest (+ marketplace.json)
โ”œโ”€โ”€ gemini-extension.json           # Gemini CLI extension manifest (+ GEMINI.md)
โ”œโ”€โ”€ commands/                       # /code-ferret:* (Claude Code .md) + ferret/*.toml (Gemini CLI)
โ”œโ”€โ”€ skills/code-ferret/             # review methodology + vector checklists + schema
โ”œโ”€โ”€ hooks/hooks.json                # PreToolUse git-commit secret guard
โ”œโ”€โ”€ scripts/                        # collectors, shard planner, analyzers, fp cache
โ”œโ”€โ”€ cli/                            # standalone `ferret` CLI (delegates to your agent)
โ”œโ”€โ”€ mcp-server/                     # MCP server + MCPB bundle build (Claude Desktop et al.)
โ”œโ”€โ”€ packaging/                      # Codex prompts/config, Claude Desktop install guide
โ””โ”€โ”€ examples/                       # native git pre-commit hook
```

More