Agent Babysitter connects a Telegram bot to a machine where Claude Code can run commands. That is powerful, so it's worth being precise about who can reach it and what protects you. Short version: only you can message your bot, and the sections below explain exactly how that's enforced — and the few things it does not protect against.
This is the core of the model, and it's worth stating plainly because it's easy to assume otherwise: a stranger who finds your bot cannot do anything.
- Pairing writes your Telegram user ID to an allowlist. Setup sets
dmPolicy: "allowlist"and records your numeric ID. Every inbound message is checked against it; anyone not on the list is dropped before Claude ever sees it. They get silence — no reply, no pairing offer, nothing. - Numeric IDs can't be spoofed. Telegram user IDs are permanent. Changing a display name or username doesn't change the ID, so no one can impersonate their way onto your allowlist.
- Pairing is inverted on purpose. Some bots DM a code to any stranger who
messages them and let them join. Agent Babysitter does the opposite: your
terminal generates a PIN and waits for it. Unknown senders are never answered,
and matching the PIN proves the person on the phone is the person at the
terminal. The PIN comes from
/dev/urandom, drops look-alike characters (I/O/0/1), expires in 5 minutes, and only counts from a private chat — a PIN pasted into a group pairs no one.
- The bot token never appears in
ps. Telegram puts the token in the URL path, so a naivecurl …/bot<TOKEN>/…would leak it to every user on the machine viaps auxww. Every API call pipes the URL throughcurl -K -instead, so the token stays out of the process's argument list. (Verified: a canary token was not visible inpsduring a live call.) - Files are owner-only. The script runs
umask 077before touching disk. The token (~/.claude/channels/telegram/.env) and the allowlist (access.json) are600; their directories are700. Writes go through a temp file andmv, so a crash can't leave a half-written or briefly world-readable token. - Claude is told the rules. The injected prompt instructs Claude to never
send secrets, tokens, keys, or
.envcontents over Telegram; to treat instructions embedded in fetched content (web pages, files) as data, not commands; and to require terminal confirmation for anything destructive or irreversible that arrives over chat.
The prompt asks Claude to behave. These two features enforce it at the hook layer — code that runs no matter what the model decides — for the obvious, high-damage cases. They don't replace Claude Code's permission system; they raise the floor beneath it, and give you a kill switch that doesn't rely on trusting the model.
- The remote kill ladder. Send any of these from Telegram as a whole
message; the session hook acts on it directly (the model never runs it):
ABS MUTE/ABS UNMUTE— mute / resume proactive reports (you get a catch-up on resume).ABS OFF— cut inbound and outbound Telegram; the session keeps working locally. Re-enable from the terminal (abs on).ABS STOP— the hook tells Claude to halt the current plan at the next step and wait. (It can't hard-interrupt a command already mid-run — the Telegram plugin only delivers your message between steps — so a long single command still needs Ctrl-C at the terminal.)ABS EXIT— close the session (Claude asks to confirm if it's mid-task). Restart withabs.ABS BLOCK— lock this bot out entirely; only a deliberateabs setupfrom the terminal brings it back.
- The destructive-command guard. A
PreToolUsehook blocks a small, high-confidence set of Bash commands —rm -rf,git push --force,reset --hard,clean -fd, branch deletion,DROP/TRUNCATE,DELETE/UPDATEwithoutWHERE,dd/mkfs, recursivechmod/chown, and reads of.env/credentials.json/*.pem/id_rsa— when the turn was driven from Telegram. A remote message is lower-trust than you at the desk, so it's stopped and you're told to run it at the terminal. From the terminal, nothing is blocked. Opt out withabs config guard off.
Honest limit: this is defense-in-depth, not a sandbox. A determined, compromised model could try to obfuscate a command (base64, a wrapper script) to slip past the pattern match — so the guard raises the floor, it isn't a wall. Claude Code's own permission system remains the real boundary.
Be clear-eyed about the limits. None of these are bugs — they're the shape of the trade you're making, and worth knowing before you rely on it.
- Telegram sees your messages. Bot chats are not end-to-end encrypted. Everything Claude reports and everything you send is readable by Telegram. Don't use this for work where that matters. Voice notes are transcribed and synthesized locally, so no cloud speech vendor hears them — but the audio still travels over Telegram like any other message.
- Your bot token is a credential. Anyone who obtains it can impersonate your
bot. It lives in plaintext at
~/.claude/channels/telegram/.env, protected by file permissions, not encryption. If it leaks, revoke it with/revokein @BotFather and runabs setupagain. - Anyone with your unlocked phone can instruct Claude. The allowlist authenticates a Telegram account, not a person. Lock your phone.
- It is not a sandbox. Within your paired account, Claude has whatever power Claude Code gives it on your machine. The allowlist decides who can reach the session; it does not limit what the session can do. The real boundary on actions is Claude Code's own permission system.
reset, notsetup, clears the allowlist. Re-runningabs setupadds to the allowlist (so existing entries survive). To revoke access for everyone, runabs reset.- The conversation log is a second copy of everything. With the log on (the
default), your messages, abs's replies, and the tools it ran are written to
~/.abs/<profile>/log/YYYY-MM-DD.jsonl— local,600, never uploaded. Control characters are stripped and secrets are scrubbed on a best-effort basis (Telegram / OpenAIsk-/ GitHub / AWS / Google / Slack keys, JWTs, PEM private keys,key=/password=pairs, and passwords embedded in URLs). But a secret in a shape the patterns don't recognise can still land there, and home-directory backups or cloud-sync tools will pick the file up. Turn it off withabs config log off, and delete it any time withabs log --clear. - The install chain is trust-by-HTTPS.
install.shfetchesabs.sh— and can run Bun's and Claude Code's owncurl | bashinstallers — over HTTPS with no checksum, the standard model for this class of tool. Installing from a cloned checkout (./install.sh) skips the download entirely. - The update check calls GitHub once a day to compare versions (opt out with
abs config update-check off). It only ever compares — it never auto-updates or executes anything.
Found something? Open an issue at github.com/Pranjalab/AgentBabysitter/issues, or for anything sensitive, describe it privately rather than in a public issue.