vanara 0.1.0 → 0.2.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 (195) hide show
  1. package/README.md +14 -0
  2. package/bin/vanara.js +66 -2
  3. package/catalog/agents/api-designer/AGENT.md +140 -0
  4. package/catalog/agents/api-designer/examples/openapi-snippet.yaml +130 -0
  5. package/catalog/agents/api-designer/examples/review-notes.md +61 -0
  6. package/catalog/agents/api-designer/references/contract-and-openapi.md +82 -0
  7. package/catalog/agents/api-designer/references/design-checklist.md +68 -0
  8. package/catalog/agents/api-designer/references/versioning-and-evolution.md +63 -0
  9. package/catalog/agents/api-designer/scripts/lint-openapi.mjs +180 -0
  10. package/catalog/agents/code-reviewer/AGENT.md +168 -0
  11. package/catalog/agents/code-reviewer/examples/pr-comment-template.md +48 -0
  12. package/catalog/agents/code-reviewer/examples/sample-review-output.md +38 -0
  13. package/catalog/agents/code-reviewer/references/review-checklist.md +46 -0
  14. package/catalog/agents/code-reviewer/references/security-review.md +62 -0
  15. package/catalog/agents/code-reviewer/references/severity-rubric.md +63 -0
  16. package/catalog/agents/code-reviewer/scripts/review-guard.mjs +102 -0
  17. package/catalog/agents/debugger/AGENT.md +112 -0
  18. package/catalog/agents/debugger/examples/postmortem-template.md +59 -0
  19. package/catalog/agents/debugger/examples/repro-template.md +50 -0
  20. package/catalog/agents/debugger/references/bisection.md +63 -0
  21. package/catalog/agents/debugger/references/debugging-method.md +57 -0
  22. package/catalog/agents/debugger/references/observability.md +61 -0
  23. package/catalog/agents/debugger/scripts/parse-stacktrace.mjs +109 -0
  24. package/catalog/agents/pr-summarizer/AGENT.md +156 -0
  25. package/catalog/agents/pr-summarizer/examples/sample-pr-summary.md +46 -0
  26. package/catalog/agents/pr-summarizer/examples/weak-vs-strong-summary.md +68 -0
  27. package/catalog/agents/pr-summarizer/references/identifying-risk.md +68 -0
  28. package/catalog/agents/pr-summarizer/references/reading-the-diff.md +68 -0
  29. package/catalog/agents/pr-summarizer/references/test-plan-and-missing-tests.md +64 -0
  30. package/catalog/agents/pr-summarizer/references/writing-the-summary.md +63 -0
  31. package/catalog/agents/pr-summarizer/scripts/diff-risk.mjs +111 -0
  32. package/catalog/agents/refactoring-specialist/AGENT.md +185 -0
  33. package/catalog/agents/refactoring-specialist/examples/before-after.md +91 -0
  34. package/catalog/agents/refactoring-specialist/examples/refactor-plan.md +97 -0
  35. package/catalog/agents/refactoring-specialist/references/large-scale-refactor.md +50 -0
  36. package/catalog/agents/refactoring-specialist/references/safe-workflow.md +75 -0
  37. package/catalog/agents/refactoring-specialist/references/smell-catalog.md +76 -0
  38. package/catalog/agents/refactoring-specialist/scripts/detect-smells.mjs +150 -0
  39. package/catalog/agents/security-auditor/AGENT.md +168 -0
  40. package/catalog/agents/security-auditor/examples/audit-report.md +68 -0
  41. package/catalog/agents/security-auditor/examples/finding-template.md +31 -0
  42. package/catalog/agents/security-auditor/references/audit-workflow.md +116 -0
  43. package/catalog/agents/security-auditor/references/severity-and-reporting.md +56 -0
  44. package/catalog/agents/security-auditor/references/vuln-classes.md +129 -0
  45. package/catalog/agents/security-auditor/scripts/scan-secrets.mjs +86 -0
  46. package/catalog/agents/technical-writer/AGENT.md +163 -0
  47. package/catalog/agents/technical-writer/examples/how-to-example.md +76 -0
  48. package/catalog/agents/technical-writer/examples/reference-example.md +75 -0
  49. package/catalog/agents/technical-writer/references/clarity-and-style.md +52 -0
  50. package/catalog/agents/technical-writer/references/diataxis-and-doc-types.md +61 -0
  51. package/catalog/agents/technical-writer/references/structure-and-maintenance.md +59 -0
  52. package/catalog/agents/technical-writer/scripts/readability.mjs +103 -0
  53. package/catalog/agents/test-author/AGENT.md +177 -0
  54. package/catalog/agents/test-author/examples/test-plan.md +54 -0
  55. package/catalog/agents/test-author/examples/unit-test-example.ts +55 -0
  56. package/catalog/agents/test-author/references/aaa-and-naming.md +75 -0
  57. package/catalog/agents/test-author/references/mocking-and-fixtures.md +94 -0
  58. package/catalog/agents/test-author/references/test-types-and-pyramid.md +60 -0
  59. package/catalog/agents/test-author/scripts/check-coverage.mjs +145 -0
  60. package/catalog/agents/threat-modeler/AGENT.md +163 -0
  61. package/catalog/agents/threat-modeler/examples/dfd-example.md +55 -0
  62. package/catalog/agents/threat-modeler/examples/threat-model.md +81 -0
  63. package/catalog/agents/threat-modeler/references/dfd-and-trust-boundaries.md +76 -0
  64. package/catalog/agents/threat-modeler/references/mitigation-catalog.md +77 -0
  65. package/catalog/agents/threat-modeler/references/stride-method.md +68 -0
  66. package/catalog/agents/threat-modeler/scripts/stride-checklist.mjs +183 -0
  67. package/catalog/agents/vuln-scanner/AGENT.md +146 -0
  68. package/catalog/agents/vuln-scanner/examples/finding-template.md +57 -0
  69. package/catalog/agents/vuln-scanner/examples/scan-report.md +49 -0
  70. package/catalog/agents/vuln-scanner/references/remediation-and-severity.md +68 -0
  71. package/catalog/agents/vuln-scanner/references/scan-types-and-tools.md +83 -0
  72. package/catalog/agents/vuln-scanner/references/triage-and-false-positives.md +73 -0
  73. package/catalog/agents/vuln-scanner/scripts/parse-scan-results.mjs +133 -0
  74. package/catalog/packs/code-review-pack/PACK.md +100 -0
  75. package/catalog/packs/code-review-pack/examples/pr-flow-example.md +50 -0
  76. package/catalog/packs/code-review-pack/references/rollout-guide.md +40 -0
  77. package/catalog/packs/security-pack/PACK.md +128 -0
  78. package/catalog/packs/security-pack/examples/owasp-vuln-triage-and-fix.md +66 -0
  79. package/catalog/packs/security-pack/examples/threat-model-then-audit.md +77 -0
  80. package/catalog/packs/security-pack/references/choosing-the-right-tool.md +37 -0
  81. package/catalog/packs/security-pack/references/threat-model-to-remediation.md +69 -0
  82. package/catalog/packs/security-pack/references/workflow.md +56 -0
  83. package/catalog/skills/api-pagination/SKILL.md +83 -0
  84. package/catalog/skills/api-pagination/examples/keyset-queries.sql +38 -0
  85. package/catalog/skills/api-pagination/examples/response-shapes.md +51 -0
  86. package/catalog/skills/api-pagination/references/consuming-pages.md +39 -0
  87. package/catalog/skills/api-pagination/references/counting-and-totals.md +41 -0
  88. package/catalog/skills/api-pagination/references/cursor-encoding.md +34 -0
  89. package/catalog/skills/api-pagination/scripts/check-cursor.mjs +51 -0
  90. package/catalog/skills/caching-strategies/SKILL.md +180 -0
  91. package/catalog/skills/caching-strategies/examples/http-cache-headers.md +82 -0
  92. package/catalog/skills/caching-strategies/examples/redis-cache-aside.js +110 -0
  93. package/catalog/skills/caching-strategies/references/cache-patterns.md +93 -0
  94. package/catalog/skills/caching-strategies/references/eviction-and-ttl.md +67 -0
  95. package/catalog/skills/caching-strategies/references/invalidation-and-stampede.md +99 -0
  96. package/catalog/skills/caching-strategies/scripts/ttl-jitter.mjs +99 -0
  97. package/catalog/skills/conventional-commits/SKILL.md +135 -0
  98. package/catalog/skills/conventional-commits/examples/commit-examples.md +60 -0
  99. package/catalog/skills/conventional-commits/examples/commitlint.config.js +31 -0
  100. package/catalog/skills/conventional-commits/references/breaking-changes-semver.md +50 -0
  101. package/catalog/skills/conventional-commits/references/scoping-commits.md +42 -0
  102. package/catalog/skills/conventional-commits/references/spec.md +78 -0
  103. package/catalog/skills/conventional-commits/scripts/lint-commit.mjs +97 -0
  104. package/catalog/skills/database-migrations/SKILL.md +137 -0
  105. package/catalog/skills/database-migrations/examples/add-column-safe.sql +34 -0
  106. package/catalog/skills/database-migrations/examples/migration-config.example.json +27 -0
  107. package/catalog/skills/database-migrations/references/expand-contract.md +74 -0
  108. package/catalog/skills/database-migrations/references/rollback-and-safety.md +71 -0
  109. package/catalog/skills/database-migrations/references/zero-downtime-changes.md +84 -0
  110. package/catalog/skills/database-migrations/scripts/check-migration-reversible.mjs +139 -0
  111. package/catalog/skills/error-handling-patterns/SKILL.md +136 -0
  112. package/catalog/skills/error-handling-patterns/examples/express-error-middleware.js +93 -0
  113. package/catalog/skills/error-handling-patterns/examples/result-pattern.ts +81 -0
  114. package/catalog/skills/error-handling-patterns/references/error-taxonomy.md +91 -0
  115. package/catalog/skills/error-handling-patterns/references/language-patterns.md +102 -0
  116. package/catalog/skills/error-handling-patterns/references/retry-and-backoff.md +76 -0
  117. package/catalog/skills/error-handling-patterns/scripts/lint-empty-catch.mjs +113 -0
  118. package/catalog/skills/git-collaboration-workflows/SKILL.md +104 -0
  119. package/catalog/skills/git-collaboration-workflows/examples/branch-protection.md +48 -0
  120. package/catalog/skills/git-collaboration-workflows/examples/pr-review-playbook.md +48 -0
  121. package/catalog/skills/git-collaboration-workflows/references/branching-models.md +52 -0
  122. package/catalog/skills/git-collaboration-workflows/references/history-hygiene.md +44 -0
  123. package/catalog/skills/git-collaboration-workflows/scripts/check-branch-hygiene.mjs +62 -0
  124. package/catalog/skills/owasp-top10/SKILL.md +112 -0
  125. package/catalog/skills/owasp-top10/examples/sql-injection-fix.md +33 -0
  126. package/catalog/skills/owasp-top10/examples/xss-fix.md +27 -0
  127. package/catalog/skills/owasp-top10/references/access-control.md +36 -0
  128. package/catalog/skills/owasp-top10/references/crypto-failures.md +29 -0
  129. package/catalog/skills/owasp-top10/references/injection.md +39 -0
  130. package/catalog/skills/owasp-top10/references/ssrf-and-design.md +35 -0
  131. package/catalog/skills/owasp-top10/scripts/scan-injection.mjs +73 -0
  132. package/catalog/skills/prompt-engineering/SKILL.md +100 -0
  133. package/catalog/skills/prompt-engineering/examples/classification-prompt.md +29 -0
  134. package/catalog/skills/prompt-engineering/examples/extraction-prompt.md +25 -0
  135. package/catalog/skills/prompt-engineering/references/prompt-injection.md +34 -0
  136. package/catalog/skills/prompt-engineering/references/structured-output.md +34 -0
  137. package/catalog/skills/prompt-engineering/references/techniques.md +33 -0
  138. package/catalog/skills/prompt-engineering/scripts/validate-output.mjs +71 -0
  139. package/catalog/skills/readme-writing/SKILL.md +176 -0
  140. package/catalog/skills/readme-writing/examples/README.template.md +73 -0
  141. package/catalog/skills/readme-writing/examples/good-readme-example.md +95 -0
  142. package/catalog/skills/readme-writing/references/anatomy.md +107 -0
  143. package/catalog/skills/readme-writing/references/maintenance.md +68 -0
  144. package/catalog/skills/readme-writing/references/writing-style.md +79 -0
  145. package/catalog/skills/readme-writing/scripts/lint-readme.mjs +117 -0
  146. package/catalog/skills/refactoring-patterns/SKILL.md +178 -0
  147. package/catalog/skills/refactoring-patterns/examples/extract-function.before-after.js +57 -0
  148. package/catalog/skills/refactoring-patterns/examples/replace-conditional-with-polymorphism.before-after.ts +63 -0
  149. package/catalog/skills/refactoring-patterns/references/code-smells.md +92 -0
  150. package/catalog/skills/refactoring-patterns/references/refactoring-catalog.md +78 -0
  151. package/catalog/skills/refactoring-patterns/references/safe-workflow.md +74 -0
  152. package/catalog/skills/refactoring-patterns/scripts/detect-smells.mjs +137 -0
  153. package/catalog/skills/rest-api-design/SKILL.md +147 -0
  154. package/catalog/skills/rest-api-design/examples/error-envelope.json +26 -0
  155. package/catalog/skills/rest-api-design/examples/orders-api.openapi.yaml +106 -0
  156. package/catalog/skills/rest-api-design/references/error-handling.md +43 -0
  157. package/catalog/skills/rest-api-design/references/pagination.md +41 -0
  158. package/catalog/skills/rest-api-design/references/status-codes.md +32 -0
  159. package/catalog/skills/rest-api-design/references/versioning.md +31 -0
  160. package/catalog/skills/rest-api-design/scripts/check-envelope.mjs +62 -0
  161. package/catalog/skills/secrets-management/SKILL.md +134 -0
  162. package/catalog/skills/secrets-management/examples/env-example.md +41 -0
  163. package/catalog/skills/secrets-management/examples/rotation-runbook.md +50 -0
  164. package/catalog/skills/secrets-management/references/leak-response.md +47 -0
  165. package/catalog/skills/secrets-management/references/rotation.md +46 -0
  166. package/catalog/skills/secrets-management/references/secret-managers.md +52 -0
  167. package/catalog/skills/secrets-management/scripts/detect-hardcoded.mjs +96 -0
  168. package/catalog/skills/secure-auth/SKILL.md +135 -0
  169. package/catalog/skills/secure-auth/examples/auth-flow.md +60 -0
  170. package/catalog/skills/secure-auth/examples/jwt-verify.ts +89 -0
  171. package/catalog/skills/secure-auth/references/auth-attacks.md +76 -0
  172. package/catalog/skills/secure-auth/references/oauth2-oidc.md +65 -0
  173. package/catalog/skills/secure-auth/references/password-hashing.md +70 -0
  174. package/catalog/skills/secure-auth/references/sessions-vs-jwt.md +69 -0
  175. package/catalog/skills/secure-auth/scripts/check-password-policy.mjs +114 -0
  176. package/catalog/skills/sql-index-tuning/SKILL.md +171 -0
  177. package/catalog/skills/sql-index-tuning/examples/explain-walkthrough.sql +91 -0
  178. package/catalog/skills/sql-index-tuning/examples/index-ddl.sql +67 -0
  179. package/catalog/skills/sql-index-tuning/references/btree-internals.md +58 -0
  180. package/catalog/skills/sql-index-tuning/references/composite-and-covering.md +60 -0
  181. package/catalog/skills/sql-index-tuning/references/reading-explain.md +54 -0
  182. package/catalog/skills/sql-index-tuning/references/selectivity-and-cardinality.md +62 -0
  183. package/catalog/skills/sql-index-tuning/scripts/suggest-index.mjs +213 -0
  184. package/catalog/skills/test-plan-design/SKILL.md +154 -0
  185. package/catalog/skills/test-plan-design/examples/test-case-template.md +45 -0
  186. package/catalog/skills/test-plan-design/examples/test-plan.md +57 -0
  187. package/catalog/skills/test-plan-design/references/case-design.md +79 -0
  188. package/catalog/skills/test-plan-design/references/risk-prioritization.md +58 -0
  189. package/catalog/skills/test-plan-design/references/test-pyramid.md +58 -0
  190. package/catalog/skills/test-plan-design/scripts/coverage-gaps.mjs +109 -0
  191. package/free-tier.json +15 -0
  192. package/package.json +15 -4
  193. package/premium-index.json +1 -0
  194. package/src/config.js +31 -1
  195. package/src/license.js +143 -0
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ // Runnable check: flags maintainability violations from a diff-stat-like JSON so a
3
+ // reviewer (human or agent) can mechanically catch oversized functions and files
4
+ // before the manual pass. Mirrors the --selftest convention of check-envelope.mjs.
5
+ //
6
+ // Input shape (a "diff stat"):
7
+ // {
8
+ // "files": [
9
+ // { "path": "a.js", "lines": 120,
10
+ // "functions": [ { "name": "doThing", "lines": 40 } ] }
11
+ // ]
12
+ // }
13
+ //
14
+ // Usage:
15
+ // node review-guard.mjs '<json>' # check a literal JSON string
16
+ // echo '<json>' | node review-guard.mjs # check from stdin
17
+ // node review-guard.mjs --selftest # run built-in test cases
18
+
19
+ const MAX_FUNC_LINES = 50; // functions should stay under 50 lines
20
+ const MAX_FILE_LINES = 800; // files should stay under 800 lines
21
+
22
+ export function reviewGuard(stat) {
23
+ const violations = [];
24
+ const files = (stat && Array.isArray(stat.files)) ? stat.files : [];
25
+ for (const f of files) {
26
+ const path = f.path ?? '<unknown>';
27
+ if (typeof f.lines === 'number' && f.lines > MAX_FILE_LINES) {
28
+ violations.push({
29
+ severity: 'MEDIUM',
30
+ where: path,
31
+ msg: `file is ${f.lines} lines (> ${MAX_FILE_LINES}); split into smaller modules`,
32
+ });
33
+ }
34
+ const fns = Array.isArray(f.functions) ? f.functions : [];
35
+ for (const fn of fns) {
36
+ if (typeof fn.lines === 'number' && fn.lines > MAX_FUNC_LINES) {
37
+ violations.push({
38
+ severity: 'MEDIUM',
39
+ where: `${path}:${fn.name ?? '<anon>'}`,
40
+ msg: `function is ${fn.lines} lines (> ${MAX_FUNC_LINES}); extract focused helpers`,
41
+ });
42
+ }
43
+ }
44
+ }
45
+ return { ok: violations.length === 0, violations };
46
+ }
47
+
48
+ function check(label, json) {
49
+ let stat;
50
+ try { stat = typeof json === 'string' ? JSON.parse(json) : json; }
51
+ catch { console.error(`✗ ${label}: invalid JSON`); return false; }
52
+ const { ok, violations } = reviewGuard(stat);
53
+ if (ok) console.log(`✓ ${label}: no oversized functions or files`);
54
+ else {
55
+ console.error(`✗ ${label}: ${violations.length} violation(s)`);
56
+ violations.forEach((v) => console.error(` [${v.severity}] ${v.where} — ${v.msg}`));
57
+ }
58
+ return ok;
59
+ }
60
+
61
+ function selftest() {
62
+ const cases = {
63
+ clean: {
64
+ files: [
65
+ { path: 'ok.js', lines: 120, functions: [{ name: 'small', lines: 20 }] },
66
+ ],
67
+ },
68
+ bad_big_function: {
69
+ files: [
70
+ { path: 'svc.js', lines: 200, functions: [{ name: 'processOrder', lines: 59 }] },
71
+ ],
72
+ },
73
+ bad_big_file: {
74
+ files: [
75
+ { path: 'huge.js', lines: 1200, functions: [{ name: 'fine', lines: 10 }] },
76
+ ],
77
+ },
78
+ bad_both: {
79
+ files: [
80
+ { path: 'monster.js', lines: 900, functions: [{ name: 'god', lines: 300 }] },
81
+ ],
82
+ },
83
+ };
84
+ let allExpected = true;
85
+ for (const [name, payload] of Object.entries(cases)) {
86
+ const { ok } = reviewGuard(payload);
87
+ const shouldPass = name === 'clean';
88
+ const correct = ok === shouldPass;
89
+ allExpected &&= correct;
90
+ console.log(`${correct ? '✓' : '✗'} selftest ${name}: ${ok ? 'clean' : 'violations'} (expected ${shouldPass ? 'clean' : 'violations'})`);
91
+ }
92
+ process.exit(allExpected ? 0 : 1);
93
+ }
94
+
95
+ const arg = process.argv[2];
96
+ if (arg === '--selftest') selftest();
97
+ else if (arg) process.exit(check('diff-stat', arg) ? 0 : 1);
98
+ else {
99
+ let buf = '';
100
+ process.stdin.on('data', (c) => (buf += c));
101
+ process.stdin.on('end', () => process.exit(check('stdin', buf) ? 0 : 1));
102
+ }
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: debugger
3
+ description: Hypothesis-driven debugging specialist. Use PROACTIVELY when a test fails, an exception or stack trace appears, a build breaks, or behavior is unexpected. Reproduces the failure, bisects to the root cause, fixes the smallest surface, and adds a regression test — never patches symptoms.
4
+ tools: Read, Grep, Glob, Bash, Edit
5
+ model: claude-sonnet-4-6
6
+ type: agent
7
+ version: 2.0.0
8
+ updated: 2026-06-29
9
+ ---
10
+ # Debugger
11
+
12
+ You are a disciplined debugging specialist. You find **root causes, not band-aids**. Debugging is not
13
+ guesswork — it is the scientific method applied to code: observe, hypothesize, predict, test, repeat. You
14
+ change code only *after* a hypothesis is confirmed, and you change as little as possible.
15
+
16
+ The single most important rule: **make the bug reproducible before you try to fix it.** A bug you cannot
17
+ reproduce is a bug you cannot prove you fixed. If you change code while the failure is intermittent, a
18
+ "fix" that coincides with the bug not appearing is indistinguishable from luck.
19
+
20
+ ## The method
21
+
22
+ Work this loop in order. Do not skip ahead — most bad fixes come from jumping to step 5 from step 1.
23
+
24
+ 1. **Reproduce.** Capture the exact input, environment, and steps that trigger the failure. Reduce it to
25
+ the smallest deterministic repro (see `examples/repro-template.md`). Save the full error text verbatim.
26
+ 2. **Read the error.** The message and stack trace usually name the file and line. Read it *top to bottom*
27
+ for the exception type and message; read the frames *top of user code first* for where your code is
28
+ involved. Details in `references/observability.md`.
29
+ 3. **Localize / bisect.** Narrow *where* the bad state originates. Binary-search the input, the code path,
30
+ or the commit history (`git bisect`). Halve the search space each step — see `references/bisection.md`.
31
+ 4. **Hypothesize.** State the single most likely cause in one falsifiable sentence: "X is null here because
32
+ Y returns undefined when the cache misses." A hypothesis you can't test is not a hypothesis.
33
+ 5. **Test the hypothesis.** Confirm with a targeted probe — a log line, a breakpoint, an assertion, a unit
34
+ test — *before* editing the fix. Change one variable at a time so the signal stays clean.
35
+ 6. **Fix at the cause.** Edit the smallest surface that addresses the confirmed cause, not the symptom.
36
+ 7. **Verify & prevent regression.** Re-run the repro: it must now pass. Add a regression test that fails
37
+ on the old code and passes on the new. Then run the surrounding suite to confirm no new breakage.
38
+
39
+ ## Symptom vs root cause
40
+
41
+ The symptom is *where it crashed*; the cause is *why the bad state arose*. A `NullPointerException` on
42
+ line 200 is the symptom — the cause may be a function 50 lines earlier that returned `null` instead of
43
+ throwing. Patching line 200 with a null check hides the real defect and lets corrupt state spread. Always
44
+ trace the bad value back to its **origin**.
45
+
46
+ ```text
47
+ Symptom fix: if (user != null) { ... } // silences the crash, bug still there
48
+ Root fix: // findUser() now throws NotFound instead of returning null on a cache miss
49
+ ```
50
+
51
+ ## Reading a stack trace
52
+
53
+ A stack trace is a map. Read the exception type and message first, then find the **topmost frame in your
54
+ own code** (skip framework/library frames) — that is almost always where to start looking.
55
+
56
+ ```text
57
+ TypeError: Cannot read properties of undefined (reading 'id') <- WHAT failed
58
+ at formatOrder (src/orders/format.js:42:18) <- TOP user frame: START HERE
59
+ at Array.map (<anonymous>) <- library frame, skip
60
+ at renderOrders (src/orders/list.js:88:24) <- caller: how we got here
61
+ at handleRequest (src/server.js:130:9) <- entry point
62
+ ```
63
+
64
+ Line 42 of `format.js` is where the bad value was *used*; lines 88 and 130 tell you the *path* that
65
+ produced it. Walk down the trace to find which caller passed the undefined value.
66
+
67
+ ## Common pitfalls (failure modes)
68
+
69
+ - **Fixing the symptom, not the cause.** A null check that silences a crash leaves the real defect alive.
70
+ - **Changing many things at once.** If you edit five things and the bug disappears, you don't know which
71
+ one mattered — and you may have introduced two new bugs. Change one variable per iteration.
72
+ - **No reproduction.** "It seems fixed" after a non-deterministic failure is not evidence. Get a repro first.
73
+ - **Ignoring the error message.** The message and stack trace usually *say* what's wrong. Read them fully
74
+ before theorizing.
75
+ - **Debugging by coincidence.** Adding random `sleep`/retries/try-catch until it "works" hides race
76
+ conditions and resource bugs instead of fixing them.
77
+ - **Trusting assumptions over observation.** "That can't be null" — prove it with a log, don't assume it.
78
+ - **Skipping the regression test.** Without one, the same bug returns the next time someone refactors.
79
+
80
+ ## When NOT to use / boundaries
81
+
82
+ - **Not a feature builder.** This agent diagnoses and fixes defects; for new functionality use a
83
+ planning/TDD workflow instead.
84
+ - **Not a performance profiler.** Slowness without incorrectness is a profiling task, not a bug hunt
85
+ (though the bisection method still applies to perf regressions).
86
+ - **Not a security auditor.** If the "bug" is a vulnerability, hand off to the `security-auditor` agent.
87
+ - **Don't guess-edit when you can't reproduce.** If reproduction is impossible, say so and list exactly
88
+ what you'd need (logs, env, input) rather than editing hopefully.
89
+ - **Don't disable tests or loosen assertions to make red go green** — that destroys the signal that
90
+ caught the bug.
91
+
92
+ ## Output format
93
+
94
+ Report in this structure:
95
+
96
+ - **Reproduction** — the minimal steps/input that trigger the failure.
97
+ - **Root cause** — the confirmed cause with `file:line`, distinguished from the symptom.
98
+ - **Fix** — the minimal diff at the cause.
99
+ - **Regression test** — a test that fails before, passes after.
100
+ - **Verification** — what you re-ran to confirm green.
101
+
102
+ ## Files in this package
103
+
104
+ - `references/debugging-method.md` — the scientific, hypothesis-driven loop in depth
105
+ - `references/bisection.md` — `git bisect` + binary-search isolation techniques
106
+ - `references/observability.md` — logs/metrics/traces, reading stack traces & core dumps
107
+ - `examples/repro-template.md` — minimal reproduction checklist
108
+ - `examples/postmortem-template.md` — blameless postmortem write-up template
109
+ - `scripts/parse-stacktrace.mjs` — extracts the top user-code frame from a JS/Python stack trace
110
+
111
+ Pairs with the `code-reviewer` agent (review the fix before merge), the `tdd-guide` agent (turn the repro
112
+ into a failing test first), and the `error-handling-patterns` skill (so the cause can't silently recur).
@@ -0,0 +1,59 @@
1
+ # Blameless Postmortem Template
2
+
3
+ Write this after a significant bug or incident is resolved. The goal is **systems, not scapegoats** — ask
4
+ how the process let the defect through, not who typed it.
5
+
6
+ ## Summary
7
+
8
+ - **Title:** _short description of the failure_
9
+ - **Date / duration:** _when it started, when it was resolved_
10
+ - **Severity / impact:** _who/what was affected, how badly (users, data, revenue)_
11
+ - **Status:** Resolved / Mitigated / Monitoring
12
+
13
+ ## Timeline (UTC)
14
+
15
+ | Time | Event |
16
+ |---|---|
17
+ | 14:01 | Deploy of `abc123` |
18
+ | 14:05 | Error rate alarm fires |
19
+ | 14:12 | On-call acknowledges, begins investigation |
20
+ | 14:30 | Root cause identified (see below) |
21
+ | 14:38 | Fix deployed, error rate normal |
22
+
23
+ ## Root cause
24
+
25
+ State the **confirmed** cause, distinguished from the symptom, with `file:line` and the commit that
26
+ introduced it. Explain *why the bad state arose*, not just where it crashed.
27
+
28
+ > e.g. `applyDiscount` mutated the shared `cart` array (`src/cart.js:48`), so a retried request applied
29
+ > the discount twice. The symptom was a wrong total at checkout; the cause was shared mutable state.
30
+
31
+ ## Detection
32
+
33
+ - How was it found? (alarm / customer report / log)
34
+ - How long until detection? Could a metric or test have caught it sooner?
35
+
36
+ ## Resolution & recovery
37
+
38
+ - What fixed it (the minimal change at the cause)?
39
+ - Any cleanup needed (data backfill, cache invalidation)?
40
+
41
+ ## The five whys
42
+
43
+ 1. Why did the total double? → discount applied twice.
44
+ 2. Why twice? → request was retried and the cart was mutated.
45
+ 3. Why was it mutated? → `applyDiscount` edited the array in place.
46
+ 4. Why in place? → no immutability convention in cart code.
47
+ 5. Why no convention? → no lint rule / review check for shared mutation.
48
+
49
+ ## Action items
50
+
51
+ | Action | Owner | Type | Status |
52
+ |---|---|---|---|
53
+ | Add regression test for double-retry discount | | prevent | |
54
+ | Make cart operations immutable | | fix-class | |
55
+ | Add alarm on total-mismatch metric | | detect | |
56
+
57
+ ## What went well / what was lucky
58
+
59
+ _Separate good process from good fortune — luck isn't repeatable._
@@ -0,0 +1,50 @@
1
+ # Minimal Reproduction Checklist
2
+
3
+ A bug isn't ready to fix until you can trigger it on demand. Fill this out *before* editing any code.
4
+
5
+ ## 1. The failure (verbatim)
6
+
7
+ - **Error message / stack trace:** _paste the full text, unedited_
8
+ - **Where it surfaced:** `file:line` of the top user-code frame
9
+ - **Expected vs actual behavior:** _one line each_
10
+
11
+ ## 2. The trigger
12
+
13
+ - **Exact input / steps:**
14
+ 1. _step_
15
+ 2. _step_
16
+ 3. _failure observed_
17
+ - **Frequency:** [ ] every time [ ] intermittent (___ % of runs) [ ] only under load/concurrency
18
+ - **First seen:** _commit / version / date_ — and the last known-good version, if any
19
+
20
+ ## 3. The environment
21
+
22
+ | Factor | Value |
23
+ |---|---|
24
+ | OS / runtime version | |
25
+ | Dependency versions | |
26
+ | Config / env vars | |
27
+ | Data / fixtures | |
28
+
29
+ ## 4. Reduce to the minimum
30
+
31
+ Strip everything that *doesn't* affect the outcome until you have the smallest case that still fails:
32
+
33
+ - [ ] Removed unrelated code paths
34
+ - [ ] Replaced external calls with fixed stubs/fixtures
35
+ - [ ] Hard-coded the triggering input
36
+ - [ ] Confirmed it **still fails** after reduction
37
+ - [ ] Confirmed it is **deterministic** (or documented the flake rate + suspected race)
38
+
39
+ ## 5. The repro artifact
40
+
41
+ A runnable snippet or single failing test is the goal — paste it here:
42
+
43
+ ```text
44
+ # minimal failing command or test
45
+ $ npm test -- checkout.spec.js -t "applies discount once"
46
+ ✗ applies discount once (expected 90, got 81)
47
+ ```
48
+
49
+ > If you cannot produce a deterministic repro after a bounded effort, **stop**. Record what you tried and
50
+ > exactly what additional evidence (logs, prod input, env access) you need — do not guess-edit.
@@ -0,0 +1,63 @@
1
+ # Bisection — Binary Search for Bugs
2
+
3
+ When reasoning stalls, *search*. Halving the problem space repeatedly finds the culprit in log₂(N) steps
4
+ instead of N. Bisection applies to three spaces: **history** (which commit), **code** (which statement),
5
+ and **input** (which data).
6
+
7
+ ## 1. History: `git bisect`
8
+
9
+ When a bug appeared "sometime in the last 200 commits," let git binary-search them. Mark a known-bad and
10
+ known-good revision; git checks out the midpoint and you tell it good or bad until it names the culprit.
11
+
12
+ ```bash
13
+ git bisect start
14
+ git bisect bad # current HEAD is broken
15
+ git bisect good v1.4.0 # this old tag worked
16
+ # git checks out the midpoint; test it, then:
17
+ git bisect good # ...or: git bisect bad
18
+ # repeat until git prints "<sha> is the first bad commit"
19
+ git bisect reset # return to where you started
20
+ ```
21
+
22
+ Automate it when you have a script that exits 0 (good) / non-zero (bad):
23
+
24
+ ```bash
25
+ git bisect start HEAD v1.4.0
26
+ git bisect run npm test -- --testPathPattern=checkout
27
+ ```
28
+
29
+ `git bisect run` will drive the entire search unattended and print the first bad commit. Keep the test
30
+ fast and deterministic, or the search inherits its flakiness.
31
+
32
+ ## 2. Code: bisect the execution path
33
+
34
+ Within a single bad function, find *where* the state goes wrong by checking the midpoint. Print or assert
35
+ the suspect value halfway through; if it's already wrong, the bug is in the first half — otherwise the
36
+ second. Repeat on the bad half.
37
+
38
+ ```text
39
+ function process(x) {
40
+ step A // assert(valid) here -> OK? search lower half
41
+ step B
42
+ step C // <-- midpoint probe: value already corrupt? bug is A/B
43
+ step D
44
+ step E // assert(valid) here -> still OK? bug is D/E
45
+ }
46
+ ```
47
+
48
+ A "wolf-fence" probe (a single well-placed log of the suspect value) beats scattering ten prints.
49
+
50
+ ## 3. Input: bisect the data
51
+
52
+ A 100k-row file that crashes the parser? Don't read 100k rows. Feed the first half — still crashes? The
53
+ offending row is in that half. Halve again. ~17 iterations isolate one row out of 100k. The same works
54
+ for narrowing a failing config to one key, or a failing request to one field.
55
+
56
+ ## Pitfalls
57
+
58
+ - **Non-deterministic test → useless bisect.** Flaky good/bad answers send the search to the wrong commit.
59
+ Stabilize the repro first.
60
+ - **Skipping untestable midpoints.** If a midpoint commit won't build, use `git bisect skip` — don't guess.
61
+ - **Forgetting `git bisect reset`** leaves you on a detached checkout.
62
+ - **Too-coarse halving.** Bisect to the *commit*, then bisect *within* it to the statement; don't stop at
63
+ "this 400-line commit did it."
@@ -0,0 +1,57 @@
1
+ # The Debugging Method — Hypothesis-Driven
2
+
3
+ Debugging is the scientific method applied to a misbehaving system. You don't "stare at code until you
4
+ see it"; you run controlled experiments that each rule something in or out.
5
+
6
+ ## The loop
7
+
8
+ ```text
9
+ observe ──> hypothesize ──> predict ──> experiment ──> compare
10
+ ^ │
11
+ └──────────────────── refine ─────────────────────────┘
12
+ ```
13
+
14
+ 1. **Observe.** Collect the facts: the exact error, the input, the environment, what changed recently.
15
+ Resist theorizing before you have the message in front of you.
16
+ 2. **Hypothesize.** Propose one *falsifiable* cause: "The total is wrong because `applyDiscount` mutates
17
+ the shared `cart` array." A good hypothesis predicts something you can check.
18
+ 3. **Predict.** If the hypothesis is true, what must also be true? "Then logging `cart` before and after
19
+ should show it changed."
20
+ 4. **Experiment.** Run the smallest test that distinguishes the hypothesis from its alternatives. Change
21
+ **one variable at a time**.
22
+ 5. **Compare.** Did the prediction hold? If yes, you've localized the cause. If no, the hypothesis is
23
+ wrong — discard it (don't patch it) and form a new one from what you learned.
24
+
25
+ ## Why "one variable at a time" is non-negotiable
26
+
27
+ If you change input, code, and config simultaneously and the bug vanishes, the experiment has no signal:
28
+ you cannot attribute the change. Worse, multi-change "fixes" routinely introduce new defects that hide
29
+ behind the apparent success. Keep a clean control: a known-failing case you re-run after each change.
30
+
31
+ ## Rubber-duck and assumption auditing
32
+
33
+ Explain the failing path aloud, line by line, to an imaginary listener. The bug is usually hidden in a
34
+ step you *assumed* was correct and therefore never checked. Make a list of your assumptions and verify the
35
+ cheapest ones first:
36
+
37
+ - "This value is never null." → log it.
38
+ - "This branch always runs." → add a counter.
39
+ - "These two configs match." → diff them.
40
+
41
+ ## Confirmation before fixing
42
+
43
+ The most common mistake is editing the fix before confirming the hypothesis. Confirm first with a probe
44
+ (log, assertion, debugger, unit test). Only then edit — and only the smallest surface at the **origin** of
45
+ the bad state, not the place where it finally crashed.
46
+
47
+ ## Binary search of everything
48
+
49
+ When you can't reason your way to the cause, *search* for it. Halve the space repeatedly: comment out half
50
+ the code, feed half the input, check the midpoint commit. See `bisection.md`. Each halving turns an
51
+ N-step problem into log₂(N) steps — a 1,000-line search becomes ~10 checks.
52
+
53
+ ## Knowing when to stop
54
+
55
+ Stop and escalate (or write down what you need) when: you cannot reproduce after a bounded effort; the
56
+ cause is in a third-party dependency you can't change; or two equally-likely hypotheses both survive
57
+ testing and you need more instrumentation. Guessing past this point produces band-aids.
@@ -0,0 +1,61 @@
1
+ # Observability — Reading the Evidence
2
+
3
+ You can't fix what you can't see. Observability is the practice of making a system's internal state
4
+ inspectable from the outside, through three complementary signals plus the artifacts a crash leaves behind.
5
+
6
+ ## The three pillars
7
+
8
+ | Signal | Answers | Use for |
9
+ |---|---|---|
10
+ | **Logs** | "What happened, exactly here?" | discrete events, error context, the bad value |
11
+ | **Metrics** | "How much / how often, over time?" | rates, latencies, error %, spotting *when* a regression started |
12
+ | **Traces** | "What was the path across services?" | distributed call graphs, finding the slow/failing hop |
13
+
14
+ Logs give detail, metrics give trends, traces give causality across boundaries. A bug hunt usually starts
15
+ at a metric spike ("errors jumped at 14:05"), zooms to a trace ("the payment service hop failed"), then
16
+ lands on a log line with the exact exception.
17
+
18
+ ## Reading a stack trace
19
+
20
+ 1. **Exception type + message first** — `TypeError: Cannot read 'id' of undefined` tells you *what*.
21
+ 2. **Top user-code frame** — skip framework/stdlib frames; the first frame in *your* files is where to
22
+ start. (Note: Python prints oldest call first / failure **last**; JS prints failure **first**.)
23
+ 3. **Walk the callers** — each lower frame shows how execution reached the failure, i.e. who passed the
24
+ bad value.
25
+
26
+ ```text
27
+ JavaScript (most-recent first): Python (most-recent LAST):
28
+ TypeError: ... 'id' of undefined Traceback (most recent call last):
29
+ at formatOrder (format.js:42) File "list.py", line 88, in render
30
+ at renderOrders (list.js:88) File "format.py", line 42, in format_order
31
+ KeyError: 'id' <- read this line first
32
+ ```
33
+
34
+ Use `scripts/parse-stacktrace.mjs` to extract the top user frame mechanically from either format.
35
+
36
+ ## Logging that actually helps
37
+
38
+ - Log the **value and the context**, not "got here": `log('discount', {cartId, before, after})`.
39
+ - Use **structured** logs (JSON) so you can filter/aggregate, not grep prose.
40
+ - Use **levels** deliberately: `error` for failures, `warn` for recovered anomalies, `debug` for probes
41
+ you'll remove. Never leave `console.log` debug spew in committed code.
42
+ - Include a **correlation/request id** so you can stitch one request's logs together.
43
+
44
+ ## Core dumps & post-mortem artifacts
45
+
46
+ When a process dies hard, it may leave a snapshot of memory at the moment of death:
47
+
48
+ - **Native (C/C++/Go):** a core file — open with `gdb ./bin core` and `bt` for the backtrace, inspect
49
+ locals with `frame`/`print`.
50
+ - **Node:** run with `--abort-on-uncaught-exception` or use `--heapsnapshot-signal` / `--cpu-prof` for
51
+ memory and CPU forensics.
52
+ - **JVM:** an `hs_err_pid.log` plus a heap dump (`jmap`) you open in a memory analyzer.
53
+
54
+ These let you debug a failure you can observe but not re-trigger live.
55
+
56
+ ## Pitfalls
57
+
58
+ - **Logging after the failure.** Put probes *before* the suspect operation so you capture the bad input.
59
+ - **Too much log noise.** Drowning the signal is as bad as none; log the decisive values, not everything.
60
+ - **No timestamps / no ids.** Unordered, uncorrelated logs can't reconstruct a sequence.
61
+ - **Sensitive data in logs.** Never log secrets, tokens, or PII — redact at the boundary.
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ // Extract the top *user-code* frame (file:line) from a JS or Python stack trace.
3
+ // Framework / stdlib / node_modules frames are skipped so you land on YOUR code —
4
+ // the place a bug hunt should start (see references/observability.md).
5
+ //
6
+ // Usage:
7
+ // node parse-stacktrace.mjs "<trace text>" # parse a literal string
8
+ // cat trace.txt | node parse-stacktrace.mjs # parse from stdin
9
+ // node parse-stacktrace.mjs --selftest # run built-in tests (exit 0/1)
10
+
11
+ // Frames we consider "not user code" and skip when looking for the origin.
12
+ const NOISE = [
13
+ /node_modules[\\/]/,
14
+ /\bnode:internal\//,
15
+ /\b<anonymous>\b/,
16
+ /[\\/](site-packages|dist-packages)[\\/]/,
17
+ /[\\/]lib[\\/]python\d/i,
18
+ /\bin <module>\b.*\b(site-packages|python\d)/i,
19
+ ];
20
+
21
+ const isNoise = (line) => NOISE.some((re) => re.test(line));
22
+
23
+ // JS: " at formatOrder (src/orders/format.js:42:18)" or " at /a/b.js:10:5"
24
+ // Python: ' File "src/format.py", line 42, in format_order'
25
+ function parseFrame(line) {
26
+ const js = line.match(/^\s*at\s+(?:(.*?)\s+\()?(.+?):(\d+)(?::\d+)?\)?\s*$/);
27
+ if (js) {
28
+ return { func: js[1] || '<top>', file: js[2], line: Number(js[3]) };
29
+ }
30
+ const py = line.match(/^\s*File\s+"(.+?)",\s+line\s+(\d+)(?:,\s+in\s+(.*))?\s*$/);
31
+ if (py) {
32
+ return { func: (py[3] || '<module>').trim(), file: py[1], line: Number(py[2]) };
33
+ }
34
+ return null;
35
+ }
36
+
37
+ // Returns the top user frame. JS traces list the failure FIRST (scan top-down);
38
+ // Python lists it LAST (scan bottom-up). We detect Python by its "File ..." frames.
39
+ export function topUserFrame(trace) {
40
+ const lines = trace.split(/\r?\n/);
41
+ const isPython = lines.some((l) => /^\s*File\s+".+?",\s+line\s+\d+/.test(l));
42
+ const ordered = isPython ? [...lines].reverse() : lines;
43
+
44
+ let firstFrame = null;
45
+ for (const line of ordered) {
46
+ const frame = parseFrame(line);
47
+ if (!frame) continue;
48
+ if (!firstFrame) firstFrame = frame; // fallback if everything is "noise"
49
+ if (!isNoise(line)) return frame; // first non-noise frame = user code
50
+ }
51
+ return firstFrame; // all frames were noise: return the outermost we saw
52
+ }
53
+
54
+ function selftest() {
55
+ const jsTrace = [
56
+ "TypeError: Cannot read properties of undefined (reading 'id')",
57
+ ' at formatOrder (src/orders/format.js:42:18)',
58
+ ' at Array.map (<anonymous>)',
59
+ ' at renderOrders (src/orders/list.js:88:24)',
60
+ ' at handleRequest (node_modules/express/lib/router.js:12:3)',
61
+ ].join('\n');
62
+
63
+ const pyTrace = [
64
+ 'Traceback (most recent call last):',
65
+ ' File "/usr/lib/python3.11/runpy.py", line 196, in _run_module',
66
+ ' File "src/orders/list.py", line 88, in render',
67
+ ' File "src/orders/format.py", line 42, in format_order',
68
+ "KeyError: 'id'",
69
+ ].join('\n');
70
+
71
+ // A trace where the only frames are in node_modules -> fall back to outermost.
72
+ const noiseOnly = [
73
+ 'Error: boom',
74
+ ' at foo (node_modules/x/index.js:1:1)',
75
+ ].join('\n');
76
+
77
+ const cases = [
78
+ ['js top user frame', jsTrace, { file: 'src/orders/format.js', line: 42, func: 'formatOrder' }],
79
+ ['python top user frame', pyTrace, { file: 'src/orders/format.py', line: 42, func: 'format_order' }],
80
+ ['noise-only fallback', noiseOnly, { file: 'node_modules/x/index.js', line: 1, func: 'foo' }],
81
+ ];
82
+
83
+ let ok = true;
84
+ for (const [name, trace, want] of cases) {
85
+ const got = topUserFrame(trace) || {};
86
+ const pass = got.file === want.file && got.line === want.line && got.func === want.func;
87
+ ok &&= pass;
88
+ console.log(`${pass ? '✓' : '✗'} ${name}: ${got.func} @ ${got.file}:${got.line}` +
89
+ (pass ? '' : ` (expected ${want.func} @ ${want.file}:${want.line})`));
90
+ }
91
+ process.exit(ok ? 0 : 1);
92
+ }
93
+
94
+ function report(trace) {
95
+ const frame = topUserFrame(trace);
96
+ if (!frame) { console.error('No stack frame found in input.'); return false; }
97
+ console.log(`Top user-code frame: ${frame.func} @ ${frame.file}:${frame.line}`);
98
+ console.log('Start your investigation here.');
99
+ return true;
100
+ }
101
+
102
+ const arg = process.argv[2];
103
+ if (arg === '--selftest') selftest();
104
+ else if (arg) process.exit(report(arg) ? 0 : 1);
105
+ else {
106
+ let buf = '';
107
+ process.stdin.on('data', (c) => (buf += c));
108
+ process.stdin.on('end', () => process.exit(report(buf) ? 0 : 1));
109
+ }