99 lines
4.1 KiB
Markdown
99 lines
4.1 KiB
Markdown
# AGENTS.md
|
|
|
|
Instructions for AI agents working on this repository.
|
|
|
|
## Project overview
|
|
|
|
`opencode-dispatch` is a Telegram bot that acts as a secure remote bridge to a locally-running `opencode` instance. It forwards messages from a single authorized Telegram chat to the opencode REST API and relays the responses back.
|
|
|
|
Single entry point: `bot.py`. Python only.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Telegram (user) ──► bot.py ──► opencode REST API (opencode serve)
|
|
◄──────────────────────────────
|
|
```
|
|
|
|
**Concurrency model:**
|
|
- `python-telegram-bot` runs an asyncio event loop
|
|
- `send_to_opencode()` is synchronous (blocking HTTP, up to 1200s timeout) and is always called via `loop.run_in_executor()` to avoid blocking the event loop
|
|
- A `queue.Queue` serializes requests when a message arrives while one is already processing
|
|
- A `threading.Lock` (`processing_lock`) guards `is_processing` and `current_task`
|
|
|
|
**opencode API endpoints used:**
|
|
|
|
| Method | Path | Purpose |
|
|
|--------|------|---------|
|
|
| `GET` | `/global/health` | Health check (`/status` command) |
|
|
| `GET` | `/session` | List existing sessions |
|
|
| `POST` | `/session` | Create a new session |
|
|
| `POST` | `/session/{id}/message` | Send a message and get the response |
|
|
|
|
## Environment variables
|
|
|
|
Defined in `.env` (copy from `.env.example`).
|
|
|
|
| Variable | Required | Description |
|
|
|----------|----------|-------------|
|
|
| `TELEGRAM_BOT_TOKEN` | **Yes** | Bot token from @BotFather |
|
|
| `TELEGRAM_ALLOWED_CHAT_ID` | **Yes** | Telegram chat ID to allow. Bot refuses to start if unset. |
|
|
| `OPENCODE_API_URL` | No | Default: `http://127.0.0.1:5050` |
|
|
| `OPENCODE_SERVER_PASSWORD` | No | If set on the opencode server, must match |
|
|
|
|
> **Note:** `OPENCODE_SERVER_PASSWORD` is read from the env but not yet forwarded in HTTP requests. If you implement password support, add it as a header or query param to `get_session()` and `send_to_opencode()`.
|
|
|
|
## Security invariants — do not break
|
|
|
|
1. **`ALLOWED_CHAT_ID` is enforced.** `main()` exits if `TELEGRAM_ALLOWED_CHAT_ID` is not set.
|
|
2. **`is_authorized()` is called at the top of every handler** — including all command handlers (`/start`, `/help`, `/status`, `/working`, `/clear`) and all message handlers. Unauthorized requests are silently dropped (no reply).
|
|
3. **No internal info is leaked to Telegram.** Error messages sent to the user are generic strings. Detailed errors go to `logger` only.
|
|
4. **No user-visible stack traces.** Use `logger.exception()` server-side, return a static string to the user.
|
|
|
|
## Adding a new bot command
|
|
|
|
1. Write an `async def my_command(update, context)` function.
|
|
2. Call `if not is_authorized(update): return` as the first line.
|
|
3. Register it in `main()` with `app.add_handler(CommandHandler("my_command", my_command))`.
|
|
4. Add it to the help text in `help_command()`.
|
|
|
|
## Adding a new message type handler (e.g. video)
|
|
|
|
Same pattern as `handle_voice`, `handle_document`, `handle_photo`:
|
|
1. Implement the handler with an `is_authorized` guard.
|
|
2. Register with `app.add_handler(MessageHandler(filters.VIDEO, handle_video))` in `main()`.
|
|
|
|
## Running locally
|
|
|
|
```bash
|
|
# Install dependencies
|
|
pip install -r requirements.txt
|
|
|
|
# Configure
|
|
cp .env.example .env
|
|
# Edit .env: fill TELEGRAM_BOT_TOKEN and TELEGRAM_ALLOWED_CHAT_ID
|
|
|
|
# Start opencode in your target project folder
|
|
cd ~/your-project
|
|
opencode serve --port 5050
|
|
|
|
# Run the bot
|
|
python bot.py
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
```
|
|
python-telegram-bot==21.6 # async Telegram bot framework
|
|
requests==2.32.3 # synchronous HTTP client for opencode API
|
|
python-dotenv==1.0.1 # .env file loading
|
|
```
|
|
|
|
No linting or test runner is currently configured. The `.gitignore` includes `.ruff_cache/` and `.pytest_cache/` anticipating future setup.
|
|
|
|
## What is not implemented yet
|
|
|
|
- `OPENCODE_SERVER_PASSWORD` forwarding in HTTP requests
|
|
- Voice, photo, and document handling (handlers exist but reply "not supported")
|
|
- Queued message processing: messages added to the queue while the bot is busy are stored but never drained — the queue worker (`process_queue`) was removed. Queued items are currently orphaned.
|