home / docs

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.

SYSTEM PROMPT SETTINGS abs.sh PYTHON TELEGRAM PLUGIN STATE FILE
FeatureLives inWhat 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.

Orientation

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().

abs.sh
How-to

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).

abs.sh · cmd_config
How-to

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.

abs.sh · build_prompt
How-to

Replace the voice engine

Installing voice is opt-in — it's a few GB of models, so nothing downloads until you ask. Once installed, replies go out as a voice note by default wherever the machine can speak. You don't need a dev checkout any more; an installed abs keeps its engines in ~/.abs/voice:

abs voice setup       # install the speech engines
abs voice status      # what's installed, what's missing, how to fix it
abs voice samples     # one voice note per voice — choose by ear

The speaking engine is Kokoro: 82M parameters, built for the CPU, a note in seconds on a laptop. The alternative wants a GPU and is the only one that can clone a voice from a reference clip, so it's a separate opt-in:

abs voice setup --chatterbox         # adds the GPU engine, for cloning
abs config voice-sample <clip>       # point it at your reference audio

Underneath, it's 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_kokoro.py "the text to speak"     # CPU, the default
speak.py "the text to speak"            # chatterbox, for cloning

abs only ever calls these files, so swapping engines never touches the main script.

transcribe.py speak.py
How-to

Tune 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.

abs.sh · SILENT_STREAK
How-to

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 ;;
abs.sh · main
How-to

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.

abs.sh · cmd_statusline usage_glance_str
Reference

Every command

You can also just say it in chat — "mute the reports", "what's my usage" — and abs runs the same thing.

CommandWhat it does
Everyday
absStart a session — first run walks you through bot setup.
abs --model opusAny Claude Code flag is passed straight through.
abs statusWhat's paired, the inbound state, and whether it's live.
abs usageYour Claude limits — in the terminal and on Telegram.
abs profilesList your bots and which are currently in use.
abs quiet on|offMute / unmute reports — inbound still works.
abs off | onDrop / re-enable all inbound Telegram.
abs exitEnd the running session. Restart with abs.
abs send "text"Send plain text to your chat — works even if the Telegram plugin is down. abs send - reads stdin.
abs say "text"Speak it and send as a voice note.
abs logYour local conversation backup. --list the days kept, --date one of them, --clear to delete.
abs doctorDiagnose the install, read-only — dependencies, plugin, pairing, and the daemon stack.
abs updateUpdate abs in place to the latest release, and verify it landed.
abs resetRemove this profile's token, allowlist, and state.
abs version | helpThe installed version; the full list.
Voice
abs voice setupInstall the local speech engines. Opt-in, and no longer needs a dev checkout.
abs voice setup --chatterboxAdd the GPU engine. Slower, and the only one that can clone a voice.
abs voice statusWhat's installed, what's missing, and the command that fixes it.
abs voice samplesSends one voice note per voice, so you choose by ear rather than by name.
abs config kokoro-voice <id>Which voice speaks. --clear for the default.
abs config engine kokoro|chatterboxWhich engine backs abs say. Absent = whichever is installed.
abs config voice-sample <file>Clone a voice from a reference clip. Needs chatterbox.
abs config voice-offer done|resetThe one-time "pick a voice" offer — mark it answered, or ask again.
How replies arrive
abs config reply-text on|offSend replies as text. On by default.
abs config reply-voice on|offSend replies as a voice note. On by default wherever the machine can speak.
abs config reply text|both|voice|autoThe mode directly. auto hands the choice back to the machine.
abs config voice-first on|offIn mode both: the note first, then the same words as text. On by default.
abs config voice-words <n>How long a reply must be before it's spoken. Default 150 — a short answer is quicker to read than to hear.
abs config footer on|offAttach your usage and remaining context to replies. On by default.
Session defaults
abs config model <name>Default model for new sessions (--clear to unset).
abs config silent on|offWhether new sessions start muted.
abs config auto-silent on|offPause reports while you're driving the terminal. On by default.
abs config statusline on|offThe bottom-bar dots, usage, remaining context and version.
abs config label <name>The name before the colon in the bar. It follows your Claude account unless you pin one.
abs config usage-refresh <min>How often the usage glance refreshes. Default 5.
abs config guard on|offBlock destructive commands on Telegram-driven turns. On by default.
abs config ack on|offA 👀 on your Telegram message the moment it lands.
abs config log on|offBack up the conversation locally under ~/.abs.
abs config start-menu on|offThe resume-first picker on interactive launch.
abs config update-check on|offThe on-launch "update now?" prompt.
The always-on layer (v3)
A curl install fetches this for you — no git clone. abs src status says whether it's there.
abs src install | status | pathFetch the v3 source into ~/.abs/src. This is what turns a curl install into a full one.
abs daemon install | start | stopThe daemon that polls your idle bots, so a session can be started when nothing is running.
abs daemon status | logsWhether it's alive, and what it's been doing.
abs sessionsList engine sessions. --json for scripts.
abs attach [profile]Attach to a running session.
abs project add | list | rm <dir>Register the projects the ABS START flow offers you from Telegram.
abs config workspace-root <dir>Where a remote "New folder" start creates it. Your home directory by default.
abs start new-botProvision a brand-new bot and profile, then launch it.
abs sandbox build | create | listDocker sandbox sessions — each with one dedicated host folder and nothing else.
abs sandbox start | stop | destroyRun, pause, or remove one.
abs start sandbox [name]Run a Claude session inside a sandbox container.

Built something good?

Open a PR — new engines, commands, and platforms are all welcome.

Contributing guide
← Back to home  ·  v3.6.0  ·  MIT License  ·  Made with for Claude Code users