Metadata-Version: 2.4
Name: coding-agent-telegram
Version: 2026.4.2
Summary: Telegram bot bridge for local coding agents (Codex/Copilot CLI)
Author: DCHA
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-telegram-bot<22.0,>=21.0
Requires-Dist: python-dotenv<2.0.0,>=1.0.0
Requires-Dist: portalocker<3.0.0,>=2.8.2
Dynamic: license-file

  Coding Agent Telegram
  
Coding Agent Telegram 🚀
  
    English (https://github.com/daocha/coding-agent-telegram/blob/main/README.md) |
    Deutsch (https://github.com/daocha/coding-agent-telegram/blob/main/README.de.md) |
    Français (https://github.com/daocha/coding-agent-telegram/blob/main/README.fr.md) |
    日本語 (https://github.com/daocha/coding-agent-telegram/blob/main/README.ja.md) |
    한국어 (https://github.com/daocha/coding-agent-telegram/blob/main/README.ko.md) |
    Nederlands (https://github.com/daocha/coding-agent-telegram/blob/main/README.nl.md) |
    ไทย (https://github.com/daocha/coding-agent-telegram/blob/main/README.th.md) |
    Tiếng Việt (https://github.com/daocha/coding-agent-telegram/blob/main/README.vi.md) |
    简体中文 (https://github.com/daocha/coding-agent-telegram/blob/main/README.zh-CN.md) |
    繁體中文（香港） (https://github.com/daocha/coding-agent-telegram/blob/main/README.zh-HK.md) |
    繁體中文（台灣） (https://github.com/daocha/coding-agent-telegram/blob/main/README.zh-TW.md)

Lightweight, Multi Bots, Multi sessions, Multi-tasking, 24/7 AI Coding Agent
  
Control your local AI coding agent from anywhere with Telegram.
  
    Experimental

    Python 3.9+

   ## ✨ Why Use It
   - ✅ Lightweight: no heavy frameworks, full transparency
   - ✅ Multi-bot: multiple chats, multiple sessions
   - ✅ Use Telegram to control Codex / Copilot CLI
   - ✅ Easily review files changed by agent in code block
   - ✅ Queue follow-up messages while the agent is working
   - ✅ Accept ✏️ Text, 🌄 Image, and 🎙️ Voice messages

   ## 🔁 Seamless Device/Session Switching
   
   Start a session on Telegram, later on you can still continue the same Codex/Copilot CLI session on your computer, and switch back again without hassle.
   
   - Use `/switch` in Telegram to continue a local session
   - Support historical sessions

   ## 🛠️ Typical Local Flow
   ```bash
   coding-agent-telegram # or run ./startup.sh
   ```
   
   ##### In Telegram:
   
   ```text
   /project my-project
   /new
   Fix the failing API test in the current project
   ```
   

→ Setup with one-liner: 
```
curl -fsSL https://raw.githubusercontent.com/daocha/coding-agent-telegram/main/install.sh | bash
```


   ## 🔐 Security
      
   - Private chat whitelist with `ALLOWED_CHAT_IDS`
   - One active agent per project to reduce conflicting writes
   - Sensitive file diffs are hidden
   - API keys, tokens, `.env` values, certificates, SSH keys, and similar secret-like output are redacted before sending back to Telegram
   - Runtime app data stays under `~/.coding-agent-telegram`
   - Existing folders can require trust before mutating git operations
   - The server does not make hidden external calls. Everything stays under your control.
   - Works well with Codex Sandbox mode (you don't have to grant `danger-full-access`)

   ## ✅ Requirements

   Before starting the server, make sure you have:
   
   - Python 3.9 or newer
   - Telegram bot token created from _@BotFather_
   - Your Telegram chat ID
   - Codex CLI and/or Copilot CLI installed locally
   - [Codex CLI install](https://developers.openai.com/codex/cli) / [Copilot CLI install](https://github.com/features/copilot/cli)
   - [Optional] `Whisper`, `ffmpeg`

## 🦞 Why do I need it if I have Openclaw already?
Openclaw offers you full capabilities and has integrated agent loop called Pi-Agent. It's quite comprehensive and designed for more diversified use cases. I am also Openclaw lover and I used to code with Openclaw. However, that is not the best choice for coding due to the built in large system prompt and context. Using Claude Code / Codex / Copilot for coding is still more effecient, accurate, less distracted, and straightforward. This project is quite simple, purely integrating with Codex / Copilot CLI. So you are directly delegating Codex / Copilot to work for you.

## 🚀 Quick Start

### Option A: Start with a one-line bootstrap script

```bash
curl -fsSL https://raw.githubusercontent.com/daocha/coding-agent-telegram/main/install.sh | bash
```

### Option B: Install from PyPI with `pip`

```bash
pip install coding-agent-telegram
coding-agent-telegram
```

### Option C: Run from a cloned repository

```bash
git clone https://github.com/daocha/coding-agent-telegram
cd coding-agent-telegram
./startup.sh
```

### 🌐 Start Bot Server
##### On first run, the app creates the env file, tells you what to fill in.
##### After updating the environment file then run:

```bash
# if you follow Option A or Option B, then run
coding-agent-telegram

# if you follow Option C, then run this again
./startup.sh
```

## 🎙️ [Optional] Speech-to-Text Feature: prepare local OpenAI-Whisper prerequisites

This enables optional local Whisper-based voice-message speech-to-text for Telegram voice notes. Voice files are capped to `20MB` max.

```bash
# if you installed from pip or one-liner install.sh
coding-agent-telegram-stt-install

# if you run from a cloned repository
./install-stt.sh
```

The installer writes the STT env flags automatically after prerequisites are ready.

Estimated local footprint:

- `openai-whisper`: about `50 MB`
- `ffmpeg` package: about `50 MB`
- Whisper model downloads vary by model: `tiny` about `72 MB`, `base` about `139 MB`, `large-v3-turbo` about `1.5 GB`

Recommended env settings for the local Whisper backend:

```text
ENABLE_OPENAI_WHISPER_SPEECH_TO_TEXT=true
OPENAI_WHISPER_MODEL=base
OPENAI_WHISPER_TIMEOUT_SECONDS=120
```

Notes:

- Whisper downloads the selected model automatically on first use into `~/.cache/whisper`.
- If you choose `OPENAI_WHISPER_MODEL=turbo`, the first voice transcription is more likely to hit the timeout while `large-v3-turbo.pt` is still downloading.
- After a voice note is transcribed, the bot immediately sends the recognized transcript back to Telegram before the agent reply. If the run can start immediately it says “working on it”; if the project is busy it shows that the transcript was queued instead.

## 🔑 Telegram Setup

### Get a Bot Token

1. Open Telegram and start a chat with `@BotFather`.
2. Send `/newbot`.
3. Follow the prompts to choose:
   - a display name
   - a bot username ending in `bot`
4. BotFather will return an HTTP API token.
5. Put that token into `TELEGRAM_BOT_TOKENS` in your `~/.coding-agent-telegram/.env_coding_agent_telegram`.

### Get Your Chat ID

The most reliable way is to use Telegram's `getUpdates` API with your own bot token.

1. Start a chat with your bot and send it a message such as `/start`.
2. Open this URL in your browser, replacing `<BOT_TOKEN>`:

```text
https://api.telegram.org/bot<BOT_TOKEN>/getUpdates
```

3. Find the `chat` object in the JSON response.
4. Copy the numeric `id` field from that object.
5. Put that value into `ALLOWED_CHAT_IDS` in your `~/.coding-agent-telegram/.env_coding_agent_telegram`

Notes:

- For private chats, the chat ID is usually a positive integer.
- If `getUpdates` returns an empty result, send another message to the bot and try again.

## 📨 Supported Message Types

The bot currently accepts:

- Text messages
- photos
- voice messages when `ENABLE_OPENAI_WHISPER_SPEECH_TO_TEXT=true` and local Whisper prerequisites are installed
- Codex and Copilot currently supports text and image only, video is not supported.

## 🤖 Telegram Commands

     /provider
     Choose the provider for new sessions. The selection is stored per bot and chat until you change it.

     /project <project_folder>
     Set the current project folder. If the folder does not exist, the app creates it and marks it trusted. If it already exists and is still untrusted, the app asks you to trust it explicitly.

     /branch <new_branch>
     Prepare or switch a branch for the current project. If the branch already exists, the bot treats that branch as the source candidate. Otherwise it uses the repository default branch as the source candidate.

     /branch <origin_branch> <new_branch>
     Prepare or switch a branch using <origin_branch> as the source candidate. 
 For both forms, the bot then offers the source choices that actually exist: local/<branch> origin/<branch> 
If only one of those exists, only that option is shown. If neither exists, the bot tells you the branch source is missing.

     /current
     Show the active session for the current bot and chat.

     /new [session_name]
     Create a new session for the current project. If you omit the name, the bot uses the real session ID. If provider, project, or branch is missing, the bot guides you through the missing step.

     /switch
     Show the latest sessions, newest first. The list includes both bot-managed sessions and local Codex/Copilot CLI sessions for the current project.

     /switch page <number>
     Show another page of stored sessions.

     /switch <session_id>
     Switch to a specific session by ID. If you choose a local CLI session, the bot imports it and continues from there.

     /compact
     Create a fresh compacted session from the active session and switch to it.

     /commit <git commands>
     Run validated git commit-related commands inside the active session project. Available only when ENABLE_COMMIT_COMMAND=true. Mutating git commands require a trusted project.

     /push
     Push origin <branch> for the current active session. The bot asks for confirmation before pushing.

     /abort
     Abort the current agent run for the current project. If queued questions are waiting, the bot asks whether to continue them.

⚙️ Environment Variables

Main env file path:

     CODING_AGENT_TELEGRAM_ENV_FILE
     Use this if you want to point the app to a specific env file.

     ~/.coding-agent-telegram/.env_coding_agent_telegram
     Default env file location.

     ./.env_coding_agent_telegram
     Used only if this local file already exists.

Required

     WORKSPACE_ROOT
     Parent folder that contains your project directories.

     TELEGRAM_BOT_TOKENS
     Comma-separated Telegram bot tokens.

     ALLOWED_CHAT_IDS
     Comma-separated Telegram private chat IDs allowed to use the bot.

Common Settings

     APP_LOCALE
     UI locale for shared bot messages and command descriptions. Supported values: en, de, fr, ja, ko, nl, th, vi, zh-CN, zh-HK, zh-TW.

     CODEX_BIN
     Command used to launch Codex CLI. Default: codex.

     COPILOT_BIN
     Command used to launch Copilot CLI. Default: copilot.

     CODEX_MODEL
     Optional Codex model override.
    Leave empty to use the Codex CLI default model.
    Example: gpt-5.4
    OpenAI Codex/OpenAI models (https://developers.openai.com/codex/models)

     COPILOT_MODEL
     Optional Copilot model override.
    Leave empty to use the Copilot CLI default model.
    Examples: gpt-5.4, claude-sonnet-4.6
    GitHub Copilot supported models (https://docs.github.com/en/copilot/reference/ai-models/supported-models)

     CODEX_APPROVAL_POLICY
     Approval mode passed to Codex. Default: never.

     CODEX_SANDBOX_MODE
     Sandbox mode passed to Codex. Default: workspace-write.

     CODEX_SKIP_GIT_REPO_CHECK
     If enabled, always bypass Codex trusted-repo checks.

     ENABLE_COMMIT_COMMAND
     Enable the /commit Telegram command. Default: false.

     AGENT_HARD_TIMEOUT_SECONDS
     Hard timeout for a single agent run. Default: 0 (disabled).

     SNAPSHOT_TEXT_FILE_MAX_BYTES
     Maximum file size the bot will read as text when building the before/after snapshot for per-run diffs. Default: 200000.

     MAX_TELEGRAM_MESSAGE_LENGTH
     Max message size used before the app splits responses. Default: 3000

     ENABLE_SENSITIVE_DIFF_FILTER
     Hide diffs for sensitive files. Default: true>

     ENABLE_SECRET_SCRUB_FILTER
     Redact tokens, keys, .env values, certificates, and similar secret-like output before sending it to Telegram. Default true (Strongly recommended)

     SNAPSHOT_INCLUDE_PATH_GLOBS
     Force-include matching paths in diffs. Example: .github/*,.profile.test,.profile.prod

     SNAPSHOT_EXCLUDE_PATH_GLOBS
     Add extra diff exclusions on top of the packaged defaults.
  Example: .*,personal/*,sensitive*.txt
  Note: .* matches hidden paths, including files inside hidden directories.

Speech to Text

     ENABLE_OPENAI_WHISPER_SPEECH_TO_TEXT
     Default: false. If true, it enables the audio messages capability. System will check the prerequisites regarding required binaries or libraries on startup.

   OPENAI_WHISPER_MODEL
   Model for the Whisper SST. Default: base
Available models: tiny about 72 MB, base about <codoe>139 MB</codoe>, large-v3-turbo about 1.5 GB
  Models will be automatically downloaded on your first voice message. Recommended: base for general usage. If you want better accuracy and quality, you can try with turbo

     OPENAI_WHISPER_TIMEOUT_SECONDS
     Default: 120Timeout for the STT process. Usually the STT processing is fast enough.

State and Logs

     ~/.coding-agent-telegram/state.json
     Main session state file.

     ~/.coding-agent-telegram/state.json.bak
     Backup state file.

     ~/.coding-agent-telegram/logs
     Log directory.

Example:

```env
APP_LOCALE=en
WORKSPACE_ROOT=~/git
TELEGRAM_BOT_TOKENS=bot_token_one
ALLOWED_CHAT_IDS=123456789
DEFAULT_AGENT_PROVIDER=codex
CODEX_BIN=codex
COPILOT_BIN=copilot
CODEX_APPROVAL_POLICY=never
CODEX_SANDBOX_MODE=workspace-write
ENABLE_SENSITIVE_DIFF_FILTER=true
ENABLE_SECRET_SCRUB_FILTER=true
```

## 🧠 Session Management

Sessions are scoped by:

- Telegram bot
- Telegram chat

That means the same Telegram account can use multiple bots without mixing sessions.

Example:

- Bot A + your chat -> backend work
- Bot B + your chat -> frontend work
- Bot C + your chat -> infra work

The active session is also tied to:

- project folder
- provider
- branch name when available

Each session stores:

- session name
- project folder
- branch name
- provider
- timestamps
- active session selection for that bot/chat scope

### 🔓 Workspace concurrency lock

Only one agent run can be active per **project folder** at a time — regardless of which chat ID or Telegram bot triggers it.

This is different from “an agent is still processing the current question”:

- **project is busy** means the workspace already has one live agent run
- **agent is busy** means that one live run is still working on the current request

The bot enforces one active run per project on purpose so two agents do not write to the same workspace at the same time. That avoids conflicting edits and reduces the chance of data corruption.

If a message arrives while an agent is already running on the same project, the bot immediately replies:

> ⏳ An agent is already running on project '…'. Please wait for it to finish.

The lock is held in memory (not on disk), so it is automatically released when the agent finishes, errors out, or if the server restarts. There are no stale lock files to clean up after a crash.

### 💬 Queued questions

If the current project already has one live agent run, later text messages are not rejected. They are queued instead:

- the new question is appended to a queued-questions file on disk
- the current agent keeps working on the earlier request
- when that run finishes normally, the bot automatically starts processing the queued questions next

If the current run is aborted and there are queued questions waiting, the bot does **not** auto-continue. It asks whether you want to continue processing the remaining queued questions. You can choose to batch process or one-by-one.

## ⚠️ Diff (file changes)

_During each agent run, the bot also takes a lightweight before/after project snapshot so it can summarize changed files and send diffs back to Telegram. This snapshot is taken by the bot app itself, not by Codex or Copilot._

**Snapshot notes:**

- the app walks the project directory before and after the run
- for normal text files, the app prefers the per-run snapshot diff rather than a git-head diff
- common dependency, cache, and runtime directories are also skipped
- binary files and files larger than `SNAPSHOT_TEXT_FILE_MAX_BYTES` are not loaded as text
- for huge projects, this extra scan can add noticeable I/O and memory overhead
- if the snapshot cannot represent a file as text, the app falls back to git diff when possible
- for large or non-text files, the diff may still be omitted and replaced with a short unavailable message

Snapshot exclusion rules live in package resource files:

- `src/coding_agent_telegram/resources/snapshot_excluded_dir_names.txt`
- `src/coding_agent_telegram/resources/snapshot_excluded_dir_globs.txt`
- `src/coding_agent_telegram/resources/snapshot_excluded_file_globs.txt`

You can override those defaults in the env file without editing the installed package:

- `SNAPSHOT_INCLUDE_PATH_GLOBS`
  Force-include matching paths in diffs.
  Example: `.github/*,.profile.test,.profile.prod`

- `SNAPSHOT_EXCLUDE_PATH_GLOBS`
  Add extra diff exclusions on top of the packaged defaults.
  Example: `.*,personal/*,sensitive*.txt`
  Note: `.*` matches hidden paths, including files inside hidden directories.

If both include and exclude rules match, the include rule wins.

## 🌿 Branch Behavior

The bot treats project and branch as a bundle.

- choosing a project does not silently choose an unrelated branch
- if branch input is needed, the bot asks you to pick it
- when branch information is printed in session-related messages, project and branch are shown together

When you create or change a branch, the bot guides you through the source explicitly:

- `local/<branch>` means use the local branch as the source
- `origin/<branch>` means update from the remote branch first and then switch

If the bot sees that the stored session branch and the repository's current branch do not match, it does not blindly continue. It asks which branch you want to use:

- keep the stored session branch
- keep the current repository branch

If your preferred source branch is missing, the bot offers fallback source choices based on the default branch and current branch instead of leaving you at a raw git error.

## 🔐 Git Trust Behavior

- Existing folders follow `CODEX_SKIP_GIT_REPO_CHECK`
- Folders created through `/project <name>` are marked as trusted by this app
- Existing folders selected through `/project <name>` remain untrusted until you confirm trust in the Telegram prompt
- That means newly created project folders can be used immediately
- `/commit` can be disabled entirely with `ENABLE_COMMIT_COMMAND`
- Mutating `/commit` operations are allowed only for trusted projects

## 🪵 Logs

Logs are written to **both stdout and a rotating log file** under:

- `~/.coding-agent-telegram/logs` (rotated at 10 MB, 3 backups kept)

> **Note:** Because messages go to both stdout and the log file, watching the terminal
> **and** tailing the log file at the same time (e.g. `tail -f ~/.coding-agent-telegram/logs/coding-agent-telegram.log`)
> will make each message appear twice — once from each sink. This is expected behavior.
> View one or the other, not both simultaneously.

Typical logged events

- bot startup and polling start
- project selection
- session creation
- session switching
- active session reporting
- normal run execution (includes an audit log line with the truncated prompt)
- session replacement after resume failure
- warnings and runtime errors

## 🗂️ Project Structure

- `src/coding_agent_telegram/`
  Main application code

- `tests/`
  Test suite

- `startup.sh`
  Local bootstrap and startup entrypoint

- `src/coding_agent_telegram/resources/.env.example`
  Canonical environment template used by both repo startup and packaged installs

- `pyproject.toml`
  Packaging and dependency configuration

## 📦 Release Versioning

Package versions are derived from Git tags.

- TestPyPI/testing: `v2026.3.26.dev1`
- PyPI prerelease: `v2026.3.26rc1`
- PyPI stable: `v2026.3.26`

## 📌 Notes

- This project is designed for users running the agents locally on their own machine.
- The Telegram bot is a control surface, not the execution environment itself.
- If you run multiple bots, all of them can be managed by one server process.
