Skip to content

Latest commit

 

History

History
216 lines (153 loc) · 6.63 KB

File metadata and controls

216 lines (153 loc) · 6.63 KB

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.

Technology stack

  • Language: TypeScript 5.x
  • Runtime: Node.js 20+
  • 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

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.

Git

  • Commits: Never create commits automatically. Commit only when the user explicitly asks.

Windows / PowerShell

  • 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).

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.

Bot commands

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.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.

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.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

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 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, and npm test.
  6. Update checkboxes in PRODUCT.md when relevant tasks are completed.
  7. Keep code clean, consistent, and maintainable.