v0.1.0 79118a8

SKILL.md RawHistoryFolder


name: hexcheck description: Use when configuring or running hexcheck in a Go repository to enforce hexagonal architecture boundaries, adapter business-logic warnings, and mock discipline.

Hexcheck Configuration Skill

Use hexcheck to lint Go repositories for hexagonal / clean architecture violations.

Core idea

hexcheck does not require folders to have fixed names. It maps project-specific paths to architecture roles through .hexcheck.yaml.

Supported roles:

  • core — domain entities, value objects, domain services, core business logic
  • usecase — application services/use cases/orchestration
  • ports — interfaces/contracts that core/usecases depend on
  • adapter — infrastructure, persistence, external services, outbound adapters
  • entrypoint — CLI, HTTP handlers, UI entrypoints, app bootstrap
  • ignore — generated code, mocks, vendored or ignored paths

Component names are arbitrary. The role is what matters.

Example mappings

A repo with domain, application, and infrastructure:

components:
  domain:
    role: core
    paths:
      - internal/domain/**
  usecases:
    role: usecase
    paths:
      - internal/application/usecase/**
      - internal/application/usecases/**
  ports:
    role: ports
    paths:
      - internal/application/port/**
  infrastructure:
    role: adapter
    paths:
      - internal/infrastructure/**
  cli:
    role: entrypoint
    paths:
      - cmd/**
      - internal/cli/**

A repo that uses core and boundaries:

components:
  core:
    role: core
    paths:
      - internal/core/**
  usecases:
    role: usecase
    paths:
      - internal/usecases/**
  inboundBoundaries:
    role: entrypoint
    paths:
      - internal/boundaries/in/**
  outboundBoundaries:
    role: adapter
    paths:
      - internal/boundaries/out/**
  contracts:
    role: ports
    paths:
      - internal/boundaries/ports/**

Start strict on deterministic rules and warning-first on heuristics:

rules:
  no-adapter-imports-in-core: error
  no-infra-imports-in-usecase: error
  no-framework-types-in-core: error
  no-infra-types-in-ports: error
  no-adapter-to-adapter-imports: warn
  suspicious-business-logic-in-adapter: warn
  no-local-fakes-for-ports: warn
  missing-generated-mock-for-port: warn
  prefer-generated-mocks: warn

Business-logic heuristic

suspicious-business-logic-in-adapter is cumulative and package-local. It should not scan the whole repository. It combines strong and weak evidence:

  • business keywords such as Validate, Migrate, Resolve, Score, Restore, Purge, Update
  • policy constants and branching
  • domain/core mutation or method calls
  • multiple port/usecase collaborators when combined with business wording

Use excludePaths for adapter areas where warnings are not useful:

ruleSettings:
  suspicious-business-logic-in-adapter:
    excludePaths:
      - internal/ui/generated/**

Generated code

Always ignore generated code and mocks:

components:
  generated:
    role: ignore
    paths:
      - '**/mocks/**'
      - '**/generated/**'
      - '**/*_templ.go'
      - '**/*_gen.go'

hexcheck also ignores files with a standard // Code generated ... DO NOT EDIT. comment.

Mock discipline

Configure generated mock locations so hexcheck can distinguish missing mocks from local fake misuse:

mocking:
  generatedMockPaths:
    - internal/mocks/**
    - internal/application/mocks/**
    - internal/application/port/mocks/**
    - internal/domain/repository/mocks/**
  generatedMockNamePatterns:
    - Mock{{Interface}}
    - '{{Interface}}Mock'

Expected behavior:

  • missing-generated-mock-for-port flags mockable interfaces without generated mocks.
  • no-local-fakes-for-ports flags local fakes only when a generated mock exists.
  • Intentional exceptions should use project config allow entries or linter suppression comments.

Running

Standalone:

hexcheck -hexcheck.config .hexcheck.yaml -hexcheck.root . ./...

With a custom golangci-lint binary, use the module plugin config from examples/custom-gcl.yml and examples/golangci.yml.

Agent checklist

When configuring a new repo:

  1. Read architecture docs (AGENTS.md, README, docs) before guessing paths.
  2. Map local folder names to roles; do not force folder renames.
  3. Add generated/mocks ignore paths.
  4. Add mock paths and name patterns.
  5. Run hexcheck once and inspect counts by rule.
  6. Tune ruleSettings.*.excludePaths for known technical adapters only after reviewing examples.
  7. Keep deterministic rules as error; keep heuristic rules as warn until signal is proven.
source
1---
2name: hexcheck
3description: Use when configuring or running hexcheck in a Go repository to enforce hexagonal architecture boundaries, adapter business-logic warnings, and mock discipline.
4---
5
6# Hexcheck Configuration Skill
7
8Use `hexcheck` to lint Go repositories for hexagonal / clean architecture violations.
9
10## Core idea
11
12`hexcheck` does not require folders to have fixed names. It maps project-specific paths to architecture roles through `.hexcheck.yaml`.
13
14Supported roles:
15
16- `core` — domain entities, value objects, domain services, core business logic
17- `usecase` — application services/use cases/orchestration
18- `ports` — interfaces/contracts that core/usecases depend on
19- `adapter` — infrastructure, persistence, external services, outbound adapters
20- `entrypoint` — CLI, HTTP handlers, UI entrypoints, app bootstrap
21- `ignore` — generated code, mocks, vendored or ignored paths
22
23Component names are arbitrary. The `role` is what matters.
24
25## Example mappings
26
27A repo with `domain`, `application`, and `infrastructure`:
28
29```yaml
30components:
31  domain:
32    role: core
33    paths:
34      - internal/domain/**
35  usecases:
36    role: usecase
37    paths:
38      - internal/application/usecase/**
39      - internal/application/usecases/**
40  ports:
41    role: ports
42    paths:
43      - internal/application/port/**
44  infrastructure:
45    role: adapter
46    paths:
47      - internal/infrastructure/**
48  cli:
49    role: entrypoint
50    paths:
51      - cmd/**
52      - internal/cli/**
53```
54
55A repo that uses `core` and `boundaries`:
56
57```yaml
58components:
59  core:
60    role: core
61    paths:
62      - internal/core/**
63  usecases:
64    role: usecase
65    paths:
66      - internal/usecases/**
67  inboundBoundaries:
68    role: entrypoint
69    paths:
70      - internal/boundaries/in/**
71  outboundBoundaries:
72    role: adapter
73    paths:
74      - internal/boundaries/out/**
75  contracts:
76    role: ports
77    paths:
78      - internal/boundaries/ports/**
79```
80
81## Recommended defaults
82
83Start strict on deterministic rules and warning-first on heuristics:
84
85```yaml
86rules:
87  no-adapter-imports-in-core: error
88  no-infra-imports-in-usecase: error
89  no-framework-types-in-core: error
90  no-infra-types-in-ports: error
91  no-adapter-to-adapter-imports: warn
92  suspicious-business-logic-in-adapter: warn
93  no-local-fakes-for-ports: warn
94  missing-generated-mock-for-port: warn
95  prefer-generated-mocks: warn
96```
97
98## Business-logic heuristic
99
100`suspicious-business-logic-in-adapter` is cumulative and package-local. It should not scan the whole repository. It combines strong and weak evidence:
101
102- business keywords such as `Validate`, `Migrate`, `Resolve`, `Score`, `Restore`, `Purge`, `Update`
103- policy constants and branching
104- domain/core mutation or method calls
105- multiple port/usecase collaborators when combined with business wording
106
107Use `excludePaths` for adapter areas where warnings are not useful:
108
109```yaml
110ruleSettings:
111  suspicious-business-logic-in-adapter:
112    excludePaths:
113      - internal/ui/generated/**
114```
115
116## Generated code
117
118Always ignore generated code and mocks:
119
120```yaml
121components:
122  generated:
123    role: ignore
124    paths:
125      - '**/mocks/**'
126      - '**/generated/**'
127      - '**/*_templ.go'
128      - '**/*_gen.go'
129```
130
131`hexcheck` also ignores files with a standard `// Code generated ... DO NOT EDIT.` comment.
132
133## Mock discipline
134
135Configure generated mock locations so `hexcheck` can distinguish missing mocks from local fake misuse:
136
137```yaml
138mocking:
139  generatedMockPaths:
140    - internal/mocks/**
141    - internal/application/mocks/**
142    - internal/application/port/mocks/**
143    - internal/domain/repository/mocks/**
144  generatedMockNamePatterns:
145    - Mock{{Interface}}
146    - '{{Interface}}Mock'
147```
148
149Expected behavior:
150
151- `missing-generated-mock-for-port` flags mockable interfaces without generated mocks.
152- `no-local-fakes-for-ports` flags local fakes only when a generated mock exists.
153- Intentional exceptions should use project config `allow` entries or linter suppression comments.
154
155## Running
156
157Standalone:
158
159```bash
160hexcheck -hexcheck.config .hexcheck.yaml -hexcheck.root . ./...
161```
162
163With a custom golangci-lint binary, use the module plugin config from `examples/custom-gcl.yml` and `examples/golangci.yml`.
164
165## Agent checklist
166
167When configuring a new repo:
168
1691. Read architecture docs (`AGENTS.md`, `README`, docs) before guessing paths.
1702. Map local folder names to roles; do not force folder renames.
1713. Add generated/mocks ignore paths.
1724. Add mock paths and name patterns.
1735. Run `hexcheck` once and inspect counts by rule.
1746. Tune `ruleSettings.*.excludePaths` for known technical adapters only after reviewing examples.
1757. Keep deterministic rules as `error`; keep heuristic rules as `warn` until signal is proven.

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