aboutsummaryrefslogtreecommitdiff
path: root/docs/architecture/README.md
blob: e09efb09cb066a9d2b00798e579dd7720eed02f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# Architecture Suite

Four chained Claude Code skills for the full architecture lifecycle: **design**, **decide**, **document**, **evaluate**. Paradigm-agnostic (supports layered, hexagonal, microservices, event-driven, CQRS, DDD, and others). Language-aware (framework-agnostic checks work everywhere; language-specific linters augment when configured).

## The Chain

```
                 ┌─────────────────┐
  New project →  │   arch-design   │ → .architecture/brief.md
                 └────────┬────────┘
                          │
             (for each open decision)
                          │
                          ▼
                 ┌─────────────────┐
                 │   arch-decide   │ → docs/adr/NNNN-*.md
                 └────────┬────────┘
                          │
          (when ready to formalize)
                          │
                          ▼
                 ┌─────────────────┐
                 │  arch-document  │ → docs/architecture/*.md
                 └────────┬────────┘      (dispatches to c4-analyze, c4-diagram)
                          │
           (once code exists, periodically)
                          │
                          ▼
                 ┌─────────────────┐
                 │  arch-evaluate  │ → .architecture/evaluation-YYYY-MM-DD.md
                 └─────────────────┘
```

Skills are standalone — invoke any one directly. The flow above is the canonical path; you can enter at any point if the prerequisite artifacts already exist.

## What Each Skill Does

### [arch-design](../../arch-design/SKILL.md)

Elicits the architecture: intake (stakeholders, scale, team, timeline), quality-attribute prioritization, constraints, then proposes 2-4 candidate paradigms with honest trade-off analysis. Picks one with rationale. Lists open decisions that become ADRs.

**Output:** `.architecture/brief.md`

### [arch-decide](../../arch-decide/SKILL.md)

Records significant technical decisions as ADRs. Five template variants (MADR, Nygard, Y-statement, lightweight, RFC). Covers ADR lifecycle (proposed / accepted / deprecated / superseded), review checklist, and `adr-tools` automation.

**Output:** `docs/adr/NNNN-<title>.md`, plus an index at `docs/adr/README.md`.

**Forked from [wshobson/agents](https://github.com/wshobson/agents) — MIT.**

### [arch-document](../../arch-document/SKILL.md)

Produces full arc42-structured documentation from the brief + ADRs + codebase. All twelve arc42 sections. Dispatches to `c4-analyze` (for code-present systems) and `c4-diagram` (for textual descriptions) for the diagrams in sections 3, 5, 6, and 7.

**Output:** `docs/architecture/01-introduction.md` through `12-glossary.md`, plus diagrams under `docs/architecture/diagrams/`.

### [arch-evaluate](../../arch-evaluate/SKILL.md)

Audits the codebase against the brief + ADRs. Four framework-agnostic checks (cyclic deps, stated-layer violations, public API drift, forbidden deps). Opportunistically invokes language-specific linters if they're already configured in the repo.

**Output:** `.architecture/evaluation-YYYY-MM-DD.md`

## Installation

These skills live in this rulesets repo alongside the other skills (`debug`, `add-tests`, `c4-analyze`, etc.). Install globally once:

```bash
make -C ~/code/rulesets install
```

This symlinks every skill (including the four `arch-*`) into `~/.claude/skills/`. Any Claude Code session on this machine will see them.

To uninstall:

```bash
make -C ~/code/rulesets uninstall
```

To check install state:

```bash
make -C ~/code/rulesets list
```

## Optional: Language-Specific Linters

`arch-evaluate` works without any external tooling — its framework-agnostic checks cover cycles, layer violations, API drift, and forbidden deps on any language Claude can read. **Installing the linters below is optional** and augments those checks with dedicated tooling: faster on large codebases, CI-friendly, and precise.

Install only the ones you need for your active languages.

### Python — import-linter

Declarative import contracts. Config in `.importlinter` or `[tool.importlinter]` in `pyproject.toml`.

```bash
pipx install import-linter
# or: pip install --user import-linter
# or (in a uv-managed project): uv add --dev import-linter
```

Verify:

```bash
lint-imports --help
```

Example config (`.importlinter`):

```ini
[importlinter]
root_package = myapp

[importlinter:contract:layers]
name = Core layers
type = layers
layers =
    myapp.presentation
    myapp.application
    myapp.domain
    myapp.infrastructure

[importlinter:contract:framework_isolation]
name = Domain isolation
type = forbidden
source_modules =
    myapp.domain
forbidden_modules =
    django
    fastapi
```

### TypeScript / JavaScript — dependency-cruiser

Rich import analysis with a JS config file. The de-facto standard for TS architectural linting.

```bash
npm install --save-dev dependency-cruiser
# or globally: npm install -g dependency-cruiser
```

Verify:

```bash
npx dependency-cruiser --version
```

Generate an initial config:

```bash
npx dependency-cruiser --init
```

Then edit `.dependency-cruiser.cjs` to encode your architecture. Example rule:

```javascript
module.exports = {
  forbidden: [
    {
      name: 'domain-no-infrastructure',
      severity: 'error',
      from: { path: '^src/domain' },
      to:   { path: '^src/infrastructure' },
    },
  ],
  options: { tsPreCompilationDeps: true, tsConfig: { fileName: 'tsconfig.json' } },
};
```

### Go — golangci-lint (with depguard)

`go vet` (part of the stdlib) covers built-in checks. `depguard` (via golangci-lint) enforces import rules.

```bash
# macOS
brew install golangci-lint

# Linux / anywhere with Go
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
```

Verify:

```bash
golangci-lint --version
go vet ./...
```

Example `.golangci.yml`:

```yaml
linters:
  disable-all: true
  enable:
    - depguard

linters-settings:
  depguard:
    rules:
      domain:
        list-mode: lax
        files:
          - "$all"
          - "!**/infrastructure/**"
        deny:
          - pkg: "github.com/yourorg/yourapp/infrastructure"
            desc: "domain must not depend on infrastructure"
```

### Java — ArchUnit (v2+)

Test-driven: architectural rules live in JUnit tests. Not invoked by `arch-evaluate` in v1.

**Maven:**

```xml
<dependency>
  <groupId>com.tngtech.archunit</groupId>
  <artifactId>archunit-junit5</artifactId>
  <version>1.3.0</version>
  <scope>test</scope>
</dependency>
```

**Gradle:**

```groovy
testImplementation 'com.tngtech.archunit:archunit-junit5:1.3.0'
```

Example rule (`src/test/java/archtest/LayerRules.java`):

```java
@AnalyzeClasses(packages = "com.yourorg.yourapp")
class LayerRules {
  @ArchTest
  static final ArchRule layered =
    layeredArchitecture().consideringAllDependencies()
      .layer("Presentation").definedBy("..presentation..")
      .layer("Application").definedBy("..application..")
      .layer("Domain").definedBy("..domain..")
      .whereLayer("Presentation").mayNotBeAccessedByAnyLayer()
      .whereLayer("Application").mayOnlyBeAccessedByLayers("Presentation")
      .whereLayer("Domain").mayOnlyBeAccessedByLayers("Application", "Presentation");
}
```

Then run `mvn test` or `gradle test`.

### C / C++ — include-what-you-use (v2+)

Checks each source file's `#include` discipline. Not invoked by `arch-evaluate` in v1; listed for completeness.

```bash
# macOS
brew install include-what-you-use

# Arch Linux
sudo pacman -S include-what-you-use

# Ubuntu/Debian
sudo apt install iwyu
```

Integrate via CMake:

```cmake
set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE include-what-you-use)
```

Verify:

```bash
include-what-you-use --version
```

## Typical Flow

### New project

```bash
# 1. Shape the architecture
# In Claude Code:
/arch-design
# Answer intake questions, rank quality attributes, review candidates.
# Output: .architecture/brief.md

# 2. Record each open decision
/arch-decide
# Once per significant decision. Output: docs/adr/0001-*.md, 0002-*.md, etc.

# 3. Formalize (when ready)
/arch-document
# Generates all twelve arc42 sections + diagrams.
# Output: docs/architecture/*.md

# 4. Audit (once code exists)
/arch-evaluate
# Report at .architecture/evaluation-YYYY-MM-DD.md
```

### Existing project with no architecture docs

```bash
# 1. Retroactively capture
/arch-design      # reconstruct the brief from what exists
/arch-decide      # write ADRs for past decisions (date them honestly)
/arch-document    # produce current-state arc42 docs

# 2. Audit against the reconstructed intent
/arch-evaluate
```

### Continuous

- Re-run `/arch-evaluate` periodically (on PR, before release, monthly)
- Every significant new decision → `/arch-decide`
- Brief or ADR changes → `/arch-document` to refresh

## Where Things Land

```
<project-root>/
├── .architecture/
│   ├── brief.md                          ← arch-design
│   └── evaluation-YYYY-MM-DD.md          ← arch-evaluate
├── docs/
│   ├── adr/
│   │   ├── README.md                     ← arch-decide (index)
│   │   └── NNNN-<title>.md               ← arch-decide
│   └── architecture/
│       ├── README.md                     ← arch-document (index)
│       ├── 01-introduction.md …          ← arch-document
│       ├── 12-glossary.md
│       └── diagrams/                     ← arch-document (via c4-*)
│           ├── context.svg
│           ├── container.svg
│           └── runtime-<scenario>.svg
```

## Dependencies Between Skills

- `arch-decide` is standalone; nothing required from the others
- `arch-document` reads the brief and ADRs; without them, it stubs sections as TODO
- `arch-evaluate` requires the brief; without it, the skill stops and tells the user to run `arch-design`
- `arch-document` dispatches to `c4-analyze` (if code exists) and `c4-diagram` (otherwise) — both live in this same rulesets repo

## Versioning and Deferred Work

v1 covers the four core skills with the chain above. The deferred feature list — CI integration, auto-generated linter configs, ArchUnit integration, DDD aggregate boundaries, etc. — is tracked at [`v2-todo.org`](v2-todo.org).

## Licensing

- `arch-design`, `arch-document`, `arch-evaluate` — part of this rulesets repo
- `arch-decide` — forked from [wshobson/agents](https://github.com/wshobson/agents), **MIT**. See `arch-decide/LICENSE`.

## Contributing / Modifying

These are personal skills; fork as needed. If you change a skill and want to re-sync the global install symlink, re-run `make -C ~/code/rulesets install`. Symlinks point back at this repo, so edits propagate without re-install.