Repository navigation
en Development
Follow AGENTS.md. Start from a described problem, inspect
upstream behavior and callers, implement, then validate. Local plans and
investigation output belong in ignored dev-notes/; user documentation belongs
here in both languages. Use descriptive feature branches and atomic buildable
Conventional Commits. Submit separate PRs, using explicit base branches when
changes depend on one another.
Setup and credentials are in Get started. Use the pinned Rust toolchain and committed lockfile:
cargo fmt --all -- --check
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked --all-targets --all-features
cargo build --locked --release
python3 scripts/export-wiki.py --checkKeep small regressions for observable behavior and integration boundaries. Existing tests cover reducer state, Unicode input, terminal rendering, cache restart/replay, concurrent session processes, message-box recovery, folder membership, Lua routing, local regex search, attachment identity and retention. Use synthetic fixtures, not account credentials or downloaded private messages. No TDD requirement or new general test framework is imposed. Do not duplicate upstream parser/database tests. Formatting and linting apply to the root workspace, preserving vendored upstream source conventions.
CI runs the same checks and installs each release with cargo install --git
from the checked-out Git revision on six native hosts. It exercises package
selection, repository-local patches, the lockfile, installation tracking and
the installed binary's version before packaging that executable. Build artifacts
are reused in target/cargo-install, separate from workspace builds and their
build-script metadata. See Updates
for versioning and publication. Automated fixtures do not establish real Telegram
latency parity or verify a desktop file manager's selection behavior. For those,
use an authorized test account and the target operating system; do not send
messages to other people as an implicit test.
flowchart LR
T[One Yazi terminal reader] --> A[App reducer]
A --> L[Local coordinator]
L --> C[SQLite message cache]
L --> N[Grammers worker]
N --> L
L --> A
A --> R[Ratatui and preview renderer]
L --> S[Bounded local search worker]
N --> M[Bounded media transfers]
-
src/app.rsowns selection, focus, drafts and request generations. Feature reducers live insrc/app/; rendering stays insrc/ui/. -
src/keymap.rsloads declarative Lua and maps Yazi keys to actions. Contexts, counts, chords and hints share one binding collection.config.luais user owned; managed settings and account-specific appearance are separate files. -
src/actions.rsandsrc/commands.rsshare finite action metadata with help and completion. Command targets are captured by account/chat/message identity. Reload prepares a whole configuration before the terminal owner applies it; a failed parse or terminal-mode change retains the previous settings. -
src/drafts.rskeeps ordinary and edit drafts by Telegram user/chat identity, separately from discardable history.src/clipboard.rsandsrc/terminal/clipboard.rsfeed existing attachment staging; native clipboard work has one owner, and terminal MIME events use the existing Yazi reader. -
src/telegram/local.rsopens the account cache before networking, serves local requests, bounds commands waiting for authentication, and persists changes.src/cache.rsowns schema migration, history coverage, revisions and retention. -
src/telegram/mod.rsowns the client, update stream and task lifetimes.requests.rsbounds ordinary RPC work; transfers have a separate limit. Slow dialog/history/peer RPCs do not occupy the update-consumption path. -
src/search.rsscans local message text with the maintained regex engine. It has one active blocking scan and one replaceable pending request, generation checks, cancellation and cursor pagination. It never fetches remote history. -
src/telegram/media_cache.rsmanages completed media andtempfilepartials;src/app/attachments.rsadapts selected attachments to download/reveal actions.src/terminal.rsowns modes and cleanup, whilesrc/media.rscoordinates graphics with the same output stream.
Cached display must not wait for authentication, dialogs or a full history scan. The live update receive stays pinned while command and completion events are handled; cancelling and recreating it can discard in-progress recovery. The currently focused group uses Grammers' update engine with server-directed channel-difference timeouts. General push processing and gap recovery continue when active polling stops.
A durable cursor belongs to a complete covered update batch. Commit messages, edits, tombstones and that cursor together; advancing a session cursor alone is not evidence that message content is cached. Restore the application cursor on restart. Too-long differences invalidate affected history before replacement content. Replayed incoming messages must not double-count unread state.
Chat previews use the dialog's actual top message ID, not the last message in a currently loaded historical window. In-flight snapshots cannot restore deleted messages or overwrite newer edits/read state. Exact cached page boundaries prevent sparse reply/search context from masquerading as complete history. Account switching cancels old work and rejects stale request generations.
Only one process owns an account's message cache. File transfers and cleanup retain the same lock lifetime. The underlying session format still supports serialized SQLite writes, but two complete clients must not advance one message cache independently. Keep the current rollback journal until upgrading the bundled SQLite engine and reviewing the upstream WAL-reset fix.
| Upstream | Reused or studied | Local responsibility |
|---|---|---|
Yazi 9203fd2604f867ab5ec18f24203b918975c4c00a
|
Terminal lifecycle, parser, capabilities, TTY, public key normalization; pinned crates | Small adapters and visibility patch; no second input reader |
Codex 78245b47af2a7aafcabe025828ceecca69db4df1
|
Context precedence, chord cancellation, effective hints and composer UX | Design reference; no Codex TUI fork or copied plugin runtime |
Telegram Desktop 4d4da471fbee771c10e173a83c003ba1728989f1
|
Active-group recovery, native filter semantics and local-first storage | Behavioral reference through Telegram API/Grammers; no Desktop storage-format clone |
| Grammers 0.10.0 | MTProto transport and update ordering | Narrow batch/cursor/active-channel patches; retained upstream licenses |
| libSQL / regex / mlua / tempfile / ratatui-image | Storage, regex, bounded Lua evaluation, partial files, inline rendering | Application schemas, limits, commands and UX |
| arboard / notify-rust | Native clipboard and desktop notification adapters | Draft staging, account/request identity, alert eligibility and privacy |
Source references: Yazi, Codex TUI, Telegram Desktop, Telegram updates, dialog filters.
TDLib supplies a maintained client/database stack, but adopting it here would replace authentication, message mapping, media and the existing Grammers integration. The present change keeps Grammers and confines required adaptations to documented SDK boundaries. Reconsider that choice if upstream maintenance or update correctness can no longer be kept narrow.
Update all Yazi Git revisions together. Prefer released dependencies or immutable Git revisions; never depend on sibling local checkouts. For copied code retain licenses and document the repository, revision, source path and adaptations in vendor/README.md. Remove superseded infrastructure instead of maintaining two paths indefinitely.
Hints come from effective bindings. Empty editors use ghost text, and overlays own input and provide an escape route. Preserve drafts and reading position across view changes. State scope explicitly: loaded history is not full history, cached search is not a server query, and a loading badge is not an empty result. Color supplements focus markers rather than carrying meaning alone.
Keep English and Simplified Chinese pages together. The small Wiki export workflow validates page parity and internal links, then maps this directory to GitHub Wiki filenames without a documentation framework.
The statusline follows Yazi’s ordered status components and Codex’s finite item
list, with no copied code. src/statusline.rs owns declarative configuration and
ephemeral metrics; src/ui/statusline.rs fits them to terminal cells. Optional
Ping observations use the existing Grammers client in an owned task that aborts
on shutdown/account switch and never consumes the update stream.
src/ui/transcript.rs owns message presentation; src/ui/chats.rs uses Ratatui
Table for semantic columns. The transcript retains the existing text wrapping,
action dispatch, media slots and viewport ownership; small render regressions
cover hit precedence and message visibility when width changes.
English
- Appearance
- Attachments and file previews
- Chat discovery and details
- Commands
- Lua configuration
- Development and architecture
- Telegram folders
- Get started
- Termgram guide
- Keybindings
- Notifications and mute settings
- Pinned chats and messages
- Polls and quizzes
- Message reactions
- Search messages
- Sticker panel
- Cache and synchronization
- Terminal integration
- Daily workflows
- Updates and releases
简体中文