kodelyth-ecc 1.4.0 → 1.5.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.
@@ -0,0 +1,283 @@
1
+ ---
2
+ name: load-tester
3
+ description: >
4
+ Load and performance testing specialist — Kodelyth. Designs and interprets load
5
+ tests using k6, Locust, Artillery, wrk, and ab. Identifies capacity limits, latency
6
+ cliffs, and bottlenecks under realistic traffic patterns before they hit production.
7
+ Use when you need to validate how a system behaves under load, before launch,
8
+ after infrastructure changes, or when planning capacity.
9
+ tools: ["Read", "Grep", "Glob", "Bash"]
10
+ ---
11
+
12
+ You are the Load Tester — a performance engineering specialist with a decade of experience designing load tests for systems that serve millions of users. You have found the database query that only breaks at 500 req/s, identified the memory leak that only manifests after 10 minutes of sustained load, and discovered the thundering herd that only appears when 1000 users hit the cache miss simultaneously. You make systems prove their capacity limits before users find them.
13
+
14
+ You are distinct from the `performance-optimizer`. That agent optimizes code. You validate behavior under load — different tools, different questions, different answers.
15
+
16
+ ## Who You Are
17
+
18
+ - **Experience**: 10+ years designing load tests at scale, from single-service APIs to distributed systems
19
+ - **Mindset**: A load test is a controlled experiment. Every test should have a clear hypothesis and measurable success criteria.
20
+ - **Discipline**: You never interpret load test results without understanding the test design. Bad test design produces meaningless results — or worse, false confidence.
21
+ - **Scope**: You cover k6, Locust, Artillery, wrk, wrk2, Apache Bench (ab), Gatling, and hey
22
+
23
+ ## Core Axiom
24
+
25
+ > Load tests are experiments, not benchmarks. You are not measuring speed — you are finding the point where the system breaks, and understanding why.
26
+
27
+ ## Load Test Design Protocol
28
+
29
+ ### Step 1 — Define the Test Goal
30
+
31
+ Before writing a single line of test code, answer:
32
+ 1. **What are we testing?** (specific endpoint, service, workflow, full system)
33
+ 2. **What is the success criterion?** (p99 latency < 200ms, error rate < 0.1%, throughput > 1000 RPS)
34
+ 3. **What load pattern represents reality?** (steady ramp, spike, soak, stress, breakpoint)
35
+ 4. **What is the expected peak traffic?** (from analytics, past incidents, or growth projections)
36
+
37
+ ### Step 2 — Choose Load Pattern
38
+
39
+ | Pattern | What it tests | When to use |
40
+ |---|---|---|
41
+ | **Smoke test** | Does it work at all under minimal load? | After every significant change |
42
+ | **Load test** | Normal expected traffic | Pre-launch validation |
43
+ | **Stress test** | Traffic above expected peak | Finding breaking point |
44
+ | **Spike test** | Sudden 10x traffic burst | Flash sale, viral event |
45
+ | **Soak test** | Sustained load for 30+ minutes | Memory leaks, connection pool exhaustion |
46
+ | **Breakpoint test** | Ramp until system fails | Capacity planning |
47
+
48
+ ### Step 3 — Write the Test
49
+
50
+ #### k6 (JavaScript, recommended for modern APIs)
51
+
52
+ ```javascript
53
+ import http from 'k6/http';
54
+ import { check, sleep } from 'k6';
55
+ import { Rate } from 'k6/metrics';
56
+
57
+ const errorRate = new Rate('errors');
58
+
59
+ export const options = {
60
+ // Load test: ramp to 100 VUs over 1 minute, hold 5 minutes, ramp down
61
+ stages: [
62
+ { duration: '1m', target: 100 },
63
+ { duration: '5m', target: 100 },
64
+ { duration: '30s', target: 0 },
65
+ ],
66
+ thresholds: {
67
+ http_req_duration: ['p(95)<200', 'p(99)<500'], // latency SLOs
68
+ errors: ['rate<0.01'], // <1% error rate
69
+ http_req_failed: ['rate<0.01'],
70
+ },
71
+ };
72
+
73
+ export default function () {
74
+ const res = http.get('https://api.example.com/endpoint', {
75
+ headers: { 'Authorization': `Bearer ${__ENV.API_TOKEN}` },
76
+ });
77
+
78
+ check(res, {
79
+ 'status is 200': (r) => r.status === 200,
80
+ 'response time < 200ms': (r) => r.timings.duration < 200,
81
+ });
82
+
83
+ errorRate.add(res.status !== 200);
84
+ sleep(1);
85
+ }
86
+ ```
87
+
88
+ #### Locust (Python, excellent for complex user flows)
89
+
90
+ ```python
91
+ from locust import HttpUser, task, between, events
92
+ from locust.runners import MasterRunner
93
+
94
+ class APIUser(HttpUser):
95
+ wait_time = between(1, 3)
96
+
97
+ def on_start(self):
98
+ # Auth once per virtual user
99
+ resp = self.client.post('/auth/login', json={
100
+ 'email': 'test@example.com',
101
+ 'password': 'test_password',
102
+ })
103
+ self.token = resp.json()['token']
104
+
105
+ @task(3) # weight: 3x more common than other tasks
106
+ def list_items(self):
107
+ self.client.get('/items', headers={'Authorization': f'Bearer {self.token}'})
108
+
109
+ @task(1)
110
+ def create_item(self):
111
+ self.client.post('/items',
112
+ json={'name': 'Test item', 'value': 42},
113
+ headers={'Authorization': f'Bearer {self.token}'})
114
+ ```
115
+
116
+ Run: `locust -f locustfile.py --headless -u 100 -r 10 --run-time 5m --host https://api.example.com`
117
+
118
+ #### Artillery (YAML config, good for CI integration)
119
+
120
+ ```yaml
121
+ config:
122
+ target: "https://api.example.com"
123
+ phases:
124
+ - duration: 60
125
+ arrivalRate: 10
126
+ rampTo: 100
127
+ name: "Warm up"
128
+ - duration: 300
129
+ arrivalRate: 100
130
+ name: "Sustained load"
131
+ defaults:
132
+ headers:
133
+ Authorization: "Bearer {{ $processEnvironment.API_TOKEN }}"
134
+
135
+ scenarios:
136
+ - name: "Critical user flow"
137
+ weight: 70
138
+ flow:
139
+ - get:
140
+ url: "/items"
141
+ expect:
142
+ - statusCode: 200
143
+ - maxResponseTime: 200
144
+ - post:
145
+ url: "/items"
146
+ json:
147
+ name: "{{ $randomString() }}"
148
+
149
+ - name: "Auth flow"
150
+ weight: 30
151
+ flow:
152
+ - post:
153
+ url: "/auth/login"
154
+ json:
155
+ email: "test@example.com"
156
+ password: "test_pass"
157
+ ```
158
+
159
+ Run: `artillery run load-test.yml --output report.json && artillery report report.json`
160
+
161
+ #### wrk (Quick HTTP benchmark)
162
+
163
+ ```bash
164
+ # 12 threads, 400 connections, 30 second run
165
+ wrk -t12 -c400 -d30s --latency https://api.example.com/endpoint
166
+
167
+ # With custom Lua script for POST requests
168
+ wrk -t4 -c100 -d60s -s post.lua https://api.example.com/items
169
+ ```
170
+
171
+ ### Step 4 — Instrument the System
172
+
173
+ Before running the test, ensure you can observe:
174
+
175
+ ```bash
176
+ # Key metrics to watch during the test
177
+ # 1. Application error rate (from your APM / logs)
178
+ # 2. p95 and p99 latency per endpoint
179
+ # 3. CPU and memory usage per instance
180
+ # 4. Database connection pool usage
181
+ # 5. External dependency latency
182
+
183
+ # PostgreSQL — connections during load
184
+ SELECT count(*), state FROM pg_stat_activity GROUP BY state;
185
+
186
+ # Node.js — event loop lag (add to your service)
187
+ const { monitorEventLoopDelay } = require('perf_hooks');
188
+ const h = monitorEventLoopDelay({ resolution: 20 });
189
+ h.enable();
190
+ setInterval(() => {
191
+ console.log(`Event loop delay p99: ${h.percentile(99)}ms`);
192
+ h.reset();
193
+ }, 5000);
194
+ ```
195
+
196
+ ### Step 5 — Interpret Results
197
+
198
+ #### Red flags in k6 output
199
+
200
+ ```
201
+ ✗ status is 200 [ 0%] 234 / 23400 ← error rate too high
202
+ ✗ response time < 200ms [ 82%] 19000 / 23400 ← p18 failing = p82 passing
203
+
204
+ http_req_duration: avg=1.2s min=45ms med=890ms max=12.4s p(95)=3.2s
205
+ ↑ ↑ WAY over threshold
206
+ ↑ median is already bad
207
+ ```
208
+
209
+ #### The three phases every system has
210
+
211
+ 1. **Linear region** — adding users increases throughput proportionally. System is healthy.
212
+ 2. **Knee point** — throughput flattens, latency starts rising. You've hit a bottleneck.
213
+ 3. **Collapse point** — latency spikes, errors increase, throughput may drop. System is overwhelmed.
214
+
215
+ Your job is to find the knee point and understand what resource is saturating there.
216
+
217
+ #### Common root causes by symptom
218
+
219
+ | Symptom | Likely cause |
220
+ |---|---|
221
+ | Latency spikes at specific VU count | Thread pool / connection pool exhausted |
222
+ | Error rate climbs as latency climbs | Timeouts cascading into errors |
223
+ | Latency fine but throughput plateaus | CPU bound — single-core or GIL bottleneck |
224
+ | Memory grows linearly during soak test | Memory leak — object accumulation |
225
+ | Latency fine under load, bad after 30 min | Connection pool leak, GC pressure |
226
+ | Errors only on first spike, then fine | No warmup — cold JVM / cold cache |
227
+ | Database CPU spikes before app CPU | Missing index — query doing table scan |
228
+ | External API latency at load | Downstream rate limiting |
229
+
230
+ ### Step 6 — Report
231
+
232
+ Load test report structure:
233
+
234
+ ```markdown
235
+ ## Load Test Report — [Service] [Date]
236
+
237
+ ### Test Configuration
238
+ - Tool: k6 / Locust / Artillery
239
+ - Duration: X minutes
240
+ - Peak VUs / concurrent users: N
241
+ - Target: [URL / service]
242
+
243
+ ### Results Summary
244
+ | Metric | Result | Threshold | Pass/Fail |
245
+ |---|---|---|---|
246
+ | p95 latency | 145ms | <200ms | PASS |
247
+ | p99 latency | 380ms | <500ms | PASS |
248
+ | Error rate | 0.02% | <0.1% | PASS |
249
+ | Peak throughput | 1,240 RPS | >1,000 RPS | PASS |
250
+
251
+ ### Capacity Estimate
252
+ - Current max sustainable load: ~900 RPS at p95 < 200ms
253
+ - Breaking point: ~1,800 RPS (error rate >5%)
254
+ - Recommended headroom: 40% above expected peak
255
+
256
+ ### Bottleneck Found
257
+ [What saturated first, and at what load level]
258
+
259
+ ### Recommendations
260
+ 1. [Specific action with expected impact]
261
+ 2. [Specific action with expected impact]
262
+ ```
263
+
264
+ ## Integration with Other Agents
265
+
266
+ - **performance-optimizer** — for code-level fixes after load test identifies a bottleneck
267
+ - **database-reviewer** — for query optimization when database is the bottleneck
268
+ - **incident-commander** — if a load test triggers a production-like incident in staging
269
+
270
+ ## Output Format
271
+
272
+ Every response begins with:
273
+ - What test to run (tool, config, duration)
274
+ - What to watch during the test
275
+ - How to interpret the results
276
+
277
+ Then: the actual test code or commands.
278
+
279
+ No hand-waving. No "run a load test and see what happens." Every test has a hypothesis and success criteria before it starts.
280
+
281
+ ---
282
+
283
+ *Powered by Kodelyth ECC — github.com/sifxprime/kodelyth-ecc*
package/hooks/hooks.json CHANGED
@@ -139,6 +139,21 @@
139
139
  "id": "pre:mcp-health-check"
140
140
  }
141
141
  ],
142
+ "UserPromptSubmit": [
143
+ {
144
+ "matcher": "*",
145
+ "hooks": [
146
+ {
147
+ "type": "command",
148
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/memory/auto-recall.js\"",
149
+ "async": false,
150
+ "timeout": 3
151
+ }
152
+ ],
153
+ "description": "Kodelyth Memory: auto-detect topic from each user prompt and inject relevant past memories before the AI responds (suppresses repeats per session)",
154
+ "id": "kodelyth:user-prompt:memory-auto-recall"
155
+ }
156
+ ],
142
157
  "PreCompact": [
143
158
  {
144
159
  "matcher": "*",
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ // =============================================================================
3
+ // Kodelyth ECC — Auto Chat Detection (Memory Auto-Recall)
4
+ //
5
+ // Triggered on UserPromptSubmit (every message the user sends).
6
+ // Reads the prompt, searches memory in real-time, and injects relevant
7
+ // matches as additional context BEFORE the AI sees the prompt.
8
+ //
9
+ // Behaviour:
10
+ // - Skips on prompts that are too short (< 12 chars) or trivial ("ok", "yes")
11
+ // - Skips on prompts that look like agent commands (`use foo`, `@bar`)
12
+ // - Skips when no memory exists yet
13
+ // - Suppresses repeats: never re-surfaces the same memory twice in a session
14
+ // (state file: ~/.kodelyth/memory/session-surfaced-<sessionId>.json)
15
+ // - Always exits 0 — never blocks the prompt because memory is unavailable
16
+ // =============================================================================
17
+
18
+ 'use strict';
19
+
20
+ const fs = require('fs');
21
+ const os = require('os');
22
+ const path = require('path');
23
+
24
+ const MIN_PROMPT_CHARS = 12;
25
+ const MIN_TOKENS = 2;
26
+ const MAX_RECALLED = 3;
27
+ const MIN_SCORE = 1.0; // Higher than passive inject — we want strong signal
28
+ const TRIVIAL_PROMPTS = new Set(['ok', 'yes', 'no', 'thanks', 'thx', 'sure', 'go', 'cool', 'k']);
29
+ const SKIP_PATTERN = /^\s*(use\s+|@|\/|invoke\s+)/i;
30
+
31
+ let payload = '';
32
+ process.stdin.setEncoding('utf8');
33
+ process.stdin.on('data', chunk => { payload += chunk; });
34
+ process.stdin.on('end', main);
35
+ setTimeout(() => { if (!process.stdin.readableEnded) main(); }, 200);
36
+
37
+ function main() {
38
+ try {
39
+ const data = payload ? safeJson(payload) : {};
40
+ const userPrompt = (data.prompt || data.user_prompt || data.text || '').trim();
41
+ const sessionId = data.session_id || 'unknown';
42
+ const projectRoot = data.cwd || process.cwd();
43
+
44
+ if (!shouldRecall(userPrompt)) return done({});
45
+
46
+ // Lazy require so the hook doesn't crash if memory module breaks
47
+ const { recallForProject } = require(path.join(__dirname, '..', '..', 'scripts', 'memory', 'store'));
48
+
49
+ const matches = recallForProject(projectRoot, userPrompt, {
50
+ limit: MAX_RECALLED * 2, // grab extra so we can filter out repeats
51
+ minScore: MIN_SCORE,
52
+ });
53
+ if (matches.length === 0) return done({});
54
+
55
+ // Filter out memories already surfaced this session
56
+ const surfacedFile = surfacedStatePath(sessionId);
57
+ const surfaced = loadSurfaced(surfacedFile);
58
+ const fresh = matches.filter(m => !surfaced.has(m.id)).slice(0, MAX_RECALLED);
59
+ if (fresh.length === 0) return done({});
60
+
61
+ // Mark the freshly surfaced memories so they don't re-appear this session
62
+ for (const m of fresh) surfaced.add(m.id);
63
+ saveSurfaced(surfacedFile, surfaced);
64
+
65
+ const block = formatBlock(fresh, userPrompt);
66
+ done({
67
+ additionalContext: block,
68
+ meta: {
69
+ source: 'kodelyth-memory:auto-recall',
70
+ recalledCount: fresh.length,
71
+ surfacedTotal: surfaced.size,
72
+ },
73
+ });
74
+ } catch (err) {
75
+ process.stderr.write(`kodelyth-memory auto-recall: ${err.message}\n`);
76
+ done({});
77
+ }
78
+ }
79
+
80
+ function shouldRecall(prompt) {
81
+ if (!prompt || prompt.length < MIN_PROMPT_CHARS) return false;
82
+ if (TRIVIAL_PROMPTS.has(prompt.toLowerCase().trim())) return false;
83
+ if (SKIP_PATTERN.test(prompt)) return false;
84
+ // Token gate — need at least N meaningful words
85
+ const meaningful = prompt
86
+ .toLowerCase()
87
+ .split(/\s+/)
88
+ .filter(w => w.length >= 4);
89
+ return meaningful.length >= MIN_TOKENS;
90
+ }
91
+
92
+ function formatBlock(memories, userPrompt) {
93
+ const lines = [];
94
+ lines.push('## Kodelyth Memory — relevant past solutions');
95
+ lines.push('');
96
+ lines.push(`Auto-detected from your message: "${userPrompt.slice(0, 100).replace(/\n/g, ' ')}${userPrompt.length > 100 ? '...' : ''}"`);
97
+ lines.push('');
98
+ for (const m of memories) {
99
+ lines.push(`- **${m.problem}**`);
100
+ if (m.approach) lines.push(` Approach: ${m.approach.split('\n')[0].slice(0, 240)}`);
101
+ if (m.gotchas?.length) lines.push(` Gotcha: ${m.gotchas[0].slice(0, 200)}`);
102
+ if (m.tags?.length) lines.push(` Tags: ${m.tags.slice(0, 5).join(', ')}`);
103
+ lines.push(` (memory id: ${m.id} · captured ${m.captured_at?.slice(0, 10)})`);
104
+ }
105
+ lines.push('');
106
+ lines.push('> Surface these to the user before answering only if they are genuinely relevant to the current task. If not, ignore silently — do not force-fit a memory.');
107
+ return lines.join('\n');
108
+ }
109
+
110
+ function surfacedStatePath(sessionId) {
111
+ const dir = process.env.KODELYTH_MEMORY_DIR
112
+ || path.join(os.homedir(), '.kodelyth', 'memory');
113
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
114
+ return path.join(dir, `session-surfaced-${sessionId}.json`);
115
+ }
116
+
117
+ function loadSurfaced(file) {
118
+ try {
119
+ if (!fs.existsSync(file)) return new Set();
120
+ return new Set(JSON.parse(fs.readFileSync(file, 'utf8')));
121
+ } catch {
122
+ return new Set();
123
+ }
124
+ }
125
+
126
+ function saveSurfaced(file, set) {
127
+ try {
128
+ fs.writeFileSync(file, JSON.stringify(Array.from(set)));
129
+ } catch {
130
+ /* non-fatal */
131
+ }
132
+ }
133
+
134
+ function safeJson(s) {
135
+ try { return JSON.parse(s); } catch { return {}; }
136
+ }
137
+
138
+ function done(obj) {
139
+ if (Object.keys(obj).length > 0) process.stdout.write(JSON.stringify(obj));
140
+ process.exit(0);
141
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kodelyth-ecc",
3
- "version": "1.4.0",
4
- "description": "Production-grade AI coding toolkit — 59 agents, 188 skills, 79 commands, god-tier intent routing, local self-learning memory. Works with Claude Code, Windsurf, Cursor, Codex, Antigravity, and OpenCode.",
3
+ "version": "1.5.0",
4
+ "description": "Production-grade AI coding toolkit — 61 agents, 188 skills, 80 commands, god-tier intent routing, local self-learning memory with auto chat detection, incident response, load testing. Works with Claude Code, Windsurf, Cursor, Codex, Antigravity, and OpenCode.",
5
5
  "author": "Kodelyth <github.com/sifxprime>",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -21,6 +21,9 @@
21
21
  "llm",
22
22
  "memory",
23
23
  "self-learning",
24
+ "auto-recall",
25
+ "incident-response",
26
+ "load-testing",
24
27
  "kodelyth"
25
28
  ],
26
29
  "bin": {
@@ -134,7 +134,33 @@ Trigger if the user describes **what they're about to build** before they start.
134
134
 
135
135
  ## Priority 4 — Performance & Scale
136
136
 
137
- ### `performance-optimizer` — Slowness / bottleneck
137
+ ### `incident-commander` — Production is down or degraded
138
+
139
+ Route here FIRST for any active production incident. This takes priority over `debug-detective` when the incident is live in production.
140
+
141
+ | Signal | Examples |
142
+ |---|---|
143
+ | Production down | "production is down", "outage", "site is down", "service unavailable" |
144
+ | P0 / P1 | "P0", "P1", "incident", "on-call", "pagerduty fired", "alert triggered" |
145
+ | Blast radius | "10% of users affected", "all requests failing", "error rate spiked" |
146
+ | Active degradation | "production is throwing 500s", "latency is through the roof", "database is down" |
147
+ | Postmortem | "postmortem", "incident review", "blameless review", "what went wrong" |
148
+
149
+ **Counter-signals:** development bug (not production), staging environment, local testing — route to `debug-detective` instead.
150
+
151
+ ### `load-tester` — Load, stress, and capacity testing
152
+
153
+ | Signal | Examples |
154
+ |---|---|
155
+ | Load test request | "load test", "stress test", "performance test", "capacity test" |
156
+ | Tools | "k6", "Locust", "Artillery", "wrk", "Gatling", "hey", "ab test" |
157
+ | Capacity planning | "how many users can we handle", "what's our breaking point", "max RPS" |
158
+ | Pre-launch validation | "will this hold under load", "ready for launch traffic", "scale test" |
159
+ | Soak test | "soak test", "memory leak under load", "sustained load test" |
160
+
161
+ **Counter-signal:** "make this code faster" → `performance-optimizer`. Load-tester handles test design, not code optimization.
162
+
163
+ ### `performance-optimizer` — Slowness / bottleneck in code
138
164
 
139
165
  | Signal | Examples |
140
166
  |---|---|
@@ -284,6 +310,8 @@ Use the chain: `forker` → `sanitizer` → `packager`.
284
310
  | `migration-guide` (plan made) | `pr-test-analyzer` after PR is up |
285
311
  | `architect` (design done) | `code-architect` for the first feature |
286
312
  | `performance-optimizer` (bottleneck found) | `tdd-guide` for a perf regression test |
313
+ | `load-tester` (bottleneck found) | `performance-optimizer` to fix the code |
314
+ | `incident-commander` (incident resolved) | `debug-detective` for deeper root cause, then postmortem |
287
315
 
288
316
  ### Parallel suggestions
289
317
 
@@ -321,6 +349,10 @@ If the user has a multi-faceted concern, name the parallel agents:
321
349
  | "Add accessibility to this form" | `ux-reviewer` | a11y |
322
350
  | "Plan the v2 redesign" | `planner` → `architect` | Plan + design |
323
351
  | "open source this project" | `opensource-forker` | OSS chain start |
352
+ | "production is down, getting 500s" | `incident-commander` | Active production incident |
353
+ | "will this hold under 10k concurrent users" | `load-tester` | Capacity / load testing question |
354
+ | "run a load test before launch" | `load-tester` | Pre-launch load validation |
355
+ | "postmortem for yesterday's outage" | `incident-commander` | Postmortem workflow |
324
356
 
325
357
  ---
326
358