Documentation

The full reference for the mind CLI: install, commands, configuration, hooks, and suppressions. New here? Start with the quick start.

Install

Install the mind CLI on macOS or Linux:

curl -fsSL https://mindrealm.ai/install.sh | sh

On Windows, in PowerShell:

iwr -useb https://mindrealm.ai/install.ps1 | iex

Re-run the same command any time to update. The installer places a single mind binary in one location and touches nothing else: /usr/local/bin or ~/.local/bin on macOS and Linux, %LOCALAPPDATA%\Programs\mind on Windows.

Install manually

Prefer to install by hand? Download the archive for your platform from the releases page:

  • macOS / Linux: download mind-<os>-<arch>.tar.gz, extract it with tar -xzf, make it executable with chmod +x mind, and move mind onto a directory in your PATH (for example /usr/local/bin).
  • Windows: download mind-windows-<arch>.zip, extract mind.exe, and add its folder to your PATH.

Authenticate

However you installed it, sign in once before reviewing:

mind login

Behind a proxy or signing in from a remote session? Keep the terminal command running and open its printed URL in your configured browser:

mind login --no-browser

The browser must bypass the proxy for localhost, 127.0.0.1, and ::1 so authentication can return to the waiting CLI.

Review

From inside a repository connected to your GitHub App, review your changes (diff-only by default, or --full-scan for the whole repo):

mind review

Commands

CommandWhat it does
mind loginAuthenticate. Opens your browser.
mind login --no-browserPrint the sign-in URL without opening a browser. Use it for proxies and remote sessions.
mind setupDetect your agent(s) and set up the stop-hook auto-fix loop.
mind reviewReview your changed files. Diff-only by default.
mind configShow the resolved configuration and which layer supplied each value.
mind hookDispatch agent lifecycle hook events. The entry point your agent calls when it stops; you won’t run it by hand.
mind feedbackReview past runs and record feedback on findings, or report a bug or feature request.
mind logoutLog out and remove stored credentials.
mind updateUpdate the mind CLI to the latest release.
mind versionPrint the CLI version.
mind --helpList every command and flag.

Review categories

Mindrealm reviews Go, Python, TypeScript, and Rust across these categories:

CategoryLooks for
HygieneDead code, unused exports, magic values, leftover markers, naming.
ReliabilityUnhandled errors, swallowed exceptions, resource leaks, missing timeouts.
ArchitectureCoupling, cohesion, duplication, oversized types and interfaces.
PerformanceWork inside loops, unbounded growth, repeated expensive calls.
ConcurrencyUnawaited calls, detached tasks, blocking work in async paths.
SecurityHardcoded secrets, SQL/command/code injection, dangerous taint flow.
StructureLong functions, deep nesting, long parameter lists, large files.
TestingMissing or weak assertions, skipped tests, mock abuse, test pollution.
Language gatesYour toolchain linters and type checks (go vet, golangci-lint, ruff, tsc, eslint, cargo clippy).

Every review is deterministic: the same code returns the same findings every run. No model decides what gets flagged.

Review scope

mind review reviews your changed files by default (diff-only), matching what the stop hook reviews. To scan the whole repository:

mind review --full-scan

--diff-only and --full-scan are mutually exclusive, and --commit implies diff-only. On a trial, reviews are diff-only by default; whole-repo --full-scan is a paid-plan feature, though a trial organization can ask Mindrealm to enable it. Both are config-backed: set diff_only or full_scan in mind.yaml.

mind review must run from inside a git repository whose origin is a GitHub repo connected to the Mindrealm GitHub App. Outside a git repo, or with no GitHub origin, it fails fast with a clear message. . After the GitHub App is installed for your organization, public repos the server can clone work as-is. A private repo not connected to that installation returns a clear not-connected message rather than a raw clone error.

FlagEffect
--full-scanScan the entire repository, not just changed files (paid plan).
--diff-onlyOnly report findings in changed files (the default).
--commit <sha>Review files changed in a specific commit. Implies diff-only.
--stagedOnly staged changes.
--unstagedOnly unstaged changes.
mind review [paths...]Scope the review to specific files or directories.
--analyzers <id,...>Run only these rules, comma-separated.
--profile <name>Run only the rules in a named profile. Overrides the mind.yaml profile; --analyzers adds to it.
--min-severity / --max-severityBound the findings shown. One of info, minor, major, blocker.
--show-suppressedInclude suppressed findings in the output.
--format text|jsonOutput format.
--enable-go-testRun the go-test gate (off by default for speed).
--enable-pytestRun the pytest gate (off by default for speed).
--enable-js-testRun the JS test gate, jest or vitest (off by default for speed).
--enable-security-gatesRun the security gates, gitleaks secrets and osv-scanner dependency CVEs (off by default).
--no-gatesDisable all gates (linters, type checks).

On a very large repository, a --full-scan can exceed the review time budget (10 minutes by default). When it does, the review returns a partial result: the findings produced before the deadline, shown with a “Partial analysis” banner. It still blocks on any blocker or major finding, does not fail with zero findings, and the findings it reports are real. For a faster review on a huge repo, narrow the scope with --diff-only, --analyzers, or --profile.

Suppressions

Disagree with a finding? Silence one check with a mind:disable comment on the line above the code. It stays recorded and reviewable, never hidden. Every suppression is meant to be temporary.

// mind:disable                 Go, TypeScript, Rust
# mind:disable                  Python
// mind:disable unused-export   silence one rule by id
// mind:disable unused-export - reason goes here

Suppress a range with a begin/end pair:

// mind:disable-begin generated block
//   ... lines here are not reviewed ...
// mind:disable-end

A bare mind:disable silences every check on that line; naming an id silences just that one. Use Python's # comment prefix, and // for Go, TypeScript, and Rust.

See suppressed findings with mind review --show-suppressed, and require a reason on every directive with require_reason in mind.yaml.

mind:disable silences check findings in your code. Gate output (linters, type checks, tests) is turned off separately, with disabled_analyzers or --no-gates. See Gates.

Feedback

mind feedback opens an interactive menu to tell us when a finding was right or wrong, and to report bugs or request features. Run it with no arguments from anywhere you are signed in:

mind feedback

Give feedback on findings

Pick one of your recent reviews (run mind review first if you have none yet), drill into a finding, and record your call. Each verdict takes an optional reason and is keyed to the finding's stable fingerprint, so it sticks even after you re-run the review.

Your callMeans
agreeYou agree with the finding.
disagreeYou disagree with the finding.
request-changesYou want changes before this finding is resolved.
manual-fix-appliedYou fixed it by hand rather than as suggested.
skipMove on without recording a verdict.

Report a bug or request a feature

The same menu lets you file a bug report or a feature request: give a one-line summary, then a few lines of detail. Mindrealm tags it with your CLI version and current repository so we have the context to act on it.

Custom rules

MindQL lets you encode your team's standards as rules that run across Go, Python, TypeScript, and Rust: no build, no database, and deterministic findings on every run. Rules live in .mind/rules/*.mql and run in every mind review, right alongside the built-in checks.

One rule, four languages

This rule keeps your API layer from importing a database package directly. The same .mql fires on Go, Python, TypeScript, and Rust, with no per-language rewrite:

rule api_no_db {
  match import i
  where i.file.path ~ "internal/api/" and i.imports_package("db*")
  block "api must not import a db package directly"
}

MindQL reads every language through the same import graph, so one rule covers them all. No model decides what gets flagged; the same code produces the same findings on every run.

What a rule looks like

A rule names what to match, filters it with a condition, then emits a finding at a fixed severity:

PartWhat it does
matchPick what to look at: an import, function, call, type, symbol, file, or the whole review.
whereFilter the match with a condition over import paths, call reachability, structure, and names.
defName a reusable condition once and share it across rules.
actionWhen the match passes the filter, emit a finding at this severity (the verbs are below), followed by the message your team sees.

match: what you can read

match picks what to look at. Each kind exposes attributes you filter on in where. Glob arguments (in quotes) match names or paths; every entity also carries file and line.

MatchWhat you can read
importmodule, module_path, last_segment, segments, imports_package("glob")
funcname, exported, is_method, receiver, body_lines, callers, caller_count, callees, calls("glob"), reachable_from("glob"), is_entrypoint("kind")
callname, in_loop, inside("kind") — a call site
typename, exported, method_count, field_count, exported_field_count, method_lines, method_names, is_god_object
symbolname, symbol_kind, exported, receiver
filepath, language, is_test, is_generated, is_third_party, is_config, class, imports, symbols
nodetype, text, name, in_loop, in_test, inside("kind"), has("rule") — raw AST, for shapes the typed kinds do not cover
reviewdiff.files (path, status, changed_lines, is_test), changed("glob") — the whole change

where: filtering the match

where keeps only the matches that satisfy a condition, built from the matched entity's attributes with these operators and helpers:

Operator / formWhat it does
~Regex match against a string: path ~ "internal/api/".
and or notCombine conditions.
== != > <Compare values: body_lines > 80.
.Read a nested attribute: i.file.path.
any(list, cond)True if any item matches: any(diff.files, .path ~ "src/").

def: reusable conditions

def names a condition once so you can share it across rules. It takes the matched entity as a parameter and returns a boolean:

def is_handler(f) = f.is_entrypoint("http")

rule big_handler {
  match func f
  where is_handler(f) and f.body_lines > 80
  emit minor "split this handler; it is doing too much"
}

action: emit a finding

The action fires when a match passes the filter: a rule emits at one fixed severity, so a finding's weight is part of the rule, not a guess:

KeywordSeverityMeaning
emit blockerBlocker tier. Stops the change at a gate.
emit majorMajor tier. Must be fixed before merge.
emit minorMinor tier. Worth addressing.
emit infoInfo tier. A small remark.

More examples

Flag oversized handlers

Flag an oversized HTTP handler: a function reached from a *Handler whose body runs over 80 lines.

rule long_http_handler {
  match func f
  where f.reachable_from("*Handler") and f.body_lines > 80
  emit minor "split this handler; it is doing too much"
}

Catch queries in loops

Catch a database query that runs inside a loop, where it should be lifted out.

rule query_in_loop {
  match call c
  where c.name ~ "Query" and c.in_loop
  emit minor "move this query out of the loop"
}

Add a rule

Drop a .mql file in .mind/rules/ and run mind review. Rules are checked in with your code, so the whole team gets them:

// .mind/rules/detection_suite_reminder.mql
// A rule we run on our own repo: when we change a check,
// it reminds us to add a test for it in the same change.
rule detection_suite_reminder {
  match review
  where any(diff.files,
      (.path ~ "internal/software_code_" and not .is_test)
      or .path == "internal/analysis/rule_ids.go")
    and not any(diff.files, .path ~ "internal/detectionsuite")
  emit minor "detection changed; add a detectionsuite regression fixture"
}

Commit .mind/ to version control so the whole team gets your rules.

What works today

Available nowComing next
Match imports, functions, calls, types, symbols, files, and the whole review.Metavariable patterns for matching code shapes.
Filter with conditions over import paths, call reachability, structure, and file class.Autofix that rewrites the flagged code for you.
Classify each file (code, test, config, docs, generated) and flag god-object types.A package entity for module coupling, instability, and dependency cycles.
Reusable conditions, fixed severities, deterministic findings, four languages.Rules that carry their own tests.

Want your team's standards encoded as rules without doing it yourself? I'll build them with you.

Gates

Gates run your own toolchain on the machine doing the review: the linters, type checks, builds, and (optionally) tests you already use. They run alongside the deterministic checks and merge into one report, so a compile error, a lint violation, and a design finding all land together. A failing gate can block the review.

Because they run where your environment lives, gates catch what your machine already knows: real build and test failures, not guesses. The trade-off is speed. Linters and type checks are quick and run by default; the test gates are the slow ones and stay off until you opt in.

Why let Mindrealm run them instead of asking the agent to? Agents are unreliable at running a whole toolchain. Asked to run several linters and the test suite, an agent often runs one, a couple, or none, then reports success anyway. The stop hook runs every gate every time and blocks on any failure, so the checks you depend on actually happen on every change.

GateToolsDefault
Build and type checksgo build, go vet, tsc, cargo checkon
Lintersgolangci-lint, ruff, vulture, eslint, cargo clippyon
Module hygienego mod tidy, go mod verifyon
Test runners (slow)go test, cargo test, pytest, jest/vitestoff

Test gates

Turn the test gates on per project (or globally) when the extra seconds are worth it:

# .mind/mind.yaml
gates:
  go_test: true
  cargo_test: true
  pytest: true
  js_test: true

The JS test gate auto-detects jest or vitest from your package.json. Or enable a test gate for a single run with --enable-go-test, --enable-pytest, or --enable-js-test. To skip every gate for a faster, checks-only pass, use mind review --no-gates or turn them off in config with disabled_analyzers (see Configuration).

The JS test gate detects jest and vitest today; node:test, mocha, and other runners are not supported yet. If a different test runner, another toolchain gate, or a project-specific custom gate would help your team, tell us what you run.

Security gates

Two extra gates run dedicated security scanners over your repo: one for leaked secrets, one for vulnerable dependencies. They are off by default. Unlike the build, lint, and type gates, which key off the change in front of them, these scan the whole tree and are built for a deep, point-in-time security review, so they ship dark until you ask for them.

Security gateToolWhat it findsDefault
SecretsgitleaksHardcoded API keys, tokens, and credentials across any language (regex + entropy).off
Dependency CVEsosv-scannerKnown vulnerabilities in your dependencies. Reads Go, npm, PyPI, and Cargo lockfiles.off

Turn both on for a project (or globally) in config:

# .mind/mind.yaml
gates:
  security: true

Or enable them for a single run with --enable-security-gates. The scanners are optional local tools: if gitleaks or osv-scanner is not installed on the machine running the review, that gate simply skips. It never fails the run. These gates are primarily meant for the in-depth security pass of a consulting audit, not the per-change review loop.

Hook setup

mind setup wires Mindrealm into your agent so it reviews every change automatically. It detects which agents are present (Claude Code, Codex, Kimi Code, and Antigravity), asks which to set up, and asks where: globally in your home config (the default), or just the current project with --local. Kimi Code is the exception: it reads hooks only from ~/.kimi-code/config.toml, so it is always set up globally. Each agent is covered below.

Why a hook? Getting an agent to reliably review its own work or follow a rule does not work. It forgets, skips, or calls itself done. A stop hook runs every time the agent finishes, no matter what. When Mindrealm flags findings it blocks the stop and feeds them back as the agent's next instruction, so the agent fixes them before the work reaches you. That auto-fix loop works on Claude Code, Codex, Kimi Code, and Antigravity.

Skip the prompts with flags, for example mind setup --platform claude-code,codex,kimi,antigravity --global --yes.

Claude Code

mind setup --platform claude-code writes a Stop hook and the Bash(mind:*) permission to ~/.claude/settings.json (or .claude/settings.json with --local). The hook runs as soon as it is written, with no approval step:

{
  "hooks": {
    "Stop": [
      { "hooks": [{ "type": "command", "command": "mind hook" }] }
    ]
  },
  "permissions": { "allow": ["Bash(mind:*)"] }
}

Codex

mind setup --platform codex writes a Stop hook to ~/.codex/hooks.json (or .codex/hooks.json with --local):

{
  "hooks": {
    "Stop": [
      { "hooks": [{ "type": "command", "command": "mind hook" }] }
    ]
  }
}

One extra step: Codex requires you to trust hooks before they run. After setup, start Codex and run /hooks to review and trust the Mindrealm Stop hook. It stays inactive until trusted, and Codex re-prompts whenever the command changes.

Kimi Code

mind setup --platform kimi splices a managed hooks block into ~/.kimi-code/config.toml ($KIMI_CODE_HOME/config.toml when that is set). Kimi Code reads hooks only from that file, so setup is always global and --local does not apply. The block runs mind hook when the agent stops, same as the other agents. Re-run setup any time to refresh the block; it replaces only what it manages.

Antigravity

mind setup --platform antigravity writes a mindrealm-review Stop hook to ~/.gemini/config/hooks.json (or .agents/hooks.json with --local). The Stop hook runs mind hook when the agent finishes, same as the other agents.

Removing the hook

Run mind setup --uninstall to remove it (add --platform claude-code to target one agent, or --local for the current project only). It removes only what setup added, leaving your other hooks and permissions intact, and is a no-op when nothing is installed. On Codex you can instead disable the hook from inside the agent with /hooks, without editing any files.

To wire it by hand, drop the matching block into the file above. The reviewer itself is agent-agnostic: mind review and the GitHub App review code from any agent or author.

Continuous integration

mind login is interactive, so for CI generate a CI token from your dashboard and give it to the CLI headless. The token is organization-scoped, review-only, and revocable, and it stays valid for long runs, so a --full-scan never expires mid-review.

Provide it as the MIND_CI_TOKEN environment variable:

MIND_CI_TOKEN=mind_ci_xxxxx mind review --full-scan

Or store it once with mind login --token for repeated local headless use:

mind login --token mind_ci_xxxxx
mind review

The repository still needs the Mindrealm GitHub App installed: the token authenticates the caller, the app authorizes the repo.

GitHub Actions

Add the token as a repository secret, then run mind review as a step. fetch-depth: 0 gives mind the history it needs to compute the diff:

- uses: actions/checkout@v4
  with:
    fetch-depth: 0            # so mind can diff against the base commit
- run: curl -fsSL https://mindrealm.ai/install.sh | sh
- run: mind review
  env:
    MIND_CI_TOKEN: ${{ secrets.MIND_CI_TOKEN }}

Exit codes

mind review sets its exit code so a CI step fails the build on a blocking finding:

CodeMeaning
0Review passed.
1A blocker or major finding fails the build. Also the fallback for an untyped error.
2Config or credential problem, for example a revoked token.
3Network or service problem.
4Invalid arguments.

Machine-readable output

For machine-readable output use mind review --format json (the default is text); each finding carries severity, filePath, startLine, description, remediation, and rule_id.

If your pipeline already runs its own linters, type checks, and tests, mind review --no-gates skips Mindrealm's gate checks while the rest of the review still runs and still blocks on a must-fix.

Configuration

mind reads YAML config from two locations: a project file at .mind/mind.yaml and a global file at ~/.config/mind/mind.yaml. The project file overrides the global one.

Precedence, highest first: a command-line flag, then environment variables (MIND_*), then .env in the current directory, then the project .mind/mind.yaml, then the global ~/.config/mind/mind.yaml, then built-in defaults.

Only the highest layer that sets a key counts, so an edit to a lower one has no effect. mind config prints every resolved key with the layer that supplied it, which is the fastest way to find out why an edit did nothing.

$ mind config
user config file:    /home/you/.config/mind/mind.yaml
project config file: .mind/mind.yaml

KEY               VALUE                 SOURCE
grpc_url          localhost:50051       environment MIND_GRPC_URL
task_grpc_url     localhost:50051       .env MIND_TASK_GRPC_URL
auth_token        (set, not shown)      credentials file
timeout           60s                   default

Credentials are never printed. An address a client could never dial — a port outside 1-65535, or a value with no port — fails immediately and names the layer that supplied it, rather than being silently ignored.

Top-level keys

KeyDefaultMeaning
timeout60sRequest timeout.
diff_onlyfalseReview only changed files. With neither key set, reviews are diff-only.
full_scanfalseReview the whole repository instead (paid plan).
profilenoneRun only the rules in a named profile. A --profile flag overrides it.
debugfalseDebug logging. MIND_DEBUG and --debug also turn it on.
min_severitynoneHide findings below this severity (info, minor, major, blocker).
max_severitynoneHide findings above this severity.
disabled_analyzersnoneA list of rules to turn off, by full ID, short name, or concern.
require_reasonfalseRequire a reason on every mind:disable directive.
show_suppressedfalseInclude suppressed findings in output.
gates.go_testfalseRun the go-test gate.
gates.cargo_testfalseRun the cargo-test gate.
gates.pytestfalseRun the pytest gate.
gates.js_testfalseRun the JS test gate (jest or vitest, auto-detected).
gates.securityfalseRun the security gates (gitleaks secrets, osv-scanner dependency CVEs).
outputnoneOutput template overrides. See Output templates below.
thresholdsnonePer-rule thresholds. See Thresholds below.

Linters and type checks for all four languages run automatically. Each language also has an opt-in test gate: go-test, cargo-test, pytest, and a JS test gate that runs jest or vitest. See Gates for the full list.

disabled_analyzers accepts a full rule ID, a short name, or a concern that matches a whole group. The gate concern turns off every gate at once:

# .mind/mind.yaml
disabled_analyzers:
  - gate                          # all gates
  - software:code:gate:go-test    # one rule by full id
  - golangci-lint                 # short name also matches

Environment variables

These override the matching config keys.

VariableDefaultOverrides
MIND_TIMEOUT60stimeout
MIND_DEBUGfalsedebug
MIND_FINDING_TEMPLATEdefaultoutput.finding_template
MIND_HEADER_TEMPLATEdefaultoutput.header_template

Thresholds

Thresholds set when the size, coupling, and duplication checks fire. They all live under thresholds in mind.yaml. A few common ones:

KeyDefaultMeaning
long_function_threshold75Lines before a function is flagged.
large_file_threshold1500Lines before a file is flagged.
interface_size_threshold10Methods before an interface is flagged.
method_count_major20Methods before a type must be split.
type_cohesion_major600Cohesion score before a type is flagged.
duplicate_code_block_min_lcs_similarity75Minimum percent similarity to flag duplicate blocks.

More keys exist under thresholds to adjust coupling, duplication, and complexity limits.

Output templates

Customize what your agent sees in the stop-hook output. finding_template and header_template (under output) each accept default or a path to a Go text/template .tmpl file. analyzer_templates maps a rule short name to its own template.

Template keys, per finding: Severity, ShortName, RuleID, FilePath, StartLine, EndLine, Description, Remediation, Value, Threshold. For the header: TotalCount, BlockerCount, MajorCount, MinorCount, InfoCount, BatchSize, HasMore, Findings.

The default finding template:

[{{.Severity}}] {{.ShortName}} — {{.FilePath}}:{{.StartLine}}: {{.Description}}{{if .Remediation}}
  fix: {{.Remediation}}{{end}}