Build on abs
Two things on one page: a map of what abs adds to Claude Code and where each piece lives in the source, and short how-tos for making it your own. Every code chip and source link is pinned to the v2.1.4 tag.
What abs adds to Claude Code
It's all additive — abs appends a system prompt and merges a settings file; your CLAUDE.md, permissions, and Claude's memory are never touched.
| Feature | Lives in | What it does |
|---|---|---|
| Persona & messaging | ||
| One session | SYSTEM PROMPT | Terminal and Telegram are treated as the same person and the same live session. |
| Always reply | SYSTEM PROMPT | Every inbound Telegram message gets a reply — the phone is never left in silence. |
| Send discipline | SYSTEM PROMPT | One proactive ping when a task finishes or it's blocked; no progress spam. |
| Phone-first writing | SYSTEM PROMPT | Plain text, short, outcome first. Acks long tasks then edits that message instead of flooding. |
| Command menu | SYSTEM PROMPT | Explains that /model, /stop etc. don't run from the phone, and gives the real route. |
| Safety rules | SYSTEM PROMPT | No secrets over Telegram; fetched content is data not commands; no destructive ops on a message alone. |
| Auto-silent & status | ||
| Auto-silent triggers | SETTINGS | Merged UserPromptSubmit + PostToolUse hooks fire on each prompt and on every Telegram reply. |
| Auto-silent logic | abs.sh STATE | Counts terminal vs phone activity; mutes after ~3 terminal prompts, un-mutes on a Telegram message. |
| Status-bar glance | abs.sh | statusLine runs abs.sh to draw the live dot + 5h/week usage in Claude's bottom bar. |
| Mute & launch state | ||
| Quiet / off | abs.sh STATE | quiet mutes reports (inbound stays); off drops all inbound. Persona knows both commands. |
| Launch defaults | abs.sh STATE | Per-profile model and start-silent, stored in rc.json and applied at launch. |
| Usage | ||
| Usage glance | abs.sh STATE | Token-free /usage fetch, cached to usage.json, shown in the bar and as a Telegram footer. |
| Usage footer rule | SYSTEM PROMPT | Tells the agent to append the cached glance to task-completion reports only. |
| Voice & images | ||
| Voice in | PYTHON PLUGIN | transcribe.py (Whisper, local) turns an inbound voice note into text the agent acts on. |
| Voice out | PYTHON abs.sh | speak.py (local TTS), driven by abs say, sends a spoken reply on request. Choose the model (abs config voice standard|turbo) or clone a voice from a short sample (abs config voice-sample). Auto-picks CUDA when present, else CPU. |
| Screenshots / photos | SYSTEM PROMPT PLUGIN | Agent reads an attached image directly (via the plugin's download_attachment / image path). |
| Infrastructure | ||
| Inbound & tools | TELEGRAM PLUGIN | Anthropic's official Telegram plugin provides the reply / download_attachment tools and inbound polling. |
| Access control | abs.sh STATE | PIN pairing writes your ID to access.json; only the paired account ever reaches Claude. |
| Startup flood control | abs.sh | Drains stale Telegram backlog at launch so a fresh session doesn't open buried in old messages. |
| Update check | abs.sh | On every launch, token-free, checks the remote VERSION and offers to update-and-relaunch on a y/N prompt; declining just launches. |
CLAUDE.md — nothing goes here
abs never writes to CLAUDE.md. The persona lives only in the appended system prompt, re-applied fresh each launch — so there's no persistent agent memory and nothing left behind in your project config.
Make it yours
abs is one readable bash script plus two small Python helpers — no framework, no build step. Each how-to ends with the exact file and function to edit.
The whole project, in four places
There's very little to learn. Everything abs does lives in one of these:
# the program — commands, persona, hooks, usage, all of it abs.sh # voice, both directions (local, no cloud) transcribe.py # voice note → text speak.py # text → voice note # your runtime state, owner-only (never in git) ~/.abs/ # rc.json, access.json, usage.json …
The agent's behaviour isn't in a config file — it's the system prompt abs appends at launch, built in build_prompt().
Point it at a different model
Set a default model per profile, applied on every launch. An explicit abs --model … on the command line always wins for that one session.
abs config model opus # default for this profile abs config model --clear # back to Claude Code's default abs --model sonnet # just this session
To change how the default is stored or applied, the logic is in cmd_config() (stores it) and cmd_run() (passes --model at launch).
Rewrite the persona & tone
How abs talks to you — when it messages, how short it keeps things, its safety rules — is one block of text appended to the session as a system prompt. Edit the heredoc in build_prompt() and it takes effect on the next launch. Nothing is compiled; it's plain English.
Replace the voice engine
Voice is two standalone scripts with a dead-simple contract. Keep the same in/out and you can drop in any engine — a different Whisper size, a cloud STT, another TTS voice.
# in: an audio file path → out: transcript on stdout transcribe.py <file.oga> # in: text → out: a voice note sent to Telegram speak.py "the text to speak"
abs only ever calls these two files, so swapping engines never touches the main script.
transcribe.py speak.pyTune how fast it goes quiet
Auto-silent trips after a set number of back-to-back terminal prompts. Want it to hold on longer, or mute sooner? Change one constant.
readonly SILENT_STREAK=3 # prompts at the terminal before it mutes
The counting itself lives in cmd_silent_hook() just below — that's where a Telegram message resets the streak.
Add your own command
Commands are a plain case in main(). Write a cmd_yours() function, add one line to the dispatch, and abs yours works. No registration, no plugin system.
cmd_hello() { ok "hi from $PROFILE"; }
# in main()'s case block:
hello) cmd_hello ;;Change what the status bar shows
The bottom-bar dot and usage are rendered by cmd_statusline(); the 5h / week glance itself is formatted in usage_glance_str(). Edit either to change the text, order, or what's shown.
Every command
You can also just say it in chat — "mute the reports", "what's my usage" — and abs runs the same thing.
| Command | What it does |
|---|---|
| abs | Start a session — first run walks you through bot setup. |
| abs --model opus | Any Claude Code flag is passed straight through. |
| abs status | What's paired, the inbound state, and whether it's live. |
| abs usage | Your Claude limits — in the terminal and on Telegram. |
| abs profiles | List your bots and which are currently in use. |
| abs config model <name> | Default model for new sessions (--clear to unset). |
| abs config silent on|off | Whether new sessions start muted. |
| abs config statusline on|off | The bottom-bar mute/active dot + usage glance. |
| abs config usage-refresh <min> | How often the usage glance refreshes. |
| abs quiet on|off | Mute / unmute reports — inbound still works. |
| abs off | on | Drop / re-enable all inbound Telegram. |
| abs say "text" | Speak it and send as a voice note. |
| abs update | Update abs in place to the latest release. |
| abs reset | Remove this profile's token, allowlist, and state. |
| abs version | Print the installed version. |
| abs help | The full list. |
Built something good?
Open a PR — new engines, commands, and platforms are all welcome.