| name | headless-bot |
| description | Nested swiss-knife reference for creating and operating a headless LingTai bot project without opening the TUI. Start from `lingtai-tui spawn`, then apply the relevant addon/MCP wiring, keep secrets in sidecar files, copy preset policy by referencing existing presets instead of copying preset JSON files, refresh or relaunch, and verify the bot safely. The bundled helper currently implements the Telegram MCP case.
|
| version | 1.1.0 |
| tags | ["utilities","bot","telegram","mcp","headless","bootstrap"] |
| last_changed_at | 2026-07-18T00:00:00Z |
| maintenance | If you find stale or incorrect information here, use the lingtai-issue-report skill to assemble evidence and obtain per-issue human consent before filing an issue. Never include secrets, credentials, tokens, or private paths. |
Headless Bot Project
Use this reference when a human asks for a LingTai-backed bot that should run as
its own project without stepping through the interactive TUI. The pattern is
channel-agnostic:
- Create a normal LingTai project with
lingtai-tui spawn.
- Write channel secrets into sidecar files under the agent directory.
- Activate the required addon/MCP entries in
init.json.
- Copy or construct the agent's preset policy (
manifest.preset) by
referencing the intended saved/template presets.
- Refresh or relaunch the agent and verify the channel end-to-end.
Do not fabricate .lingtai/ by hand. The supported bootstrap entrypoint remains
lingtai-tui spawn. The helper bundled here currently provisions Telegram bots;
future helpers for other chat surfaces should live under this same generic
reference rather than creating channel-specific top-level skill names.
Inputs
Common inputs:
PROJECT_DIR: new project directory. It must not already contain .lingtai/.
PRESET: saved or template preset name for the initial lingtai-tui spawn.
AGENT_NAME: agent directory/name to create under .lingtai/.
LANGUAGE: one of en, zh, or wen.
- Optional source agent
init.json if the new bot should inherit the same
manifest.preset policy as an existing orchestrator.
Telegram-specific inputs:
TELEGRAM_BOT_TOKEN: bot token from @BotFather. Keep it in the environment
or a local prompt, never in shell history, logs, git, issues, or docs.
ALLOWED_USERS: comma-separated Telegram numeric user IDs allowed to talk to
the bot.
Preferred Telegram Helper
Run the bundled helper. Use the installed-bundle path
~/.lingtai-tui/utilities/swiss-knife/reference/headless-bot/scripts/create_telegram_bot_project.py,
or the source-checkout path
tui/internal/preset/skills/swiss-knife/reference/headless-bot/scripts/create_telegram_bot_project.py:
read -rsp 'Telegram bot token: ' TELEGRAM_BOT_TOKEN; export TELEGRAM_BOT_TOKEN; echo
python3 <helper-path>/create_telegram_bot_project.py \
--project-dir /path/to/new-project \
--preset minimax \
--agent-name my-bot-agent \
--language en \
--allowed-users 123456789 \
--preset-policy-from /path/to/source-agent/init.json
The helper:
- Runs
lingtai-tui spawn <dir> --preset <name> --agent-name <name> --language <code>.
- Writes
<agent_dir>/.secrets/telegram.json with mode 0600.
- Adds
telegram to top-level addons.
- Adds top-level
mcp.telegram using the local LingTai runtime Python and
invokes lingtai.mcp_servers.telegram with args: ["-m", "lingtai.mcp_servers.telegram"];
it passes LINGTAI_TELEGRAM_CONFIG=.secrets/telegram.json.
- Optionally copies
manifest.preset from --preset-policy-from into the new
agent's init.json without copying any preset JSON files.
- Touches
<agent_dir>/.refresh so a running agent reloads the updated config.
If refresh is not enough for the installed runtime, relaunch or CPR the agent.
The helper intentionally reads TELEGRAM_BOT_TOKEN from the environment instead
of a command-line flag, because argv can be captured by shell history and process
monitors. Its output redacts token-like values. The --preset-policy-from flag
is optional; use it when the bot should inherit an existing agent's preset access
policy.
Preset Policy: Copy References, Not Preset Files
Headless bots often need access to the same model/preset choices as an existing
orchestrator. Do not grant that access by manually copying saved preset JSON
files into the new project's .lingtai/presets/saved/ directory. That creates
stale, duplicated configuration and can diverge from the user's real saved
presets.
Instead, patch the new agent's init.json so its manifest.preset block points
to the intended saved or template presets. If the bot should mirror an existing
agent, copy only that source agent's manifest.preset policy block:
python3 - <<'PY'
import json
from pathlib import Path
source_init = Path('/path/to/source-agent/init.json')
target_init = Path('/path/to/new-project/.lingtai/<agent-name>/init.json')
source = json.loads(source_init.read_text())
target = json.loads(target_init.read_text())
preset_policy = source.get('manifest', {}).get('preset')
if not isinstance(preset_policy, dict):
raise SystemExit(f'{source_init} has no manifest.preset policy object')
target.setdefault('manifest', {})['preset'] = preset_policy
target_init.write_text(json.dumps(target, indent=2, ensure_ascii=False) + '\n')
PY
Expected shape:
{
"manifest": {
"preset": {
"active": "~/.lingtai-tui/presets/saved/codex.json",
"default": "~/.lingtai-tui/presets/saved/codex.json",
"allowed": [
"~/.lingtai-tui/presets/saved/codex.json",
"~/.lingtai-tui/presets/saved/minimax_cn.json"
]
}
}
}
Keep this separate from secrets and MCP credentials. After changing the preset
policy, refresh or restart the agent and confirm the active preset in
.agent.json or the runtime logs.
Manual Telegram Workflow
Use this when you need to inspect or adapt each step. Replace placeholders, but
never paste a real token into committed files or chat transcripts.
lingtai-tui spawn "$PROJECT_DIR" \
--preset "$PRESET" \
--agent-name "$AGENT_NAME" \
--language "$LANGUAGE"
The command prints JSON containing agent_dir. Treat that as the only supported
source for the agent path.
Create the sidecar secret:
{
"accounts": [
{
"alias": "main",
"bot_token": "<redacted-telegram-bot-token>",
"allowed_users": [123456789]
}
],
"poll_interval": 1.0
}
Save it as:
<agent_dir>/.secrets/telegram.json
Then set restrictive permissions:
chmod 700 "<agent_dir>/.secrets"
chmod 600 "<agent_dir>/.secrets/telegram.json"
Patch <agent_dir>/init.json so these top-level keys exist:
{
"addons": ["telegram"],
"mcp": {
"telegram": {
"type": "stdio",
"command": "~/.lingtai-tui/runtime/venv/bin/python",
"args": ["-m", "lingtai.mcp_servers.telegram"],
"env": {
"LINGTAI_TELEGRAM_CONFIG": ".secrets/telegram.json"
}
}
}
}
If addons or mcp already exists, merge instead of replacing unrelated entries.
The command should point to the local LingTai runtime Python. On unusual
installs, resolve it with:
python3 - <<'PY'
from pathlib import Path
print(Path.home() / ".lingtai-tui" / "runtime" / "venv" / "bin" / "python")
PY
Refresh Or Relaunch
After writing init.json and channel secret files, refresh the running agent:
touch "<agent_dir>/.refresh"
If the listener does not appear in logs within a minute, inspect process state
before starting anything else:
lingtai-tui list "$PROJECT_DIR"
If the agent is stuck in a relaunch/dead loop, use the runtime lifecycle controls
available in your environment (for example suspend/CPR from an orchestrator) or
relaunch from the project. Do not start a second copy of the same agent without
checking lingtai-tui list first.
Verification Checklist
Run these checks before handing the bot to a user:
lingtai-tui list "$PROJECT_DIR" shows the new agent and no duplicate copy.
- Bot API
getMe succeeds. Redact the token in commands and logs:
python3 - <<'PY'
import json, os, urllib.request
token = os.environ["TELEGRAM_BOT_TOKEN"]
with urllib.request.urlopen(f"https://api.telegram.org/bot{token}/getMe", timeout=15) as r:
data = json.load(r)
print(json.dumps({"ok": data.get("ok"), "result": data.get("result", {})}, indent=2))
print("token: <redacted>")
PY
- The agent log shows the Telegram MCP/listener starting, without printing the
bot token.
- The runtime sees the intended preset policy; check
init.json, .agent.json,
or the logs after refresh/relaunch.
- Slash commands still work in the TUI, especially
/refresh, /doctor, and a
simple chat prompt.
- From an allowed Telegram account, send
/start to the bot and confirm the
agent responds.
- From a non-allowed account, confirm access is denied or ignored.
Security Rules
- Never commit
.secrets/telegram.json, .env, screenshots, terminal captures,
issue comments, or summaries containing a real bot token.
- Prefer
allowed_users; an omitted allowlist makes the bot reachable by anyone
who discovers it.
- Rotate the token in
@BotFather immediately if it appears in logs, git
history, chat, crash reports, or process arguments.
- Use placeholders such as
<redacted-telegram-bot-token> in examples. Do not use
realistic token-shaped dummy strings.
- Keep generated secret files mode
0600 and directories mode 0700 on shared
machines.