Configuration
Edit project policy after Quick start. Suites and CI live in Usage.
Try this
# .shipgate/shipgate.yaml
suite: standard
env: managed
target: .
error-format: compact
configs:
mode: auto
shipgate install --suite standard
shipgate check --suite extended
Success is exit 0 with little stderr. Failures write findings to stderr in
error-format and always store canonical JSON under .shipgate/reports/.
Policy files
Policy lives in .shipgate/shipgate.yaml or [tool.shipgate] in pyproject.toml
(see .shipgate/pyproject.toml.example after init). shipgate init also scaffolds
.shipgate/catalog/, .shipgate/gates/, .shipgate/configs/, and cache metadata.
When layout detection finds an importable package (src/<pkg>/ or flat pkg/ at
the repo root), init may add an importlinter.ini starter and a [tool.deptry]
section if missing. Trees with no importable package skip import-linter.check
with a stderr line such as no importable package in project layout. Managed env
prepends src/ onto PYTHONPATH only for that src-layout package; flat packages
at the repo root stay on the default path. known_first_party is filled only for
a real package — otherwise the commented placeholder stays.
If an older init left a broken importlinter.ini (root_package set to the
directory name), delete it and re-run shipgate configs sync after you have a
real package. pip-audit needs no project config file.
Path delivery respects .gitignore unless a scope sets respect_gitignore: false.
Python support: 3.11–3.14. Prefer 3.13 when running suites that include
Semgrep or deadcode. On 3.14 those tools skip with requires_python: >=3.11,<3.14
instead of crashing.
Key fields
| Field | Role |
|---|---|
suite |
Default checklist (standard, full, security, …) |
env |
managed installs tools under .shipgate/tools/ |
target |
Default path root for check / format |
error-format |
Stderr shape on failure (compact, github, …) |
configs.mode |
How bundled vs project configs are discovered (see below) |
checks |
Per-tool scopes, thresholds, and metric gates |
configs.mode
Each catalog tool declares configuration.discover paths (for example ruff:
.shipgate/configs/ruff.toml, .ruff.toml, pyproject.toml). ShipGate passes
the first resolved path to the tool's --config flag (or equivalent).
| Mode | Behavior |
|---|---|
auto (default) |
Prefer repo-native configs (anything outside .shipgate/configs/). If the project already has [tool.ruff] in pyproject.toml, a root .ruff.toml, or similar, that wins over scaffolded .shipgate/configs/* from shipgate init. Fall back to scaffold, then bundled catalog defaults when nothing repo-native exists. |
repo |
Use catalog discover order as written — .shipgate/configs/ first when present. |
bundled |
Always use the bundled catalog config; ignore project files. |
pyproject.toml counts as a discover match only when the tool's
pyproject_section exists (for ruff, [tool.ruff]). This keeps auto aligned
with tools the project already configured.
Override the project suite for one run with --suite. List live names:
shipgate list suites.
Radon metric gates
Letter-rank threshold still gates each block (cyclomatic complexity) or file
(maintainability index). Optional numeric gates cover distribution summaries
computed from Radon JSON:
| Metric | Meaning | Prefer for gating? |
|---|---|---|
average |
Arithmetic mean | Useful, but skewed by outliers |
median |
50th percentile | Preferred central tendency (robust) |
minimum / maximum |
Worst single value | Strict; one outlier fails the gate |
p5 / p10 |
Left-tail percentiles | Preferred low-end floors for MI |
p95 |
95th percentile (inclusive linear interp.) | Preferred high-end tail for CC |
Direction: Maintainability index is worse when lower → floors for average,
median, minimum, p5, p10, and p95. Cyclomatic complexity is worse when
higher → ceilings for average, median, maximum, p5, p10, and p95.
Prefer median over average when you care about typical code. For MI, prefer
p5 / p10 / minimum floors to control the bad left tail; a high MI
p95 floor (for example 100) mostly measures how many near-perfect files you
have, not how bad the worst files are. For CC, prefer p95 over raw
maximum when you want a hard high-end bound without letting a single block
fail the whole suite.
When a metric gate fails, ShipGate emits canonical findings with the distribution
summary (n, median, mean) and the worst offenders (lowest MI files / highest CC
blocks) so humans and agents can fix without re-running ad-hoc radon scripts.
| Tool | Typical keys | Worse when |
|---|---|---|
radon.mi |
median-*, p5-*, p10-* (also average-*, minimum-*, p95-*) |
lower (floors) |
radon.cc |
median-*, p95-* (also average-*, maximum-*, p5-*, p10-*) |
higher (ceilings) |
Modes:
threshold— absolute floor/ceiling; fails when the measured metric crosses it.progressive— must not regress vs the last saved value in.shipgate/cache/.env. First progressive run seeds the baseline and passes.
Bundled shipgate init scaffolds progressive MI distribution floors (seed on
first run, fail on regression) plus letter rank B. That stays portable across
repos; pin absolute floors with shipgate radon calibrate when you want dogfood-
style strictness. ShipGate's own .shipgate/shipgate.yaml uses absolute median /
p5 / p10 thresholds and progressive minimum — not an inverted MI p95≥100
floor.
Env keys (progressive only): SHIPGATE_RADON_MI_AVG, SHIPGATE_RADON_MI_MEDIAN,
SHIPGATE_RADON_MI_MIN, SHIPGATE_RADON_MI_P5, SHIPGATE_RADON_MI_P10,
SHIPGATE_RADON_MI_P95, SHIPGATE_RADON_CC_AVG, SHIPGATE_RADON_CC_MEDIAN,
SHIPGATE_RADON_CC_MAX, SHIPGATE_RADON_CC_P5, SHIPGATE_RADON_CC_P10,
SHIPGATE_RADON_CC_P95.
After a refactor that dipped then recovered, reset those keys and re-seed on the
next check. This is not the check-result cache under .shipgate/cache/check-results/.
shipgate radon reset
shipgate check --check radon.mi
shipgate check --check radon.cc
Use shipgate radon calibrate when you want absolute floors instead of
progressive baselines.
# Bundled init (portable): progressive MI floors
checks:
radon.mi:
threshold: B
median-mode: progressive
p5-mode: progressive
p10-mode: progressive
minimum-mode: progressive
radon.cc:
threshold: B
median-mode: threshold
median-threshold: 3
p95-mode: threshold
p95-threshold: 7
# Absolute MI floors after calibrate (ShipGate dogfood style)
checks:
radon.mi:
threshold: B
median-mode: threshold
median-threshold: 55.8
p5-mode: threshold
p5-threshold: 28
p10-mode: threshold
p10-threshold: 32
minimum-mode: progressive
Calibrate suggested thresholds
shipgate radon calibrate mi --path src --path tests
shipgate radon calibrate cc --path src --yaml
shipgate radon calibrate mi --json-file /tmp/radon-mi.json
shipgate radon calibrate prints the live distribution (n, mean/median/min/max,
p5/p10/p95), the worst offenders, and a YAML binding snippet with
passable suggested floors (MI) or ceilings (CC). Use --yaml for the snippet
only. Prefer --json-file in tests or offline; otherwise radon runs from the
managed tool env when present.
Consumers may still use progressive or average/min/max:
checks:
radon.mi:
threshold: B
average-mode: progressive
minimum-mode: threshold
minimum-threshold: 20
radon.cc:
threshold: B
average-mode: threshold
average-threshold: 5
maximum-mode: progressive