@slamb2k/mad-skills 2.0.14 → 2.0.16

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.
@@ -0,0 +1,474 @@
1
+ # Terraform Templates
2
+
3
+ Starter templates for common infrastructure components. Customize based on
4
+ INFRA_CONFIG from the interview. Each module is self-contained with its own
5
+ variables and outputs.
6
+
7
+ ---
8
+
9
+ ## Project Root
10
+
11
+ ### versions.tf
12
+
13
+ ```hcl
14
+ terraform {
15
+ required_version = ">= 1.5"
16
+
17
+ required_providers {
18
+ # Include only the provider(s) selected in the interview
19
+ azurerm = {
20
+ source = "hashicorp/azurerm"
21
+ version = "~> 4.0"
22
+ }
23
+ # aws = {
24
+ # source = "hashicorp/aws"
25
+ # version = "~> 5.0"
26
+ # }
27
+ # google = {
28
+ # source = "hashicorp/google"
29
+ # version = "~> 6.0"
30
+ # }
31
+ }
32
+ }
33
+ ```
34
+
35
+ ### main.tf — Azure
36
+
37
+ ```hcl
38
+ terraform {
39
+ backend "azurerm" {
40
+ resource_group_name = "{STATE_RG}"
41
+ storage_account_name = "{STATE_STORAGE}"
42
+ container_name = "tfstate"
43
+ key = "{PROJECT}.tfstate"
44
+ }
45
+ }
46
+
47
+ provider "azurerm" {
48
+ features {}
49
+ }
50
+
51
+ locals {
52
+ name_prefix = "{NAMING_PREFIX}-${var.environment}"
53
+ tags = {
54
+ project = "{PROJECT}"
55
+ environment = var.environment
56
+ managed_by = "terraform"
57
+ }
58
+ }
59
+
60
+ resource "azurerm_resource_group" "main" {
61
+ name = "rg-${local.name_prefix}"
62
+ location = var.location
63
+ tags = local.tags
64
+ }
65
+
66
+ module "registry" {
67
+ source = "./modules/registry"
68
+ name = "acr${replace(local.name_prefix, "-", "")}"
69
+ resource_group_name = azurerm_resource_group.main.name
70
+ location = azurerm_resource_group.main.location
71
+ sku = var.environment == "prod" ? "Premium" : "Basic"
72
+ tags = local.tags
73
+ }
74
+
75
+ # Add module calls for each selected component
76
+ ```
77
+
78
+ ### main.tf — AWS
79
+
80
+ ```hcl
81
+ terraform {
82
+ backend "s3" {
83
+ bucket = "{PROJECT}-tfstate"
84
+ key = "infra/{PROJECT}.tfstate"
85
+ region = "{REGION}"
86
+ dynamodb_table = "{PROJECT}-tflock"
87
+ encrypt = true
88
+ }
89
+ }
90
+
91
+ provider "aws" {
92
+ region = var.region
93
+
94
+ default_tags {
95
+ tags = {
96
+ Project = "{PROJECT}"
97
+ Environment = var.environment
98
+ ManagedBy = "terraform"
99
+ }
100
+ }
101
+ }
102
+
103
+ module "registry" {
104
+ source = "./modules/registry"
105
+ name = "{PROJECT}-${var.environment}"
106
+ }
107
+ ```
108
+
109
+ ### main.tf — GCP
110
+
111
+ ```hcl
112
+ terraform {
113
+ backend "gcs" {
114
+ bucket = "{PROJECT}-tfstate"
115
+ prefix = "infra"
116
+ }
117
+ }
118
+
119
+ provider "google" {
120
+ project = var.project_id
121
+ region = var.region
122
+ }
123
+
124
+ module "registry" {
125
+ source = "./modules/registry"
126
+ project_id = var.project_id
127
+ location = var.region
128
+ }
129
+ ```
130
+
131
+ ### variables.tf
132
+
133
+ ```hcl
134
+ variable "environment" {
135
+ description = "Deployment environment (dev, staging, prod)"
136
+ type = string
137
+ validation {
138
+ condition = contains(["dev", "staging", "prod"], var.environment)
139
+ error_message = "Environment must be dev, staging, or prod."
140
+ }
141
+ }
142
+
143
+ variable "location" {
144
+ description = "Cloud region"
145
+ type = string
146
+ default = "{DEFAULT_REGION}"
147
+ }
148
+
149
+ variable "project" {
150
+ description = "Project name"
151
+ type = string
152
+ default = "{PROJECT}"
153
+ }
154
+ ```
155
+
156
+ ### outputs.tf
157
+
158
+ ```hcl
159
+ output "registry_url" {
160
+ description = "Container registry login server URL"
161
+ value = module.registry.login_server
162
+ }
163
+
164
+ output "registry_name" {
165
+ description = "Container registry name"
166
+ value = module.registry.name
167
+ }
168
+
169
+ # Add outputs for each provisioned component
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Module: Container Registry
175
+
176
+ ### Azure (modules/registry/)
177
+
178
+ ```hcl
179
+ # modules/registry/main.tf
180
+ resource "azurerm_container_registry" "this" {
181
+ name = var.name
182
+ resource_group_name = var.resource_group_name
183
+ location = var.location
184
+ sku = var.sku
185
+ admin_enabled = false
186
+ tags = var.tags
187
+ }
188
+
189
+ output "login_server" { value = azurerm_container_registry.this.login_server }
190
+ output "name" { value = azurerm_container_registry.this.name }
191
+ output "id" { value = azurerm_container_registry.this.id }
192
+ ```
193
+
194
+ ### AWS (modules/registry/)
195
+
196
+ ```hcl
197
+ resource "aws_ecr_repository" "this" {
198
+ name = var.name
199
+ image_tag_mutability = "IMMUTABLE"
200
+
201
+ image_scanning_configuration {
202
+ scan_on_push = true
203
+ }
204
+
205
+ encryption_configuration {
206
+ encryption_type = "AES256"
207
+ }
208
+ }
209
+
210
+ resource "aws_ecr_lifecycle_policy" "this" {
211
+ repository = aws_ecr_repository.this.name
212
+ policy = jsonencode({
213
+ rules = [{
214
+ rulePriority = 1
215
+ description = "Keep last 50 images"
216
+ selection = {
217
+ tagStatus = "any"
218
+ countType = "imageCountMoreThan"
219
+ countNumber = 50
220
+ }
221
+ action = { type = "expire" }
222
+ }]
223
+ })
224
+ }
225
+
226
+ output "repository_url" { value = aws_ecr_repository.this.repository_url }
227
+ output "name" { value = aws_ecr_repository.this.name }
228
+ ```
229
+
230
+ ### GCP (modules/registry/)
231
+
232
+ ```hcl
233
+ resource "google_artifact_registry_repository" "this" {
234
+ location = var.location
235
+ repository_id = var.name
236
+ format = "DOCKER"
237
+ project = var.project_id
238
+ }
239
+
240
+ output "repository_url" {
241
+ value = "${var.location}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.this.repository_id}"
242
+ }
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Module: Managed Database
248
+
249
+ ### Azure PostgreSQL Flexible Server
250
+
251
+ ```hcl
252
+ # modules/database/main.tf
253
+ resource "azurerm_postgresql_flexible_server" "this" {
254
+ name = "psql-${var.name_prefix}"
255
+ resource_group_name = var.resource_group_name
256
+ location = var.location
257
+ version = "16"
258
+ administrator_login = var.admin_username
259
+ administrator_password = var.admin_password
260
+ storage_mb = var.environment == "prod" ? 65536 : 32768
261
+ sku_name = var.environment == "prod" ? "GP_Standard_D2s_v3" : "B_Standard_B1ms"
262
+ zone = var.environment == "prod" ? "1" : null
263
+ tags = var.tags
264
+
265
+ authentication {
266
+ active_directory_auth_enabled = true
267
+ password_auth_enabled = true
268
+ }
269
+ }
270
+
271
+ resource "azurerm_postgresql_flexible_server_database" "app" {
272
+ name = var.database_name
273
+ server_id = azurerm_postgresql_flexible_server.this.id
274
+ charset = "UTF8"
275
+ collation = "en_US.utf8"
276
+ }
277
+
278
+ resource "azurerm_postgresql_flexible_server_firewall_rule" "allow_azure" {
279
+ name = "AllowAzureServices"
280
+ server_id = azurerm_postgresql_flexible_server.this.id
281
+ start_ip_address = "0.0.0.0"
282
+ end_ip_address = "0.0.0.0"
283
+ }
284
+
285
+ output "fqdn" { value = azurerm_postgresql_flexible_server.this.fqdn }
286
+ output "connection_string" {
287
+ value = "postgresql://${var.admin_username}:${var.admin_password}@${azurerm_postgresql_flexible_server.this.fqdn}:5432/${var.database_name}?sslmode=require"
288
+ sensitive = true
289
+ }
290
+ ```
291
+
292
+ ### AWS RDS PostgreSQL
293
+
294
+ ```hcl
295
+ resource "aws_db_instance" "this" {
296
+ identifier = "${var.name_prefix}-db"
297
+ engine = "postgres"
298
+ engine_version = "16"
299
+ instance_class = var.environment == "prod" ? "db.t3.medium" : "db.t3.micro"
300
+
301
+ allocated_storage = var.environment == "prod" ? 100 : 20
302
+ max_allocated_storage = var.environment == "prod" ? 500 : 50
303
+ storage_encrypted = true
304
+
305
+ db_name = var.database_name
306
+ username = var.admin_username
307
+ password = var.admin_password
308
+
309
+ multi_az = var.environment == "prod"
310
+ backup_retention_period = var.environment == "prod" ? 14 : 1
311
+ skip_final_snapshot = var.environment != "prod"
312
+
313
+ vpc_security_group_ids = [var.db_security_group_id]
314
+ db_subnet_group_name = var.db_subnet_group_name
315
+
316
+ tags = var.tags
317
+ }
318
+
319
+ output "endpoint" { value = aws_db_instance.this.endpoint }
320
+ output "connection_string" {
321
+ value = "postgresql://${var.admin_username}:${var.admin_password}@${aws_db_instance.this.endpoint}/${var.database_name}"
322
+ sensitive = true
323
+ }
324
+ ```
325
+
326
+ ---
327
+
328
+ ## Module: Serverless Containers
329
+
330
+ ### Azure Container Apps
331
+
332
+ ```hcl
333
+ resource "azurerm_container_app_environment" "this" {
334
+ name = "cae-${var.name_prefix}"
335
+ resource_group_name = var.resource_group_name
336
+ location = var.location
337
+ tags = var.tags
338
+ }
339
+
340
+ output "id" { value = azurerm_container_app_environment.this.id }
341
+ output "default_domain" { value = azurerm_container_app_environment.this.default_domain }
342
+ ```
343
+
344
+ ### AWS ECS Fargate Cluster
345
+
346
+ ```hcl
347
+ resource "aws_ecs_cluster" "this" {
348
+ name = "${var.name_prefix}-cluster"
349
+
350
+ setting {
351
+ name = "containerInsights"
352
+ value = var.environment == "prod" ? "enabled" : "disabled"
353
+ }
354
+ }
355
+
356
+ resource "aws_ecs_cluster_capacity_providers" "this" {
357
+ cluster_name = aws_ecs_cluster.this.name
358
+ capacity_providers = ["FARGATE", "FARGATE_SPOT"]
359
+
360
+ default_capacity_provider_strategy {
361
+ capacity_provider = var.environment == "prod" ? "FARGATE" : "FARGATE_SPOT"
362
+ weight = 1
363
+ }
364
+ }
365
+
366
+ output "cluster_arn" { value = aws_ecs_cluster.this.arn }
367
+ output "cluster_name" { value = aws_ecs_cluster.this.name }
368
+ ```
369
+
370
+ ---
371
+
372
+ ## Module: Networking (Azure)
373
+
374
+ ```hcl
375
+ resource "azurerm_virtual_network" "this" {
376
+ name = "vnet-${var.name_prefix}"
377
+ resource_group_name = var.resource_group_name
378
+ location = var.location
379
+ address_space = [var.address_space]
380
+ tags = var.tags
381
+ }
382
+
383
+ resource "azurerm_subnet" "app" {
384
+ name = "snet-app"
385
+ resource_group_name = var.resource_group_name
386
+ virtual_network_name = azurerm_virtual_network.this.name
387
+ address_prefixes = [cidrsubnet(var.address_space, 8, 1)]
388
+ }
389
+
390
+ resource "azurerm_subnet" "db" {
391
+ name = "snet-db"
392
+ resource_group_name = var.resource_group_name
393
+ virtual_network_name = azurerm_virtual_network.this.name
394
+ address_prefixes = [cidrsubnet(var.address_space, 8, 2)]
395
+
396
+ delegation {
397
+ name = "postgresql"
398
+ service_delegation {
399
+ name = "Microsoft.DBforPostgreSQL/flexibleServers"
400
+ }
401
+ }
402
+ }
403
+
404
+ output "vnet_id" { value = azurerm_virtual_network.this.id }
405
+ output "app_subnet_id" { value = azurerm_subnet.app.id }
406
+ output "db_subnet_id" { value = azurerm_subnet.db.id }
407
+ ```
408
+
409
+ ---
410
+
411
+ ## Module: Key Vault / Secrets
412
+
413
+ ### Azure Key Vault
414
+
415
+ ```hcl
416
+ data "azurerm_client_config" "current" {}
417
+
418
+ resource "azurerm_key_vault" "this" {
419
+ name = "kv-${var.name_prefix}"
420
+ resource_group_name = var.resource_group_name
421
+ location = var.location
422
+ tenant_id = data.azurerm_client_config.current.tenant_id
423
+ sku_name = "standard"
424
+
425
+ enable_rbac_authorization = true
426
+ purge_protection_enabled = var.environment == "prod"
427
+
428
+ tags = var.tags
429
+ }
430
+
431
+ output "vault_uri" { value = azurerm_key_vault.this.vault_uri }
432
+ output "vault_id" { value = azurerm_key_vault.this.id }
433
+ ```
434
+
435
+ ### AWS Secrets Manager
436
+
437
+ ```hcl
438
+ resource "aws_secretsmanager_secret" "app" {
439
+ name = "${var.name_prefix}/app-secrets"
440
+ description = "Application secrets for ${var.name_prefix}"
441
+
442
+ tags = var.tags
443
+ }
444
+
445
+ output "secret_arn" { value = aws_secretsmanager_secret.app.arn }
446
+ ```
447
+
448
+ ---
449
+
450
+ ## Environment Variable Files
451
+
452
+ ### dev.tfvars
453
+
454
+ ```hcl
455
+ environment = "dev"
456
+ location = "{REGION}"
457
+ # Minimal sizing — cost-optimized for development
458
+ ```
459
+
460
+ ### staging.tfvars
461
+
462
+ ```hcl
463
+ environment = "staging"
464
+ location = "{REGION}"
465
+ # Standard sizing — mirrors prod structure at lower scale
466
+ ```
467
+
468
+ ### prod.tfvars
469
+
470
+ ```hcl
471
+ environment = "prod"
472
+ location = "{REGION}"
473
+ # Production sizing — HA, redundancy, scaling enabled
474
+ ```
@@ -0,0 +1,35 @@
1
+ [
2
+ {
3
+ "name": "banner-display",
4
+ "prompt": "/keel",
5
+ "assertions": [
6
+ { "type": "contains", "value": "██" },
7
+ { "type": "regex", "value": "⚓|🏗️|🌍|🔩|☁️|🧱|📐|🗺️" },
8
+ { "type": "semantic", "value": "Displays an ASCII art banner for the keel skill before doing anything else" }
9
+ ]
10
+ },
11
+ {
12
+ "name": "iac-tool-selection",
13
+ "prompt": "/keel for an Azure-hosted Node.js app",
14
+ "assertions": [
15
+ { "type": "semantic", "value": "Suggests or asks about IaC tool choice, mentioning at least Terraform and Bicep as options" },
16
+ { "type": "semantic", "value": "Detects or mentions Azure as the cloud provider" }
17
+ ]
18
+ },
19
+ {
20
+ "name": "skill-ordering",
21
+ "prompt": "/keel",
22
+ "assertions": [
23
+ { "type": "semantic", "value": "Describes the recommended skill ordering where /keel runs before /dock to provision infrastructure" },
24
+ { "type": "regex", "value": "(?i)(keel.*dock|infrastructure.*deploy|provision.*before)" }
25
+ ]
26
+ },
27
+ {
28
+ "name": "plan-apply-pattern",
29
+ "prompt": "/keel --skip-interview for a Terraform project on AWS",
30
+ "assertions": [
31
+ { "type": "semantic", "value": "Describes or generates a CI/CD pipeline that plans on pull requests and applies on merge" },
32
+ { "type": "semantic", "value": "Mentions state management for Terraform such as S3 backend or remote state" }
33
+ ]
34
+ }
35
+ ]
@@ -1,6 +1,6 @@
1
1
  {
2
- "generated": "2026-03-09T14:11:12.798Z",
3
- "count": 8,
2
+ "generated": "2026-03-09T17:01:26.694Z",
3
+ "count": 10,
4
4
  "skills": [
5
5
  {
6
6
  "name": "brace",
@@ -16,7 +16,7 @@
16
16
  "name": "build",
17
17
  "directory": "build",
18
18
  "description": "Context-isolated feature development pipeline. Takes a detailed design/plan as argument and executes the full feature-dev lifecycle (explore, question, architect, implement, review, ship) inside subagents so the primary conversation stays compact. Use when you have a well-defined plan and want autonomous execution with minimal context window consumption.",
19
- "lines": 328,
19
+ "lines": 332,
20
20
  "hasScripts": false,
21
21
  "hasReferences": true,
22
22
  "hasAssets": false,
@@ -32,11 +32,31 @@
32
32
  "hasAssets": true,
33
33
  "hasTests": true
34
34
  },
35
+ {
36
+ "name": "dock",
37
+ "directory": "dock",
38
+ "description": ">- Generate container-based release pipelines that build once and promote immutable artifacts through environments (dev → staging → prod). Detects your stack, interviews for infrastructure choices, then outputs deterministic CI/CD files (Dockerfile, workflows, deployment manifests) that run without an LLM. Use when setting up deployment pipelines, containerizing an app, creating release workflows, or connecting CI to container-friendly infrastructure (Azure Container Apps, AWS Fargate, Google Cloud Run, Kubernetes, Dokku, Coolify, CapRover, etc.).",
39
+ "lines": 358,
40
+ "hasScripts": false,
41
+ "hasReferences": true,
42
+ "hasAssets": false,
43
+ "hasTests": true
44
+ },
45
+ {
46
+ "name": "keel",
47
+ "directory": "keel",
48
+ "description": ">- Generate Infrastructure as Code (IaC) pipelines that provision the cloud and container infrastructure your app deploys to. Interview-driven: detects your stack and cloud provider, then outputs deterministic IaC files (Terraform, Bicep, Pulumi, or CDK) plus CI/CD pipelines that plan on PR and apply on merge. Use when setting up cloud infrastructure, provisioning container registries, databases, networking, DNS, or any infrastructure that containers deploy onto. Designed to run before /dock — /keel lays the infrastructure, /dock deploys to it.",
49
+ "lines": 499,
50
+ "hasScripts": false,
51
+ "hasReferences": true,
52
+ "hasAssets": false,
53
+ "hasTests": true
54
+ },
35
55
  {
36
56
  "name": "prime",
37
57
  "directory": "prime",
38
- "description": "\"Load project context before implementing features or making architectural decisions. Invoke proactively when starting significant work on DexAI. Supports domain-specific context loading: security (vault, RBAC, audit), routing (OpenRouter, model selection), adhd (design principles, RSD-safe), dashboard (frontend, backend, API), office (OAuth, email, calendar), memory (context capture, commitments), tasks (decomposition, friction-solving), channels (Telegram, Discord, Slack).\"",
39
- "lines": 108,
58
+ "description": "\"Load project context before implementing features or making architectural decisions. Invoke proactively at the start of significant work on any project. Scans CLAUDE.md, README, goals/, specs/, docs/, and source structure to build a context summary. Supports optional domain hints to focus on specific areas of the codebase. Use when you need project conventions, architecture understanding, or domain context before coding.\"",
59
+ "lines": 113,
40
60
  "hasScripts": false,
41
61
  "hasReferences": true,
42
62
  "hasAssets": false,
@@ -46,7 +66,7 @@
46
66
  "name": "rig",
47
67
  "directory": "rig",
48
68
  "description": "'Idempotently bootstrap any repository with standard development tools, hooks, and workflows. Use when starting work on a new repo, onboarding to an existing project, or ensuring a repo has proper CI/CD setup. Configures: git hooks (lefthook), commit message templates, PR templates, and GitHub Actions for lint/format/type-check/build. Prompts for user confirmation before changes. Triggers: \"bootstrap repo\", \"setup hooks\", \"configure CI\", \"rig\", \"standardize repo\".'",
49
- "lines": 197,
69
+ "lines": 206,
50
70
  "hasScripts": false,
51
71
  "hasReferences": true,
52
72
  "hasAssets": true,
@@ -66,7 +86,7 @@
66
86
  "name": "speccy",
67
87
  "directory": "speccy",
68
88
  "description": "Deep-dive interview skill for creating comprehensive specifications. Reviews existing code and docs, then interviews the user through multiple rounds of targeted questions covering technical implementation, UI/UX, concerns, and tradeoffs. Produces a structured spec via create-specification. Use when starting a new feature, system, or major change that needs a spec.",
69
- "lines": 166,
89
+ "lines": 170,
70
90
  "hasScripts": false,
71
91
  "hasReferences": true,
72
92
  "hasAssets": false,
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: prime
3
- description: "Load project context before implementing features or making architectural decisions. Invoke proactively when starting significant work on DexAI. Supports domain-specific context loading: security (vault, RBAC, audit), routing (OpenRouter, model selection), adhd (design principles, RSD-safe), dashboard (frontend, backend, API), office (OAuth, email, calendar), memory (context capture, commitments), tasks (decomposition, friction-solving), channels (Telegram, Discord, Slack)."
4
- argument-hint: security, routing, adhd, dashboard, office, memory, tasks, channels (comma-separated)
5
- allowed-tools: Read, Glob, Grep, LS
3
+ description: "Load project context before implementing features or making architectural decisions. Invoke proactively at the start of significant work on any project. Scans CLAUDE.md, README, goals/, specs/, docs/, and source structure to build a context summary. Supports optional domain hints to focus on specific areas of the codebase. Use when you need project conventions, architecture understanding, or domain context before coding."
4
+ argument-hint: "[domain hints: comma-separated directory or topic names to focus on]"
5
+ allowed-tools: Read, Glob, Grep, LS, Agent
6
6
  ---
7
7
 
8
8
  # Prime - Project Context Loader
@@ -39,8 +39,9 @@ subagent — the primary thread only sees a structured PRIME_REPORT.
39
39
 
40
40
  ## Step 1: Parse Arguments
41
41
 
42
- Extract domain hints from the request (comma-separated). Valid domains are
43
- listed in `references/domains.md`. If no domain specified, load core context only.
42
+ Extract domain hints from the request (comma-separated). These are directory
43
+ names or topic keywords to focus the context scan on. If no domain specified,
44
+ load core context only (CLAUDE.md, README, goals/, specs/).
44
45
 
45
46
  ## Step 2: Load Context via Subagent
46
47
 
@@ -64,15 +65,19 @@ Limit PRIME_REPORT to 30 lines maximum.
64
65
 
65
66
  ## Core Files (always load)
66
67
 
67
- 1. CLAUDE.md — System handbook, operating procedures
68
- 2. goals/manifest.md — Phase status, available goals, project roadmap
69
- 3. tools/manifest.mdAvailable tools and their locations
68
+ 1. CLAUDE.md — Project conventions, architecture, instructions
69
+ 2. README.md — Project overview, setup, usage
70
+ 3. goals/ or specs/ Project goals, specs, roadmap (scan directory if present)
71
+ 4. docs/ — Documentation directory (scan if present)
70
72
 
71
- If CLAUDE.md is missing, record as NOT FOUND and continue.
73
+ If a file is missing, record as NOT FOUND and continue.
72
74
 
73
75
  ## Domain Files
74
76
 
75
- {For each requested domain, list files from references/domains.md}
77
+ {For each requested domain hint, use Glob to find relevant files:}
78
+ - Search for directories matching the hint name (e.g., "auth" → src/auth/, lib/auth/)
79
+ - Search for files matching *{hint}*.md, *{hint}*.yaml, *{hint}*.json
80
+ - Read the most relevant matches (max 5 files per domain)
76
81
 
77
82
  For each file:
78
83
  - If it exists: read and summarise (2-3 lines max per domain)