chill-agent 1.4.0 → 1.6.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 (240) hide show
  1. package/.agents/rules/ponytail.md +30 -0
  2. package/.claude-plugin/contrast-mcp-launcher.mjs +31 -0
  3. package/.claude-plugin/marketplace.json +17 -0
  4. package/.claude-plugin/plugin.json +8 -3
  5. package/.cline-plugin/plugin.js +6 -0
  6. package/.clinerules/ponytail.md +30 -0
  7. package/.codex-plugin/plugin.json +4 -3
  8. package/.cursor/rules/ponytail.mdc +36 -0
  9. package/.cursor-plugin/marketplace.json +16 -0
  10. package/.cursor-plugin/plugin.json +2 -2
  11. package/.devin-plugin/plugin.json +2 -2
  12. package/.grok-plugin/marketplace.json +16 -0
  13. package/.kimi-plugin/plugin.json +11 -29
  14. package/.kiro/steering/ponytail.md +35 -0
  15. package/.omp-plugin/marketplace.json +15 -0
  16. package/.openclaw/skills/ponytail/SKILL.md +47 -0
  17. package/.openclaw/skills/ponytail-audit/SKILL.md +100 -0
  18. package/.openclaw/skills/ponytail-debt/SKILL.md +43 -0
  19. package/.openclaw/skills/ponytail-gain/SKILL.md +51 -0
  20. package/.openclaw/skills/ponytail-help/SKILL.md +76 -0
  21. package/.openclaw/skills/ponytail-review/SKILL.md +98 -0
  22. package/.opencode/command/ponytail-audit.md +5 -0
  23. package/.opencode/command/ponytail-debt.md +5 -0
  24. package/.opencode/command/ponytail-gain.md +5 -0
  25. package/.opencode/command/ponytail-help.md +5 -0
  26. package/.opencode/command/ponytail-review.md +5 -0
  27. package/.opencode/command/ponytail.md +5 -0
  28. package/.opencode/plugins/index.js +4 -0
  29. package/.opencode/plugins/ponytail-frontmatter.cjs +63 -0
  30. package/.opencode/plugins/ponytail.mjs +206 -0
  31. package/.qoder-plugin/plugin.json +12 -26
  32. package/.windsurf/rules/ponytail.md +30 -0
  33. package/AGENTS.md +32 -0
  34. package/__init__.py +228 -0
  35. package/assets/antislop-banner.png +0 -0
  36. package/assets/band/band.png +0 -0
  37. package/assets/band/board.png +0 -0
  38. package/assets/benchmark-3model.svg +21 -0
  39. package/assets/benchmark-agentic.svg +62 -0
  40. package/assets/codex-icon.png +0 -0
  41. package/assets/compare/code/after.webp +0 -0
  42. package/assets/compare/code/before.webp +0 -0
  43. package/assets/compare/text/after.webp +0 -0
  44. package/assets/compare/text/before.webp +0 -0
  45. package/assets/compare/ui/w-all.webp +0 -0
  46. package/assets/compare/ui/w-antislop.webp +0 -0
  47. package/assets/compare/ui/w-design.webp +0 -0
  48. package/assets/compare/ui/without.webp +0 -0
  49. package/assets/logo-dark.png +0 -0
  50. package/assets/logo-dark.svg +115 -0
  51. package/assets/logo-greenpt-dark.svg +27 -0
  52. package/assets/logo-greenpt.svg +27 -0
  53. package/assets/logo.png +0 -0
  54. package/assets/photoreunion-logo-dark.svg +4 -0
  55. package/assets/photoreunion-logo-light.svg +4 -0
  56. package/assets/profile.png +0 -0
  57. package/assets/retriever-logo-dark.svg +4 -0
  58. package/assets/retriever-logo-light.svg +4 -0
  59. package/assets/stories-banner.png +0 -0
  60. package/assets/v5/audit-es.png +0 -0
  61. package/assets/v5/audit-ja.png +0 -0
  62. package/assets/v5/audit-ko.png +0 -0
  63. package/assets/v5/audit-zh-CN.png +0 -0
  64. package/assets/v5/audit.png +0 -0
  65. package/assets/v5/beforeafter-es.png +0 -0
  66. package/assets/v5/beforeafter-ja.png +0 -0
  67. package/assets/v5/beforeafter-ko.png +0 -0
  68. package/assets/v5/beforeafter-zh-CN.png +0 -0
  69. package/assets/v5/beforeafter.png +0 -0
  70. package/assets/v5/chart-es.png +0 -0
  71. package/assets/v5/chart-ja.png +0 -0
  72. package/assets/v5/chart-ko.png +0 -0
  73. package/assets/v5/chart-zh-CN.png +0 -0
  74. package/assets/v5/chart.png +0 -0
  75. package/assets/v5/hero-es.jpg +0 -0
  76. package/assets/v5/hero-ja.jpg +0 -0
  77. package/assets/v5/hero-ko.jpg +0 -0
  78. package/assets/v5/hero-zh-CN.jpg +0 -0
  79. package/assets/v5/hero.jpg +0 -0
  80. package/assets/v5/ladder-es.png +0 -0
  81. package/assets/v5/ladder-ja.png +0 -0
  82. package/assets/v5/ladder-ko.png +0 -0
  83. package/assets/v5/ladder-zh-CN.png +0 -0
  84. package/assets/v5/ladder.png +0 -0
  85. package/assets/v5/review-es.png +0 -0
  86. package/assets/v5/review-ja.png +0 -0
  87. package/assets/v5/review-ko.png +0 -0
  88. package/assets/v5/review-zh-CN.png +0 -0
  89. package/assets/v5/review.png +0 -0
  90. package/assets/v5/tests-es.png +0 -0
  91. package/assets/v5/tests-ja.png +0 -0
  92. package/assets/v5/tests-ko.png +0 -0
  93. package/assets/v5/tests-zh-CN.png +0 -0
  94. package/assets/v5/tests.png +0 -0
  95. package/assets/waitlist-banner-es.png +0 -0
  96. package/assets/waitlist-banner-ja.png +0 -0
  97. package/assets/waitlist-banner-ko.png +0 -0
  98. package/assets/waitlist-banner-zh-CN.png +0 -0
  99. package/assets/waitlist-banner.png +0 -0
  100. package/benchmarks/.env.example +2 -0
  101. package/benchmarks/agentic/README.md +201 -0
  102. package/benchmarks/agentic/answer.py +288 -0
  103. package/benchmarks/agentic/compare.py +93 -0
  104. package/benchmarks/agentic/complete.py +178 -0
  105. package/benchmarks/agentic/judge.py +198 -0
  106. package/benchmarks/agentic/run.py +543 -0
  107. package/benchmarks/agentic/tasks.py +1544 -0
  108. package/benchmarks/arms/baseline.js +2 -0
  109. package/benchmarks/arms/caveman-SKILL.md +67 -0
  110. package/benchmarks/arms/caveman.js +8 -0
  111. package/benchmarks/arms/ponytail.js +8 -0
  112. package/benchmarks/behavior.js +54 -0
  113. package/benchmarks/behavior.yaml +40 -0
  114. package/benchmarks/correctness.js +291 -0
  115. package/benchmarks/loc.js +17 -19
  116. package/benchmarks/promptfooconfig.gemini.yaml +32 -0
  117. package/benchmarks/promptfooconfig.gpt-newest.yaml +33 -0
  118. package/benchmarks/promptfooconfig.yaml +41 -0
  119. package/benchmarks/results/2026-06-12-caveman-vs-ponytail.md +71 -0
  120. package/benchmarks/results/2026-06-12-v4-hardening-vs-caveman.md +125 -0
  121. package/benchmarks/results/2026-06-15-llama3.2-local.md +82 -0
  122. package/benchmarks/results/2026-06-16-correctness-gate-fix.md +113 -0
  123. package/benchmarks/results/2026-06-16-robustness-audit.md +135 -0
  124. package/benchmarks/results/2026-06-17-agentic-safety.md +164 -0
  125. package/benchmarks/results/2026-06-17-cost-verification.md +93 -0
  126. package/benchmarks/results/2026-06-18-agentic.md +219 -0
  127. package/benchmarks/results/2026-06-22-issue-245-217-comprehension.md +98 -0
  128. package/benchmarks/results/2026-10-07-agentic.md +186 -0
  129. package/cli/index.mjs +241 -0
  130. package/cli/lib/banner.mjs +21 -0
  131. package/cli/lib/install.mjs +498 -0
  132. package/cli/lib/settings.mjs +48 -0
  133. package/cli/package-lock.json +87 -0
  134. package/cli/package.json +42 -0
  135. package/cli/scripts/smoke-test.mjs +95 -0
  136. package/cli/scripts/smoke-worker.mjs +411 -0
  137. package/cli/scripts/sync-skills.mjs +81 -0
  138. package/commands/ponytail-audit.toml +2 -0
  139. package/commands/ponytail-debt.toml +2 -0
  140. package/commands/ponytail-gain.toml +2 -0
  141. package/commands/ponytail-help.toml +2 -0
  142. package/commands/ponytail-review.toml +2 -0
  143. package/commands/ponytail.toml +2 -0
  144. package/examples/email-validation.md +156 -0
  145. package/examples/group-by.md +35 -0
  146. package/examples/infinite-scroll.md +58 -0
  147. package/examples/number-formatting.md +37 -0
  148. package/examples/rate-limit.md +272 -0
  149. package/examples/react-countdown.md +390 -0
  150. package/examples/url-params.md +41 -0
  151. package/gemini-extension.json +2 -2
  152. package/hooks/band/board.ts +560 -0
  153. package/hooks/band/logo.ts +3 -0
  154. package/hooks/band/metrics.ts +311 -0
  155. package/hooks/band/register.tsx +495 -0
  156. package/hooks/band/types.d.ts +34 -0
  157. package/hooks/chill-statusline.ps1 +1 -1
  158. package/hooks/claude-band.json +6 -0
  159. package/hooks/claude-codex-hooks.json +34 -4
  160. package/hooks/copilot-hooks.json +12 -2
  161. package/hooks/cursor-hooks.json +2 -2
  162. package/hooks/ponytail-activate.js +201 -0
  163. package/hooks/ponytail-band-import.js +274 -0
  164. package/hooks/ponytail-config.js +175 -0
  165. package/hooks/ponytail-instructions.js +98 -0
  166. package/hooks/ponytail-map.js +111 -0
  167. package/hooks/ponytail-mode-tracker.js +216 -0
  168. package/hooks/ponytail-runtime.js +182 -0
  169. package/hooks/ponytail-statusline.ps1 +24 -0
  170. package/hooks/ponytail-statusline.sh +18 -0
  171. package/hooks/ponytail-subagent.js +94 -0
  172. package/hooks/qoder-hooks.json +19 -4
  173. package/i18n/README.ko.md +230 -0
  174. package/package.json +17 -6
  175. package/pi-extension/index.js +254 -0
  176. package/pi-extension/package.json +8 -0
  177. package/pi-extension/test/extension.test.js +367 -0
  178. package/pi-extension/test/helpers.test.js +179 -0
  179. package/plugin.yaml +21 -12
  180. package/rules/antislop.mdc +18 -0
  181. package/scripts/build-openclaw-skills.js +60 -0
  182. package/scripts/check-repo.mjs +389 -0
  183. package/scripts/check-rule-copies.js +74 -0
  184. package/scripts/check-versions.js +77 -0
  185. package/scripts/cursor-hooks.js +145 -0
  186. package/scripts/generate-chillslop.mjs +42 -0
  187. package/scripts/generate-examples.mjs +149 -0
  188. package/scripts/generate-plugin-doors.mjs +108 -0
  189. package/scripts/publish-openclaw-skills.js +75 -0
  190. package/scripts/skill-index.mjs +81 -0
  191. package/scripts/sync-ponytail.mjs +65 -0
  192. package/scripts/uninstall.js +92 -0
  193. package/skills/antislop/SKILL.md +700 -0
  194. package/skills/antislop/VERSION +1 -0
  195. package/skills/antislop-code/SKILL.md +128 -0
  196. package/skills/antislop-copywriting/SKILL.md +407 -0
  197. package/skills/antislop-human/LICENSE-web-quality-skills +21 -0
  198. package/skills/antislop-human/SKILL.md +204 -0
  199. package/skills/antislop-human/contrast-check.py +168 -0
  200. package/skills/antislop-human/contrast-mcp.py +121 -0
  201. package/skills/antislop-human/references/A11Y-PATTERNS.md +249 -0
  202. package/skills/antislop-human/references/WCAG.md +127 -0
  203. package/skills/antislop-layoutmobile/SKILL.md +170 -0
  204. package/skills/antislop-ui/LICENSE-web-quality-skills +21 -0
  205. package/skills/antislop-ui/SKILL.md +344 -0
  206. package/skills/antislop-ui/references/CORE-WEB-VITALS.md +181 -0
  207. package/skills/antislop-ui/references/WEB-BASELINE.md +28 -0
  208. package/skills/plugin.json +5 -0
  209. package/skills/ponytail/SKILL.md +52 -0
  210. package/skills/ponytail-audit/SKILL.md +103 -0
  211. package/skills/ponytail-debt/SKILL.md +44 -0
  212. package/skills/ponytail-gain/SKILL.md +52 -0
  213. package/skills/ponytail-help/SKILL.md +76 -0
  214. package/skills/ponytail-review/SKILL.md +101 -0
  215. package/src/package.json +3 -0
  216. package/tests/activation-map.test.js +63 -0
  217. package/tests/band-import.test.js +111 -0
  218. package/tests/band.test.tsx +520 -0
  219. package/tests/behavior.test.js +80 -0
  220. package/tests/commands.test.js +94 -0
  221. package/tests/copilot-plugin.test.js +35 -0
  222. package/tests/correctness.test.js +245 -0
  223. package/tests/cursor-hooks.test.js +343 -0
  224. package/tests/gemini-extension.test.js +91 -0
  225. package/tests/grok-plugin.test.js +39 -0
  226. package/tests/hermes-plugin.test.js +403 -0
  227. package/tests/hooks-windows.test.js +205 -0
  228. package/tests/hooks.test.js +1005 -0
  229. package/tests/kimi-plugin.test.js +25 -0
  230. package/tests/loc.test.js +18 -0
  231. package/tests/map.test.js +30 -0
  232. package/tests/openclaw-skills.test.js +26 -0
  233. package/tests/opencode-plugin.test.js +340 -0
  234. package/tests/package-scripts.test.js +35 -0
  235. package/tests/package.test.js +23 -0
  236. package/tests/qoder-plugin.test.js +84 -0
  237. package/tests/uninstall.test.js +202 -0
  238. /package/bin/{chill-agent.js → chill-agent.mjs} +0 -0
  239. /package/tests/{manifests.test.js → manifests.test.mjs} +0 -0
  240. /package/tests/{rules.test.js → rules.test.mjs} +0 -0
package/__init__.py ADDED
@@ -0,0 +1,228 @@
1
+ """Hermes plugin for Ponytail."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ import re
8
+ from pathlib import Path
9
+ from typing import Any, Callable
10
+
11
+ DEFAULT_MODE = "full"
12
+ RUNTIME_MODES = {"off", "lite", "full", "ultra"}
13
+ SKILL_COMMANDS = {
14
+ "ponytail-review": "Review the current diff or provided target: bugs, security, load, missing tests, speed, and what to cut.",
15
+ "ponytail-audit": "Audit the whole repo: bugs, security, load, missing tests, speed, and what to cut.",
16
+ "ponytail-debt": "List every deliberate `shortcut:` comment and its upgrade path.",
17
+ "ponytail-gain": "Show the measured-impact scoreboard (less code, less cost, more speed).",
18
+ "ponytail-help": "Show the Ponytail command reference.",
19
+ }
20
+
21
+ ROOT = Path(__file__).resolve().parent
22
+ SKILLS_DIR = ROOT / "skills"
23
+ PONYTAIL_SKILL = SKILLS_DIR / "ponytail" / "SKILL.md"
24
+
25
+ _current_mode = None
26
+
27
+
28
+ def _normalize_runtime_mode(mode: str | None) -> str | None:
29
+ if not isinstance(mode, str):
30
+ return None
31
+ mode = mode.strip().lower()
32
+ return mode if mode in RUNTIME_MODES else None
33
+
34
+
35
+ def _config_dir() -> Path:
36
+ if os.environ.get("XDG_CONFIG_HOME"):
37
+ return Path(os.environ["XDG_CONFIG_HOME"]) / "ponytail"
38
+ if os.name == "nt":
39
+ return Path(os.environ.get("APPDATA", Path.home() / "AppData" / "Roaming")) / "ponytail"
40
+ return Path.home() / ".config" / "ponytail"
41
+
42
+
43
+ def _default_mode() -> str:
44
+ env_mode = _normalize_runtime_mode(os.environ.get("PONYTAIL_DEFAULT_MODE"))
45
+ if env_mode:
46
+ return env_mode
47
+ try:
48
+ data = json.loads((_config_dir() / "config.json").read_text(encoding="utf-8-sig"))
49
+ file_mode = _normalize_runtime_mode(data.get("defaultMode"))
50
+ if file_mode:
51
+ return file_mode
52
+ except Exception:
53
+ pass
54
+ return DEFAULT_MODE
55
+
56
+
57
+ def _strip_frontmatter(text: str) -> str:
58
+ return re.sub(r"^---[\s\S]*?---\s*", "", text or "", count=1)
59
+
60
+
61
+ def _filter_skill_body_for_mode(body: str, mode: str) -> str:
62
+ effective = _normalize_runtime_mode(mode) or DEFAULT_MODE
63
+ lines = []
64
+ # str.splitlines() drops a trailing line terminator instead of yielding a
65
+ # trailing empty element, so a body ending in "\n" loses that newline on
66
+ # rejoin. re.split keeps it, matching the JS filter's split(/\r?\n/).
67
+ for line in re.split(r"\r?\n", _strip_frontmatter(body)):
68
+ table_label = re.match(r"^\|\s*\*\*(.+?)\*\*\s*\|", line)
69
+ if table_label:
70
+ label_mode = _normalize_runtime_mode(table_label.group(1))
71
+ if label_mode and label_mode != effective:
72
+ continue
73
+
74
+ # Require a quoted value: every worked example is `- lite: "..."`. Without
75
+ # this, an ordinary rule bullet that happens to start with a mode word
76
+ # (e.g. "- Full: ...") is silently dropped in every other mode — it looks
77
+ # like a worked example but is really prose meant to survive verbatim.
78
+ # Mirrors the fix in hooks/ponytail-instructions.js (#571).
79
+ example_label = re.match(r'^-\s*([^:]+):\s*"', line)
80
+ if example_label:
81
+ label_mode = _normalize_runtime_mode(example_label.group(1))
82
+ if label_mode and label_mode != effective:
83
+ continue
84
+
85
+ lines.append(line)
86
+ return "\n".join(lines)
87
+
88
+
89
+ def _fallback_instructions(mode: str) -> str:
90
+ return (
91
+ f"PONYTAIL MODE ACTIVE — level: {mode}\n\n"
92
+ "You are a lazy senior developer. The best code is the code never written. "
93
+ "Before you write, list every place your change must reach (callers, tests, "
94
+ "fixtures) and what it could break for users. First rung that works: skip what "
95
+ "is not needed, reuse what the codebase has, stdlib or platform, installed "
96
+ "dependency, one readable line, then minimum code. No unrequested abstractions, "
97
+ "wrappers, options or boilerplate. Never cut trust-boundary validation, "
98
+ "data-loss handling, security, accessibility or anything asked for."
99
+ )
100
+
101
+
102
+ def build_injected_context(mode: str | None = None) -> str:
103
+ """Return the mode-filtered Ponytail context injected before LLM turns."""
104
+ effective = _normalize_runtime_mode(mode) or _default_mode()
105
+ if effective == "off":
106
+ return ""
107
+ try:
108
+ body = PONYTAIL_SKILL.read_text(encoding="utf-8")
109
+ return f"PONYTAIL MODE ACTIVE — level: {effective}\n\n{_filter_skill_body_for_mode(body, effective)}"
110
+ except OSError:
111
+ return _fallback_instructions(effective)
112
+
113
+
114
+ def _pre_llm_call(
115
+ session_id: str = "", conversation_history: Any = None, **_: Any
116
+ ) -> dict[str, str] | None:
117
+ mode = _current_mode or _default_mode()
118
+ # Off is injected too: the ruleset from an earlier turn is replayed every turn,
119
+ # and the /ponytail off reply goes to the user, never to the model.
120
+ context = build_injected_context(mode) or "PONYTAIL MODE OFF"
121
+
122
+ # Hermes persists hook context in api_content for cache-stable replay.
123
+ # Re-inject only when the active mode changed or compaction removed it.
124
+ for message in reversed(conversation_history or []):
125
+ if not isinstance(message, dict):
126
+ continue
127
+ api_content = message.get("api_content")
128
+ if not isinstance(api_content, str):
129
+ continue
130
+ matches = re.findall(r"PONYTAIL MODE (?:ACTIVE — level: ([a-z]+)|OFF)", api_content)
131
+ if matches:
132
+ return None if (matches[-1] or "off") == mode else {"context": context}
133
+
134
+ # Nothing persisted, so off has nothing to switch off.
135
+ return None if mode == "off" else {"context": context}
136
+
137
+
138
+ def _skill_prompt(command: str, args: str = "") -> str:
139
+ tail = args.strip()
140
+ target = f"\n\nUser arguments: {tail}" if tail else ""
141
+ return (
142
+ f"Load and follow the Hermes plugin skill `ponytail:{command}`. "
143
+ f"{SKILL_COMMANDS[command]}{target}"
144
+ )
145
+
146
+
147
+ def _slash_access_denied(event: Any, gateway: Any, command: str) -> bool:
148
+ if gateway is None or event is None:
149
+ return False
150
+ checker = getattr(gateway, "_check_slash_access", None)
151
+ source = getattr(event, "source", None)
152
+ if checker is None or source is None:
153
+ return False
154
+ try:
155
+ return checker(source, command) is not None
156
+ except Exception:
157
+ return True
158
+
159
+
160
+ def rewrite_gateway_command(event: Any = None, gateway: Any = None, **_: Any) -> dict[str, str] | None:
161
+ """Rewrite authorized gateway /ponytail-* commands into normal agent prompts."""
162
+ text = str(getattr(event, "text", "") or "").strip()
163
+ if not text.startswith("/"):
164
+ return None
165
+ head, _, rest = text[1:].partition(" ")
166
+ command = head.replace("_", "-").lower()
167
+ if command not in SKILL_COMMANDS:
168
+ return None
169
+ if _slash_access_denied(event, gateway, command):
170
+ return None
171
+ return {"action": "rewrite", "text": _skill_prompt(command, rest)}
172
+
173
+
174
+ def _handle_mode_command(raw_args: str) -> str:
175
+ global _current_mode
176
+ arg = (raw_args or "").strip().lower()
177
+ if not arg:
178
+ # Bare /ponytail switches ponytail on, or reports the level when it already is (#639).
179
+ mode = _current_mode or _default_mode()
180
+ if mode != "off":
181
+ return f"Ponytail mode: {mode}. Use `/ponytail lite|full|ultra|off`."
182
+ _current_mode = "full" if _default_mode() == "off" else _default_mode()
183
+ return f"Ponytail mode set to {_current_mode}."
184
+ mode = _normalize_runtime_mode(arg)
185
+ if not mode:
186
+ return "Usage: /ponytail [lite|full|ultra|off]"
187
+ _current_mode = mode
188
+ return f"Ponytail mode set to {mode}."
189
+
190
+
191
+ def _make_skill_command_handler(ctx: Any, command: str) -> Callable[[str], str]:
192
+ def handler(raw_args: str) -> str:
193
+ prompt = _skill_prompt(command, raw_args or "")
194
+ injected = False
195
+ try:
196
+ injected = bool(ctx.inject_message(prompt))
197
+ except Exception:
198
+ injected = False
199
+ if injected:
200
+ return f"Queued `{command}` for the agent."
201
+ return prompt
202
+
203
+ return handler
204
+
205
+
206
+ def register(ctx: Any) -> None:
207
+ """Register Ponytail hooks, skills, and slash commands with Hermes."""
208
+ for child in sorted(SKILLS_DIR.iterdir() if SKILLS_DIR.exists() else []):
209
+ skill_md = child / "SKILL.md"
210
+ if child.is_dir() and skill_md.exists() and child.name.startswith("ponytail"):
211
+ ctx.register_skill(child.name, skill_md)
212
+
213
+ ctx.register_hook("pre_llm_call", _pre_llm_call)
214
+ ctx.register_hook("pre_gateway_dispatch", rewrite_gateway_command)
215
+
216
+ ctx.register_command(
217
+ "ponytail",
218
+ _handle_mode_command,
219
+ description="Set Ponytail lazy senior dev mode: lite, full, ultra, or off.",
220
+ args_hint="[lite|full|ultra|off]",
221
+ )
222
+ for command, description in SKILL_COMMANDS.items():
223
+ ctx.register_command(
224
+ command,
225
+ _make_skill_command_handler(ctx, command),
226
+ description=description,
227
+ args_hint="[target or notes]",
228
+ )
Binary file
Binary file
Binary file
@@ -0,0 +1,21 @@
1
+ <svg viewBox="0 0 860 336" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system, 'Segoe UI', Helvetica, Arial, sans-serif">
2
+ <title>Median lines of code per arm across three models</title>
3
+ <text x="20" y="26" font-size="15" font-weight="600" fill="#8b949e">Median lines of code. 10 runs per cell. Lower is leaner.</text>
4
+ <text x="20" y="45" font-size="12" fill="#8b949e" opacity="0.85">Ponytail writes 80-94% less code, costs 42-75% less, and runs 3-6x faster than a no-skill agent.</text>
5
+ <rect x="20" y="58" width="12" height="12" rx="2" fill="#8b949e"/><text x="38" y="69" font-size="13" fill="#8b949e">baseline (no skill)</text>
6
+ <rect x="190" y="58" width="12" height="12" rx="2" fill="#d9822b"/><text x="208" y="69" font-size="13" fill="#8b949e">caveman</text>
7
+ <rect x="300" y="58" width="12" height="12" rx="2" fill="#2da44e"/><text x="318" y="69" font-size="13" fill="#8b949e">ponytail</text>
8
+ <text x="112" y="119" font-size="13" font-weight="600" fill="#8b949e" text-anchor="end">Haiku</text>
9
+ <rect x="120" y="92" width="508" height="14" rx="2" fill="#8b949e"/><text x="634" y="103" font-size="11" fill="#8b949e">518</text>
10
+ <rect x="120" y="110" width="114" height="14" rx="2" fill="#d9822b"/><text x="240" y="121" font-size="11" fill="#d9822b">116</text>
11
+ <rect x="120" y="128" width="38" height="14" rx="2" fill="#2da44e"/><text x="164" y="139" font-size="11" fill="#2da44e" font-weight="600">39</text>
12
+ <text x="112" y="193" font-size="13" font-weight="600" fill="#8b949e" text-anchor="end">Sonnet</text>
13
+ <rect x="120" y="166" width="680" height="14" rx="2" fill="#8b949e"/><text x="806" y="177" font-size="11" fill="#8b949e">693</text>
14
+ <rect x="120" y="184" width="118" height="14" rx="2" fill="#d9822b"/><text x="244" y="195" font-size="11" fill="#d9822b">120</text>
15
+ <rect x="120" y="202" width="43" height="14" rx="2" fill="#2da44e"/><text x="169" y="213" font-size="11" fill="#2da44e" font-weight="600">44</text>
16
+ <text x="112" y="267" font-size="13" font-weight="600" fill="#8b949e" text-anchor="end">Opus</text>
17
+ <rect x="120" y="240" width="251" height="14" rx="2" fill="#8b949e"/><text x="377" y="251" font-size="11" fill="#8b949e">256</text>
18
+ <rect x="120" y="258" width="66" height="14" rx="2" fill="#d9822b"/><text x="192" y="269" font-size="11" fill="#d9822b">67</text>
19
+ <rect x="120" y="276" width="50" height="14" rx="2" fill="#2da44e"/><text x="176" y="287" font-size="11" fill="#2da44e" font-weight="600">51</text>
20
+ <text x="120" y="324" font-size="11" fill="#8b949e" opacity="0.8">Median of 10 runs/cell, default temperature. 5 tasks (email, debounce, CSV sum, countdown, rate-limit), same model per group. Reproduce: npx promptfoo eval -c benchmarks/promptfooconfig.yaml</text>
21
+ </svg>
@@ -0,0 +1,62 @@
1
+ <svg viewBox="0 0 860 488" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system, 'Segoe UI', Helvetica, Arial, sans-serif">
2
+ <title>Each arm vs the no-skill baseline across every metric, plus safety, Claude Code on Haiku 4.5</title>
3
+ <text x="430" y="24" font-size="15" font-weight="600" fill="#8b949e" text-anchor="middle">Every metric vs the no-skill baseline (Claude Code, Haiku 4.5, 12 tasks)</text>
4
+
5
+ <rect x="212" y="38" width="12" height="12" rx="2" fill="#8b949e"/><text x="229" y="48" font-size="12" fill="#8b949e">baseline</text>
6
+ <rect x="300" y="38" width="12" height="12" rx="2" fill="#d9822b"/><text x="317" y="48" font-size="12" fill="#8b949e">caveman</text>
7
+ <rect x="392" y="38" width="12" height="12" rx="2" fill="#2da44e"/><text x="409" y="48" font-size="12" fill="#8b949e">ponytail</text>
8
+ <rect x="478" y="38" width="12" height="12" rx="2" fill="#8957e5"/><text x="495" y="48" font-size="12" fill="#8b949e">yagni-oneliner</text>
9
+
10
+ <text x="32" y="248" font-size="12" fill="#8b949e" text-anchor="middle" transform="rotate(-90 32 248)">% of baseline (lower is leaner)</text>
11
+ <line x1="85" y1="360" x2="815" y2="360" stroke="#8b949e" stroke-opacity="0.55"/>
12
+ <line x1="85" y1="305" x2="815" y2="305" stroke="#8b949e" stroke-opacity="0.16"/>
13
+ <line x1="85" y1="250" x2="815" y2="250" stroke="#8b949e" stroke-opacity="0.16"/>
14
+ <line x1="85" y1="195" x2="815" y2="195" stroke="#8b949e" stroke-opacity="0.16"/>
15
+ <line x1="85" y1="140" x2="815" y2="140" stroke="#8b949e" stroke-opacity="0.45" stroke-dasharray="4 4"/>
16
+ <text x="78" y="364" font-size="11" fill="#8b949e" text-anchor="end">0%</text>
17
+ <text x="78" y="309" font-size="11" fill="#8b949e" text-anchor="end">25%</text>
18
+ <text x="78" y="254" font-size="11" fill="#8b949e" text-anchor="end">50%</text>
19
+ <text x="78" y="199" font-size="11" fill="#8b949e" text-anchor="end">75%</text>
20
+ <text x="78" y="144" font-size="11" fill="#8b949e" text-anchor="end">100%</text>
21
+
22
+ <!-- LOC -->
23
+ <rect x="108" y="140" width="30" height="220" rx="2" fill="#8b949e"/><text x="123" y="135" font-size="10" fill="#8b949e" text-anchor="middle">100%</text>
24
+ <rect x="146" y="184" width="30" height="176" rx="2" fill="#d9822b"/><text x="161" y="179" font-size="10" fill="#d9822b" text-anchor="middle">80%</text>
25
+ <rect x="184" y="259" width="30" height="101" rx="2" fill="#2da44e"/><text x="199" y="254" font-size="10" font-weight="600" fill="#2da44e" text-anchor="middle">46%</text>
26
+ <rect x="222" y="213" width="30" height="147" rx="2" fill="#8957e5"/><text x="237" y="208" font-size="10" fill="#8957e5" text-anchor="middle">67%</text>
27
+ <text x="180" y="380" font-size="13" fill="#8b949e" text-anchor="middle">LOC</text>
28
+ <text x="180" y="395" font-size="10" fill="#8b949e" opacity="0.8" text-anchor="middle">base 191</text>
29
+
30
+ <!-- tokens -->
31
+ <rect x="288" y="140" width="30" height="220" rx="2" fill="#8b949e"/><text x="303" y="135" font-size="10" fill="#8b949e" text-anchor="middle">100%</text>
32
+ <rect x="326" y="125" width="30" height="235" rx="2" fill="#d9822b"/><text x="341" y="120" font-size="10" fill="#d9822b" text-anchor="middle">107%</text>
33
+ <rect x="364" y="188" width="30" height="172" rx="2" fill="#2da44e"/><text x="379" y="183" font-size="10" font-weight="600" fill="#2da44e" text-anchor="middle">78%</text>
34
+ <rect x="402" y="171" width="30" height="189" rx="2" fill="#8957e5"/><text x="417" y="166" font-size="10" fill="#8957e5" text-anchor="middle">86%</text>
35
+ <text x="360" y="380" font-size="13" fill="#8b949e" text-anchor="middle">tokens</text>
36
+ <text x="360" y="395" font-size="10" fill="#8b949e" opacity="0.8" text-anchor="middle">base 349k</text>
37
+
38
+ <!-- cost -->
39
+ <rect x="468" y="140" width="30" height="220" rx="2" fill="#8b949e"/><text x="483" y="135" font-size="10" fill="#8b949e" text-anchor="middle">100%</text>
40
+ <rect x="506" y="136" width="30" height="224" rx="2" fill="#d9822b"/><text x="521" y="131" font-size="10" fill="#d9822b" text-anchor="middle">102%</text>
41
+ <rect x="544" y="184" width="30" height="176" rx="2" fill="#2da44e"/><text x="559" y="179" font-size="10" font-weight="600" fill="#2da44e" text-anchor="middle">80%</text>
42
+ <rect x="582" y="188" width="30" height="172" rx="2" fill="#8957e5"/><text x="597" y="183" font-size="10" fill="#8957e5" text-anchor="middle">78%</text>
43
+ <text x="540" y="380" font-size="13" fill="#8b949e" text-anchor="middle">cost</text>
44
+ <text x="540" y="395" font-size="10" fill="#8b949e" opacity="0.8" text-anchor="middle">base $0.10</text>
45
+
46
+ <!-- time -->
47
+ <rect x="648" y="140" width="30" height="220" rx="2" fill="#8b949e"/><text x="663" y="135" font-size="10" fill="#8b949e" text-anchor="middle">100%</text>
48
+ <rect x="686" y="136" width="30" height="224" rx="2" fill="#d9822b"/><text x="701" y="131" font-size="10" fill="#d9822b" text-anchor="middle">102%</text>
49
+ <rect x="724" y="199" width="30" height="161" rx="2" fill="#2da44e"/><text x="739" y="194" font-size="10" font-weight="600" fill="#2da44e" text-anchor="middle">73%</text>
50
+ <rect x="762" y="206" width="30" height="154" rx="2" fill="#8957e5"/><text x="777" y="201" font-size="10" fill="#8957e5" text-anchor="middle">70%</text>
51
+ <text x="720" y="380" font-size="13" fill="#8b949e" text-anchor="middle">time</text>
52
+ <text x="720" y="395" font-size="10" fill="#8b949e" opacity="0.8" text-anchor="middle">base 69s</text>
53
+
54
+ <text x="20" y="418" font-size="11" fill="#8b949e" opacity="0.8">Each bar = that arm's mean as a % of the no-skill baseline (the gray 100% bars). Lower is leaner / cheaper / faster; caveman rises above 100% on tokens, cost and time. n=4.</text>
55
+
56
+ <line x1="20" y1="438" x2="815" y2="438" stroke="#8b949e" stroke-opacity="0.25"/>
57
+ <text x="20" y="460" font-size="11" fill="#8b949e" opacity="0.9">Safety, separate 6-task adversarial tier (path-traversal, SQLi, token forgery, malformed input, rate-limit). Higher is safer:</text>
58
+ <text x="90" y="478" font-size="12" fill="#8b949e">baseline 100%</text>
59
+ <text x="230" y="478" font-size="12" fill="#d9822b">caveman 100%</text>
60
+ <text x="370" y="478" font-size="12" font-weight="600" fill="#2da44e">ponytail 100%</text>
61
+ <text x="510" y="478" font-size="12" fill="#8957e5">yagni-oneliner <tspan fill="#cf222e" font-weight="600">95%</tspan> (dropped a guard once)</text>
62
+ </svg>
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file