<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Focused Systems</title><link>https://blog.focused.systems/</link><description>Exploring modern cloud workflows. DevOps, APIs, Git, serverless architectures, pipelines, and software integrations, alongside personal tech solutions.</description><language>en</language><generator>Hugo</generator><image><url>https://blog.focused.systems/images/social.png</url><title>Focused Systems</title><link>https://blog.focused.systems/</link></image><lastBuildDate>Fri, 11 Sep 2026 19:00:00 +0000</lastBuildDate><atom:link href="https://blog.focused.systems/tags/productivity/index.xml" rel="self" type="application/rss+xml"/><item><title>How to Stop Claude Opus 5 From Writing Walls of Text</title><link>https://blog.focused.systems/terse-claude-code-reports/</link><guid isPermaLink="true">https://blog.focused.systems/terse-claude-code-reports/</guid><pubDate>Fri, 11 Sep 2026 19:00:00 +0000</pubDate><dc:creator>Rod Christiansen</dc:creator><category>claude-code</category><category>ai</category><category>productivity</category><description>Telling Opus 5 to 'be concise' doesn't stick. Give it a report shape, put that shape in CLAUDE.md, and re-inject it on every prompt with a hook. Here's the whole setup, copy-paste ready.</description><content:encoded><![CDATA[<p>If you run long Claude Code sessions on Opus 5, you&rsquo;ve probably met the end-of-session report: five paragraphs, a &ldquo;Current state&rdquo; section, numbered open questions with a mini-essay each, a &ldquo;Net:&rdquo; summary of everything it just said, and a closing <em>&ldquo;Want me to…?&rdquo;</em>. All accurate. None of it readable at the end of a long day.</p>
<p>For weeks I typed the same reply back — <em>too much, succinct, bullet points</em> — and the next answer would be perfect. So the model <em>can</em> do it. It just doesn&rsquo;t by default, and &ldquo;be concise&rdquo; in your instructions doesn&rsquo;t fix that.</p>
<p>Here&rsquo;s what does.</p>
<h2 id="why-be-concise-doesnt-work">Why &ldquo;be concise&rdquo; doesn&rsquo;t work</h2>
<p>Three things work against you:</p>
<ul>
<li><strong>&ldquo;Concise&rdquo; isn&rsquo;t a shape.</strong> When a session produces a lot of material, the model has nowhere to put it, so it writes it all out. Short needs structure.</li>
<li><strong>Your instructions fade.</strong> <code>CLAUDE.md</code> is read once, at the start. Three hours and a few hundred tool calls later it&rsquo;s a long way back in the context — which is exactly when the walls of text show up.</li>
<li><strong>Rules fight each other.</strong> Mine said <em>&ldquo;prose only; no bullet lists&rdquo;</em> (written months ago for a different annoyance). Opus 5 obeyed it faithfully: long reports, as prose. <strong>Check your own rules for anything that forbids structure</strong> — that alone might be your problem.</li>
</ul>
<p>The fix is to give the model a fixed shape to fill, and to repeat it on every single prompt.</p>
<h2 id="the-shape-done-pending-decisions">The shape: Done, Pending, Decisions</h2>
<p>Every reply that reports work, status or analysis gets exactly three groups, and every
bullet is numbered by its group:</p>
<ul>
<li><strong>Done</strong> — fixed, shipped or verified, each with where (a PR link or a path). <code>1.1</code>, <code>1.2</code>, …</li>
<li><strong>Pending</strong> — in flight or waiting, each with what it&rsquo;s waiting on. <code>2.1</code>, <code>2.2</code>, …</li>
<li><strong>Decisions</strong> — choices only you can make, each one question with its options. <code>3.1</code>, <code>3.2</code>, …</li>
</ul>
<p>The numbers are what make it a conversation instead of a wall: the prefix is fixed per
group and doesn&rsquo;t shift when a group is empty, so you answer with &ldquo;3.2 — later&rdquo; instead of
quoting the line you mean.</p>
<p>Plus hard limits, because &ldquo;short&rdquo; without numbers drifts: one line per bullet, about twelve words, at most five bullets per group, empty groups left out, and <strong>nothing after the groups</strong>. That last one kills the <em>&ldquo;Want me to…?&rdquo;</em> closer — any question for you goes in <em>Decisions</em>, where you&rsquo;ll actually see it.</p>
<p>A few carve-outs keep it from becoming its own kind of annoying. Analysis gets up to eight bullets, then <em>Decisions</em>. A plain question gets a plain one-to-three line answer. A mid-task progress note is one line.</p>
<h2 id="step-1-put-the-rule-in-claudemd">Step 1: Put the rule in CLAUDE.md</h2>
<p>Add this to <code>~/.claude/CLAUDE.md</code> so it applies to every project, and delete any older answer-style section that disagrees with it:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gu">## Answer style — three numbered groups
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Every reply that reports work, status or analysis uses only these groups, each a bold
</span></span><span class="line"><span class="cl">label with numbered short bullets under it. Leave out any group that is empty.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> **Done** — fixed, shipped or verified. Each bullet names where: PR link or path. <span class="sb">`1.1`</span>, <span class="sb">`1.2`</span>, …
</span></span><span class="line"><span class="cl"><span class="k">-</span> **Pending** — in flight or waiting. Each bullet names what it waits on. <span class="sb">`2.1`</span>, <span class="sb">`2.2`</span>, …
</span></span><span class="line"><span class="cl"><span class="k">-</span> **Decisions** — choices only I can make. Each bullet is one question with its options. <span class="sb">`3.1`</span>, <span class="sb">`3.2`</span>, …
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Every bullet opens with its number and a dash — <span class="sb">`3.2 - Ship it now, or after the release?`</span>
</span></span><span class="line"><span class="cl">The prefix is fixed by group (Done <span class="sb">`1.x`</span>, Pending <span class="sb">`2.x`</span>, Decisions <span class="sb">`3.x`</span>) and never shifts
</span></span><span class="line"><span class="cl">when a group is left out, so I can answer with a bare number instead of quoting a line.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">One line per bullet, about twelve words or fewer, at most five bullets per group. No
</span></span><span class="line"><span class="cl">paragraphs, no background, no recap of the steps taken, no restating the request, no
</span></span><span class="line"><span class="cl">explanation of how something works unless asked. Nothing after the groups — no &#34;Want me
</span></span><span class="line"><span class="cl">to…?&#34; closer; a question for me belongs in <span class="gs">**Decisions**</span>.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Analysis or advice (parsing someone&#39;s message, weighing options) gets at most eight
</span></span><span class="line"><span class="cl">numbered bullets, then <span class="gs">**Decisions**</span>. A mid-task progress note is one short line. A plain
</span></span><span class="line"><span class="cl">question gets a plain one-to-three line answer. Write longer only when I explicitly ask
</span></span><span class="line"><span class="cl">for a doc, a design or an explanation.
</span></span></code></pre></div><h2 id="step-2-re-inject-it-on-every-prompt-with-a-hook">Step 2: Re-inject it on every prompt with a hook</h2>
<p>This is the part that actually makes it stick. A <code>UserPromptSubmit</code> hook runs every time you send a message, and whatever it prints as <code>additionalContext</code> gets attached to that prompt — so the rule is always sitting right next to your latest message, no matter how long the session has run.</p>
<p>Save this as <code>~/.claude/hooks/terse-output.sh</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl">cat <span class="s">&lt;&lt;&#39;JSON&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">{&#34;hookSpecificOutput&#34;:{&#34;hookEventName&#34;:&#34;UserPromptSubmit&#34;,&#34;additionalContext&#34;:&#34;REPORT FORMAT (hard rule, overrides default verbosity, applies to every reply that reports work, status, or analysis):\nUse only these three groups, each a bold label followed by numbered short bullets; leave out any group that is empty:\n**Done** - fixed, shipped, or verified; each bullet names where (PR link or path). Numbered 1.1, 1.2, ...\n**Pending** - in flight or waiting; each bullet names what it waits on. Numbered 2.1, 2.2, ...\n**Decisions** - choices only I can make; each bullet is one question with its options. Numbered 3.1, 3.2, ...\nRules:\n- Every bullet starts with its number and a dash: &#39;1.1 - ...&#39;. The prefix is fixed by group (Done 1.x, Pending 2.x, Decisions 3.x) and does not shift when a group is left out, so I can reply with just &#39;3.2&#39;.\n- One line per bullet, about 12 words or fewer, at most 5 bullets per group.\n- No paragraphs, no background, no recap of steps taken, no restating the request, no explaining how something works unless asked.\n- Nothing after the groups: no &#39;Want me to...?&#39; closer; a question for me goes in Decisions.\n- Analysis or advice (parsing a message, weighing options): at most 8 numbered bullets, then Decisions.\n- Mid-task progress notes: one short line, no groups.\n- A plain question gets a plain one-to-three line answer, no groups.\n- Write longer only when I explicitly ask for a doc, a design, or an explanation.&#34;}}
</span></span></span><span class="line"><span class="cl"><span class="s">JSON</span>
</span></span></code></pre></div><p>Make it executable:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">chmod +x ~/.claude/hooks/terse-output.sh
</span></span></code></pre></div><h2 id="step-3-register-the-hook">Step 3: Register the hook</h2>
<p>Add this to <code>~/.claude/settings.json</code>. If you already have a <code>hooks</code> block, merge the <code>UserPromptSubmit</code> entry into it rather than replacing the whole thing:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;UserPromptSubmit&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;~/.claude/hooks/terse-output.sh&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;timeout&#34;</span><span class="p">:</span> <span class="mi">5000</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="step-4-test-it">Step 4: Test it</h2>
<p>Start a new session and run <code>/hooks</code> — you should see <code>terse-output.sh</code> listed under <code>UserPromptSubmit</code>. Then ask for something with real output, like a small fix, and look at the reply.</p>
<p>Here&rsquo;s the same kind of report before and after.</p>
<p>Before:</p>
<blockquote>
<p>Here&rsquo;s my read, grounded in how the client actually deploys today.</p>
<p><strong>Current state:</strong> The client is a managed install, auto-pushed to every machine. Printers are self-service items that already appear grouped under a category… <em>(four more paragraphs, three numbered questions, a &ldquo;Net:&rdquo; summary, and &ldquo;Want me to check X, or draft the reply?&rdquo;)</em></p>
</blockquote>
<p>After:</p>
<blockquote>
<p><strong>Done</strong>
1.1 - The every-prompt hook used to say &ldquo;prose only&rdquo;; it now requires these three groups.
1.2 - The global CLAUDE.md answer-style section now matches that rule.</p>
<p><strong>Pending</strong>
2.1 - Sessions already open pick up the new rule from their next prompt.</p>
<p><strong>Decisions</strong>
3.1 - Also turn off the recap block after each turn?</p>
</blockquote>
<p>Ten seconds to read, and the one decision I need to make is at the bottom where I can&rsquo;t miss it.</p>
]]></content:encoded></item></channel></rss>