Deny lists: telling nreactive what not to touch
There are files in every codebase you don't want an automated tool modifying. Generated clients that get overwritten on the next build. Vendored code you've patched and cannot re-derive. Security-sensitive middleware where the cost of a wrong change is several orders of magnitude higher than the value of a right one. Legacy modules that are scheduled for deletion and aren't worth investing in. The deny list is the mechanism for fencing all of those off from nreactive.
How deny lists are expressed
Deny patterns are standard globs. Wildcards, braces, negation — everything you'd expect. The match is against the repo-relative path, so src/generated/** matches anything under the generated directory, and **/*.snap matches snapshot files anywhere in the tree. Patterns are stored per-application in your settings, which means each app can have its own rules.
We compile the list once per request into an efficient matcher and apply it at every touch point: when the scan lists source files, when an error-driven fix resolves file paths from a stack, and when a model response proposes changes. If any of those stages references a deny-listed path, the path is dropped before it enters the model context or the patcher.
The touch points in detail
On scheduled scans, the deny list runs against the output of the file-prioritization pass. Paths that match are removed from the candidate set before budgeting, so they never get fetched and never enter the model context. The scan's activity log records how many paths were filtered out so you can see how much work the deny list is doing.
On error-driven fixes, the deny list runs against the file from error.source.file and against every file path the analyzer extracts from the stack trace. If every resolved path is deny-listed, the analysis is skipped entirely and a note is logged — no half-context analysis based on the files that happened to survive the filter.
On patch application, the deny list runs a final time against every change the model proposes. This is belt-and-suspenders: the model has been told in the system prompt not to propose changes to deny-listed files, but if it slips through anyway, the change is dropped before it's committed.
Common starting patterns
A useful starter list for most projects:
**/generated/**and**/*.gen.ts— anything written by a code generator.**/migrations/**— database migrations, where the wrong edit can corrupt data.**/*.snapand**/__snapshots__/**— test snapshots that must match exactly.vendor/**andthird_party/**— vendored dependencies you maintain patches on top of.- Any security-sensitive middleware or crypto-adjacent files, listed explicitly by path.
Start stricter than you think you need to. You can always remove a pattern later once you've built confidence in how the pipeline behaves on your codebase.
Interaction with ignore-error patterns
Deny lists are not the same thing as ignore-error patterns. Deny lists control which files the pipeline is allowed to read and modify. Ignore-error patterns control which errors the ingest endpoint accepts at all. The two are complementary. You might ignore all errors matching a flaky third-party pattern while also denying the pipeline from touching that vendor's code — one prevents the noise at capture, the other prevents an AI fix from wandering into territory you don't own.
Operational visibility
Every time the deny list matches, the activity log records it. On a scheduled scan you'll see how many of the forty candidate files were filtered out. On an error-driven fix you'll see a note when files are skipped, or when the pipeline aborts because every referenced file was on the list. That visibility makes it easy to tune — if you're seeing the pipeline abort on a class of errors you actually care about, you know the list is too wide.
A note on expectation setting
A deny list is a trust boundary, not a security boundary. It prevents honest mistakes; it is not a sandbox. The underlying VCS permissions are what actually control what the AI can commit. Treat the deny list as a way to focus the pipeline on the parts of your codebase where its judgement is good, not as the last line of defence — the last line of defence is a reviewer reading the PR and the branch protection rules on your repository.