Pi extension bridging a Telegram bot to a local Pi agent, in two mutually-exclusive modes:
terminal-continuation (connect) and business manager (manager).
pi/— the ONLY boundary that imports@earendil-works/*(SDK). Enforced by an invariant test.telegram/— grammY client + raw-api escape for Bot API 10.1 methods, updates, media, rich rendering.storage/— ACID JSON/JSONL (atomic temp+rename, in-process file lock). Source of truth.settings/— defaults → global → project merge with bespoke normalizers.core/— shared kernel: lifecycle (mode activation), instructions, timers, queue, turns, abort, render.ui/— Pi TUI indicators (footer, manager banner).modes/connectandmodes/manager— the two mode controllers.
- One Pi extension entrypoint:
export default (pi: ExtensionAPI) => void. - Modes are mutually exclusive; default OFF; explicit enable/disable; crash-reset via stale pid/heartbeat.
- Manager context isolation uses
pi.on("context")to rebuildmessagesfrom the active chat only. - Reply decision uses tools
telegram_manager_reply/telegram_manager_silent(not text sentinels).
- Raw TypeScript shipped (Pi runs it);
tscis typecheck-only. ESM, tabs, double quotes (biome). - All tests and mocks live in
tests/(never insrc/). Test via the latest vitest. - Every runtime is a
create*Runtime(deps)factory / class with injected ports (fake-ports testing). - Tests must use synthetic chat ids, names, and message text only. Never copy real Telegram
names, ids, timestamps, or message wording into fixtures; reproduce a production case with
neutral placeholders such as
Alice,chat-a, anddelayed hello.
The approved plan: ~/.claude/plans/lazy-giggling-gosling.md.