docs Home GitHub

Command reference

Every command, its flags, the environment variables perch reads, and its exit codes.

The Perch command line interface (CLI) lets you scan code, review issues and manage rules from your terminal. Every command follows the same pattern:

perch <command> [options]
CommandDescriptionNeeds
loginSign in to Perch Cloud.a browser
logoutRemove this device's Perch Cloud login.nothing
scanScan the repository at HEAD and save the issues.a model endpoint
coverageRun your tests against mutated code and list the gaps.a model endpoint and your test tools
issuesList the issues the last scan found, or show one.nothing
checkCheck one file or method on disk without recording anything.a model endpoint
rulesList, add, edit and remove rules in perch.yaml.nothing
closeClose issues.nothing
reopenReopen closed issues.nothing
setupInstall the Perch skill for a coding assistant.nothing
ciList this branch's CI runs, or show one run's issues.perch login, or a CI token in PERCH_API_KEY
cloudShow or change this repository's Perch Cloud settings.perch login
doctorCheck that Perch can run, and report on the last run.nothing

Commands that need a model endpoint use Perch Cloud by default. You can sign in with perch login, a CI token or a GitHub Actions OIDC token, or set PERCH_BASE_URL to use a different endpoint. See Environment.

Every command accepts --json, which prints the same information as JSON. Commands that read or write results accept --out DIR, which defaults to .perch. To see a command's options, run perch <command> --help. perch findings is another name for perch issues.

perch login#

perch login [organization-id]

Prints a link and a code to confirm in your browser, then saves the login to ~/.perch/cloud.json, outside the repository. If your account belongs to more than one organization, Perch lists them and asks you to run perch login <id> with the one you want.

perch logout#

perch logout

Removes the login saved on this device. To revoke a CI token, use the Perch Cloud dashboard.

perch scan#

perch scan [target] [options]

Parses the repository at HEAD with tree-sitter, then asks the model about each method with its callers and callees in view. Custom rules from perch.yaml and .perch/rules/ are asked at the same time. target is a file or directory to scan, and defaults to the current directory.

The scan exits with code 3 when it lists a problem. scan_types in perch.yaml sets which types of problem it asks about, and defaults to defect and lint.

With --since, Perch asks only about methods the diff touches. The bug questions has_bug, bug_edge_case, kind and severity go in a request that contains the method's code at the merge base with REF and the diff, without callers or callees. Custom rules and other types of question are asked in the usual request, with callers and callees.

FlagDescription
--paths a,bScan only files under these repository paths.
--since REFScan only what changed since this branch or commit. Use --since origin/main in CI.
--filter k=vAsk only the questions that can raise a matching issue, such as type=security, kind=off_by_one or rule=<name>. severity= asks everything. The scan fails only on what it lists.
--include-testsAlso review test code and test helpers.
--include-filesAlso parse documents, configuration, styles and templates with their own grammars.
--parallel NHow many methods to ask about at once. Default 32. Files and tests run 32 at a time alongside them.
--forceAsk again instead of using Perch Cloud's cached answers, and replace the cached answers.
--min PList only issues Perch is more than P percent sure of. Default 50. --min 0 lists everything.
--allList every row instead of the top 10.
--out DIRResults directory. Default .perch.
--jsonPrint JSON instead of the table.
--verboseShow every file, method, model call and command.

perch coverage#

perch coverage [target] [options]

Runs your tests against small edits to your code, called mutants, and asks the model which surviving mutants a caller could notice. It lists those survivors, tests that catch nothing, and tests that catch exactly what another test catches. Test coverage explains the output and lists the supported test frameworks. It exits with code 3 when it lists a problem and 1 when it can't run your tests.

FlagDescription
--paths a,bCover only files under these repository paths.
--since REFReport only problems in code changed since this branch or commit.
--diff REFCompare with the run saved at this branch or commit.
--filter kind=Only these kinds of problem: survived, redundant, checks_nothing, mocked, infra.
--parallel NHow many tests or methods to ask about at once. Default 32.
--min PList only problems Perch is more than P percent sure of. Default 50.
--allList every method and every surviving mutant instead of the top 10.
--html FILEWhere to write the HTML report. Default coverage/index.html under --out.
--out DIRResults directory. Default .perch.
--jsonPrint JSON instead of the tables.
--verboseShow every file, method, model call and command.

perch issues#

perch issues [issue-id] [options]

Lists open issues from the last scan, most serious first, 10 rows at a time. With an issue ID, it shows everything Perch recorded about that method. It reads .perch and sends no requests.

FlagDescription
--filter k=vOnly issues that match, such as type=security, kind=off_by_one, severity=P1 or rule=<name>. Separate several values with commas.
--typesPrint every value --filter accepts, then exit.
--allList every row instead of the top 10.
--limit NRows per page. Default 10.
--page NWhich page to show, starting at 1.
--closedInclude closed issues.
--min PList only issues Perch is more than P percent sure of. Default 50.
--out DIRResults directory. Default .perch.
--jsonPrint JSON instead of the table.

perch check#

perch check <path | path::method | issue-id> [options]

Checks a single method or file as it is on disk. For a method, Perch asks its built-in questions and every custom rule that applies to it. For a file, it asks the rules that apply to the file. perch check works on uncommitted code and doesn't save its results. It exits with code 3 if anything it checked is still broken.

FlagDescription
--rules a,bAsk only these: rule names, or defect, security, refactor, docs.
--forceAsk again instead of using Perch Cloud's cached answers.
--out DIRResults directory. Default .perch.
--jsonPrint JSON instead of the table.
--verboseShow every file, method, model call and command.

perch rules#

perch rules [list | add <name> | edit <name> | remove <name>] [options]

Writes rules to perch.yaml, or to the file under .perch/rules/ that --file names, and keeps the file's comments and order. edit and remove find the file a rule is in. Most rules are a yes-or-no sentence, so --ensure is often the only flag you need:

perch rules add errors-reach-the-caller --each method --where "**/*.py" --ensure "When this method catches an exception, it raises it again or returns an error."
FlagDescription
--ensure TEXTA sentence that has to be true of every file or method the rule covers.
--ensure_present TEXTSomething that has to exist somewhere in what the rule covers.
--ensure_absent TEXTSomething that must not exist anywhere in what the rule covers.
--where WWhat the rule covers: a glob, callers of <method>, or mentions <text>. Default **/*.
--except WA glob for paths the rule skips.
--each UAsk about each file, method or test instead of each file as a whole.
--sees SWhat else to show with a file or test: file, calls, callers or neighbors.
--context PATHA document to send with each file, method or test: a path from the repository root, or a file name to look for in the code's directory and the directories above it.
--min PThe floor for this rule, in percent.
--gate yes|noWhether breaking the rule fails a scan. Default yes.
--file FThe rule file: perch.yaml or a .yaml file under .perch/rules/. add creates it, and list shows only it.
--jsonPrint JSON instead of the table.

For a question whose answer isn't yes or no, use the longhand flags:

FlagDescription
--type TThe kind of answer: noul, choice or score. Default noul.
--ask TEXTThe question, in place of --ensure.
--true TEXT / --false TEXTWhat a yes and a no mean, for --type noul.
--options "a=..; b=.."The options and what each one means, for --type choice.
--levels "a; b; c"The grades, weakest first, for --type score.
--when NAMEAnother question this one depends on. Perch multiplies the two probabilities.
--issue "type=..,label=.."What an answer means: type, label, on, pick, except.

Semantic linting has an example of each kind of rule.

perch close#

perch close <issue-id>... [options]

Closes one or more issues, such as false positives or code you've reviewed and decided to keep. A closed issue stays closed through later scans and edits until you reopen it, and perch issues <id> shows the reason you gave. You can also close a problem reported by perch coverage by passing its ID.

FlagDescription
--reason RWhy you're closing it. Perch keeps the reason with the issue.
--kind a,bClose only these kinds of problem on the issue, such as docs or too_big. Default: every kind on it now.
--out DIRResults directory. Default .perch.
--jsonPrint JSON instead of a summary.

perch reopen#

perch reopen <issue-id>... [options]

Puts closed issues back on the list. --kind reopens only some kinds of problem on an issue.

perch setup#

perch setup <claude-code | codex | pi | cursor> [options]

Installs the Perch skill for a coding assistant in the current repository:

AssistantFile
claude-code.claude/skills/perch/SKILL.md
codex.codex/skills/perch/SKILL.md
pi.pi/skills/perch/SKILL.md
cursor.cursor/rules/perch.mdc

It also adds Perch Cloud's MCP server, perch-cloud at https://dash.perchscan.com/mcp, to .mcp.json for Claude Code and .cursor/mcp.json for Cursor. For Codex, it prints the codex mcp add command to run. An existing perch-cloud entry is left as it is.

If the skill file matches the one this version of Perch ships, Perch changes nothing. If it differs, because you edited it or an older Perch wrote it, Perch leaves it alone and exits with code 2.

FlagDescription
--forceReplace the skill file, including your edits.
--jsonPrint JSON instead of a summary.

perch in a coding assistant lists what the skill tells the assistant to do.

perch ci#

perch ci [run-id] [options]

Lists this branch's CI runs in Perch Cloud, newest first, including runs still in progress:

$ perch ci
ID                                    Commit   Pull request  Result               When
043812ac-ea68-4c3b-88f0-737328f62826  5d7b033  #320          clean                23h ago
edf9f510-875c-44c8-8ff1-773e286be26e  a246d74  #320          clean                24h ago
6323adfc-9440-4640-badf-58c8e61cd5ba  d738e69  #320          4 problems, failing  45h ago

With a run ID, it shows that run's issues in the same layout as perch scan:

$ perch ci 6323adfc-9440-4640-badf-58c8e61cd5ba
docs/coverage.md
  ID        Line  Severity  Type  Confidence  Problem                   Method
  8fd1e766     1  -         lint         72%  docs-sentences-are-short  docs/coverage.md

src/coverage.js
  ID        Line  Severity  Type    Confidence  Problem             Method
  8d9306ba   428  P1        defect         71%  wrong_return_value  askCoverage.<anonymous>.build
  7a5c2d1b   463  P1        defect         68%  wrong_return_value  askCoverage.<anonymous>.build#2

test/test-detection.test.js
  ID        Line  Severity  Type  Confidence  Problem                     Method
  69903bef     1  -         lint         61%  tests-assert-real-behavior  test/test-detection.test.…

✖ 4 problems in 3 files, failing
#320 at d738e69, finished 45h ago: https://dash.perchscan.com/#/scan/6323adfc-9440-4640-badf-58c8e61cd5ba

On a pull request, each issue also shows the state of Perch's review comment on it: open, fixed when a later scan stopped reporting it, or resolved once someone resolves the thread. Replies are listed underneath. With --json, each issue's method works as a perch check target.

perch ci uses your perch login and the repository named by the origin remote. A CI token in PERCH_API_KEY also works, but sees only its own repository's finished runs. With a run ID, it exits with the run's result: 3 if the run found failing issues, and 1 if the run didn't finish.

FlagDescription
--waitWait for the current commit's run, or the named run, to finish, then print its issues. Gives up if no run starts within 10 minutes.
--jsonPrint JSON instead of the table.

perch cloud#

perch cloud [set] [options]

Shows your account, your workspace, and this repository's pull request settings in Perch Cloud: whether the GitHub app is installed, whether pull requests are scanned, which types of problem are asked about, whether Perch reads the changed code or the whole repository, and whether issues fail the Perch Scan check. The repository is the one the origin remote names.

perch cloud set changes the settings you pass and leaves the rest. It needs a workspace admin signed in with perch login. A CI token can't read or change settings.

FlagDescription
--pull_requests yes|noWhether Perch Cloud scans this repository's pull requests.
--scan_types a,bTypes of problem to ask about: defect, security, lint, refactor, docs.
--scope changes|allScan the changed code or the whole repository.
--gate yes|noWhether issues fail the Perch Scan check on a pull request.
--jsonPrint JSON instead of a summary.

perch doctor#

perch doctor [options]

Checks that Perch can run here: Node, credentials, git, the repository and commit, the results directory, and whether perch.yaml parses. A failed check says how to fix it, and the command exits with code 1.

Below that, it reports on the last run: every method it couldn't read and the error, every question it asked and what each one raised, and the end of .perch/scan.log if the run didn't finish. The report contains names, paths, counts and error messages but no source code, so you can paste it into a bug report.

Environment#

Perch sends scan, coverage and check requests to Perch Cloud unless PERCH_BASE_URL names another endpoint. Without PERCH_BASE_URL, it signs in to Perch Cloud with the first of these it finds: a CI token in PERCH_API_KEY, the login saved by perch login, or a GitHub Actions job's OIDC token when the job has id-token: write.

VariableDescription
PERCH_API_KEYA Perch Cloud CI token, or your key for PERCH_BASE_URL.
PERCH_BASE_URLAnother endpoint to send questions to, as the exact URL to POST to. A URL ending in /decisions is OpenAI's Decisions API.
PERCH_MODEL_IDThe model to ask. Defaults to the model Perch Cloud serves, gpt-6-luna on the Decisions API, or jev-latest on any other endpoint.
OPENAI_API_KEYThe Decisions API key, when PERCH_API_KEY is not set.
TYPESAFE_API_KEYThe key for any other PERCH_BASE_URL, when PERCH_API_KEY is not set.
PERCH_MAX_QUESTIONSThe most questions to send in one request, for a PERCH_BASE_URL model that doesn't report its limit.
PERCH_MAX_OPTIONSThe most options in one choice question, for the same kind of model.
PERCH_CONTEXT_LENGTHThe tokens one request may hold, over the model's own limit. Past 64k on TypeSafe, it turns Jev's long context on.
PERCH_ORGANIZATIONThe Perch Cloud organization to use, when your login belongs to several.
PERCH_REPOSITORYThe Perch Cloud repository ID, in place of the one the origin remote names.

Perch uses PERCH_BASE_URL exactly as given, including its path, query string and any trailing slash. To use TypeSafe System One:

export PERCH_BASE_URL=https://api.typesafe.ai/v1/systemone
export PERCH_API_KEY='paste-your-TypeSafe-key-here'

To use a Liquid AI decision model, which uses the same request format:

export PERCH_BASE_URL=https://api.liquid.ai/decisions/v1/systemone
export PERCH_API_KEY='paste-your-Liquid-key-here'
export PERCH_MODEL_ID=d1:free

To use OpenAI's Decisions API:

export PERCH_BASE_URL=https://api.openai.com/v1/decisions
export OPENAI_API_KEY='paste-your-OpenAI-key-here'

Perch translates its questions and answers to and from the Decisions API format when the URL's path ends in /decisions.

Any other endpoint must accept the System One format, where typed questions about a piece of code are answered with probabilities. An OpenAI-compatible chat endpoint does not accept it.

Models accept different numbers of questions in one request. If a model reports max_questions in its answers, Perch keeps its first request to eight questions and sizes later requests to fit. For a model that reports nothing, set PERCH_MAX_QUESTIONS.

How much code goes in one request also depends on the model: about 24k tokens of a method and its neighbours for Jev, whose requests take 64k, and about 200k for OpenAI's Decisions API and for Perch Cloud. Any other model gets Jev's budget. PERCH_CONTEXT_LENGTH sets the size of one request yourself; the code gets 80% of it, and the code plus any one question 96%. A context length past 64k on TypeSafe sends the TypeSafe-Danger-Zone-Long-Context header, which raises Jev's limits to 262k. TypeSafe says that is slower and less accurate, so Perch never turns it on unless you set the length.

Configuration file#

~/.perch/config.toml sets defaults for this machine. It accepts four settings, each a quoted string:

organization = "your-organization-id"
repository = "your-repository-id"
base_url = "https://api.typesafe.ai/v1/systemone"
model = "jev-latest"

They set PERCH_ORGANIZATION, PERCH_REPOSITORY, PERCH_BASE_URL and PERCH_MODEL_ID. An environment variable overrides the file.

Exit codes#

CodeMeaning
0The command finished and found nothing that fails it.
1The command failed. A scan that couldn't read some methods or rules after retrying exits with 1, and so does perch ci for a run that didn't finish, and perch doctor when a check fails.
2The command line was wrong, or perch setup needs --force to replace a file you edited.
3scan, check, coverage, or a CI run shown by perch ci, found something that fails it.

A scan asks about defects and custom rules unless scan_types in perch.yaml lists other types, and any problem it lists makes it exit with 3. A rule with gate: false is still listed, but doesn't change the exit code.

Edit this page on GitHub