REPOSITORY / ScuroNeko/Laniakea

Wiki

KNOWLEDGE REPOSITORY

wip

2026-03-26 18:31:57 +03:00
parent f36229ddf1
commit d9eba254fc
17 changed files with 1135 additions and 1 deletions
+44
@@ -0,0 +1,44 @@
# AGENTS.md
## Scope
These instructions apply only to the wiki repository in this directory.
## Purpose
The wiki is the structured documentation layer for Laniakea.
It should complement the main `README.md` rather than duplicate it line-by-line.
## Writing goals
- Optimize for navigation and fast orientation.
- Prefer short pages with strong links over giant all-in-one documents.
- Explain design intent, API boundaries, defaults, and migration-relevant behavior.
- Keep examples practical and consistent with the current codebase.
- Sort information by importance, necessity, and expected popularity of use.
- Put setup and first-use material before advanced extension points.
- Apply that ordering consistently on `Home.md`, when adding new pages, and inside each page when listing methods, types, structures, or workflows.
- Documentation should be as detailed as needed to remove ambiguity.
- Add examples whenever they materially improve understanding.
## Content rules
- Reflect the current public API from the main repository.
- When behavior is version-sensitive, mention the relevant version explicitly.
- Prefer English page titles and stable page names.
- Keep Home.md concise and link-focused.
- Avoid restating low-value godoc verbatim unless the wiki adds context.
## Page structure
- Start each page with a one-paragraph summary.
- Then list the most important concepts or decisions first.
- Use short sections and flat bullet lists.
- Link related pages whenever a topic crosses page boundaries.
- Within a page, explain the most necessary and most frequently used APIs before less common or advanced ones.
- Prefer complete explanations over minimal notes when the topic has real usage nuance.
## Maintenance rules
- When adding a new page, update `Home.md` if the page is user-relevant.
- Prefer editing existing pages over creating overlapping pages.
- Keep terminology aligned with the code and README.
## Commit discipline
- Wiki commit messages should follow the same repository rule:
1. one short summary line;
2. up to three additional high-signal lines.
+9
@@ -0,0 +1,9 @@
# Bot Lifecycle
This page explains how a bot is configured, started, stopped, and why a `Bot` instance is single-use.
## This page should cover
- `BotOpts`, defaults, and startup validation;
- `Run`, `RunWithContext`, `Close`, and `CloseRemote`;
- workers, polling, and shutdown behavior;
- which configuration must be finalized before `Run`.
+307
@@ -0,0 +1,307 @@
# Commands and Plugins
Laniakea organizes most bot behavior through plugins.
If you understand how plugins, commands, payload handlers, and update handlers fit together, the rest of the library becomes much easier to reason about.
## The important model first
The normal layering is:
- `Bot` owns runtime, update flow, logging, and API clients
- `Plugin` groups related handlers
- commands handle text commands like `/start`
- payload handlers handle inline-button callback payloads
- update handlers handle non-command Telegram updates
In practice, most bots start with:
- one or more plugins
- a few commands
- optional plugin middleware
- maybe payload handlers once inline keyboards appear
## Plugins
A plugin is a named group of:
- commands
- payload handlers
- update handlers
- shared middleware
- optional plugin logger and close hook
Example:
```go
plugin := laniakea.NewPlugin[laniakea.NoDB]("admin")
```
Use plugins to group functionality by concern:
- `admin`
- `payments`
- `profile`
- `support`
That keeps command registration and middleware ownership clear.
## Command handlers
The command handler signature is:
```go
func(ctx *laniakea.MsgContext, db T) error
```
Where:
- `ctx` is the current message/update context
- `db` is the dependency value of the bots generic type `T`
Return:
- `nil` on success
- `error` when the centralized bot error flow should handle failure
Example:
```go
func start(ctx *laniakea.MsgContext, db *App) error {
ctx.Answer("Welcome")
return nil
}
```
## Registering commands
Create a command with `NewCommand(...)` and add it to a plugin:
```go
plugin := laniakea.NewPlugin[*App]("main")
plugin.AddCommand(plugin.NewCommand(start, "start"))
```
The command name:
- must not include the slash
- is matched against the parsed command token
So:
- `"start"` matches `/start`
- `"help"` matches `/help`
## The easiest command example
```go
func echo(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
if ctx.Text == "" {
ctx.Answer("Usage: /echo <text>")
return nil
}
ctx.Answer(ctx.Text)
return nil
}
plugin.AddCommand(plugin.NewCommand(echo, "echo"))
```
For `/echo hello world`:
- `ctx.Text == "hello world"`
- `ctx.Args == []string{"hello", "world"}`
## Commands with argument validation
You can declare command arguments using `CommandArg`.
Example:
```go
plugin.AddCommand(
plugin.NewCommand(banUser, "ban",
laniakea.NewCommandArg("user_id").
SetValueType(laniakea.CommandValueIntType).
SetRequired(),
),
)
```
This lets the framework validate:
- required argument presence
- integer/string/bool shape
- custom regex-based restrictions through the argument configuration
If validation fails, the command does not run and the bot error path is used.
## Payload handlers
Payload handlers are for callback data coming from inline keyboard buttons.
Register them with `NewPayload(...)` or `AddPayload(...)`:
```go
func confirmDelete(ctx *laniakea.MsgContext, db *App) error {
ctx.EditCallback("Deleted", nil)
return nil
}
plugin.AddPayload(plugin.NewPayload(confirmDelete, "delete.confirm"))
```
Payload handlers:
- are triggered by callback payload command names
- use the same handler signature as normal commands
- receive parsed payload args in `ctx.Args`
Use payloads when the trigger source is a button press, not a text command.
## Update handlers
Update handlers are for Telegram updates outside the normal command/payload flow.
Register them with `AddUpdateHandler(...)`:
```go
plugin.AddUpdateHandler(tgapi.UpdateTypeInlineQuery, func(ctx *laniakea.MsgContext, db *App) error {
// handle inline query here
return nil
})
```
This is the right tool for update types like:
- `inline_query`
- `chosen_inline_result`
- `poll`
- `chat_member`
- other non-command updates
Important:
- `message`
- `channel_post`
- `callback_query`
stay on the command/payload flow and are not meant to be registered through `AddUpdateHandler(...)`.
## The runtime flow
For text commands:
1. Telegram update arrives
2. bot prepares `MsgContext`
3. bot middleware runs
4. matching plugin is found
5. plugin middleware runs
6. command argument validation runs
7. command-specific middleware runs
8. command handler runs
9. returned error, if any, goes through centralized error handling
For callback payloads, the same idea applies, except the trigger comes from decoded callback data instead of text command parsing.
## Middleware placement
You have two main middleware levels:
### Plugin middleware
Added with:
```go
plugin.AddMiddleware(...)
```
Use this for logic shared by most handlers in the plugin.
### Command-specific middleware
Added with:
```go
plugin.NewCommand(handler, "name").Use(middleware)
```
Use this when only one command or payload needs the check.
See [[Middleware]] for behavior details.
## Good plugin boundaries
Good plugin grouping usually follows one of these patterns:
- by business domain: `billing`, `admin`, `profile`
- by update source: `inline`, `support`, `moderation`
- by ownership: one plugin per subsystem or package
Avoid one giant plugin for the entire bot unless the bot is very small.
## Examples
### Example: admin command with plugin middleware
```go
admin := laniakea.NewPlugin[*App]("admin")
admin.AddMiddleware(laniakea.NewMiddleware("admin-only", func(ctx *laniakea.MsgContext, app *App) bool {
if !app.IsAdmin(ctx.FromID) {
ctx.Answer("Access denied")
return false
}
return true
}))
admin.AddCommand(admin.NewCommand(func(ctx *laniakea.MsgContext, app *App) error {
ctx.Answer("Banned")
return nil
}, "ban"))
```
### Example: payload handler for inline keyboard callback
```go
plugin.AddPayload(plugin.NewPayload(func(ctx *laniakea.MsgContext, app *App) error {
ctx.AnswerCbQueryText("Accepted")
ctx.EditCallback("Done", nil)
return nil
}, "approve"))
```
## Common mistakes
### Putting the slash into command names
Wrong:
```go
plugin.NewCommand(start, "/start")
```
Right:
```go
plugin.NewCommand(start, "start")
```
### Treating payloads like commands
Payloads are not matched from text messages. They come from button callback data.
### Using `AddUpdateHandler(...)` for command updates
Reserved update types like `message`, `channel_post`, and `callback_query` belong to the normal command/payload pipeline.
### Returning errors for normal user-facing branching
Not every branch is an error. For normal usage failures, often the better pattern is:
```go
ctx.Answer("Usage: /ban <id>")
return nil
```
Return an error when the failure is genuinely exceptional or when you want the centralized error flow.
## When to use what
Use:
- commands for slash-prefixed user messages
- payload handlers for inline button callbacks
- update handlers for other Telegram update types
- plugin middleware for shared checks
- command middleware for narrow, local checks
## Where to go next
- Read [[MsgContext]] next to understand what handlers can do once they are triggered.
- Read [[Inline-Keyboards-and-Payloads]] if you are starting to use buttons and callback data.
- Read [[Middleware]] for execution-order and async details.
+9
@@ -0,0 +1,9 @@
# Drafts
Drafts provide a staged way to accumulate and then flush messages.
## This page should cover
- `DraftProvider`, `Draft`, `Push`, and `Flush`;
- random vs linear draft IDs;
- validation and send-time behavior;
- when drafts are better than direct replies.
+10
@@ -0,0 +1,10 @@
# FAQ
This page should answer the recurring design and usage questions around Laniakea.
## This page should cover
- why handlers return `error`;
- why `Bot` is single-use;
- why `AnswerLong` is separate from `Answer`;
- why both JSON and Base64 payloads exist;
- how to choose between high-level helpers and `tgapi`.
+261
@@ -0,0 +1,261 @@
# Getting Started
Start here if you are integrating Laniakea into a new bot for the first time.
This page covers the shortest path to a working bot, the minimum concepts you need to understand, and the most important defaults that affect startup and runtime behavior.
## What you need first
- Go 1.24 or newer
- a Telegram bot token from `@BotFather`
- a module that can import `git.nix13.pw/scuroneko/laniakea`
Install the module with one of:
```bash
go get git.nix13.pw/scuroneko/laniakea
```
or
```bash
go get github.com/scuroneko/laniakea
```
## The smallest useful bot
```go
package main
import (
"log"
"git.nix13.pw/scuroneko/laniakea"
)
func ping(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
ctx.Answer("Pong")
return nil
}
func main() {
bot, err := laniakea.NewBot[laniakea.NoDB](&laniakea.BotOpts{
Token: "TOKEN",
})
if err != nil {
log.Fatal(err)
}
defer bot.Close()
plugin := laniakea.NewPlugin[laniakea.NoDB]("main")
plugin.AddCommand(plugin.NewCommand(ping, "ping"))
bot.AddPlugins(plugin)
if err := bot.Run(); err != nil {
log.Fatal(err)
}
}
```
If the user sends `/ping`, the bot replies with `Pong`.
## The first things to understand
### 1. `NewBot[T]` uses a generic dependency type
The type parameter `T` is the shared dependency context passed into handlers, middleware, and runners.
Use:
- `laniakea.NoDB` when you do not need dependency injection
- a pointer type like `*sql.DB`, `*Store`, or `*App` when you do
Example:
```go
type App struct {
Users *sql.DB
}
app := &App{Users: db}
bot, err := laniakea.NewBot[*App](opts)
if err != nil {
return err
}
bot.DatabaseContext(app)
```
Pointer types are usually the right default for shared application state.
### 2. Commands live inside plugins
Laniakea does not register commands directly on the bot. The normal flow is:
- create a bot
- create one or more plugins
- add commands and middleware to plugins
- register plugins on the bot
Example:
```go
plugin := laniakea.NewPlugin[laniakea.NoDB]("admin")
plugin.AddCommand(plugin.NewCommand(ping, "ping"))
bot.AddPlugins(plugin)
```
See [[Commands-and-Plugins]] for the full model.
### 3. Handlers return `error`
The command handler signature is:
```go
func(ctx *laniakea.MsgContext, db T) error
```
This means:
- do your normal work inside the handler
- return `nil` on success
- return an error when you want centralized bot error handling
Example:
```go
func profile(ctx *laniakea.MsgContext, db *App) error {
user, err := db.LoadUser(ctx.FromID)
if err != nil {
return err
}
ctx.Answerf("Hello, %s", user.Name)
return nil
}
```
### 4. `Run()` is not reusable
A `Bot` instance is single-use.
After `Run()` or `RunWithContext(...)` returns:
- do not call `Run()` again on the same bot
- create a new bot instance for the next run
This is an intentional lifecycle rule, not a temporary limitation.
See [[Bot-Lifecycle]] for details.
### 5. Always close the bot
`RunWithContext(...)` and `Run()` do not replace `Close()`.
You should still release bot-owned resources explicitly:
```go
defer bot.Close()
```
## Recommended startup sequence
For most bots, this order is the least surprising:
1. Build `BotOpts`
2. Call `NewBot[T](opts)`
3. Attach database context, localization, or other configuration
4. Create plugins
5. Add commands, payloads, and middleware to plugins
6. Register plugins with `AddPlugins(...)`
7. Optionally call `AutoGenerateCommands()`
8. Call `Run()` or `RunWithContext(...)`
9. Call `Close()` when done
## A slightly more realistic example
```go
package main
import (
"log"
"git.nix13.pw/scuroneko/laniakea"
)
type App struct{}
func echo(ctx *laniakea.MsgContext, app *App) error {
if ctx.Text == "" {
ctx.Answer("Send some text after the command.")
return nil
}
ctx.Answer(ctx.Text)
return nil
}
func main() {
bot, err := laniakea.NewBot[*App](&laniakea.BotOpts{
Token: "TOKEN",
Debug: true,
})
if err != nil {
log.Fatal(err)
}
defer bot.Close()
bot.DatabaseContext(&App{})
plugin := laniakea.NewPlugin[*App]("main")
plugin.AddCommand(plugin.NewCommand(echo, "echo"))
bot.AddPlugins(plugin)
if err := bot.AutoGenerateCommands(); err != nil {
log.Println(err)
}
if err := bot.Run(); err != nil {
log.Fatal(err)
}
}
```
This bot:
- enables debug logging
- injects an application dependency
- registers a command through a plugin
- generates Telegram command metadata
- echoes the command text back to the user
## Common first-run pitfalls
### Missing token
`NewBot(...)` validates the token configuration and returns an error if it is missing.
### No plugins
Running a bot without registered plugins is invalid. The bot expects at least one plugin before start.
### No prefixes
The bot also requires command prefixes. If you do not configure them, the default is usually `"/"`.
### Forgetting that handlers receive parsed command text
For commands, `ctx.Text` contains the text after the command itself, not the original raw message.
Example:
- incoming message: `/echo hello world`
- command name: `echo`
- `ctx.Text`: `hello world`
- `ctx.Args`: `[]string{"hello", "world"}`
### Using value types for shared dependencies
This often works, but it is easy to accidentally copy state.
Prefer pointer types unless you have a strong reason not to.
## Where to go next
- Read [[Commands-and-Plugins]] next if you want to build the handler layer correctly.
- Read [[MsgContext]] next if you want to understand reply, edit, callback, and draft helpers.
- Read [[Bot-Lifecycle]] if you need shutdown, worker, or startup details.
+30 -1
@@ -1 +1,30 @@
Добро пожаловать в вики.
# Laniakea Wiki
Laniakea is a Go framework and Telegram Bot API wrapper built around plugins, typed handlers, middleware, and explicit control over update and reply flow.
Use this wiki as the structured companion to the README: start with setup, then move through commands, context, keyboards, and lower-level API usage.
Current fill plan: [[Page-Priority]]
## Start here
- [[Getting-Started]]
- [[Commands-and-Plugins]]
- [[MsgContext]]
## Core API
- [[Inline-Keyboards-and-Payloads]]
- [[tgapi-Overview]]
- [[Bot-Lifecycle]]
- [[Middleware]]
## Changes and troubleshooting
- [[Migration]]
- [[FAQ]]
## Additional topics
- [[Drafts]]
- [[Localization]]
- [[Rate-Limiting]]
- [[Recipes]]
- [[Semver-and-Releases]]
- [[Page-Priority]]
+10
@@ -0,0 +1,10 @@
# Inline Keyboards and Payloads
This page documents how Laniakea builds inline keyboards and encodes callback payloads.
## This page should cover
- `InlineKeyboard` builders and row layout;
- JSON vs Base64 callback payloads;
- bot default payload type vs keyboard-local override;
- strict payload mode and tolerant fallback behavior;
- payload size and compatibility guidance.
+9
@@ -0,0 +1,9 @@
# Localization
Localization in Laniakea is centered around `L10n` and key-based translation lookup.
## This page should cover
- fallback language behavior;
- attaching localization to the bot;
- `MsgContext.Translate`;
- organizing dictionaries and keeping them maintainable.
+10
@@ -0,0 +1,10 @@
# Middleware
Middleware lets you run logic before commands, payloads, and update handlers.
## This page should cover
- synchronous vs asynchronous middleware;
- stop/continue behavior;
- ordering expectations;
- race and mutation caveats for async middleware;
- where middleware fits relative to plugins and handlers.
+9
@@ -0,0 +1,9 @@
# Migration
Use this page to track version-to-version changes that affect existing bots.
## This page should cover
- breaking changes by release;
- migration notes for major release-candidate milestones;
- changed defaults and behavior contracts;
- links to [[Semver-and-Releases]] and `CHANGELOG.md`.
+358
@@ -0,0 +1,358 @@
# MsgContext
`MsgContext` is the runtime object passed into command handlers, payload handlers, middleware, and update handlers.
It gives you access to:
- the incoming update
- the current message and sender
- parsed command or payload arguments
- reply, edit, delete, callback, draft, and localization helpers
If you write handlers, `MsgContext` is the API surface you will use most often.
## The fields you will use first
### `Text`
`ctx.Text` is the parsed text payload after the command name.
Example:
- incoming message: `/echo hello world`
- command: `echo`
- `ctx.Text == "hello world"`
This is usually the easiest field to use for simple commands.
### `Args`
`ctx.Args` is the tokenized version of `ctx.Text`.
Example:
- `ctx.Text == "hello world"`
- `ctx.Args == []string{"hello", "world"}`
Use this when you want simple positional arguments.
### `Msg`
`ctx.Msg` points to the current Telegram message when the current update has one.
You will often use it for:
- chat ID
- thread ID
- original message metadata
Not every update has a message. For some non-message update types, `ctx.Msg` is nil.
### `From` and `FromID`
`ctx.From` is the sender user when one exists.
`ctx.FromID` is the same senders numeric ID, extracted for convenience.
Use `FromID` when you only need the identifier and do not want to keep checking for nil.
## The helpers you will use most often
### `Answer`
Use `Answer(...)` for the normal “reply with text” case.
```go
func start(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
ctx.Answer("Welcome")
return nil
}
```
This is the default high-level reply helper for plain text.
### `AnswerLong`
Use `AnswerLong(...)` when plain text may exceed Telegrams message limit.
```go
func help(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
ctx.AnswerLong(buildLargeHelpText())
return nil
}
```
Important:
- this is explicit on purpose
- normal `Answer(...)` keeps single-message semantics
- `AnswerLong(...)` may send multiple messages
### `Keyboard`
Use `Keyboard(...)` when you want to send a message with an inline keyboard.
```go
func menu(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
kb := ctx.NewInlineKeyboard(2).
AddCallbackButton("Profile", "profile.open").
AddCallbackButton("Settings", "settings.open")
ctx.Keyboard("Choose an action", kb)
return nil
}
```
### `KeyboardLong`
Use `KeyboardLong(...)` when plain text may be too long and the keyboard should stay attached to the final chunk.
This is useful for:
- long help text
- generated summaries
- reports with an action button at the end
## Markdown helpers
Use:
- `AnswerMarkdown(...)`
- `KeyboardMarkdown(...)`
- `EditCallbackMarkdown(...)`
- other `...Markdown` variants
Important rule:
- user input must be escaped before passing it into MarkdownV2 helpers
Use `laniakea.EscapeMarkdownV2(...)` for this.
Example:
```go
func whoami(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
name := laniakea.EscapeMarkdownV2(ctx.From.FirstName)
ctx.AnswerMarkdown("*User:* " + name)
return nil
}
```
## Editing and deleting
Once you already have an `AnswerMessage`, you can edit or delete it.
Example:
```go
func slowTask(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
msg := ctx.Answer("Working...")
if msg == nil {
return nil
}
// do work
msg.Edit("Done")
return nil
}
```
Available patterns include:
- `Edit(...)`
- `EditMarkdown(...)`
- `EditCaption(...)`
- `Delete()`
These methods assume a single concrete message target.
That is why multi-message helpers like `AnswerLong(...)` are separate APIs.
## Callback-specific helpers
When handling inline button callbacks, these helpers are especially useful.
### `EditCallback`
Edits the callback-linked message.
```go
func approve(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
ctx.EditCallback("Approved", nil)
return nil
}
```
### `AnswerCbQuery`
Acknowledges the callback query itself.
Use:
- `AnswerCbQuery()` for empty acknowledgement
- `AnswerCbQueryText(...)` for a short notice
- `AnswerCbQueryAlert(...)` for a visible alert
- `AnswerCbQueryUrl(...)` for redirect behavior
Example:
```go
func approve(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
ctx.AnswerCbQueryText("Saved")
ctx.EditCallback("Saved", nil)
return nil
}
```
### `CallbackDelete`
Deletes the message that triggered the callback.
Use this only when that behavior is really clear to the user.
## Photos and captions
Use:
- `AnswerPhoto(...)`
- `AnswerPhotoKeyboard(...)`
- `AnswerPhotoMarkdown(...)`
These helpers are for sending a photo with an optional caption.
Caption rules differ from normal message text:
- captions have a smaller Telegram limit
- caption editing uses the caption-specific edit helpers
## Drafts
`MsgContext` also exposes draft creation helpers:
- `NewDraft()`
- `NewDraftMarkdown()`
Drafts are useful when:
- a response is built incrementally
- you want to stage text before flushing
- the workflow benefits from draft IDs or batching behavior
For ordinary one-shot replies, `Answer(...)` is simpler.
See [[Drafts]] for the full model.
## Localization
Use:
```go
ctx.Translate("some.key")
```
This looks up text using the current users language when available and falls back to the configured default language.
Example:
```go
func ping(ctx *laniakea.MsgContext, db laniakea.NoDB) error {
ctx.Answer(ctx.Translate("ping.answer"))
return nil
}
```
See [[Localization]] for setup and dictionary structure.
## `NewInlineKeyboard`
The recommended way to build keyboards inside handlers is:
```go
kb := ctx.NewInlineKeyboard(2)
```
This is important because it inherits the bots default payload configuration automatically.
A keyboard can still override its own payload type locally if needed.
See [[Inline-Keyboards-and-Payloads]].
## Sending chat actions
Use `SendAction(...)` to show activity like typing or uploading.
Example:
```go
func report(ctx *laniakea.MsgContext, db *App) error {
ctx.SendAction(tgapi.ChatActionTyping)
text, err := db.BuildReport(ctx.FromID)
if err != nil {
return err
}
ctx.AnswerLong(text)
return nil
}
```
This is especially useful for slower handlers.
## Error handling inside handlers
A common pattern is:
```go
func profile(ctx *laniakea.MsgContext, db *App) error {
user, err := db.LoadUser(ctx.FromID)
if err != nil {
return err
}
ctx.Answer(user.Name)
return nil
}
```
You usually do not call `ctx.Error(...)` directly in normal handlers unless you intentionally want immediate explicit error messaging there.
The more idiomatic pattern is:
- return `error`
- let the bots centralized error flow handle it
## Common pitfalls
### `ctx.Msg` can be nil
Do not assume every update has a message object.
This especially matters in custom update handlers.
### `Answer(...)` and `Edit(...)` are not interchangeable
`Answer(...)` creates a new message.
`Edit(...)` changes an existing one and requires a valid target.
### Long replies are explicit
If the text may exceed Telegrams normal message limit, use `AnswerLong(...)` or `KeyboardLong(...)`.
### Markdown helpers require escaping
Do not pass raw user input to MarkdownV2 methods without escaping.
### Callback helpers only make sense in callback flow
Methods like `EditCallback(...)` and `AnswerCbQueryText(...)` depend on callback-specific context.
## A practical example
```go
func settings(ctx *laniakea.MsgContext, db *App) error {
kb := ctx.NewInlineKeyboard(1).
AddCallbackButton("Enable notifications", "settings.notifications.enable").
AddCallbackButton("Disable notifications", "settings.notifications.disable")
ctx.Keyboard("Notification settings", kb)
return nil
}
```
This example uses:
- a handler
- `ctx.NewInlineKeyboard(...)`
- callback payload routing
- `ctx.Keyboard(...)`
That is a typical Laniakea interaction pattern.
## Where to go next
- Read [[Inline-Keyboards-and-Payloads]] if you are building button-driven flows.
- Read [[Commands-and-Plugins]] if you want the full handler registration model.
- Read [[Drafts]] if you need staged or multi-step message assembly.
+30
@@ -0,0 +1,30 @@
# Page Priority
This page tracks the recommended fill order for the wiki while documentation is still being built out.
## Priority 1
- [[Getting-Started]]
- [[Commands-and-Plugins]]
- [[MsgContext]]
- [[Inline-Keyboards-and-Payloads]]
- [[tgapi-Overview]]
## Priority 2
- [[Bot-Lifecycle]]
- [[Middleware]]
- [[Migration]]
- [[FAQ]]
## Priority 3
- [[Drafts]]
- [[Localization]]
- [[Rate-Limiting]]
- [[Recipes]]
## Priority 4
- [[Semver-and-Releases]]
## Notes
- Keep `Home.md` ordered the same way.
- Within each page, explain the most necessary and most frequently used APIs first.
- Add new pages into this list before writing large amounts of content for them.
+9
@@ -0,0 +1,9 @@
# Rate Limiting
This page explains how Laniakea applies request throttling and reacts to Telegram rate-limit responses.
## This page should cover
- configured limiter behavior;
- drop mode vs waiting;
- `retry_after` handling;
- practical tuning guidelines for different bot sizes.
+11
@@ -0,0 +1,11 @@
# Recipes
This page should collect short, task-focused examples for common bot patterns.
## This page should cover
- admin-only commands;
- callback button flows;
- long replies;
- file uploads;
- localized commands;
- custom update handlers.
+9
@@ -0,0 +1,9 @@
# Semver and Releases
This page is for maintainers and contributors who need the projects release rules in one place.
## This page should cover
- what counts as public API;
- what is considered a breaking change;
- how version numbers are chosen;
- how changelog sections map to published tags.
+10
@@ -0,0 +1,10 @@
# tgapi Overview
`tgapi` is the lower-level Telegram API layer used by Laniakea.
## This page should cover
- the difference between `API` and `Uploader`;
- when to use typed helpers vs low-level request builders;
- context-aware methods;
- request/response modeling and Telegram wire compatibility;
- where `tgapi` ends and higher-level bot behavior begins.