Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a420123
fix(auth): report upstream edge challenge instead of misleading OAuth…
cleverhoods Jun 20, 2026
b265308
test(ci): add live Device-Flow activation lane behind workflow_dispatch
cleverhoods Jun 20, 2026
83076b6
perf(check): faster rendering on large projects; dev-only stage timer…
cleverhoods Jun 20, 2026
250339e
fix(auth): raise typed errors on unreadable credentials/config instea…
cleverhoods Jun 20, 2026
67d5691
test(architecture): AST floor forbidding sentinel-collapse of caught …
cleverhoods Jun 20, 2026
b7c308b
refactor(rules): rename Google agent pack gemini to antigravity follo…
cleverhoods Jun 21, 2026
98410bb
style(tests): normalize formatter line-length in test_checks_command …
cleverhoods Jun 21, 2026
fa1c30c
chore: gitignore .doku session state
cleverhoods Jun 25, 2026
0cfa8df
feat(lint): per-line suppression directive + strip link/citation refs…
cleverhoods Jun 25, 2026
5a03774
fix(discovery): repo scans ignore home-scope config so a global ~/.co…
cleverhoods Jun 27, 2026
a9548bc
test(ci): gate hermetic smoke suite + rule lint in QA; cover heal --d…
cleverhoods Jun 27, 2026
e6ac9c9
chore: bump version to 0.5.12
cleverhoods Jun 27, 2026
effbf09
test(smoke): make multi-target exclusion load-bearing; correct heal d…
cleverhoods Jun 27, 2026
ce6f95b
feat(check): 0.5.12 cohort — canonical JSON rule IDs, heal scope + au…
cleverhoods Jun 27, 2026
e9cf3a3
fix(check): drop overpromising score-movement claim from collapsed fi…
cleverhoods Jun 27, 2026
a1b2dde
fix(0.5.12): heal scope-safety + suppression/exclude/tier/strict corr…
cleverhoods Jun 27, 2026
593e244
test(heal): run the scope-safety dot+token test in an isolated cwd so…
cleverhoods Jun 27, 2026
ed67a07
test(smoke): force text format in the uppercase-agent no-match test s…
cleverhoods Jun 27, 2026
d3aff29
fix(check): restore the project auto-memory segment dropped from repo…
cleverhoods Jun 27, 2026
67cb6f2
fix(check): show the worklist caption only when an error list actuall…
cleverhoods Jun 27, 2026
1609201
test(scan): skip POSIX-shaped auto-memory slug tests on Windows
cleverhoods Jun 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
branches:
- "[0-9]*.[0-9]*.[0-9]*"
- main
workflow_dispatch:

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
Expand All @@ -20,6 +21,10 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-latest deliberately omitted: ubuntu-latest covers the POSIX/Unix
# surface and windows-latest covers the non-POSIX surface; macOS is POSIX-like,
# so it is unlikely to surface issues ubuntu does not, and GitHub's macOS
# runners bill far more CI minutes. Revisit if a macOS-specific defect appears.
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
Expand All @@ -37,12 +42,38 @@ jobs:
- name: Type check
run: uv run poe type

- name: Rule lint
run: uv run poe test_lint

- name: Unit tests
run: uv run poe test_unit

- name: Integration tests
run: uv run poe test_integration

# Smoke tests intentionally not gated in CI yet — a few test cases have
# environment-dependent assumptions that pass locally but fail on the GH
# runner. Re-enable once the smoke suite is hermetic.
# Smoke suite is hermetic: tests/smoke/conftest.py forces offline
# diagnostics (no network), HOME is isolated, and tests that can only
# be observed via the mapper model declare `requires_model` so they
# skip cleanly on the model-free runner.
- name: Smoke tests
run: uv run poe test_smoke

# Live-path regression — hits the real platform host, so it stays out of the
# gated QA matrix (offline CI must remain green when the edge is flaky).
# Manual via the Actions tab; the assertion is the new-user activation hop.
live:
name: Live activation path
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Install dependencies
run: uv sync

- name: Live network tests
run: uv run poe test_live
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ __pycache__
# Internal coordination surface — private inner repo, never ships in the public CLI
/hub/

# doku session/worker state — hub coordination bookkeeping, never tracked in the public CLI
/.doku/

# Claude specific - Dev internals (root only; fixtures under tests/ and framework/ are tracked)
/.claude/
/.mcp.json
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Reporails CLI (v0.5.11)
# Reporails CLI (v0.5.12)

> **AI Instruction Diagnostics for coding agents. Validates the entire agentic instruction system against 120+ rules across six rule packs (core + per-agent). Supports Claude, Codex, Copilot, Cursor, and Gemini.**
>
Expand Down
43 changes: 43 additions & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,51 @@

### Added

- check: inline per-line finding suppression. Mark a single reviewed line with `<!-- ails-disable-line CORE:C:0047 -->` to silence just that one rule on just that line, while the rule keeps firing everywhere else. The directive is an invisible HTML comment, must name the rule (space/comma-separate several), and never changes how the rest of the line is analyzed. See `docs/configuration.md`.
- testing: added internal regression coverage to keep `ails check` output stable across refactors.
- testing: added an architecture check that keeps error handling at the network boundary consistent, so faults surface clearly instead of being silently swallowed.
- testing: opt-in live-network lane exercising the `ails auth login` activation path so first-contact auth regressions surface in CI rather than at a new user.
- testing: the suite now runs against an isolated home directory, so a contributor's machine-wide config (`~/.reporails/config.yml`, `~/.codex/`, `~/.claude/`) no longer leaks into agent-detection tests — they pass or fail the same way locally as in CI. Includes a regression test pinning that a global `~/.codex/config.toml` cannot hijack detection of an `AGENTS.md`-only project.
- testing: the end-to-end smoke suite now runs in CI on every push. It is hermetic — diagnostics run offline (no network), home is isolated, and the few assertions that can only be observed through the bundled mapper model skip cleanly on the model-free runner — so smoke regressions are caught in CI instead of shipping green.
- testing: the rule-library lint pass (`ails test --lint`) now runs as part of the QA gate, so a duplicate rule ID anywhere in the rule library or a malformed rule fails the gate instead of slipping through unnoticed.
- testing: new CI-gated coverage for three previously-untested behaviors — `ails check --heal --dry-run` leaving files unmodified, the friendly "Path not found" error on a bare keyword that is neither a path nor a capability, and multi-target `ails check` (several targets in one invocation) scoping the scan to exactly those targets.
- testing: hardened that new coverage — the multi-target test now asserts against a file the scan would otherwise discover, so it genuinely proves out-of-target scoping, and the `--heal --dry-run` no-mutation test documents that its full assertion runs only where the bundled model is present.

### Changed

- rules: renamed the Google agent rule pack and registry entry from `gemini` to `antigravity`, following Google's 2026-06-18 retirement of the Gemini CLI in favor of the Antigravity CLI. The pack still validates legacy `GEMINI.md` / `~/.gemini/` files for backward-compat and now also recognizes Antigravity's `AGENTS.md` primary and `.agents/` skills layout. `ails check` reports the agent as `antigravity`; the five implemented agents are now claude, codex, copilot, cursor, antigravity.
- testing: normalized code formatting in two test modules (no behavior change).
- check: `ails check --heal` now requires you to name what to fix. A whole-project heal — a bare `--heal`, or `ails check . --heal` / `ails check ./ --heal` — is refused; pass an explicit target (`ails check CLAUDE.md --heal`), preview everything with `--dry-run`, or opt into a whole-project rewrite with the new `--cwd` flag. `--heal` also never writes through an in-tree symlink whose real file lies outside the named target, so a scoped heal cannot modify files outside its scope. Prevents accidental project-wide and out-of-scope rewrites.
- check: applying fixes now requires an account. The diagnosis stays free for everyone, but `--heal` (apply or `--dry-run` preview) needs sign-in — anonymous users get the full diagnosis plus a prompt to run `ails auth login`. This keeps the free experience honest: the diagnosis names what to fix; the fix is the account feature.
- explain: `ails explain <rule>` now shows the rule's Pass / Fail examples, matching `ails rules -f md`. Both surfaces draw examples from the same fence-aware extractor, and both now name an absent example block ("no Pass / Fail examples") instead of silently omitting it.
- json: `-f json` and the `--format github` trailing JSON now emit canonical rule IDs (e.g. `CORE:S:0039`) for findings that previously carried a bare client-side token like `format` or `orphan`, matching the text output. The raw token is preserved under a new `label` key when it differs, so machine baselines keyed on it stay stable. As a result those findings now carry a populated `category` and join the per-surface category breakdown, and `top_rules` is keyed by canonical ID. (The `ambiguous_charge` classifier-confidence marker has no canonical rule and intentionally stays label-only.)
- rules: a rule's check can now declare `project_scope: true` in `checks.yml` to be skipped on a narrowed (single-target) run where a whole-project aggregate is meaningless — previously this was hard-coded in the engine, so adding such a rule required a code change. No change to default whole-project scans.
- help: the `npx @reporails/cli` help output now lists the `ails rules` command.
- check: the collapsed lower-priority findings row no longer claims those findings "won't move your score yet" — it now reads `+N lower-priority · -v to list`. The old wording implied the deferred findings would move the score once the higher-priority ones were fixed, which overpromised; the row simply marks the collapsed tail.

### Fixed

- check: a neutral sentence is no longer flagged as ambiguous when the only instruction-like word sits inside a Markdown link label, a citation reference, or a `code span` — those are references, not instructions. Genuine inline instruction language in a neutral sentence still surfaces. Reduces false positives on documentation prose that links to or cites a rule by name.
- auth: clearer errors when the credentials or config file can't be read — a corrupt file now produces a visible warning and the session continues with anonymous access, instead of a silent tier downgrade.
- performance: `ails check` is substantially faster on large projects, with identical output.
- auth: `ails auth login` now gives a clear, actionable error when the auth endpoint is reachable but returns an unexpected response (a non-200 status or a non-JSON body) — "retry shortly or contact support" — instead of a generic HTTP error or a misleading "OAuth not configured" message. Both the client-id lookup and the token-exchange step surface it.
- check: a whole-project scan no longer lets your machine-wide agent config decide which agent a repository is. A global home-directory file such as `~/.codex/config.toml` could make `ails check` treat a project that only has an `AGENTS.md` as that specific agent's project, narrowing the findings to that agent's rules instead of the cross-agent core set. Discovery now ignores home-scope (`~/...`) paths during a repository scan; those surfaces remain reachable only when you target them explicitly (e.g. `ails check subagent_memory`).
- check: a whole-project scan again surfaces the project's own auto-memory (the Memory segment). A recent change that stopped a machine-wide config from deciding a repo's agent had also dropped the project's per-project memory, which is keyed to this project specifically and is not a cross-project surface — it now shows again, while another project's memory still stays out of scope.
- check: the bridging caption "the listed errors are still your worklist" no longer appears when there is no error list below it. Anonymous and free-tier runs that show a quality score but gate the per-finding list behind sign-in previously printed the caption pointing at a list that wasn't there; it now appears only when error findings are actually listed.
- check: per-surface health bars stay column-aligned when a surface name is long and its file count reaches two digits — the name column now sizes to the widest label in the set instead of a fixed width.
- check: targeting a directory (`ails check <dir>`) no longer drops instruction files that are symlinks pointing outside that directory; an in-tree symlinked file under the target is now scanned.
- update: rule-framework archive extraction is forward-compatible with Python 3.14's stricter tar handling (uses the safe `data` extraction filter).
- check: `--heal` now leaves a line you marked with `<!-- ails-disable-line ... -->` untouched — a line you reviewed and silenced is no longer auto-rewritten. `--heal` also never writes through a symlinked file (including a capability target like a `.claude/rules/` symlink) whose real path lies outside the named scope, and skips a file whose `@import` directives would shift its line numbers rather than risk editing the wrong line.
- check: inline `ails-disable-line` suppression directives are now honored on the MCP `validate` tool too, matching `ails check` — an agent no longer re-flags a finding you already dismissed.
- check: `--exclude-files` (and `exclude_files` config) now also excludes a file reached only via an `@import` from a non-excluded file; previously such a file silently re-entered the scan. Naming an excluded file explicitly (`ails check VENDORED.md`) still scans it — an explicit target overrides the exclusion.
- check: `ails check <file> --heal -f json` run anonymously now still emits the full diagnosis JSON (the auth notice goes to stderr) — a machine consumer that adds `--heal` no longer loses all diagnostic data.
- check: `--strict` now exits non-zero for a displayed error on a user-scope target (e.g. `ails check subagent_memory --strict`), matching what the run displayed.
- auth: a session no longer silently downgrades to the free tier when the server returns a tier alongside an otherwise-unparseable response body.
- testing: the heal scope-safety regression for `ails check . <token> --heal` now runs in an isolated working directory, so it no longer depends on the checkout carrying a root `CLAUDE.md` — it passes identically in CI and locally.
- testing: the uppercase-agent smoke test now requests text output explicitly, so it asserts the human "No instruction files found" message reliably under CI (where the default output format is machine-readable) instead of only locally.
- testing: the project auto-memory regression tests skip on Windows, where the `~/.claude/projects/<slug>/memory/` slug derivation is POSIX-path-shaped and does not form a valid Windows path component — the behavior they assert holds only on POSIX.

### Removed

- internal: removed two unused output-rendering helpers; no change to `ails check` output.
- internal: pruned several unused internal modules (a feature-summary helper, a display stub, a dead init path, a rules-path resolver, and an orphan-feature detector); no user-facing behavior change.
16 changes: 16 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ disabled_rules:

Browse the full rule reference at [reporails.com/rules](https://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.

## Suppressing one finding on one line

`disabled_rules` turns a rule off everywhere. When a single line is an intentional, reviewed exception but the rule is still worth running everywhere else, mark just that line with an inline directive instead:

```markdown
## Always run the tests before committing <!-- ails-disable-line CORE:C:0047 -->
```

The directive is an HTML comment, so it stays invisible when the file renders. It suppresses **only** the named rule **only** on its own line — the same rule still fires on every other line, and other rules on the annotated line still fire. Name several rules with a space- or comma-separated list:

```markdown
Some heading line <!-- ails-disable-line CORE:C:0047, CORE:C:0042 -->
```

Use the rule ID shown next to the finding in `ails check` output (e.g. `CORE:C:0047`); the rule's slug works too. A directive that names no rule suppresses nothing — suppression is always targeted, so it stays auditable in review. The directive text never affects how the rest of the line is analyzed.

## 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.
Expand Down
4 changes: 2 additions & 2 deletions framework/capabilities_matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ version: "1.1.0"

# Implemented scope — these agents have full config.yml and audited docs.
# The rest are cataloged but not reconciled.
implemented: [claude, codex, copilot, cursor, gemini]
implemented: [antigravity, claude, codex, copilot, cursor]

# Capability taxonomy — stable IDs mapped to human labels.
taxonomy:
Expand Down Expand Up @@ -35,6 +35,7 @@ agents:
aider: [root, user_surfaces, config]
amazonq: [root, scoped, hooks, mcp, subagents, enterprise, plugins, agents_md, cross_read, user_surfaces, config]
amp: [root, scoped, skills, mcp, enterprise, agents_md, cross_read, user_surfaces, config]
antigravity: [root, scoped, skills, hooks, mcp, subagents, memory, enterprise, plugins, agents_md, cross_read, user_surfaces, config, templates, output]
augment: [root, scoped, mcp, agents_md, cross_read, user_surfaces, config]
bito: [root, enterprise, agents_md, cross_read, user_surfaces, config]
blackbox: [skills, user_surfaces, config]
Expand All @@ -48,7 +49,6 @@ agents:
copilot: [root, scoped, skills, hooks, mcp, subagents, memory, enterprise, plugins, agents_md, cross_read, user_surfaces, config, templates]
cursor: [root, scoped, skills, hooks, mcp, subagents, memory, enterprise, plugins, agents_md, cross_read, user_surfaces, config, templates, output, scheduled_tasks]
devin: [root, scoped, mcp, memory, enterprise, agents_md, user_surfaces, config, templates]
gemini: [root, scoped, skills, hooks, mcp, subagents, memory, enterprise, plugins, agents_md, cross_read, user_surfaces, config, templates, output]
goose: [root, scoped, mcp, memory, enterprise, plugins, agents_md, cross_read, user_surfaces, config, templates]
jetbrains: [root, scoped, mcp, enterprise, user_surfaces, config]
junie: [root, agents_md, user_surfaces, config]
Expand Down
Loading
Loading