Skip to content

Latest commit

Β 

History

History
236 lines (188 loc) Β· 17 KB

File metadata and controls

236 lines (188 loc) Β· 17 KB

πŸ€– Agent Development Rules & Guidelines

This document serves as the single source of truth for all development rules, coding standards, and agent behavior guidelines for this project.

πŸ“‹ Table of Contents


πŸ“– Codebase Overview

ngbot is a Telegram gatekeeper bot with CAPTCHA verification, LLM-powered spam detection, and community voting moderation.

Stack: Go 1.26.8, SQLite, Telegram Bot API, OpenAI/Gemini LLMs

Structure:

  • cmd/ngbot/ - Entry point, runtime wiring
  • internal/bot/ - Core service, update processor
  • internal/handlers/ - Admin, Gatekeeper, Reactor, Moderation
  • internal/db/sqlite/ - Persistence with embedded migrations
  • internal/adapters/llm/ - OpenAI/Gemini clients
  • resources/ - i18n, challenges, migrations

For detailed architecture, see docs/CODEBASE_MAP.md.


πŸ—£οΈ Communication & Response Style

  • Language Policy 🌐: Always reason and edit in English, but answer user in their prompt language.
  • Response Format πŸ“Š: Always format responses using structured tables with emojis instead of long text blocks.
  • Visual Clarity ✨: Use tables for better visual clarity and quick scanning. Replace lengthy paragraphs with concise, emoji-enhanced tabular format.
  • Present in diagrams πŸ“Š: Present complex flows and business in Mermaid diagrams when appropriate.
  • Continuation Style ⚑: Continue without stopping to reiterate or provide feedback, and don't report until all planned work is finished.
  • Web Search & Fetch πŸ”: Use ZAI MCP tools when needing to search or fetch web content.

πŸ›οΈ Architecture & Design

Core Philosophy

  • Architecture Style πŸ—οΈ: Hexagonal / Domain-Driven Design (DDD). Keep it modular and layered but compact. Avoid over-abstraction.
  • Avoid Over-Abstraction 🎯: Don't abstract prematurely; keep solutions simple and focused.
  • Interfaces Near Consumer πŸ“: Ports (interfaces) must be defined near the code that uses them.

Project Structure & Module Organization

  • cmd/ngbot: entrypoint and lifecycle wiring.
  • internal/bot: core service, update processor, Telegram helpers.
  • internal/handlers: admin, gatekeeper, reactor, moderation workflows.
  • internal/db/sqlite: persistence with embedded migrations (including gatekeeper challenges).
  • internal/adapters/llm: OpenAI/Gemini clients.
  • resources: embedded i18n, gatekeeper challenges, migrations.
  • Observability stack is removed; logs only.

Architecture Layers

  • Domain: internal/db entities and pure policies where applicable.
  • Application: internal/bot and workflow handlers.
  • Adapters: Telegram API, SQLite, LLM providers, banlist HTTP.

External Services

  • Telegram Bot API.
  • LLM APIs (OpenAI-compatible and Gemini).
  • Banlist API (lols.bot).
  • Join-Captcha WebApp πŸ”’: The gatekeeper join-captcha WebApp server speaks plain HTTP and MUST run behind a TLS-terminating reverse proxy. Its listen address is configured via GatekeeperWebApp.ListenAddr. In the Docker deployment it binds 0.0.0.0:8080 inside the container (mapped to 127.0.0.1:18080 on the host); the default must NOT be changed to loopback or the container port mapping breaks.
  • No-Rights Mode πŸ›‘οΈ: Before banlist, LLM, reaction, or voting moderation, check the bot's restrict-member capability. A confirmed Telegram privilege error is terminal and must not be retried. Public CAPTCHA may still run without restricting the user: success deletes the CAPTCHA; failure leaves a durable 30-minute notice.
  • Manual Allowlist Priority βœ…: A matching per-chat chat_not_spammer_overrides row is the only exemption checked before cached or provider-backed banlist enforcement. For every non-allowlisted user, effective banlist membership remains an unconditional deny decision before remembered membership, admin status, commands, voting, or LLM. The always-on cached guard precedes the configured admin β†’ gatekeeper β†’ reactor chain, and join updates are checked even when Gatekeeper is disabled. Enforcement directly bans and deletes the available join/current-message artifact without creating a spam case. The guard may inspect the in-memory effective set to short-circuit routing, but it must verify moderation capability before Telegram I/O and must not perform online provider checks in no-rights mode. Allowlist lookup failures fail closed and continue normal moderation.
  • Durable Author Trust ✏️: All chats use a typed MessageAuthor (user or sender_chat); SenderChat takes precedence over technical From. Three distinct safe new semantic messages grant 30 days of per-chat trust by default; one safe new message renews expired trust. SQLite atomically binds checked messages, increments the counter and grants trust. Membership bookkeeping is separate and best effort after persistence; reactions and chat_known_non_members never grant trust. Commands, bot mentions, empty media, reactions and edits never advance or renew admission. Before admission and after expiry all semantic edits are checked; during trust previously bound edits remain protected. Checked-message bindings are durable identity metadata: never expire them with context or trust, because renewal would otherwise make old checked edits unprotected; chat deletion may cascade them. Pending/resolving cases suspend trust; confirmed spam resets it, false positives retain any previous unexpired grant. Channels follow community voting without a mute or technical-user fallback. Keep user allowlist-before-banlist priority; user banlists never consume channel IDs. Preserve linked-channel and anonymous group-admin exemptions.
  • Bounded Conversation Context πŸ’¬: Persist message context separately from author trust in SQLite. Retain original send time, thread/reply links, edited text and Telegram update IDs for same-second edit ordering; snapshots cannot supersede newer authoritative edits. Use only same-chat/thread history younger than 24 hours, at most five earlier replies, 2,000 characters per saved text and 8,000 extra context characters. Prioritize direct reply/quote, source post, then nearby replies. Unknown discussion threads use reply chains, ordinary groups may use recent group history. Successful bot deletions leave short-lived tombstones. Successful user bans that revoke messages clear the matching user context; channel bans do not imply removal of previous channel messages. CAPTCHA context cleanup uses a distinct durable phase so a SQLite retry cannot repeat a completed ban. Ordinary user deletions are not reliably observable through Bot API. Pass history as untrusted structured evidence and classify only the candidate. Never log message texts. No external-reply automatic verdict.
  • Author Trust Configuration βš™οΈ: Global NG_SPAM_SAFE_MESSAGES_REQUIRED and NG_SPAM_AUTHOR_TRUST_DURATION default to 3 and 720h. Keep the existing per-chat LLM switch. NG_SPAM_MESSAGE_PROBATION_DURATION is accepted as deprecated with a warning and has no effect. Migrate prior effective user trust for 30 days from migration, including suspended grants; active probations restart at zero and reaction-only records are excluded. Preserve cases, votes and durable actions.

Admin Panel UX Rules

  • Cascading Menus 🧭: Admin settings must be structured as cascading category menus. Do not place many unrelated controls on a single page.
  • Leaf Screens 🌿: Concrete value changes (presets/inputs) must live on leaf screens dedicated to one setting or one logical group.
  • i18n Completeness 🌍: Any new admin UI key must be added for all supported locales before merge.

🐹 Go Development Rules

Core Principles

  • Self-documenting code πŸ“–: No commentsβ€”clear names and structure speak for themselves.
  • No TODOs 🚫: Write complete code or nothing. No placeholders.
  • Professional standards πŸ‘¨β€πŸ’»: Write like a professional Go developer would, without unnecessary code bloat.
  • Architecture first πŸ›οΈ: Audit before coding: scan repo, read related packages, plan all changes.

Go Version & Documentation

  • Go Version πŸ”’: 1.26.8, as pinned in go.mod and Dockerfile. Ref: Go Release Notes
  • Documentation Strategy πŸ“š: Use go doc, go tool, go list for Go packages.
  • English Only πŸ‡ΊπŸ‡Έ: Code and technical reasoning in English.

Tool Dependencies

  • Tool Directive πŸ”§: Use Go 1.24+ tool directive in go.mod for dev tools (golangci-lint, goimports, etc.).
  • No tools.go Hack 🚫: Avoid the tools.go blank import pattern.
  • Refactor tooling πŸ› οΈ:
    • go tool gorename β€” safe, reference-aware renames.
    • go tool godoctor β€” extract/inline functions and move code.
    • go tool gopatch β€” template-driven patches.
    • go tool goimports β€” auto-manage imports.

Naming & Structure

  • Case Convention πŸ”€: Use MixedCaps/mixedCaps (no underscores).
  • Acronyms πŸ”€: All uppercase (HTTP, URL, ID, API).
  • Getters 🎣: No "Get" prefix (user.Name() not user.GetName()).
  • Interfaces πŸ”Œ: Ends in "-er" (Reader) or "-able" (Readable).
  • Organization πŸ“‚: Group related constants/variables/types together.
  • Packages πŸ“: One package per directory with short, meaningful names.
  • Formatting ✨: Use gofumpt -w . (tabs, newline at EOF).

Error Handling & Types

  • Check Immediately ⚠️: Check errors immediately, no panic for normal errors.
  • Wrapping 🎁: Use fmt.Errorf("op: %w", err).
  • Inspection πŸ”: Use errors.Is / errors.As.
  • Interface Types πŸ”„: Use any instead of interface{}.

Best Practices

  • Testing πŸ§ͺ: Table-driven tests beside code (*_test.go). Mock interfaces.
  • Context ⏱️: Use context.Context for cancellation/timeouts (first param).
  • Global Variables 🚫: Avoid them.
  • Composition πŸ”—: Prefer composition over inheritance.
  • Embedding πŸ“Ž: Use judiciously.
  • Preallocation 🧠: Preallocate slices when length is known.

Concurrency Rules

  • Philosophy 🧠: Share memory by communicating.
  • Coordination πŸ“‘: Channels for coordination, mutexes for state.
  • Error Groups πŸ‘₯: Use errgroup for concurrent tasks.
  • Leaks 🚰: Prevent goroutine leaks.

πŸ—„οΈ Database & Schema Management

Reality check βœ…: The persistence stack is SQLite, not PostgreSQL. There is no pgx, no sqlc, no internal/db/sql/, and no internal/db/sqlc/ in this repo. The notes below describe what the code actually uses.

Migrations

  • Location πŸ“: resources/migrations/ as numbered/timestamped plain-SQL files (e.g., 0-init.sql, 20260613000000-add-gatekeeper-webapp-challenges.sql).
  • Embedding πŸ“Ž: Embedded via //go:embed * in resources/embed.go (resources.FS).
  • Runner πŸ› οΈ: rubenv/sql-migrate (EmbedFileSystemMigrationSource, dialect "sqlite3"), applied at startup in internal/db/sqlite/client.go.
  • Direction ↕️: Every migration uses -- +migrate Up and -- +migrate Down; never rewrite an applied migration, add a new file instead.

Query Layer

  • Driver πŸ”Œ: modernc.org/sqlite (pure-Go, CGO-free β€” enables the distroless static build).
  • Access 🧩: Hand-written SQL through jmoiron/sqlx (db: struct tags, StructScan). No code generation.
  • Ports πŸ”Œ: Consumer-owned interfaces live beside bot.service and each handler. The concrete SQLite adapter satisfies them structurally; there is no repository-wide database interface.
  • Concurrency πŸ”’: SQLite runs in WAL mode with SetMaxOpenConns(42), a 1,000-page auto-checkpoint, and a per-connection 64 MiB journal size limit. One app-level sync.RWMutex serializes ordinary writes. Banlist imports write an inactive generation in short batches, release the lock between batches, atomically activate the generation, then garbage-collect retired entries in bounded transactions. Race-sensitive state changes use transactions or atomic compare-and-set (UPDATE … WHERE status=… + RowsAffected()==1).
  • Maintenance 🧹: ngbot --database-maintenance is an offline-only mode. With the service stopped, it applies migrations, enables incremental auto-vacuum through a full VACUUM, optimizes and validates the database, restores WAL mode, and exits before Telegram initialization.

Storage Layer

  • Architecture πŸ—οΈ: Flat β€” one concrete sqliteClient adapter implements consumer-owned ports directly. No interface β†’ Postgres β†’ buffered/cached β†’ factory chain.
  • Caching ⚑: Lives in bot.service (memberCache 5-min TTL, settingsCache process-lifetime) above persistence β€” not in a storage decorator.
  • Value semantics 🧊: Settings enter and leave the cache as clones; a new snapshot is published only after a successful DB write, and warmup never overwrites a newer cached value.

πŸ“ File Editing Strategy

Core Principle

Single-Action Complete Revisions: Consolidate ALL necessary changes into bulk comprehensive updates. Deliver complete, functional code in a single edit action.

Mass Import Replacements

  • Edge Case πŸ”„: When restructuring requires updating imports across many files (30+), use sed or find ... -exec sed.
  • Example: find . -name "*.go" -exec sed -i '' 's|old/path|new/path|g' {} \;
  • Verification: Always run go vet ./... after mass replacements.

Best Practices (DOs & DON'Ts)

  • βœ… Audit First: Read and understand the complete file context.
  • βœ… Plan Comprehensively: Identify all changes needed across the file.
  • βœ… Verify Completeness: Ensure the edit delivers fully functional code.
  • ❌ No Placeholders: No "TODO" or incomplete states.

🧹 Code Quality & Hygiene

Linting & Static Analysis

  • Full Lint πŸ”: go tool golangci-lint run --no-config --enable=unused --enable=unparam --enable=ineffassign --enable=goconst ./.... The repository has no tracked linter configuration; --no-config prevents parent or home configuration from silently weakening local checks compared with CI.
  • Quick Check ⚑: go vet ./... (Do not use go build for validation).
  • Compliance βœ…: Never ignore lint warnings and fix them right away.

Cleanup Rules

  • Unused Code πŸ—‘οΈ: Remove unused files, functions, parameters.
  • No Dead Code πŸ’€: Don't leave dead code unless protected by a describing comment.
  • Constants πŸ“¦: Extract repeated string literals into constants.
  • Signature Refactoring βœ‚οΈ: Simplify function signatures by removing unused params/returns.

πŸ”„ Workflow

Information Gathering

  • Tool Usage πŸ› οΈ: Use provided tools extensively instead of guessing.
  • Code Inspection πŸ”: Inspect code when unsure: list project structure, read whole files.
  • Dependency Check πŸ“¦: Verify library existence in go.mod before importing.

Feedback & Communication

  • Interactive Feedback πŸ’¬: Always call interactive_feedback MCP when asking questions.
  • Continuous Feedback πŸ”„: Continue calling until user feedback is empty.
  • Reporting πŸ“‹: Request feedback or ask when finished or unsure.

Agent Workflow Steps

  1. Audit First πŸ”: Read and understand the complete project structure (tree -a -I .git).
  2. Plan πŸ“‹: Identify all changes needed across files.
  3. Verify βœ…: Use go vet ./... to check code; go test ./... if applicable.
  4. Update Docs πŸ“: Update AGENTS.md if architecture changes or new rules introduced.