Configuration¶
The config file describes your whole bot: the Telegram
connection, who may use it, the button menu, and logging.
You pass it with --config to the commands that read it — run, validate,
fmt, and list-functions (see CLI).
All keys use lower_snake_case. Unknown keys are rejected, so a typo is an
error you will see immediately when you validate.
Required means validation fails if the field is missing or empty after
defaults are applied.
Optional fields may be omitted; the Default column shows what is used then.
New to the project? Start with Run in CLI, which walks through building a first config. See Concepts for the vocabulary used below.
A minimal config¶
Only telegram (with a token and one allowed user)
and menu are required. Everything else has a default:
Start with one allowed user and three status buttons
telegram:
bot_token: "YOUR_BOT_TOKEN"
allowed_users:
- "123456789"
menu:
- name: System Status
type: category
icon: "🖥️"
items:
- name: Uptime
type: button
icon: "🕒"
function: command
command: "uptime"
- name: Memory
type: button
icon: "🧮"
function: command
command: "free -h"
- name: Disk Space
type: button
icon: "💾"
function: command
command: "df -h /"
The config-examples/ folder in the release includes both a minimal and a full
example.
Root fields¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
telegram |
object | yes | — | Telegram settings (see below) |
menu |
list | yes | — | Menu tree; at least one node |
function_directory |
string | no | unset | Custom function YAML directory (see rules below) |
shell |
string | no | /bin/bash |
Shell used as shell -c "<command>" |
timeout |
duration | no | 60s |
Default command timeout |
max_output_bytes |
int | no | 524288 |
Max output kept per command (see How much command output you see and Control output) |
output |
auto | text | file |
no | auto |
How command results are delivered (see How much command output you see and Control output) |
max_output_messages |
int | no | 2 |
Root only. In auto mode, send a .txt file when the result would need more than this many messages (1–10). Omit it to keep 2. See Control output |
workdir |
string | no | process cwd | Default working directory for commands |
env |
map | no | empty | Extra environment variables for commands |
menu_columns |
int | no | 2 |
Item buttons per row under the message box |
page_size |
int | no | 8 |
Items per page before pagination |
confirm_ttl |
duration | no | 5m |
How long a confirmation prompt stays valid |
delivery_retry_backoff |
duration | no | 1s |
Root only. Initial wait before the first retry after a send to Telegram fails. See Delivery retries |
delivery_retry_backoff_max |
duration | no | 30s |
Root only. Longest wait between retries. See Delivery retries |
delivery_retry_ttl |
duration | no | 2m |
Root only. Total time the bot keeps retrying before it gives up (logged on the server only). See Delivery retries |
enable_run_command |
bool | no | false |
Show a $ >_ Run Command button that runs the next message as a shell command. Off by default. Anyone who can use the bot can then run any command on the host, so only turn this on if you trust every allowed user. Putting this key under telegram is invalid. |
logging |
object | no | built-in default logger | Named loggers (see below) |
What if I omit shell?
You can omit it. The bot uses /bin/bash. Same for timeout, page_size,
and other optional root fields: omit them and defaults apply. You only need
to set them when you want a non-default value (for example
shell: /bin/sh).
How much command output you see¶
Two limits apply, one after the other. max_output_bytes is your limit and
comes on top of a Telegram limit you cannot change.
1. Your limit: max_output_bytes (default 524288, so 512 KB)
While a command runs, the bot keeps at most this much of its output, counted
separately for normal output and error output. Anything past that is dropped,
but the command itself keeps running until it finishes or hits its timeout.
When this happens, the result starts with (output truncated).
2. How the bot delivers the result: output (default auto)
Telegram allows at most 4096 bytes in one message. The bot can either split a
long result into several reply messages, or send the full result as a .txt
file. Choose the mode with output on the root config, or override it on a
single button:
| Value | Behaviour |
|---|---|
auto |
Use text messages while the result fits in max_output_messages messages (default 2). If it would need more, send one .txt file instead. |
text |
Always split into text messages. Still stops after 10 messages and notes that more was cut. |
file |
Always send one .txt file with a short caption (button name, exit code, duration). |
In auto and file modes, the file includes the header plus stdout and
stderr, so raising max_output_bytes really does deliver more output to you.
If sending the file fails, the bot retries automatically and only falls back
to the text-message path once it gives up. See Delivery retries.
You do not need to write output or max_output_messages. If you omit them,
the bot uses auto and 2. A config that already works stays the same.
max_output_messages exists only at the root. On a button, omit output to
use the root value; set it only when that one button should always send a file
or always stay as text.
So for long logs, prefer output: auto (the default) or set output: file on
that button. You can still shorten the command itself when you only need a
tail of the log.
More on this: Control output
A whole page is dedicated to these three fields. It walks through every root and button combination, one at a time, and shows a picture of the Telegram chat for each one.
function_directory rules¶
| Situation | Result |
|---|---|
| Key missing | Info log; built-in functions only |
Key present but empty ("") |
Info log; built-in functions only |
| Key set to a path that does not exist or is not accessible | Hard error; process stops |
| Path exists but directory is empty | OK |
A wrong path stops the bot
If function_directory points to a folder that does not exist or cannot be
read, the program stops with an error instead of starting without your
custom functions.
telegram¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
bot_token |
string | yes | — | Bot token from BotFather |
allowed_users |
list of string | yes | — | Allowed users |
api |
string | no | https://api.telegram.org |
Bot API base URL |
proxy.enabled |
bool | no | false |
Use proxy for Telegram API |
proxy.url |
string | conditional | — | Required when proxy.enabled is true |
insecure |
bool | no | false |
Skip TLS verify (not recommended) |
Unauthorized users receive a message with their user_id and username so they can ask an admin for access. This is also how you find your own id the first time — see Run in CLI → Step 5.
Connect through a proxy
To let allowed users type a shell command from Telegram, set this at the root of the file (not under telegram):
Menu¶
This section is the field reference. For a guided explanation with examples, see Menu. Each button or category node:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Display name (unique among siblings, case-insensitive) |
type |
category | button |
yes | Node kind |
items |
list | yes if category |
Children; category must have at least one |
function |
string | yes if button |
Function name |
command |
string | yes if function: command |
Shell command for built-in command |
path |
string | yes if function: script |
Script path for built-in script |
icon |
string | no | Optional emoji prefix |
id |
string | no | Optional id for this node. You can omit it |
confirm |
bool | no | Ask for confirmation before run (default false) |
timeout |
duration | no | Override global timeout |
workdir |
string | no | Override working directory |
env |
map | no | Extra env for this button |
columns |
int | no | Override columns for this category |
output |
auto | text | file |
no | Optional. Omit it to use the root output value. Set it only to force this button to file or text (see How much command output you see and Control output) |
args |
string | no | Optional args for script |
| Any declared parameter name | scalar | as declared by the function | Value passed to the selected function, for example url, host, unit, or lines |
On a button, any other scalar key is treated as a function parameter.
Its name must match a parameter declared by the selected function. Unknown
parameter names fail validate. Values declared as int or
bool are also checked. Strings, numbers, and booleans can be written directly
as YAML values; numbers do not need quotes.
On a category, any key outside the category fields above is an error. Categories do not run functions, so they cannot have parameter keys.
command, path, and args are shortcut fields that fill parameters with the
same names. Other parameter names are written directly
on the button. Do not place button values inside a nested params: map. See
Functions → Passing values from a button.
logging¶
Optional. If omitted, a default console logger on stderr at info is used.
Named loggers:
Write normal logs and an audit file
Supported outputs: stdout, stderr, file, discard.
The audit logger shown above records every command run (who, which button,
exit code, duration). See Audit log.
Related pages¶
- Run in CLI — build and run a first config
- Menu — the menu tree in depth
- Delivery retries — automatic retry after a short network drop
- Control output — messages versus a
.txtfile, with every root and button combination - Functions — what
function,command,path, andargsmean - CLI — validate and run with your config