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 source link is pinned to the v3.7.4 tag, so the line it opens is the line that shipped — not a line number that moves under you.

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_kokoro.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.
Editable prompt layers abs.sh PYTHON STATE abs prompt opens every layer — persona, hook wording, CLAUDE.md, memory — read the locked ones, edit yours, ^R to reset. Built on Textual.
Named personas abs.sh STATE ~/.abs/personas/<name>.md replaces the middle slot only; ceo, cto and friend ship. Chosen at launch and shown in the status bar.
Commit & ship policy SYSTEM PROMPT STATE Finished work stays uncommitted until you say so, and push, deploy and tag each ask one plain question first. abs config commits auto relaxes the commit half; push still waits.
Bridge health abs.sh Two sessions polling one bot is the one failure the plugin can't heal, so the status bar says so and a per-turn hook clears the stray. abs reconnect does it on purpose.
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 — abs doesn't write there

abs never edits your CLAUDE.md, global or project. Its own behaviour lives in the system prompt it appends fresh at every launch, so nothing is left behind in your project config. What Claude chooses to remember across sessions is Claude Code's own memory, not abs's — and because it still shapes every reply you get, abs prompt gives you a tab to read it, edit any fact, or delete one.

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, what it calls itself — is plain English in a file you own, and you don't need to touch the source to change it. abs prompt opens it on the Persona tab; ^R puts the shipped wording back.

abs prompt                   # the page: read it, edit it, reset it
abs persona list             # abs, ceo, cto, friend, and yours
abs persona create mine      # start one from the shipped text
abs --persona cto            # just this session

~/.abs/persona.md            # the default persona, if you'd rather edit by hand
~/.abs/personas/<name>.md    # the named ones

The prompt is assembled in three slots — bridge mechanics, then your persona, then safety. Safety is appended last on purpose, so a persona can change the voice and the priorities but never talk abs past a destructive-command rail. Over 16,000 characters, or containing a <channel tag, is refused at save rather than silently swapped.

abs.sh · build_prompt
How-to

See everything it tells Claude

Nothing abs adds to a session is hidden. One command opens a tabbed page over every layer: the locked bridge mechanics, your persona, the wording each remote command injects, this project's CLAUDE.md, your global one, and what Claude has remembered.

abs prompt                   # the page — F1…F7 or ^PgUp/^PgDn to move
abs prompt show persona      # or do it without the page at all
abs prompt diff persona      # what you changed vs what ships
abs prompt reset persona     # back to the shipped wording

^S saves, ^R resets, ^N adds a hook phrase or a memory fact, ^T deletes one, ^Q or Esc leaves — and if anything is unsaved it asks first. The System tab is read-only: it is what makes the bridge work, so breaking it would break the tool rather than personalise it.

abs.sh · build_prompt
How-to

Add a remote command of your own

The ABS … phrases you send from Telegram are handled by a session hook, not by the model, which is why they work even when a message tries to talk the model out of them. The wording each one injects lives in ~/.abs/hooks.json, and you can add your own.

# ~/.abs/hooks.json — send "ABS REVIEW" as a whole message
{ "ABS REVIEW": "Stop and review the diff before going further." }

Three phrases can't be reworded — the two that mute and the two that cut the bridge act in the hook and never reach the model at all, so an entry under those names is ignored. Everything else is yours, and the Hooks tab of abs prompt is the editor.

abs.sh · the session's hooks
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 reconnectTelegram stopped arriving? Says what is holding the bot, clears a stray, and names the one thing only a restart fixes. Also abs telegram-reset.
abs menuRe-register the Telegram "/" command menu if it goes missing.
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.
From Telegram — send as a whole message
A session hook acts on these itself, before the model sees them — so they work even if a message tries to talk the model out of them. Anything else you type is simply said to Claude. The wording each one injects, and phrases of your own, live in abs prompt.
ABS MUTE / ABS UNMUTEPause or resume the proactive reports. Inbound keeps working.
ABS STOPHalt the current plan at the next step and wait for you.
ABS OFFCut all Telegram, in and out — the session keeps working locally. Terminal-only to re-enable.
ABS EXITClose the Claude session; it confirms first if it is mid-task.
ABS BLOCKLock the bot out until you re-pair at the terminal.
/usagePost your full Claude usage limits back into the chat.
Persona & what it tells Claude
abs promptThe tabbed page: persona, hook wording, project and global CLAUDE.md, memory. Read the locked layers, edit yours.
abs prompt show|edit|diff|reset <part>The same, without the page — for a machine without Textual, or a script.
abs persona list | showWhich personas exist, and what one says.
abs persona use <name>Make it the default for every session from now on.
abs persona create|edit|rename|deleteYours, in ~/.abs/personas/. A new one starts from the shipped text.
abs --persona ctoJust this session, skipping the picker at launch.
abs config persona-menu on|offAsk which persona at every launch. On by default.
abs config commits ask|autoask (default): nothing is committed until you say so. auto: commit each finished task — pushing still waits for your word either way.
The abs prompt tabs — F1…F7
OverviewWhat each layer is, where it lives on disk, and how big it is.
SystemThe bridge mechanics abs must send. Read-only, on purpose.
PersonaWho it is and how it writes to you. Pick one, or edit it here.
HooksThe wording each remote command injects, plus phrases of your own.
ProjectThis repo's CLAUDE.md — with a warning that it is committed.
GlobalYour ~/.claude/CLAUDE.md, which shapes every Claude session.
MemoryThe facts Claude has kept about you and the work, one per entry.
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.7.4  ·  MIT License  ·  About & contact  ·  Made with ♥ for Claude Code users