detached 04ad7a9

docs: document rules, inline ignores, CLI flags and exit codes

commit
04ad7a97ad1f14260d06c0a5aae9f55aef7eaaf0
author
brice · · 2026-10-08 05:44 UTC
parent
6cbb6f5
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
4 files · +90 -11
M CHANGELOG.md +23 -0
@@ -1,5 +1,28 @@
11 # Changelog
22
3+## Unreleased
4+
5+### Breaking
6+
7+- The CLI uses plain flags: `-config`, `-root`, `-module` replace `-hexcheck.config`, `-hexcheck.root`, `-hexcheck.module`.
8+- The config is strict: unknown keys and unknown rule names in `rules`, `ruleSettings`, and `allow` are errors.
9+- Diagnostic messages are prefixed with their severity, e.g. `[error] no-adapter-imports-in-core: ...`.
10+
11+### Added
12+
13+- Rules `no-usecase-imports-in-core`, `no-infra-imports-in-ports`, and `no-entrypoint-imports-in-adapter`. `no-infra-imports-in-usecase` also covers entrypoint imports.
14+- Rule severity drives the CLI exit code: only `error` rules fail by default; `-fail-on warn` also fails on warnings.
15+- `//hexcheck:ignore <rule>[,<rule>] <reason>` inline suppression.
16+- `hexcheck init` writes a starter `.hexcheck.yaml` from detected folders.
17+- `-json` and `-version` CLI flags.
18+- Type-leak rules inspect channels, function signatures, inline structs, aliases, and generic type arguments.
19+- Release builds with GoReleaser.
20+
21+### Fixed
22+
23+- The config is loaded once per run instead of once per package.
24+- The generated-mock index is rebuilt on each run instead of being cached for the process lifetime.
25+
326 ## v0.1.0
427
528 Initial release of `hexcheck`.
@@ -1,5 +1,28 @@
1 # Changelog1 # Changelog
2 2
3+## Unreleased
4+
5+### Breaking
6+
7+- The CLI uses plain flags: `-config`, `-root`, `-module` replace `-hexcheck.config`, `-hexcheck.root`, `-hexcheck.module`.
8+- The config is strict: unknown keys and unknown rule names in `rules`, `ruleSettings`, and `allow` are errors.
9+- Diagnostic messages are prefixed with their severity, e.g. `[error] no-adapter-imports-in-core: ...`.
10+
11+### Added
12+
13+- Rules `no-usecase-imports-in-core`, `no-infra-imports-in-ports`, and `no-entrypoint-imports-in-adapter`. `no-infra-imports-in-usecase` also covers entrypoint imports.
14+- Rule severity drives the CLI exit code: only `error` rules fail by default; `-fail-on warn` also fails on warnings.
15+- `//hexcheck:ignore <rule>[,<rule>] <reason>` inline suppression.
16+- `hexcheck init` writes a starter `.hexcheck.yaml` from detected folders.
17+- `-json` and `-version` CLI flags.
18+- Type-leak rules inspect channels, function signatures, inline structs, aliases, and generic type arguments.
19+- Release builds with GoReleaser.
20+
21+### Fixed
22+
23+- The config is loaded once per run instead of once per package.
24+- The generated-mock index is rebuilt on each run instead of being cached for the process lifetime.
25+
3 ## v0.1.026 ## v0.1.0
4 27
5 Initial release of `hexcheck`.28 Initial release of `hexcheck`.
M README.md +55 -8
@@ -66,7 +66,10 @@ components:
6666
6767 rules:
6868 no-adapter-imports-in-core: error
69+ no-usecase-imports-in-core: error
6970 no-infra-imports-in-usecase: error
71+ no-infra-imports-in-ports: error
72+ no-entrypoint-imports-in-adapter: error
7073 no-framework-types-in-core: error
7174 no-infra-types-in-ports: error
7275 no-adapter-to-adapter-imports: warn
@@ -99,20 +102,62 @@ A fuller example lives in [`examples/hexcheck.yaml`](examples/hexcheck.yaml).
99102
100103 Business-logic diagnostics include a confidence level. `audit` mode reports findings at or above `businessLogicMinConfidence`; `ci` mode reports only high-confidence findings.
101104
102-## Standalone CLI
105+## Rules
103106
104-Because `hexcheck` is a `go/analysis` analyzer, standalone flags use the analyzer prefix:
107+| Rule | Default | Reports |
108+| --- | --- | --- |
109+| `no-adapter-imports-in-core` | error | core imports an adapter or entrypoint |
110+| `no-usecase-imports-in-core` | error | core imports a usecase |
111+| `no-infra-imports-in-usecase` | error | usecase imports an adapter or entrypoint |
112+| `no-infra-imports-in-ports` | error | ports import an adapter or entrypoint |
113+| `no-entrypoint-imports-in-adapter` | error | adapter imports an entrypoint |
114+| `no-framework-types-in-core` | error | exported core API exposes an adapter or framework type |
115+| `no-infra-types-in-ports` | error | port interface method exposes an adapter or framework type |
116+| `no-adapter-to-adapter-imports` | warn | adapter imports another adapter component |
117+| `suspicious-business-logic-in-adapter` | warn | adapter or entrypoint function looks like business logic |
118+| `no-local-fakes-for-ports` | warn | test defines a fake for a port that has a generated mock |
119+| `missing-generated-mock-for-port` | warn | port interface has no generated mock |
120+| `prefer-generated-mocks` | warn | usecase/core test imports a concrete adapter |
105121
106-```bash
107-hexcheck -hexcheck.config .hexcheck.yaml -hexcheck.root . ./...
122+Type-leak rules look through pointers, slices, maps, channels, function signatures, inline structs, aliases, and generic type arguments.
123+
124+The config is strict: unknown keys and unknown rule names are errors.
125+
126+## Suppressing a finding
127+
128+Prefer config `allow` entries for whole files or directories. For one line, use an inline directive with a reason:
129+
130+```go
131+type Rows interface {
132+ //hexcheck:ignore no-infra-types-in-ports row type is part of the published contract
133+ Next() sql.Row
134+}
108135 ```
109136
110-During development:
137+The directive covers its own line and the next one. It accepts a comma-separated rule list. A directive without a reason, or with an unknown rule, is reported as `invalid-ignore-directive`.
138+
139+## Standalone CLI
111140
112141 ```bash
113-go run ./cmd/hexcheck -hexcheck.config examples/hexcheck.yaml -hexcheck.root . ./...
142+hexcheck init # write a starter .hexcheck.yaml from detected folders
143+hexcheck ./... # check; config is discovered from the root upwards
144+hexcheck -config .hexcheck.yaml -root . ./...
114145 ```
115146
147+| Flag | Default | Meaning |
148+| --- | --- | --- |
149+| `-config` | discovered | path to `.hexcheck.yaml` |
150+| `-root` | current dir | project root for config-relative paths |
151+| `-module` | from `go.mod` | Go module path |
152+| `-fail-on` | `error` | lowest severity that fails: `error` or `warn` |
153+| `-json` | false | JSON output on stdout |
154+| `-test` | true | also analyze test files |
155+| `-version` | | print the version |
156+
157+Each finding is prefixed with its severity, e.g. `[warn] no-adapter-to-adapter-imports: ...`.
158+
159+Exit codes: `0` no failing findings, `1` load/config/analysis error, `2` usage error, `3` findings at or above `-fail-on`.
160+
116161 ## golangci-lint module plugin
117162
118163 Build a custom golangci-lint binary using the module plugin system:
@@ -149,6 +194,8 @@ linters:
149194 config: .hexcheck.yaml
150195 ```
151196
197+golangci-lint reports every hexcheck finding as an issue, whatever its configured severity. To fail only on `error` rules, set the warn rules to `off` in `.hexcheck.yaml`, or exclude issues whose text matches `^\[warn\]` with `linters.exclusions.rules`.
198+
152199 ## Agent configuration guide
153200
154201 [`SKILL.md`](SKILL.md) explains how an agent should configure `hexcheck` for a new repository, including non-standard layouts such as `core`/`boundaries`.
@@ -156,7 +203,7 @@ linters:
156203 ## Local development
157204
158205 ```bash
159-make test
160-make check
206+make test # go test -race
207+make check # tidy, lint, test, and hexcheck on its own code
161208 HEXCHECK_SMOKE_REPO=/path/to/local/go/repo make smoke-local
162209 ```
@@ -66,7 +66,10 @@ components:
66 66
67 rules:67 rules:
68 no-adapter-imports-in-core: error68 no-adapter-imports-in-core: error
69+ no-usecase-imports-in-core: error
69 no-infra-imports-in-usecase: error70 no-infra-imports-in-usecase: error
71+ no-infra-imports-in-ports: error
72+ no-entrypoint-imports-in-adapter: error
70 no-framework-types-in-core: error73 no-framework-types-in-core: error
71 no-infra-types-in-ports: error74 no-infra-types-in-ports: error
72 no-adapter-to-adapter-imports: warn75 no-adapter-to-adapter-imports: warn
@@ -99,20 +102,62 @@ A fuller example lives in [`examples/hexcheck.yaml`](examples/hexcheck.yaml).
99 102
100 Business-logic diagnostics include a confidence level. `audit` mode reports findings at or above `businessLogicMinConfidence`; `ci` mode reports only high-confidence findings.103 Business-logic diagnostics include a confidence level. `audit` mode reports findings at or above `businessLogicMinConfidence`; `ci` mode reports only high-confidence findings.
101 104
102-## Standalone CLI105+## Rules
103 106
104-Because `hexcheck` is a `go/analysis` analyzer, standalone flags use the analyzer prefix:107+| Rule | Default | Reports |
108+| --- | --- | --- |
109+| `no-adapter-imports-in-core` | error | core imports an adapter or entrypoint |
110+| `no-usecase-imports-in-core` | error | core imports a usecase |
111+| `no-infra-imports-in-usecase` | error | usecase imports an adapter or entrypoint |
112+| `no-infra-imports-in-ports` | error | ports import an adapter or entrypoint |
113+| `no-entrypoint-imports-in-adapter` | error | adapter imports an entrypoint |
114+| `no-framework-types-in-core` | error | exported core API exposes an adapter or framework type |
115+| `no-infra-types-in-ports` | error | port interface method exposes an adapter or framework type |
116+| `no-adapter-to-adapter-imports` | warn | adapter imports another adapter component |
117+| `suspicious-business-logic-in-adapter` | warn | adapter or entrypoint function looks like business logic |
118+| `no-local-fakes-for-ports` | warn | test defines a fake for a port that has a generated mock |
119+| `missing-generated-mock-for-port` | warn | port interface has no generated mock |
120+| `prefer-generated-mocks` | warn | usecase/core test imports a concrete adapter |
105 121
106-```bash122+Type-leak rules look through pointers, slices, maps, channels, function signatures, inline structs, aliases, and generic type arguments.
107-hexcheck -hexcheck.config .hexcheck.yaml -hexcheck.root . ./...123+
124+The config is strict: unknown keys and unknown rule names are errors.
125+
126+## Suppressing a finding
127+
128+Prefer config `allow` entries for whole files or directories. For one line, use an inline directive with a reason:
129+
130+```go
131+type Rows interface {
132+ //hexcheck:ignore no-infra-types-in-ports row type is part of the published contract
133+ Next() sql.Row
134+}
108 ```135 ```
109 136
110-During development:137+The directive covers its own line and the next one. It accepts a comma-separated rule list. A directive without a reason, or with an unknown rule, is reported as `invalid-ignore-directive`.
138+
139+## Standalone CLI
111 140
112 ```bash141 ```bash
113-go run ./cmd/hexcheck -hexcheck.config examples/hexcheck.yaml -hexcheck.root . ./...142+hexcheck init # write a starter .hexcheck.yaml from detected folders
143+hexcheck ./... # check; config is discovered from the root upwards
144+hexcheck -config .hexcheck.yaml -root . ./...
114 ```145 ```
115 146
147+| Flag | Default | Meaning |
148+| --- | --- | --- |
149+| `-config` | discovered | path to `.hexcheck.yaml` |
150+| `-root` | current dir | project root for config-relative paths |
151+| `-module` | from `go.mod` | Go module path |
152+| `-fail-on` | `error` | lowest severity that fails: `error` or `warn` |
153+| `-json` | false | JSON output on stdout |
154+| `-test` | true | also analyze test files |
155+| `-version` | | print the version |
156+
157+Each finding is prefixed with its severity, e.g. `[warn] no-adapter-to-adapter-imports: ...`.
158+
159+Exit codes: `0` no failing findings, `1` load/config/analysis error, `2` usage error, `3` findings at or above `-fail-on`.
160+
116 ## golangci-lint module plugin161 ## golangci-lint module plugin
117 162
118 Build a custom golangci-lint binary using the module plugin system:163 Build a custom golangci-lint binary using the module plugin system:
@@ -149,6 +194,8 @@ linters:
149 config: .hexcheck.yaml194 config: .hexcheck.yaml
150 ```195 ```
151 196
197+golangci-lint reports every hexcheck finding as an issue, whatever its configured severity. To fail only on `error` rules, set the warn rules to `off` in `.hexcheck.yaml`, or exclude issues whose text matches `^\[warn\]` with `linters.exclusions.rules`.
198+
152 ## Agent configuration guide199 ## Agent configuration guide
153 200
154 [`SKILL.md`](SKILL.md) explains how an agent should configure `hexcheck` for a new repository, including non-standard layouts such as `core`/`boundaries`.201 [`SKILL.md`](SKILL.md) explains how an agent should configure `hexcheck` for a new repository, including non-standard layouts such as `core`/`boundaries`.
@@ -156,7 +203,7 @@ linters:
156 ## Local development203 ## Local development
157 204
158 ```bash205 ```bash
159-make test206+make test # go test -race
160-make check207+make check # tidy, lint, test, and hexcheck on its own code
161 HEXCHECK_SMOKE_REPO=/path/to/local/go/repo make smoke-local208 HEXCHECK_SMOKE_REPO=/path/to/local/go/repo make smoke-local
162 ```209 ```
M SKILL.md +9 -3
@@ -5,7 +5,7 @@ description: Use when configuring or running hexcheck in a Go repo for hexagonal
55
66 # Hexcheck
77
8-Configure `.hexcheck.yaml` by mapping repo paths to roles. Folder names do not matter; roles do.
8+Configure `.hexcheck.yaml` by mapping repo paths to roles. Folder names do not matter; roles do. Start with `hexcheck init`, which writes a starter config from detected folders, then refine it.
99
1010 Roles:
1111 - `core`: domain/core business logic
@@ -35,7 +35,10 @@ Recommended rules:
3535 ```yaml
3636 rules:
3737 no-adapter-imports-in-core: error
38+ no-usecase-imports-in-core: error
3839 no-infra-imports-in-usecase: error
40+ no-infra-imports-in-ports: error
41+ no-entrypoint-imports-in-adapter: error
3942 no-framework-types-in-core: error
4043 no-infra-types-in-ports: error
4144 no-adapter-to-adapter-imports: warn
@@ -66,7 +69,10 @@ mocking:
6669 Run:
6770
6871 ```bash
69-hexcheck -hexcheck.config .hexcheck.yaml -hexcheck.root . ./...
72+hexcheck -config .hexcheck.yaml -root . ./... # exit 3 on error-level findings
73+hexcheck -fail-on warn ./... # also fail on warn-level findings
7074 ```
7175
72-Agent checklist: read repo architecture docs, map paths to roles, ignore generated/mocks, configure mock paths, run once, tune `ruleSettings.*.excludePaths` only after inspecting examples.
76+The config is strict: unknown keys or rule names fail the run. For a single justified exception, use an inline directive with a reason: `//hexcheck:ignore <rule>[,<rule>] <reason>`.
77+
78+Agent checklist: read repo architecture docs, map paths to roles, ignore generated/mocks, configure mock paths, run once, tune `ruleSettings.*.excludePaths` only after inspecting examples, and prefer `allow` entries or inline directives with reasons over turning rules off.
@@ -5,7 +5,7 @@ description: Use when configuring or running hexcheck in a Go repo for hexagonal
5 5
6 # Hexcheck6 # Hexcheck
7 7
8-Configure `.hexcheck.yaml` by mapping repo paths to roles. Folder names do not matter; roles do.8+Configure `.hexcheck.yaml` by mapping repo paths to roles. Folder names do not matter; roles do. Start with `hexcheck init`, which writes a starter config from detected folders, then refine it.
9 9
10 Roles:10 Roles:
11 - `core`: domain/core business logic11 - `core`: domain/core business logic
@@ -35,7 +35,10 @@ Recommended rules:
35 ```yaml35 ```yaml
36 rules:36 rules:
37 no-adapter-imports-in-core: error37 no-adapter-imports-in-core: error
38+ no-usecase-imports-in-core: error
38 no-infra-imports-in-usecase: error39 no-infra-imports-in-usecase: error
40+ no-infra-imports-in-ports: error
41+ no-entrypoint-imports-in-adapter: error
39 no-framework-types-in-core: error42 no-framework-types-in-core: error
40 no-infra-types-in-ports: error43 no-infra-types-in-ports: error
41 no-adapter-to-adapter-imports: warn44 no-adapter-to-adapter-imports: warn
@@ -66,7 +69,10 @@ mocking:
66 Run:69 Run:
67 70
68 ```bash71 ```bash
69-hexcheck -hexcheck.config .hexcheck.yaml -hexcheck.root . ./...72+hexcheck -config .hexcheck.yaml -root . ./... # exit 3 on error-level findings
73+hexcheck -fail-on warn ./... # also fail on warn-level findings
70 ```74 ```
71 75
72-Agent checklist: read repo architecture docs, map paths to roles, ignore generated/mocks, configure mock paths, run once, tune `ruleSettings.*.excludePaths` only after inspecting examples.76+The config is strict: unknown keys or rule names fail the run. For a single justified exception, use an inline directive with a reason: `//hexcheck:ignore <rule>[,<rule>] <reason>`.
77+
78+Agent checklist: read repo architecture docs, map paths to roles, ignore generated/mocks, configure mock paths, run once, tune `ruleSettings.*.excludePaths` only after inspecting examples, and prefer `allow` entries or inline directives with reasons over turning rules off.
M examples/hexcheck.yaml +3 -0
@@ -40,7 +40,10 @@ components:
4040
4141 rules:
4242 no-adapter-imports-in-core: error
43+ no-usecase-imports-in-core: error
4344 no-infra-imports-in-usecase: error
45+ no-infra-imports-in-ports: error
46+ no-entrypoint-imports-in-adapter: error
4447 no-framework-types-in-core: error
4548 no-infra-types-in-ports: error
4649 no-adapter-to-adapter-imports: warn
@@ -40,7 +40,10 @@ components:
40 40
41 rules:41 rules:
42 no-adapter-imports-in-core: error42 no-adapter-imports-in-core: error
43+ no-usecase-imports-in-core: error
43 no-infra-imports-in-usecase: error44 no-infra-imports-in-usecase: error
45+ no-infra-imports-in-ports: error
46+ no-entrypoint-imports-in-adapter: error
44 no-framework-types-in-core: error47 no-framework-types-in-core: error
45 no-infra-types-in-ports: error48 no-infra-types-in-ports: error
46 no-adapter-to-adapter-imports: warn49 no-adapter-to-adapter-imports: warn

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 5

↑↓ moveenter openesc close