Problem
When a whole directory sits outside the include allowlist, filesystem_unmatched_files emits one violation line per file inside it — even though every line has the same message and root cause (the parent directory isn't allowed).
Reproduction
Given .katalyst/bases/local.yaml:
type: filesystem
root: .
filesystemChecks:
- path: .
include:
- "README.md"
- "ongoing/**"
- "episodic/**"
checks:
- kind: filesystem_unmatched_files
And a project layout with a disallowed sibling directory one-time/ containing 28 files, katalyst check prints 28 nearly-identical lines:
filesystem .: one-time/ai-council-followups-2026/README.md: /: unmatched file (matches no include pattern [README.md, ongoing/, episodic/] and no exclude pattern [])
filesystem .: one-time/ai-council-followups-2026/people/apoorva.md: /: unmatched file (matches no include pattern [...])
filesystem .: one-time/ai-council-followups-2026/people/barry.md: /: unmatched file (matches no include pattern [...])
... (25 more lines)
This drowns the real signal — that one-time/ (the directory) isn't allowed at all — in noise. Adding another disallowed dir with hundreds of files would make the output nearly unreadable.
Suggested behavior
When N files in the same disallowed subtree fail the same check with the same reason, collapse into a single grouped line, e.g.:
filesystem .: one-time/ (28 files): unmatched — matches no include pattern [README.md, ongoing/, episodic/]
filesystem .: sunday-school-scheduling/ (2 files): unmatched — matches no include pattern [...]
Or, more incrementally: identify the shallowest directory whose entire subtree is unmatched and report only that directory, with an optional file count. Files unmatched in an otherwise-allowed directory (e.g. a stray .tmp inside ongoing/) still print individually.
Bonus: verbose mode
Keep the per-file output available behind --verbose / -v for users who want the full list.
Problem
When a whole directory sits outside the include allowlist, filesystem_unmatched_files emits one violation line per file inside it — even though every line has the same message and root cause (the parent directory isn't allowed).
Reproduction
Given .katalyst/bases/local.yaml:
type: filesystem
root: .
filesystemChecks:
include:
checks:
And a project layout with a disallowed sibling directory one-time/ containing 28 files, katalyst check prints 28 nearly-identical lines:
filesystem .: one-time/ai-council-followups-2026/README.md: /: unmatched file (matches no include pattern [README.md, ongoing/, episodic/] and no exclude pattern [])
filesystem .: one-time/ai-council-followups-2026/people/apoorva.md: /: unmatched file (matches no include pattern [...])
filesystem .: one-time/ai-council-followups-2026/people/barry.md: /: unmatched file (matches no include pattern [...])
... (25 more lines)
This drowns the real signal — that one-time/ (the directory) isn't allowed at all — in noise. Adding another disallowed dir with hundreds of files would make the output nearly unreadable.
Suggested behavior
When N files in the same disallowed subtree fail the same check with the same reason, collapse into a single grouped line, e.g.:
filesystem .: one-time/ (28 files): unmatched — matches no include pattern [README.md, ongoing/, episodic/]
filesystem .: sunday-school-scheduling/ (2 files): unmatched — matches no include pattern [...]
Or, more incrementally: identify the shallowest directory whose entire subtree is unmatched and report only that directory, with an optional file count. Files unmatched in an otherwise-allowed directory (e.g. a stray .tmp inside ongoing/) still print individually.
Bonus: verbose mode
Keep the per-file output available behind --verbose / -v for users who want the full list.