A month ago I deleted my 17,000-line research app and replaced it with a Claude Code plugin (the writeup). The bet was that four slash commands and a nightly Slack digest cover everything the web app did. The bet mostly held, and two gaps showed up by week two.
Papers longer than about fifteen pages sat in my inbox unread. And the digest was a one-way broadcast: when Slack showed me something interesting at 7am, there was nothing to do about it until I was back at a desk.
v2.1 shipped on July 9 to close both: 820 lines across 24 files, built from a written plan that subagents on cheaper models executed task by task while a larger model reviewed each diff. The four commands are now six. The diagram above shows where the new pieces plug in.
A podcast instead of a backlog
/scribe:episode turns the day's top paper into a two-host audio episode,
NotebookLM-style: a skeptic and an expert arguing through the paper for 40 to
60 turns. The script is JSONL, one turn per line, and every factual claim
carries an inline citation like [§4.2] pointing at the section of the paper
it came from. If the model can't cite it, the rule is it doesn't get said. The
markers are stripped before audio and kept in the show notes.
Everything after the script is a 183-line Python file with no model in it:
edge-tts renders each turn (free Microsoft neural voices, one per host),
ffmpeg concatenates with 300ms gaps and normalizes loudness, feedgen
regenerates an RSS feed. The feed sits behind an unguessable URL path because
podcast apps can't do authentication. Subscribe once in any podcast app and a
12 to 15 minute episode about yesterday's best paper shows up like any other
show.
The quality lives entirely in the dialogue prompt. The TTS and stitching were an evening; I expect to be iterating on the script instructions for months.
Replying to the digest
A 158-line daemon (bridge.py, a systemd unit on the same Proxmox LXC that
runs the nightly scan) long-polls Telegram, so there's no public endpoint to
secure. Three commands do the things I kept wishing I could do from my phone:
queue 2marks paper #2 for my next/scribe:learnmute diffusion modelsappends to the avoid-listepisode 3makes tonight's podcast deep-dive paper #3
Anything else is treated as a question. The bridge fetches the referenced
paper's sections and spawns a headless claude -p run to answer, grounded in
the actual text. Ask "why is #2 relevant to me?" and the reply quotes the
paper's sections, not a paraphrase of the abstract. Those question runs and
the nightly dialogue script are the only model calls in the whole v2.1
surface; the bill scales with the two calls a day that actually require
judgment.
The original spec called for a Haiku call to classify each inbound message as command, question, or feedback. I replaced it with a regex over three verbs. It covers the whole verb set, costs nothing, and the classifier can come back when the verbs outgrow a regex.
Two things bit me here. First, my reference regex matched digits inside arXiv
IDs: "why is 2606.11111 relevant" matched 06 and silently grounded the
answer in row 6 of the digest. A lookahead excluding dots fixed it, and that
case is now in the test file. Second, the headless claude -p call inside
the bridge consumes paper text fetched from the internet, which makes it a
prompt-injection target: a crafted abstract could tell the model to do
something with tools. I assumed --disallowedTools "*" would lock it down.
Tested it; the model happily ran Bash anyway. Only an explicit list of tool
names actually denies them. The Q&A run now gets every tool banned by name,
and the bot answers nobody outside an allowlist of Telegram user IDs.
Interest packs
interests.md turned out to be the highest-leverage file in the system, so
v2.1 makes it shareable. A pack is one markdown file with the same schema plus
frontmatter; /scribe:interests install agentic-ai merges one into your
active interests with semantic dedupe. Five seed packs ship in the repo
(ml-systems, agentic-ai, security, distributed-systems, quant), and
CONTRIBUTING.md exists mostly to invite pack PRs. It's the cheapest feature in
the release and probably the one most useful to anyone who isn't me.
What deploying it broke
The deploy step in deploy.sh ran pip3 install -r requirements.txt with
errors suppressed, because a notification failure should never block a scan.
Debian 12 refuses system-wide pip installs (PEP 668), so the install failed
silently and the first episode run would have crashed at import. The fix falls
back to pip3 install --user --break-system-packages. ffmpeg also wasn't on
the container; that one was just an apt install, but nothing in the pipeline
would have told me before the 06:15 cron did.
The quieter cost: v2 shipped with a stdlib-only guarantee, no installs anywhere. v2.1 ends that. The core scan path is still pure stdlib, but the podcast and bridge pull in five pip packages and a systemd unit. That's a real step back toward the machinery I deleted in June, and I took it with open eyes, because "listen to papers while walking the dog" was worth a requirements.txt. The line I'm holding is that judgment stays in prompts, plumbing stays in Python, and state stays in files a human can read.
Trying it
The repo is at github.com/mukitmomin/scribe:
/plugin marketplace add mukitmomin/scribe
/plugin install scribe@scribe
# write ~/.scribe/interests.md, or: /scribe:interests install ml-systems
/scribe:scan
The podcast and bridge are opt-in extras that need requirements.txt and
ffmpeg on whatever box runs your cron; the README covers both, and
docs/superpowers/plans/ has the implementation plan the subagents executed.
A month ago I traded features for a tool I actually use. This month I traded
a little purity for a tool that talks back.