Think-Short Setup — install terse-mode hooks
sonnet status / install / upgrade / enable / disable / uninstall / purge project | global user-invokedWhat it does
/brewtools:think-short-setup installs (or removes) a small set of hooks that inject a fixed brevity directive into the Claude Code session. Run the skill with a free-text intent — “make responses shorter”, “stop the preamble” — and it asks via AskUserQuestion whether to apply to the current Project or Globally. It then copies four files into the target hooks directory — three hook scripts and think-short-prompt.md (the directive body) — and registers three hook entries in the appropriate settings.json. The subagent hook injects the directive on SubagentStart via hookSpecificOutput.additionalContext.
The -setup suffix is literal: this skill installs a mechanism you then use instead of the skill. After install you never type the skill again unless you want to change or remove the wiring.
There are no profiles and no config file. The only persisted state is the copied prompt file plus an ephemeral per-session counter in the OS temp directory. Because the hooks have no enabled flag, disable renames think-short-prompt.md to think-short-prompt.md.disabled — the hooks stay wired, find no prompt and no-op. purge deletes the files and the tmp markers outright.
The same directive body is injected at every point:
Be terse. Results first, no preamble/filler/sycophancy. ASCII only.
Think short: minimal internal reasoning, no exploring aloud.
Grep before Read. Edit over Write. Parallel calls in one message.
Plan the full edit set, then execute.
Keep code simple - do not over-engineer. Before writing anything new,
check existing code and libraries for the needed functionality.
Prefer extending or abstracting a similar class over adding a new one.
After writing code, one pass: can this be simpler? If yes - simplify it.
Comment like a human, not an AI. Write comments only where they earn it:
non-obvious logic, public APIs, class/method docstrings (JavaDoc/PyDoc/etc).
Do NOT narrate self-evident code or add line-by-line noise. Keep docstrings -
just stop over-commenting. Each comment terse: ~1 line, 2 only if asked.
Two of those lines are the simplicity discipline: the model thinks short instead of exploring aloud, and after the code is written it makes one explicit pass asking whether the same thing can be done simpler.
When to use
| Situation | Suggested invocation |
|---|---|
| See what is wired where, change nothing | /brewtools:think-short-setup status |
| Long automated runs where preamble accumulates across many subagent turns | /brewtools:think-short-setup install project |
| Consistent brevity across all projects on this machine | /brewtools:think-short-setup install global |
| Pick up a new directive text after a brewtools update | /brewtools:think-short-setup upgrade |
Status says injects=unknown — the installed copy is older than the --check diagnostic | /brewtools:think-short-setup upgrade |
| Pause terseness for a few sessions without deleting anything | /brewtools:think-short-setup disable |
| Turn it back on | /brewtools:think-short-setup enable |
| Unwire the hooks, keep the tmp markers | /brewtools:think-short-setup uninstall |
| Delete every file and every marker this skill ever wrote | /brewtools:think-short-setup purge |
| Output-heavy sessions where you want periodic reinforcement, not constant injection | Install project-scope — counter hook fires every 10 turns, not every turn |
Examples
Install for the current project:
/brewtools:think-short-setup make responses shorter, install in this project
Install globally (all projects on this machine):
/brewtools:think-short-setup install global
Pause it without deleting anything:
/brewtools:think-short-setup disable
Every mode starts with the same status block, and the skill calls AskUserQuestion to confirm scope (Project vs. Global) before writing any files. With no arguments at all it defaults to status when something is installed and install when nothing is.
Workflow
- Status first, always
Every mode opens with the same status block: how many of the 3 hook scripts are present per scope, how many
settings.jsonentries reference them, whether the prompt file isenabled,disabledornone, and — via—checkon the installed subagent hook — whether subagent injection actually fires (injects). Half-installed states are reported as such, never as installed. - Mode read from free text
The argument is a free-text description or one of
status,install,upgrade,enable,disable,uninstall,purge— RU triggers included. Ambiguity between an install and a removal verb raisesAskUserQuestioninstead of a guess. - Scope confirmation (AskUserQuestion)
The skill asks: Project (writes to
.claude/hooks/+.claude/settings.json) or Global (writes to~/.claude/hooks/+~/.claude/settings.json). No files are written until you answer. - Hook files copied to target directory
Four files are copied: three hook scripts (
think-short-session.mjs,think-short-prompt-counter.mjs,think-short-subagent.mjs) andthink-short-prompt.md(the directive body text each hook reads at runtime). For global scope, writes go via Bash (theWritetool is blocked on~/.claude/*in all permission modes). - Entries merged into settings.json
Three hook registrations are added to the matching
settings.json— one per hook file. Existing entries from other skills are preserved. - Hooks active from the next session start
Wiring changes (
install,upgrade,uninstall,purge) need a new Claude Code session — plainsettings.jsonhooks, so/reload-pluginsis not involved.enableanddisabletake effect immediately, because the hooks re-read the prompt file on every call.
Modes
| Mode | Effect | Hook files | settings.json | Prompt file | tmp markers |
|---|---|---|---|---|---|
status | report only | — | — | — | — |
install | wire the 3 hooks | copied | entries merged | copied | — |
upgrade | re-emit from the current plugin version | re-copied | entries re-merged | re-copied, disabled state kept | kept |
enable | .disabled -> think-short-prompt.md | kept | kept | renamed back | kept |
disable | prompt renamed away; hooks stay wired, become no-ops | kept | kept | renamed away | kept |
uninstall | unwire | deleted | entries stripped | deleted | kept |
purge | full wipe | deleted | entries stripped | deleted | deleted |
Re-install is a no-op. One target per run; “both scopes” is two runs.
Delegation
Warning
A big task handed to one agent = an agent gone for an hour. You cannot observe it, you cannot correct it, and it usually drifts off-target. Install or remove for one target is one bounded unit — 4 asset files plus one settings.json, well under 10 steps — so it is a single brewcode:hook-creator spawn. A wider request (“install here AND globally AND clean three other repos”) is split into N tasks, one per target, all spawned in a single message.
The spawn prompt carries six fields. A bare one-line task is never enough:
| Field | Content |
|---|---|
| GOAL | the user wants terse-mode hooks installed or removed for this target; pure file + settings wiring |
| ROLE | own the file copy/strip and the settings.json merge — never edit hook logic or unrelated settings keys |
| SCOPE | in — the 4 assets, the target .claude/ dir, its settings.json; global target is Bash-only (protected path) |
| CONTEXT | the plugin cache is already verified and every path resolved; nothing copied yet, no sibling writer |
| CONSUMER | the settings file is loaded by the next Claude Code session — a malformed merge breaks that session, not this one |
| DONE | which hooks were installed or removed, plus the exact settings.json path touched |
That CONSUMER line is the reason the agent must report the exact path: the failure surfaces one session later, so it has to be checkable now.
How it works
Three hooks are installed, each targeting a different injection point:
| Hook | Event | Behavior |
|---|---|---|
think-short-session.mjs | SessionStart | Injects the full directive; resets the per-session prompt counter in $TMPDIR; prunes stale counters from prior sessions |
think-short-prompt-counter.mjs | UserPromptSubmit | Injects the directive on every 10th user prompt (turns 10, 20, 30 — never turn 1, which is covered by SessionStart) |
think-short-subagent.mjs | SubagentStart | Injects the full directive into every spawned subagent via additionalContext |
The counter hook keeps injection periodic, not per-turn. Turns 2–9 run without re-injection; at turn 10 the hook fires again to reinforce brevity after context drift.
Installation targets
| Scope | Hook files written to | Settings file updated |
|---|---|---|
| Project | .claude/hooks/ | .claude/settings.json |
| Global | ~/.claude/hooks/ | ~/.claude/settings.json (via Bash) |
Global installs use the Bash tool for all file operations because ~/.claude/* is a protected path — the Write and Edit tools are blocked there in every permission mode, including bypassPermissions.
Subagent hook injection
think-short-subagent.mjs fires on SubagentStart and delivers the directive via hookSpecificOutput.additionalContext. That channel accumulates across hooks — every registered SubagentStart hook’s context is appended and delivered into the subagent’s own message list, so any number of injectors coexist with no clobbering and nothing to yield to.
Note
This replaces an earlier PreToolUse:Task|Agent design that rewrote the spawn prompt via updatedInput. That channel is single-writer/last-wins — every PreToolUse hook on the same event receives the same original input, and the runner keeps only the last hook’s updatedInput, so two hooks editing it would clobber each other. SubagentStart + additionalContext has no such conflict.
status runs node <that scope's hooks>/think-short-subagent.mjs --check "$PWD" and adds one field:
| Field | Value | Meaning |
|---|---|---|
injects | yes | subagents really receive the directive |
no | wired and enabled, but the prompt file is missing or empty — a broken install | |
n/a | no subagent hook installed in that scope | |
unknown | the installed copy predates the --check diagnostic — run upgrade on that scope |
injects measures the subagent hook only. SessionStart and the every-10th-prompt injection are separate paths.
Example status output on a machine whose global install predates the diagnostic:
project: hook_files=0/3 settings_refs=0/3 prompt=none injects=n/a
global: hook_files=3/3 settings_refs=3/3 prompt=enabled injects=unknown
The 3/3 3/3 enabled line used to be the whole report, and it read as a healthy install. injects=unknown is the part that says otherwise.
Version and ownership
install/upgrade stamp all four copied files with generated_by: "brewtools:think-short-setup". Each of the three .mjs hooks carries // brewcode-meta: version=X.Y.Z generated_by=brewtools:think-short-setup on line 2; think-short-prompt.md carries <!-- think-short brewcode-meta: version=X.Y.Z generated_by=brewtools:think-short-setup --> on line 1. /brewcode:setup-status reads these lines to tell an install running an older brewtools apart from one on the current version — upgrade is what refreshes them.
Removal
uninstall deletes all four copied files (the three hook scripts and think-short-prompt.md) and strips the corresponding three entries from settings.json, keeping the tmp markers. purge does the same and deletes the marker directory too. Neither touches entries added by other skills or plugins.
Manager Setup
Installs a HARD wall that blocks main-session edits and forces subagent delegation. Pairs with think-short for focused, low-noise automated runs.
Setup Status
Read-only dashboard across every -setup skill — installed, stale or missing, with the hand-run command for each.
Brewtools overview
All brewtools skills and agents in one place.
GitHub source
Hook scripts and install/remove logic.
Updating plugins
/brewtools:plugin-update to check and update the brewcode plugin suite in one command.
See the FAQ for details.