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.
- Language: TypeScript 5.x
- Runtime: Node.js 20+
- Package manager: npm
- Configuration: environment variables (
.env) - Logging: custom logger with levels (
debug,info,warn,error)
grammy- Telegram Bot API framework (https://grammy.dev/)@grammyjs/menu- inline keyboards and menus@opencode-ai/sdk- official OpenCode Server SDKdotenv- environment variable loading
- Vitest
- Mocks/stubs via
vi.mock()
- ESLint + Prettier
- TypeScript strict mode
- Bot Layer - grammY setup, middleware, commands, callback handlers
- OpenCode Client Layer - SDK wrapper and SSE event subscription
- State Managers - session/project/settings/question/permission/model/agent/variant/keyboard/pinned
- Summary Pipeline - event aggregation and Telegram-friendly formatting
- Process Manager - local OpenCode server process start, stop, and status
- Runtime/CLI Layer - runtime mode, config bootstrap, CLI commands
- I18n Layer - localized bot and CLI strings to multiple languages
Telegram User
-> Telegram Bot (grammY)
-> Managers + OpenCodeClient
-> OpenCode Server
OpenCode Server
-> SSE Events
-> Event Listener
-> Summary Aggregator / Tool Managers
-> Telegram Bot
-> Telegram User
- 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.
- Response language: Reply in the same language the user uses in their questions.
- Clarifications: If plan confirmation is needed, use the
questiontool. Do not make major decisions (architecture changes, mass deletion, risky changes) without explicit confirmation.
- Commits: Never create commits automatically. Commit only when the user explicitly asks.
- Keep in mind the runtime environment is Windows.
- Avoid fragile one-liners that can break in PowerShell.
- Use absolute paths when working with file tools (
read,write,edit).
- Code, identifiers, comments, and in-code documentation must be in English.
- User-facing Telegram messages should be localized through i18n.
- Use TypeScript strict mode.
- Use ESLint + Prettier.
- Prefer
constoverlet. - Use clear names and avoid unnecessary abbreviations.
- Keep functions small and focused.
- Prefer
async/awaitover chained.then().
- Use
try/catcharound async operations. - Log errors with context (session ID, operation type, etc.).
- Send understandable error messages to users.
- Never expose stack traces to users.
The command list is centralized in src/bot/commands/definitions.ts.
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.tsonly. - The same source is used for Telegram
setMyCommandsand help/docs. - Do not duplicate command lists elsewhere.
The project uses src/utils/logger.ts with level-based logging.
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:
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.errordirectly in feature code; uselogger. - Put internal diagnostics under
debug. - Keep important operational events under
info. - Default level is
info.
- 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
- Tests live in
tests/(organized by module) - Use descriptive test names
- Follow Arrange-Act-Assert
- Use
vi.mock()for external dependencies
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
- Read PRODUCT.md to understand scope and status.
- Inspect existing code before adding or changing components.
- Align major architecture changes (including new dependencies) with the user first.
- Add or update tests for new functionality.
- After code changes, run quality checks:
npm run build,npm run lint, andnpm test. - Update checkboxes in
PRODUCT.mdwhen relevant tasks are completed. - Keep code clean, consistent, and maintainable.