Skip to main content

Configuration

Updated 2026-05-06 CLI 0.5.8

Reporails provides two configuration surfaces: global (per-user) and project (per-repo). Project config wins where both define the same key — global supplies the defaults, project overrides per-repo.

Project config — .ails/config.yml

Lives at the root of your repo.

default_agent: claude              # Which agent's rules to run by default
exclude_dirs: [examples]           # Extra directory names to skip during discovery (added to the built-in defaults below)
disabled_rules: [CORE:C:0010]      # Rule IDs to disable entirely
overrides:                         # Per-rule severity overrides
  CORE:S:0005:                     # Identity Fields In Frontmatter
    severity: low                  # Downgrade from default

Set values from the command line instead of editing the file:

Running these in the PROJECT_ROOT

ails config set default_agent claude
ails config set exclude_dirs examples,third_party

Built-in directory excludes

Reporails always skips these directory names during discovery, no matter where they appear in the tree. Without these defaults, the scan would descend into vendored trees and build output and pick up third-party instruction files (e.g. a CLAUDE.md shipped inside node_modules/<pkg>/) you didn't author:

Category Directory names
VCS .git, .svn, .hg
Python __pycache__, .venv, venv, .env, .mypy_cache, .ruff_cache, .pytest_cache
JS / TS node_modules
Build output dist, build, target, out
Data data, datasets
Vendored vendor
IDE / OS .idea, .vscode

Anything you add to exclude_dirs is additional — the built-ins always apply.

Global config — ~/.reporails/config.yml

Applies to every project.

default_agent: claude
auto_update_check: true

Set values from the command line:

ails config set --global default_agent claude
ails config set --global auto_update_check false

Project config wins where it overlaps with global. So if global says default_agent: claude and the repo's .ails/config.yml says default_agent: cursor, that repo runs the Cursor rule set.

Disabling rules

The single most common config change is disabling rules you disagree with:

# PROJECT_ROOT/.ails/config.yml
disabled_rules:
  - CORE:C:0010   # Build And Test Commands
  - CORE:S:0005   # Identity Fields In Frontmatter

Browse the full rule reference at reporails.com/rules to look up each rule's body and pass / fail examples before disabling — sometimes the rule's intent fits your project but the surface form doesn't, and a severity override (below) reads better than a disable. ails explain CORE:C:0010 shows the rule body inline from the CLI when you already know the ID.

Excluding directories

exclude_dirs is a list of directory names (not paths). Any directory matching one of these names is skipped no matter where it appears. The setting exists because the discovery walk scans every directory looking for instruction files — without an exclude list it would descend into vendored trees (node_modules, vendor/), build output (dist/, target/), and data dumps (data/), surfacing third-party CLAUDE.md / AGENTS.md files you didn't author and slowing the scan.

The built-in list above already covers the common cases. Add to exclude_dirs only when your project has a non-standard tree:

exclude_dirs:
  - examples
  - third_party

For one-off runs, pass --exclude-dirs on the command line:

ails check --exclude-dirs examples --exclude-dirs third_party

Per-surface include / exclude

Each agent has a set of surfacesmain (the primary instruction file), nested_context (subdirectory variants), rules, skills, agents, etc. The surfaces key lets you adjust the glob patterns each surface scans, without modifying the bundled framework configs:

# .ails/config.yml
surfaces:
  cursor.rules:
    exclude: ["**/draft/**"]            # drop matches under draft/ from Cursor rules
  claude.skills:
    include: [".github/skills/**/SKILL.md"]   # also scan .github/skills/ for Claude
  codex.main:
    exclude: ["**/legacy/AGENTS.md"]    # drop legacy AGENTS.md from Codex's main candidates

Keys are <agent_id>.<file_type> (e.g. cursor.rules, claude.main, codex.nested_context). Each entry may set:

  • include: additional glob patterns to scan on top of the agent's bundled patterns.
  • exclude: glob patterns whose matches are dropped from the surface's results.

Patterns match relative to the project root (the directory you ran ails check from).

Codex fallback filenames

Codex supports project_doc_fallback_filenames in its own ~/.codex/config.toml to recognize alternative instruction filenames (e.g. TEAM_GUIDE.md, .agents.md). Reading that user-home config from the validator is fragile — CI users have different homes — so Reporails reads the same setting from the project's own .ails/config.yml:

# .ails/config.yml
agents:
  codex:
    fallback_filenames: ["TEAM_GUIDE.md", ".agents.md"]

These filenames are added as **/<filename> to Codex's main surface — they classify the same way AGENTS.md does and pick up the same rules.

Local overrides — .ails/config.local.yml

Personal or CI-specific config that should not be committed goes in .ails/config.local.yml. The file is layered on top of .ails/config.yml:

  • Object keys merge recursively.
  • Array keys extend (the local list is appended to the committed list).
  • Scalar keys are replaced.
# .ails/config.local.yml — gitignored
surfaces:
  claude.main:
    exclude: ["**/legacy/CLAUDE.md"]    # I personally don't care about legacy/

When ails config set … writes .ails/config.yml, it also writes .ails/.gitignore listing config.local.yml and .gitignore itself — the gitignore is per-machine scaffolding (recreated on the next ails config set) and doesn't need to be committed. If you create .ails/ manually, add the two lines yourself:

# .ails/.gitignore
.gitignore
config.local.yml

Severity overrides

Severity is what makes a finding "critical" vs "info". Default severity comes from the rule itself; you can override it per project:

overrides:
  CORE:S:0005:                     # Identity Fields In Frontmatter
    severity: info                  # I don't care about this one — keep it visible but don't weight it
  CORE:G:0001:                     # Vcs Tracked
    severity: critical             # I really care about this one — escalate

Valid severity values: critical, high, medium, low, info.

Strict mode and minimum score

By default, ails check always exits 0 (so it doesn't break workflows). To make it exit non-zero on any finding:

ails check --strict

The CLI does not have a built-in --min-score flag. To gate on a minimum score, use the GitHub Action's min-score input — it parses the score from the JSON output and runs a post-step gate:

- uses: reporails/cli/action
  with:
    strict: "true"            # exit 1 if any rule fires
    min-score: "7.0"          # exit 1 if score < 7.0

Outside the action, wrap ails check -f json in a script that parses the score field and exits accordingly.

Authentication

The anonymous tier requires no account. To raise rate / payload caps and unlock the full diagnostic detail, sign in:

ails auth login        # browser-based GitHub Device Flow
ails auth status       # show current tier and a redacted key prefix
ails auth token        # print the full API key (for CI export)
ails auth logout       # remove stored credentials

Credentials are stored in ~/.reporails/credentials.yml (chmod 0600 on POSIX; Windows logs a warning, secure the file manually).

For CI, capture the API key with ails auth token and add it to your CI provider's secret store as AILS_API_KEY (or pass it via the GitHub Action's api-key input — see the GitHub Actions section in the README).

Output format

Pick output format per-run:

ails check -f text       # default — human-readable (see the Quick Start in the README for an example)
ails check -f json       # machine-readable JSON
ails check -f github     # GitHub Actions inline annotations

JSON output is one object per run, grouping findings under files keyed by path, plus aggregate stats and (when present) cross-file blocks. Tier-conditional fields are noted below.

{
  "offline": false,
  "files": {
    "CLAUDE.md": {
      "findings": [
        {
          "line": 18,
          "severity": "warning",
          "rule": "CORE:C:0034",
          "message": "Missing tech stack declaration"
        }
      ],
      "count": 5
    }
  },
  "stats": { "total": 21, "errors": 0, "warnings": 16, "info": 5 }
}

What differs by tier:

Field Anonymous Signed in
files.<path>.findings[].fix omitted included when the rule has fix text
cross_file[] (full detail, line / type per pair) omitted included
cross_file_coordinates[] (counts per file pair) included omitted
pro{} (summary of hints) omitted included when present

Always present, regardless of tier: offline, files{}, stats. surface_health[] is added when surfaces are populated.

GitHub annotations format emits one workflow command per finding so warnings appear inline on the diff in pull requests:

::warning file=CLAUDE.md,line=18,col=1::Missing tech stack declaration (CORE:C:0034)
::warning file=CLAUDE.md,line=42,col=1::Missing MCP documentation (CORE:C:0027)

← Tiers and Limits · Configuration · Score Guide →