opencode-skills-collection 3.0.45 → 3.0.47

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 (71) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +10 -1
  2. package/bundled-skills/2slides-ppt-generator/SKILL.md +1 -1
  3. package/bundled-skills/2slides-ppt-generator/scripts/create_pdf_slides.py +2 -1
  4. package/bundled-skills/2slides-ppt-generator/scripts/generate_narration.py +2 -1
  5. package/bundled-skills/2slides-ppt-generator/scripts/generate_slides.py +13 -7
  6. package/bundled-skills/android-dev/references/hybrid.md +7 -4
  7. package/bundled-skills/android-dev/references/react-native.md +5 -2
  8. package/bundled-skills/atlas-contract/SKILL.md +4 -4
  9. package/bundled-skills/atlas-ledger/SKILL.md +10 -7
  10. package/bundled-skills/bun-development/SKILL.md +1 -1
  11. package/bundled-skills/cloud-penetration-testing/SKILL.md +1 -1
  12. package/bundled-skills/codebase-to-wordpress-converter/SKILL.md +1 -0
  13. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  14. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  15. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  16. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  17. package/bundled-skills/docs/users/bundles.md +1 -1
  18. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  19. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  20. package/bundled-skills/docs/users/getting-started.md +1 -1
  21. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  22. package/bundled-skills/docs/users/usage.md +4 -4
  23. package/bundled-skills/docs/users/visual-guide.md +4 -4
  24. package/bundled-skills/dos-verify-done-claims/SKILL.md +173 -0
  25. package/bundled-skills/ecl-harness-engineer/LICENSE +21 -0
  26. package/bundled-skills/ecl-harness-engineer/SKILL.md +714 -0
  27. package/bundled-skills/ecl-harness-engineer/agents/analyzer.md +119 -0
  28. package/bundled-skills/ecl-harness-engineer/agents/auditor.md +212 -0
  29. package/bundled-skills/ecl-harness-engineer/agents/creator-config.md +343 -0
  30. package/bundled-skills/ecl-harness-engineer/agents/creator-docs.md +201 -0
  31. package/bundled-skills/ecl-harness-engineer/agents/creator-linters.md +123 -0
  32. package/bundled-skills/ecl-harness-engineer/references/adapters/adapter-schema.md +204 -0
  33. package/bundled-skills/ecl-harness-engineer/references/adapters/generic.md +156 -0
  34. package/bundled-skills/ecl-harness-engineer/references/adapters/go.md +212 -0
  35. package/bundled-skills/ecl-harness-engineer/references/adapters/java.md +205 -0
  36. package/bundled-skills/ecl-harness-engineer/references/adapters/python.md +225 -0
  37. package/bundled-skills/ecl-harness-engineer/references/adapters/rust.md +220 -0
  38. package/bundled-skills/ecl-harness-engineer/references/adapters/typescript.md +245 -0
  39. package/bundled-skills/ecl-harness-engineer/references/architecture-diagrams.md +420 -0
  40. package/bundled-skills/ecl-harness-engineer/references/audit-templates.md +649 -0
  41. package/bundled-skills/ecl-harness-engineer/references/capability-registry.md +485 -0
  42. package/bundled-skills/ecl-harness-engineer/references/darwin-eval-prompts.md +373 -0
  43. package/bundled-skills/ecl-harness-engineer/references/documentation-templates.md +741 -0
  44. package/bundled-skills/ecl-harness-engineer/references/durability-patterns.md +423 -0
  45. package/bundled-skills/ecl-harness-engineer/references/ecl-harness.md +1431 -0
  46. package/bundled-skills/ecl-harness-engineer/references/environment-config-guide.md +534 -0
  47. package/bundled-skills/ecl-harness-engineer/references/environment-detection-guide.md +751 -0
  48. package/bundled-skills/ecl-harness-engineer/references/eval-templates.md +377 -0
  49. package/bundled-skills/ecl-harness-engineer/references/gc-templates.md +798 -0
  50. package/bundled-skills/ecl-harness-engineer/references/greenfield-templates.md +1385 -0
  51. package/bundled-skills/ecl-harness-engineer/references/linter-templates.md +448 -0
  52. package/bundled-skills/ecl-harness-engineer/references/observability-templates.md +315 -0
  53. package/bundled-skills/environment-setup-guide/SKILL.md +2 -2
  54. package/bundled-skills/evolution/SKILL.md +1 -1
  55. package/bundled-skills/gitops-workflow/SKILL.md +1 -1
  56. package/bundled-skills/linkerd-patterns/SKILL.md +1 -1
  57. package/bundled-skills/loki-mode/examples/todo-app-generated/frontend/package-lock.json +504 -1317
  58. package/bundled-skills/loki-mode/examples/todo-app-generated/frontend/package.json +2 -2
  59. package/bundled-skills/lovable-cleanup/SKILL.md +416 -0
  60. package/bundled-skills/monopoly/SKILL.md +397 -0
  61. package/bundled-skills/monopoly/patterns/SKILL.md +331 -0
  62. package/bundled-skills/monopoly/scale-benchmarks/SKILL.md +174 -0
  63. package/bundled-skills/monopoly/security-checklist/SKILL.md +69 -0
  64. package/bundled-skills/monopoly/tech-matrix/SKILL.md +268 -0
  65. package/bundled-skills/pagespeed-enhancer/SKILL.md +579 -0
  66. package/bundled-skills/polis-protocol/SKILL.md +6 -3
  67. package/bundled-skills/unship/SKILL.md +11 -5
  68. package/bundled-skills/uv-package-manager/resources/implementation-playbook.md +1 -1
  69. package/bundled-skills/varlock/SKILL.md +2 -2
  70. package/package.json +1 -1
  71. package/skills_index.json +204 -4
@@ -0,0 +1,1385 @@
1
+ # Greenfield Templates
2
+
3
+ Complete, ready-to-use templates for 0→1 project scaffolding. Each section provides real file contents — not placeholders — for bootstrapping a new project with core harness infrastructure.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Go CLI Tool](#go-cli-tool)
8
+ - [Go Web API](#go-web-api)
9
+ - [TypeScript/Node CLI](#typescriptnode-cli)
10
+ - [TypeScript/Node Web API](#typescriptnode-web-api)
11
+ - [Python CLI](#python-cli)
12
+ - [Python Web API](#python-web-api)
13
+ - [Shared Templates](#shared-templates) (docs, exec-plans, quality — same for all stacks)
14
+
15
+ ---
16
+
17
+ ## Go CLI Tool
18
+
19
+ ### go.mod
20
+
21
+ ```
22
+ module {module-path}
23
+
24
+ go 1.22
25
+ ```
26
+
27
+ ### main.go
28
+
29
+ ```go
30
+ package main
31
+
32
+ import (
33
+ "fmt"
34
+ "os"
35
+
36
+ "{module-path}/cmd"
37
+ )
38
+
39
+ func main() {
40
+ if err := cmd.Execute(); err != nil {
41
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
42
+ os.Exit(1)
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### cmd/root.go
48
+
49
+ ```go
50
+ package cmd
51
+
52
+ import (
53
+ "fmt"
54
+ "os"
55
+ )
56
+
57
+ func Execute() error {
58
+ if len(os.Args) < 2 {
59
+ fmt.Println("{project-name} - {description}")
60
+ fmt.Println("\nUsage:")
61
+ fmt.Println(" {project-name} <command> [arguments]")
62
+ fmt.Println("\nCommands:")
63
+ fmt.Println(" version Print version info")
64
+ return nil
65
+ }
66
+
67
+ switch os.Args[1] {
68
+ case "version":
69
+ fmt.Println("{project-name} v0.1.0")
70
+ default:
71
+ return fmt.Errorf("unknown command: %s", os.Args[1])
72
+ }
73
+ return nil
74
+ }
75
+ ```
76
+
77
+ ### internal/types/types.go
78
+
79
+ ```go
80
+ // Package types defines core types shared across the application.
81
+ // Layer 0: No internal dependencies allowed.
82
+ package types
83
+ ```
84
+
85
+ ### internal/core/core.go
86
+
87
+ ```go
88
+ // Package core contains the main business logic.
89
+ // Layer 1: May depend on types (Layer 0) only.
90
+ package core
91
+ ```
92
+
93
+ ### Makefile
94
+
95
+ ```makefile
96
+ .PHONY: build test lint lint-arch clean
97
+
98
+ build:
99
+ go build -o bin/{project-name} .
100
+
101
+ test:
102
+ go test ./...
103
+
104
+ lint: lint-arch
105
+ @if command -v golangci-lint >/dev/null 2>&1; then \
106
+ golangci-lint run; \
107
+ else \
108
+ echo "golangci-lint not installed, skipping"; \
109
+ fi
110
+
111
+ lint-arch:
112
+ @echo "Checking architecture constraints..."
113
+ @go run scripts/lint-deps.go
114
+ @go run scripts/lint-quality.go
115
+ @echo "✓ Architecture checks passed"
116
+
117
+ clean:
118
+ rm -rf bin/
119
+ ```
120
+
121
+ ### scripts/lint-deps.go
122
+
123
+ Use the template from `references/linter-templates.md`, with:
124
+ - `modulePath` set to the project's module path
125
+ - `layers` configured for the project's directory structure:
126
+ ```go
127
+ var layers = [][]string{
128
+ {"internal/types"}, // Layer 0
129
+ {"internal/core"}, // Layer 1
130
+ {"cmd"}, // Layer 2 (top)
131
+ }
132
+ ```
133
+
134
+ ### scripts/lint-quality.go
135
+
136
+ Use the template from `references/linter-templates.md`, with file size limit set to 500 for new projects (can grow to 1000 later).
137
+
138
+ ---
139
+
140
+ ## Go Web API
141
+
142
+ Same as Go CLI Tool, with these additions/changes:
143
+
144
+ ### main.go
145
+
146
+ ```go
147
+ package main
148
+
149
+ import (
150
+ "log"
151
+ "net/http"
152
+
153
+ "{module-path}/internal/api"
154
+ )
155
+
156
+ func main() {
157
+ router := api.NewRouter()
158
+ log.Println("Starting server on :8080")
159
+ if err := http.ListenAndServe(":8080", router); err != nil {
160
+ log.Fatalf("Server failed: %v", err)
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### internal/api/router.go
166
+
167
+ ```go
168
+ // Package api defines HTTP handlers and routing.
169
+ // Layer 2: May depend on core (Layer 1) and types (Layer 0).
170
+ package api
171
+
172
+ import "net/http"
173
+
174
+ func NewRouter() http.Handler {
175
+ mux := http.NewServeMux()
176
+ mux.HandleFunc("GET /health", handleHealth)
177
+ return mux
178
+ }
179
+
180
+ func handleHealth(w http.ResponseWriter, r *http.Request) {
181
+ w.Header().Set("Content-Type", "application/json")
182
+ w.Write([]byte(`{"status":"ok"}`))
183
+ }
184
+ ```
185
+
186
+ ### Layer hierarchy
187
+
188
+ ```go
189
+ var layers = [][]string{
190
+ {"internal/types"}, // Layer 0
191
+ {"internal/core"}, // Layer 1
192
+ {"internal/api"}, // Layer 2
193
+ {"cmd"}, // Layer 3 (top)
194
+ }
195
+ ```
196
+
197
+ ---
198
+
199
+ ## TypeScript/Node CLI
200
+
201
+ ### package.json
202
+
203
+ ```json
204
+ {
205
+ "name": "{project-name}",
206
+ "version": "0.1.0",
207
+ "description": "{description}",
208
+ "main": "dist/index.js",
209
+ "scripts": {
210
+ "build": "tsc",
211
+ "start": "node dist/index.js",
212
+ "dev": "ts-node src/index.ts",
213
+ "test": "jest",
214
+ "lint": "npm run lint:arch && eslint src/",
215
+ "lint:arch": "ts-node scripts/lint-deps.ts && ts-node scripts/lint-quality.ts"
216
+ },
217
+ "devDependencies": {
218
+ "@types/node": "^20.0.0",
219
+ "eslint": "^8.0.0",
220
+ "jest": "^29.0.0",
221
+ "ts-node": "^10.0.0",
222
+ "typescript": "^5.0.0"
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### tsconfig.json
228
+
229
+ ```json
230
+ {
231
+ "compilerOptions": {
232
+ "target": "ES2022",
233
+ "module": "commonjs",
234
+ "outDir": "dist",
235
+ "rootDir": "src",
236
+ "strict": true,
237
+ "esModuleInterop": true,
238
+ "skipLibCheck": true,
239
+ "resolveJsonModule": true,
240
+ "declaration": true
241
+ },
242
+ "include": ["src/**/*"],
243
+ "exclude": ["node_modules", "dist"]
244
+ }
245
+ ```
246
+
247
+ ### src/index.ts
248
+
249
+ ```typescript
250
+ #!/usr/bin/env node
251
+
252
+ function main(): void {
253
+ const args = process.argv.slice(2);
254
+ const command = args[0];
255
+
256
+ switch (command) {
257
+ case "version":
258
+ console.log("{project-name} v0.1.0");
259
+ break;
260
+ default:
261
+ console.log("{project-name} - {description}");
262
+ console.log("\nUsage:");
263
+ console.log(" {project-name} <command>");
264
+ console.log("\nCommands:");
265
+ console.log(" version Print version info");
266
+ }
267
+ }
268
+
269
+ main();
270
+ ```
271
+
272
+ ### src/types/index.ts
273
+
274
+ ```typescript
275
+ // Layer 0: Core types — no internal imports allowed
276
+ export interface Config {
277
+ // Add configuration types here
278
+ }
279
+ ```
280
+
281
+ ### scripts/lint-deps.ts
282
+
283
+ ```typescript
284
+ #!/usr/bin/env ts-node
285
+ /**
286
+ * Validates that imports respect the layer hierarchy.
287
+ *
288
+ * Layer 0: src/types/ — No internal imports
289
+ * Layer 1: src/core/ — May import types only
290
+ * Layer 2: src/commands/ — May import core and types
291
+ * Layer 3: src/index.ts — May import anything
292
+ */
293
+ import * as fs from "fs";
294
+ import * as path from "path";
295
+
296
+ interface LayerRule {
297
+ pattern: string;
298
+ layer: number;
299
+ forbiddenImports: string[];
300
+ }
301
+
302
+ const rules: LayerRule[] = [
303
+ {
304
+ pattern: "src/types/",
305
+ layer: 0,
306
+ forbiddenImports: ["../core", "../commands"],
307
+ },
308
+ {
309
+ pattern: "src/core/",
310
+ layer: 1,
311
+ forbiddenImports: ["../commands"],
312
+ },
313
+ ];
314
+
315
+ let violations = 0;
316
+
317
+ function checkFile(filePath: string): void {
318
+ const content = fs.readFileSync(filePath, "utf8");
319
+ const lines = content.split("\n");
320
+
321
+ for (const rule of rules) {
322
+ if (!filePath.includes(rule.pattern)) continue;
323
+
324
+ lines.forEach((line, i) => {
325
+ const importMatch = line.match(/from\s+['"]([^'"]+)['"]/);
326
+ if (!importMatch) return;
327
+
328
+ const importPath = importMatch[1];
329
+ for (const forbidden of rule.forbiddenImports) {
330
+ if (importPath.includes(forbidden)) {
331
+ console.error(
332
+ `✗ ${filePath}:${i + 1} — Layer ${rule.layer} cannot import "${importPath}"`,
333
+ );
334
+ console.error(
335
+ ` Fix: Move this logic to a higher layer, or pass the dependency as a parameter.`,
336
+ );
337
+ violations++;
338
+ }
339
+ }
340
+ });
341
+ }
342
+ }
343
+
344
+ function walkDir(dir: string): void {
345
+ if (!fs.existsSync(dir)) return;
346
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
347
+ for (const entry of entries) {
348
+ const fullPath = path.join(dir, entry.name);
349
+ if (entry.isDirectory() && entry.name !== "node_modules") {
350
+ walkDir(fullPath);
351
+ } else if (entry.name.endsWith(".ts") && !entry.name.endsWith(".test.ts")) {
352
+ checkFile(fullPath);
353
+ }
354
+ }
355
+ }
356
+
357
+ walkDir("src");
358
+
359
+ if (violations === 0) {
360
+ console.log("✓ All imports follow the layer hierarchy");
361
+ process.exit(0);
362
+ } else {
363
+ console.error(`\n✗ Found ${violations} layer violation(s)`);
364
+ process.exit(1);
365
+ }
366
+ ```
367
+
368
+ ### scripts/lint-quality.ts
369
+
370
+ ```typescript
371
+ #!/usr/bin/env ts-node
372
+ /**
373
+ * Validates quality rules:
374
+ * - File size limits (max 500 lines)
375
+ * - No console.log in production code (use a logger)
376
+ */
377
+ import * as fs from "fs";
378
+ import * as path from "path";
379
+
380
+ const MAX_FILE_LINES = 500;
381
+ let violations = 0;
382
+
383
+ function checkFile(filePath: string): void {
384
+ const content = fs.readFileSync(filePath, "utf8");
385
+ const lines = content.split("\n");
386
+
387
+ // Check file size
388
+ if (lines.length > MAX_FILE_LINES) {
389
+ console.error(
390
+ `✗ ${filePath} has ${lines.length} lines (max ${MAX_FILE_LINES})`,
391
+ );
392
+ console.error(
393
+ ` Fix: Split this file into smaller, focused modules.`,
394
+ );
395
+ violations++;
396
+ }
397
+
398
+ // Check for console.log in non-test, non-index files
399
+ if (!filePath.includes(".test.") && !filePath.endsWith("index.ts")) {
400
+ lines.forEach((line, i) => {
401
+ if (line.match(/console\.log\(/) && !line.trim().startsWith("//")) {
402
+ console.error(
403
+ `✗ ${filePath}:${i + 1} — Use structured logger instead of console.log`,
404
+ );
405
+ console.error(
406
+ ` Fix: Import the logger from src/utils/logger.ts and use logger.info() instead.`,
407
+ );
408
+ violations++;
409
+ }
410
+ });
411
+ }
412
+ }
413
+
414
+ function walkDir(dir: string): void {
415
+ if (!fs.existsSync(dir)) return;
416
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
417
+ for (const entry of entries) {
418
+ const fullPath = path.join(dir, entry.name);
419
+ if (entry.isDirectory() && entry.name !== "node_modules") {
420
+ walkDir(fullPath);
421
+ } else if (entry.name.endsWith(".ts")) {
422
+ checkFile(fullPath);
423
+ }
424
+ }
425
+ }
426
+
427
+ walkDir("src");
428
+
429
+ if (violations === 0) {
430
+ console.log("✓ All quality checks passed");
431
+ process.exit(0);
432
+ } else {
433
+ console.error(`\n✗ Found ${violations} quality violation(s)`);
434
+ process.exit(1);
435
+ }
436
+ ```
437
+
438
+ ---
439
+
440
+ ## TypeScript/Node Web API
441
+
442
+ Same as TypeScript CLI, with these additions:
443
+
444
+ ### src/index.ts
445
+
446
+ ```typescript
447
+ import http from "http";
448
+ import { router } from "./api/router";
449
+
450
+ const PORT = process.env.PORT || 8080;
451
+
452
+ const server = http.createServer(router);
453
+
454
+ server.listen(PORT, () => {
455
+ console.log(`Server running on port ${PORT}`);
456
+ });
457
+ ```
458
+
459
+ ### src/api/router.ts
460
+
461
+ ```typescript
462
+ import http from "http";
463
+
464
+ export function router(
465
+ req: http.IncomingMessage,
466
+ res: http.ServerResponse,
467
+ ): void {
468
+ if (req.url === "/health" && req.method === "GET") {
469
+ res.writeHead(200, { "Content-Type": "application/json" });
470
+ res.end(JSON.stringify({ status: "ok" }));
471
+ return;
472
+ }
473
+
474
+ res.writeHead(404, { "Content-Type": "application/json" });
475
+ res.end(JSON.stringify({ error: "Not Found" }));
476
+ }
477
+ ```
478
+
479
+ ---
480
+
481
+ ## Python CLI
482
+
483
+ ### pyproject.toml
484
+
485
+ ```toml
486
+ [build-system]
487
+ requires = ["setuptools>=68.0", "wheel"]
488
+ build-backend = "setuptools.backends._legacy:_Backend"
489
+
490
+ [project]
491
+ name = "{project-name}"
492
+ version = "0.1.0"
493
+ description = "{description}"
494
+ requires-python = ">=3.10"
495
+ dependencies = []
496
+
497
+ [project.optional-dependencies]
498
+ dev = ["pytest", "ruff", "mypy"]
499
+
500
+ [project.scripts]
501
+ {project-name} = "{package_name}.main:main"
502
+
503
+ [tool.ruff]
504
+ line-length = 100
505
+ target-version = "py310"
506
+
507
+ [tool.mypy]
508
+ strict = true
509
+ ```
510
+
511
+ ### requirements.txt
512
+
513
+ ```
514
+ # Production dependencies
515
+
516
+ # Dev dependencies
517
+ pytest>=7.0
518
+ ruff>=0.1.0
519
+ mypy>=1.0
520
+ ```
521
+
522
+ ### src/{package_name}/__init__.py
523
+
524
+ ```python
525
+ """
526
+ {Project Name} - {description}
527
+ """
528
+
529
+ __version__ = "0.1.0"
530
+ ```
531
+
532
+ ### src/{package_name}/main.py
533
+
534
+ ```python
535
+ """Entry point for {project-name}."""
536
+ import sys
537
+
538
+
539
+ def main() -> None:
540
+ """Main entry point."""
541
+ args = sys.argv[1:]
542
+
543
+ if not args:
544
+ print("{project-name} - {description}")
545
+ print("\nUsage:")
546
+ print(" {project-name} <command>")
547
+ print("\nCommands:")
548
+ print(" version Print version info")
549
+ return
550
+
551
+ command = args[0]
552
+ if command == "version":
553
+ print("{project-name} v0.1.0")
554
+ else:
555
+ print(f"Unknown command: {command}", file=sys.stderr)
556
+ sys.exit(1)
557
+
558
+
559
+ if __name__ == "__main__":
560
+ main()
561
+ ```
562
+
563
+ ### src/{package_name}/types.py
564
+
565
+ ```python
566
+ """
567
+ Core types shared across the application.
568
+ Layer 0: No internal imports allowed.
569
+ """
570
+ from dataclasses import dataclass
571
+
572
+
573
+ @dataclass
574
+ class Config:
575
+ """Application configuration."""
576
+ pass
577
+ ```
578
+
579
+ ### tests/__init__.py
580
+
581
+ ```python
582
+ ```
583
+
584
+ ### tests/test_main.py
585
+
586
+ ```python
587
+ """Tests for main module."""
588
+ from {package_name}.main import main
589
+
590
+
591
+ def test_main_no_args(capsys, monkeypatch):
592
+ """Test main with no arguments shows usage."""
593
+ monkeypatch.setattr("sys.argv", ["{project-name}"])
594
+ main()
595
+ captured = capsys.readouterr()
596
+ assert "{project-name}" in captured.out
597
+ ```
598
+
599
+ ### Makefile (Python)
600
+
601
+ ```makefile
602
+ .PHONY: install test lint lint-arch format clean
603
+
604
+ install:
605
+ pip install -e ".[dev]"
606
+
607
+ test:
608
+ pytest tests/ -v
609
+
610
+ lint: lint-arch
611
+ ruff check src/ tests/
612
+ mypy src/
613
+
614
+ lint-arch:
615
+ @echo "Checking architecture constraints..."
616
+ @python scripts/lint_deps.py
617
+ @python scripts/lint_quality.py
618
+ @echo "✓ Architecture checks passed"
619
+
620
+ format:
621
+ ruff format src/ tests/
622
+
623
+ clean:
624
+ rm -rf dist/ build/ *.egg-info __pycache__
625
+ find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
626
+ ```
627
+
628
+ ### scripts/lint_deps.py
629
+
630
+ ```python
631
+ #!/usr/bin/env python3
632
+ """
633
+ Validates that imports respect the layer hierarchy.
634
+
635
+ Layer 0: src/{package}/types.py — No internal imports
636
+ Layer 1: src/{package}/core/ — May import types only
637
+ Layer 2: src/{package}/api/ — May import core and types
638
+ Layer 3: src/{package}/main.py — May import anything
639
+ """
640
+ import ast
641
+ import sys
642
+ from pathlib import Path
643
+
644
+ PACKAGE_NAME = "{package_name}"
645
+
646
+ LAYER_MAP = {
647
+ "types": 0,
648
+ "core": 1,
649
+ "api": 2,
650
+ "main": 3,
651
+ }
652
+
653
+ violations = []
654
+
655
+
656
+ def get_layer(filepath: Path) -> int:
657
+ """Determine the layer of a file based on its path."""
658
+ parts = filepath.parts
659
+ for part in parts:
660
+ if part in LAYER_MAP:
661
+ return LAYER_MAP[part]
662
+ # main.py at package root
663
+ if filepath.stem == "main":
664
+ return 3
665
+ return -1
666
+
667
+
668
+ def check_file(filepath: Path) -> None:
669
+ """Check a single file for layer violations."""
670
+ source_layer = get_layer(filepath)
671
+ if source_layer < 0:
672
+ return
673
+
674
+ try:
675
+ tree = ast.parse(filepath.read_text())
676
+ except SyntaxError:
677
+ return
678
+
679
+ for node in ast.walk(tree):
680
+ if isinstance(node, (ast.Import, ast.ImportFrom)):
681
+ module = ""
682
+ if isinstance(node, ast.ImportFrom) and node.module:
683
+ module = node.module
684
+ elif isinstance(node, ast.Import):
685
+ for alias in node.names:
686
+ module = alias.name
687
+
688
+ if not module.startswith(PACKAGE_NAME):
689
+ continue
690
+
691
+ for target, target_layer in LAYER_MAP.items():
692
+ if target in module and target_layer >= source_layer and target != filepath.stem:
693
+ violations.append(
694
+ f" ✗ {filepath}:{node.lineno} — "
695
+ f"Layer {source_layer} imports '{module}' (layer {target_layer})\n"
696
+ f" Fix: Move this logic to a higher layer, "
697
+ f"or pass the dependency as a parameter."
698
+ )
699
+
700
+
701
+ def main() -> None:
702
+ src_dir = Path("src") / PACKAGE_NAME
703
+ if not src_dir.exists():
704
+ print(f"Source directory {src_dir} not found")
705
+ sys.exit(1)
706
+
707
+ for py_file in src_dir.rglob("*.py"):
708
+ if "__pycache__" in str(py_file):
709
+ continue
710
+ check_file(py_file)
711
+
712
+ if not violations:
713
+ print("✓ All imports follow the layer hierarchy")
714
+ sys.exit(0)
715
+ else:
716
+ print(f"✗ Found {len(violations)} layer violation(s):\n")
717
+ for v in violations:
718
+ print(v)
719
+ sys.exit(1)
720
+
721
+
722
+ if __name__ == "__main__":
723
+ main()
724
+ ```
725
+
726
+ ### scripts/lint_quality.py
727
+
728
+ ```python
729
+ #!/usr/bin/env python3
730
+ """
731
+ Validates quality rules:
732
+ - File size limits (max 500 lines)
733
+ - No print() in production code (use logging)
734
+ """
735
+ import sys
736
+ from pathlib import Path
737
+
738
+ MAX_FILE_LINES = 500
739
+ violations = []
740
+
741
+
742
+ def check_file(filepath: Path) -> None:
743
+ """Check a single file for quality violations."""
744
+ lines = filepath.read_text().splitlines()
745
+
746
+ # File size check
747
+ if len(lines) > MAX_FILE_LINES:
748
+ violations.append(
749
+ f" ✗ {filepath} has {len(lines)} lines (max {MAX_FILE_LINES})\n"
750
+ f" Fix: Split this file into smaller, focused modules."
751
+ )
752
+
753
+ # print() in non-test, non-main files
754
+ if "test_" not in filepath.name and filepath.stem != "main":
755
+ for i, line in enumerate(lines, 1):
756
+ stripped = line.strip()
757
+ if stripped.startswith("#"):
758
+ continue
759
+ if "print(" in stripped:
760
+ violations.append(
761
+ f" ✗ {filepath}:{i} — Use logging instead of print()\n"
762
+ f" Fix: import logging; logger = logging.getLogger(__name__); logger.info(...)"
763
+ )
764
+
765
+
766
+ def main() -> None:
767
+ src_dir = Path("src")
768
+ if not src_dir.exists():
769
+ print("src/ directory not found")
770
+ sys.exit(1)
771
+
772
+ for py_file in src_dir.rglob("*.py"):
773
+ if "__pycache__" in str(py_file):
774
+ continue
775
+ check_file(py_file)
776
+
777
+ if not violations:
778
+ print("✓ All quality checks passed")
779
+ sys.exit(0)
780
+ else:
781
+ print(f"✗ Found {len(violations)} quality violation(s):\n")
782
+ for v in violations:
783
+ print(v)
784
+ sys.exit(1)
785
+
786
+
787
+ if __name__ == "__main__":
788
+ main()
789
+ ```
790
+
791
+ ---
792
+
793
+ ## Python Web API
794
+
795
+ Same as Python CLI, with these additions:
796
+
797
+ ### src/{package_name}/main.py (Web API version)
798
+
799
+ ```python
800
+ """Entry point for {project-name} web API."""
801
+ from http.server import HTTPServer, BaseHTTPRequestHandler
802
+ import json
803
+
804
+
805
+ class APIHandler(BaseHTTPRequestHandler):
806
+ """Simple HTTP request handler."""
807
+
808
+ def do_GET(self) -> None:
809
+ if self.path == "/health":
810
+ self._json_response(200, {"status": "ok"})
811
+ else:
812
+ self._json_response(404, {"error": "Not Found"})
813
+
814
+ def _json_response(self, status: int, body: dict) -> None:
815
+ self.send_response(status)
816
+ self.send_header("Content-Type", "application/json")
817
+ self.end_headers()
818
+ self.wfile.write(json.dumps(body).encode())
819
+
820
+
821
+ def main() -> None:
822
+ """Start the HTTP server."""
823
+ port = 8080
824
+ server = HTTPServer(("", port), APIHandler)
825
+ print(f"Server running on port {port}")
826
+ server.serve_forever()
827
+
828
+
829
+ if __name__ == "__main__":
830
+ main()
831
+ ```
832
+
833
+ ---
834
+
835
+ ## Shared Templates
836
+
837
+ These files are the same regardless of tech stack. All templates use:
838
+ - **Hierarchical numbering** (1, 1.1, 1.2...) for stable cross-references
839
+ - **Placeholder source citations** (`> Sources: [`file`]()`) pointing to files that will be created
840
+ - **Mermaid diagrams** showing the planned architecture
841
+
842
+ ### AGENTS.md Template (DeepWiki-style)
843
+
844
+ ```markdown
845
+ # {Project Name} Agent Guide
846
+
847
+ {One-sentence description}
848
+
849
+ ## 1 Quick Start
850
+
851
+ - [Architecture Overview](docs/ARCHITECTURE.md) — System design, layers, data flow
852
+ - [Development Setup](docs/DEVELOPMENT.md) — Build, test, environment
853
+
854
+ ## 2 Architecture
855
+
856
+ | Section | Document | Description |
857
+ |---------|----------|-------------|
858
+ | 2.1 | [System Architecture](docs/ARCHITECTURE.md) | Layer hierarchy, dependency graph, data flow |
859
+ | 2.2 | [Design Documents](docs/design-docs/index.md) | Component deep-dives (to be added) |
860
+
861
+ ## 3 Quality & Standards
862
+
863
+ | Section | Document | Description |
864
+ |---------|----------|-------------|
865
+ | 3.1 | [Code Quality](docs/QUALITY.md) | Golden principles, linter rules |
866
+ | 3.2 | [Testing Standards](docs/TESTING.md) | Test patterns, coverage |
867
+ | 3.3 | [Security Policy](docs/SECURITY.md) | Security considerations |
868
+ | 3.4 | [Quality Score](docs/QUALITY_SCORE.md) | Per-domain quality grades |
869
+
870
+ ## 4 Development
871
+
872
+ \`\`\`bash
873
+ {stack-specific build commands}
874
+ \`\`\`
875
+
876
+ See [Development Setup](docs/DEVELOPMENT.md) for complete reference.
877
+
878
+ ## 5 Execution Plans
879
+
880
+ - [Active Plans](docs/exec-plans/active/) — Work in progress
881
+ - [Completed Plans](docs/exec-plans/completed/) — Historical record
882
+ - [Tech Debt Tracker](docs/exec-plans/tech-debt-tracker.md)
883
+
884
+ ## 6 Key Directories
885
+
886
+ | Directory | Layer | Purpose |
887
+ |-----------|-------|---------|
888
+ | \`{main-source-dir}/\` | L2-L3 | Application code |
889
+ | \`{types-dir}/\` | L0 | Type definitions |
890
+ | \`docs/\` | — | All documentation |
891
+ | \`scripts/\` | — | Linters and tooling |
892
+ | \`harness/\` | — | Eval and quality |
893
+
894
+ ---
895
+
896
+ **Note**: This file is a navigation map (~80 lines). Details live in linked documents.
897
+ ```
898
+
899
+ ### docs/ARCHITECTURE.md Template (DeepWiki-style, Greenfield)
900
+
901
+ For greenfield projects, the architecture document describes the **planned** structure, with
902
+ Mermaid diagrams showing the intended layer hierarchy. Source citations point to files that
903
+ will be created by the execution plan.
904
+
905
+ ```markdown
906
+ # Architecture
907
+
908
+ > Project initialized: {today's date}
909
+ > Status: Greenfield — structure defined, implementation pending
910
+
911
+ ## 1 Overview
912
+
913
+ {One paragraph: what this project will do, who will use it, and the architectural approach.}
914
+
915
+ ## 2 System Architecture
916
+
917
+ ### 2.1 Package Dependency Graph
918
+
919
+ \`\`\`mermaid
920
+ graph TD
921
+ subgraph "Layer 2 — Entry Points"
922
+ CMD[cmd/]
923
+ end
924
+ subgraph "Layer 1 — Business Logic"
925
+ CORE[internal/core/]
926
+ end
927
+ subgraph "Layer 0 — Types"
928
+ TYPES[internal/types/]
929
+ end
930
+
931
+ CMD --> CORE
932
+ CORE --> TYPES
933
+
934
+ style TYPES fill:#e8f5e9
935
+ style CORE fill:#fff3e0
936
+ style CMD fill:#f3e5f5
937
+ \`\`\`
938
+
939
+ > Planned structure. To be enforced by: [\`scripts/lint-deps.go\`]()
940
+
941
+ ### 2.2 Layer Hierarchy
942
+
943
+ | Layer | Packages | Can Import | Cannot Import | Purpose |
944
+ |-------|----------|------------|---------------|---------|
945
+ | L0 | \`internal/types/\` | stdlib only | anything internal | Shared type definitions |
946
+ | L1 | \`internal/core/\` | L0 | L2 | Business logic |
947
+ | L2 | \`cmd/\` | L0, L1 | — | CLI commands, entry points |
948
+
949
+ > Will be enforced by: [\`scripts/lint-deps.go\`]()
950
+
951
+ ### 2.3 Forbidden Dependencies
952
+
953
+ | From | To | Why Forbidden |
954
+ |------|----|---------------|
955
+ | \`internal/types/\` | any internal | Types must be dependency-free |
956
+ | \`internal/core/\` | \`cmd/\` | Core logic must not know about CLI |
957
+
958
+ ## 3 Planned Components
959
+
960
+ ### 3.1 Types Package
961
+
962
+ **Purpose**: Shared type definitions used across all layers
963
+ **Location**: \`internal/types/types.go\`
964
+
965
+ \`\`\`go
966
+ // Planned structure (to be implemented)
967
+ package types
968
+
969
+ type Config struct {
970
+ // Configuration fields
971
+ }
972
+ \`\`\`
973
+
974
+ > Source: [\`internal/types/types.go\`]() (to be created)
975
+
976
+ ### 3.2 Core Package
977
+
978
+ **Purpose**: Main business logic
979
+ **Location**: \`internal/core/core.go\`
980
+
981
+ \`\`\`mermaid
982
+ classDiagram
983
+ class Core {
984
+ +Process(input) Result, error
985
+ +Validate(input) error
986
+ }
987
+ \`\`\`
988
+
989
+ > Source: [\`internal/core/core.go\`]() (to be created)
990
+
991
+ ### 3.3 CLI Commands
992
+
993
+ **Purpose**: User-facing command interface
994
+ **Location**: \`cmd/root.go\`
995
+
996
+ > Source: [\`cmd/root.go\`]() (to be created)
997
+
998
+ ## 4 Data Flow
999
+
1000
+ ### 4.1 Primary Flow
1001
+
1002
+ \`\`\`mermaid
1003
+ sequenceDiagram
1004
+ participant User
1005
+ participant CLI as CLI (cmd/)
1006
+ participant Core as Core (internal/core/)
1007
+
1008
+ User->>CLI: command args
1009
+ CLI->>Core: Process(args)
1010
+ Core-->>CLI: Result
1011
+ CLI-->>User: Output
1012
+ \`\`\`
1013
+
1014
+ ## 5 Key Design Decisions
1015
+
1016
+ | # | Decision | Rationale | Alternatives Considered |
1017
+ |---|----------|-----------|------------------------|
1018
+ | 1 | Layered architecture | Enforces clean dependencies, testable | Flat structure (rejected: harder to maintain) |
1019
+ | 2 | Types in L0 | Shared across all layers without cycles | Types in each package (rejected: duplication) |
1020
+ | 3 | internal/ packages | Prevents external imports | Public packages (rejected: not needed) |
1021
+
1022
+ ## 6 Module & Dependencies
1023
+
1024
+ \`\`\`
1025
+ module {module-path}
1026
+ go {version}
1027
+ \`\`\`
1028
+
1029
+ **External Dependencies**: None initially (boring technology principle)
1030
+
1031
+ ## See Also
1032
+
1033
+ - [Development Setup](DEVELOPMENT.md) — Build and test commands
1034
+ - [Quality Score](QUALITY_SCORE.md) — Quality tracking
1035
+ ```
1036
+
1037
+ ### docs/PRODUCT_SENSE.md
1038
+
1039
+ ```markdown
1040
+ # Product Sense
1041
+
1042
+ ## 1 What This Project Does
1043
+
1044
+ {description}
1045
+
1046
+ ## 2 Business Context
1047
+
1048
+ [Why does this project exist? What problem does it solve?]
1049
+
1050
+ ## 3 Key Priorities
1051
+
1052
+ | Priority | Level | Description |
1053
+ |----------|-------|-------------|
1054
+ | Correctness | [High/Medium/Low] | [How critical is data accuracy?] |
1055
+ | Performance | [High/Medium/Low] | [What are latency requirements?] |
1056
+ | Security | [High/Medium/Low] | [What data sensitivity level?] |
1057
+ | Reliability | [High/Medium/Low] | [What uptime is expected?] |
1058
+
1059
+ ## 4 Target Users
1060
+
1061
+ [Who uses this? What do they care about?]
1062
+
1063
+ ## 5 Non-Goals
1064
+
1065
+ [What is explicitly out of scope?]
1066
+ ```
1067
+
1068
+ ### docs/QUALITY_SCORE.md
1069
+
1070
+ ```markdown
1071
+ # Quality Score
1072
+
1073
+ Last updated: {today's date}
1074
+
1075
+ ## 1 Domain Grades
1076
+
1077
+ | Domain | Grade | Issues | Trend | Notes |
1078
+ |--------|-------|--------|-------|-------|
1079
+ | Core | N/A | 0 | — | New project |
1080
+
1081
+ ## 2 Architectural Layers
1082
+
1083
+ | Layer | Coverage | Lint Pass | Doc Fresh |
1084
+ |-------|----------|-----------|-----------|
1085
+ | Types (L0) | N/A | ✓ | ✓ |
1086
+ | Core (L1) | N/A | ✓ | ✓ |
1087
+ | CLI (L2) | N/A | ✓ | ✓ |
1088
+
1089
+ ## 3 Golden Principles
1090
+
1091
+ 1. Structured logging over raw print/log statements
1092
+ 2. Typed errors with context
1093
+ 3. Files under 500 lines
1094
+ 4. Layer hierarchy enforced by linters
1095
+ 5. All public APIs documented
1096
+
1097
+ > Enforced by: [\`scripts/lint-quality.go\`]()
1098
+
1099
+ ## 4 Quality Trend
1100
+
1101
+ | Date | Overall | Notes |
1102
+ |------|---------|-------|
1103
+ | {today} | Baseline | Project initialized |
1104
+ ```
1105
+
1106
+ ### docs/TESTING.md
1107
+
1108
+ ```markdown
1109
+ # Testing Standards
1110
+
1111
+ ## 1 Test Organization
1112
+
1113
+ \`\`\`
1114
+ tests/
1115
+ ├── unit/ — Fast, isolated tests
1116
+ ├── integration/ — Tests with real dependencies
1117
+ └── fixtures/ — Shared test data
1118
+ \`\`\`
1119
+
1120
+ ## 2 Running Tests
1121
+
1122
+ {stack-specific commands}
1123
+
1124
+ ## 3 Test Patterns
1125
+
1126
+ ### 3.1 Unit Tests
1127
+ - Test one thing per test
1128
+ - Use descriptive names: \`test_<scenario>_<expected_result>\`
1129
+ - Mock external dependencies
1130
+
1131
+ ### 3.2 Integration Tests
1132
+ - Test real interactions between components
1133
+ - Use test fixtures for reproducible state
1134
+ - Clean up after each test
1135
+
1136
+ ## 4 Coverage Goals
1137
+
1138
+ | Component | Target | Current |
1139
+ |-----------|--------|---------|
1140
+ | Core logic | 80% | N/A |
1141
+ | CLI commands | 70% | N/A |
1142
+ | Utils | 60% | N/A |
1143
+ ```
1144
+
1145
+ ### docs/SECURITY.md
1146
+
1147
+ ```markdown
1148
+ # Security Policy
1149
+
1150
+ ## 1 Principles
1151
+
1152
+ 1. Never commit secrets (API keys, passwords, tokens)
1153
+ 2. Validate all external input
1154
+ 3. Use parameterized queries for database access
1155
+ 4. Log security-relevant events
1156
+ 5. Keep dependencies updated
1157
+
1158
+ ## 2 Sensitive Files
1159
+
1160
+ Never commit these:
1161
+ - \`.env\` files
1162
+ - \`credentials.json\`
1163
+ - Private keys (\`*.pem\`, \`*.key\`)
1164
+ - Database dumps
1165
+
1166
+ ## 3 Input Validation
1167
+
1168
+ All user input must be validated before processing:
1169
+ - Type checking
1170
+ - Length limits
1171
+ - Character allowlists where appropriate
1172
+
1173
+ ## 4 Dependency Management
1174
+
1175
+ - Review new dependencies before adding
1176
+ - Keep dependencies updated regularly
1177
+ - Audit for known vulnerabilities
1178
+ ```
1179
+
1180
+ ### docs/DEVELOPMENT.md (Go version)
1181
+
1182
+ ```markdown
1183
+ # Development Setup
1184
+
1185
+ ## 1 Prerequisites
1186
+
1187
+ - Go 1.22+
1188
+ - make
1189
+
1190
+ ## 2 Quick Start
1191
+
1192
+ \`\`\`bash
1193
+ git clone {repo-url}
1194
+ cd {project-name}
1195
+ make build
1196
+ \`\`\`
1197
+
1198
+ ## 3 Build Commands
1199
+
1200
+ | Command | Description | Duration |
1201
+ |---------|-------------|----------|
1202
+ | \`make build\` | Build the binary | ~5s |
1203
+ | \`make test\` | Run all tests | ~10s |
1204
+ | \`make lint\` | Run all linters | ~5s |
1205
+ | \`make lint-arch\` | Run architecture linters only | ~3s |
1206
+ | \`make clean\` | Remove build artifacts | ~1s |
1207
+
1208
+ ## 4 Project Structure
1209
+
1210
+ \`\`\`
1211
+ .
1212
+ ├── cmd/ — CLI commands (Layer 2)
1213
+ ├── internal/ — Private packages
1214
+ │ ├── types/ — Core types (Layer 0)
1215
+ │ └── core/ — Business logic (Layer 1)
1216
+ ├── docs/ — Documentation
1217
+ ├── scripts/ — Linters and tools
1218
+ └── harness/ — Eval and quality
1219
+ \`\`\`
1220
+
1221
+ ## 5 Environment Variables
1222
+
1223
+ | Variable | Default | Required | Description |
1224
+ |----------|---------|----------|-------------|
1225
+ | (none yet) | | | |
1226
+ ```
1227
+
1228
+ ### docs/design-docs/index.md
1229
+
1230
+ ```markdown
1231
+ # Design Documents Index
1232
+
1233
+ | Document | Status | Last Updated | Description |
1234
+ |----------|--------|-------------|-------------|
1235
+ | (none yet) | | | |
1236
+
1237
+ ## How to Add a Design Doc
1238
+
1239
+ 1. Create a new file: `docs/design-docs/{component-name}.md`
1240
+ 2. Use the template from the project's SKILL reference
1241
+ 3. Add an entry to this index
1242
+ 4. Link from AGENTS.md if it's a major component
1243
+ ```
1244
+
1245
+ ### docs/exec-plans/tech-debt-tracker.md
1246
+
1247
+ ```markdown
1248
+ # Tech Debt Tracker
1249
+
1250
+ ## Active Debt
1251
+
1252
+ | ID | Description | Priority | Owner | Created |
1253
+ |----|-------------|----------|-------|---------|
1254
+ | (none yet) | | | | |
1255
+
1256
+ ## Resolved Debt
1257
+
1258
+ | ID | Description | Resolution | Date |
1259
+ |----|-------------|-----------|------|
1260
+ | (none yet) | | | |
1261
+
1262
+ ## How to Track Debt
1263
+
1264
+ When you notice tech debt during development:
1265
+ 1. Add a row to the Active Debt table
1266
+ 2. Assign a priority (P0-P3)
1267
+ 3. Reference it in the relevant execution plan if applicable
1268
+ ```
1269
+
1270
+ ### docs/references/index.md
1271
+
1272
+ ```markdown
1273
+ # Reference Documents Index
1274
+
1275
+ | Document | Description | Last Updated |
1276
+ |----------|-------------|-------------|
1277
+ | (none yet) | | |
1278
+
1279
+ ## Adding References
1280
+
1281
+ Reference documents provide agent-readable summaries of external dependencies, APIs, and schemas.
1282
+
1283
+ Format: `{dependency-name}-llms.txt` style — concise, focused on API surface and common patterns.
1284
+ ```
1285
+
1286
+ ### .github/workflows/ci.yml (Go version)
1287
+
1288
+ ```yaml
1289
+ name: CI
1290
+
1291
+ on:
1292
+ push:
1293
+ branches: [main]
1294
+ pull_request:
1295
+ branches: [main]
1296
+
1297
+ jobs:
1298
+ build:
1299
+ runs-on: ubuntu-latest
1300
+ steps:
1301
+ - uses: actions/checkout@v4
1302
+
1303
+ - uses: actions/setup-go@v5
1304
+ with:
1305
+ go-version: '1.22'
1306
+
1307
+ - name: Build
1308
+ run: go build ./...
1309
+
1310
+ - name: Test
1311
+ run: go test ./...
1312
+
1313
+ - name: Lint Architecture
1314
+ run: |
1315
+ go run scripts/lint-deps.go
1316
+ go run scripts/lint-quality.go
1317
+ ```
1318
+
1319
+ ### .github/workflows/ci.yml (TypeScript version)
1320
+
1321
+ ```yaml
1322
+ name: CI
1323
+
1324
+ on:
1325
+ push:
1326
+ branches: [main]
1327
+ pull_request:
1328
+ branches: [main]
1329
+
1330
+ jobs:
1331
+ build:
1332
+ runs-on: ubuntu-latest
1333
+ steps:
1334
+ - uses: actions/checkout@v4
1335
+
1336
+ - uses: actions/setup-node@v4
1337
+ with:
1338
+ node-version: '20'
1339
+
1340
+ - name: Install
1341
+ run: npm install
1342
+
1343
+ - name: Build
1344
+ run: npm run build
1345
+
1346
+ - name: Test
1347
+ run: npm test
1348
+
1349
+ - name: Lint
1350
+ run: npm run lint
1351
+ ```
1352
+
1353
+ ### .github/workflows/ci.yml (Python version)
1354
+
1355
+ ```yaml
1356
+ name: CI
1357
+
1358
+ on:
1359
+ push:
1360
+ branches: [main]
1361
+ pull_request:
1362
+ branches: [main]
1363
+
1364
+ jobs:
1365
+ build:
1366
+ runs-on: ubuntu-latest
1367
+ steps:
1368
+ - uses: actions/checkout@v4
1369
+
1370
+ - uses: actions/setup-python@v5
1371
+ with:
1372
+ python-version: '3.12'
1373
+
1374
+ - name: Install
1375
+ run: pip install -e ".[dev]"
1376
+
1377
+ - name: Test
1378
+ run: pytest tests/ -v
1379
+
1380
+ - name: Lint
1381
+ run: |
1382
+ ruff check src/ tests/
1383
+ python scripts/lint_deps.py
1384
+ python scripts/lint_quality.py
1385
+ ```