@mohammadhprp/system-prompt 0.12.4 → 0.12.6

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 (43) hide show
  1. package/framework/commands/README.md +2 -6
  2. package/framework/commands/audit-your-codebase.md +47 -0
  3. package/framework/commands/explain-codebase.md +101 -0
  4. package/framework/commands/learn.md +1 -1
  5. package/framework/plugins/ponytail/README.md +1 -1
  6. package/framework/plugins/ponytail/capabilities.md +1 -1
  7. package/framework/references/standards/pull-requests.md +1 -1
  8. package/framework/skills/README.md +1 -0
  9. package/framework/skills/adhd/SKILL.md +141 -0
  10. package/framework/skills/adhd/examples.md +77 -0
  11. package/framework/skills/gh/SKILL.md +157 -0
  12. package/framework/skills/gh/examples.md +10 -0
  13. package/framework/skills/ponytail/SKILL.md +145 -0
  14. package/framework/skills/ponytail/references/ponytail-audit.md +18 -0
  15. package/framework/skills/ponytail/references/ponytail-debt.md +21 -0
  16. package/framework/skills/ponytail/references/ponytail-gain.md +25 -0
  17. package/framework/skills/ponytail/references/ponytail-help.md +18 -0
  18. package/framework/skills/ponytail/references/ponytail-mode.md +33 -0
  19. package/framework/skills/ponytail/references/ponytail-review.md +27 -0
  20. package/framework/skills/ponytail/references/ponytail-rules.md +31 -0
  21. package/framework/skills/ponytail/references/principle-boundary-discipline.md +7 -0
  22. package/framework/skills/ponytail/references/principle-encode-lessons-in-structure.md +13 -0
  23. package/framework/skills/ponytail/references/principle-fix-root-causes.md +17 -0
  24. package/framework/skills/ponytail/references/principle-make-operations-idempotent.md +12 -0
  25. package/framework/skills/ponytail/references/principle-model-the-domain.md +7 -0
  26. package/framework/skills/ponytail/references/principle-prove-it-works.md +27 -0
  27. package/framework/skills/ponytail/references/principle-sequence-verifiable-units.md +7 -0
  28. package/framework/skills/review/SKILL.md +106 -11
  29. package/framework/skills/review/examples.md +4 -3
  30. package/framework/skills/review/scripts/render_review.py +95 -0
  31. package/framework/skills/review/scripts/resolve_spec_context.py +723 -0
  32. package/framework/skills/review/scripts/validate_review_json.py +348 -0
  33. package/framework/skills/unslop/SKILL.md +34 -3
  34. package/framework/skills/unslop/examples.md +2 -0
  35. package/framework/skills/unslop/references/eval.md +44 -0
  36. package/package.json +1 -1
  37. package/src/catalog.js +6 -7
  38. package/framework/commands/changelog.md +0 -44
  39. package/framework/commands/commit.md +0 -28
  40. package/framework/commands/mr.md +0 -45
  41. package/framework/commands/pr.md +0 -39
  42. package/framework/commands/release.md +0 -34
  43. package/framework/commands/review.md +0 -24
@@ -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())
@@ -14,6 +14,12 @@ Edit text to remove AI patterns and add human voice.
14
14
  2. Rewrite. Preserve meaning, match intended tone.
15
15
  3. Add soul (see next section).
16
16
  4. Self-audit: "What makes this obviously AI generated?" Fix remaining tells.
17
+ 5. Output the full edited draft plus a short **What changed** section listing the patterns fixed.
18
+ 6. Run the checks in [eval.md](references/eval.md). If any check fails, fix the draft and re-check.
19
+
20
+ ## Detect mode
21
+
22
+ When the user asks whether a piece is slop, or asks to audit, scan, or flag a draft without rewriting: name each pattern from this skill that appears, quote the line, and give the fix in a few words. Do not rewrite, score the draft, or guess whether AI wrote it. Offer to edit the draft after.
17
23
 
18
24
  ## Adding soul
19
25
 
@@ -39,7 +45,7 @@ Removing patterns is half the job. Sterile, voiceless writing is just as obvious
39
45
 
40
46
  ### Language
41
47
 
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.
48
+ 7. **AI vocabulary.** Additionally, beacon, crucial, cutting-edge, delve, empower, embark, elevate, enduring, enhance, ever-evolving, fostering, game changer, garner, interplay, intricate, landscape (abstract), meticulous, multifaceted, paradigm shift, paramount, pivotal, realm, robust, showcase, streamline, supercharge, tapestry (abstract), testament, this changes everything, this is huge, transformative, underscore, vibrant. Replace with plain words.
43
49
  8. **Fancy ways to say "is".** "serves as", "stands as", "boasts", "features". Just say "is" or "has".
44
50
  9. **"Not just X, but Y."** State the point directly instead.
45
51
  10. **Rule of three.** Forcing ideas into groups of three. Use the natural number.
@@ -64,8 +70,8 @@ Removing patterns is half the job. Sterile, voiceless writing is just as obvious
64
70
 
65
71
  ### Filler
66
72
 
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".
73
+ 23. **Filler phrases.** "In order to" becomes "To". "Due to the fact that" becomes "Because". "It is important to note that" gets deleted. Often-empty phrases that delay the point: it's worth noting, at the end of the day, when it comes to, at its core, in today's world, in the age of, in the world of, the reality is, the truth is, in terms of, with regard to, going forward, in this article, let's dive in. Cut them unless part of the writer's recognizable voice.
74
+ 24. **Excessive hedging.** "could potentially possibly be argued that it might" becomes "may". Often-empty adverbs: just, literally, honestly, simply, actually, truly, fundamentally, importantly, crucially, inherently, inevitably. Cut when they add nothing; keep when they carry emphasis, uncertainty, contrast, or spoken rhythm.
69
75
  25. **Generic conclusions.** "The future looks bright." State specific plans or facts.
70
76
 
71
77
  ### Jargon
@@ -79,3 +85,28 @@ Removing patterns is half the job. Sterile, voiceless writing is just as obvious
79
85
  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
86
  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
87
  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.
88
+
89
+ ### Voice preservation (from no-ai-slop)
90
+
91
+ 32. **Minimum effective edit.** Fix AI patterns, errors, repetition, and unclear passages. Leave strong human sentences alone. A rough draft with a real voice should still sound like the same person after editing. Do not make every paragraph equally tidy.
92
+ 33. **Show, don't label.** Cut commentary that labels a point important, surprising, subtle, or obvious instead of demonstrating why ("That last part matters more than it sounds", "The key point is", "As you can see", "This distinction matters", redundant "In other words"). If the prose already shows the point, delete the aside. Otherwise replace it with facts.
93
+ 34. **Protect the specific fact.** Don't smooth a useful detail into generic importance. "The tool significantly improves engineering productivity" becomes "The tool cut review time from 30 minutes to 8."
94
+ 35. **Portability test.** If a sentence could move unchanged to another person, company, country, or product, it is filler. Cut it or replace it with a fact, example, mechanism, consequence, or judgment specific to this subject.
95
+
96
+ ### Dramatic setups and endings (from no-ai-slop)
97
+
98
+ 36. **Throat-clearing openers.** "Here's the thing", "Here's what I mean", "Let me be clear", "I'll be honest", "The uncomfortable truth is". Cut and state the point. Keep a personal aside only when it creates context, tension, or character.
99
+ 37. **Faux-insight setups.** "What nobody tells you", "What most people get wrong", "The part everyone misses", "This is the part most people skip". These flatter the writer as the lone expert. Cut the setup; make the claim stand on its own.
100
+ 38. **Binary contrasts.** "It's not X. It's Y.", "The question isn't X, it's Y." State Y directly. "The question isn't the model. It's the eval." becomes "The eval matters more than the model." (See also 9.)
101
+ 39. **Negative listing.** "Not a X. Not a Y. A Z." Just say Z.
102
+ 40. **Rhetorical setups.** "What if I told you...", "Think about it:", "Plot twist:", self-answered "Question? Answer." pairs. Drop them and make the point.
103
+ 41. **Colon reveals.** A noun phrase, a colon, then a lowercase dramatic reveal: "The best part: it learns." Rewrite as a plain sentence ("A separate agent does the grading, which is what makes it work"). Colons are for lists, labels, and quotes, not fake drama. (See also 14.)
104
+ 42. **Dramatic fragmentation.** "That's it. That's the whole thing.", "X. And Y. And Z." Use complete sentences unless the fragment is clearly the writer's own cadence.
105
+ 43. **Robotic rhythm.** Repeated sentence shapes, identical paragraph structures, stacked punchy fragments. Vary the shape only when it helps the point.
106
+ 44. **Fake-profound kickers.** Cut the final "deep" line when it turns the point into a metaphor, aphorism, or mic-drop ("The future isn't coming. It's already here."). Do not rewrite it into a better metaphor. Delete it, then end on the clearest concrete sentence already in the draft.
107
+ 45. **Summary-recap endings.** "In conclusion", "Ultimately", "Overall", or a final paragraph restating the piece. The reader was just there. End on the last concrete point, takeaway, or next action instead. (See also 25.)
108
+ 46. **Formatting slop.** Bullet lists where two sentences of prose would read better, headers over two-sentence sections. Format follows the content, not decorates it. (See also 15, 18.)
109
+
110
+ ## Source
111
+
112
+ Patterns 32–46, detect mode, and `references/eval.md` adapted from [no-ai-slop](https://github.com/petergyang/no-ai-slop) by Peter Yang, MIT License.
@@ -3,3 +3,5 @@
3
3
  - Rewrite release notes to remove inflated claims, filler, and generic AI phrasing while preserving meaning.
4
4
  - Edit technical prose for plain language, varied rhythm, active voice, and a natural human tone.
5
5
  - Scan a document for em-dash overuse, formulaic transitions, vague claims, and unnecessary jargon before rewriting it.
6
+ - Detect mode: flag each slop pattern with a quoted line and a short fix, without rewriting. Example: "`The best part: it learns.` — colon reveal (41). Rewrite as a plain sentence."
7
+ - Minimum effective edit: leave strong human sentences alone. Example: keep the writer's blunt aside, cut only the throat-clearing opener and the fake-profound kicker.
@@ -0,0 +1,44 @@
1
+ # Unslop eval
2
+
3
+ Use after the rewrite. Answer each check with pass or fail. If any check fails, fix the draft before returning it.
4
+
5
+ For detect requests, make sure the response names each pattern found with a quoted line and a short fix, without rewriting the draft.
6
+
7
+ ## Edit integrity
8
+
9
+ 1. Does the edit preserve the user's point without adding claims, examples, stats, quotes, or opinions?
10
+ 2. Does it preserve the writer's distinctive vocabulary, cadence, bluntness, humor, uncertainty, and level of polish (32)?
11
+ 3. Does it leave strong human sentences alone instead of making every paragraph equally tidy (32)?
12
+ 4. Is the amount of cutting proportional to the actual slop, with no aggressive compression that strips out character?
13
+ 5. Does the draft lead with what the reader needs while keeping personal setup that adds context, tension, or character (36)?
14
+ 6. Do sentences earn their place, with concrete facts, protected details (34), and direct verbs?
15
+ 7. Does every generic sentence pass the portability test (35), or was it cut or made specific?
16
+ 8. Does the draft use active voice with human subjects where possible (29)?
17
+ 9. Are genuinely tangled sentences fixed while clear spoken cadence and changes in pace remain intact (28)?
18
+
19
+ ## Words to cut
20
+
21
+ 1. Are banned words (7), filler phrases (23), often-empty adverbs (24), and inflated claims removed unless quoted as examples?
22
+
23
+ ## Patterns to cut
24
+
25
+ 1. Are binary contrasts (9, 38), negative listings (39), rhetorical setups (40), and throat-clearing openers (36) removed?
26
+ 2. Are faux-insight setups (37), colon reveals (41), superficial -ing phrases (3), fancy "is" verbs (8), synonym cycling (11), dramatic fragments (42), and robotic rhythm (43) fixed?
27
+ 3. Are puffery (1), promotional language (4), and vague attributions (5) replaced with plain facts and named sources, or flagged when no source exists?
28
+ 4. Is interpretive metadiscourse (33) removed, including emphasis markers and redundant glossing?
29
+ 5. Are fake-profound kickers (44) deleted instead of rewritten into better metaphors?
30
+ 6. Are summary-recap endings (45) cut so the piece ends on a concrete point, takeaway, or next action?
31
+ 7. Is formatting slop removed: decorative emoji (18), decorative bold (15), bullets that should be prose, headers over tiny sections (46)?
32
+ 8. Are em dashes (13), colons (14), title case headings (17), and curly quotes (19) fixed?
33
+
34
+ ## Final read
35
+
36
+ 1. Does the draft avoid robotic symmetry, repeated sentence shapes, and stacked punchy fragments (43)?
37
+ 2. Would the writer recognize the edited draft as their own voice?
38
+ 3. Would the edited draft sound natural if read to a sharp colleague?
39
+ 4. Does the final output include the full edited draft and a short **What changed** section?
40
+ 5. For detect requests, does the response name each pattern with a quoted line and a short fix, without rewriting, scoring, or claiming AI authorship?
41
+
42
+ ## Source
43
+
44
+ Adapted from [no-ai-slop](https://github.com/petergyang/no-ai-slop) `eval.md` by Peter Yang, MIT License.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohammadhprp/system-prompt",
3
- "version": "0.12.4",
3
+ "version": "0.12.6",
4
4
  "description": "AI Coding Agent Framework — interactive bootstrap CLI",
5
5
  "keywords": [
6
6
  "ai",
package/src/catalog.js CHANGED
@@ -4,6 +4,7 @@ export const categories = {
4
4
  description: 'Task-specific procedures for AI coding agents',
5
5
  sourceDir: 'framework/skills',
6
6
  items: [
7
+ { id: 'adhd', name: 'ADHD', description: 'Shape output for ADHD readers: action first, numbered steps, restated state, no tangents' },
7
8
  { id: 'agent-browser', name: 'Agent Browser', description: 'Automate browser and Electron workflows for navigation, testing, screenshots, and data extraction' },
8
9
  { id: 'architect', name: 'Architect', description: 'Sketch architecture and module boundaries before implementation' },
9
10
  { id: 'arena', name: 'Arena', description: 'Compare parallel candidate solutions and synthesize the strongest result' },
@@ -16,6 +17,7 @@ export const categories = {
16
17
  { id: 'effective-html', name: 'Effective HTML', description: 'Create self-contained HTML artifacts with routed guidance for design, wireframes, prototypes, plans, and diagrams' },
17
18
  { id: 'find-skills', name: 'Find Skills', description: 'Discover, evaluate, and install agent skills for specialized tasks' },
18
19
  { id: 'frontend-design', name: 'Frontend Design', description: 'Distinctive, intentional visual design for new UI or reshaping existing UI' },
20
+ { id: 'gh', name: 'GitHub CLI', description: 'Work with GitHub via the gh CLI for repositories, issues, pull requests, Actions, releases, and APIs' },
19
21
  { id: 'glab', name: 'Glab', description: 'Work with GitLab via the glab CLI for MRs, issues, and pipelines' },
20
22
  { id: 'humanizer', name: 'Humanizer', description: 'Remove signs of AI-generated writing to make text sound more natural and human' },
21
23
  { id: 'improve', name: 'Improve', description: 'Audit repositories and produce prioritized, read-only implementation plans for another agent' },
@@ -24,9 +26,10 @@ export const categories = {
24
26
  { id: 'laravel-best-practices', name: 'Laravel Best Practices', description: 'Laravel patterns for Eloquent, validation, testing' },
25
27
  { id: 'merge-request', name: 'Merge Request', description: 'Create a GitLab merge request (MR) for the current branch' },
26
28
  { id: 'perf-web-optimization', name: 'Web Performance Optimization', description: 'Optimize web performance: bundle size, images, caching, lazy loading, and overall page speed' },
29
+ { id: 'ponytail', name: 'Ponytail', description: 'Lazy senior developer workflow focused on YAGNI, reuse, and the smallest working change' },
27
30
  { id: 'pull-request', name: 'Pull Request', description: 'Create or update a GitHub pull request (PR) for the current branch' },
28
31
  { id: 'release', name: 'Release', description: 'Prepare and tag semantic-versioned releases' },
29
- { id: 'review', name: 'Review', description: 'Perform comprehensive code quality review' },
32
+ { id: 'review', name: 'Review', description: 'Review local, GitHub, or GitLab changes and write review.json' },
30
33
  { id: 'security-best-practices', name: 'Security Best Practices', description: 'Language and framework specific security best-practice reviews and secure-by-default coding help' },
31
34
  { id: 'sentry', name: 'Sentry', description: 'Inspect Sentry issues, summarize production errors, and pull health data via the Sentry API' },
32
35
  { id: 'show-me', name: 'Show Me', description: 'Explain the current topic visually with diagrams, code-shape sketches, and focused HTML artifacts' },
@@ -55,13 +58,9 @@ export const categories = {
55
58
  description: 'Slash command workflows for repeatable tasks',
56
59
  sourceDir: 'framework/commands',
57
60
  items: [
58
- { id: 'changelog', name: 'Changelog', description: 'Create, add, or update CHANGELOG.md entries' },
59
- { id: 'commit', name: 'Commit', description: 'Create atomic git commits with conventional messages' },
61
+ { id: 'audit-your-codebase', name: 'Audit Your Codebase', description: 'Audit for materially useful simplifications in structure, state, algorithms, and ownership' },
62
+ { id: 'explain-codebase', name: 'Explain Codebase', description: 'Map a codebase and teach it interactively, from overview to focused deep-dives' },
60
63
  { id: 'learn', name: 'Learn', description: 'Distill a reusable skill from any source' },
61
- { id: 'pr', name: 'PR', description: 'Create a GitHub PR for the current branch' },
62
- { id: 'mr', name: 'MR', description: 'Create a GitLab MR for the current branch' },
63
- { id: 'release', name: 'Release', description: 'Tag releases, update changelog, and bump versions' },
64
- { id: 'review', name: 'Review', description: 'Perform comprehensive code quality review' },
65
64
  { id: 'summarize-changes', name: 'Summarize Changes', description: 'Summarize uncommitted changes and flag risks' },
66
65
  ],
67
66
  },
@@ -1,44 +0,0 @@
1
- ---
2
- description: Create, add, or update entries in CHANGELOG.md
3
- agent: build
4
- ---
5
-
6
- Changelog $ARGUMENTS
7
-
8
- Maintain CHANGELOG.md entries for my changes.
9
-
10
- ## Process
11
-
12
- 1. **Review and categorize** - Review conversation history, read current `CHANGELOG.md`, determine if changes are `Added`, `Changed`, `Fixed`, `Removed`, `Deprecated`, or `Security`. Read the existing `## Unreleased` section.
13
-
14
- 2. **Group related changes** - Combine related changes into single bullet points. Use past tense ("Added...", "Fixed..."). Include file paths or component names in backticks when helpful. Match existing style and tone.
15
-
16
- 3. **Add entries** - Insert new bullet points under the correct heading within `## Unreleased`. Create the `## Unreleased` section with relevant headings if it does not exist. Preserve all existing entries.
17
-
18
- 4. **Verify** - Read the final `CHANGELOG.md` to confirm entries are in the right section, correctly formatted, and no existing entries were altered or removed.
19
-
20
- ## Entry Format
21
-
22
- ```markdown
23
- ## Unreleased
24
-
25
- ### Added
26
- - New features, entries, additions.
27
-
28
- ### Changed
29
- - Changes in existing functionality, refactors, renames.
30
-
31
- ### Fixed
32
- - Bug fixes, corrections.
33
-
34
- ### Removed
35
- - Removed features, files, entries.
36
-
37
- ### Deprecated
38
- - Soon-to-be-removed features.
39
-
40
- ### Security
41
- - Vulnerabilities, security fixes.
42
- ```
43
-
44
- **Note:** Group entries by section. Order sections: Added, Changed, Fixed, Removed, Deprecated, Security. Within each section, entries are reverse-chronological (newest first). Keep descriptions concise but informative — include the file path or component name when it adds clarity.
@@ -1,28 +0,0 @@
1
- ---
2
- description: Create atomic git commits with conventional messages
3
- agent: build
4
- ---
5
-
6
- Commit $ARGUMENTS
7
-
8
- Create git commits for my changes.
9
-
10
- ## Process
11
-
12
- 1. **Analyze and plan** - Review conversation history, run `git status -s` and `git diff`, determine if changes should be one or multiple logical commits, group related files, draft conventional commit messages (`type: description`) in imperative mood focusing on why
13
- 2. **Present plan** - List files for each commit, show commit messages with type prefix, ask: "I plan to create [N] commit(s) with these changes. Shall I proceed?"
14
- 3. **Execute upon confirmation** - Use `git add` with specific files (never `-A` or `.`), create commits with planned messages, show result with `git log --oneline -n [N]`
15
-
16
- ## Commit Message Format
17
-
18
- Use conventional commit format: `type: description`
19
-
20
- **Types:**
21
- - `feat:` - New feature (user-facing)
22
- - `fix:` - Bug fix (user-facing)
23
- - `docs:` - Documentation only
24
- - `chore:` - Maintenance, tooling, dependencies
25
- - `refactor:` - Code restructuring without behavior change
26
- - `test:` - Adding or updating tests
27
- - `perf:` - Performance improvement
28
- - `ci:` - CI/CD changes
@@ -1,45 +0,0 @@
1
- ---
2
- description: Create a merge request from the current branch
3
- ---
4
-
5
- Create $ARGUMENTS merge request
6
-
7
- Create a merge request for the current branch.
8
-
9
- ## Process
10
-
11
- 1. **Collect information**
12
- - Get current branch name: `git branch --show-current`
13
- - Read MR template from `.gitlab/merge_request_templates/default.md` of exsits
14
-
15
- 2. **Format MR title**
16
- - Take the branch name, replace all `-` with spaces, capitalize first character
17
-
18
- 3. **Collect commits and build summary**
19
- - List commits on the branch that are not on `dev`: `git log dev..HEAD --oneline`
20
- - Read each commit message, convert to a bullet list summarizing user-facing changes
21
- - Merge/squash related commits (e.g. multiple commits for the same change)
22
- - Keep concise, one bullet per logical change
23
-
24
- 4. **Fill template**
25
- - Set Summary to the bullet list from step 3
26
- - Keep the Checklist section as-is
27
-
28
- 5. **Present plan and confirm** - Show:
29
- - Source branch
30
- - Target branch: `develop`
31
- - Title
32
- - Filled description
33
- - Ask: "Shall I create this MR?"
34
- - Push the changes if user says Yes
35
-
36
- 6. **Create upon confirmation** - Use `glab mr create`:
37
- - `--source-branch`: Current branch
38
- - `--target-branch`: `develop`
39
- - `--title`: Prepend "Draft: " to the formatted branch name
40
- - `--description`: Filled template content
41
- - `--assignee`: `1`
42
- - `--squash`
43
- - `--remove-source-branch`
44
-
45
- 7. **Show the resulting URL.**