opencode-skills-collection 3.0.27 → 3.0.29

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 (30) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +16 -1
  2. package/bundled-skills/bumblebee/SKILL.md +186 -0
  3. package/bundled-skills/bumblebee/scripts/render_report.py +362 -0
  4. package/bundled-skills/complexity-cuts/SKILL.md +254 -0
  5. package/bundled-skills/decision-navigator/SKILL.md +238 -0
  6. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  7. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  8. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  9. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  10. package/bundled-skills/docs/users/bundles.md +1 -1
  11. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  12. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  13. package/bundled-skills/docs/users/getting-started.md +1 -1
  14. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  15. package/bundled-skills/docs/users/usage.md +4 -4
  16. package/bundled-skills/docs/users/visual-guide.md +4 -4
  17. package/bundled-skills/flowhunt-skill/SKILL.md +141 -0
  18. package/bundled-skills/geminiignore-finops/SKILL.md +173 -0
  19. package/bundled-skills/ii-commons/SKILL.md +110 -0
  20. package/bundled-skills/invariant-guard/SKILL.md +307 -0
  21. package/bundled-skills/lemmaly/SKILL.md +236 -0
  22. package/bundled-skills/mathguard/SKILL.md +269 -0
  23. package/bundled-skills/mesh-memory/SKILL.md +161 -0
  24. package/bundled-skills/sendblue/sendblue-api/SKILL.md +194 -0
  25. package/bundled-skills/sendblue/sendblue-cli/SKILL.md +145 -0
  26. package/bundled-skills/sendblue/sendblue-notify/SKILL.md +173 -0
  27. package/bundled-skills/sendblue/textme/SKILL.md +232 -0
  28. package/bundled-skills/socialclaw/SKILL.md +107 -0
  29. package/package.json +1 -1
  30. package/skills_index.json +330 -0
@@ -0,0 +1,307 @@
1
+ ---
2
+ name: invariant-guard
3
+ description: "Correctness-first: forces writing the function contract, loop invariant, termination argument, and edge cases BEFORE code. Catches Boyer-Moore, leftmost binary search, QuickSelect traps."
4
+ risk: safe
5
+ source: community
6
+ source_repo: morsechimwai/lemmaly
7
+ source_type: community
8
+ date_added: "2026-05-26"
9
+ author: morsechimwai
10
+ tags: [algorithms, correctness, loop-invariants, contracts, edge-cases, verification]
11
+ tools: [claude-code, antigravity, cursor, gemini-cli, codex-cli]
12
+ license: "Apache-2.0"
13
+ license_source: "https://github.com/morsechimwai/lemmaly/blob/main/LICENSE"
14
+ ---
15
+
16
+ # invariant-guard — Correctness-First Coding
17
+
18
+ The model knows what a loop invariant is. It knows recursion needs a base case. It knows about empty lists, integer overflow, and the difference between `<` and `≤`. It just does not write these down before producing code, so it ships subtle correctness bugs that tests do not catch.
19
+
20
+ invariant-guard fixes the behavior. State the invariants. State the base case. State the termination argument. State the edge cases. Then write the code — and verify that the code maintains what you stated.
21
+
22
+ **Violating the letter of these rules is violating the spirit of the skill.** "I know this algorithm" is the exact rationalization that ships off-by-one and missing-postcondition bugs.
23
+
24
+ ## When to Use This Skill
25
+
26
+ Use **invariant-guard** when writing or reviewing algorithms where the obvious implementation is subtly wrong:
27
+
28
+ - Postcondition stronger than the loop's natural invariant: Boyer–Moore majority, Floyd's cycle detection, leftmost vs any binary search, QuickSelect partition.
29
+ - In-place mutation with read+write pointers: dedup-in-place, partition, rotate.
30
+ - Recursion with multiple parameters or accumulator state.
31
+ - Off-by-one suspects with duplicates, empty inputs, boundary values.
32
+ - Iterative refinements that must terminate: fixed-point, Newton, EM.
33
+ - Any function where you catch yourself thinking "I know this algorithm" — the trap is usually in the contract, not the loop body.
34
+
35
+ Pairs with `lemmaly` (picks the algorithm) and `mathguard` (picks the math). Load `invariant-guard` *after* the algorithm has been chosen and *before* the loop body is written.
36
+
37
+ ## The Iron Law
38
+
39
+ ```text
40
+ NO LOOP OR RECURSION WITHOUT A WRITTEN INVARIANT AND TERMINATION ARGUMENT
41
+ ```
42
+
43
+ If you cannot write the invariant in one sentence, you have not designed the loop. Write code anyway and you are coding by guess — and the bug will be in the case you did not enumerate.
44
+
45
+ ## Non-negotiable rules
46
+
47
+ 1. **Every loop gets a one-line invariant.** Before writing any loop, state in one sentence what is true at the top of every iteration. Examples:
48
+ - "At loop top: `result` contains the sum of `a[0..i)`."
49
+ - "At loop top: `lo ≤ target_position ≤ hi`."
50
+ - "At loop top: `seen` contains every element processed so far; `dups` contains every element that appeared at least twice."
51
+
52
+ If you cannot write the invariant in one sentence, you have not designed the loop yet.
53
+
54
+ 2. **Every loop gets a one-line termination argument.** Name the quantity that strictly decreases (or strictly increases toward a bound) on every iteration. Examples:
55
+ - "`hi − lo` strictly decreases each iteration."
56
+ - "`i` increases by 1 and is bounded above by `n`."
57
+ - "`stack.length` strictly decreases each pop; nothing pushes inside this branch."
58
+
59
+ No termination argument, no loop.
60
+
61
+ 3. **Every recursion gets an explicit base case and a measure.** Before writing a recursive function, state:
62
+ - The base case(s) — the smallest inputs that return without recursing.
63
+ - The measure — a non-negative integer that strictly decreases on every recursive call (e.g. `len(xs)`, `hi − lo`, `depth`, `n`).
64
+ - The combination — how the recursive results combine into the answer.
65
+
66
+ No base case + measure, no recursion. (Mutual recursion: state the measure across the cycle.)
67
+
68
+ 4. **List edge cases before writing, not after.** For every function operating on a collection or number, list which of these apply and how they behave:
69
+ - Empty input (`[]`, `""`, `null`, `undefined`, `None`).
70
+ - Singleton (`[x]`).
71
+ - All-equal elements.
72
+ - Already-sorted / reverse-sorted input.
73
+ - Duplicates (when uniqueness is assumed).
74
+ - Negative numbers, zero, exactly the boundary value.
75
+ - Integer overflow / underflow at the type max/min.
76
+ - NaN, ±Infinity, `-0`, denormals (for floats).
77
+ - Off-by-one boundaries: index 0, index n−1, index n, length 0, length 1.
78
+ - Concurrent modification while iterating.
79
+
80
+ The cases that apply must each have a one-phrase expected behavior written down.
81
+
82
+ 5. **Make illegal states unreachable, not just unhandled.** Prefer encoding constraints in types and structure so the wrong state cannot be constructed:
83
+ - Sum type over boolean flag soup (`Loading | Loaded(data) | Error(msg)` not `{loading, data, error}`).
84
+ - Newtype for IDs that must not be swapped (`UserId` vs `OrderId`).
85
+ - Non-empty list type when the function requires at least one element.
86
+ - Parsed value at the boundary, not validated repeatedly downstream (parse-don't-validate).
87
+
88
+ If the language cannot encode it, write the invariant as a comment and assert it at the boundary.
89
+
90
+ ## The pre-write protocol
91
+
92
+ Before producing non-trivial code that has loops, recursion, or non-trivial state, your message must contain — in this order:
93
+
94
+ 1. **Function contract** — preconditions, postconditions, and what the function returns. One line each.
95
+ 2. **Loop invariants** — one per loop. (Rule 1.)
96
+ 3. **Termination arguments** — one per loop or recursion. (Rules 2, 3.)
97
+ 4. **Base cases and measure** — for recursion. (Rule 3.)
98
+ 5. **Edge case table** — bullets, one per applicable case, with expected behavior. (Rule 4.)
99
+ 6. **Illegal states made unrepresentable** — name the types or asserts that enforce invariants. (Rule 5.)
100
+ 7. **The code.**
101
+ 8. **Self-check** — one line per loop confirming the invariant holds at top, body preserves it, and exit implies postcondition.
102
+
103
+ If any of 1–6 is missing, do not emit code.
104
+
105
+ ## Worked trap — Boyer–Moore majority vote
106
+
107
+ This is the canonical "the trap is in the contract, not the loop body" case.
108
+
109
+ **Naive baseline (what gets shipped without the skill):**
110
+
111
+ ```typescript
112
+ function findMajority(arr: number[]): number | null {
113
+ if (arr.length === 0) return null;
114
+ let candidate = arr[0], count = 0;
115
+ for (const x of arr) {
116
+ if (count === 0) candidate = x;
117
+ if (x === candidate) count++; else count--;
118
+ }
119
+ return candidate; // BUG: returns the candidate even when no majority exists
120
+ }
121
+ ```
122
+
123
+ This implementation fails on `[1,2,3]` (returns `3`, expected `null`) and `[2,2,1,1]` (returns `1`, expected `null`). The voting loop is correct; the postcondition is wrong.
124
+
125
+ **Why the protocol catches it.** Writing **step 1 (function contract)** forces the postcondition in plain language:
126
+
127
+ > Returns `x` iff `count(x, arr) > arr.length / 2`; else `null`.
128
+
129
+ Then writing **step 2 (loop invariant)** forces the invariant of the voting pass:
130
+
131
+ > If a strict majority element exists in `arr`, it equals `candidate` when the loop exits.
132
+
133
+ These two statements are not equivalent. The loop invariant guarantees "if a majority exists, it is the candidate" — not "the candidate is a majority." Once you write both down, the gap is visible: you need a second pass to verify, or the postcondition is unmet.
134
+
135
+ **Correct implementation that survives the protocol:**
136
+
137
+ ```typescript
138
+ function findMajority(arr: number[]): number | null {
139
+ if (arr.length === 0) return null;
140
+ // Pass 1: vote.
141
+ let candidate = arr[0], count = 0;
142
+ // inv: if a strict majority exists in arr, it equals candidate at every count===0 reset.
143
+ for (const x of arr) {
144
+ if (count === 0) candidate = x;
145
+ if (x === candidate) count++; else count--;
146
+ }
147
+ // Pass 2: verify — the voting invariant is strictly weaker than the postcondition.
148
+ let tally = 0;
149
+ // inv: tally = count of candidate in arr[0..i).
150
+ for (const x of arr) if (x === candidate) tally++;
151
+ return tally * 2 > arr.length ? candidate : null;
152
+ }
153
+ ```
154
+
155
+ **Pattern to generalize.** The same trap appears in:
156
+
157
+ - **Floyd's cycle detection** — finding the meeting point tells you a cycle exists, *not* where it starts. You need a second walk.
158
+ - **Two-pointer "find any"** vs **"find leftmost"** — the loop invariant for one does not satisfy the postcondition of the other.
159
+ - **QuickSelect partition** — the loop returns a position; the postcondition is that the element at that position is the k-th smallest. Off by one in the partition invariant silently breaks it.
160
+ - **DP with reconstruction** — the table tells you the optimum value; reconstructing the optimum path needs separate invariants on the choice array.
161
+
162
+ In every case: **write the postcondition first; write the loop invariant second; check that the second implies the first. If not, you are missing a pass, a check, or an auxiliary state.**
163
+
164
+ ## Canonical example — binary search for the leftmost match
165
+
166
+ Most "I know binary search" implementations are written for "find any match." The trap is the postcondition.
167
+
168
+ **Problem.** Given a sorted array with duplicates, return the index of the **leftmost** occurrence of `target`, or `-1`.
169
+
170
+ ### Without the protocol — returns any match
171
+
172
+ ```ts
173
+ function leftmost(a: number[], target: number): number {
174
+ let lo = 0, hi = a.length - 1;
175
+ while (lo <= hi) {
176
+ const mid = (lo + hi) >> 1;
177
+ if (a[mid] === target) return mid; // returns ANY occurrence
178
+ if (a[mid] < target) lo = mid + 1; else hi = mid - 1;
179
+ }
180
+ return -1;
181
+ }
182
+ // leftmost([1,2,2,2,3], 2) → may return 2, not 1
183
+ ```
184
+
185
+ The loop invariant ("target lies in `a[lo..hi]` if anywhere") is satisfied. But the postcondition ("returned index is the *smallest* `i` with `a[i] === target`") is strictly stronger. The loop body's early return abandons the search before reaching the leftmost.
186
+
187
+ ### With the protocol — contract-driven leftmost
188
+
189
+ ```ts
190
+ function leftmost(a: number[], target: number): number {
191
+ // contract:
192
+ // pre: a is sorted ascending
193
+ // post: returns smallest i with a[i] === target, or -1 if absent
194
+ let lo = 0, hi = a.length; // half-open [lo, hi)
195
+ // inv: every index < lo has a[i] < target; every index ≥ hi has a[i] > target OR is past leftmost match
196
+ // term: hi - lo strictly halves each iteration
197
+ while (lo < hi) {
198
+ const mid = (lo + hi) >> 1;
199
+ if (a[mid] < target) lo = mid + 1; else hi = mid;
200
+ }
201
+ // exit: lo === hi, and by invariant lo is the leftmost index where a[lo] >= target
202
+ return lo < a.length && a[lo] === target ? lo : -1;
203
+ }
204
+ ```
205
+
206
+ Same loop shape. The difference is the contract was written first — and the loop body was chosen to maintain an invariant that *implies* the postcondition.
207
+
208
+ ## Common invariant patterns to reach for
209
+
210
+ | Loop / algorithm shape | Canonical invariant | Termination |
211
+ |---|---|---|
212
+ | Linear scan accumulating | `acc = f(a[0..i))` at top | `i` increases by 1, bounded by `n` |
213
+ | Two-pointer (sorted) | `target (if any) lies in a[lo..hi]` | `hi − lo` strictly decreases |
214
+ | Binary search | `target (if present) ∈ a[lo..hi]` and `a[lo..hi]` non-empty | `hi − lo` strictly halves |
215
+ | Sliding window | window `[l..r)` satisfies the constraint; answer ≥ best so far | `r` advances at least once per outer iter |
216
+ | BFS | every node at distance < d has been popped; queue contains some at distance d | strict node count decrease per pop |
217
+ | DFS / recursion on tree | result for subtree rooted at v = combine(children results) | depth (or remaining nodes) strictly decreases |
218
+ | Divide and conquer | result on `a[lo..hi]` = combine(results on the two halves) | `hi − lo` strictly halves |
219
+ | Greedy with priority queue | extracted item is globally optimal for the remaining problem | heap size strictly decreases per extract |
220
+ | Union-Find op | `find(x)` always returns the canonical root of x's component | tree height bounded by O(log n) (with rank) |
221
+ | In-place partition | `a[0..i)` < pivot; `a[i..j)` ≥ pivot; `a[j..n)` unseen | `n − j` strictly decreases |
222
+
223
+ ## Edge case table — defaults to consider
224
+
225
+ | Input shape | Cases to check |
226
+ |---|---|
227
+ | Array / list | empty, singleton, all-equal, sorted, reversed, with duplicates |
228
+ | String | empty, single char, all whitespace, unicode (surrogates, combining), bytes vs code points |
229
+ | Integer | 0, 1, −1, MIN, MAX, MAX − 1, near overflow in arithmetic, division by 0 |
230
+ | Float | 0.0, −0.0, NaN, ±Inf, denormal, exact comparison should be ε-based |
231
+ | Map / dict | empty, missing key (default vs error), key collision semantics |
232
+ | Tree / graph | empty, single node, cycle (if undirected), self-loop, multigraph, disconnected |
233
+ | Stream / iterator | empty, infinite, single yield, exception mid-iteration |
234
+ | Time / date | DST transition, leap second/day, timezone offset, epoch boundary |
235
+ | Concurrent | empty contention, single thread, max contention, cancellation mid-op |
236
+
237
+ ## Output discipline
238
+
239
+ Code you emit must:
240
+
241
+ - Have one comment per loop stating the invariant (use `// inv:` or `# inv:`).
242
+ - Have one comment per recursion stating the base case and measure.
243
+ - Handle every edge case you listed in step 5, or explicitly delegate ("throws on empty — caller responsibility").
244
+ - Assert preconditions at function entry when the language supports it cheaply.
245
+ - Use types (sum types, newtypes, non-empty, non-null) over runtime checks where the language allows.
246
+
247
+ ## When to escalate or redirect
248
+
249
+ - The function is performance-critical and you have not picked the algorithm — go back to **`lemmaly`** first; pick the algorithm, then state its invariants here.
250
+ - The technique is mathematical (probabilistic, FFT, geometry) — load **`mathguard`**; invariants for approximate algorithms include ε-bounds, not equality.
251
+ - The code is concurrent — invariants must account for interleaving; explicitly state "single-threaded only" if that is the assumption.
252
+
253
+ ## Rationalizations to watch for
254
+
255
+ | Excuse | Reality |
256
+ | --- | --- |
257
+ | "I know this algorithm — single pass, done." | Knowing the loop ≠ knowing the contract. The trap usually lives in the postcondition the loop does not enforce. |
258
+ | "I traced it in my head, it works." | Mental tracing skips edge cases. Write the invariant; check it implies the postcondition. |
259
+ | "Edge cases are obvious." | Then write them down in 30 seconds. If they are obvious, the table is cheap. If they are not, the table just saved you. |
260
+ | "Tests will catch it." | Tests catch the examples you thought of. The trap is the example you did not. Postconditions catch all examples. |
261
+ | "The postcondition is implied." | If it were, the natural loop invariant would equal it. When they differ (Boyer–Moore, leftmost search, QuickSelect), you need a second pass, an extra check, or auxiliary state. |
262
+ | "Adding a verification pass feels redundant." | Boyer–Moore voting + verification is still O(n). "Feels redundant" is the rationalization that ships the bug. |
263
+
264
+ ## Red flags — STOP and write the invariant first
265
+
266
+ - About to write `while (...)` without having stated what is true on entry.
267
+ - About to write `if (i === n − 1)` or `if (i === n)` — boundary suspicious, restate the invariant.
268
+ - About to recurse without naming the base case in this message.
269
+ - About to write `// TODO: handle empty` — handle it now or change the type so empty is impossible.
270
+ - About to use `==` on floats.
271
+ - About to compare across signed/unsigned or across types where overflow rolls.
272
+ - About to silently swallow an error in the middle of a loop ("just continue").
273
+ - Tests pass but you did not actually state what the function guarantees.
274
+ - "It works on the examples I tried."
275
+
276
+ ## Verification checklist
277
+
278
+ Before claiming the function is correct:
279
+
280
+ - [ ] Every loop has a one-line `// inv:` comment in code.
281
+ - [ ] Every loop has a termination argument written down (in comment or PR description).
282
+ - [ ] Every recursion names its base case and measure in code.
283
+ - [ ] The function's postcondition is written and is implied by the exit state of the last loop.
284
+ - [ ] Every applicable edge case from the table has a test or an explicit "delegated to caller" note.
285
+ - [ ] At least one test exercises each non-trivial boundary (empty, singleton, max, off-by-one).
286
+ - [ ] Illegal states the function rejects are either unrepresentable in the type, or asserted at entry.
287
+ - [ ] For approximate/randomized algorithms (escalated to mathguard): ε-bounds are part of the postcondition, not equality.
288
+
289
+ Cannot check every box? The code is example-correct, not behavior-correct. Either fill the gap or downgrade the function's claimed contract.
290
+
291
+ ## Limitations
292
+
293
+ - **Not an automated prover.** invariant-guard requires the author to *write* invariants; it does not mechanically check them. Pair with property-based tests for stronger evidence.
294
+ - **Concurrency is out of scope by default.** Stated invariants assume single-threaded execution unless explicitly extended; multi-threaded reasoning needs additional happens-before / linearizability arguments.
295
+ - **Float and overflow edge cases are language-specific.** The edge-case table is a checklist, not a substitute for understanding your language's numeric semantics.
296
+ - **Will slow down trivial code.** For one-liners that obviously cannot fail, the protocol is overhead; reserve it for non-trivial loops, recursion, and in-place mutation.
297
+ - **Documentation is the only enforcement.** If the author skips writing the invariants, this skill cannot detect that — pair with code review or a PR template that asks for the contract.
298
+
299
+ ## The thesis, in one line
300
+
301
+ > **Tests verify examples. Invariants verify behavior. AI assistants ship example-correct, behavior-wrong code by default. invariant-guard makes them reason about behavior first.**
302
+
303
+ ## Related Skills
304
+
305
+ - `lemmaly` — algorithm choice must be settled before invariants; load lemmaly first if the algorithm family is unclear.
306
+ - `mathguard` — ε-bounded postconditions for approximate / randomized algorithms.
307
+ - `complexity-cuts` — if 3+ optimization transformations have failed tests, the bug is a missing contract, not a missing optimization — escalate here.
@@ -0,0 +1,236 @@
1
+ ---
2
+ name: lemmaly
3
+ description: "Algorithm-first discipline: state Big-O, data structure, and algorithm family BEFORE writing loops, queries, or recursion. Catches O(n^2), N+1, and brute-force defaults."
4
+ risk: safe
5
+ source: community
6
+ source_repo: morsechimwai/lemmaly
7
+ source_type: community
8
+ date_added: "2026-05-26"
9
+ author: morsechimwai
10
+ tags: [algorithms, big-o, performance, code-review, complexity, gateway]
11
+ tools: [claude-code, antigravity, cursor, gemini-cli, codex-cli]
12
+ license: "Apache-2.0"
13
+ license_source: "https://github.com/morsechimwai/lemmaly/blob/main/LICENSE"
14
+ ---
15
+
16
+ # lemmaly — Algorithm-First Proof
17
+
18
+ The model already knows Big-O, hash tables, divide-and-conquer, dynamic programming, sorting, graph algorithms, and amortized analysis. It just does not apply them spontaneously. lemmaly fixes the behavior, not the knowledge.
19
+
20
+ This skill is the gateway for an algorithm-discipline suite of four skills (`lemmaly`, `mathguard`, `invariant-guard`, `complexity-cuts`). It enforces the hard rules that every other guard in the suite assumes.
21
+
22
+ **Violating the letter of these rules is violating the spirit of the skill.** "Just this once" is how O(n²) ships to production.
23
+
24
+ ## When to Use This Skill
25
+
26
+ Use **lemmaly** when:
27
+
28
+ - Writing, editing, or reviewing code that involves loops, collections, lookups, searches, joins, recursion, graphs, queries, or any computation over more than a handful of items.
29
+ - About to write a `for` inside a `for`, `.find` / `.includes` / `.indexOf` inside a loop, `await` inside `for` / `map` / `forEach` over independent items, or one query per item in a collection.
30
+ - Auditing a codebase / PR for known anti-patterns (await-in-loop, `.includes` inside `.filter`, string-concat in loop, `SELECT *`, N+1, etc.).
31
+ - Reviewing AI-generated code that "looks idiomatic" but might hide O(n²) or N+1.
32
+
33
+ When in doubt, **start at lemmaly** — it is the gateway and will tell you when to escalate to its three sibling skills.
34
+
35
+ | If you are about to… | Use | Why |
36
+ | --- | --- | --- |
37
+ | Write *new* code that loops, queries, joins, recurses, or processes a collection | **lemmaly** | Forces complexity + data structure + algorithm family **before** code is written. |
38
+ | Refactor *existing* code that is already slow, OOMs, times out, or has nested loops / N+1 / repeated work | **complexity-cuts** | Corrective playbook for code that already shipped with bad Big-O. |
39
+ | Implement an algorithm where the obvious version is subtly wrong (binary search variants, in-place dedup, Boyer–Moore, QuickSelect partition, recursion with accumulators, fixed-point / termination concerns) | **invariant-guard** | Forces writing the function contract + loop invariant before code. The trap is in the contract, not the loop body. |
40
+ | Work with n ≥ 10⁶, similarity search, dedup at scale, top-K, streaming analytics, cardinality estimation, embeddings, FFT/NTT, dimensionality reduction, computational geometry, randomized algorithms | **mathguard** | Classical algorithms have hit their lower bound; an approximate or math-heavy technique (Bloom, HLL, Count-Min, MinHash/LSH, FFT, JL projection, sweep line, kd-tree) gives the asymptotic win. |
41
+
42
+ ### Routing flow
43
+
44
+ ```text
45
+ Are you writing new code?
46
+ ├── yes → lemmaly (state complexity, structure, family BEFORE coding)
47
+ │ ├── classical algorithm at its lower bound AND n is large? → mathguard
48
+ │ └── subtle correctness trap (invariant, base case, off-by-one)? → invariant-guard
49
+ └── no, refactoring existing slow / OOM / timed-out code → complexity-cuts
50
+ └── still slow after classical fixes? → mathguard
51
+ ```
52
+
53
+ ### One-line mental model
54
+
55
+ - **lemmaly** = think first (prevention).
56
+ - **complexity-cuts** = clean up bad Big-O (correction).
57
+ - **invariant-guard** = prove it's correct (verification).
58
+ - **mathguard** = beat the classical floor (acceleration).
59
+
60
+ ## The Iron Law
61
+
62
+ ```text
63
+ NO NON-TRIVIAL CODE WITHOUT STATED COMPLEXITY, DATA STRUCTURE, AND ALGORITHM FAMILY
64
+ ```
65
+
66
+ Before you write a loop, a recursion, a query, or any computation over more than a handful of items, three things must appear in your message — in this order:
67
+
68
+ 1. `time = O(?)`, `space = O(?)`, with the dominant input dimension named.
69
+ 2. The data structure you will use, with a one-phrase reason.
70
+ 3. The algorithm family (one of: linear scan, two-pointer, sliding window, binary search, sort+sweep, hash join, BFS/DFS, topo sort, Dijkstra/A*, union-find, DP, greedy, recursion+memo, prefix sum, segment tree, monoid reduction).
71
+
72
+ If you cannot state all three, you do not understand the problem yet. Ask, or read more code. Do not write code.
73
+
74
+ ## Non-negotiable rules
75
+
76
+ 1. **State complexity before writing any non-trivial code.** In one line:
77
+ - `time = O(?)`, `space = O(?)`
78
+ - Dominant input dimension: `n = what`, with realistic magnitude (e.g. `n ~ 10^6 rows`)
79
+ - If you cannot state these, you do not yet understand the problem. Ask, or read more code.
80
+
81
+ 2. **Name the data structure with a one-phrase reason.** Every collection-shaped value gets a deliberate choice from `Array / List / Set / HashMap / TreeMap / Heap / Deque / Trie / Graph / BitSet / Counter / LinkedList` — with the reason: "Set for O(1) membership inside the loop", "Heap for top-K in O(n log k)", "Counter to fold the nested loop into a single pass". Default to hashed structures (`Set`, `Map`) for lookup inside loops. Default to streaming/iterator over materialized list when n is large.
82
+
83
+ 3. **Identify the algorithm family before writing.** Name one of: `linear scan`, `divide and conquer`, `two-pointer`, `sliding window`, `binary search`, `sort + sweep`, `hash join`, `BFS/DFS`, `topological sort`, `Dijkstra/A*`, `union-find`, `dynamic programming`, `greedy`, `recursion + memoization`, `prefix sum`, `segment tree`, `monoid reduction`. If you cannot name a family, you are about to write brute force. Stop and reconsider.
84
+
85
+ 4. **Repeated work in loops is algorithmic waste.** All of these are presumed wrong until justified:
86
+ - I/O inside a loop (database queries, HTTP calls, file reads) — batch with `IN (...)`, `Promise.all`, bulk endpoints, streaming
87
+ - Recomputing the same value in a loop — hoist or memoize
88
+ - Re-sorting / re-grouping inside a loop — sort once outside
89
+ - Linear scan (`.find`, `.indexOf`, `.includes`, `in list`) inside a loop — precompute an index `Map`
90
+ - Allocating fresh structures per iteration when one can be reused — hoist allocation
91
+ - Materializing intermediate collections only to iterate again — fuse into one pass
92
+
93
+ If you must do any of these inside a loop, write one comment line explaining why.
94
+
95
+ 5. **No invented complexity or numbers.** Never write "O(log n) on average" without an argument. Never write "10x faster" or "~3ms" without measuring. If you cannot derive the complexity, write `<complexity: TBD>`. If you have not measured, write `<measured: TBD>`. Move on.
96
+
97
+ ## The pre-write protocol
98
+
99
+ Before producing non-trivial code, your message must contain — in this order:
100
+
101
+ 1. **Problem shape** — one sentence. ("Given n events with a timestamp, find the longest contiguous window where total weight ≤ K.")
102
+ 2. **Input dimensions** — `n = ?`, realistic magnitude, whether hot path.
103
+ 3. **Target complexity** — `time = O(?)`, `space = O(?)`.
104
+ 4. **Data structures** — name them with a phrase each.
105
+ 5. **Algorithm family** — one phrase.
106
+ 6. **Edge cases you will handle** — empty, singleton, all-equal, n=1, n=max, overflow, duplicates. List the ones that apply.
107
+ 7. **The code.**
108
+
109
+ If any of 1–6 is missing, do not emit code yet.
110
+
111
+ ## Canonical example — protocol vs no-protocol
112
+
113
+ The same problem with and without the seven-step protocol.
114
+
115
+ **Problem.** Given `users: User[]` and `bannedIds: string[]`, return users whose `id` is not banned. Realistic n: 50k users, 5k banned.
116
+
117
+ ### Without the protocol — ships O(n·m)
118
+
119
+ ```ts
120
+ // Looks idiomatic, ships O(n·m)
121
+ const active = users.filter((u) => !bannedIds.includes(u.id));
122
+ ```
123
+
124
+ `bannedIds.includes` is O(m) per call. The filter runs it n times → 50k × 5k = 250M comparisons.
125
+
126
+ ### With the protocol — O(n + m)
127
+
128
+ ```ts
129
+ // Protocol applied:
130
+ // time = O(n + m), space = O(m), n = 50k users, m = 5k banned
131
+ // structure: Set<string> for O(1) membership inside the loop
132
+ // family: linear scan with hashed lookup
133
+ // edge cases: empty users → [], empty bannedIds → users, duplicates in bannedIds → fine (Set dedupes)
134
+ const banned = new Set(bannedIds);
135
+ const active = users.filter((u) => !banned.has(u.id));
136
+ ```
137
+
138
+ The first version is the default an AI ships when asked "filter the active users." The second is what the protocol forces — without changing how the code reads.
139
+
140
+ ## Rule catalog (the lemmaly scanner)
141
+
142
+ The upstream repo ships a deterministic CLI scanner with the same anti-patterns this skill enforces (**59 rules across 11 languages**: JavaScript/TypeScript, Python, SQL, Java, C#, C++, Go, Rust, PHP, Ruby, Shell/Bash). Each rule has a documented why, an incorrect example, a correct example, and the sibling skill to escalate to.
143
+
144
+ To run the scanner locally:
145
+
146
+ ```bash
147
+ # Clone the upstream repo for the CLI tool
148
+ git clone https://github.com/morsechimwai/lemmaly.git
149
+ cd lemmaly
150
+ node cli/lemmaly.js scan <path> # flag instances of anti-patterns
151
+ node cli/lemmaly.js rules # list all 59 rules
152
+ ```
153
+
154
+ **CRITICAL severity (error in CI):**
155
+
156
+ - `js-await-in-for-loop` — N+1 over network
157
+ - `js-async-in-foreach` — dropped promises
158
+ - `py-mutable-default-arg` — shared default state
159
+ - `sql-update-no-where` — touches every row
160
+ - `java-arraylist-remove-in-for-i` — index shifts; ConcurrentModification
161
+ - `cs-async-void` — exceptions unobserved; crashes the process
162
+ - `go-loop-var-capture` — pre-1.22 race on the last value
163
+ - `php-query-in-loop` — N+1 against the database
164
+
165
+ **HIGH severity (warning in CI):** `js-deep-clone-via-json`, `js-useeffect-missing-deps`, `js-inline-object-jsx-prop`, `js-anonymous-handler-jsx`, `js-spread-in-reduce`, `js-unique-via-indexof`, `js-helper-call-in-iterator`, `py-string-concat-in-loop`, `py-django-loop-without-eager`, `py-bare-except`, `sql-select-star`, `sql-leading-wildcard-like`, `sql-not-in-subquery`, `java-string-concat-in-loop`, `java-list-contains-in-loop`, `java-bare-catch-exception`, `cs-string-concat-in-loop`, `cs-list-contains-in-loop`, `cs-disposable-no-using`, `go-string-concat-in-loop`, `go-defer-in-loop`, `go-err-not-checked`, `rs-unwrap-in-prod`, `cpp-string-concat-in-loop`, `cpp-raw-new`, `php-count-in-for-condition`, `php-in-array-in-loop`, `rb-include-in-iterator`, `rb-n-plus-one-activerecord`, `rb-bare-rescue`, `sh-set-e-no-pipefail`, `sh-unquoted-var`, `sh-for-ls`.
166
+
167
+ **MEDIUM severity (info in CI):** `js-nested-for-loops`, `js-includes-in-iterator`, `js-array-key-index`, `py-range-len`, `py-in-list-literal`, `py-open-without-with`, `sql-select-no-limit`, `sql-or-in-where`, `go-slice-append-no-cap`, `rs-clone-in-loop`, `rs-vec-push-no-capacity`, `rs-string-push-no-capacity`, `cpp-vector-push-no-reserve`, `cpp-range-loop-copy`, `cpp-map-double-lookup`, `php-loose-equality`, `rb-string-concat-in-loop`, `sh-useless-cat-pipe`.
168
+
169
+ ## When to escalate to sibling skills
170
+
171
+ lemmaly handles classical, day-to-day algorithmic discipline. Escalate when:
172
+
173
+ - **Math-level optimization** (probabilistic data structures, FFT, dimensionality reduction, approximation algorithms, computational geometry) — load **mathguard**.
174
+ - **Algorithm correctness** (loop invariants, termination, recursion base cases, edge cases that tests miss) — load **invariant-guard**.
175
+ - **Existing code with bad complexity that already shipped** — load **complexity-cuts** for the corrective transformation playbook.
176
+
177
+ ## Rationalizations to watch for
178
+
179
+ These are real verbatim thoughts captured from controlled tests where the model shipped O(n·m) code that the seven-step protocol would have prevented:
180
+
181
+ | Excuse | Reality |
182
+ | --- | --- |
183
+ | "`.filter` then `.reduce` is the idiomatic way, ship it." | Idiomatic ≠ correct asymptotic. Idiom-driven coding is how O(n²) ships. |
184
+ | "It's fine for now, we can optimize later." | Later is a different engineer with no context. State the complexity now. |
185
+ | "I'll just use `Array.find` here, it's just one lookup." | One lookup inside a loop over `n` items is `O(n)` lookups. Make the `Map` outside. |
186
+ | "The data is small in dev — I'll worry about scale when we ship." | Production data is never the size of dev data. The seven-step protocol takes 30 seconds. |
187
+ | "I already understand the problem, the protocol is overhead." | The cases the protocol "wastes time on" are the cases that break in prod. |
188
+
189
+ If any of these sound familiar mid-thought: stop, write the seven steps.
190
+
191
+ ## Red flags — STOP and restart the protocol
192
+
193
+ - About to write a `for` inside a `for` without first stating it is the intended O(n·m).
194
+ - About to call `.find` / `.includes` / `.indexOf` inside a loop body.
195
+ - About to `await` inside `for` / `map` / `forEach` over independent items.
196
+ - About to issue one query per item in a collection.
197
+ - About to recurse without stating the base case or memoization plan.
198
+ - About to write code without having stated complexity.
199
+ - About to claim "this is fast" / "this is efficient" / "this scales" without a derivation.
200
+ - About to copy a brute-force solution from memory because it "should work for now".
201
+
202
+ All of these mean: stop, restart the seven-step protocol, choose a better algorithm or explicitly accept the brute force with a written justification.
203
+
204
+ ## Verification checklist
205
+
206
+ Before claiming the implementation is done:
207
+
208
+ - [ ] Stated `time = O(?)` and `space = O(?)` appear in the message or PR description.
209
+ - [ ] Dominant input dimension is named with a realistic magnitude.
210
+ - [ ] Every collection-shaped value has a deliberate data-structure choice with a one-phrase reason.
211
+ - [ ] The algorithm family is named (not "a loop").
212
+ - [ ] No I/O, `.find` / `.includes` / `.indexOf`, regex compile, sort, or independent `await` sits inside a loop without a one-line justification.
213
+ - [ ] The shipped code matches the complexity that was claimed (re-derive if uncertain).
214
+ - [ ] Edge cases listed in the pre-write protocol each have a corresponding code path or test.
215
+ - [ ] Any "fast" / "efficient" / "scales" claims have either a derivation or a measurement — `<measured: TBD>` is acceptable; an unsupported claim is not.
216
+
217
+ Cannot check every box? You did not run the protocol. Restart from step 1.
218
+
219
+ ## Limitations
220
+
221
+ - **Not a substitute for profiling.** lemmaly forces asymptotic reasoning, not measurement. For constant-factor wins, latency tails, or I/O bottlenecks you still need a profiler.
222
+ - **Reasoning gate, not a code generator.** This skill changes how the model thinks before writing; it does not auto-rewrite existing code (use `complexity-cuts` for that).
223
+ - **English-language enforcement.** The rule catalog and prompts are English-only.
224
+ - **n < ~10 is exempt.** The protocol explicitly accepts trivial collections and one-shot setup code; do not waste time stating complexity for `for i in range(3)`.
225
+ - **Cannot prevent intentional brute force.** If the author writes a one-line justification ("n ≤ 100 in practice; readability matters more"), brute force ships. The skill only requires the justification, not its absence.
226
+ - **CLI scanner is separate.** The 59 rules are enforced by `lemmaly scan` in the upstream repo, not by this SKILL.md alone.
227
+
228
+ ## The thesis, in one line
229
+
230
+ > **AI ships algorithmically lazy code by default. lemmaly makes it think first.**
231
+
232
+ ## Related Skills
233
+
234
+ - `mathguard` — escalation for n ≥ 10⁶ where classical O(n log n) is the floor and probabilistic / math-heavy techniques win.
235
+ - `invariant-guard` — correctness layer for algorithms whose obvious version is subtly wrong.
236
+ - `complexity-cuts` — corrective playbook for code that already shipped with bad Big-O.