商业产业 Hacker News Claude 2026-10-07T17:16 正文 ok 2567 words

Show HN:terse,一款通过删除赘词将 Claude Code 回复长度减半的插件

英文标题:🔶 Show HN: Terse, a Claude Code plugin that halves reply length by cutting filler

terse 是一款 Claude Code 插件,旨在压缩冗长回复并移除口号式、比喻式和自我叙述式表达。作者的基准测试显示,在真实代码库的 20 个提示词中,Fable 5.1 的回复字数减少 46%、成本降低 51%,Opus 5.5 的回复字数减少 54%、成本降低 32%。插件通过输出风格规则、子代理 Hook 以及每轮提示词提醒来维持简洁风格,并附带上下文占用状态栏仪表。对开发者而言,该项目提供了一种降低 Agent 输出 token 成本、提高代码协作信息密度的 Claude Code 插件方案。
打开原文相关 3 · 机会 0
media1.9 KB media898 B media612.4 KB media46.5 KB

中文

terse:让 Claude 正常说话

我很难适应 Claude Code 对我说话的方式。每一个问题都会得到一篇小作文作为回答:口号、隐喻、对刚刚完成事项的回顾、“不是 X,而是 Y”。每一次都是如此。

Claude 自己的“简洁”模式确实会缩短一些内容,但其余那些冗余表达仍然存在。

我试过 system prompt,但几轮对话后它们就会被遗忘。我试着寻找插件,但没有一个能始终让 Claude 正常说话。有些是 slash command,有些解决 token 使用问题,有些面向神经多样性需求。没有一个能让 Claude 正常说话。

我只是不想每次都读一篇小作文,希望 Claude 每一次都能快速切入重点。

所以,我花了几周时间记下它做的每一件让我烦恼的事,以及我希望它改成怎样表达,并围绕这些内容构建了一个插件。它对我有效。如果 Claude 对你说话也是这个样子,那么它就是你的。

在 Opus 5.5 上使用相同提示词:原生 Claude Code 为 636 词,terse 为 180 词

本 README 的其余部分由 Claude Code 使用 terse 插件共同撰写。我拿走大部分功劳,但这些文字的功劳一点不拿。

这是一款 Claude Code 插件,可将回复长度减半,并移除矫饰的文风。**Fable 5.1:字数减少 46%,成本降低 51%。Opus 5.5:字数减少 54%,成本降低 32%。测量结果基于真实代码库中的 20 个提示词。**这些写作规则适用于回复、文档、提交记录和子代理。插件还附带一个用于状态栏的上下文仪表。

表格中使用以下术语。

  • Vanilla 指不使用 CLAUDE.md、不使用插件且没有自定义指令的 Claude Code。
  • 风格违规指违反任一规则的句子。Opus 5 评审通过将每条回复与规则列表对照阅读来统计违规数。统计值按每 1,000 词计算,因此长短回复可以比较。
  • 隐喻指在存在字面表达时使用的比喻性措辞。例如,用“一个 3,000 行的合并请求只得到匆匆一瞥和一番祈祷”替代“一个 3,000 行的合并请求得到 10 分钟阅读,但没有逐行审查”。
  • “X,而不是 Y”重构,指使用对比作为标签来替代解释。例如,用“这是意图,而不是行为”替代“文档字符串说 X,代码做 Y”。
  • 口号是一句听起来像原则、但没有说明机制的短句。例如,“决策本身就是功能。”
  • 节奏感是为追求效果而构造的韵律,例如三段式和包袱式结尾。
  • 冗余是没有增加任何事实的句子,包括“我现在来看看代码”这样的叙述。
  • 第一人称包括 “I”、“me”、“my”、“let me”及其缩写形式,即主语为写作者的句子。
  • 输出 token 是模型写出的内容,包括思考过程。Opus 和 Fable 的输出 token 定价大约是输入 token 的五倍。

在 12 个公开提示词上测量,对比原生 Claude Code 与 terse 1.1.0。使用 Opus 5.5,高努力等级,每个提示词各运行一次。

| 原生 | terse | 变化
---|---|---|---
字数,10 条聊天回复 | 5,959 | 1,793 | -70%
回复中位数 | 636 词 | 181 词 | -72%
输出 token,12 次运行 | 19,310 | 10,528 | -45%
每千词风格违规数(Opus 评审) | 11.1 | 1.1 | -90%
每千词第一人称数 | 2.79 | 0.47 | -83%
每千词“X,而不是 Y”重构数 | 0.84 | 0.56 | -33%
每千词口号数 | 1.17 | 0.0 | -100%
每千词隐喻数 | 3.69 | 0.0 | -100%

Fable 5.1、努力等级为 medium 的 Opus 5.5,以及 1.0.0 规则文本对应的表格,见:docs/models。方法、提示词和评审准则,见:docs/benchmark.md。

通过 Claude 目录安装:打开 terse 条目,然后选择 Add to Claude Code。该插件会保存至你的 claude.ai 账户,并会在你下次使用该账户登录并启动 Claude Code 时下载。在正在运行的会话中,使用 /reload-plugins 可立即加载。Anthropic 会在目录提供每个版本前进行扫描和审核。

通过 GitHub 在 Claude Code 中安装:

/plugin marketplace add lowenbjer/claude-terse
/plugin install terse@terse

两种途径安装的是相同文件。写作规则适用于每个新会话、执行 /clear 后的会话,以及退出后通过 claude --resume 恢复的既有会话。

如需上下文仪表,运行一次 /terse:install-meter。它会将 26 行的仪表脚本复制到插件的数据目录中,该目录不会受到插件更新影响,并向你的 ~/.claude/settings.json 添加一条 statusLine 配置。保存后该配置即会生效。

规则包括一种回复结构、22 条规则和 18 组修改前后示例,共 877 个词。该结构为:先用一句话给出答案,然后给出一个列表或表格,随后最多一句注意事项,然后结束。每句话都以主题作为主语:不使用“我”,不说明检查了什么或将会做什么。项目符号以事实开头,因此没有加粗引导语或标签行。用普通词语替代杜撰的名称。不使用破折号、口号、“X,而不是 Y”的框架、自我标签或结尾的主动邀约。除非要求文档或演练说明,否则聊天回复在 150 词内结束。发现列表中的每项发现使用一到两句话。重新生成时只发送变化部分。当规则存在肯定形式时,文本会在禁止项之前说明这种形式(“最后一句是一个事实。”)。完整文本:rules/RULES.md。

这些规则作为一种输出风格发布。它在插件启用期间生效,并成为主 Agent system prompt 的一部分。子代理运行各自的 system prompt,因此 SubagentStart Hook 会向它们提供相同的文本。没有任何 Hook 会改写或阻止任何内容。

之所以需要提醒,是因为输出风格位于上下文的最前部。经过 20 或 30 轮后,它会位于当前提示词之前约 100k token 处。模型自身近期的回复会变成距离最近的风格示例。从那时起,回复会把答案放在最后一行,出现“我检查了”之类的句子、破折号、“X,而不是 Y”和口号。UserPromptSubmit Hook 会将压缩为 576 个字符的完整规则集添加到每个提示词中,位置紧邻你的文本。每轮成本约为 145 个输入 token。文本见:rules/REMINDER.md。

仪表会显示模型名称和上下文填充百分比。低于 37% 为绿色,从 37% 开始为黄色,从 49% 开始为橙色,从 60% 开始显示骷髅。阈值设定低于通常的 50%、65% 和 80%。三项研究显示,在大上下文窗口填满很久之前,检索质量就会下降:

  • Chroma 的 Context Rot 报告:在 200k 上下文窗口中测试 18 个模型,性能从 50k token 开始下降。
  • NoLiMa:13 个模型中有 11 个在 32k token 时降至其基线水平的一半。
  • Lost in the Middle:长上下文中间的内容获得的关注少于开头和结尾。

阈值是 statusline/context-meter.js 顶部附近的三个数字。

提示词,在每种配置下均使用 Opus 5.5 运行:“我们有一个 Flask API 和一个 Postgres 数据库。每天大约 09:00,负载升高时请求会超时。你会首先检查哪里,为什么?”

原生版本,636 词:

我会首先检查 09:00 超时问题的地方

09:00 这一时间点是最有用的线索。在查看任何代码之前,先确认以下两种情况中发生的是哪一种:

  1. 09:00 流量上升。 工作日开始会带来登录、仪表盘访问和同步任务。这是容量问题。
  2. 流量保持平稳,但在 09:00 有其他任务运行。 这是定时任务造成的资源争用。

将 09:00 的请求速率图与其他时段进行比较。这一项检查就能告诉你问题属于哪一半。

1. 检查 09:00 运行了什么

检查 crontab、pg_cron、Celery beat、Kubernetes CronJob、备份(pg_dump)、ETL 和报表任务,以及 REFRESH MATERIALIZED VIEW。还要检查是否有在同一时刻一起过期的缓存条目,因为这会让所有请求同时涌向数据库。

注意时区。调度器配置中的本地时间 09:00 可能是 UTC 07:00,因此要同时 grep 这两个时间。

常见问题:

  • 未使用 CONCURRENTLY 的 REFRESH MATERIALIZED VIEW、批量 UPDATE 或迁移操作。它们都会持有锁,导致 API 查询在后面等待。
  • 消耗完磁盘 I/O 的备份或批处理任务。

2. 捕获该时间窗口内 Postgres 正在执行的内容

这能最快得到真正的答案。从 08:55 到 09:15,每隔 10–15 秒抓取一次 pg_stat_activity 快照:

SELECT now(), state, wait_event_type, wait_event,
       now() - xact_start AS xact_age, left(query, 120) AS query, application_name
FROM pg_stat_activity
WHERE datname = current_database()
ORDER BY xact_start NULLS LAST;

按以下方式解读结果:

  • 大量 wait_event_type = 'Lock': 有任务正在持有锁。与 pg_locks 关联查询(或使用 pg_blocking_pids())以找出阻塞会话。通常是第 1 步中的定时任务。
  • 大量 idle in transaction: 应用打开事务后没有及时关闭。这会占用连接和锁。
  • 许多 active 会话运行相同查询: 有一条查询在规模增长时变慢,通常是缺少索引或计划过期。检查该时间窗口的 pg_stat_statements。
  • 会话数接近 max_connections: 你的连接即将耗尽(见第 3 步)。

同时设置 log_min_duration_statement(例如 500ms)和 log_lock_waits = on,这样下一次发生时就会留下记录。

3. 检查应用侧连接池是否耗尽

这是 Flask + SQLAlchemy 应用中最常见的超时原因。搜索 09:00 前后应用日志中的以下内容:

QueuePool limit of size 5 overflow 10 reached, connection timed out

然后进行计算:gunicorn worker 数 × 线程数 ×(pool_size + max_overflow)× 实例数,对比 Postgres 的 max_connections。当流量激增时,请求会排队等待池化连接,直至超时。发生这种情况时,Postgres 看上去可能几乎处于空闲状态。

还要检查是否有会话未归还给连接池。常见原因是缺少 db.session.remove() 或 teardown handler,或者在事务内部发起了缓慢的外部 HTTP 调用。

4. 查明是哪一种超时正在触发

负载均衡器(通常为 60 秒)、gunicorn --timeout(默认 30 秒)和 SQLAlchemy pool_timeout(默认 30 秒)分别指向不同位置:

  • Gunicorn 的 WORKER TIMEOUT 消息意味着 worker 被阻塞。它们要么在等待数据库,要么是同步 worker 太少。
  • 如果负载均衡器返回 504,但没有 gunicorn 错误,说明请求在到达 worker 前就在排队。

在明天的 09:00 运行 pg_stat_activity 快照循环。同时,grep 应用日志中的连接池错误,并列出所有接近 09:00 的定时任务。这很可能会将问题缩小到两种原因之一:一个任务持有锁,或早晨流量下连接池耗尽。二者的修复方法完全不同:移动或重写任务,或者调整连接池大小并添加 PgBouncer 等连接池代理。

如果你提供调度器配置、SQLAlchemy engine 设置和 gunicorn 命令,我可以为你检查连接数计算。

terse 1.2.0,180 词:

首先检查 09:00 有什么任务运行,因为固定的每日时间点表明原因是定时任务或登录高峰,而不是随机负载。

  • 在 08:55 至 09:15 期间检查 pg_stat_activity。长查询、“idle in transaction”会话或锁等待会显示哪一侧造成阻塞。
  • 列出安排在 09:00 附近的 cron 任务、Celery beat 任务、pg_cron 条目和备份任务。报表、ETL 或 pg_dump 可能持有锁或耗尽磁盘 I/O。
  • 将 Gunicorn worker 数乘以线程数,与 SQLAlchemy 的 pool_size 加 max_overflow 对比。超出该容量的请求会在 pool_timeout(默认 30 秒)期间排队,这看上去就像超时。
  • 将 Postgres 的 max_connections 与所有应用实例的总连接数对比。耗尽该值会直接拒绝新连接。
  • 启用 log_min_duration_statement(例如 500 ms)和 log_lock_waits。下一次 09:00 运行时便会记录慢语句及其阻塞者。
  • 检查最繁忙表上的 autovacuum 和 ANALYZE 时机。夜间批量加载后的过期统计信息可能使计划切换为顺序扫描。

这两项日志设置现在就可以低成本启用,并能在一个早晨后区分数据库侧原因与应用侧连接池限制。

两份回复都提到了定时任务、锁等待和连接池耗尽。原生版本增加了六个标题、一个重复第 1 至 3 步的建议部分,以及一个提出检查配置的邀约。terse 版本给出了连接池计算方式、采样窗口和两项日志设置,没有任何关于写作者的句子。1.2.0 文本运行该提示词四次,结果分别为 148、176、180 和 189 词。四次中有两次以带有加粗引导语的项目符号开头,违反了规则 21。这里展示的是 180 词的运行结果。

  • Opus 5.5 和 Fable 5.1 是被测量的主 Agent。Opus 5 和 Sonnet 5 仅作为子代理运行。在规则位于上下文中的情况下,Opus 5 每千词仍保留 13 个破折号,而 Sonnet 在 5 条回复中有 1 条使用了破折号。两者都没有作为主模型的统计数据。按模型分类的表格:docs/models。
  • 在公开数据集上,隐喻降至 0;在私有数据集上,隐喻数量减半。使用 1.1.0 文本的 Opus 5.5:在 12 个公开提示词上,每千词从 3.69 降至 0.0;在 20 个私有提示词上,从 3.09 降至 1.57。使用 1.0.0 文本的 Fable 5.1:在公开数据集上从 7.2 降至 3.3。
  • 150 词上限会缩短回复,但不会强制执行该限制。在两个提示词集和两个模型中,聊天回复字数下降了 46% 至 70%。长篇分析问题仍会超出上限。
  • 子代理输出遵循子代理模型。在一个 Fable 5.1 会话中,Explore 类型子代理

English / 原文

terse - makes Claude speak normally

I struggle with the way Claude Code speaks to me. Every single question comes back as an essay. Slogans, metaphors, a recap of what it just did, "it's not X, it's Y". Every. Single. Time.

Claude's own "concise" mode shortens it, somewhat, but keeps the the rest of the slop.

I tried system prompts, those got forgotten after a couple of turns. I tried looking for plugins but none consistently made Claude speak normally. Some where slash commands, other solved for token use, others solved for neurodivergence. None of them made Claude speak normally.

I just wanted to not read an essay and make Claude get to the point fast, every single time.

So I spent a few weeks nothing down every thing it did that annoyed me and what i want it say instead, and built a Plugin around that. It worked for me. If Claude speaks to you the same way, it is yours.

Same prompt on Opus 5.5: vanilla Claude Code at 636 words against terse at 180 words

The rest of this README is co-written by Claude Code using the terse plugin. I take most of the credit, but none for the words.

A Claude Code plugin that cuts reply length in half and removes mannered prose. Fable 5.1: 46% fewer words, 51% lower cost. Opus 5.5: 54% fewer words, 32% lower cost.Measured on 20 prompts against a real codebase. The writing rules apply to replies, documents, commits and subagents. A context meter for the status line comes with it.

The tables use these terms.

  • Vanilla is Claude Code with no CLAUDE.md, no plugins and no custom instructions.
  • A style violation is a sentence that breaks one of the rules. An Opus 5 judge counts them by reading each reply against the rule list. Counts are per 1,000 words, so long and short replies compare.
  • Metaphor is figurative wording where a literal phrase exists. "A 3,000-line merge gets a skim and a prayer" in place of "a 3,000-line merge gets a 10-minute read and no line-by-line review".
  • An "X, not Y" reframe is a contrast used as a label in place of an explanation. "This is intent, not behavior" in place of "the docstring says X, the code does Y".
  • A slogan is a short line that sounds like a principle and states no mechanism. "The decision is the feature."
  • Cadence is rhythm built for effect, such as triads and punchline endings.
  • Bloat is a sentence that adds no fact, including narration like "I'll look at the code now".
  • First person is "I", "me", "my", "let me" and their contractions. Sentences whose subject is the writer.
  • Output tokens are what the model wrote, thinking included. Output tokens are priced about five times higher than input tokens on Opus and Fable.

Measured on 12 public prompts, vanilla Claude Code against terse 1.1.0. Opus 5.5, effort high, one run each.

| vanilla | terse | change
---|---|---|---
Words, 10 chat replies | 5,959 | 1,793 | -70%
Median reply | 636 words | 181 words | -72%
Output tokens, 12 runs | 19,310 | 10,528 | -45%
Style violations per 1k words (Opus judge) | 11.1 | 1.1 | -90%
First person per 1k | 2.79 | 0.47 | -83%
"X, not Y" reframes per 1k | 0.84 | 0.56 | -33%
Slogans per 1k | 1.17 | 0.0 | -100%
Metaphor per 1k | 3.69 | 0.0 | -100%

Tables for Fable 5.1, for Opus 5.5 at effort medium, and for the 1.0.0 rule text: docs/models. Method, prompts and the judge rubric: docs/benchmark.md.

From the Claude directory: open the terse listing and select Add to Claude Code. The plugin is saved to your claude.ai account and downloads the next time you start Claude Code signed in to that account. In a running session, /reload-plugins loads it at once. Anthropic scans and reviews each version before the directory serves it.

From GitHub, in Claude Code:

/plugin marketplace add lowenbjer/claude-terse
/plugin install terse@terse

Both routes install the same files. The writing rules apply to every new session, after /clear, and to an existing session you exit and resume with claude --resume.

For the context meter, run /terse:install-meter once. It copies the 26-line meter script to the plugin's data directory, which plugin updates leave in place, and adds one statusLine entry to your ~/.claude/settings.json. The entry takes effect on save.

The rules are a reply shape, 22 rules and 18 before/after pairs, 877 words. The shape: one sentence with the answer, then a list or a table, then at most one caveat sentence, then stop. Every sentence has the topic as its subject: no "I", no account of what was checked or would be done. Bullets start with the fact, so no bold lead-ins and no label lines. Plain words in place of coined names. No em dashes, no slogans, no "X, not Y" framing, no self-labeling, no closing offers. Chat replies stop at 150 words unless you ask for a document or a walkthrough. A findings list gets one or two sentences per finding. A redo sends only the delta. Where a rule has a positive form, the text states the form ("The last sentence is a fact.") ahead of the ban. Full text: rules/RULES.md.

The rules ship as an output style. It applies while the plugin is enabled and is part of the main agent's system prompt. Subagents run their own system prompt, so a SubagentStart hook hands them the same text. No hook rewrites or blocks anything.

The reminder exists because the output style is the first part of the context. After 20 or 30 turns it is 100k tokens before the current prompt. The model's own recent replies become its nearest style examples. From there the replies show the answer in the last line, "I checked" sentences, dashes, "X, not Y" and slogans. A UserPromptSubmit hook adds the whole rule set, condensed to 576 characters, to every prompt next to your text. Cost per turn is about 145 input tokens. The text is rules/REMINDER.md.

The meter shows model name and context fill as a percentage. Green below 37%, yellow from 37%, orange from 49%, skull from 60%. The thresholds are set below the usual 50, 65 and 80 percent. Three studies show retrieval quality dropping well before a large window fills:

  • Chroma's Context Rot report: 18 models, degradation from 50k tokens on a 200k window.
  • NoLiMa: 11 of 13 models at half their baseline by 32k tokens.
  • Lost in the Middle: content in the middle of a long context gets less attention than the start and end.

The thresholds are the three numbers near the top of statusline/context-meter.js.

Prompt, run on Opus 5.5 with each setup: "We have a Flask API with a Postgres database. Requests time out under load once a day around 09:00. Where would you look first and why?"

Vanilla, 636 words:

Where I'd look first for the 09:00 timeouts

The 09:00 timing is the most useful clue. Before looking at any code, find out which of these two things is happening:

  1. Traffic goes up at 09:00. The start of the workday brings logins, dashboards and syncs. That's a capacity problem.
  2. Traffic stays flat but something else runs at 09:00. That's contention from a scheduled job.

Compare your request-rate graph at 09:00 with other hours. That one check tells you which half of the problem you're in.

1. Check what runs at 09:00

Look at crontabs, pg_cron, Celery beat, Kubernetes CronJobs, backups (pg_dump), ETL and report jobs, and REFRESH MATERIALIZED VIEW. Also check for cache entries that all expire at the same moment, because that sends every request to the database at once.

Be careful with timezones. 09:00 local might be 07:00 UTC in the scheduler config, so grep for both.

Common problems:

  • A REFRESH MATERIALIZED VIEW without CONCURRENTLY, a bulk UPDATE, or a migration. Each of these takes locks that API queries then wait behind.
  • A backup or batch job using up disk I/O.

2. Capture what Postgres is doing during the window

This gives you the fastest real answer. Snapshot pg_stat_activity every 10–15 seconds from 08:55 to 09:15:

SELECT now(), state, wait_event_type, wait_event,
       now() - xact_start AS xact_age, left(query, 120) AS query, application_name
FROM pg_stat_activity
WHERE datname = current_database()
ORDER BY xact_start NULLS LAST;

Read the results like this:

  • Lots ofwait_event_type = 'Lock': something is holding locks. Join with pg_locks (or use pg_blocking_pids()) to find the blocking session. It's usually the scheduled job from step 1.
  • Lots ofidle in transaction: the app opens transactions and doesn't close them quickly. That holds connections and locks.
  • Manyactive sessions running the same query: one query is slow at scale, often a missing index or a stale plan. Check pg_stat_statements for that window.
  • Session count close tomax_connections: you're running out of connections (see step 3).

Also set log_min_duration_statement (e.g. 500ms) and log_lock_waits = on so the next occurrence leaves a record.

3. Check for app-side connection pool exhaustion

This is the most common cause of timeouts in Flask + SQLAlchemy apps. Search the app logs around 09:00 for:

QueuePool limit of size 5 overflow 10 reached, connection timed out

Then do the arithmetic: gunicorn workers × threads × (pool_size + max_overflow) × number of instances, compared with Postgres max_connections. When traffic jumps, requests queue for a pooled connection until they time out. Postgres can look almost idle while this happens.

Also check for sessions that aren't returned to the pool. The usual causes are a missing db.session.remove() or teardown handler, or slow external HTTP calls made inside a transaction.

4. Find out which timeout is firing

The load balancer (often 60s), gunicorn --timeout (30s by default) and SQLAlchemy pool_timeout (30s by default) each point to a different place:

  • Gunicorn WORKER TIMEOUT messages mean the workers are blocked. They're either waiting on the database or there are too few sync workers.
  • A 504 from the load balancer with no gunicorn error means requests are queuing before they reach a worker.

Run the pg_stat_activity snapshot loop at tomorrow's 09:00. At the same time, grep the app logs for the pool error and list every scheduled job near 09:00. That will very likely narrow it to one of two causes: a job holding locks, or pool exhaustion under the morning traffic. The fix is very different for each: move or rewrite the job, or resize the pool and add a connection pooler such as PgBouncer.

If you share the scheduler config, the SQLAlchemy engine settings and the gunicorn command, I can check the connection arithmetic for you.

terse 1.2.0, 180 words:

Start with what runs at 09:00, since a fixed daily time points to a scheduled job or a login surge, not random load.

  • Check pg_stat_activity from 08:55 to 09:15. Long queries, "idle in transaction" sessions, or lock waits show which side blocks.
  • List cron jobs, Celery beat tasks, pg_cron entries and backups scheduled near 09:00. A report, ETL or pg_dump can hold locks or saturate disk I/O.
  • Compare Gunicorn workers times threads with SQLAlchemy pool_size plus max_overflow. Requests beyond that queue for pool_timeout (30 s default), which looks like a timeout.
  • Compare Postgres max_connections with the total across all app instances. Exhausting it rejects new connections outright.
  • Turn on log_min_duration_statement (for example 500 ms) and log_lock_waits. The next 09:00 run then records the slow statements and their blockers.
  • Check autovacuum and ANALYZE timing on the busiest tables. Stale statistics after a nightly bulk load can switch plans to sequential scans.

The two logging settings are cheap to turn on today, and they separate a database-side cause from an app-side pool limit after one morning.

Both replies name scheduled jobs, lock waits and pool exhaustion. The vanilla one adds six headers, a recommendation section that repeats steps 1 to 3, and an offer to check the config. The terse one gives the pool arithmetic, the sampling window and the two log settings, with no sentence about the writer. The 1.2.0 text ran this prompt four times: 148, 176, 180 and 189 words. Two of the four opened bullets with bold lead-ins against rule 21. The 180-word run is shown.

  • Opus 5.5 and Fable 5.1 are the measured main agents. Opus 5 and Sonnet 5 ran only as subagents. With the rules in context, Opus 5 kept 13 em dashes per 1k words and Sonnet put a dash in 1 reply of 5. No numbers exist for either as the main model. Per-model tables: docs/models.
  • Metaphor drops to 0 on the public set and by half on the private set. Opus 5.5 with the 1.1.0 text: 3.69 to 0.0 per 1k on 12 public prompts, 3.09 to 1.57 on 20 private prompts. Fable 5.1 with the 1.0.0 text: 7.2 to 3.3 on the public set.
  • The 150-word cap shortens replies without enforcing the limit. Chat words fell 46 to 70 percent across two prompt sets and two models. Long analysis questions still run over.
  • Subagent output followed the subagent model. In a Fable 5.1 session, Explore-type subagents ran Opus 5 and kept 13 em dashes per 1k words with the rules in their context. Fable subagents produced 0.1 per 1k without any rules. In an Opus 5.5 session, the subagents ran Opus 5.5 and wrote 0.4 per 1k without the rules and 0 with them. To pick the subagent model, set CLAUDE_CODE_SUBAGENT_MODEL to your main model, or ask for general-purpose subagents, which inherit it.
  • The reply shape and rule 21 removed the two forms they name and no others. The check was a 10-turn conversation with the same prompts on both models. Bold lead-ins went from 20 to 0 on Fable 5.1 and from 36 to 0 on Opus 5.5. Label lines went from 10 to 4 and from 8 to 0. Judge-counted metaphor, cadence and bloat stayed level. Reply length stayed level. Table in docs/benchmark.md. The 1.2.0 text has no public-set rerun. The tables above are the 1.1.0 text.
  • Cost fell less than words. Output tokens fell 42 to 55 percent. Context tokens are most of the cost per call. Total cost fell 2 percent on the short public set with the 1.1.0 text and 9 to 12 percent with the 1.0.0 text. The reminder adds about 100 uncached tokens per turn. Thinking rose from 2,150 tokens over 12 runs with the 1.0.0 text to 4,155 with 1.1.0. On 20 chat prompts against a real codebase with a large CLAUDE.md, cost fell 51 percent on Fable 5.1 with the 1.0.0 text. On Opus 5.5 with the 1.1.0 text it fell 32 percent.

The catalog in docs/models has one file per model. A row costs about $1 and one pull request: run the 12 public prompts with and without the plugin through bench/run.py, paste the two summaries, write 2 to 5 findings. Steps in docs/models/CONTRIBUTING.md. A reply that broke the rules goes in an issue with the "Post your worst reply" template.

The plugin makes no network calls and collects nothing. Its hooks read a text file inside the plugin directory and hand it to Claude Code. The install skill writes one key to your settings file. Details in docs/privacy.md.

Installed from the directory: open the plugin under Customize > Plugins on claude.ai and select Remove from its menu.

Installed from GitHub:

/plugin uninstall terse@terse

Remove the statusLine entry from ~/.claude/settings.json if you installed the meter. The uninstall deletes the plugin's data directory, where the meter copy lives.

MIT.