@mohammadhprp/system-prompt 0.12.3 → 0.12.5

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 (69) hide show
  1. package/framework/commands/review.md +5 -20
  2. package/framework/skills/README.md +15 -0
  3. package/framework/skills/architect/SKILL.md +83 -0
  4. package/framework/skills/architect/examples.md +5 -0
  5. package/framework/skills/architect/references/design-red-flags.md +33 -0
  6. package/framework/skills/architect/references/rationale-template.md +35 -0
  7. package/framework/skills/architect/references/runner-prompt.md +20 -0
  8. package/framework/skills/arena/SKILL.md +71 -0
  9. package/framework/skills/arena/examples.md +5 -0
  10. package/framework/skills/bro/SKILL.md +7 -0
  11. package/framework/skills/bro/examples.md +5 -0
  12. package/framework/skills/changelog/SKILL.md +41 -0
  13. package/framework/skills/changelog/examples.md +5 -0
  14. package/framework/skills/commit/SKILL.md +28 -0
  15. package/framework/skills/commit/examples.md +5 -0
  16. package/framework/skills/gh/SKILL.md +157 -0
  17. package/framework/skills/gh/examples.md +10 -0
  18. package/framework/skills/how/SKILL.md +135 -0
  19. package/framework/skills/how/examples.md +5 -0
  20. package/framework/skills/how/references/critic-prompt.md +59 -0
  21. package/framework/skills/how/references/critique-rubric.md +58 -0
  22. package/framework/skills/how/references/explainer-prompt.md +55 -0
  23. package/framework/skills/how/references/explorer-prompt.md +52 -0
  24. package/framework/skills/merge-request/SKILL.md +40 -0
  25. package/framework/skills/merge-request/examples.md +5 -0
  26. package/framework/skills/ponytail/SKILL.md +145 -0
  27. package/framework/skills/ponytail/references/ponytail-audit.md +18 -0
  28. package/framework/skills/ponytail/references/ponytail-debt.md +21 -0
  29. package/framework/skills/ponytail/references/ponytail-gain.md +25 -0
  30. package/framework/skills/ponytail/references/ponytail-help.md +18 -0
  31. package/framework/skills/ponytail/references/ponytail-mode.md +33 -0
  32. package/framework/skills/ponytail/references/ponytail-review.md +27 -0
  33. package/framework/skills/ponytail/references/ponytail-rules.md +31 -0
  34. package/framework/skills/ponytail/references/principle-boundary-discipline.md +7 -0
  35. package/framework/skills/ponytail/references/principle-encode-lessons-in-structure.md +13 -0
  36. package/framework/skills/ponytail/references/principle-fix-root-causes.md +17 -0
  37. package/framework/skills/ponytail/references/principle-make-operations-idempotent.md +12 -0
  38. package/framework/skills/ponytail/references/principle-model-the-domain.md +7 -0
  39. package/framework/skills/ponytail/references/principle-prove-it-works.md +27 -0
  40. package/framework/skills/ponytail/references/principle-sequence-verifiable-units.md +7 -0
  41. package/framework/skills/pull-request/SKILL.md +31 -0
  42. package/framework/skills/pull-request/examples.md +5 -0
  43. package/framework/skills/release/SKILL.md +30 -0
  44. package/framework/skills/release/examples.md +5 -0
  45. package/framework/skills/review/SKILL.md +113 -0
  46. package/framework/skills/review/examples.md +6 -0
  47. package/framework/skills/review/scripts/render_review.py +95 -0
  48. package/framework/skills/review/scripts/resolve_spec_context.py +723 -0
  49. package/framework/skills/review/scripts/validate_review_json.py +348 -0
  50. package/framework/skills/tdd/SKILL.md +44 -0
  51. package/framework/skills/tdd/examples.md +5 -0
  52. package/framework/skills/unslop/SKILL.md +81 -0
  53. package/framework/skills/unslop/examples.md +5 -0
  54. package/framework/skills/why/SKILL.md +230 -0
  55. package/framework/skills/why/examples.md +5 -0
  56. package/framework/skills/why/references/epistemics.md +144 -0
  57. package/framework/skills/why/references/investigator-prompt.md +103 -0
  58. package/framework/skills/why/references/source-playbook.md +17 -0
  59. package/framework/skills/why/references/sources/code-archaeology.md +88 -0
  60. package/framework/skills/why/references/sources/databricks.md +70 -0
  61. package/framework/skills/why/references/sources/datadog.md +99 -0
  62. package/framework/skills/why/references/sources/incident-postmortem.md +15 -0
  63. package/framework/skills/why/references/sources/linear.md +48 -0
  64. package/framework/skills/why/references/sources/notion.md +55 -0
  65. package/framework/skills/why/references/sources/sentry.md +100 -0
  66. package/framework/skills/why/references/sources/slack.md +54 -0
  67. package/framework/skills/why/references/synthesizer-prompt.md +135 -0
  68. package/package.json +1 -1
  69. package/src/catalog.js +17 -2
@@ -0,0 +1,348 @@
1
+ #!/usr/bin/env python3
2
+ """Validate a review.json artifact against an annotated PR diff.
3
+
4
+ This script is packaged with the review-pr skill and must work when the skill
5
+ is copied into a consuming repository without the full oz-for-oss source tree.
6
+ Keep it self-contained: do not import helpers from the repository package.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import json
13
+ import re
14
+ import sys
15
+ from dataclasses import dataclass
16
+ from pathlib import Path
17
+ from typing import Any, TypedDict
18
+
19
+
20
+ class ReviewComment(TypedDict, total=False):
21
+ """Normalized review comment accepted by GitHub's create-review API."""
22
+
23
+ path: str
24
+ line: int
25
+ side: str
26
+ body: str
27
+ start_line: int
28
+ start_side: str
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class ReviewValidationResult:
33
+ """Validated review fields plus any comment-location errors."""
34
+
35
+ body: str
36
+ comments: list[ReviewComment]
37
+ errors: list[str]
38
+
39
+
40
+ SUGGESTION_BLOCK_PATTERN = re.compile(
41
+ r"```suggestion[^\n]*\r?\n(?P<content>.*?)\r?\n```",
42
+ re.DOTALL,
43
+ )
44
+ ANNOTATED_OLD_PATTERN = re.compile(r"^\[OLD:(?P<old>\d+)\] ?(?P<text>.*)$")
45
+ ANNOTATED_NEW_PATTERN = re.compile(r"^\[NEW:(?P<new>\d+)\] ?(?P<text>.*)$")
46
+ ANNOTATED_CONTEXT_PATTERN = re.compile(
47
+ r"^\[OLD:(?P<old>\d+),NEW:(?P<new>\d+)\] ?(?P<text>.*)$"
48
+ )
49
+
50
+
51
+ def normalize_review_path(value: Any) -> str:
52
+ path = str(value or "").strip()
53
+ path = re.sub(r"^(a/|b/|\./)", "", path)
54
+ return path
55
+
56
+
57
+ def build_diff_maps_from_annotated_diff(
58
+ diff_text: str,
59
+ ) -> tuple[dict[str, dict[str, set[int]]], dict[str, dict[str, dict[int, str]]]]:
60
+ """Build validation maps from the annotated diff shown to review agents."""
61
+ diff_line_map: dict[str, dict[str, set[int]]] = {}
62
+ diff_content_map: dict[str, dict[str, dict[int, str]]] = {}
63
+ current_path = ""
64
+ old_path = ""
65
+
66
+ def ensure_path(path: str) -> None:
67
+ diff_line_map.setdefault(path, {"LEFT": set(), "RIGHT": set()})
68
+ diff_content_map.setdefault(path, {"LEFT": {}, "RIGHT": {}})
69
+
70
+ for raw_line in diff_text.splitlines():
71
+ if raw_line.startswith("diff --git "):
72
+ current_path = ""
73
+ old_path = ""
74
+ continue
75
+ if raw_line.startswith("--- "):
76
+ candidate = raw_line[4:].strip()
77
+ old_path = (
78
+ "" if candidate == "/dev/null" else normalize_review_path(candidate)
79
+ )
80
+ continue
81
+ if raw_line.startswith("+++ "):
82
+ candidate = raw_line[4:].strip()
83
+ if candidate == "/dev/null":
84
+ current_path = old_path
85
+ else:
86
+ current_path = normalize_review_path(candidate)
87
+ if current_path:
88
+ ensure_path(current_path)
89
+ continue
90
+ if not current_path:
91
+ continue
92
+ old_match = ANNOTATED_OLD_PATTERN.match(raw_line)
93
+ if old_match:
94
+ line = int(old_match.group("old"))
95
+ text = old_match.group("text")
96
+ diff_line_map[current_path]["LEFT"].add(line)
97
+ diff_content_map[current_path]["LEFT"][line] = text
98
+ continue
99
+ new_match = ANNOTATED_NEW_PATTERN.match(raw_line)
100
+ if new_match:
101
+ line = int(new_match.group("new"))
102
+ text = new_match.group("text")
103
+ diff_line_map[current_path]["RIGHT"].add(line)
104
+ diff_content_map[current_path]["RIGHT"][line] = text
105
+ continue
106
+ context_match = ANNOTATED_CONTEXT_PATTERN.match(raw_line)
107
+ if context_match:
108
+ old_line = int(context_match.group("old"))
109
+ new_line = int(context_match.group("new"))
110
+ text = context_match.group("text")
111
+ diff_line_map[current_path]["LEFT"].add(old_line)
112
+ diff_line_map[current_path]["RIGHT"].add(new_line)
113
+ diff_content_map[current_path]["LEFT"][old_line] = text
114
+ diff_content_map[current_path]["RIGHT"][new_line] = text
115
+
116
+ return diff_line_map, diff_content_map
117
+
118
+
119
+ def _extract_suggestion_blocks(body: str | None) -> list[list[str]]:
120
+ blocks: list[list[str]] = []
121
+ for match in SUGGESTION_BLOCK_PATTERN.finditer(body or ""):
122
+ content = match.group("content")
123
+ lines = [line.rstrip("\r") for line in content.split("\n")]
124
+ blocks.append(lines)
125
+ return blocks
126
+
127
+
128
+ def _validate_suggestion_blocks(
129
+ comment: dict[str, Any],
130
+ diff_content_map: dict[str, dict[str, dict[int, str]]],
131
+ ) -> list[str]:
132
+ errors: list[str] = []
133
+ body = comment.get("body") or ""
134
+ blocks = _extract_suggestion_blocks(body)
135
+ if not blocks:
136
+ return errors
137
+
138
+ path = comment.get("path") or ""
139
+ side = comment.get("side") or "RIGHT"
140
+ start_side = comment.get("start_side") or side
141
+ line_no = comment.get("line")
142
+ if not isinstance(line_no, int):
143
+ return errors
144
+ start_line = comment.get("start_line") or line_no
145
+ content_for_start_side = diff_content_map.get(path, {}).get(start_side, {})
146
+ content_for_end_side = diff_content_map.get(path, {}).get(side, {})
147
+
148
+ for block_index, block_lines in enumerate(blocks):
149
+ if not block_lines or block_lines == [""]:
150
+ continue
151
+ prev_context = content_for_start_side.get(start_line - 1)
152
+ next_context = content_for_end_side.get(line_no + 1)
153
+ first_line = block_lines[0]
154
+ last_line = block_lines[-1]
155
+ if prev_context is not None and first_line == prev_context:
156
+ errors.append(
157
+ f"suggestion block {block_index} duplicates the context line immediately above "
158
+ f"`start_line` ({start_line - 1}); that line is not replaced and will appear twice after the suggestion is applied"
159
+ )
160
+ if next_context is not None and last_line == next_context:
161
+ errors.append(
162
+ f"suggestion block {block_index} duplicates the context line immediately below "
163
+ f"`line` ({line_no + 1}); that line is not replaced and will appear twice after the suggestion is applied"
164
+ )
165
+ return errors
166
+
167
+
168
+ def validate_review_payload(
169
+ review: Any,
170
+ diff_line_map: dict[str, dict[str, set[int]]],
171
+ diff_content_map: dict[str, dict[str, dict[int, str]]] | None = None,
172
+ ) -> ReviewValidationResult:
173
+ """Validate a review.json payload against the annotated PR diff."""
174
+ if not isinstance(review, dict):
175
+ raise ValueError("Review payload must be a JSON object.")
176
+
177
+ raw_body = review.get("body")
178
+ if raw_body is None:
179
+ raw_body = review.get("summary") or ""
180
+ if not isinstance(raw_body, str):
181
+ raise ValueError("Review payload `body` must be a string.")
182
+
183
+ raw_comments = review.get("comments") or []
184
+ if not isinstance(raw_comments, list):
185
+ raise ValueError("Review payload `comments` must be a list.")
186
+
187
+ normalized_comments: list[ReviewComment] = []
188
+ errors: list[str] = []
189
+
190
+ for index, raw_comment in enumerate(raw_comments):
191
+ if not isinstance(raw_comment, dict):
192
+ errors.append(f"`comments[{index}]` must be an object.")
193
+ continue
194
+
195
+ path = normalize_review_path(raw_comment.get("path"))
196
+ line = raw_comment.get("line")
197
+ body_value = raw_comment.get("body")
198
+ body = body_value.strip() if isinstance(body_value, str) else ""
199
+ side = raw_comment.get("side")
200
+
201
+ if not path:
202
+ errors.append(f"`comments[{index}]` is missing `path`.")
203
+ continue
204
+ if path not in diff_line_map:
205
+ errors.append(
206
+ f"`comments[{index}]` references `{path}`, which is not part of the PR diff. Move that feedback to top-level `body` instead."
207
+ )
208
+ continue
209
+ if not isinstance(line, int) or line <= 0:
210
+ errors.append(
211
+ f"`comments[{index}]` for `{path}` must include a positive integer `line`."
212
+ )
213
+ continue
214
+ if side not in {"LEFT", "RIGHT"}:
215
+ errors.append(
216
+ f"`comments[{index}]` for `{path}:{line}` must include `side` set to `LEFT` or `RIGHT`."
217
+ )
218
+ continue
219
+ if not body:
220
+ errors.append(f"`comments[{index}]` for `{path}` is missing `body`.")
221
+ continue
222
+
223
+ allowed_lines = diff_line_map[path][side]
224
+ if line not in allowed_lines:
225
+ errors.append(
226
+ f"`comments[{index}]` references `{path}:{line}` on `{side}`, which is not commentable in the PR diff."
227
+ )
228
+ continue
229
+
230
+ normalized_comment: ReviewComment = {
231
+ "path": path,
232
+ "line": line,
233
+ "side": side,
234
+ "body": body,
235
+ }
236
+
237
+ if "start_line" in raw_comment and raw_comment.get("start_line") is not None:
238
+ start_line = raw_comment.get("start_line")
239
+ if not isinstance(start_line, int) or start_line <= 0:
240
+ errors.append(
241
+ f"`comments[{index}]` for `{path}` has invalid `start_line`; it must be a positive integer."
242
+ )
243
+ continue
244
+ start_side = raw_comment.get("start_side")
245
+ if start_side not in {"LEFT", "RIGHT"}:
246
+ errors.append(
247
+ f"`comments[{index}]` for `{path}` has `start_line` but is missing `start_side`; set `start_side` to `LEFT` or `RIGHT`."
248
+ )
249
+ continue
250
+ if start_side == side and start_line >= line:
251
+ errors.append(
252
+ f"`comments[{index}]` for `{path}` has invalid `start_line`; when `start_side` matches `side`, it must be smaller than `line`."
253
+ )
254
+ continue
255
+ if start_line not in diff_line_map[path][start_side]:
256
+ errors.append(
257
+ f"`comments[{index}]` references `{path}:{start_line}` on `{start_side}` as `start_line`, which is not commentable in the PR diff."
258
+ )
259
+ continue
260
+ normalized_comment["start_line"] = start_line
261
+ normalized_comment["start_side"] = start_side
262
+ elif raw_comment.get("start_side") is not None:
263
+ errors.append(
264
+ f"`comments[{index}]` for `{path}:{line}` has `start_side` without `start_line`."
265
+ )
266
+ continue
267
+
268
+ if diff_content_map is not None:
269
+ suggestion_errors = _validate_suggestion_blocks(
270
+ normalized_comment, diff_content_map
271
+ )
272
+ if suggestion_errors:
273
+ for err in suggestion_errors:
274
+ errors.append(
275
+ f"`comments[{index}]` for `{path}:{line}` on `{side}` has an invalid suggestion block: {err}."
276
+ )
277
+ continue
278
+
279
+ normalized_comments.append(normalized_comment)
280
+
281
+ return ReviewValidationResult(
282
+ body=raw_body.strip(),
283
+ comments=normalized_comments,
284
+ errors=errors,
285
+ )
286
+
287
+
288
+ def _load_json(path: Path) -> Any:
289
+ try:
290
+ return json.loads(path.read_text(encoding="utf-8"))
291
+ except FileNotFoundError:
292
+ raise SystemExit(f"review validation failed: {path} does not exist")
293
+ except json.JSONDecodeError as exc:
294
+ raise SystemExit(f"review validation failed: {path} is invalid JSON: {exc}")
295
+
296
+
297
+ def _validate_verdict(payload: Any) -> list[str]:
298
+ if not isinstance(payload, dict):
299
+ return ["review.json must decode to a JSON object."]
300
+ verdict = payload.get("verdict")
301
+ if verdict not in {"APPROVE", "REJECT"}:
302
+ return ['`verdict` must be exactly "APPROVE" or "REJECT".']
303
+ return []
304
+
305
+
306
+ def main() -> int:
307
+ parser = argparse.ArgumentParser(
308
+ description="Validate review.json comments against annotated pr_diff.txt."
309
+ )
310
+ parser.add_argument(
311
+ "--review-json",
312
+ default="review.json",
313
+ type=Path,
314
+ help="Path to the review.json artifact to validate.",
315
+ )
316
+ parser.add_argument(
317
+ "--diff",
318
+ default="pr_diff.txt",
319
+ type=Path,
320
+ help="Path to the annotated PR diff consumed during review.",
321
+ )
322
+ args = parser.parse_args()
323
+
324
+ payload = _load_json(args.review_json)
325
+ try:
326
+ diff_text = args.diff.read_text(encoding="utf-8")
327
+ except FileNotFoundError:
328
+ print(f"review validation failed: {args.diff} does not exist", file=sys.stderr)
329
+ return 1
330
+
331
+ diff_line_map, diff_content_map = build_diff_maps_from_annotated_diff(diff_text)
332
+ result = validate_review_payload(payload, diff_line_map, diff_content_map)
333
+ errors = _validate_verdict(payload) + result.errors
334
+ if errors:
335
+ print("review validation failed:", file=sys.stderr)
336
+ for error in errors:
337
+ print(f"- {error}", file=sys.stderr)
338
+ return 1
339
+
340
+ print(
341
+ "review validation passed: "
342
+ f"{len(result.comments)} inline comment(s), {len(diff_line_map)} diff file(s)"
343
+ )
344
+ return 0
345
+
346
+
347
+ if __name__ == "__main__":
348
+ raise SystemExit(main())
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: tdd
3
+ description: "Use only when the user explicitly asks for TDD, a failing test, or a regression test, OR when the bug has an obvious cheap local test target. Skip when the test path is unclear, expensive, integration-heavy, or not requested."
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # TDD Bug Fix
8
+
9
+ When fixing a bug with a clear, cheap test path, make the broken behavior executable before changing production code. The goal is a focused regression test that fails before the fix and passes after it.
10
+
11
+ Do not force a test when it would be impractical. If the available test would require broad harness setup, brittle mocks, slow end-to-end infrastructure, production-only state, vague reproduction steps, or large unrelated fixture churn, skip adding a new test and use the closest useful verification instead.
12
+
13
+ ## Workflow
14
+
15
+ 1. **Understand the bug.** Identify the intended behavior, current behavior, affected path, and smallest observable reproduction.
16
+ 2. **Choose the narrowest executable check.** Prefer the closest unit, component, integration, or regression test already used for that codepath. If no practical test path is obvious, do not create one from scratch just to satisfy the workflow.
17
+ 3. **Write the failing test first.** Add the smallest focused test that would have caught the bug. The test should encode intended behavior, not mirror the current implementation.
18
+ 4. **Run the new test before fixing.** Confirm it fails for the intended reason. If it passes or fails for an unrelated reason, correct the test or reproduction before editing the implementation.
19
+ 5. **Fix the bug.** Make the smallest production change that satisfies the intended behavior while preserving nearby contracts.
20
+ 6. **Rerun the regression test.** Confirm the test now passes.
21
+ 7. **Run nearby validation.** Run relevant adjacent tests, type checks, lint, or scenario checks when the change has broader risk.
22
+
23
+ ## If a Failing Test Is Impractical
24
+
25
+ Do not silently skip the regression step. Before fixing, explicitly explain why a failing test is impossible or not worth the cost, then choose the closest executable regression check available. Examples include a targeted script, manual reproduction command, browser automation, snapshot comparison, log assertion, or focused integration check.
26
+
27
+ Prefer no new test over a bad test. A bad test is one that mostly tests mocks, encodes current implementation details, depends on timing or unrelated global state, needs expensive infrastructure for a small fix, or would be deleted immediately after proving the fix.
28
+
29
+ ## Guardrails
30
+
31
+ - Do not change tests merely to match a wrong implementation.
32
+ - Do not weaken existing assertions unless the expected behavior has genuinely changed and the reason is clear.
33
+ - Keep the regression test focused on the bug; avoid broad fixture churn or unrelated coverage expansion.
34
+ - Do not add tests when the practical signal is weak; use manual or scripted verification and say why.
35
+ - If the bug is flaky, make the test deterministic where possible and document the signal being locked down.
36
+ - If the bug exposes a broader class of failures, first land the focused regression path, then consider additional sibling coverage.
37
+
38
+ ## Final Response
39
+
40
+ Report the evidence, not just the outcome:
41
+
42
+ - Name the failing-before test or executable check and the failure it produced.
43
+ - Name the passing-after test run and any nearby validation performed.
44
+ - If failing-before evidence could not be demonstrated, state why and describe the closest regression check used instead.
@@ -0,0 +1,5 @@
1
+ # Examples
2
+
3
+ - Reproduce a bug with a focused failing regression test before changing the implementation.
4
+ - Use the narrowest practical test path, then run the regression test and relevant nearby validation after the fix.
5
+ - Explain why a failing test is impractical and use the closest reliable executable check instead.
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: unslop
3
+ description: Cut AI tells from any writing. Must always apply.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Unslop
8
+
9
+ Edit text to remove AI patterns and add human voice.
10
+
11
+ ## Process
12
+
13
+ 1. Scan for the patterns below.
14
+ 2. Rewrite. Preserve meaning, match intended tone.
15
+ 3. Add soul (see next section).
16
+ 4. Self-audit: "What makes this obviously AI generated?" Fix remaining tells.
17
+
18
+ ## Adding soul
19
+
20
+ Removing patterns is half the job. Sterile, voiceless writing is just as obvious.
21
+
22
+ - **Have opinions.** React to facts instead of neutrally listing pros and cons.
23
+ - **Vary rhythm.** Short sentences. Then longer ones that take their time. Mix it up.
24
+ - **Acknowledge complexity.** "Impressive but also kind of unsettling" beats "impressive."
25
+ - **Use "I" when it fits.** First person isn't unprofessional.
26
+ - **Let some mess in.** Perfect structure looks machine-made.
27
+ - **Be specific.** Not "this is concerning" but "there's something unsettling about agents churning away at 3am."
28
+
29
+ ## Patterns to detect and fix
30
+
31
+ ### Content
32
+
33
+ 1. **Puffery.** "pivotal moment", "testament to", "evolving landscape", "setting the stage for", "indelible mark", "deeply rooted". Cut puffery, state what happened.
34
+ 2. **Name-dropping.** Listing media outlets without context. Pick one, say what was said.
35
+ 3. **Superficial -ing phrases.** "highlighting...", "ensuring...", "reflecting...", "showcasing...", "fostering...". Delete or expand with real sources.
36
+ 4. **Promotional language.** "nestled", "vibrant", "breathtaking", "groundbreaking", "renowned", "stunning", "must-visit". Use neutral descriptions.
37
+ 5. **Vague attributions.** "Experts believe", "Industry reports suggest", "Some critics argue". Name the source or delete.
38
+ 6. **Formulaic challenges.** "Despite challenges... continues to thrive." Replace with specific facts.
39
+
40
+ ### Language
41
+
42
+ 7. **AI vocabulary.** Additionally, crucial, delve, enduring, enhance, fostering, garner, interplay, intricate, landscape (abstract), pivotal, showcase, tapestry (abstract), testament, underscore, vibrant. Replace with plain words.
43
+ 8. **Fancy ways to say "is".** "serves as", "stands as", "boasts", "features". Just say "is" or "has".
44
+ 9. **"Not just X, but Y."** State the point directly instead.
45
+ 10. **Rule of three.** Forcing ideas into groups of three. Use the natural number.
46
+ 11. **Synonym cycling.** Protagonist, main character, central figure, hero all in one paragraph. Pick one, repeat it.
47
+ 12. **False ranges.** "from X to Y" where X and Y aren't on a meaningful scale. List topics directly.
48
+
49
+ ### Style
50
+
51
+ 13. **Em dash overuse.** Avoid em dashes entirely. Use periods or commas only (no parentheses, no en dashes, no hyphen-as-dash substitutes). Em dashes are an AI tell, and reaching for parentheses instead just trades one tell for another. If a thought needs separation, end the sentence or use a comma.
52
+ 14. **Colon overuse.** Colons are fine before a list or example. Not as mid-sentence connectors. "If you're coming from traditional automation: instead of registering event handlers, you describe conditions" adds nothing with the colon. Rewrite to let the point stand on its own without comparison framing. "Describing when the scheduler should fire works best as plain English." Same meaning, no crutch punctuation.
53
+ 15. **Boldface overuse.** Don't bold every proper noun or acronym.
54
+ 16. **Inline-header lists.** The tell is a bold label and colon that restates the line: "**Performance:** Performance improved...". Convert those to prose. A bold lead-in that ends in a period, names the item, and is followed by genuinely new detail ("**Schema in TypeScript.** Tables live in one file.") is fine, not a tell.
55
+ 17. **Title case headings.** Use sentence case.
56
+ 18. **Decorative emojis.** Remove from headings and bullets.
57
+ 19. **Curly quotes.** Replace with straight quotes.
58
+
59
+ ### Communication artifacts
60
+
61
+ 20. **Chatbot phrases.** "I hope this helps!", "Let me know if...", "Of course!", "Certainly!", "Found the smoking gun!" Remove.
62
+ 21. **Cutoff disclaimers.** "While specific details are limited..." Find sources or remove.
63
+ 22. **Sycophantic tone.** "Great question! You're absolutely right!" Respond directly.
64
+
65
+ ### Filler
66
+
67
+ 23. **Filler phrases.** "In order to" becomes "To". "Due to the fact that" becomes "Because". "It is important to note that" gets deleted.
68
+ 24. **Excessive hedging.** "could potentially possibly be argued that it might" becomes "may".
69
+ 25. **Generic conclusions.** "The future looks bright." State specific plans or facts.
70
+
71
+ ### Jargon
72
+
73
+ 26. **Abstract metaphor nouns.** Substrate, wedge, vector, locus, vantage, nexus, primitive (as noun), harness (as metaphor), surface (as in "API surface"), bedrock, scaffolding (as metaphor), modality, paradigm, gold-plating, ratchet (as metaphor), evacuate (for moving code), endgame, north star, flywheel. These read as technical but usually have a plainer concrete word. "Substrate" becomes "base". "Wedge in" becomes "add". "Vector" becomes "way" or "method". "Gold-plating" becomes "more than the job needs". "Ratchet" becomes the mechanism's real name or "a limit that only tightens". "Evacuate" becomes "move out". "Endgame" becomes "the last phase". Pick the concrete word.
74
+
75
+ ### Plain speech
76
+
77
+ 27. **Say what it does, not how it feels.** "the database stays close at hand", "SQL you can read", "types that follow your schema" name a feeling. The fix names the mechanism or a number: "`.toSQL()` returns the exact string sent to the database", "a column rename fails the build". Ask what the sentence tells the reader to do or know, then write that. If you can't restate it as a concrete instruction, fact, or number, cut it. One more check: if the sentence could appear unchanged in another project's docs, it says nothing about this one. Cut it.
78
+ 28. **Shorten or split dense sentences.** If the reader has to backtrack to parse a sentence, break it in two or drop clauses. One idea per sentence.
79
+ 29. **Active voice.** Prefer it. Catch "is/are/was/were + past participle" and name the actor: "queries are validated" becomes "the compiler validates queries", "the file is parsed by the loader" becomes "the loader parses the file". Passive is fine only when the actor is unknown or genuinely doesn't matter.
80
+ 30. **Cut adverbs, or use a stronger verb.** "runs quickly" becomes "is fast" or the number. "significantly improves" becomes the measured delta. An adverb propping up a weak verb means the verb is wrong.
81
+ 31. **Prefer the plain word.** "utilize" becomes "use", "leverage" becomes "use", "facilitate" becomes "help", "numerous" becomes "many", "in the event that" becomes "if". The fancier synonym is rarely clearer.
@@ -0,0 +1,5 @@
1
+ # Examples
2
+
3
+ - Rewrite release notes to remove inflated claims, filler, and generic AI phrasing while preserving meaning.
4
+ - Edit technical prose for plain language, varied rhythm, active voice, and a natural human tone.
5
+ - Scan a document for em-dash overuse, formulaic transitions, vague claims, and unnecessary jargon before rewriting it.