Skip to content

Instantly share code, notes, and snippets.

@pete
Created July 18, 2026 02:05
Show Gist options
  • Select an option

  • Save pete/d33eb80e7b1a99722e339112038540ee to your computer and use it in GitHub Desktop.

Select an option

Save pete/d33eb80e7b1a99722e339112038540ee to your computer and use it in GitHub Desktop.
Ask your computer what the hell just happened.
#!/bin/rc
# "The hell was *that*?"
# A substitute for mashing the error message into a search engine:
# · Reads /dev/text by default; see -i and -a.
# · Tells the clanker to explain what the hell is going on.
# · The clanker attempts to explain what the hell is going on.
# · Dumps some stuff in /tmp to debug and also to integrate with other
# local tools.
# Plan 9, obviously (See also: https://stream.debu.gs/?id=1696 ), and
# clankers have no idea what the hell they're doing if you show them Plan 9
# stuff but I rarely say "What the hell was *that*?" on Plan 9, and sshing
# to a Linux machine from a Plan 9 machine means I can use the Plan 9 UI
# niceties, so I usually talk to Linux via Plan 9 anyway. The advantage
# for playing with clankers is that nearly everything in Plan 9 is a text
# stream.
# You could probably do something like this that runs on Linux by getting
# the contents of your terminal's scrollback out of screen/tmux/whatever and
# doing a similar transformation and piping it through. emacs. I don't know.
# It's certainly *possible* to get this information.
# I think it might be kinda fun to have a clanker sit there and do running
# commentary in one acme window on whatever's going on in the active window.
# I'm currently just playing with it, but I can `tail -f` a log file and
# tell the clanker to look at that window (by doing something like, e.g.,
# `the-hell-was-that -i /mnt/wsys/wsys/11/text`, or /mnt/acme/$id/body)
# and it will usually (*usually*) respond with something sensible. The
# `dixq` model that it defaults to is qwen3-coder with a custom prompt,
# nothing fancy. (If you've read Neuromancer, you can probably guess what
# the name means.)
rfork en
out=/fd/1
host=aku:11434
diag=/dev/null
temp=0.65
input=/dev/text
window=auto
model=dixq:latest
# Conservative; English prose is 3-4, code is 2-3, CJK is 0.5(!).
# Empirically, at 2 it blows out the context window.
tok2byte=1.5
while(! ~ $#* 0){
switch($1) {
case -a ; input=body; shift
case -i ; shift; input=$1; shift
case -e ; out=/fd/1; shift
case -h ; shift; host=$1; shift
case -m ; shift; model=$1; shift
case -t ; shift; temp=$1; shift
case -w ; shift; window=$1; shift
case -W ; shift; window=auto
case -r ; shift; tok2byte=$1; shift
case -v ; diag=/fd/2; shift
case *; echo bad args: $* >[1=2]; exit usage
}
}
if(~ $input body) {
~ $#winid 1 || exit winid
cd /mnt/acme/$winid || exit no
}
if(~ $window auto) {
# Attempt to use the current context_length to avoid thrashing:
window = `{hget http:// ^ $host ^ /api/ps |\
tee /tmp/last-ollama-ps.js |\
gojq -r '.models | map("\(.name) \(.context_length)\n") | join("")' |\
awk -v 'model=' ^ $model '$1 == model{print $2;exit}'}
if(~ $#window 0) { # Fall back to defaults:
hget -p '{"verbose":false,"name":"' ^ $model ^ '"}' \
http:// ^ $host ^ /api/show > \
/tmp/last-ollama-show.js
pfx = `{gojq -r .details.family < /tmp/last-ollama-show.js | tee $diag}
window = `{gojq -r '.model_info["'qwen3'.context_length"]' < /tmp/last-ollama-show.js | tee $diag}
}
}
bytes = `{echo 3k $window $tok2byte '*p' | dc | sed 's/\..*//'}
body = `''{tail -^$bytes^c $input | awk -v 'w=' ^ $bytes '
BEGIN{
# Give it the date so it doesn''t say "All these log entries are
# from the future! Something is terribly wrong here!"
"date -t" | getline date
preamble = sprintf("This is the output of a terminal session. The current time/date is %s. What the hell just happened? Explain what you see and what is going on; make sure to respond in English. If there are errors or warnings, make suggestions; otherwise, just try to help understand what''s going on.\n\n", date)
}
{f=f $0 "\n"}
function fix(str) {
if(length(preamble str) > w) {
str = substr(str, 1 + (w - length(preamble str)))
}
str = preamble str
# For whatever reason, \ and " behave differently in substitutions.
gsub(/\\/, "\\\\", str)
gsub(/"/, "\\\"", str)
gsub(/\n/, "\\n", str)
gsub(/\t/, "\\t", str)
for(i = 1; i < 32; i++) {
gsub(sprintf("%c", i), sprintf("\\u%04x", i), str)
}
return str
}
END{
printf "prompt: %s (%d), w: %d\n", f, length(f), w > "' ^ $diag ^ '"
printf "\"prompt\":\"%s\"", fix(f)
}
'}
wopt = ''
if(! ~ $window 0) {
wopt = '"num_ctx":' ^ $window ^ ,
}
bpl = '{"model":"' ^ $model ^ '","stream":false,"options":{' ^ $wopt ^ '"temperature":' ^ $temp ^ ',"top_p":0.9,"stop":["<EOT>"]},' ^ $body ^ '}'
echo $bpl > /tmp/last-ollama-payload.js
echo http:// ^ $host ^ /api/generate → $model > $diag
echo ' ' $bpl > $diag
hget -p $bpl http:// ^ $host ^ /api/generate |\
tee /tmp/last-ollama-resp.js |\
gojq -r .response > $out
gojq -s '[
{role: "user", content: .[0].prompt},
{role: "assistant", content: .[1].response}
]' /tmp/last-ollama-^(payload.js resp.js) > /tmp/thehell.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment