opencode-telegram-bot
grinev/opencode-telegram-bot/AGENTS.md
Instructions for AI agents working on this project. opencode-telegram-bot is a Telegram bot that acts as a mobile client for OpenCode. It lets a user run and monitor coding tasks on a local machine through Telegram. Functional requirements, features, and development status are in PRODUCT.md. Don't assume. Don't hide confusion. Surface tradeoffs. Before implementing: - State your assumptions explicitly. If uncertain, ask. - If multiple interpretations exist, present them - don't pick silently. - If a simpler approach exists, say…
- Reads credentials
What's in it
- AGENTS.md
- About the project
- Technology stack
- Core dependencies
- Test dependencies
- Code quality
- Architecture
- Main components
- Data flow
- State management
- AI agent behavior rules
- Communication
- Think Before Coding
- Simplicity First
- Surgical Changes
- Goal-Driven Execution
- Git
- Working on Windows
- Coding rules
- Language
- Code style
- Error handling
- Cross-platform
- Bot commands
- Logging
- Testing
- What to test
- Test structure
- OpenCode SDK quick reference
- Workflow
# AGENTS.md
Instructions for AI agents working on this project.
## About the project
**opencode-telegram-bot** is a Telegram bot that acts as a mobile client for OpenCode.
It lets a user run and monitor coding tasks on a local machine through Telegram.
Functional requirements, features, and development status are in [PRODUCT.md](./PRODUCT.md).
## Technology stack
- **Language:** TypeScript 5.x
- **Runtime:** Node.js 22.14+
- **Package manager:** npm
- **Configuration:** environment variables (`.env`)
- **Logging:** custom logger with levels (`debug`, `info`, `warn`, `error`)
### Core dependencies
- `grammy` - Telegram Bot API framework (https://grammy.dev/)
- `@grammyjs/menu` - inline keyboards and menus
- `@opencode-ai/sdk` - official OpenCode Server SDK
- `dotenv` - environment variable loading
### Test dependencies
- Vitest
- Mocks/stubs via `vi.mock()`
### Code quality
- ESLint + Prettier
- TypeScript strict mode
## Architecture
### Main components
1. **Bot Layer** - grammY setup, middleware, commands, callback handlers
2. **OpenCode Client Layer** - SDK wrapper and SSE event subscription
3. **State Managers** - session/project/settings/question/permission/model/agent/variant/keyboard/pinned
4. **Summary Pipeline** - event aggregation and Telegram-friendly formatting
5. **Process Manager** - local OpenCode server process start, stop, and status
6. **Runtime/CLI Layer** - runtime mode, config bootstrap, CLI commands
7. **I18n Layer** - localized bot and CLI strings to multiple languages
### Data flow
```text
Telegram User
-> Telegram Bot (grammY)
-> Managers + OpenCodeClient
-> OpenCode Server
OpenCode Server
-> SSE Events
-> Event Listener
-> Summary Aggregator / Tool Managers
-> Telegram Bot
-> Telegram User
```
### State management
- Persistent state is stored in `settings.json`.
- Active runtime state is kept in dedicated in-memory managers.
- Session/project/model/agent context is synchronized through OpenCode API calls.
- The app is currently single-user by design.
## AI agent behavior rules
### Communication
- **Response language:** Reply in the same language the user uses in their questions.
- **Clarifications:** If plan confirmation is needed, use the `question` tool. Do not make major decisions (architecture changes, mass deletion, risky changes) without explicit confirmation.
### Think Before Coding
**Don't assume. Don't hide confusion. Surface tradeoffs.**
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
### Simplicity First
**Minimum code that solves the problem. Nothing speculative.**
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
### Surgical Changes
**Touch only what you must. Clean up only your own mess.**
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: Every changed line should trace directly to the user's request.
### Goal-Driven Execution
**Define success criteria. Loop until verified.**
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multi-step tasks, state a brief plan:
```
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
```
### Git
- **Commits:** Never create commits automatically. Commit only when the user explicitly asks.
### Working on Windows
If your shell runs on Windows:
- Avoid fragile one-liners that can break in PowerShell.
- Use absolute paths when working with file tools (`read`, `write`, `edit`).
## Coding rules
### Language
- Code, identifiers, comments, and in-code documentation must be in English.
- User-facing Telegram messages should be localized through i18n.
### Code style
- Use TypeScript strict mode.
- Use ESLint + Prettier.
- Prefer `const` over `let`.
- Use clear names and avoid unnecessary abbreviations.
- Keep functions small and focused.
- Prefer `async/await` over chained `.then()`.
### Error handling
- Use `try/catch` around async operations.
- Log errors with context (session ID, operation type, etc.).
- Send understandable error messages to users.
- Never expose stack traces to users.
### Cross-platform
- The bot runs on Linux, macOS, and Windows; CI runs tests on Linux.
- Code must work on all three regardless of the OS you develop on: passing checks locally does not prove it works elsewhere.
- Code that touches paths, processes, shells, or the filesystem must work on all three: no hardcoded `\` or `/` separators, no assumptions about line endings or path case.
- Windows-only logic runs behind a `process.platform` check. A test for it either passes on every OS or is skipped outside Windows.
### Bot commands
The command list is centralized in `src/bot/commands/definitions.ts`.
```typescript
const COMMAND_DEFINITIONS: BotCommandI18nDefinition[] = [
{ command: "status", descriptionKey: "cmd.description.status" },
{ command: "new", descriptionKey: "cmd.description.new" },
{ command: "abort", descriptionKey: "cmd.description.stop" },
{ command: "sessions", descriptionKey: "cmd.description.sessions" },
{ command: "projects", descriptionKey: "cmd.description.projects" },
{ command: "rename", descriptionKey: "cmd.description.rename" },
{ command: "opencode_start", descriptionKey: "cmd.description.opencode_start" },
{ command: "opencode_stop", descriptionKey: "cmd.description.opencode_stop" },
{ command: "help", descriptionKey: "cmd.description.help" },
];
```
Important:
- When adding a command, update `definitions.ts` only.
- The same source is used for Telegram `setMyCommands` and help/docs.
- Do not duplicate command lists elsewhere.
### Logging
The project uses `src/utils/logger.ts` with level-based logging.
Log files:
- In source mode logs are stored `<project root>/logs` by default.
- Each source-mode bot run writes to a separate file named `bot-YYYY-MM-DD_HH-MM-SS_<pid>.log`.
- The `logs/` directory is gitignored, so search inside it directly: use `path: "logs"` with `pattern: "*.log"`.
- Installed mode writes under the installed app home `logs` directory and uses daily files named `bot-YYYY-MM-DD.log`.
Levels:
- **DEBUG** - detailed diagnostics (callbacks, keyboard build, SSE internals, polling flow)
- **INFO** - key lifecycle events (session/task start/finish, status changes)
- **WARN** - recoverable issues (timeouts, retries, unauthorized attempts)
- **ERROR** - critical failures requiring attention
Use:
```typescript
import { logger } from "../utils/logger.js";
logger.debug("[Component] Detailed operation", details);
logger.info("[Component] Important event occurred");
logger.warn("[Component] Recoverable problem", error);
logger.error("[Component] Critical failure", error);
```
Important:
- Do not use raw `console.log` / `console.error` directly in feature code; use `logger`.
- Put internal diagnostics under `debug`.
- Keep important operational events under `info`.
- Default level is `info`.
## Testing
### What to test
- Unit tests for business logic, formatters, managers, runtime helpers
- Integration-style tests around OpenCode SDK interaction using mocks
- Focus on critical paths; avoid over-testing trivial code
### Test structure
- Tests live in `tests/` (organized by module)
- Use descriptive test names
- Follow Arrange-Act-Assert
- Use `vi.mock()` for external dependencies
## OpenCode SDK quick reference
The example below is the V1 client. OpenCode V2 goes through `@opencode/client`, wrapped in `src/opencode/v2/`.
```typescript
import { createOpencodeClient } from "@opencode-ai/sdk";
const client = createOpencodeClient({ baseUrl: "http://localhost:4096" });
await client.global.health();
await client.project.list();
await client.project.current();
await client.session.list();
await client.session.create({ body: { title: "My session" } });
await client.session.prompt({
path: { id: "session-id" },
body: { parts: [{ type: "text", text: "Implement feature X" }] },
});
await client.session.abort({ path: { id: "session-id" } });
const events = await client.event.subscribe();
for await (const event of events.stream) {
// handle SSE event
}
```
Full docs: https://opencode.ai/docs/sdk
## Workflow
1. Read [PRODUCT.md](./PRODUCT.md) to understand scope and status.
2. Inspect existing code before adding or changing components.
3. Align major architecture changes (including new dependencies) with the user first.
4. Add or update tests for new functionality.
5. After code changes, run quality checks: `npm run build`, `npm run lint`, `npm run typecheck`, and `npm test`.
6. Update checkboxes in `PRODUCT.md` when relevant tasks are completed.
7. Keep code clean, consistent, and maintainable.
More agent context in grinev/opencode-telegram-bot
One other file this repository gives its agents.
CLAUDE.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.

