SuperAPI AI Directory

think-short-setup

Office & productivity

View repository

Updated 10-15 20:09

About this skill

Think-Short

Installer/configurator skill. It wires three self-contained hooks (SessionStart, UserPromptSubmit, SubagentStart) that inject a terse-output prompt — or configures/removes them. No profiles and no project-level config: the only state is the copied think-short-prompt.md plus an ephemeral per-session counter in the OS temp dir (os.tmpdir()/brewtools-think-short/<session_id>.think-short-counter), auto-pruned. The hooks own all runtime behavior. This skill only decides mode and project vs global, then delegates the file work to the brewcode:hook-creator agent following the runbook.

What the hooks do (informational — skill does NOT implement)

Hook Behavior
SessionStart inject the full terse prompt + reset the per-session counter
UserPromptSubmit inject the full prompt every 10th user prompt (10/20/30…, not the 1st)
SubagentStart inject the full terse prompt into spawned subagents (additionalContext accumulates across hooks — no coexistence/yield logic needed)

All three read think-short-prompt.md from their OWN directory and emit {} when it cannot be read. There is no enabled flag and no config file to add one to — so disable renames the copied prompt to think-short-prompt.md.disabled: the hooks stay wired, find no prompt, and every event becomes a genuine no-op. enable renames it back. This is the hooks' existing fail-open path, not new machinery.

think-short-prompt.md is copied into the target at install — an existing install keeps its old text forever. After the prompt changes (incl. a brewtools update), run upgrade on that target to pick it up.

Prompt contract

Position 1 of $ARGUMENTS is a free-form prompt (RU/EN) — modes and the project/global target are optional and may follow in any order. Nobody types keys: resolve mode + target FROM the prompt.

  1. Strip nothing beyond mode/target words themselves — no other flags exist. An explicit mode token anywhere wins outright, no scoring.
  2. Else score modes by distinct whole-word keyword hits (Step 2 table below). Highest unique score wins. Tie between install and a removal verb -> AskUserQuestion; never guess destructive. All zero -> the documented default: status if anything is installed, else install.
  3. Empty arguments -> the same documented default; Step 1's STATUS FIRST always runs before anything else, so the answer is never guessed blind.
  4. Outcome-changing ambiguity (target unspecified, mode ambiguous between install/removal) -> ONE AskUserQuestion BEFORE any work — this is already Steps 2-3's own gate.
  5. Prose that is not a mode/target keyword is still input: extract intent from it (e.g. "pick up new prompt" -> upgrade), never treat the first word as a positional id.

Then print this block ONCE, before the first action:

PLAN — brewtools:think-short-setup
INPUT:  <arguments verbatim, or "(empty)">
MODE:   <resolved> — <explicit | matched keyword: X | default>
SCOPE:  <resolved target: project|global, resolved paths>
DO:     <2-5 imperative bullets>
RESULT: <what the user ends up holding>

Labels are literal; values follow the conversation language. status (read-only) prints it at the end of Step 1, right before its state table. Every mutating mode prints it in Step 4, once target is resolved, before the hook-creator delegation.

BT_ROOT Resolver (use in EVERY bash block)

The plugin root is resolved from the skill's OWN directory (the CLAUDE_SKILL_DIR prompt substitution), never from CLAUDE_PLUGIN_ROOT -- that env var is not exported to a skill's Bash tool:

SD="${CLAUDE_SKILL_DIR}"
if [ -n "$SD" ] && [ -f "$SD/../../.claude-plugin/plugin.json" ]; then BT_ROOT=$(cd "$SD/../.." && pwd); else BT_ROOT=$(ls -d ~/.claude/plugins/cache/claude-brewcode/brewtools/*/ 2>/dev/null | sort -V | tail -1 | sed 's:/*$::'); fi
[ -n "$BT_ROOT" ] || { echo "ERROR: cannot locate brewtools plugin root -- install/update brewtools first."; exit 1; }
test -d "$BT_ROOT/skills/think-short-setup/assets" || { echo "❌ BT_ROOT invalid: $BT_ROOT"; exit 1; }

Asset paths (all under $BT_ROOT/skills/think-short-setup/assets/):

  • INSTALL.md — the runbook: install project/global, upgrade, disable/enable, uninstall, purge. Single source of truth — follow it, never re-derive its commands here.
  • think-short-session.mjs, think-short-prompt-counter.mjs, think-short-subagent.mjs, think-short-prompt.md — the hook files that travel together

Never use Write/Edit on ~/.claude/* — protected path, blocked in ALL modes. Global operations run through the Bash tool only (cp + node + mv + rm). The hook-creator agent handles this per the runbook.


Step 1 — STATUS FIRST, always

Run this before anything else, in EVERY mode. Never install, re-install or remove blind.

EXECUTE using Bash tool:

SD="${CLAUDE_SKILL_DIR}"
if [ -n "$SD" ] && [ -f "$SD/../../.claude-plugin/plugin.json" ]; then BT_ROOT=$(cd "$SD/../.." && pwd); else BT_ROOT=$(ls -d ~/.claude/plugins/cache/claude-brewcode/brewtools/*/ 2>/dev/null | sort -V | tail -1 | sed 's:/*$::'); fi
[ -n "$BT_ROOT" ] || { echo "ERROR: cannot locate brewtools plugin root -- install/update brewtools first."; exit 1; }
A="$BT_ROOT/skills/think-short-setup/assets"
for f in INSTALL.md think-short-session.mjs think-short-prompt-counter.mjs think-short-subagent.mjs think-short-prompt.md; do
  test -f "$A/$f" || { echo "❌ FAILED — assets incomplete under BT_ROOT=$BT_ROOT (missing $f)"; exit 1; }
done
echo "ASSETS_DIR=$A"
echo "RUNBOOK=$A/INSTALL.md"
for S in "$PWD/.claude:project" "$HOME/.claude:global"; do
  D="${S%%:*}"; N="${S##*:}"
  F=0
  for f in think-short-session.mjs think-short-prompt-counter.mjs think-short-subagent.mjs; do
    [ -f "$D/hooks/$f" ] && F=$((F+1))
  done
  W=$({ grep -o 'think-short-[a-z-]*\.mjs' "$D/settings.json" 2>/dev/null || true; } | sort -u | wc -l | tr -d ' '); W=${W:-0}
  P=none
  [ -f "$D/hooks/think-short-prompt.md.disabled" ] && P=disabled
  [ -f "$D/hooks/think-short-prompt.md" ] && P=enabled
  I=n/a
  if [ -f "$D/hooks/think-short-subagent.mjs" ]; then
    C=$(node "$D/hooks/think-short-subagent.mjs" --check "$PWD" </dev/null 2>/dev/null || true)
    case "$C" in *'"injects":true'*) I=yes ;; *'"injects":false'*) I=no ;; *) I=unknown ;; esac
  fi
  echo "$N: hook_files=$F/3 settings_refs=$W/3 prompt=$P injects=$I"
done
M="${TMPDIR:-/tmp}/brewtools-think-short"
echo "markers=$({ ls "$M" 2>/dev/null || true; } | wc -l | tr -d ' ') dir=$M"
echo "✅ status"

STOP if ❌ — plugin cache incomplete; reinstall/update brewtools first.

Field meanings — do not paraphrase them into something stronger:

Field Value
hook_files how many of the 3 scripts are present in that scope's hooks/; 3/3 = complete, 1/3-2/3 = half-installed → repair
settings_refs count of DISTINCT think-short-*.mjs scripts referenced in that scope's settings.json; 0/3 = not wired, 3/3 = fully wired
prompt enabled = think-short-prompt.md present, disabled = only the .disabled rename is there, none = neither (the hooks would no-op even though they are wired)
injects node <that scope's copy>/think-short-subagent.mjs --check "$PWD" → injects. yes = the prompt file is present and readable, so the SubagentStart hook really delivers it. no = wired but the prompt is missing/empty — a broken install, not a yield: additionalContext accumulates across hooks, so nothing here ever loses to another hook. n/a = no subagent hook in that scope. unknown = the installed copy answered nothing parseable — it predates --check, so run upgrade on that scope
markers number of tmp counter files; state only, never affects behavior

settings_refs is a textual count, not a JSON validation — it does not prove the entries are well-formed or attached to the right events.

injects covers ONLY think-short-subagent.mjs (the subagent injection). SessionStart and the every-10th-prompt injection are separate paths and are not measured by it — injects=no means subagents get nothing while the main session still gets the directive.

Read the output into a state table. If MODE resolves to status, print the Prompt contract PLAN block now, right before this table. Then PRINT the table to the user:

Scope Hook files settings.json wired Prompt Injects Effective

Effective = hook_files=3/3 settings_refs=3/3 prompt=enabled injects=yes. Anything else is NOT effective — say so plainly instead of reporting a half-state as installed. In particular: prompt=enabled injects=no means the prompt file is empty or corrupt — fully wired but injecting nothing into subagents. Offer upgrade to re-copy it; do not report it as installed.

Early exit

If it is already installed the way the user could want it and the intent is not explicit (no argument, or vague like "terse mode"), PRINT the status, list the operations available (upgrade, enable, disable, uninstall, purge, install for the other scope) and STOP. Do not re-install, do not ask a chain of questions.

Step 2 — Decide MODE

Read $ARGUMENTS. Default when there are NO arguments at all = status if anything is installed, install if nothing is.

Mode EN keywords RU keywords Mutates?
status (no args + installed), status status, check what is set no
install (no args + nothing installed), install, set up set up, install yes
upgrade upgrade, update, refresh, after plugin update update, re-set, pick up new prompt, after plugin update yes
enable enable turn back on, restore yes
disable disable turn off, disable, pause yes
uninstall uninstall remove, take down, delete hooks yes
purge purge, wipe, remove everything clean out everything, delete completely, wipe yes, destructive

Ambiguous between install and a removal verb → AskUserQuestion. Use AskUserQuestion ONLY for genuinely destructive ambiguity, never to guess a mode.

Step 3 — Decide TARGET (project | global)

  • Explicit global → global: global, глобально, for all projects, всех проектах.
  • Explicit project → project: project, this repo, локально, здесь, этот проект.
  • NOT specified → AskUserQuestion: "think-short for this Project or Globally?" (options: Project / Global). Do not auto-guess.
  • Settled by the status table when only ONE scope is installed and the mode is not install — do not ask then.

For uninstall/purge with an unspecified target, ask the same Project/Global question (or offer to clean both if the user says "everywhere").

Step 4 — State the plan, then delegate

For every mutating mode, print the Prompt contract PLAN block now — target is resolved (Step 3) — before the delegation below. Tell the user plainly what will happen, e.g.:

Installing think-short hooks (SessionStart + UserPromptSubmit + SubagentStart) into <repo>/.claude/ and merging <repo>/.claude/settings.json.

For uninstall/purge list exactly which files are deleted and confirm once.

Delegation

A big task handed to one agent = an agent gone for an hour: you cannot observe it, cannot correct it, and it usually drifts off-target. One mode for ONE target is ONE bounded unit (4 asset files + one settings.json, well under 10 steps) — a single hook-creator spawn. A wider request ("install here AND globally AND clean three other repos") MUST be split into N tasks, one per target, all spawned in ONE message.

Every spawn prompt MUST carry:

Field Content
GOAL the overall task and why it exists — the point beyond the file edit
ROLE what this agent owns; what it must NOT touch
SCOPE exact paths/commands in bounds + explicit out-of-bounds
CONTEXT what is already done, by whom, what runs in parallel — trimmed to what THIS agent needs
CONSUMER who or what uses the result next, and the shape it must fit
DONE acceptance criteria + the exact report shape you want back

A bare one-line task is never enough. The prompt below is that shape.

The runbook path only survives if it reaches the SHELL. RUNBOOK written as prose in the prompt is just text — the runbook's blocks derive their source dir from $RUNBOOK, so an un-exported value copies from nowhere. The spawn prompt below therefore carries the literal export line the agent must run FIRST, in the same Bash invocation as every runbook block.

Spawn the agent (substitute MODE, TARGET, RUNBOOK, ASSETS_DIR from Steps 1-3 — into BOTH the CONTEXT block and the export line):

Task(subagent_type="brewcode:hook-creator", prompt="
GOAL: the user wants think-short terse-mode hooks MODE-ed for TARGET. Three hooks
(SessionStart, UserPromptSubmit, SubagentStart) inject a terse-output prompt; runtime
behavior lives entirely in the hook files, so this task is pure file + settings wiring.
ROLE: you own the file copy/rename/strip and the settings.json merge. Do NOT edit hook
logic, do NOT touch unrelated hooks or settings keys, do NOT act on the other target.
SCOPE: in — the 4 assets under ASSETS_DIR, the target .claude/ dir, its settings.json.
Out — everything else. Project target: Write/Edit settings.json freely. Global target
(~/.claude/*): BASH ONLY (cp + node merge + mv + rm), never Write/Edit — protected path.
CONTEXT:
  Step 1 already verified the plugin cache and resolved every path below; nothing has been
  copied or merged yet, and no sibling agent is running — you are the only writer.
  MODE = MODE (install|upgrade|enable|disable|uninstall|purge)
  TARGET = TARGET (project|global)
  RUNBOOK = RUNBOOK (absolute path to assets/INSTALL.md)
  ASSETS_DIR = ASSETS_DIR (absolute path to the assets source dir — copy the 4 hook files FROM here)
  MANDATORY FIRST BASH COMMAND — the runbook's blocks read this from the ENVIRONMENT,
  not from this prompt. Run this VERBATIM as the first line of EVERY Bash call that executes
  a runbook block (a new Bash call does NOT inherit exports from the previous one):
    export RUNBOOK='RUNBOOK'
  Then verify before writing anything:
    echo \"RUNBOOK=\$RUNBOOK\"
  Follow the runbook at RUNBOOK exactly — it self-locates its source via SRC=\$(dirname \"\$RUNBOOK\").
  Sections map 1:1 to MODE: 'PROJECT target'/'GLOBAL target' for install, 'UPGRADE',
  'DISABLE / ENABLE', 'UNINSTALL', 'PURGE'.
  Merge = append + dedupe by think-short-*.mjs script path (idempotent).
  Upgrade = re-copy the 4 files + re-merge, PRESERVING a disabled prompt as .disabled.
  Disable/enable = rename think-short-prompt.md <-> think-short-prompt.md.disabled ONLY;
  never touch settings.json or the 3 scripts.
  Uninstall = strip entries by the 3 basenames, drop empty event arrays, delete the 4 files,
  KEEP the tmp markers. Purge = uninstall + delete the tmp marker dir.
CONSUMER: Step 5 reports your result to the user; the settings.json you write is then loaded
  by the NEXT Claude Code session, so a malformed merge breaks that session instead of
  failing here — report the exact path you touched so it can be checked.
DONE: report which hooks were installed/removed/renamed, the exact settings.json path, and
  the final state of think-short-prompt.md (present | .disabled | absent).
")

Step 5 — Final status

Re-run the Step 1 status block and print the refreshed table, plus:

  • what changed (files, settings.json, prompt state),
  • a NEW session is required for hook WIRING changes (install / upgrade / uninstall / purge) — /reload-plugins is NOT needed, these are plain settings.json hooks; SessionStart fires on the next claude start / --resume;
  • enable/disable take effect immediately — the hooks re-read the prompt file on every call, no restart;
  • for upgrade: that the prompt text is what actually changed, since the 3 scripts are usually identical between versions,
  • injects for the touched scope — if it is still no, say plainly that the wiring succeeded but the prompt file is missing/empty, and offer upgrade.

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 think-short-prompt.md → .disabled; 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" is two runs.

Guards

Condition Response
BT_ROOT resolves but $BT_ROOT/skills/think-short-setup/assets missing ERROR: think-short: assets not found under $BT_ROOT — plugin cache incomplete. STOP.
Neither the skill dir nor any cached plugin dir yields .claude-plugin/plugin.json ERROR: think-short: cannot locate plugin root — install/update brewtools first. STOP.
Status shows installed + vague intent Print status, list available operations, STOP. Do not re-install.
Target unspecified AskUserQuestion: Project / Global. Never guess.
Mode ambiguous between install and removal AskUserQuestion. Never guess a destructive mode.
Global target Hook-creator MUST use Bash only (cp/node/mv/rm) — ~/.claude/* is protected.
enable asked for but no .disabled file exists Not disabled — say so and stop. If prompt=none the install is BROKEN, not disabled: offer upgrade to re-copy the prompt.
disable asked for but hook_files is not 3/3 Nothing effective to disable; report the half-state and offer upgrade or uninstall.
Status shows injects=no Wired and enabled, but the prompt file is missing/empty (broken install) — subagents get nothing. Offer upgrade for that scope.
Status shows injects=unknown The installed think-short-subagent.mjs is older than the --check diagnostic. Offer upgrade for that scope, then re-run status.
User expects disable to stop the hooks from RUNNING It does not: the 3 processes still spawn per event and exit with {}. It removes the injection, not the ~50 ms. Say this; offer uninstall if the cost is the complaint.
uninstall/purge requested Restate exactly what gets deleted, confirm once, then delegate.
settings.json exists but is malformed JSON Report it: every runbook block ABORTS rather than overwriting it blind, and the rm is skipped too so files and settings stay consistent. Offer to fix.

Smoke Test

Verify the 5 assets exist and the scripts parse before delegating.

EXECUTE using Bash tool:

SD="${CLAUDE_SKILL_DIR}"
if [ -n "$SD" ] && [ -f "$SD/../../.claude-plugin/plugin.json" ]; then BT_ROOT=$(cd "$SD/../.." && pwd); else BT_ROOT=$(ls -d ~/.claude/plugins/cache/claude-brewcode/brewtools/*/ 2>/dev/null | sort -V | tail -1 | sed 's:/*$::'); fi
[ -n "$BT_ROOT" ] || { echo "ERROR: cannot locate brewtools plugin root -- install/update brewtools first."; exit 1; }
A="$BT_ROOT/skills/think-short-setup/assets"
test -d "$A" || { echo "❌ assets dir missing"; exit 1; }
for f in think-short-session.mjs think-short-prompt-counter.mjs think-short-subagent.mjs think-short-prompt.md INSTALL.md; do
  test -f "$A/$f" || { echo "❌ missing $f"; exit 1; }
done
test -s "$A/think-short-prompt.md" || { echo "❌ smoke FAILED — think-short-prompt.md is empty (all 3 hooks would no-op)"; exit 1; }
node --check "$A/think-short-session.mjs" && \
node --check "$A/think-short-prompt-counter.mjs" && \
node --check "$A/think-short-subagent.mjs" && \
echo "✅ smoke" || echo "❌ smoke FAILED"

STOP if ❌ — do NOT delegate; reinstall/update brewtools first.

node --check proves the files parse, nothing more. The full behavioral suite is tests/run.sh in the skill dir and is NOT run here.