acpgram
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Fail
- fs module — File system access in .github/workflows/publish.yml
- rm -rf — Recursive force deletion command in install.sh
- spawnSync — Synchronous process spawning in src/acp.mjs
- exec() — Shell command execution in src/admin.mjs
- process.env — Environment variable access in src/app.mjs
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Telegram gateway to AI coding agents (Gemini CLI, Claude Code, Antigravity CLI) over the Agent Client Protocol
AcpGram
English · Русский
A Telegram gateway to AI coding agents — Gemini CLI, Claude Code, Antigravity CLI and OpenAI Codex. The bot runs the agent as a subprocess on the machine where it is installed and talks to it over the Agent Client Protocol (JSON-RPC over stdin/stdout). You write a task in Telegram; the agent works in the selected project on your server, PC or laptop, and you watch its progress, approve its actions and get the answer right in the chat.
- No npm dependencies — plain Node.js 24 (built-in
node:sqlite,fetch). - Windows, Linux and macOS. Tested on Windows Server and Linux (Ubuntu in WSL); macOS uses the same code as Linux.
- Multi-user: the main admin invites teammates and controls what each of them can do.
The bot's interface is currently in Russian.
Features
- Streaming replies in a Telegram draft with a stop button: the agent's thoughts, the steps it takes (reading files, running commands, searching, editing) and the elapsed time, then the answer itself.
- Rich final answer — headings, lists, tables, code blocks — with a collapsible "work log" of every step and a footer showing the engine, the actual model, reasoning level, tokens, cost (Claude Code) and time.
- Four engines, one interface —
/engineswitches between Gemini CLI, Claude Code, Antigravity CLI and Codex; the default engine is set in.env. - Model and reasoning level —
/modellists the models the agent itself reports (pluseffortfor Claude Code andthought_levelfor Antigravity); the choice is remembered per user and per engine. - Permission requests as buttons — "Allow", "Allow for this session", "Reject". Options that would persist a rule forever or raise the session above the user's access level are never shown.
- Files and images — send the bot a photo or a file (text, PDF, spreadsheet, etc., up to 20 MB); the caption becomes the request. The file is saved to
<data dir>/uploads/<user id>/and the agent gets its path and reads it with its own tools. An album of several photos or files is handled as one request..zip,.tar,.tar.gzand.tgzarchives are unpacked next to the file (…_unpacked, at most 500 files and 100 MB; unsafe paths and links are skipped) and the agent gets the file list;.7zand.rarstay a plain file; images are also passed as animageblock when the agent supports it. In the other direction the agent can create a file and send it to the chat: it saves the file to<data dir>/outbox/<user id>/(or the project folder) and puts a[[send:path]]marker in its reply. Only files from these two folders are sent, never secrets (.env, the bot's database and logs,.git). Files are kept for 7 days (FILES_KEEP_DAYS). - Language — the bot talks to each user in their Telegram language (
ru,ukoren; any other falls back toDEFAULT_LANG, English by default)./languagechanges it and takes priority over the Telegram language. Theacpgramterminal commands (setup wizard, service, update, help) speak the system language: Russian, Ukrainian, otherwise English; on Windows the system UI language is used, not the regional format. - Projects —
/projectpicks the working folder by buttons, by name search or by path (/project ~/projects/web), with one-tap recent projects. - Sessions —
/sessionsresumes a previous conversation (in the engine it was created in), even after a restart;/newstarts fresh;/closeunloads the agent process. - Team access — invite links and access requests; per-user access levels, engines and model restrictions;
/activeshows who is working and lets the admin end any session. - Audit log — SQLite database with sessions, requests, tool calls, permissions, answers, token usage and cost.
Supported engines
| Engine | How it is started | Install | Auth |
|---|---|---|---|
| Gemini CLI | gemini --acp |
npm i -g @google/gemini-cli |
GEMINI_API_KEY or Gemini CLI login |
| Claude Code | claude-agent-acp (ACP bridge) |
npm i -g @agentclientprotocol/claude-agent-acp |
ANTHROPIC_API_KEY or Claude Code login |
| Antigravity CLI 1.5+ | agy acp |
see Antigravity docs | Google sign-in once: agy acp --login |
| OpenAI Codex | codex-acp (ACP bridge) |
npm i -g @agentclientprotocol/codex-acp (Codex CLI required) |
OPENAI_API_KEY or codex login; on Windows read-only/workspace-write need a working Codex sandbox |
Only the default engine (DEFAULT_ENGINE, Gemini CLI unless set) is required; the others are optional — engines that are not installed are simply not offered.
Quick start
You need at least one engine from the table above and a Telegram bot token from @BotFather (Bot API 10.1+ — rich messages and drafts).
Option 1. Install via npm (requires Node.js 22.13+)
npm install -g acpgram
Then run the setup wizard:
acpgram setup
Settings (.env) and SQLite database (data/bot.db) are stored in ~/.acpgram (or ACPGRAM_HOME), so updating via npm install -g acpgram@latest keeps all settings and history intact.
Migrating from install.ps1 (resolving PATH conflict)
The install.ps1 script adds %LOCALAPPDATA%\acpgram\bin to the user PATH. If you switch to the npm installation, Windows might still invoke the old script due to PATH order.
You do not need to move settings and the database by hand: on the first acpgram setup the wizard finds %LOCALAPPDATA%cpgram (~/.local/share/acpgram on Linux and macOS) and offers to import .env and data/bot.db. Stop the old service first, otherwise the bot token stays busy and Telegram returns a Conflict error.
To switch:
- Stop and uninstall any previous service:
acpgram service uninstall - Check which binary is resolved:
Get-Command acpgram - Remove
%LOCALAPPDATA%\acpgram\binfrom userPATH:[Environment]::SetEnvironmentVariable("Path", (([Environment]::GetEnvironmentVariable("Path", "User") -split ';') | Where-Object { $_ -notlike '*\acpgram\bin' }) -join ';', "User") - Optionally copy your previous settings and database:
New-Item -ItemType Directory -Force "$HOME\.acpgram" Copy-Item "$env:LOCALAPPDATA\acpgram\.env" "$HOME\.acpgram\.env" if (Test-Path "$env:LOCALAPPDATA\acpgram\data") { Copy-Item -Recurse "$env:LOCALAPPDATA\acpgram\data" "$HOME\.acpgram\" } - Restart your terminal window.
Option 2. One-line installer
Windows (PowerShell):
irm https://raw.githubusercontent.com/selesnow/acpgram/main/install.ps1 | iex
Linux / macOS:
curl -fsSL https://raw.githubusercontent.com/selesnow/acpgram/main/install.sh | bash
The installer downloads the latest release (checksum verified) into %LOCALAPPDATA%\acpgram or ~/.local/share/acpgram, installs a private Node.js 24 if yours is missing or older (official build, checksum verified, no admin rights), adds the acpgram command to your PATH and starts the setup wizard. Run it again — or acpgram update — to update; your settings and data are kept.
acpgram start the bot
acpgram setup settings wizard
acpgram service install run as a service (also: restart, stop, status, uninstall)
acpgram update update to the latest release
From source instead (Node.js 24+): git clone https://github.com/selesnow/acpgram.git && cd acpgram && npm start — npm scripts mirror the commands: npm run setup, npm run service:install.
The setup wizard (acpgram setup / npm run setup, safe to re-run — current values are suggested):
- bot token — checked right away with
getMe; - main admin — just send any message to your bot, the wizard picks up your Telegram ID;
- projects root — optional (see
PROJECTS_ROOTbelow); - engines — finds installed Gemini CLI, Claude Code and Antigravity CLI, stores their full paths (so they are found under a service too), asks for the default engine;
- API keys — optional; the token, keys and passwords are typed hidden;
- writes
.env(owner-only permissions; the previous one goes todata/.env.bak), creates the database and sends you a test message; - offers to install the bot as a service.
Run as a service
Autostart with the system and restart on failure — one command:
| OS | How | Command |
|---|---|---|
| Windows | Windows service via nssm (winget install --id NSSM.NSSM -e); run the terminal as administrator; you will be offered to run the service under your account (where the agents are signed in) |
npm run service:install |
| Linux | systemd --user (to keep it running without a login session: sudo loginctl enable-linger $USER) |
npm run service:install |
| macOS | LaunchAgent (launchd) |
npm run service:install |
Also: acpgram service restart (after an update; a hung service is force-stopped), acpgram service stop (stops it without removing: the service starts again after a reboot), acpgram service status, acpgram service uninstall (npm: npm run service:status, npm run service:uninstall). Options go after -- (otherwise npm takes them for itself): npm run service:install -- --dry-run prints the commands without running them, -- --name <name> sets another service name (default acpgram; Windows and Linux), -- --system installs a Windows service under LocalSystem without a terminal. Logs: data/service.log (Linux: journalctl --user -u acpgram -f; Windows PowerShell 5.1: Get-Content <path>\data\service.log -Tail 30 -Encoding UTF8, otherwise non-English text looks garbled).
On Windows the service needs your account's password: if you sign in with a Microsoft account, that is the Microsoft account password, not the Windows PIN (with a PIN the service fails to log on — the wizard detects this and asks again). Accounts without a password cannot run services.
The account password is passed to
nssmas a command-line argument — this is how nssm grants the "Log on as a service" right. It is never printed or stored by the bot and is visible in the process list only to administrators and the same user for the fraction of a second the command runs. Without a terminal the service can only be installed with--system(LocalSystem).
Docker
cp .env.example .env # set TELEGRAM_BOT_TOKEN, ALLOWED_USER_ID, engine API keys and uncomment PROJECTS_DIR
docker compose up -d --build
In the container the agent sees only the mounted projects folder (PROJECTS_DIR → /projects). The image ships all four engines: Gemini CLI, Claude Code (claude-agent-acp bridge), OpenAI Codex (codex + codex-acp bridge) and Antigravity CLI. To build a lighter image, list only the engines you need in ENGINES in .env (e.g. ENGINES=gemini claude); DEFAULT_ENGINE must be one of them.
- Authentication: Gemini -
GEMINI_API_KEY, Claude Code -ANTHROPIC_API_KEY, Codex -OPENAI_API_KEY(all from.env). - Antigravity CLI has no API keys: log in once with your Google account (a link and a code, no browser needed on the server):
docker compose exec -it bot agy acp --login. The login is kept in thegemini-homevolume. The build fails if Antigravity cannot be installed or lacks theacpsubcommand (1.5+) - then dropagyfromENGINES. - Volumes:
bot-data,gemini-home,claude-home,codex-homesurvive container re-creation;docker compose down -vremoves them. - An engine that starts but is not authenticated is shown as "login needed" in
/engine.
Bot commands
| Command | Who | What |
|---|---|---|
/start |
everyone | welcome screen: engine, model, access level, project |
/project [name or path] |
everyone | choose the working folder |
/engine [gemini, claude, agy, codex] |
everyone | choose the engine |
/model |
everyone | choose the model and reasoning level |
/new |
everyone | new session |
/sessions |
everyone | resume a previous session in this project |
/stop |
everyone | stop the running request |
/close, /exit |
everyone | close the session and unload the agent process |
/users |
admin | teammates: level, engines, models, end session, revoke access |
/active |
admin | active sessions with buttons to end them |
/invite |
admin | one-time invite link (24 h) |
Access levels
The main admin is set by ALLOWED_USER_ID. Everyone else gets access through an invite link or by asking (the request goes to the admin with buttons).
| Level | Gemini CLI | Claude Code | Antigravity CLI | Codex | Meaning |
|---|---|---|---|---|---|
| Read | plan |
plan |
plan |
read-only |
the agent only reads and analyzes |
| Normal | default |
default |
default |
workspace-write |
permission requests go to the user |
| Full | autoEdit |
bypassPermissions |
accept-edits |
agent-full-access |
edits without confirmation (Claude Code: no confirmations at all) |
| Admin | autoEdit |
bypassPermissions |
accept-edits |
agent-full-access |
change with ACP_MODE/GEMINI_ADMIN_MODE, CLAUDE_ADMIN_MODE, AGY_ADMIN_MODE |
New teammates get only the default engine; the admin grants other engines and can restrict models per user and per engine. At most MAX_AGENTS (3) teammate agents run at once across all engines (the admin is not counted); idle sessions close after IDLE_MINUTES (30).
An agent mode limits what the agent does, but it is not a sandbox: the agent runs with the rights of the account the bot runs under. The project folder is where it starts, not a jail. All users share the API keys and quotas. Give the "Full" level (Claude Code
bypassPermissions) deliberately.
Configuration (.env)
| Variable | Required | Description |
|---|---|---|
TELEGRAM_BOT_TOKEN |
yes | bot token |
ALLOWED_USER_ID |
yes | Telegram ID of the main admin |
PROJECTS_ROOT |
no | projects root: projects can be chosen only inside it (team server). Without it any folder on the machine can be chosen, the home folder by default (personal install) |
DEFAULT_ENGINE |
no | gemini (default), claude, agy or codex; the bot does not start if this engine is not installed |
DEFAULT_LANG |
no | bot language when the user's Telegram language is not ru, uk or en: en (default), ru or uk. Each user can change it with /language |
ACPGRAM_LANG |
no | language of the acpgram terminal commands: ru, uk or en. Usually not needed: the language comes from the system (for Docker and CI, where the system has none) |
GEMINI_API_KEY |
no | Gemini API key, passed to the agent through the bot's environment |
ANTHROPIC_API_KEY |
no | Anthropic API key for Claude Code (API billing instead of a subscription) |
GEMINI_COMMAND, CLAUDE_COMMAND, AGY_COMMAND, CODEX_COMMAND |
no | full paths to the engines if they are not in PATH (typical for services) |
ACP_MODE / GEMINI_ADMIN_MODE, CLAUDE_ADMIN_MODE, AGY_ADMIN_MODE, CODEX_ADMIN_MODE |
no | admin session mode per engine |
MAX_AGENTS |
no | concurrent teammate agents (3) |
IDLE_MINUTES |
no | idle session timeout, minutes (30) |
FILES_DIR |
no | folder for received (uploads) and outgoing (outbox) files (the bot's data folder) |
FILES_KEEP_DAYS |
no | how many days to keep those files (7) |
ANIMATED_ICONS |
no | 0 — plain emoji instead of animated icons in drafts |
.env is never committed. Keep the token and keys out of the code.
Development
npm test # node:test, no dependencies, no Telegram
install.ps1 one-line installer for Windows
install.sh one-line installer for Linux and macOS
src/
cli.mjs the acpgram command: start, setup, service, update, version
cli-i18n.mjs terminal language (detected from the system) and the texts of the acpgram commands in en, ru, uk
main.mjs entry point: loads .env, runs the setup wizard on first start
setup.mjs setup wizard
service.mjs service: nssm (Windows), systemd --user (Linux), launchd (macOS)
bot.mjs message and button routing, access checks
engines.mjs engine registry: commands, modes per level, catalogs, usage parsing
acp.mjs Agent Client Protocol client (agent subprocess)
access.mjs per-user engines and models, model catalogs, applying the choice
turn.mjs one request: streaming draft, work log, permissions, final answer
state.mjs per-user state: agent process, engine, project, limits, idle reaper
admin.mjs invites, access requests, /users, /active
projects.mjs project paths (inside the root or anywhere), recent projects, search
*Ui.mjs /project, /sessions, /engine, /model screens
ui.mjs rendering: drafts, steps, final message, screens
telegram.mjs Bot API calls, rich messages, long text splitting, file download and upload
files.mjs attachments: names, saving, prompt blocks, [[send:path]] markers, outgoing file checks, cleanup
archive.mjs safe unpacking of zip, tar, tar.gz without dependencies
albums.mjs collects Telegram albums (shared media_group_id) into one request
db.mjs SQLite: sessions, requests, tool calls, permissions, users, usage
test/ node:test tests and a fake ACP agent
.github/workflows CI (tests on Windows / Linux / macOS) and releases (archives, checksums, installer checks)
Releases are built by GitHub Actions on a version tag: tests on all three OSes, .zip / .tar.gz archives with SHA256SUMS, then both installers are verified on Windows, Linux and macOS against the published release. Installers can be tested against a local build with ACPGRAM_RELEASE_URL=file:///path/to/dist, ACPGRAM_VERSION, ACPGRAM_NO_SETUP=1, ACPGRAM_YES=1, ACPGRAM_HOME.
License
MIT © 2026 Alexey Seleznev
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found