jdi-cli 0.1.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 (159) hide show
  1. package/AGENTS.md +209 -0
  2. package/ARCHITECTURE.md +210 -0
  3. package/COMMANDS.md +241 -0
  4. package/CREATE-EXAMPLE.md +385 -0
  5. package/CREATE.md +315 -0
  6. package/EXTENSION.md +141 -0
  7. package/LICENSE +21 -0
  8. package/MEMORY.md +471 -0
  9. package/PORTABILITY.md +438 -0
  10. package/README.md +789 -0
  11. package/bin/git-hooks/post-commit +16 -0
  12. package/bin/git-hooks/pre-commit +21 -0
  13. package/bin/jdi-build.ps1 +381 -0
  14. package/bin/jdi-build.sh +332 -0
  15. package/bin/jdi-doctor.ps1 +403 -0
  16. package/bin/jdi-doctor.sh +400 -0
  17. package/bin/jdi-install-caveman.ps1 +97 -0
  18. package/bin/jdi-install-caveman.sh +99 -0
  19. package/bin/jdi-install-playwright.ps1 +319 -0
  20. package/bin/jdi-install-playwright.sh +284 -0
  21. package/bin/jdi-install.ps1 +154 -0
  22. package/bin/jdi-install.sh +132 -0
  23. package/bin/jdi-uninstall.ps1 +309 -0
  24. package/bin/jdi-uninstall.sh +264 -0
  25. package/bin/jdi-update.ps1 +215 -0
  26. package/bin/jdi-update.sh +209 -0
  27. package/bin/jdi.js +460 -0
  28. package/bin/lib/jdi-monitor.ps1 +66 -0
  29. package/bin/lib/jdi-monitor.sh +74 -0
  30. package/bin/lib/jdi-truncate.ps1 +96 -0
  31. package/bin/lib/jdi-truncate.sh +99 -0
  32. package/bin/lib/ui.js +197 -0
  33. package/core/agents/jdi-adopter.md +465 -0
  34. package/core/agents/jdi-architect.md +894 -0
  35. package/core/agents/jdi-asker.md +153 -0
  36. package/core/agents/jdi-bootstrap.md +247 -0
  37. package/core/agents/jdi-planner.md +254 -0
  38. package/core/agents/jdi-researcher.md +303 -0
  39. package/core/commands/jdi-adopt.md +155 -0
  40. package/core/commands/jdi-bootstrap.md +81 -0
  41. package/core/commands/jdi-create.md +80 -0
  42. package/core/commands/jdi-discuss.md +80 -0
  43. package/core/commands/jdi-do.md +200 -0
  44. package/core/commands/jdi-loop.md +315 -0
  45. package/core/commands/jdi-new.md +131 -0
  46. package/core/commands/jdi-plan.md +73 -0
  47. package/core/commands/jdi-ship.md +146 -0
  48. package/core/commands/jdi-verify.md +159 -0
  49. package/core/skills/clean-code/SKILL.md +261 -0
  50. package/core/skills/dry/SKILL.md +150 -0
  51. package/core/skills/frontend-rules/SKILL.md +386 -0
  52. package/core/skills/frontend-validator/SKILL.md +567 -0
  53. package/core/skills/kiss/SKILL.md +178 -0
  54. package/core/skills/solid/SKILL.md +281 -0
  55. package/core/skills/yagni/SKILL.md +207 -0
  56. package/core/templates/agent.md +72 -0
  57. package/core/templates/doer-specialist.md +216 -0
  58. package/core/templates/reviewer-specialist.md +405 -0
  59. package/core/templates/skill.md +66 -0
  60. package/package.json +70 -0
  61. package/runtimes/antigravity/agents.md +74 -0
  62. package/runtimes/antigravity/skills/clean-code/SKILL.md +252 -0
  63. package/runtimes/antigravity/skills/dry/SKILL.md +141 -0
  64. package/runtimes/antigravity/skills/frontend-rules/SKILL.md +376 -0
  65. package/runtimes/antigravity/skills/frontend-validator/SKILL.md +559 -0
  66. package/runtimes/antigravity/skills/jdi-adopt/SKILL.md +155 -0
  67. package/runtimes/antigravity/skills/jdi-adopter/SKILL.md +436 -0
  68. package/runtimes/antigravity/skills/jdi-architect/SKILL.md +872 -0
  69. package/runtimes/antigravity/skills/jdi-asker/SKILL.md +125 -0
  70. package/runtimes/antigravity/skills/jdi-asker/references/context-template.md +34 -0
  71. package/runtimes/antigravity/skills/jdi-asker/references/decision-format.md +19 -0
  72. package/runtimes/antigravity/skills/jdi-asker/scripts/find_phase_dir.sh +25 -0
  73. package/runtimes/antigravity/skills/jdi-bootstrap/SKILL.md +81 -0
  74. package/runtimes/antigravity/skills/jdi-create/SKILL.md +80 -0
  75. package/runtimes/antigravity/skills/jdi-discuss/SKILL.md +80 -0
  76. package/runtimes/antigravity/skills/jdi-discuss/scripts/run_command.sh +62 -0
  77. package/runtimes/antigravity/skills/jdi-do/SKILL.md +200 -0
  78. package/runtimes/antigravity/skills/jdi-loop/SKILL.md +315 -0
  79. package/runtimes/antigravity/skills/jdi-new/SKILL.md +131 -0
  80. package/runtimes/antigravity/skills/jdi-plan/SKILL.md +73 -0
  81. package/runtimes/antigravity/skills/jdi-planner/SKILL.md +225 -0
  82. package/runtimes/antigravity/skills/jdi-researcher/SKILL.md +274 -0
  83. package/runtimes/antigravity/skills/jdi-ship/SKILL.md +146 -0
  84. package/runtimes/antigravity/skills/jdi-verify/SKILL.md +159 -0
  85. package/runtimes/antigravity/skills/kiss/SKILL.md +169 -0
  86. package/runtimes/antigravity/skills/solid/SKILL.md +272 -0
  87. package/runtimes/antigravity/skills/yagni/SKILL.md +198 -0
  88. package/runtimes/claude/CLAUDE.md +91 -0
  89. package/runtimes/claude/agents/jdi-adopter.md +430 -0
  90. package/runtimes/claude/agents/jdi-architect.md +864 -0
  91. package/runtimes/claude/agents/jdi-asker.md +119 -0
  92. package/runtimes/claude/agents/jdi-bootstrap.md +213 -0
  93. package/runtimes/claude/agents/jdi-planner.md +221 -0
  94. package/runtimes/claude/agents/jdi-researcher.md +269 -0
  95. package/runtimes/claude/commands/jdi-adopt.md +155 -0
  96. package/runtimes/claude/commands/jdi-bootstrap.md +81 -0
  97. package/runtimes/claude/commands/jdi-create.md +80 -0
  98. package/runtimes/claude/commands/jdi-discuss.md +80 -0
  99. package/runtimes/claude/commands/jdi-do.md +200 -0
  100. package/runtimes/claude/commands/jdi-loop.md +315 -0
  101. package/runtimes/claude/commands/jdi-new.md +131 -0
  102. package/runtimes/claude/commands/jdi-plan.md +73 -0
  103. package/runtimes/claude/commands/jdi-ship.md +146 -0
  104. package/runtimes/claude/commands/jdi-verify.md +159 -0
  105. package/runtimes/claude/settings.example.json +132 -0
  106. package/runtimes/claude/skills/clean-code/SKILL.md +247 -0
  107. package/runtimes/claude/skills/dry/SKILL.md +136 -0
  108. package/runtimes/claude/skills/frontend-rules/SKILL.md +369 -0
  109. package/runtimes/claude/skills/frontend-validator/SKILL.md +553 -0
  110. package/runtimes/claude/skills/kiss/SKILL.md +164 -0
  111. package/runtimes/claude/skills/solid/SKILL.md +267 -0
  112. package/runtimes/claude/skills/yagni/SKILL.md +193 -0
  113. package/runtimes/copilot/agents/jdi-adopter.agent.md +430 -0
  114. package/runtimes/copilot/agents/jdi-architect.agent.md +864 -0
  115. package/runtimes/copilot/agents/jdi-asker.agent.md +119 -0
  116. package/runtimes/copilot/agents/jdi-bootstrap.agent.md +213 -0
  117. package/runtimes/copilot/agents/jdi-planner.agent.md +221 -0
  118. package/runtimes/copilot/agents/jdi-researcher.agent.md +269 -0
  119. package/runtimes/copilot/copilot-instructions.md +80 -0
  120. package/runtimes/copilot/prompts/jdi-adopt.prompt.md +155 -0
  121. package/runtimes/copilot/prompts/jdi-bootstrap.prompt.md +81 -0
  122. package/runtimes/copilot/prompts/jdi-create.prompt.md +80 -0
  123. package/runtimes/copilot/prompts/jdi-discuss.prompt.md +80 -0
  124. package/runtimes/copilot/prompts/jdi-do.prompt.md +200 -0
  125. package/runtimes/copilot/prompts/jdi-loop.prompt.md +315 -0
  126. package/runtimes/copilot/prompts/jdi-new.prompt.md +131 -0
  127. package/runtimes/copilot/prompts/jdi-plan.prompt.md +73 -0
  128. package/runtimes/copilot/prompts/jdi-ship.prompt.md +146 -0
  129. package/runtimes/copilot/prompts/jdi-verify.prompt.md +159 -0
  130. package/runtimes/opencode/AGENTS.md +87 -0
  131. package/runtimes/opencode/agents/jdi-adopter.md +434 -0
  132. package/runtimes/opencode/agents/jdi-architect.md +861 -0
  133. package/runtimes/opencode/agents/jdi-asker.md +123 -0
  134. package/runtimes/opencode/agents/jdi-bootstrap.md +217 -0
  135. package/runtimes/opencode/agents/jdi-planner.md +225 -0
  136. package/runtimes/opencode/agents/jdi-researcher.md +273 -0
  137. package/runtimes/opencode/commands/jdi-adopt.md +155 -0
  138. package/runtimes/opencode/commands/jdi-bootstrap.md +81 -0
  139. package/runtimes/opencode/commands/jdi-create.md +80 -0
  140. package/runtimes/opencode/commands/jdi-discuss.md +80 -0
  141. package/runtimes/opencode/commands/jdi-do.md +200 -0
  142. package/runtimes/opencode/commands/jdi-loop.md +315 -0
  143. package/runtimes/opencode/commands/jdi-new.md +131 -0
  144. package/runtimes/opencode/commands/jdi-plan.md +73 -0
  145. package/runtimes/opencode/commands/jdi-ship.md +146 -0
  146. package/runtimes/opencode/commands/jdi-verify.md +159 -0
  147. package/runtimes/opencode/opencode.example.jsonc +169 -0
  148. package/runtimes/opencode/skills/clean-code/SKILL.md +247 -0
  149. package/runtimes/opencode/skills/dry/SKILL.md +136 -0
  150. package/runtimes/opencode/skills/frontend-rules/SKILL.md +369 -0
  151. package/runtimes/opencode/skills/frontend-validator/SKILL.md +553 -0
  152. package/runtimes/opencode/skills/kiss/SKILL.md +164 -0
  153. package/runtimes/opencode/skills/solid/SKILL.md +267 -0
  154. package/runtimes/opencode/skills/yagni/SKILL.md +193 -0
  155. package/templates-jdi-folder/config.json +18 -0
  156. package/templates-jdi-folder/registry.md +31 -0
  157. package/templates-jdi-folder/reviewers.md +33 -0
  158. package/templates-jdi-folder/skills-registry.md +32 -0
  159. package/templates-jdi-folder/specialists.md +39 -0
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: kiss
3
+ description: KISS (Keep It Simple, Stupid). The simplest solution that solves the problem wins. Complexity only justified by real measured pain. Each layer/abstraction must pay its own cost. Applies in any language.
4
+ type: skill
5
+ applies_to: |
6
+ Loaded by doer when designing a new feature/module.
7
+ Loaded by reviewer at gate 5 to detect over-engineering.
8
+ loaded_by:
9
+ - jdi-doer-{slug}
10
+ - jdi-reviewer-{slug}
11
+ runtime_overrides:
12
+ antigravity:
13
+ triggers:
14
+ - "KISS"
15
+ - "keep simple"
16
+ - "over-engineering"
17
+ - "simplicity"
18
+ ---
19
+
20
+ # Skill: KISS
21
+
22
+ > Simplicity is the best design. Every complexity must pay its own cost.
23
+
24
+ KISS is not "dumb code". It's **rejecting unjustified complexity**. Every interface, every layer, every abstraction has maintenance cost — only worth it if it solves real pain.
25
+
26
+ ## Rules
27
+
28
+ ### 1. Default is the simplest
29
+
30
+ Ask before adding:
31
+ - **Function** vs class vs framework?
32
+ - **Variable** vs config vs feature flag?
33
+ - **If/else** vs strategy pattern vs plugin system?
34
+ - **Sync** vs async vs queue vs event bus?
35
+ - **Inline** vs helper vs lib?
36
+
37
+ Start with the leftmost. Only step up if there is a real requirement.
38
+
39
+ ### 2. Complexity must justify pain
40
+
41
+ **Allowed:**
42
+ - New pattern if it has 3+ real cases using it
43
+ - Abstraction layer if it has 2+ implementations that exist today
44
+ - Cache if measurement shows hot path
45
+ - Async if there's unacceptable latency synchronous
46
+ - Plugin system if there are confirmed external extenders
47
+
48
+ **Forbidden:**
49
+ - "Will scale later" without current requirement
50
+ - "Other people might need it" without other people
51
+ - "To make it generic" without 2nd use case
52
+ - "Will look cleaner" trading 5 clear lines for 50 elegant ones
53
+ - Enterprise pattern in small codebase (Repository + UoW + Mediator + CQRS for 10-controller app)
54
+
55
+ ### 3. Cognitive load is a real metric
56
+
57
+ Code you read 10x and write 1x. Optimize for reading:
58
+ - **Named variables** > composite expression
59
+ - **Early return** > nested if/else
60
+ - **Linear function** > jumps between callbacks
61
+ - **Explicit types** > magical inference in large codebase
62
+ - **Simple procedural code** > fancy OOP for 50 lines
63
+
64
+ Rule: code that needs a comment explaining "why so complex" is too complex.
65
+
66
+ ### 4. Indicators of over-engineering
67
+
68
+ Signs the code went over the line:
69
+
70
+ - Interface with 1 implementation
71
+ - Factory/Builder for something instantiated 1x
72
+ - Generic <T> only used with 1 type
73
+ - Config with a key that never changed
74
+ - Abstraction layer that only encapsulates a call to another layer (pass-through)
75
+ - Inheritance hierarchy > 2 levels
76
+ - File with more setup than logic
77
+ - Test that needs 30 lines of mock to run 5 lines of logic
78
+
79
+ ### 5. Refactor is the opposite direction
80
+
81
+ Natural tendency: code grows in complexity. Refactoring = REMOVE complexity that no longer pays.
82
+
83
+ Ask:
84
+ - Does this layer still exist to solve a problem, or did it become tradition?
85
+ - Does this abstraction have 2+ implementations today?
86
+ - If I delete this, what breaks?
87
+ - Can I solve it with 5 lines instead of 50?
88
+
89
+ ## Anti-patterns
90
+
91
+ | Anti-pattern | Symptom |
92
+ |---|---|
93
+ | Interface + 1 implementation | `IUserService` + `UserService` (only 1) — delete the interface, use the class |
94
+ | Generic `<T>` used with 1 type | `Repository<User>` but never `Repository<Order>` — concretize |
95
+ | Factory for new() | `UserFactory.create()` that only does `return new User()` |
96
+ | Config string that never changed | `MAX_RETRIES: 3` in config + nobody ever changed it — hardcode |
97
+ | Inheritance > 2 levels | `BaseEntity -> AuditableEntity -> SoftDeletableEntity -> User` — flatten via composition |
98
+ | Pass-through layer | `Controller -> Service -> Repository -> DbContext` where Service only calls Repository without logic — delete Service |
99
+ | Enterprise pattern without demand | Mediator/CQRS in small app — replace with direct call |
100
+ | Comment explaining "why so complex" | Code lost the war — refactor |
101
+ | Mock setup > logic test | Test gets fragile; code under test is over-coupled |
102
+ | Unused future-proof params | `(opts?: { future?: boolean })` without caller passing — remove |
103
+
104
+ ## Procedure
105
+
106
+ ### Doer (before writing)
107
+
108
+ 1. Ask: "What is the **simplest** version that meets the current requirement?"
109
+ 2. Write that version.
110
+ 3. Only step up complexity if you hit real pain.
111
+ 4. After writing, ask: "Can I delete any layer/parameter/abstraction without losing functionality?"
112
+
113
+ ### Reviewer (gate 5)
114
+
115
+ Over-engineering heuristics:
116
+
117
+ ```bash
118
+ # Interfaces with 1 implementation
119
+ grep -RnE '^(public |export )?interface I?[A-Z]\w+' src/ | while read iface; do
120
+ name=$(echo "$iface" | grep -oE '[A-Z]\w+\b' | head -1)
121
+ count=$(grep -RnE "class \w+\s*:\s*$name|implements $name" src/ | wc -l)
122
+ [[ $count -eq 1 ]] && echo "WARN: $iface has only 1 implementation"
123
+ done
124
+
125
+ # Deep inheritance (> 2 levels)
126
+ # (depends on stack — specific heuristic)
127
+
128
+ # Very large or nested functions
129
+ grep -cE '^\s{20,}\S' src/**/* # lines with 20+ spaces = deep nesting
130
+ ```
131
+
132
+ Match -> WARN with suggestion to simplify.
133
+
134
+ ## Inputs
135
+
136
+ - Diff/content of the file
137
+ - Context: codebase size (over-engineering is relative)
138
+
139
+ ## Outputs
140
+
141
+ Does NOT produce a file. Modifies judgement.
142
+
143
+ ## Examples
144
+
145
+ ### Example 1: Interface with 1 impl
146
+
147
+ Wrong:
148
+ ```typescript
149
+ interface ILogger { log(msg: string): void }
150
+ class ConsoleLogger implements ILogger { log(msg) { console.log(msg) } }
151
+ const logger: ILogger = new ConsoleLogger()
152
+ ```
153
+
154
+ Right (KISS):
155
+ ```typescript
156
+ function log(msg: string) { console.log(msg) }
157
+ // or
158
+ class Logger { static log(msg: string) { console.log(msg) } }
159
+ ```
160
+
161
+ Add interface when 2nd impl arrives, not before.
162
+
163
+ ### Example 2: Pass-through service
164
+
165
+ Wrong:
166
+ ```csharp
167
+ public class UserService {
168
+ public User GetById(int id) => _repo.GetById(id); // only calls repo
169
+ }
170
+ ```
171
+
172
+ Right: use `_repo` directly in the controller. Add Service when there is real logic (validation, multi-step, transaction, event).
173
+
174
+ ### Example 3: Hardcodable config
175
+
176
+ Wrong: `appsettings.json -> "MaxItemsPerPage": 50` that nobody ever changed in 2 years.
177
+
178
+ Right: `const MAX_ITEMS_PER_PAGE = 50` in the code. Move back to config if some client actually needs to customize.
@@ -0,0 +1,281 @@
1
+ ---
2
+ name: solid
3
+ description: SOLID. Robert C. Martin's 5 OO design principles - SRP, OCP, LSP, ISP, DIP. Applicable in any language with types/classes/interfaces (C#, Java, TS, Python, Go, Rust, Kotlin, Swift, etc). Direct summary + anti-patterns + detection heuristics.
4
+ type: skill
5
+ applies_to: |
6
+ Loaded by doer when designing classes/modules/interfaces.
7
+ Loaded by reviewer at gate 5 to detect structural violations.
8
+ loaded_by:
9
+ - jdi-doer-{slug}
10
+ - jdi-reviewer-{slug}
11
+ runtime_overrides:
12
+ antigravity:
13
+ triggers:
14
+ - "SOLID"
15
+ - "SOLID principles"
16
+ - "SRP OCP LSP ISP DIP"
17
+ - "OO design"
18
+ ---
19
+
20
+ # Skill: SOLID
21
+
22
+ 5 design principles — **S**ingle Responsibility, **O**pen/Closed, **L**iskov Substitution, **I**nterface Segregation, **D**ependency Inversion.
23
+
24
+ Applicable in any language with classes or interfaces. In FP/procedural, principles map to modules and functions (SRP: 1 function 1 responsibility; ISP: minimal parameters; DIP: dependency injection via parameter).
25
+
26
+ ## S - Single Responsibility Principle (SRP)
27
+
28
+ > A class/module must have **1 reason to change**.
29
+
30
+ **1 reason = 1 stakeholder or 1 axis of change**, not "1 action".
31
+
32
+ `UserService` that does auth + persistence + sends email violates — there are 3 reasons to change (security team changes auth, DBA changes persistence, marketing changes email).
33
+
34
+ ### Violation symptoms
35
+ - Class with generic name (`Manager`, `Helper`, `Service`, `Util`)
36
+ - Methods without thematic coherence
37
+ - Multiple imports of unrelated libraries (DB + email + crypto in the same class)
38
+ - Diff of one class affects separate domains in different sprints
39
+
40
+ ### Fix
41
+ Extract responsibilities into separate classes:
42
+ - `UserAuthenticator` (auth)
43
+ - `UserRepository` (persistence)
44
+ - `UserNotifier` (email)
45
+
46
+ Compose in a coordinator if needed, but each piece has 1 reason.
47
+
48
+ ## O - Open/Closed Principle (OCP)
49
+
50
+ > Open for **extension**, closed for **modification**.
51
+
52
+ Adding new behavior shouldn't require editing tested code. Use polymorphism, strategy, plugins, or config — not infinite if/else.
53
+
54
+ ### Violation symptoms
55
+ - `switch (type)` that grows with every new feature
56
+ - `if (provider === "x") ... else if ... else if ...`
57
+ - Each new feature edits N existing classes instead of adding 1 new one
58
+
59
+ ### Fix
60
+ - **Strategy pattern**: each case becomes an impl of an interface
61
+ - **Polymorphism**: subclass override instead of external switch
62
+ - **Registry**: `registry.register("x", handler)` — new feature just adds
63
+ - **Visitor**: for closed type hierarchies
64
+
65
+ ### When to ignore
66
+ OCP is aspirational, not absolute. Apply at points of **known** variation (payment strategies are multiple), don't speculate (KISS + YAGNI).
67
+
68
+ ## L - Liskov Substitution Principle (LSP)
69
+
70
+ > Subtype must be **substitutable** for the supertype without breaking behavior.
71
+
72
+ If `Bird` has method `fly()`, `Penguin extends Bird` violates LSP — penguin doesn't fly. Caller receiving `Bird` breaks when it receives `Penguin`.
73
+
74
+ ### Violation symptoms
75
+ - Subclass that **throws exception** on inherited method ("not supported")
76
+ - Subclass that **strengthens precondition** (`base accepts >= 0`, sub accepts `> 0`)
77
+ - Subclass that **weakens postcondition** (base guarantees "sorted", sub doesn't guarantee)
78
+ - Caller needs `if (instanceof Subtype)` to handle a special case
79
+
80
+ ### Fix
81
+ - Rethink hierarchy: `Penguin` isn't a flying `Bird`, it's a `Bird` that walks. Create `FlyingBird : Bird` and `Penguin : Bird` without fly.
82
+ - Composition over inheritance: prefer composed interfaces over deep hierarchies.
83
+ - Refactor to capabilities: `Flyable`, `Swimmable`, `Walkable` (overlap with ISP).
84
+
85
+ ## I - Interface Segregation Principle (ISP)
86
+
87
+ > Clients should not be forced to depend on interfaces they **do not use**.
88
+
89
+ Big interfaces ("fat interfaces") force impls to stub meaningless methods (throwing NotImplemented), and callers to import broad dependencies.
90
+
91
+ ### Violation symptoms
92
+ - Interface with 15 methods, each caller uses 2-3
93
+ - Impl with several methods throwing `throw new NotImplementedException()`
94
+ - Huge test mock to use 1 method of the interface
95
+
96
+ ### Fix
97
+ Split into smaller, cohesive interfaces:
98
+ ```
99
+ IFileReader { read() }
100
+ IFileWriter { write() }
101
+ // callers pick the subset they need
102
+ ```
103
+
104
+ In FP/Go, same principle: minimal parameters, structural typing doesn't force implementing everything.
105
+
106
+ ## D - Dependency Inversion Principle (DIP)
107
+
108
+ > High-level modules **do not** depend on low-level. Both depend on **abstractions**.
109
+
110
+ Business logic doesn't care about "PostgreSQL", "AWS S3", "SendGrid". It cares about abstractions (`UserRepository`, `BlobStorage`, `EmailSender`). Concrete implementations live in outer layers.
111
+
112
+ ### Violation symptoms
113
+ - Domain class imports `pg`, `aws-sdk`, `sendgrid`, `axios`
114
+ - Business logic testable only with real infra (DB up, S3 mocked, etc)
115
+ - Swapping provider requires rewriting business logic
116
+
117
+ ### Fix
118
+ - **Dependency injection** (constructor / property / parameter)
119
+ - Define interfaces in the domain module; impls live in infra/adapter layer (overlap with Hexagonal/Clean Architecture)
120
+ - Composition root injects the right impl
121
+
122
+ ### DIP != IoC container
123
+ DIP is a principle. IoC container is **one** tool. You can apply DIP with manual constructor, simple factory, or parameter injection — no framework.
124
+
125
+ ## Summary of the 5
126
+
127
+ | Letter | Focus | Key question |
128
+ |---|---|---|
129
+ | **S** | Unit cohesion | How many reasons to change this class/module? (>1 = violates) |
130
+ | **O** | Stability against extension | Does adding a new feature edit tested code or add new code? |
131
+ | **L** | Inheritance contract | Does replacing parent with child break any caller? |
132
+ | **I** | Interface size | Does every impl/caller use all methods? |
133
+ | **D** | Direction of dependency | Does domain import infra or does infra import domain? |
134
+
135
+ ## General anti-patterns
136
+
137
+ | Anti-pattern | Principle violated |
138
+ |---|---|
139
+ | `God class` with 30+ heterogeneous methods | SRP |
140
+ | `switch (kind)` in N callers, grows with each feature | OCP |
141
+ | Subclass with `throw NotSupportedException()` | LSP |
142
+ | `IRepository` with 20 generic methods | ISP |
143
+ | Domain service importing concrete ORM | DIP |
144
+ | Inheritance > 3 levels | LSP + SRP (usually) |
145
+ | Constructor with 8+ parameters | SRP (too many responsibilities) |
146
+ | Util class with 50 unrelated functions | SRP |
147
+
148
+ ## Procedure
149
+
150
+ ### Doer
151
+
152
+ Before creating class/module/interface:
153
+ - **SRP**: describe in 1 sentence. If you need "and", split.
154
+ - **ISP**: list expected callers. Does each one need **all** methods? If not, split.
155
+ - **DIP**: what does this depend on? Concretions (DB, HTTP, FS) -> inject as abstraction.
156
+
157
+ Before subclassing:
158
+ - **LSP**: does substitution by parent work in all callers? If not, wrong hierarchy.
159
+
160
+ Before adding `if/switch` at a growing point:
161
+ - **OCP**: is strategy/registry worth it?
162
+
163
+ ### Reviewer (gate 5)
164
+
165
+ ```bash
166
+ # SRP — very large classes
167
+ find src/ -name '*.cs' -o -name '*.ts' -o -name '*.py' | while read f; do
168
+ loc=$(wc -l < "$f")
169
+ [[ $loc -gt 400 ]] && echo "WARN SRP: $f has $loc lines, possible god class"
170
+ done
171
+
172
+ # OCP — big switches on hot paths
173
+ grep -RnE 'switch\s*\(' src/ | head
174
+ # (manually: evaluate if it grows with each feature)
175
+
176
+ # LSP — NotImplemented in subclass
177
+ grep -RnE 'NotImplemented|UnsupportedOperation|throw new.*not (implemented|supported)' src/
178
+
179
+ # ISP — giant interfaces
180
+ grep -RnA50 '^(public |export )?interface' src/ | grep -cE '^\s+\w+\s*\(' | sort -rn
181
+ # count > 10 methods -> WARN
182
+
183
+ # DIP — domain module importing concretions
184
+ grep -RnE 'from.*pg|from.*aws-sdk|using Npgsql|using AWSSDK' src/domain/ src/core/
185
+ ```
186
+
187
+ Relevant match -> WARN with principle cited.
188
+
189
+ ## Inputs
190
+
191
+ - Diff/content of the file
192
+ - Project structure (to detect domain vs infra)
193
+
194
+ ## Outputs
195
+
196
+ Does NOT produce a file. Modifies judgement.
197
+
198
+ ## Examples
199
+
200
+ ### Example 1: SRP violated
201
+
202
+ Wrong:
203
+ ```csharp
204
+ public class OrderService {
205
+ public Order Create(...) { /* validate + save + email + log + audit */ }
206
+ }
207
+ ```
208
+
209
+ 5 reasons to change.
210
+
211
+ Right:
212
+ ```csharp
213
+ public class OrderValidator { }
214
+ public class OrderRepository { }
215
+ public class OrderNotifier { }
216
+ public class OrderService {
217
+ public Order Create(...) {
218
+ _validator.Validate(...)
219
+ var order = _repo.Save(...)
220
+ _notifier.Notify(order)
221
+ return order;
222
+ }
223
+ }
224
+ ```
225
+
226
+ ### Example 2: OCP violated
227
+
228
+ Wrong:
229
+ ```typescript
230
+ function calcDiscount(type: string, amount: number) {
231
+ if (type === "vip") return amount * 0.2
232
+ else if (type === "newcomer") return amount * 0.1
233
+ else if (type === "blackfriday") return amount * 0.5
234
+ return 0
235
+ }
236
+ ```
237
+
238
+ Each new type edits this function.
239
+
240
+ Right:
241
+ ```typescript
242
+ const strategies: Record<string, (amount: number) => number> = {
243
+ vip: a => a * 0.2,
244
+ newcomer: a => a * 0.1,
245
+ blackfriday: a => a * 0.5,
246
+ }
247
+ function calcDiscount(type: string, amount: number) {
248
+ return strategies[type]?.(amount) ?? 0
249
+ }
250
+ ```
251
+
252
+ New type: register in `strategies`, don't touch `calcDiscount`.
253
+
254
+ ### Example 3: DIP violated
255
+
256
+ Wrong:
257
+ ```python
258
+ # domain/order.py
259
+ import psycopg2
260
+ class OrderService:
261
+ def get(self, id):
262
+ conn = psycopg2.connect(...)
263
+ ...
264
+ ```
265
+
266
+ Domain coupled to Postgres.
267
+
268
+ Right:
269
+ ```python
270
+ # domain/order.py
271
+ class OrderService:
272
+ def __init__(self, repo: OrderRepository): # abstraction
273
+ self._repo = repo
274
+ def get(self, id): return self._repo.get(id)
275
+
276
+ # infra/postgres_order_repo.py
277
+ class PostgresOrderRepository(OrderRepository):
278
+ def get(self, id): ... # concrete impl
279
+ ```
280
+
281
+ Domain doesn't know Postgres exists.
@@ -0,0 +1,207 @@
1
+ ---
2
+ name: yagni
3
+ description: YAGNI (You Aren't Gonna Need It). Build only what the current requirement asks for. Generalize after the 3rd real case, never before. Code not written is code with no bug, no maintenance cost, no pending test. Applies in any language.
4
+ type: skill
5
+ applies_to: |
6
+ Loaded by doer when planning implementation.
7
+ Loaded by reviewer at gate 5 to detect speculative code.
8
+ loaded_by:
9
+ - jdi-doer-{slug}
10
+ - jdi-reviewer-{slug}
11
+ runtime_overrides:
12
+ antigravity:
13
+ triggers:
14
+ - "YAGNI"
15
+ - "speculative code"
16
+ - "future-proof"
17
+ - "premature abstraction"
18
+ ---
19
+
20
+ # Skill: YAGNI
21
+
22
+ > You aren't gonna need it.
23
+
24
+ YAGNI is discipline against **speculative code**: features, abstractions, parameters, hooks, layers, configs that exist "in case it's needed". In 90% of cases, never needed — and when needed, the requirement is different from what you imagined.
25
+
26
+ ## Rules
27
+
28
+ ### 1. Build only what the current requirement asks
29
+
30
+ Ask of every new line of code:
31
+ - **Does this functionality have a requirement today?**
32
+ - **Who is the caller that needs this NOW?**
33
+
34
+ If there's no real caller, don't write it. Dead code is **net negative**: latent bug, maintenance cost, distraction in review, hinders refactor.
35
+
36
+ ### 2. Generalize after the 3rd real case
37
+
38
+ Sandi Metz: "Duplication is far cheaper than the wrong abstraction."
39
+
40
+ - 1 case: implement specific
41
+ - 2 cases: copy or minimally parameterize
42
+ - 3 cases: now extract real pattern (one you **saw** happen, not imagined)
43
+
44
+ Generalizing earlier couples callers to the wrong interface. Refactoring later to the right interface is cheap; breaking callers to swap a wrong generic interface is expensive.
45
+
46
+ ### 3. Costs of speculative code
47
+
48
+ Every "in case it's needed" line costs:
49
+
50
+ - **Maintenance**: someone will touch it when refactoring the neighborhood
51
+ - **Confusion**: reader thinks "this is being used, must be important"
52
+ - **Tests**: untested code becomes a bomb; tested, wasted time
53
+ - **Coupling**: callers will couple to the speculative interface, making it hard to remove
54
+ - **Scope creep**: simple feature becomes complex feature
55
+ - **Bug surface**: a line that doesn't exist has no bug
56
+
57
+ ### 4. What YAGNI is NOT
58
+
59
+ YAGNI is not an excuse to:
60
+ - **Hardcoded everywhere**: some extension points are real requirements (i18n, logging, auth)
61
+ - **Cut real requirement**: if ticket asks for X, deliver X complete, not half
62
+ - **Skip security/error handling**: these are universal requirements, not speculative
63
+ - **Raw illegible code**: clarity is a requirement, not speculation
64
+ - **Skip tests**: coverage is a contract
65
+
66
+ ### 5. Symptoms of violation
67
+
68
+ Code smells of broken YAGNI if:
69
+
70
+ - Optional parameters never passed (`fn(a, b, opts?: {...})` with opts always `undefined`)
71
+ - Hooks/events without subscribers
72
+ - Plugin system without plugins
73
+ - Config "in case we want to change" that nobody ever changed
74
+ - Interface with 1 impl (overlap with KISS)
75
+ - Generic `<T>` used with only 1 type
76
+ - "Future-proof" architecture written to scale 100x before validating current requirement
77
+ - Branches in code for scenarios nobody can describe
78
+
79
+ ### 6. How to remove
80
+
81
+ After discovering speculative code:
82
+ 1. Confirm nobody calls (`grep` callers)
83
+ 2. Delete. Yes, delete directly. Git keeps history.
84
+ 3. Don't leave "// removed on XX/YY" — more trash.
85
+ 4. If you find out later you need it, add it when you need it (safe bet: later you know the real requirement, not imagined).
86
+
87
+ ## Anti-patterns
88
+
89
+ | Anti-pattern | Why it violates |
90
+ |---|---|
91
+ | Optional parameter never used | Adds surface area without benefit |
92
+ | "Generic" function used by 1 caller | Generalized too early |
93
+ | Plugin/extension point without extenders | Dead code carries maintenance |
94
+ | "Configurable" config nobody changes | False flexibility — becomes hardcode later |
95
+ | Try/catch for impossible exception | Indicates fear, not requirement |
96
+ | Defensive validation for value coming from a safe type | TypeScript/C#/Python types already guarantee |
97
+ | `for/while` instead of direct return for "future looping" | Invents speculative repetition |
98
+ | Layer "to make it generic" without 2nd impl | Speculation with pass-through cost |
99
+ | Comment "TODO: extend to X later" without ticket | Message to nobody |
100
+ | Abstraction with 1 concrete implementation | Generic abstraction without second case |
101
+ | `enum` with 1 value "will grow" | Add value when it appears |
102
+
103
+ ## Procedure
104
+
105
+ ### Doer (before/during implementation)
106
+
107
+ Before adding:
108
+
109
+ 1. **Is there a current requirement?** (ticket, conversation, explicit business rule) Otherwise, don't add.
110
+ 2. **Who calls this today?** If nobody, don't add.
111
+ 3. **When will I use that flexibility?** If "don't know", don't add.
112
+
113
+ After writing, ask:
114
+ - Is there a parameter/config/branch that could disappear without losing requirement?
115
+
116
+ ### Reviewer (gate 5)
117
+
118
+ Heuristics:
119
+
120
+ ```bash
121
+ # Optional parameters never passed
122
+ # (depends on stack — examples)
123
+ grep -RnE 'function \w+\([^)]*opts\?:' src/ # TS
124
+ grep -RnE '\([^)]*=\s*null\)' src/ # optional default null
125
+
126
+ # "TODO: extend" code
127
+ grep -RnE 'TODO.*(extend|future|reserved|placeholder|in case)' src/
128
+
129
+ # Try/catch without clear reason
130
+ grep -RnA3 'try\s*{' src/ | grep -B1 'catch.*:.*ignore'
131
+
132
+ # Declared and unused variables
133
+ # (linter already catches — confirm in review)
134
+
135
+ # Plugin/extension points
136
+ grep -RnE 'register|registerPlugin|EventEmitter|hook(' src/
137
+ # Cross-check: are there actually callers?
138
+ ```
139
+
140
+ 3+ matches without real caller -> WARN.
141
+
142
+ ## Inputs
143
+
144
+ - File diff (focus on additions)
145
+ - List of callers if any
146
+
147
+ ## Outputs
148
+
149
+ Does NOT produce a file. Modifies judgement — doer avoids writing, reviewer marks WARN.
150
+
151
+ ## Examples
152
+
153
+ ### Example 1: Speculative optional param
154
+
155
+ Wrong:
156
+ ```python
157
+ def send_email(to: str, subject: str, body: str,
158
+ cc: list[str] = None,
159
+ bcc: list[str] = None,
160
+ attachments: list[Path] = None,
161
+ priority: str = "normal",
162
+ retry_count: int = 3,
163
+ on_failure: Callable = None):
164
+ ...
165
+ ```
166
+
167
+ Current requirement is to send simple email (`to, subject, body`). The other 5 params are speculative.
168
+
169
+ Right:
170
+ ```python
171
+ def send_email(to: str, subject: str, body: str):
172
+ ...
173
+ ```
174
+
175
+ Add `cc`, `bcc` etc **when** real requirement arrives, not before.
176
+
177
+ ### Example 2: Plugin system without plugins
178
+
179
+ Wrong:
180
+ ```typescript
181
+ class PaymentProcessor {
182
+ private plugins: Plugin[] = []
183
+ registerPlugin(p: Plugin) { this.plugins.push(p) }
184
+ process(...) {
185
+ this.plugins.forEach(p => p.beforeProcess())
186
+ // logic
187
+ this.plugins.forEach(p => p.afterProcess())
188
+ }
189
+ }
190
+ ```
191
+
192
+ Has 0 plugins registered. Whole plugin system is dead code.
193
+
194
+ Right:
195
+ ```typescript
196
+ class PaymentProcessor {
197
+ process(...) { /* logic */ }
198
+ }
199
+ ```
200
+
201
+ When the 1st real plugin appears, then yes. Not before.
202
+
203
+ ### Example 3: Unused config string
204
+
205
+ Wrong: `config.json -> "DEFAULT_LANGUAGE": "pt-BR"` but nobody reads it. Code uses `"pt-BR"` directly.
206
+
207
+ Right: delete the config. Add it when the multi-language feature is actually implemented.