协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
headless-bot【开发与工程】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…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
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.1
tags: [utilities, bot, telegram, mcp, headless, bootstrap]
last_changed_at: "2026-09-29T00: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."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:
lingtai-tui spawn.init.json.manifest.preset) by
referencing the intended saved/template presets.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.
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.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.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 codex \
--agent-name my-bot-agent \
--language en \
--allowed-users 123456789 \
--preset-policy-from /path/to/source-agent/init.json
The helper:
lingtai-tui spawn <dir> --preset <name> --agent-name <name> --language <code>.<agent_dir>/.secrets/telegram.json with mode 0600.telegram to top-level addons.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.manifest.preset from --preset-policy-from into the new
agent's init.json without copying any preset JSON files.<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.
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.
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
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.
Run these checks before handing the bot to a user:
lingtai-tui list "$PROJECT_DIR" shows the new agent and no duplicate copy.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
init.json, .agent.json,
or the logs after refresh/relaunch./refresh, /doctor, and a
simple chat prompt./start to the bot and confirm the
agent responds..secrets/telegram.json, .env, screenshots, terminal captures,
issue comments, or summaries containing a real bot token.allowed_users; an omitted allowlist makes the bot reachable by anyone
who discovers it.@BotFather immediately if it appears in logs, git
history, chat, crash reports, or process arguments.<redacted-telegram-bot-token> in examples. Do not use
realistic token-shaped dummy strings.0600 and directories mode 0700 on shared
machines.