Files
dotfiles/bin/tarbuckle
T
David F GliddenandClaude Opus 5 4b3e08dc7f [FIX] zsh ate the question mark before the wrapper ran
'tarbuckle opinion?' failed at '(eval):1: no matches found' — zsh expands ?, * and [ as
globs before the script is reached, and asking him a question is the natural use of the
one surface built for questions.

Three ways past it, and the wrapper's help now names all three in order of least fuss:
drop the ?, quote the phrase, or the noglob alias now in shell/.zshrc. ⚠ The alias is
listed LAST and with its limit stated, because it only helps if the calling shell is
interactive — .zshrc is not read otherwise — and that is exactly the kind of fix that
looks total and silently is not.

noglob for one command rather than 'unsetopt nomatch', which would change how every
command in the shell behaves to fix one of them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J6hZXNYSxEfZseBGTni4sf
2026-08-25 18:39:14 +02:00

44 lines
2.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Tarbuckle — the short way in. v2 §9: named invocation, mute, off.
#
# ! tarbuckle call him by name; he answers at length
# ! tarbuckle what now ask him something
# ! tarbuckle "opinion?" a QUESTION MARK must be quoted, or dropped
#
# ⚠ zsh expands `?`, `*` and `[` as globs before this script is ever reached, so an
# unquoted `tarbuckle opinion?` dies at "no matches found" in the shell. Three ways
# past it, in order of least fuss: drop the `?`, quote the phrase, or rely on the
# `alias tarbuckle='noglob tarbuckle'` in shell/.zshrc — which only helps if the
# calling shell is interactive, since that is the only kind that reads .zshrc.
# ! tarbuckle mute silence the utterances; he stays in the room
# ! tarbuckle off remove him entirely
# ! tarbuckle on bring him back
# ! tarbuckle status what he is doing, and when he might speak next
#
# ⚠ Run this YOURSELF. A fool relayed by the executor is the executor's paraphrase of
# a fool. The `!` prefix in Claude Code runs it in the session so the output is his.
set -euo pipefail
S="$HOME/dotfiles/scripts"
M="$HOME/.claude/state/tarbuckle-mute"
mkdir -p "$(dirname "$M")"
case "${1-}" in
mute) echo mute > "$M"; echo "muted — he stays in the room and says nothing. Never a fault." ;;
off) echo off > "$M"; echo "off — removed from the status line too." ;;
on|unmute) rm -f "$M"; echo "back." ;;
status)
st=$(cat "$M" 2>/dev/null || echo "listening")
echo "state: $st"
if [ -f "$HOME/.claude/state/tarbuckle-last-tick" ]; then
python3 - "$HOME/.claude/state/tarbuckle-last-tick" <<'PY'
import sys, time
t = int(open(sys.argv[1]).read())
print("next tick:", time.strftime('%H:%M', time.localtime(t + 20*60)), "(27% he speaks)")
PY
fi
r="$HOME/.claude/state/tarbuckle-rejects.jsonl"
[ -f "$r" ] && echo "silences: $(wc -l < "$r" | tr -d ' ') logged (net rejections + timeouts)" || true
;;
--help|-h) sed -n '2,22p' "$0" | sed 's/^# \{0,1\}//' ;;
*) exec python3 "$S/tarbuckle-invoke.py" "$@" ;;
esac