コマンド
bca is the command-line tool. Each subcommand performs one analysis and takes its own flags. This section covers what every subcommand shares: installation, how flags and input paths are placed, which files the walk visits, and the exit-code contract. The subcommands themselves each have a page: Metrics, Change-history (VCS) metrics, Report, Check, Suppression markers, Nodes, the REST API, and Operating bca-web.
インストール
The bca command-line tool ships as a pip-installable wheel. The distribution name is big-code-analysis-cli and the installed command is bca. The two differ on purpose: the bca name on PyPI belongs to an unrelated project, and big-code-analysis is this project’s importable library bindings.
pip install big-code-analysis-cli # PATH に `bca` コマンドをインストールします
bca --version
This puts the compiled bca binary on your PATH the way pip install ruff gives you the ruff command, with no Rust toolchain required. The wheel carries the full all-languages grammar set, so every supported language works out of the box. A single py3-none-<platform> wheel covers every CPython 3.x (and PyPy) on that platform. Prebuilt wheels ship for Linux (manylinux_2_28 x86_64 / aarch64), macOS (x86_64 / arm64), and Windows (x86_64). On any other platform pip falls back to a source build, which needs a Rust toolchain.
This is the binary CLI, distinct from the importable Python bindings (pip install big-code-analysis). The repository README describes the other install paths: Homebrew, .deb / .rpm / .apk packages, prebuilt release archives, and cargo install big-code-analysis-cli.
wheel のビルドと公開のマトリクスは .github/workflows/python-cli-wheels.yml で定義されています。
メトリクス
Metrics are quantitative measures of source code. They help to:
- compare programming languages;
- describe the quality of a codebase;
- show developers where their code is hardest to handle;
- surface potential problems early in development.
bca computes its metrics from the source text alone, without running the program; such metrics are called static metrics. See Metrics for the command and Supported Metrics for each metric’s definition.
ノード
To represent the structure of program code, bca builds an Abstract Syntax Tree (AST). A node is an element of this tree and denotes one syntactic construct of the language. The Nodes commands use them to:
- print the syntactic structure of a source file;
- find whether a construct is present in the analyzed code;
- count the constructs of a given kind;
- detect syntax errors in the source.
REST API
bca-web runs a server offering a REST API. Clients send source code over HTTP and receive the corresponding metrics as JSON.
フラグの位置と入力パス
Most subcommands read the input they analyze as a trailing positional path, so the common case reads like every other code tool (tokei, cloc, scc, rg). The exceptions: report and vcs select input with --paths, diff compares two result sets, and init targets a directory via --dir.
bca metrics src/ # src/ ツリーを解析する
bca check src/ tests/ # 2 つのサブツリーをゲートする
bca find -t function_item . # 現在のツリー内のすべての関数を検索する
フラグは それを消費するサブコマンドにスコープされ、サブコマンドのトークンの後に 書く必要があります:
bca metrics --exclude '*.generated.rs' src/ # 正しい
bca --exclude '*.generated.rs' metrics src/ # エラー(終了コード 1)
Only -w / --warnings and --report-skipped are universal and accepted in any position. Every other shared flag lives in a help-grouped section on the subcommands that read it:
- Input selection:
-p/--paths,-I/--include,-X/--exclude,-l/--language,--paths-from,--exclude-from,--no-ignore,--no-skip-generated,--no-config. - Walker tuning:
-j/--jobs,--exclude-tests,--cyclomatic-count-try,--mi-charges-docs. - Preprocessor:
--preproc-data. - Output:
--color.
A flag passed to a subcommand that never consumes it is a hard usage error (exit 1) rather than a silent no-op, so bca vcs commit --exclude-tests and bca list-metrics --paths both error, and bca list-metrics --help does not advertise walker flags.
-p / --paths フラグは引き続き機能し、位置引数のパスと 和集合 になります。つまり bca metrics a.rs --paths b.rs は両方を走査します。find と count サブコマンドは、繰り返し指定できる -t / --type フラグでノード種別を受け取ります(そのため位置引数のスロットはパス用に空いています): bca find -t function_item -t struct_item src/。
生成コードのスキップ
Generated files inflate metrics for code no human will refactor. By default, bca scans the first ~50 lines / 5 KiB of each file for a generated-code marker and skips matches before parsing, so the skipped file pays no tree-sitter parse cost.
認識されるマーカー(大文字小文字を区別しません):
@generated: a marker emitted by code generators.DO NOT EDIT: a marker used by Go’s generated-code convention and other generators.GENERATED CODE: Lizard’s marker, recognized for compatibility.
A marker phrase that appears only deep in the file body (past the scan window) does not trigger the skip; the detector deliberately looks only at the file header.
このスキップは bca metrics、bca report、およびしきい値エンジンに一律に適用されます。
フラグ
--no-skip-generated: disable the auto-skip, so every file is parsed.--report-skipped: logskipped (generated): <path>to stderr for each file the detector excludes, so you can audit the exclusions. If a file is wrongly tagged, pass--no-skip-generated; an include filter does not override the detector.
さらに bca check は、ゲート実行で検出器がファイルを除外した場合に 1 行のサマリーを stderr に出力します(bca: 1 file not checked (1 generated) — pass --report-skipped to list them)。また、--strict プロファイルは検出器そのものを無効にします。マーカーはテスト対象のブランチが管理するコンテンツなので、プルリクエストのゲートでは、それによって検査対象のファイル集合が狭められるべきではありません。
.gitignore の尊重
--paths にディレクトリが渡されると、bca はデフォルトで .gitignore を考慮して走査します。次のいずれかに一致するファイルは、パース前にスキップされます:
- 走査対象ツリー内の
.gitignoreファイル。 .ignorefiles (the ripgrep /fdconvention)..git/info/exclude。- グローバル gitignore(
~/.config/git/ignore、またはcore.excludesFileが指す先)。 - 起点の祖先ディレクトリにある
.gitignoreファイル(そのため、プロジェクトルートからbca metrics src/を実行すると、プロジェクト最上位の.gitignoreが反映されます)。
ウォーカーは、チェックインされた git リポジトリの外でも .gitignore を尊重します。そのため、.gitignore ファイルを含む展開済みのソース tarball も、git clone した直後と同じ扱いになります。
Hidden files (those whose basename starts with .) are filtered during the walk.
明示的なパスはフィルターを迂回する
Files passed by name (via --paths, --paths-from, or a trailing positional path) are always analyzed, even when the project’s ignore rules cover them. This makes it safe to run bca metrics --paths-from - from a git diff --name-only pipeline without losing files that happen to match a wildcard ignore rule.
The override is deliberate, and it is the same rule rg and fd apply: a path you named is a direct request. It spans every deny-set the walk consults: .gitignore and friends, -X / --exclude, --exclude-from, a .bcaignore, and a manifest exclude list alike. rg --glob '!x.txt' pattern x.txt searches x.txt for exactly this reason.
これには 2 つの境界があります。
-I/--includeは引き続き適用されます。 許可リストは、名指しされたファイルの「どれ」を解析するかを絞り込むため、bca metrics -I '*.rs' notes.mdは何も解析しません。上書きされるのは拒否セットだけです。[check] excludestill applies. The gate-exemption set (--check-exclude/--check-exclude-from, orexcludeunder[check]inbca.toml) is not a walk filter: it drops violations, not files. It therefore survives an explicit path and reportsbca: skipped N violations via [check.exclude]when it fires. A glob written inbca.tomlresolves against the manifest’s directory whichever directory you run from (#1164); one passed as--check-excluderesolves against the working directory. See What a relative glob is relative to.
That second point is the one to reach for. A walker exclude shapes what gets analyzed; a check exclude shapes what gets gated. Anything you want kept out of the threshold gate permanently (dev tooling, generated code you still want measured, a subtree under active rewrite) belongs in [check] exclude, because any caller that names paths one at a time bypasses the walker excludes by design. Per-file callers are not hypothetical: that is the shape the agent feedback hooks use on every edit.
明示的に名指しされたパスが実際にウォーカーの除外を上書きした場合、bca は stderr でそのことを伝え、該当するグロブを名指しします。
warning: utils/gate.py matches an exclude pattern (./utils/**) but was named explicitly; analyzing anyway
パス探索フラグ
--no-ignore: disable.gitignore/.ignore/ global-gitignore awareness when expanding directory seeds.bca checkcounts the analyzable files ignore rules dropped from a gate run in its not-checked summary, lists every dropped entry under--report-skipped(note: skipped (ignored): <path>,note: skipped (ignored directory): <path>), and disables the awareness under its--strictprofile, since an ignore file committed in the branch under test otherwise shrinks the checked set.--paths-from <FILE>: read newline-separated input paths from<FILE>, or from stdin when<FILE>is-. Combined as a union with any--pathsvalues.-Iglobs still apply;-Xglobs do not reach an entry that names a file directly, per Explicit paths bypass the filter. Blank lines are skipped;#is treated as a path character (not a comment). To pass a file literally named-, write./-.--exclude-from <FILE>: read newline-separated--excludeglob patterns from<FILE>, or from stdin when<FILE>is-. Patterns are unioned with any inline--exclude/-Xvalues into a single deny-set; order does not matter..gitignore-style: blank lines and lines whose first non-whitespace character is#are skipped, and a leading UTF-8 BOM is stripped. Convention is a.bcaignoreat the repo root, mirroring.gitignore/.dockerignore. To pass a file literally named-, write./-.
終了コード
bca はすべてのサブコマンドで単一の終了コード規約に従うため、CI スクリプトは出力を検査せずにプロセスのステータスで分岐できます:
| コード | 意味 |
|---|---|
0 | 成功。 |
1 | Tool error: a bad flag / threshold / glob spec, unreadable input, or a parse failure. This includes usage errors (unknown flag, bad subcommand, a malformed --threshold value rejected by clap). Never a metric signal. |
2 | メトリクスゲート: check のしきい値を超過した、vcs commit --fail-above に違反した、または --exit-code 指定時の diff / diff-baseline がフィルター後の空でない差分を検出した場合。 |
3–5 | check --exit-codes=tiered のみ: 段階化された違反の重大度(回帰のみ / 混在 / ハード違反。tiered モードではコード 2 は新規のみを意味します)。 |
Codes 2–5 are gate signals, emitted only by check, vcs commit --fail-above, and diff / diff-baseline under the opt-in --exit-code flag; they report a metric result, not a failure of the tool. Every other subcommand (metrics, ops, report, diff, diff-baseline, exemptions, init, and the rest) exits 0 on success and 1 on error. Code 1 is reserved for tool errors, usage errors included, so a mistyped flag never lands in the gate band and CI can always tell “the gate found a regression” (2–5) from “the tool itself failed” (1).
読み取れない入力
Every source-walking subcommand (metrics, ops, report, functions, find, count, dump, exemptions, preproc, strip-comments, check) exits 1 if any selected input file cannot be read: permission denied, or a path that vanished between the walk and the read. This includes init, which uses check to scaffold its baseline, and diff --since. Each failure names the path on stderr as error processing <path>: …, followed by a summary.
The rule is “any read failure”, not “no output at all”, because a missing file is invisible in the result. A partial metrics --output document, a report, or a count looks complete; a diff --since side that lost a file reports it as added or removed rather than as the I/O error it was. The exit code is the only place the failure can be observed, so it has to carry it.
Output streamed during the walk is still emitted, because the check runs after it. A mixed run therefore still shows the files that were read: the stdout trees of metrics / ops / dump / find / functions, and the per-file documents of --output-dir.
Output assembled after the walk is suppressed entirely, because a partial one is indistinguishable from a complete one. That covers the metrics --output / ops --output aggregate document, the report document, count’s tally, preproc’s JSON, and the exemptions report; none of them is printed or written.
開けないファイルがツリーに正当に含まれている場合は、--exclude で除外してください(あるいは --include でより狭い集合を指定します)。これらのフィルタで除去されたファイルは開かれないため、読み取り失敗にはなりません。
列挙できないディレクトリ
A directory the walk cannot list is the same failure one level up, and carries the same exit 1. Its whole subtree drops out of the analysed set before any file is selected, so every count downstream (the metrics document, the count tally, a diff --since side, vcs rank’s ranking) is short by an amount nothing in the output reveals. bca check is the worst case: a gate that reports clean on a tree it could not read is indistinguishable from a gate that passed.
Each unlistable entry warns on stderr as warning: skipping walk entry in …. The walk continues, so one bad directory does not take down the rest of the tree, and the run ends with a summary line and exit 1.
To exempt a directory you knowingly cannot list, name it in an ignore file (.gitignore, .ignore) or narrow --paths so the walk never reaches it. --exclude does not work here, though it is the right answer for an unreadable file: --exclude filters the paths the walk yielded, and a directory that could not be listed yielded none, because the failure happened before the filter could apply.
隣接する 2 つのケースは、設計上、致命的にはなりません。
- 不正な形式の ignore ファイル、またはその中のコンパイルできないパターン。 ウォーカーはこれらを同じチャネルで報告し、警告の形も同一ですが、これらが記述するのは走査が失ったファイルではなく、走査がどう「構成」されたかです。カウントされるのは基盤に I/O エラーを伴うエラーだけなので、
.gitignoreに紛れ込んだタイポがビルドを失敗させることはありません。 - A broken symlink discovered by walking. It is dropped for not being a regular file and never surfaces as an error at all. The walk does not follow links, so it deliberately does not resolve symlinks and has nothing to report. Treating one as fatal would make a stale symlink in a vendored tree a hard CI failure.
An explicitly named path is the exception to that last point, and a pre-existing one: --paths resolves a symlink seed once, and a seed that does not exist (a dangling link or a typo) is its own error, also exit 1.
書き込めない出力
The mirror image is the same rule, and it holds for every emission path: a run whose output could not be written exits 1. That covers a per-file document under an unwritable --output-dir, and a full disk on stdout: dump’s banners and trees, find‘s matches, strip-comments’ rewritten source, count’s tally, preproc’s JSON, and the single-document reports from vcs, vcs commit, and vcs trend alike, in every format. A per-file failure is named on stderr and counted in a summary line; output assembled after the walk reports the operating system’s error directly.
唯一の免除は、閉じられた下流のパイプです。bca dump | head は失敗ではなく日常的な操作であるため、BrokenPipe は握りつぶされ、実行はそれでも 0 で終了します。