@xenos1996/usa 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +335 -0
  3. package/USA.md +597 -0
  4. package/dist/bootstrap/catalog.d.ts +46 -0
  5. package/dist/bootstrap/catalog.d.ts.map +1 -0
  6. package/dist/bootstrap/catalog.js +312 -0
  7. package/dist/bootstrap/catalog.js.map +1 -0
  8. package/dist/bootstrap/index.d.ts +36 -0
  9. package/dist/bootstrap/index.d.ts.map +1 -0
  10. package/dist/bootstrap/index.js +177 -0
  11. package/dist/bootstrap/index.js.map +1 -0
  12. package/dist/cli.d.ts +5 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +706 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/config.d.ts +7 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/config.js +88 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/detect/index.d.ts +58 -0
  21. package/dist/detect/index.d.ts.map +1 -0
  22. package/dist/detect/index.js +329 -0
  23. package/dist/detect/index.js.map +1 -0
  24. package/dist/engine/audit.d.ts +32 -0
  25. package/dist/engine/audit.d.ts.map +1 -0
  26. package/dist/engine/audit.js +366 -0
  27. package/dist/engine/audit.js.map +1 -0
  28. package/dist/engine/diff.d.ts +24 -0
  29. package/dist/engine/diff.d.ts.map +1 -0
  30. package/dist/engine/diff.js +136 -0
  31. package/dist/engine/diff.js.map +1 -0
  32. package/dist/engine/evaluate.d.ts +19 -0
  33. package/dist/engine/evaluate.d.ts.map +1 -0
  34. package/dist/engine/evaluate.js +377 -0
  35. package/dist/engine/evaluate.js.map +1 -0
  36. package/dist/engine/gate.d.ts +19 -0
  37. package/dist/engine/gate.d.ts.map +1 -0
  38. package/dist/engine/gate.js +47 -0
  39. package/dist/engine/gate.js.map +1 -0
  40. package/dist/engine/loader.d.ts +37 -0
  41. package/dist/engine/loader.d.ts.map +1 -0
  42. package/dist/engine/loader.js +388 -0
  43. package/dist/engine/loader.js.map +1 -0
  44. package/dist/engine/maturity.d.ts +20 -0
  45. package/dist/engine/maturity.d.ts.map +1 -0
  46. package/dist/engine/maturity.js +157 -0
  47. package/dist/engine/maturity.js.map +1 -0
  48. package/dist/engine/score.d.ts +19 -0
  49. package/dist/engine/score.d.ts.map +1 -0
  50. package/dist/engine/score.js +141 -0
  51. package/dist/engine/score.js.map +1 -0
  52. package/dist/engine/sections.d.ts +14 -0
  53. package/dist/engine/sections.d.ts.map +1 -0
  54. package/dist/engine/sections.js +50 -0
  55. package/dist/engine/sections.js.map +1 -0
  56. package/dist/evolution/benchmark.d.ts +12 -0
  57. package/dist/evolution/benchmark.d.ts.map +1 -0
  58. package/dist/evolution/benchmark.js +107 -0
  59. package/dist/evolution/benchmark.js.map +1 -0
  60. package/dist/evolution/capability.d.ts +22 -0
  61. package/dist/evolution/capability.d.ts.map +1 -0
  62. package/dist/evolution/capability.js +69 -0
  63. package/dist/evolution/capability.js.map +1 -0
  64. package/dist/evolution/coverage.d.ts +15 -0
  65. package/dist/evolution/coverage.d.ts.map +1 -0
  66. package/dist/evolution/coverage.js +65 -0
  67. package/dist/evolution/coverage.js.map +1 -0
  68. package/dist/evolution/gap.d.ts +10 -0
  69. package/dist/evolution/gap.d.ts.map +1 -0
  70. package/dist/evolution/gap.js +52 -0
  71. package/dist/evolution/gap.js.map +1 -0
  72. package/dist/evolution/propose.d.ts +50 -0
  73. package/dist/evolution/propose.d.ts.map +1 -0
  74. package/dist/evolution/propose.js +188 -0
  75. package/dist/evolution/propose.js.map +1 -0
  76. package/dist/evolution/queue.d.ts +64 -0
  77. package/dist/evolution/queue.d.ts.map +1 -0
  78. package/dist/evolution/queue.js +192 -0
  79. package/dist/evolution/queue.js.map +1 -0
  80. package/dist/evolution/release.d.ts +11 -0
  81. package/dist/evolution/release.d.ts.map +1 -0
  82. package/dist/evolution/release.js +55 -0
  83. package/dist/evolution/release.js.map +1 -0
  84. package/dist/evolution/run.d.ts +88 -0
  85. package/dist/evolution/run.d.ts.map +1 -0
  86. package/dist/evolution/run.js +258 -0
  87. package/dist/evolution/run.js.map +1 -0
  88. package/dist/evolution/schedule.d.ts +59 -0
  89. package/dist/evolution/schedule.d.ts.map +1 -0
  90. package/dist/evolution/schedule.js +77 -0
  91. package/dist/evolution/schedule.js.map +1 -0
  92. package/dist/evolution/types.d.ts +174 -0
  93. package/dist/evolution/types.d.ts.map +1 -0
  94. package/dist/evolution/types.js +8 -0
  95. package/dist/evolution/types.js.map +1 -0
  96. package/dist/index.d.ts +36 -0
  97. package/dist/index.d.ts.map +1 -0
  98. package/dist/index.js +30 -0
  99. package/dist/index.js.map +1 -0
  100. package/dist/learn/index.d.ts +27 -0
  101. package/dist/learn/index.d.ts.map +1 -0
  102. package/dist/learn/index.js +196 -0
  103. package/dist/learn/index.js.map +1 -0
  104. package/dist/report/markdown.d.ts +16 -0
  105. package/dist/report/markdown.d.ts.map +1 -0
  106. package/dist/report/markdown.js +488 -0
  107. package/dist/report/markdown.js.map +1 -0
  108. package/dist/snapshot/index.d.ts +55 -0
  109. package/dist/snapshot/index.d.ts.map +1 -0
  110. package/dist/snapshot/index.js +76 -0
  111. package/dist/snapshot/index.js.map +1 -0
  112. package/dist/store/index.d.ts +31 -0
  113. package/dist/store/index.d.ts.map +1 -0
  114. package/dist/store/index.js +69 -0
  115. package/dist/store/index.js.map +1 -0
  116. package/dist/types.d.ts +287 -0
  117. package/dist/types.d.ts.map +1 -0
  118. package/dist/types.js +16 -0
  119. package/dist/types.js.map +1 -0
  120. package/dist/util/glob.d.ts +11 -0
  121. package/dist/util/glob.d.ts.map +1 -0
  122. package/dist/util/glob.js +86 -0
  123. package/dist/util/glob.js.map +1 -0
  124. package/dist/util/project.d.ts +90 -0
  125. package/dist/util/project.d.ts.map +1 -0
  126. package/dist/util/project.js +636 -0
  127. package/dist/util/project.js.map +1 -0
  128. package/dist/util/yaml.d.ts +28 -0
  129. package/dist/util/yaml.d.ts.map +1 -0
  130. package/dist/util/yaml.js +48 -0
  131. package/dist/util/yaml.js.map +1 -0
  132. package/package.json +94 -0
  133. package/rules/core/architecture.yaml +190 -0
  134. package/rules/core/cicd.yaml +212 -0
  135. package/rules/core/code-quality.yaml +261 -0
  136. package/rules/core/dependencies.yaml +132 -0
  137. package/rules/core/documentation.yaml +119 -0
  138. package/rules/core/future-readiness.yaml +91 -0
  139. package/rules/core/release.yaml +131 -0
  140. package/rules/core/repo.yaml +313 -0
  141. package/rules/core/security.yaml +496 -0
  142. package/rules/core/supply-chain.yaml +357 -0
  143. package/rules/core/testing.yaml +266 -0
  144. package/rules/detectors.yaml +2028 -0
  145. package/rules/index.yaml +42 -0
  146. package/rules/profiles/maturity.yaml +135 -0
  147. package/rules/stacks/ai-era.yaml +193 -0
  148. package/rules/stacks/api-backend.yaml +121 -0
  149. package/rules/stacks/cli.yaml +105 -0
  150. package/rules/stacks/compliance.yaml +157 -0
  151. package/rules/stacks/containers.yaml +124 -0
  152. package/rules/stacks/data.yaml +165 -0
  153. package/rules/stacks/go.yaml +134 -0
  154. package/rules/stacks/iac.yaml +128 -0
  155. package/rules/stacks/jvm.yaml +150 -0
  156. package/rules/stacks/ml-ai.yaml +140 -0
  157. package/rules/stacks/mobile.yaml +121 -0
  158. package/rules/stacks/node-typescript.yaml +166 -0
  159. package/rules/stacks/python.yaml +175 -0
  160. package/rules/stacks/rust.yaml +129 -0
  161. package/rules/stacks/solidity.yaml +139 -0
  162. package/rules/stacks/swift.yaml +100 -0
  163. package/rules/stacks/web-frontend.yaml +159 -0
@@ -0,0 +1,2028 @@
1
+ # =============================================================================
2
+ # USA — Auto-detection signal registry (schema: usa-detectors-v1)
3
+ # -----------------------------------------------------------------------------
4
+ # Every rule pack declares `applies_when` over the FACTS produced here, so
5
+ # USA "adapts to the project" purely by data. Add a signal, and every pack
6
+ # that cares about it starts applying — no code change required.
7
+ #
8
+ # Fact namespaces
9
+ # lang:* programming language present
10
+ # pm:* package manager
11
+ # fw:* framework / library
12
+ # project:* project archetype
13
+ # platform:* runtime platform
14
+ # db:* datastore
15
+ # orm:* data-access layer
16
+ # auth:* authentication mechanism
17
+ # test:* test tooling
18
+ # ci:* CI provider
19
+ # infra:* infrastructure tooling
20
+ # api:* API style
21
+ # obs:* observability
22
+ # ai:* AI/LLM stack
23
+ # has:* cross-cutting capability
24
+ # doc:* documentation artefact
25
+ # practice:* team practice
26
+ # maturity:* lifecycle stage (computed)
27
+ #
28
+ # Match primitives (inside `match`)
29
+ # any_file: [glob] at least one file matches
30
+ # file_exists:[path/glob] path present
31
+ # dir_exists: [path] directory present
32
+ # content: {include: [glob], pattern} regex found in matching files
33
+ # manifest: {file, key, contains?} dotted key resolves in JSON/TOML/YAML
34
+ # metric: {name, min|max} numeric fact comparison
35
+ # any_of / all_of boolean composition
36
+ # implies: [fact] derived: all listed facts must hold
37
+ # =============================================================================
38
+
39
+ detectors:
40
+ # ------------------------------------------------------------------ language
41
+ - {
42
+ fact: 'lang:typescript',
43
+ category: language,
44
+ title: TypeScript,
45
+ match: { any_file: ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'] },
46
+ }
47
+ - {
48
+ fact: 'lang:javascript',
49
+ category: language,
50
+ title: JavaScript,
51
+ match: { any_file: ['**/*.js', '**/*.jsx', '**/*.mjs', '**/*.cjs'] },
52
+ }
53
+ - {
54
+ fact: 'lang:python',
55
+ category: language,
56
+ title: Python,
57
+ match: { any_file: ['**/*.py', '**/*.pyi'] },
58
+ }
59
+ - { fact: 'lang:go', category: language, title: Go, match: { any_file: ['**/*.go'] } }
60
+ - { fact: 'lang:rust', category: language, title: Rust, match: { any_file: ['**/*.rs'] } }
61
+ - { fact: 'lang:java', category: language, title: Java, match: { any_file: ['**/*.java'] } }
62
+ - {
63
+ fact: 'lang:kotlin',
64
+ category: language,
65
+ title: Kotlin,
66
+ match: { any_file: ['**/*.kt', '**/*.kts'] },
67
+ }
68
+ - { fact: 'lang:swift', category: language, title: Swift, match: { any_file: ['**/*.swift'] } }
69
+ - { fact: 'lang:ruby', category: language, title: Ruby, match: { any_file: ['**/*.rb'] } }
70
+ - { fact: 'lang:php', category: language, title: PHP, match: { any_file: ['**/*.php'] } }
71
+ - { fact: 'lang:csharp', category: language, title: 'C#', match: { any_file: ['**/*.cs'] } }
72
+ - {
73
+ fact: 'lang:cpp',
74
+ category: language,
75
+ title: 'C/C++',
76
+ match: { any_file: ['**/*.c', '**/*.h', '**/*.cc', '**/*.cpp', '**/*.hpp'] },
77
+ }
78
+ - { fact: 'lang:scala', category: language, title: Scala, match: { any_file: ['**/*.scala'] } }
79
+ - { fact: 'lang:dart', category: language, title: Dart, match: { any_file: ['**/*.dart'] } }
80
+ - {
81
+ fact: 'lang:elixir',
82
+ category: language,
83
+ title: Elixir,
84
+ match: { any_file: ['**/*.ex', '**/*.exs'] },
85
+ }
86
+ - { fact: 'lang:lua', category: language, title: Lua, match: { any_file: ['**/*.lua'] } }
87
+ - { fact: 'lang:zig', category: language, title: Zig, match: { any_file: ['**/*.zig'] } }
88
+ - {
89
+ fact: 'lang:solidity',
90
+ category: language,
91
+ title: Solidity,
92
+ match: { any_file: ['**/*.sol'] },
93
+ }
94
+ - {
95
+ fact: 'lang:shell',
96
+ category: language,
97
+ title: Shell,
98
+ match: { any_file: ['**/*.sh', '**/*.bash'] },
99
+ }
100
+ - { fact: 'lang:haskell', category: language, title: Haskell, match: { any_file: ['**/*.hs'] } }
101
+
102
+ # ------------------------------------------------------------ package manager
103
+ - {
104
+ fact: 'pm:node',
105
+ category: pm,
106
+ title: 'Node (package.json)',
107
+ match: { file_exists: ['package.json'] },
108
+ }
109
+ - { fact: 'pm:npm', category: pm, title: npm, match: { file_exists: ['package-lock.json'] } }
110
+ - {
111
+ fact: 'pm:pnpm',
112
+ category: pm,
113
+ title: pnpm,
114
+ match:
115
+ {
116
+ any_of:
117
+ [
118
+ { file_exists: ['pnpm-lock.yaml', 'pnpm-workspace.yaml'] },
119
+ { content: { include: ['package.json'], pattern: '"packageManager"\\s*:\\s*"pnpm' } },
120
+ ],
121
+ },
122
+ }
123
+ - {
124
+ fact: 'pm:yarn',
125
+ category: pm,
126
+ title: Yarn,
127
+ match:
128
+ {
129
+ any_of:
130
+ [
131
+ { file_exists: ['yarn.lock', '.yarnrc.yml'] },
132
+ { content: { include: ['package.json'], pattern: '"packageManager"\\s*:\\s*"yarn' } },
133
+ ],
134
+ },
135
+ }
136
+ - {
137
+ fact: 'pm:bun',
138
+ category: pm,
139
+ title: Bun,
140
+ match:
141
+ {
142
+ any_of:
143
+ [
144
+ { file_exists: ['bun.lockb', 'bun.lock'] },
145
+ { content: { include: ['package.json'], pattern: '"packageManager"\\s*:\\s*"bun' } },
146
+ ],
147
+ },
148
+ }
149
+ - {
150
+ fact: 'pm:pip',
151
+ category: pm,
152
+ title: pip,
153
+ match: { file_exists: ['requirements.txt', 'requirements-dev.txt'] },
154
+ }
155
+ - {
156
+ fact: 'pm:poetry',
157
+ category: pm,
158
+ title: Poetry,
159
+ match:
160
+ {
161
+ any_of:
162
+ [
163
+ { file_exists: ['poetry.lock'] },
164
+ { content: { include: ['pyproject.toml'], pattern: '\\[tool\\.poetry\\]' } },
165
+ ],
166
+ },
167
+ }
168
+ - {
169
+ fact: 'pm:uv',
170
+ category: pm,
171
+ title: uv,
172
+ match:
173
+ {
174
+ any_of:
175
+ [
176
+ { file_exists: ['uv.lock'] },
177
+ { content: { include: ['pyproject.toml'], pattern: '\\[tool\\.uv\\]' } },
178
+ ],
179
+ },
180
+ }
181
+ - { fact: 'pm:pipenv', category: pm, title: Pipenv, match: { file_exists: ['Pipfile'] } }
182
+ - { fact: 'pm:cargo', category: pm, title: Cargo, match: { file_exists: ['Cargo.toml'] } }
183
+ - { fact: 'pm:go-mod', category: pm, title: 'Go modules', match: { file_exists: ['go.mod'] } }
184
+ - { fact: 'pm:maven', category: pm, title: Maven, match: { file_exists: ['pom.xml'] } }
185
+ - {
186
+ fact: 'pm:gradle',
187
+ category: pm,
188
+ title: Gradle,
189
+ match:
190
+ {
191
+ any_file: ['build.gradle', 'build.gradle.kts', 'settings.gradle', 'settings.gradle.kts'],
192
+ },
193
+ }
194
+ - {
195
+ fact: 'pm:composer',
196
+ category: pm,
197
+ title: Composer,
198
+ match: { file_exists: ['composer.json'] },
199
+ }
200
+ - {
201
+ fact: 'pm:nuget',
202
+ category: pm,
203
+ title: NuGet,
204
+ match: { any_file: ['*.csproj', '*.fsproj', 'packages.config'] },
205
+ }
206
+ - {
207
+ fact: 'pm:swiftpm',
208
+ category: pm,
209
+ title: 'SwiftPM',
210
+ match: { file_exists: ['Package.swift'] },
211
+ }
212
+ - { fact: 'pm:pub', category: pm, title: Pub, match: { file_exists: ['pubspec.yaml'] } }
213
+ - { fact: 'pm:mix', category: pm, title: Mix, match: { file_exists: ['mix.exs'] } }
214
+ - { fact: 'pm:foundry', category: pm, title: Foundry, match: { file_exists: ['foundry.toml'] } }
215
+ - { fact: 'pm:hardhat', category: pm, title: Hardhat, match: { any_file: ['hardhat.config.*'] } }
216
+
217
+ # --------------------------------------------------------------- web frontend
218
+ - {
219
+ fact: 'fw:react',
220
+ category: framework,
221
+ title: React,
222
+ match:
223
+ {
224
+ any_of:
225
+ [
226
+ { manifest: { file: 'package.json', key: 'dependencies.react' } },
227
+ { manifest: { file: 'package.json', key: 'devDependencies.react' } },
228
+ ],
229
+ },
230
+ }
231
+ - {
232
+ fact: 'fw:vue',
233
+ category: framework,
234
+ title: Vue,
235
+ match: { manifest: { file: 'package.json', key: 'dependencies.vue' } },
236
+ }
237
+ - {
238
+ fact: 'fw:angular',
239
+ category: framework,
240
+ title: Angular,
241
+ match:
242
+ {
243
+ any_of:
244
+ [
245
+ { manifest: { file: 'package.json', key: 'dependencies.@angular/core' } },
246
+ { file_exists: ['angular.json'] },
247
+ ],
248
+ },
249
+ }
250
+ - {
251
+ fact: 'fw:svelte',
252
+ category: framework,
253
+ title: Svelte,
254
+ match: { manifest: { file: 'package.json', key: 'dependencies.svelte' } },
255
+ }
256
+ - {
257
+ fact: 'fw:solid',
258
+ category: framework,
259
+ title: 'SolidJS',
260
+ match: { manifest: { file: 'package.json', key: 'dependencies.solid-js' } },
261
+ }
262
+ - {
263
+ fact: 'fw:next',
264
+ category: framework,
265
+ title: 'Next.js',
266
+ match:
267
+ {
268
+ any_of:
269
+ [
270
+ {
271
+ file_exists:
272
+ ['next.config.js', 'next.config.mjs', 'next.config.ts', 'next.config.cjs'],
273
+ },
274
+ { manifest: { file: 'package.json', key: 'dependencies.next' } },
275
+ ],
276
+ },
277
+ }
278
+ - {
279
+ fact: 'fw:nuxt',
280
+ category: framework,
281
+ title: Nuxt,
282
+ match:
283
+ {
284
+ any_of:
285
+ [
286
+ { file_exists: ['nuxt.config.ts', 'nuxt.config.js'] },
287
+ { manifest: { file: 'package.json', key: 'dependencies.nuxt' } },
288
+ ],
289
+ },
290
+ }
291
+ - {
292
+ fact: 'fw:remix',
293
+ category: framework,
294
+ title: Remix,
295
+ match: { manifest: { file: 'package.json', key: 'dependencies.@remix-run/node' } },
296
+ }
297
+ - {
298
+ fact: 'fw:sveltekit',
299
+ category: framework,
300
+ title: 'SvelteKit',
301
+ match:
302
+ {
303
+ any_of:
304
+ [
305
+ { file_exists: ['svelte.config.js'] },
306
+ { manifest: { file: 'package.json', key: 'dependencies.@sveltejs/kit' } },
307
+ ],
308
+ },
309
+ }
310
+ - {
311
+ fact: 'fw:astro',
312
+ category: framework,
313
+ title: Astro,
314
+ match: { manifest: { file: 'package.json', key: 'dependencies.astro' } },
315
+ }
316
+ - {
317
+ fact: 'fw:vite',
318
+ category: framework,
319
+ title: Vite,
320
+ match:
321
+ {
322
+ any_of:
323
+ [
324
+ { file_exists: ['vite.config.ts', 'vite.config.js', 'vite.config.mts'] },
325
+ { manifest: { file: 'package.json', key: 'devDependencies.vite' } },
326
+ ],
327
+ },
328
+ }
329
+ - {
330
+ fact: 'fw:tailwind',
331
+ category: framework,
332
+ title: Tailwind CSS,
333
+ match:
334
+ {
335
+ any_of:
336
+ [
337
+ { file_exists: ['tailwind.config.js', 'tailwind.config.ts'] },
338
+ { manifest: { file: 'package.json', key: 'devDependencies.tailwindcss' } },
339
+ ],
340
+ },
341
+ }
342
+ - {
343
+ fact: 'fw:electron',
344
+ category: framework,
345
+ title: Electron,
346
+ match: { manifest: { file: 'package.json', key: 'devDependencies.electron' } },
347
+ }
348
+ - {
349
+ fact: 'fw:tauri',
350
+ category: framework,
351
+ title: Tauri,
352
+ match:
353
+ {
354
+ any_of:
355
+ [
356
+ { dir_exists: ['src-tauri'] },
357
+ { manifest: { file: 'package.json', key: 'dependencies.@tauri-apps/api' } },
358
+ ],
359
+ },
360
+ }
361
+
362
+ # ---------------------------------------------------------------- node backend
363
+ - {
364
+ fact: 'fw:express',
365
+ category: framework,
366
+ title: Express,
367
+ match: { manifest: { file: 'package.json', key: 'dependencies.express' } },
368
+ }
369
+ - {
370
+ fact: 'fw:fastify',
371
+ category: framework,
372
+ title: Fastify,
373
+ match: { manifest: { file: 'package.json', key: 'dependencies.fastify' } },
374
+ }
375
+ - {
376
+ fact: 'fw:nest',
377
+ category: framework,
378
+ title: NestJS,
379
+ match: { manifest: { file: 'package.json', key: 'dependencies.@nestjs/core' } },
380
+ }
381
+ - {
382
+ fact: 'fw:hono',
383
+ category: framework,
384
+ title: Hono,
385
+ match: { manifest: { file: 'package.json', key: 'dependencies.hono' } },
386
+ }
387
+ - {
388
+ fact: 'fw:koa',
389
+ category: framework,
390
+ title: Koa,
391
+ match: { manifest: { file: 'package.json', key: 'dependencies.koa' } },
392
+ }
393
+
394
+ # --------------------------------------------------------------------- python
395
+ - {
396
+ fact: 'fw:django',
397
+ category: framework,
398
+ title: Django,
399
+ match:
400
+ {
401
+ any_of:
402
+ [
403
+ { file_exists: ['manage.py'] },
404
+ {
405
+ content:
406
+ { include: ['requirements*.txt', 'pyproject.toml'], pattern: '^django[=<>~]' },
407
+ },
408
+ ],
409
+ },
410
+ }
411
+ - {
412
+ fact: 'fw:flask',
413
+ category: framework,
414
+ title: Flask,
415
+ match:
416
+ { content: { include: ['requirements*.txt', 'pyproject.toml'], pattern: '^flask[=<>~]' } },
417
+ }
418
+ - {
419
+ fact: 'fw:fastapi',
420
+ category: framework,
421
+ title: FastAPI,
422
+ match:
423
+ {
424
+ content: { include: ['requirements*.txt', 'pyproject.toml'], pattern: '^fastapi[=<>~]' },
425
+ },
426
+ }
427
+ - {
428
+ fact: 'fw:celery',
429
+ category: framework,
430
+ title: Celery,
431
+ match:
432
+ { content: { include: ['requirements*.txt', 'pyproject.toml'], pattern: '^celery[=<>~]' } },
433
+ }
434
+ - {
435
+ fact: 'fw:airflow',
436
+ category: framework,
437
+ title: Airflow,
438
+ match:
439
+ {
440
+ content:
441
+ { include: ['requirements*.txt', 'pyproject.toml'], pattern: '^apache-airflow[=<>~]' },
442
+ },
443
+ }
444
+ - {
445
+ fact: 'fw:streamlit',
446
+ category: framework,
447
+ title: Streamlit,
448
+ match:
449
+ {
450
+ content:
451
+ { include: ['requirements*.txt', 'pyproject.toml'], pattern: '^streamlit[=<>~]' },
452
+ },
453
+ }
454
+
455
+ # ------------------------------------------------------------------------ go
456
+ - {
457
+ fact: 'fw:gin',
458
+ category: framework,
459
+ title: Gin,
460
+ match: { content: { include: ['go.mod'], pattern: 'gin-gonic/gin' } },
461
+ }
462
+ - {
463
+ fact: 'fw:echo',
464
+ category: framework,
465
+ title: Echo,
466
+ match: { content: { include: ['go.mod'], pattern: 'labstack/echo' } },
467
+ }
468
+ - {
469
+ fact: 'fw:fiber',
470
+ category: framework,
471
+ title: Fiber,
472
+ match: { content: { include: ['go.mod'], pattern: 'gofiber/fiber' } },
473
+ }
474
+ - {
475
+ fact: 'fw:chi',
476
+ category: framework,
477
+ title: Chi,
478
+ match: { content: { include: ['go.mod'], pattern: 'go-chi/chi' } },
479
+ }
480
+
481
+ # ---------------------------------------------------------------------- rust
482
+ - {
483
+ fact: 'fw:axum',
484
+ category: framework,
485
+ title: Axum,
486
+ match: { content: { include: ['Cargo.toml'], pattern: '^axum\\s*=' } },
487
+ }
488
+ - {
489
+ fact: 'fw:actix',
490
+ category: framework,
491
+ title: Actix,
492
+ match: { content: { include: ['Cargo.toml'], pattern: '^actix-web\\s*=' } },
493
+ }
494
+ - {
495
+ fact: 'fw:rocket',
496
+ category: framework,
497
+ title: Rocket,
498
+ match: { content: { include: ['Cargo.toml'], pattern: '^rocket\\s*=' } },
499
+ }
500
+
501
+ # ----------------------------------------------------------------- jvm / other
502
+ - {
503
+ fact: 'fw:spring',
504
+ category: framework,
505
+ title: Spring,
506
+ match:
507
+ {
508
+ any_of:
509
+ [
510
+ { content: { include: ['pom.xml', 'build.gradle*'], pattern: 'spring-boot' } },
511
+ { content: { include: ['**/*.java'], pattern: 'org\\.springframework' } },
512
+ ],
513
+ },
514
+ }
515
+ - {
516
+ fact: 'fw:quarkus',
517
+ category: framework,
518
+ title: Quarkus,
519
+ match: { content: { include: ['pom.xml', 'build.gradle*'], pattern: 'quarkus' } },
520
+ }
521
+ - {
522
+ fact: 'fw:rails',
523
+ category: framework,
524
+ title: Rails,
525
+ match:
526
+ {
527
+ any_of:
528
+ [
529
+ { file_exists: ['config/application.rb'] },
530
+ { content: { include: ['Gemfile'], pattern: 'gem [''"]rails[''"]' } },
531
+ ],
532
+ },
533
+ }
534
+ - {
535
+ fact: 'fw:laravel',
536
+ category: framework,
537
+ title: Laravel,
538
+ match:
539
+ {
540
+ any_of:
541
+ [
542
+ { file_exists: ['artisan'] },
543
+ { content: { include: ['composer.json'], pattern: 'laravel/framework' } },
544
+ ],
545
+ },
546
+ }
547
+ - {
548
+ fact: 'fw:symfony',
549
+ category: framework,
550
+ title: Symfony,
551
+ match: { content: { include: ['composer.json'], pattern: 'symfony/framework-bundle' } },
552
+ }
553
+ - {
554
+ fact: 'fw:dotnet',
555
+ category: framework,
556
+ title: '.NET / ASP.NET',
557
+ match: { content: { include: ['**/*.csproj'], pattern: 'Microsoft\\.(NET|AspNetCore)' } },
558
+ }
559
+
560
+ # --------------------------------------------------------------------- mobile
561
+ - {
562
+ fact: 'fw:react-native',
563
+ category: framework,
564
+ title: 'React Native',
565
+ match:
566
+ {
567
+ any_of:
568
+ [
569
+ { manifest: { file: 'package.json', key: 'dependencies.react-native' } },
570
+ { file_exists: ['app.json'] },
571
+ ],
572
+ },
573
+ }
574
+ - {
575
+ fact: 'fw:expo',
576
+ category: framework,
577
+ title: Expo,
578
+ match:
579
+ {
580
+ any_of:
581
+ [
582
+ { manifest: { file: 'package.json', key: 'dependencies.expo' } },
583
+ { file_exists: ['app.config.js', 'app.config.ts', 'expo.json'] },
584
+ ],
585
+ },
586
+ }
587
+ - {
588
+ fact: 'fw:flutter',
589
+ category: framework,
590
+ title: Flutter,
591
+ match: { any_of: [{ file_exists: ['pubspec.yaml'] }, { any_file: ['**/*.dart'] }] },
592
+ }
593
+ - {
594
+ fact: 'platform:ios',
595
+ category: platform,
596
+ title: iOS,
597
+ match:
598
+ {
599
+ any_of:
600
+ [
601
+ { dir_exists: ['ios', '*.xcodeproj'] },
602
+ { any_file: ['**/*.xcworkspace/**', '**/Info.plist', '**/*.pbxproj'] },
603
+ ],
604
+ },
605
+ }
606
+ - {
607
+ fact: 'platform:android',
608
+ category: platform,
609
+ title: Android,
610
+ match:
611
+ {
612
+ any_of:
613
+ [{ dir_exists: ['android'] }, { any_file: ['**/AndroidManifest.xml', '**/*.gradle'] }],
614
+ },
615
+ }
616
+ - { fact: 'platform:mobile', category: platform, title: Mobile, implies: ['platform:ios'] }
617
+ - { fact: 'platform:mobile', category: platform, title: Mobile, implies: ['platform:android'] }
618
+ - { fact: 'platform:mobile', category: platform, title: Mobile, implies: ['fw:react-native'] }
619
+ - { fact: 'platform:mobile', category: platform, title: Mobile, implies: ['fw:flutter'] }
620
+ - { fact: 'platform:mobile', category: platform, title: Mobile, implies: ['fw:expo'] }
621
+
622
+ # ------------------------------------------------------------------- platform
623
+ - {
624
+ fact: 'platform:web',
625
+ category: platform,
626
+ title: Web,
627
+ match:
628
+ {
629
+ any_of:
630
+ [
631
+ { any_file: ['**/*.html', '**/*.jsx', '**/*.tsx', '**/*.vue', '**/*.svelte'] },
632
+ { manifest: { file: 'package.json', key: 'dependencies.react' } },
633
+ { manifest: { file: 'package.json', key: 'dependencies.vue' } },
634
+ ],
635
+ },
636
+ }
637
+ - {
638
+ fact: 'platform:server',
639
+ category: platform,
640
+ title: Server,
641
+ match:
642
+ {
643
+ any_of:
644
+ [
645
+ {
646
+ file_exists:
647
+ ['Dockerfile', 'Procfile', 'fly.toml', 'vercel.json', 'serverless.yml'],
648
+ },
649
+ { dir_exists: ['server', 'api', 'backend'] },
650
+ ],
651
+ },
652
+ }
653
+ - { fact: 'platform:desktop', category: platform, title: Desktop, implies: ['fw:electron'] }
654
+ - { fact: 'platform:desktop', category: platform, title: Desktop, implies: ['fw:tauri'] }
655
+ # A request-serving framework IS a server, with or without a Dockerfile:
656
+ # without these, a bare Express/FastAPI/Rails app skipped every
657
+ # platform-gated rule (SEC-003 et al.) for lack of platform:server.
658
+ # Deliberately request handlers only — task queues (celery, airflow),
659
+ # static builders (astro, vite), and desktop/mobile packs imply nothing.
660
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:express'] }
661
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:fastify'] }
662
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:nest'] }
663
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:hono'] }
664
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:koa'] }
665
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:django'] }
666
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:flask'] }
667
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:fastapi'] }
668
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:gin'] }
669
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:echo'] }
670
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:fiber'] }
671
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:chi'] }
672
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:axum'] }
673
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:actix'] }
674
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:rocket'] }
675
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:spring'] }
676
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:quarkus'] }
677
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:rails'] }
678
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:laravel'] }
679
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:symfony'] }
680
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:next'] }
681
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:nuxt'] }
682
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:remix'] }
683
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:sveltekit'] }
684
+ # Swift ecosystem, graduated from the bootstrap proof on vapor/vapor:
685
+ # framework identity, executable-vs-library shape (Package.resolved is
686
+ # only meaningful for apps), and the platform consequence. See ADR-0012.
687
+ - fact: 'fw:vapor'
688
+ category: framework
689
+ title: Vapor
690
+ match: { content: { include: ['Package.swift'], pattern: '[Vv]apor' } }
691
+ - fact: 'has:swift-validation'
692
+ category: has
693
+ title: 'Swift validation (Validatable)'
694
+ match: { content: { include: ['**/*.swift'], pattern: 'Validatable' } }
695
+ - fact: 'has:swift-security-headers'
696
+ category: has
697
+ title: 'Swift security headers middleware'
698
+ match:
699
+ { content: { include: ['**/*.swift'], pattern: 'SecurityHeadersMiddleware|CORSMiddleware' } }
700
+ - fact: 'swift:executable'
701
+ category: type
702
+ title: Swift executable target
703
+ match: { content: { include: ['Package.swift'], pattern: 'executableTarget' } }
704
+ - { fact: 'platform:server', category: platform, title: Server, implies: ['fw:vapor'] }
705
+ - {
706
+ fact: 'platform:evm',
707
+ category: platform,
708
+ title: 'EVM / Blockchain',
709
+ match:
710
+ {
711
+ any_of:
712
+ [
713
+ { any_file: ['**/*.sol', '**/*.vy'] },
714
+ {
715
+ file_exists:
716
+ ['foundry.toml', 'hardhat.config.js', 'hardhat.config.ts', 'truffle-config.js'],
717
+ },
718
+ ],
719
+ },
720
+ }
721
+ - {
722
+ fact: 'platform:embedded',
723
+ category: platform,
724
+ title: Embedded,
725
+ match:
726
+ { any_of: [{ any_file: ['**/*.ino', '**/*.hex'] }, { file_exists: ['platformio.ini'] }] },
727
+ }
728
+
729
+ # ---------------------------------------------------------------------- types
730
+ - {
731
+ fact: 'project:library',
732
+ category: type,
733
+ title: 'Library / SDK',
734
+ match:
735
+ {
736
+ any_of:
737
+ [
738
+ { manifest: { file: 'package.json', key: 'main' } },
739
+ { manifest: { file: 'package.json', key: 'exports' } },
740
+ { manifest: { file: 'pyproject.toml', key: 'project.name' } },
741
+ { file_exists: ['setup.py', 'setup.cfg'] },
742
+ ],
743
+ },
744
+ }
745
+ - {
746
+ fact: 'project:cli',
747
+ category: type,
748
+ title: 'CLI tool',
749
+ match:
750
+ {
751
+ any_of:
752
+ [
753
+ { manifest: { file: 'package.json', key: 'bin' } },
754
+ { content: { include: ['pyproject.toml'], pattern: '\\[project\\.scripts\\]' } },
755
+ { dir_exists: ['cmd'] },
756
+ ],
757
+ },
758
+ }
759
+ - {
760
+ fact: 'project:monorepo',
761
+ category: type,
762
+ title: Monorepo,
763
+ match:
764
+ {
765
+ any_of:
766
+ [
767
+ { file_exists: ['pnpm-workspace.yaml', 'turbo.json', 'nx.json', 'lerna.json'] },
768
+ { content: { include: ['package.json'], pattern: '"workspaces"\\s*:' } },
769
+ { dir_exists: ['packages', 'apps'] },
770
+ ],
771
+ },
772
+ }
773
+ - {
774
+ fact: 'project:api',
775
+ category: type,
776
+ title: 'API / service',
777
+ match:
778
+ {
779
+ any_of:
780
+ [
781
+ {
782
+ any_file: ['**/openapi.yaml', '**/openapi.json', '**/swagger.json', '**/*.graphql'],
783
+ },
784
+ { dir_exists: ['api', 'routes', 'handlers', 'controllers'] },
785
+ ],
786
+ },
787
+ }
788
+ - {
789
+ fact: 'project:ml',
790
+ category: type,
791
+ title: 'ML / AI system',
792
+ match:
793
+ {
794
+ any_of:
795
+ [
796
+ {
797
+ content:
798
+ {
799
+ include: ['requirements*.txt', 'pyproject.toml', 'environment.yml'],
800
+ pattern: '^(torch|tensorflow|scikit-learn|transformers|jax|keras|pandas|numpy)[=<>~]',
801
+ },
802
+ },
803
+ { dir_exists: ['notebooks', 'models', 'checkpoints'] },
804
+ { any_file: ['**/*.ipynb'] },
805
+ ],
806
+ },
807
+ }
808
+ - {
809
+ fact: 'project:blockchain',
810
+ category: type,
811
+ title: 'Smart contracts',
812
+ implies: ['platform:evm'],
813
+ }
814
+ - {
815
+ fact: 'project:iac',
816
+ category: type,
817
+ title: 'IaC / DevOps tooling',
818
+ match:
819
+ {
820
+ any_of:
821
+ [
822
+ { any_file: ['**/*.tf'] },
823
+ {
824
+ dir_exists: ['terraform', 'infra', 'infrastructure', 'charts', 'manifests', 'k8s'],
825
+ },
826
+ ],
827
+ },
828
+ }
829
+ - {
830
+ fact: 'project:data-pipeline',
831
+ category: type,
832
+ title: 'Data pipeline / ETL',
833
+ match:
834
+ {
835
+ any_of:
836
+ [
837
+ { dir_exists: ['dags', 'pipelines', 'etl'] },
838
+ {
839
+ content:
840
+ {
841
+ include: ['requirements*.txt', 'pyproject.toml'],
842
+ pattern: '^(apache-airflow|dagster|prefect|luigi|dbt-core)[=<>~]',
843
+ },
844
+ },
845
+ ],
846
+ },
847
+ }
848
+ - {
849
+ fact: 'project:game',
850
+ category: type,
851
+ title: Game,
852
+ match:
853
+ {
854
+ any_of:
855
+ [
856
+ { any_file: ['**/*.unity', '**/*.godot', '**/*.tscn'] },
857
+ {
858
+ content:
859
+ {
860
+ include: ['package.json'],
861
+ pattern: '"(phaser|three|babylonjs|pixi\\.js)"\\s*:',
862
+ },
863
+ },
864
+ ],
865
+ },
866
+ }
867
+ - {
868
+ fact: 'project:docs',
869
+ category: type,
870
+ title: 'Docs site',
871
+ match:
872
+ {
873
+ any_of:
874
+ [
875
+ { file_exists: ['docusaurus.config.js', 'mkdocs.yml', 'book.toml'] },
876
+ { dir_exists: ['docs'] },
877
+ ],
878
+ },
879
+ }
880
+
881
+ # ----------------------------------------------------------------- databases
882
+ - {
883
+ fact: 'db:postgres',
884
+ category: db,
885
+ title: PostgreSQL,
886
+ match:
887
+ {
888
+ any_of:
889
+ [
890
+ {
891
+ content:
892
+ {
893
+ include: ['**/*.{env,example,yml,yaml,toml,json,ts,js,py,go,rs}'],
894
+ pattern: 'postgres(ql)?://',
895
+ },
896
+ },
897
+ {
898
+ content:
899
+ {
900
+ include:
901
+ [
902
+ 'requirements*.txt',
903
+ 'pyproject.toml',
904
+ 'package.json',
905
+ 'go.mod',
906
+ 'Cargo.toml',
907
+ ],
908
+ pattern: '(psycopg|pg|postgres|postgresql)',
909
+ },
910
+ },
911
+ ],
912
+ },
913
+ }
914
+ - {
915
+ fact: 'db:mysql',
916
+ category: db,
917
+ title: MySQL/MariaDB,
918
+ match:
919
+ {
920
+ any_of:
921
+ [
922
+ {
923
+ content:
924
+ {
925
+ include: ['**/*.{env,example,yml,yaml,toml,json,ts,js,py,go}'],
926
+ pattern: 'mysql://',
927
+ },
928
+ },
929
+ {
930
+ content:
931
+ {
932
+ include: ['requirements*.txt', 'package.json', 'go.mod'],
933
+ pattern: '(mysql2?|pymysql|mariadb)',
934
+ },
935
+ },
936
+ ],
937
+ },
938
+ }
939
+ - {
940
+ fact: 'db:sqlite',
941
+ category: db,
942
+ title: SQLite,
943
+ match:
944
+ {
945
+ any_of:
946
+ [
947
+ { any_file: ['**/*.sqlite', '**/*.sqlite3', '**/*.db'] },
948
+ {
949
+ content:
950
+ {
951
+ include: ['requirements*.txt', 'package.json', 'go.mod', 'Cargo.toml'],
952
+ pattern: '(sqlite3|better-sqlite3|sqlx.*sqlite)',
953
+ },
954
+ },
955
+ ],
956
+ },
957
+ }
958
+ - {
959
+ fact: 'db:mongodb',
960
+ category: db,
961
+ title: MongoDB,
962
+ match:
963
+ {
964
+ any_of:
965
+ [
966
+ {
967
+ content:
968
+ {
969
+ include: ['**/*.{env,example,yml,yaml,ts,js,py}'],
970
+ pattern: 'mongodb(\\+srv)?://',
971
+ },
972
+ },
973
+ {
974
+ content:
975
+ {
976
+ include: ['package.json', 'requirements*.txt', 'go.mod'],
977
+ pattern: '(mongoose|pymongo|mongo-driver)',
978
+ },
979
+ },
980
+ ],
981
+ },
982
+ }
983
+ - {
984
+ fact: 'db:redis',
985
+ category: db,
986
+ title: Redis,
987
+ match:
988
+ {
989
+ any_of:
990
+ [
991
+ {
992
+ content:
993
+ { include: ['**/*.{env,example,yml,yaml,ts,js,py,go}'], pattern: 'redis://' },
994
+ },
995
+ {
996
+ content:
997
+ {
998
+ include: ['package.json', 'requirements*.txt', 'go.mod'],
999
+ pattern: '(^|")(ioredis|redis|go-redis)',
1000
+ },
1001
+ },
1002
+ ],
1003
+ },
1004
+ }
1005
+ - {
1006
+ fact: 'db:clickhouse',
1007
+ category: db,
1008
+ title: ClickHouse,
1009
+ match: { content: { include: ['**/*.{env,example,yml,yaml,py,go}'], pattern: 'clickhouse' } },
1010
+ }
1011
+ - {
1012
+ fact: 'db:elasticsearch',
1013
+ category: db,
1014
+ title: Elasticsearch,
1015
+ match:
1016
+ {
1017
+ content:
1018
+ {
1019
+ include: ['**/*.{env,example,yml,yaml,py,go,ts,js}'],
1020
+ pattern: '(elasticsearch|opensearch)',
1021
+ },
1022
+ },
1023
+ }
1024
+ - {
1025
+ fact: 'db:vector',
1026
+ category: db,
1027
+ title: 'Vector store',
1028
+ match:
1029
+ {
1030
+ content:
1031
+ {
1032
+ include: ['package.json', 'requirements*.txt', 'pyproject.toml', 'go.mod'],
1033
+ pattern: '(pgvector|pinecone|weaviate|qdrant|chromadb|milvus|faiss|lancedb)',
1034
+ },
1035
+ },
1036
+ }
1037
+ - {
1038
+ fact: 'db:dynamodb',
1039
+ category: db,
1040
+ title: DynamoDB,
1041
+ match: { content: { include: ['**/*.{ts,js,py,go,yml,yaml,json}'], pattern: 'dynamodb' } },
1042
+ }
1043
+ - {
1044
+ fact: 'has:database',
1045
+ category: db,
1046
+ title: 'Uses a database',
1047
+ match:
1048
+ {
1049
+ any_of:
1050
+ [{ dir_exists: ['migrations', 'prisma', 'db', 'models'] }, { any_file: ['**/*.sql'] }],
1051
+ },
1052
+ }
1053
+
1054
+ - {
1055
+ fact: 'orm:prisma',
1056
+ category: orm,
1057
+ title: Prisma,
1058
+ match:
1059
+ {
1060
+ any_of:
1061
+ [
1062
+ { dir_exists: ['prisma'] },
1063
+ { manifest: { file: 'package.json', key: 'dependencies.@prisma/client' } },
1064
+ ],
1065
+ },
1066
+ }
1067
+ - {
1068
+ fact: 'orm:drizzle',
1069
+ category: orm,
1070
+ title: Drizzle,
1071
+ match: { manifest: { file: 'package.json', key: 'dependencies.drizzle-orm' } },
1072
+ }
1073
+ - {
1074
+ fact: 'orm:typeorm',
1075
+ category: orm,
1076
+ title: TypeORM,
1077
+ match: { manifest: { file: 'package.json', key: 'dependencies.typeorm' } },
1078
+ }
1079
+ - {
1080
+ fact: 'orm:sequelize',
1081
+ category: orm,
1082
+ title: Sequelize,
1083
+ match: { manifest: { file: 'package.json', key: 'dependencies.sequelize' } },
1084
+ }
1085
+ - {
1086
+ fact: 'orm:mongoose',
1087
+ category: orm,
1088
+ title: Mongoose,
1089
+ match: { manifest: { file: 'package.json', key: 'dependencies.mongoose' } },
1090
+ }
1091
+ - {
1092
+ fact: 'orm:sqlalchemy',
1093
+ category: orm,
1094
+ title: SQLAlchemy,
1095
+ match:
1096
+ {
1097
+ content:
1098
+ { include: ['requirements*.txt', 'pyproject.toml'], pattern: '^sqlalchemy[=<>~]' },
1099
+ },
1100
+ }
1101
+ - {
1102
+ fact: 'orm:gorm',
1103
+ category: orm,
1104
+ title: GORM,
1105
+ match: { content: { include: ['go.mod'], pattern: 'gorm\\.io/gorm' } },
1106
+ }
1107
+ - {
1108
+ fact: 'orm:sqlx',
1109
+ category: orm,
1110
+ title: SQLx,
1111
+ match: { content: { include: ['Cargo.toml'], pattern: '^sqlx\\s*=' } },
1112
+ }
1113
+ - {
1114
+ fact: 'orm:diesel',
1115
+ category: orm,
1116
+ title: Diesel,
1117
+ match: { content: { include: ['Cargo.toml'], pattern: '^diesel\\s*=' } },
1118
+ }
1119
+ - {
1120
+ fact: 'orm:hibernate',
1121
+ category: orm,
1122
+ title: Hibernate/JPA,
1123
+ match:
1124
+ {
1125
+ content: { include: ['**/*.java'], pattern: 'javax\\.persistence|jakarta\\.persistence' },
1126
+ },
1127
+ }
1128
+ - {
1129
+ fact: 'orm:activerecord',
1130
+ category: orm,
1131
+ title: ActiveRecord,
1132
+ match: { content: { include: ['**/*.rb'], pattern: 'ApplicationRecord' } },
1133
+ }
1134
+
1135
+ # ------------------------------------------------------------------- auth
1136
+ - {
1137
+ fact: 'auth:jwt',
1138
+ category: auth,
1139
+ title: JWT,
1140
+ match:
1141
+ {
1142
+ any_of:
1143
+ [
1144
+ {
1145
+ content:
1146
+ {
1147
+ include: ['**/*.{ts,js,py,go,rs,java,kt}'],
1148
+ pattern: 'jsonwebtoken|jose|PyJWT|golang-jwt|json_web_token',
1149
+ },
1150
+ },
1151
+ { content: { include: ['**/*.{ts,js,py,go,rs}'], pattern: 'Bearer\\s' } },
1152
+ ],
1153
+ },
1154
+ }
1155
+ - {
1156
+ fact: 'auth:oauth',
1157
+ category: auth,
1158
+ title: OAuth / OIDC,
1159
+ match:
1160
+ {
1161
+ content:
1162
+ {
1163
+ include: ['**/*.{ts,js,py,go,rs,java,yaml,yml,json}'],
1164
+ pattern: 'oauth2?|openid|oidc',
1165
+ },
1166
+ },
1167
+ }
1168
+ - {
1169
+ fact: 'auth:session',
1170
+ category: auth,
1171
+ title: Sessions / cookies,
1172
+ match:
1173
+ {
1174
+ content:
1175
+ {
1176
+ include: ['**/*.{ts,js,py,go,rs}'],
1177
+ pattern: 'express-session|cookie-session|sessionMiddleware|SESSION_SECRET',
1178
+ },
1179
+ },
1180
+ }
1181
+ - {
1182
+ fact: 'auth:apikey',
1183
+ category: auth,
1184
+ title: 'API keys',
1185
+ match:
1186
+ {
1187
+ content:
1188
+ { include: ['**/*.{ts,js,py,go,rs,env,example}'], pattern: 'API_KEY|X-API-Key|apiKey' },
1189
+ },
1190
+ }
1191
+ - {
1192
+ fact: 'auth:passport',
1193
+ category: auth,
1194
+ title: Passport.js,
1195
+ match: { manifest: { file: 'package.json', key: 'dependencies.passport' } },
1196
+ }
1197
+ - {
1198
+ fact: 'auth:nextauth',
1199
+ category: auth,
1200
+ title: Auth.js / NextAuth,
1201
+ match:
1202
+ {
1203
+ any_of:
1204
+ [
1205
+ { manifest: { file: 'package.json', key: 'dependencies.next-auth' } },
1206
+ { manifest: { file: 'package.json', key: 'dependencies.@auth/core' } },
1207
+ ],
1208
+ },
1209
+ }
1210
+ - {
1211
+ fact: 'auth:supabase',
1212
+ category: auth,
1213
+ title: Supabase,
1214
+ match: { manifest: { file: 'package.json', key: 'dependencies.@supabase/supabase-js' } },
1215
+ }
1216
+ - {
1217
+ fact: 'auth:firebase',
1218
+ category: auth,
1219
+ title: Firebase Auth,
1220
+ match:
1221
+ {
1222
+ content:
1223
+ {
1224
+ include: ['package.json', '**/*.{ts,js,py}'],
1225
+ pattern: 'firebase/auth|firebase-admin',
1226
+ },
1227
+ },
1228
+ }
1229
+ - {
1230
+ fact: 'auth:auth0',
1231
+ category: auth,
1232
+ title: Auth0,
1233
+ match: { content: { include: ['**/*.{ts,js,py,go,json,yml,yaml}'], pattern: 'auth0' } },
1234
+ }
1235
+
1236
+ # ----------------------------------------------------------------- api style
1237
+ - {
1238
+ fact: 'api:graphql',
1239
+ category: api,
1240
+ title: GraphQL,
1241
+ match:
1242
+ {
1243
+ any_of:
1244
+ [
1245
+ { any_file: ['**/*.graphql', '**/*.gql'] },
1246
+ {
1247
+ content:
1248
+ {
1249
+ include: ['package.json'],
1250
+ pattern: '"(graphql|apollo-server|@apollo/server)"\\s*:',
1251
+ },
1252
+ },
1253
+ ],
1254
+ },
1255
+ }
1256
+ - {
1257
+ fact: 'api:grpc',
1258
+ category: api,
1259
+ title: gRPC,
1260
+ match:
1261
+ {
1262
+ any_of:
1263
+ [
1264
+ { any_file: ['**/*.proto'] },
1265
+ {
1266
+ content:
1267
+ {
1268
+ include: ['package.json', 'go.mod', 'Cargo.toml', 'requirements*.txt'],
1269
+ pattern: '(grpc|tonic)',
1270
+ },
1271
+ },
1272
+ ],
1273
+ },
1274
+ }
1275
+ - {
1276
+ fact: 'api:trpc',
1277
+ category: api,
1278
+ title: tRPC,
1279
+ match: { manifest: { file: 'package.json', key: 'dependencies.@trpc/server' } },
1280
+ }
1281
+ - {
1282
+ fact: 'api:websocket',
1283
+ category: api,
1284
+ title: WebSockets,
1285
+ match:
1286
+ {
1287
+ content:
1288
+ {
1289
+ include: ['package.json', '**/*.{ts,js,py,go}'],
1290
+ pattern: '(socket\\.io|\\bws\\b|websocket)',
1291
+ },
1292
+ },
1293
+ }
1294
+
1295
+ # ------------------------------------------------------------------- testing
1296
+ - {
1297
+ fact: 'test:vitest',
1298
+ category: test,
1299
+ title: Vitest,
1300
+ match: { manifest: { file: 'package.json', key: 'devDependencies.vitest' } },
1301
+ }
1302
+ - {
1303
+ fact: 'test:jest',
1304
+ category: test,
1305
+ title: Jest,
1306
+ match: { manifest: { file: 'package.json', key: 'devDependencies.jest' } },
1307
+ }
1308
+ - {
1309
+ fact: 'test:mocha',
1310
+ category: test,
1311
+ title: Mocha,
1312
+ match: { manifest: { file: 'package.json', key: 'devDependencies.mocha' } },
1313
+ }
1314
+ - {
1315
+ fact: 'test:pytest',
1316
+ category: test,
1317
+ title: pytest,
1318
+ match:
1319
+ {
1320
+ any_of:
1321
+ [
1322
+ {
1323
+ content:
1324
+ { include: ['pyproject.toml', 'requirements*.txt'], pattern: '^pytest[=<>~]' },
1325
+ },
1326
+ { any_file: ['**/test_*.py', '**/*_test.py'] },
1327
+ ],
1328
+ },
1329
+ }
1330
+ - { fact: 'test:gotest', category: test, title: 'go test', match: { any_file: ['**/*_test.go'] } }
1331
+ - {
1332
+ fact: 'test:cargotest',
1333
+ category: test,
1334
+ title: 'cargo test',
1335
+ match:
1336
+ {
1337
+ any_of:
1338
+ [
1339
+ { any_file: ['**/*.rs'] },
1340
+ { content: { include: ['**/*.rs'], pattern: '#\\[test\\]' } },
1341
+ ],
1342
+ },
1343
+ }
1344
+ - {
1345
+ fact: 'test:junit',
1346
+ category: test,
1347
+ title: JUnit,
1348
+ match:
1349
+ {
1350
+ any_of:
1351
+ [
1352
+ { content: { include: ['**/*.java'], pattern: 'org\\.junit' } },
1353
+ { content: { include: ['**/*.kt'], pattern: 'org\\.junit|io\\.kotest' } },
1354
+ ],
1355
+ },
1356
+ }
1357
+ - {
1358
+ fact: 'test:rspec',
1359
+ category: test,
1360
+ title: RSpec,
1361
+ match:
1362
+ {
1363
+ any_of:
1364
+ [
1365
+ { any_file: ['**/*_spec.rb'] },
1366
+ { content: { include: ['Gemfile'], pattern: 'gem [''"]rspec' } },
1367
+ ],
1368
+ },
1369
+ }
1370
+ - {
1371
+ fact: 'test:phpunit',
1372
+ category: test,
1373
+ title: PHPUnit,
1374
+ match: { content: { include: ['**/*.php'], pattern: 'PHPUnit' } },
1375
+ }
1376
+ - {
1377
+ fact: 'test:playwright',
1378
+ category: test,
1379
+ title: Playwright,
1380
+ match: { manifest: { file: 'package.json', key: 'devDependencies.@playwright/test' } },
1381
+ }
1382
+ - {
1383
+ fact: 'test:cypress',
1384
+ category: test,
1385
+ title: Cypress,
1386
+ match: { manifest: { file: 'package.json', key: 'devDependencies.cypress' } },
1387
+ }
1388
+ - {
1389
+ fact: 'has:tests',
1390
+ category: test,
1391
+ title: 'Has tests',
1392
+ match:
1393
+ {
1394
+ any_of:
1395
+ [
1396
+ {
1397
+ any_file:
1398
+ [
1399
+ '**/*.test.ts',
1400
+ '**/*.test.js',
1401
+ '**/*.test.tsx',
1402
+ '**/*.test.jsx',
1403
+ '**/*.spec.ts',
1404
+ '**/*.spec.js',
1405
+ '**/test_*.py',
1406
+ '**/*_test.py',
1407
+ '**/*_test.go',
1408
+ '**/*_spec.rb',
1409
+ '**/*Test.java',
1410
+ '**/*Test.kt',
1411
+ ],
1412
+ },
1413
+ { dir_exists: ['tests', 'test', '__tests__', 'spec'] },
1414
+ ],
1415
+ },
1416
+ }
1417
+ - {
1418
+ fact: 'has:e2e',
1419
+ category: test,
1420
+ title: 'Has E2E tests',
1421
+ match:
1422
+ {
1423
+ any_of:
1424
+ [
1425
+ { dir_exists: ['e2e', 'cypress', 'playwright'] },
1426
+ { any_file: ['**/*.e2e.*', '**/*.cy.*', '**/*.spec.ts', '**/*.spec.js'] },
1427
+ ],
1428
+ },
1429
+ }
1430
+ - {
1431
+ fact: 'has:perf-tests',
1432
+ category: test,
1433
+ title: 'Has performance tests',
1434
+ match:
1435
+ {
1436
+ any_of:
1437
+ [
1438
+ { any_file: ['**/*.perf.*', '**/*.bench.*', '**/*.load.*', '**/k6/**'] },
1439
+ { dir_exists: ['benchmarks', 'perf', 'load-tests'] },
1440
+ ],
1441
+ },
1442
+ }
1443
+
1444
+ # ----------------------------------------------------------------- tooling
1445
+ - {
1446
+ fact: 'has:lint',
1447
+ category: tooling,
1448
+ title: Linter configured,
1449
+ match:
1450
+ {
1451
+ any_of:
1452
+ [
1453
+ {
1454
+ any_file:
1455
+ [
1456
+ '**/.eslintrc*',
1457
+ 'eslint.config.*',
1458
+ '.ruff.toml',
1459
+ '.flake8',
1460
+ '.pylintrc',
1461
+ 'clippy.toml',
1462
+ '.golangci*',
1463
+ ],
1464
+ },
1465
+ {
1466
+ content:
1467
+ {
1468
+ include: ['package.json', 'pyproject.toml'],
1469
+ pattern: '"(eslint|ruff|biome)"\\s*:|^\\[tool\\.(ruff|pylint)\\]',
1470
+ },
1471
+ },
1472
+ ],
1473
+ },
1474
+ }
1475
+ - {
1476
+ fact: 'has:format',
1477
+ category: tooling,
1478
+ title: Formatter configured,
1479
+ match:
1480
+ {
1481
+ any_of:
1482
+ [
1483
+ {
1484
+ any_file:
1485
+ [
1486
+ '.prettierrc*',
1487
+ 'prettier.config.*',
1488
+ '.rustfmt.toml',
1489
+ 'rustfmt.toml',
1490
+ '.clang-format',
1491
+ ],
1492
+ },
1493
+ {
1494
+ content:
1495
+ {
1496
+ include: ['package.json', 'pyproject.toml'],
1497
+ pattern: '"prettier"\\s*:|^\\[tool\\.black\\]',
1498
+ },
1499
+ },
1500
+ ],
1501
+ },
1502
+ }
1503
+ - {
1504
+ fact: 'has:typecheck',
1505
+ category: tooling,
1506
+ title: Type checking,
1507
+ match:
1508
+ {
1509
+ any_of:
1510
+ [
1511
+ { file_exists: ['tsconfig.json'] },
1512
+ { content: { include: ['package.json'], pattern: '"typescript"\\s*:' } },
1513
+ { content: { include: ['pyproject.toml'], pattern: '^\\[tool\\.mypy\\]' } },
1514
+ ],
1515
+ },
1516
+ }
1517
+ - {
1518
+ fact: 'has:precommit',
1519
+ category: tooling,
1520
+ title: Pre-commit hooks,
1521
+ match:
1522
+ {
1523
+ any_of:
1524
+ [
1525
+ { file_exists: ['.pre-commit-config.yaml', '.husky/pre-commit', 'lefthook.yml'] },
1526
+ { manifest: { file: 'package.json', key: 'devDependencies.husky' } },
1527
+ ],
1528
+ },
1529
+ }
1530
+ - {
1531
+ fact: 'has:dependabot',
1532
+ category: tooling,
1533
+ title: Dependabot,
1534
+ match: { file_exists: ['.github/dependabot.yml'] },
1535
+ }
1536
+ - {
1537
+ fact: 'has:renovate',
1538
+ category: tooling,
1539
+ title: Renovate,
1540
+ match: { any_file: ['renovate.json*', '.github/renovate.json*', '.renovaterc*'] },
1541
+ }
1542
+ - {
1543
+ fact: 'has:changesets',
1544
+ category: tooling,
1545
+ title: Changesets,
1546
+ match: { dir_exists: ['.changeset'] },
1547
+ }
1548
+ - {
1549
+ fact: 'has:release-automation',
1550
+ category: tooling,
1551
+ title: Release automation,
1552
+ match:
1553
+ {
1554
+ any_of:
1555
+ [
1556
+ { dir_exists: ['.changeset'] },
1557
+ {
1558
+ content:
1559
+ {
1560
+ include: ['package.json', '.github/workflows/*.yml'],
1561
+ pattern: 'semantic-release',
1562
+ },
1563
+ },
1564
+ ],
1565
+ },
1566
+ }
1567
+ - {
1568
+ fact: 'has:editorconfig',
1569
+ category: tooling,
1570
+ title: EditorConfig,
1571
+ match: { file_exists: ['.editorconfig'] },
1572
+ }
1573
+ - {
1574
+ fact: 'has:containers',
1575
+ category: tooling,
1576
+ title: Containers,
1577
+ match:
1578
+ {
1579
+ any_of:
1580
+ [
1581
+ {
1582
+ any_file:
1583
+ ['Dockerfile*', 'docker-compose*.yml', 'docker-compose*.yaml', 'compose.yaml'],
1584
+ },
1585
+ { dir_exists: ['.devcontainer'] },
1586
+ ],
1587
+ },
1588
+ }
1589
+ - {
1590
+ fact: 'has:kubernetes',
1591
+ category: tooling,
1592
+ title: Kubernetes,
1593
+ match:
1594
+ {
1595
+ any_of:
1596
+ [
1597
+ {
1598
+ content:
1599
+ {
1600
+ include: ['**/*.yaml', '**/*.yml'],
1601
+ pattern: 'kind:\\s*(Deployment|Service|StatefulSet|CronJob)',
1602
+ },
1603
+ },
1604
+ { dir_exists: ['k8s', 'kube', 'manifests', 'charts'] },
1605
+ ],
1606
+ },
1607
+ }
1608
+ - {
1609
+ fact: 'has:terraform',
1610
+ category: tooling,
1611
+ title: Terraform/OpenTofu,
1612
+ match: { any_file: ['**/*.tf'] },
1613
+ }
1614
+ - {
1615
+ fact: 'has:serverless',
1616
+ category: tooling,
1617
+ title: Serverless,
1618
+ match:
1619
+ {
1620
+ any_file: ['serverless.yml', 'serverless.ts', 'vercel.json', 'netlify.toml', 'fly.toml'],
1621
+ },
1622
+ }
1623
+ - {
1624
+ fact: 'has:sbom',
1625
+ category: tooling,
1626
+ title: SBOM published,
1627
+ match:
1628
+ { any_file: ['**/sbom.*', '**/*sbom*.json', '**/*sbom*.xml', '.github/workflows/*sbom*'] },
1629
+ }
1630
+ - {
1631
+ fact: 'has:secrets-scan',
1632
+ category: tooling,
1633
+ title: Secret scanning in CI,
1634
+ match:
1635
+ {
1636
+ any_of:
1637
+ [
1638
+ { file_exists: ['.github/workflows/*secret*'] },
1639
+ {
1640
+ content:
1641
+ {
1642
+ include: ['.github/workflows/*.yml'],
1643
+ pattern: '(gitleaks|trufflehog|secret-scanning|detect-secrets)',
1644
+ },
1645
+ },
1646
+ ],
1647
+ },
1648
+ }
1649
+ - {
1650
+ fact: 'has:sast',
1651
+ category: tooling,
1652
+ title: SAST in CI,
1653
+ match:
1654
+ {
1655
+ content:
1656
+ {
1657
+ include: ['.github/workflows/*.yml'],
1658
+ pattern: '(codeql|semgrep|snyk|sonar|bandit|gosec|clippy-sarif|trivy)',
1659
+ },
1660
+ },
1661
+ }
1662
+ - {
1663
+ fact: 'has:dep-scan',
1664
+ category: tooling,
1665
+ title: Dependency scanning,
1666
+ match:
1667
+ {
1668
+ content:
1669
+ {
1670
+ include: ['.github/workflows/*.yml'],
1671
+ pattern: '(npm audit|pnpm audit|pip-audit|osv-scanner|snyk test|trivy fs|dependabot|renovate|grype)',
1672
+ },
1673
+ },
1674
+ }
1675
+ - {
1676
+ fact: 'has:codecov',
1677
+ category: tooling,
1678
+ title: Coverage tracking,
1679
+ match:
1680
+ {
1681
+ any_of:
1682
+ [
1683
+ { any_file: ['.codecov.yml', 'codecov.yml', '.coveragerc'] },
1684
+ {
1685
+ content:
1686
+ { include: ['.github/workflows/*.yml'], pattern: 'codecov|coveralls|coverage' },
1687
+ },
1688
+ ],
1689
+ },
1690
+ }
1691
+
1692
+ # ------------------------------------------------------------------------ ci
1693
+ - {
1694
+ fact: 'ci:github-actions',
1695
+ category: ci,
1696
+ title: 'GitHub Actions',
1697
+ match: { dir_exists: ['.github/workflows'] },
1698
+ }
1699
+ - {
1700
+ fact: 'ci:gitlab',
1701
+ category: ci,
1702
+ title: 'GitLab CI',
1703
+ match: { file_exists: ['.gitlab-ci.yml'] },
1704
+ }
1705
+ - { fact: 'ci:jenkins', category: ci, title: Jenkins, match: { file_exists: ['Jenkinsfile'] } }
1706
+ - { fact: 'ci:circleci', category: ci, title: CircleCI, match: { dir_exists: ['.circleci'] } }
1707
+ - {
1708
+ fact: 'ci:buildkite',
1709
+ category: ci,
1710
+ title: Buildkite,
1711
+ match: { file_exists: ['.buildkite/pipeline.yml'] },
1712
+ }
1713
+ - {
1714
+ fact: 'ci:azure',
1715
+ category: ci,
1716
+ title: 'Azure Pipelines',
1717
+ match: { file_exists: ['azure-pipelines.yml'] },
1718
+ }
1719
+ - { fact: 'has:ci', category: ci, title: 'Has CI', implies: ['ci:github-actions'] }
1720
+ - { fact: 'has:ci', category: ci, title: 'Has CI', implies: ['ci:gitlab'] }
1721
+ - { fact: 'has:ci', category: ci, title: 'Has CI', implies: ['ci:jenkins'] }
1722
+ - { fact: 'has:ci', category: ci, title: 'Has CI', implies: ['ci:circleci'] }
1723
+ - { fact: 'has:ci', category: ci, title: 'Has CI', implies: ['ci:buildkite'] }
1724
+ - { fact: 'has:ci', category: ci, title: 'Has CI', implies: ['ci:azure'] }
1725
+
1726
+ # ----------------------------------------------------------- observability
1727
+ - {
1728
+ fact: 'obs:sentry',
1729
+ category: obs,
1730
+ title: Sentry,
1731
+ match:
1732
+ {
1733
+ content:
1734
+ {
1735
+ include: ['package.json', 'requirements*.txt', '**/*.{ts,js,py}'],
1736
+ pattern: '@sentry/|sentry-sdk',
1737
+ },
1738
+ },
1739
+ }
1740
+ - {
1741
+ fact: 'obs:otel',
1742
+ category: obs,
1743
+ title: OpenTelemetry,
1744
+ match:
1745
+ {
1746
+ content:
1747
+ {
1748
+ include:
1749
+ ['package.json', 'requirements*.txt', 'go.mod', 'Cargo.toml', '**/*.{ts,js,py,go}'],
1750
+ pattern: 'opentelemetry',
1751
+ },
1752
+ },
1753
+ }
1754
+ - {
1755
+ fact: 'obs:prometheus',
1756
+ category: obs,
1757
+ title: Prometheus,
1758
+ match:
1759
+ {
1760
+ any_of:
1761
+ [
1762
+ { any_file: ['**/prometheus*.yml'] },
1763
+ {
1764
+ content:
1765
+ {
1766
+ include: ['package.json', 'go.mod'],
1767
+ pattern: 'prom-client|prometheus/client_golang',
1768
+ },
1769
+ },
1770
+ ],
1771
+ },
1772
+ }
1773
+ - {
1774
+ fact: 'obs:datadog',
1775
+ category: obs,
1776
+ title: Datadog,
1777
+ match:
1778
+ { content: { include: ['**/*.{yml,yaml,json,ts,js,py}'], pattern: 'datadog|dd-trace' } },
1779
+ }
1780
+ - {
1781
+ fact: 'obs:grafana',
1782
+ category: obs,
1783
+ title: Grafana,
1784
+ match: { any_of: [{ dir_exists: ['grafana'] }, { any_file: ['**/grafana/**/*.json'] }] },
1785
+ }
1786
+ - {
1787
+ fact: 'has:monitoring',
1788
+ category: obs,
1789
+ title: Monitoring configured,
1790
+ match:
1791
+ {
1792
+ any_of:
1793
+ [
1794
+ { dir_exists: ['monitoring', 'observability', 'grafana'] },
1795
+ {
1796
+ content:
1797
+ {
1798
+ include: ['**/*.{yml,yaml,json}'],
1799
+ pattern: 'datadog|newrelic|grafana|prometheus',
1800
+ },
1801
+ },
1802
+ ],
1803
+ },
1804
+ }
1805
+
1806
+ # ---------------------------------------------------------------------- ai
1807
+ - {
1808
+ fact: 'ai:llm-sdk',
1809
+ category: ai,
1810
+ title: LLM SDK,
1811
+ match:
1812
+ {
1813
+ content:
1814
+ {
1815
+ include: ['package.json', 'requirements*.txt', 'pyproject.toml', 'go.mod'],
1816
+ pattern: '(openai|anthropic|@anthropic-ai|ai-sdk|langchain|llamaindex|google-generativeai|cohere|mistralai|bedrock|vertexai)',
1817
+ },
1818
+ },
1819
+ }
1820
+ - {
1821
+ fact: 'ai:prompts',
1822
+ category: ai,
1823
+ title: Prompt assets,
1824
+ match:
1825
+ {
1826
+ any_of:
1827
+ [
1828
+ { dir_exists: ['prompts'] },
1829
+ {
1830
+ any_file: ['**/*.prompt', '**/*.prompt.md', '**/prompts/*.md', '**/prompts/*.yaml'],
1831
+ },
1832
+ ],
1833
+ },
1834
+ }
1835
+ - {
1836
+ fact: 'ai:agents',
1837
+ category: ai,
1838
+ title: 'Agent / agentic code',
1839
+ match:
1840
+ {
1841
+ any_of:
1842
+ [
1843
+ {
1844
+ file_exists:
1845
+ [
1846
+ 'AGENTS.md',
1847
+ 'CLAUDE.md',
1848
+ '.cursorrules',
1849
+ '.github/copilot-instructions.md',
1850
+ 'codex.md',
1851
+ '.windsurfrules',
1852
+ ],
1853
+ },
1854
+ { dir_exists: ['agents', '.claude/agents'] },
1855
+ {
1856
+ content:
1857
+ {
1858
+ include: ['package.json', 'requirements*.txt', 'pyproject.toml'],
1859
+ pattern: '(langgraph|crewai|autogen|@openai/agents|mastra|smolagents|pydantic-ai|llamaindex)',
1860
+ },
1861
+ },
1862
+ ],
1863
+ },
1864
+ }
1865
+ - {
1866
+ fact: 'ai:mcp',
1867
+ category: ai,
1868
+ title: 'MCP servers / tool use',
1869
+ match:
1870
+ {
1871
+ any_of:
1872
+ [
1873
+ {
1874
+ content:
1875
+ {
1876
+ include: ['**/*.{json,jsonc}', '.mcp.json', '**/.mcp.json', '**/mcp.json'],
1877
+ pattern: '"mcpServers"|modelcontextprotocol',
1878
+ },
1879
+ },
1880
+ { content: { include: ['package.json'], pattern: '@modelcontextprotocol' } },
1881
+ ],
1882
+ },
1883
+ }
1884
+ - { fact: 'ai:rag', category: ai, title: 'RAG pipeline', implies: ['db:vector'] }
1885
+ - {
1886
+ fact: 'ai:rag',
1887
+ category: ai,
1888
+ title: 'RAG pipeline',
1889
+ match:
1890
+ {
1891
+ content: { include: ['**/*.{ts,js,py}'], pattern: '(embedding|retriev|rerank|chunking)' },
1892
+ },
1893
+ }
1894
+ - {
1895
+ fact: 'ai:evals',
1896
+ category: ai,
1897
+ title: LLM evals,
1898
+ match:
1899
+ {
1900
+ any_of:
1901
+ [
1902
+ { dir_exists: ['evals', 'eval'] },
1903
+ { any_file: ['**/*.eval.{ts,js,py}', '**/evals/**'] },
1904
+ ],
1905
+ },
1906
+ }
1907
+
1908
+ # ------------------------------------------------------------------- docs
1909
+ - {
1910
+ fact: 'doc:readme',
1911
+ category: doc,
1912
+ title: README,
1913
+ match: { any_file: ['README.md', 'readme.md', 'README.rst', 'README.txt', 'README'] },
1914
+ }
1915
+ - {
1916
+ fact: 'doc:license',
1917
+ category: doc,
1918
+ title: LICENSE,
1919
+ match: { any_file: ['LICENSE*', 'COPYING*'] },
1920
+ }
1921
+ - {
1922
+ fact: 'doc:contributing',
1923
+ category: doc,
1924
+ title: CONTRIBUTING,
1925
+ match: { any_file: ['CONTRIBUTING*'] },
1926
+ }
1927
+ - {
1928
+ fact: 'doc:code-of-conduct',
1929
+ category: doc,
1930
+ title: 'Code of conduct',
1931
+ match: { any_file: ['CODE_OF_CONDUCT*'] },
1932
+ }
1933
+ - {
1934
+ fact: 'doc:security-policy',
1935
+ category: doc,
1936
+ title: SECURITY.md,
1937
+ match: { any_file: ['SECURITY.md', '.github/SECURITY.md', 'docs/SECURITY.md'] },
1938
+ }
1939
+ - {
1940
+ fact: 'doc:changelog',
1941
+ category: doc,
1942
+ title: CHANGELOG,
1943
+ match: { any_file: ['CHANGELOG*', 'CHANGES*', 'HISTORY.md'] },
1944
+ }
1945
+ - {
1946
+ fact: 'doc:architecture',
1947
+ category: doc,
1948
+ title: Architecture docs,
1949
+ match:
1950
+ {
1951
+ any_of:
1952
+ [
1953
+ { dir_exists: ['docs/adrs', 'docs/adr', 'adr', 'docs/architecture'] },
1954
+ {
1955
+ any_file:
1956
+ [
1957
+ 'docs/ARCHITECTURE.md',
1958
+ 'ARCHITECTURE.md',
1959
+ 'docs/**/adr-*.md',
1960
+ 'docs/**/*.adr.md',
1961
+ ],
1962
+ },
1963
+ ],
1964
+ },
1965
+ }
1966
+ - {
1967
+ fact: 'doc:adr',
1968
+ category: doc,
1969
+ title: ADRs,
1970
+ match:
1971
+ {
1972
+ any_of:
1973
+ [
1974
+ { dir_exists: ['docs/adrs', 'docs/adr', 'adr', 'docs/decisions'] },
1975
+ { any_file: ['**/adr-*.md', '**/ADR-*.md'] },
1976
+ ],
1977
+ },
1978
+ }
1979
+ - {
1980
+ fact: 'doc:api-reference',
1981
+ category: doc,
1982
+ title: API reference,
1983
+ match:
1984
+ {
1985
+ any_of:
1986
+ [
1987
+ { any_file: ['**/openapi.yaml', '**/openapi.json', '**/swagger.*', '**/*.graphql'] },
1988
+ { dir_exists: ['docs/api'] },
1989
+ ],
1990
+ },
1991
+ }
1992
+ - {
1993
+ fact: 'doc:runbook',
1994
+ category: doc,
1995
+ title: Runbook,
1996
+ match:
1997
+ {
1998
+ any_of:
1999
+ [{ any_file: ['**/RUNBOOK*', '**/runbook*'] }, { dir_exists: ['ops', 'runbooks'] }],
2000
+ },
2001
+ }
2002
+ - {
2003
+ fact: 'doc:governance',
2004
+ category: doc,
2005
+ title: Governance docs,
2006
+ match:
2007
+ {
2008
+ any_file:
2009
+ ['GOVERNANCE.md', 'docs/GOVERNANCE.md', 'ADOPTERS.md', 'ROADMAP.md', 'MAINTAINERS.md'],
2010
+ },
2011
+ }
2012
+ - {
2013
+ fact: 'doc:agents',
2014
+ category: doc,
2015
+ title: Agent instructions,
2016
+ match:
2017
+ {
2018
+ any_file:
2019
+ [
2020
+ 'AGENTS.md',
2021
+ 'CLAUDE.md',
2022
+ '.cursorrules',
2023
+ '.github/copilot-instructions.md',
2024
+ 'codex.md',
2025
+ '.windsurfrules',
2026
+ ],
2027
+ },
2028
+ }