install-openclaw-to-yc
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseInstall OpenClaw to Yandex Cloud (Kazakhstan)
将OpenClaw安装到Yandex Cloud(哈萨克斯坦)
A wizard that takes a non-DevOps user from zero to a working OpenClaw bot on a fresh Yandex Cloud Kazakhstan VM in ~15 minutes. The user does exactly two-or-three things: paste a Telegram bot token, paste an LLM API key (or say "Codex" for OAuth via ChatGPT subscription), press in Telegram once, and — only for Codex — confirm a device code on auth.openai.com. Everything else is silent.
/start本向导可帮助非DevOps用户在约15分钟内,从0开始在哈萨克斯坦区域的Yandex Cloud虚拟机上部署可正常运行的OpenClaw机器人。用户仅需完成2-3项操作:粘贴Telegram机器人令牌、粘贴LLM API密钥(或选择“Codex”以通过ChatGPT订阅进行OAuth认证)、在Telegram中按下一次/start,以及(仅针对Codex方式)在auth.openai.com上确认设备代码。其余所有操作均自动静默完成。
Operating principles (the "don't bother the user" rules)
操作原则(“不打扰用户”规则)
These rules override the rest of the document. Read them first.
- Two questions. Total. The only inputs you ask the user for are the Telegram bot token and the LLM access (one of three options — see Step 1). Everything else — VM name, zone, image, SSH key, security-group ingress, chat_id — is decided silently from safe defaults or auto-detected.
- Never ask "are you sure" for actions inside this wizard's own scope (creating its own VM, its own security group, its own bot pairing). Only confirm if you're about to destroy something the user might want to keep (an existing VM with the same name).
- Never show shell commands, flags, paths, or stack traces to the user unless they explicitly ask "what did you run?". Progress is plain language: "Создаю VM…", "Ставлю OpenClaw…", "Проверяю что бот отвечает…".
- Validate inputs upfront with a one-call test (Telegram , LLM key probe). Don't burn 15 minutes on a VM bootstrap with a bad key.
/getMe - Auto-fix prerequisites silently when it's safe — install CLI, generate an SSH key, switch endpoint to Kazakhstan. Only stop and ask the user when something can't be done without their input (
ycOAuth login, no billing account).yc init - One language — and the bot speaks it too. If the user wrote to the agent in Russian, all wizard prompts are in Russian, and the OpenClaw bot itself is configured to reply in Russian. Detect the user's language from their first few messages, pass it through to cloud-init as (ISO 639-1:
{{USER_LANGUAGE}}/ru/en/...), and the bootstrap script appends a localization block to the bot'skk. Default if you can't tell:USER.md(workshop audience).ru - No emojis in user-facing text unless the user used them first.
这些规则优先于文档其他内容,请先阅读。
- 仅提两个问题。仅向用户请求Telegram机器人令牌和LLM访问方式(三种选项之一——见步骤1)。其余所有内容——虚拟机名称、可用区、镜像、SSH密钥、安全组入站规则、chat_id——均通过安全默认值自动决定或自动检测。
- 绝不询问“是否确定”。对于本向导自身范围内的操作(创建专属虚拟机、专属安全组、专属机器人配对),无需确认。仅当要销毁用户可能需要保留的内容(同名现有虚拟机)时,才需确认。
- 绝不向用户展示Shell命令、参数、路径或堆栈跟踪,除非用户明确询问“你执行了什么命令?”。进度用通俗易懂的语言展示:“正在创建虚拟机…”、“正在安装OpenClaw…”、“正在验证机器人回复…”。
- 提前验证输入。通过单次调用测试(Telegram 、LLM密钥探测)。避免因无效密钥导致虚拟机启动浪费15分钟时间。
/getMe - 安全时自动静默修复前置条件——安装CLI、生成SSH密钥、切换至哈萨克斯坦端点。仅当无法在无用户输入的情况下完成操作时(如
ycOAuth登录、无计费账户),才停止并询问用户。yc init - 单一语言——机器人也使用该语言。若用户用俄语与Agent交流,所有向导提示均为俄语,且OpenClaw机器人自身也会配置为俄语回复。从用户最初几条消息中检测语言,将其作为(ISO 639-1格式:
{{USER_LANGUAGE}}/ru/en/...)传递给cloud-init,引导脚本会将本地化块追加到机器人的kk中。若无法检测语言,默认使用USER.md(工作坊受众常用语言)。ru - 用户界面文本中不使用表情符号,除非用户先使用。
Do NOT ask the user for these (hard override)
绝对不要向用户询问以下内容(强制规则)
These are the things the wizard has been observed asking by mistake. Don't:
| Don't ask | Why | What to do instead |
|---|---|---|
| Telegram chat_id | Auto-detected in Step 4 from | Poll |
| VM name | Default is | Set silently. Tell user the name only in the final summary. |
| SSH IP restriction | Default is "current laptop IP, lock SSH to it". Detected via | Set silently. |
| Zone / region / subnet / image / VM shape | All hard-coded for YC Kazakhstan (kz1-a, ubuntu-2404-lts, standard-v3, 2 vCPU / 4 GB / 30 GB). | Don't surface to user. |
| Linux username on the VM | Always | Use it without asking. |
| Anthropic / OpenRouter / OpenAI billing balance | Caught upfront in Step 1 by a probe call. If insufficient, fail fast with a one-line message — don't ask "are you sure you topped up?". | Probe call before VM create. |
If you catch yourself drafting a question outside the two allowed inputs, re-read this section. The wizard's whole point is autonomy.
以下是向导曾错误询问过的内容,请勿询问:
| 请勿询问 | 原因 | 替代方案 |
|---|---|---|
| Telegram chat_id | 用户按下/start后,可在步骤4中通过 | 在步骤4中每2秒轮询 |
| 虚拟机名称 | 默认名称为 | 静默设置。仅在最终总结中告知用户名称。 |
| SSH IP限制 | 默认设置为“当前笔记本IP,仅允许该IP访问SSH”。通过 | 静默设置。 |
| 可用区/区域/子网/镜像/虚拟机规格 | 均为Yandex Cloud哈萨克斯坦区域硬编码配置(kz1-a、ubuntu-2404-lts、standard-v3、2 vCPU / 4 GB内存 / 30 GB存储)。 | 不向用户展示。 |
| 虚拟机上的Linux用户名 | 固定为 | 直接使用,无需询问。 |
| Anthropic / OpenRouter / OpenAI计费余额 | 在步骤1中通过探测调用提前检测。若余额不足,直接用单行消息快速失败——不要询问“你确定已充值?”。 | 创建虚拟机前执行探测调用。 |
若发现自己准备询问上述两项允许输入之外的问题,请重新阅读本节。向导的核心就是自主性。
When to invoke
触发时机
Trigger on: "install OpenClaw on Yandex Cloud", "set up my bot in YC Kazakhstan", "OpenClaw workshop workshop", "deploy OpenClaw remotely", "поставь себе openclaw", "разверни мне бота в Yandex Cloud", "у меня workshop-ключ", "вот bundle от организатора", and close paraphrases.
Do NOT use this skill for:
- Local-machine OpenClaw install → use in this repo (the user runs it on their laptop)
openclaw/install.sh - AWS / GCP / Azure / other Yandex Cloud regions → this skill is hard-coded for Yandex Cloud Kazakhstan (kz1-a)
- Adding a second agent or a second bot to an existing OpenClaw VM → out of scope
- Preparing the workshop as an organizer (creating N folders + keys for participants) → use (the matching organizer-side skill) — this skill is for the participant
prepare-yc-workshop
在用户提及以下内容时触发:“在Yandex Cloud上安装OpenClaw”“在YC哈萨克斯坦设置我的机器人”“OpenClaw工作坊”“远程部署OpenClaw”“поставь себе openclaw”“разверни мне бота в Yandex Cloud”“у меня workshop-ключ”“вот bundle от организатора”,以及类似表述。
请勿将本技能用于:
- 本地机器安装OpenClaw → 使用本仓库中的(用户在自己的笔记本上运行)
openclaw/install.sh - AWS / GCP / Azure / Yandex Cloud其他区域 → 本技能仅针对Yandex Cloud哈萨克斯坦区域(kz1-a)硬编码
- 在现有OpenClaw虚拟机上添加第二个Agent或第二个机器人 → 超出范围
- 作为组织者准备工作坊(为参与者创建N个文件夹+密钥) → 使用(对应的组织者端技能)——本技能面向参与者
prepare-yc-workshop
Two access modes (Plan A and Plan B)
两种访问模式(方案A和方案B)
This skill works in two modes — picked silently at Step 0 from what the user has on hand. The user is shown the choice only once in Step 1; after that, both branches converge and the rest of the wizard is identical.
| Mode | When | What the user supplies | Skill does |
|---|---|---|---|
| Plan A — own YC account (default) | The user has (or is willing to create) a Yandex Cloud Kazakhstan account. | OAuth token from | |
| Plan B — workshop bundle | The user is at a workshop, the organizer DM'd them a | Path to the | Parses the bundle, configures |
Plan B is recognised by detecting a workshop bundle file in any of these ways (auto-detected in Step 0.5 below):
- The user pasted a file path that resolves to a JSON whose starts with
$schema.openclaw-workshop-bundle@ - The user said one of: "у меня workshop-ключ", "вот bundle от организатора", "I have a workshop key", "organizer gave me a key file", "у меня нет своего Yandex Cloud, есть только ключ от воркшопа".
- A file matching is present in the user's current working directory or
bundle-*.json(offered with a one-line confirmation).~/Downloads
If none match, the wizard defaults to Plan A.
After Step 0.5 the two branches converge — Steps 1, 2, 3, 4, 5 are identical regardless of mode. Plan A and Plan B both end with a working YC profile pointing at one folder; everything downstream just uses that.
本技能支持两种模式——根据用户手头的资源在步骤0中自动静默选择。仅在步骤1中向用户展示一次选择;之后,两个分支会合并,向导其余流程完全一致。
| 模式 | 适用场景 | 用户需提供的内容 | 技能执行操作 |
|---|---|---|---|
| 方案A——自有YC账户(默认) | 用户拥有(或愿意创建)Yandex Cloud哈萨克斯坦账户。 | | 在向导专属配置文件中执行等效 |
| 方案B——工作坊密钥包 | 用户正在参加工作坊,组织者已通过私信发送 | 组织者发送的 | 解析密钥包,使用嵌入的服务账户密钥 + cloud-id + folder-id配置 |
通过以下任意方式自动检测方案B(在步骤0.5中自动检测):
- 用户粘贴的文件路径指向一个JSON文件,其以
$schema开头。openclaw-workshop-bundle@ - 用户提及以下内容之一:“у меня workshop-ключ”“вот bundle от организатора”“I have a workshop key”“organizer gave me a key file”“у меня нет своего Yandex Cloud, есть только ключ от воркшопа”。
- 用户当前工作目录或中存在匹配
~/Downloads的文件(用单行消息确认后使用)。bundle-*.json
若以上均不匹配,向导默认使用方案A。
步骤0.5之后,两个分支合并——无论使用哪种模式,步骤1、2、3、4、5均完全一致。方案A和方案B最终都会生成指向某个文件夹的有效YC配置文件;后续所有操作仅需使用该配置文件。
Inputs (the only two questions you ask)
输入内容(仅需询问的两个问题)
| # | Input | How user gets it (paste this verbatim in your prompt) |
|---|---|---|
| 1 | Telegram bot token | Open @BotFather in Telegram → send |
| 2 | LLM access — one of three options | See the table below. The user picks ONE option, the wizard auto-detects which one from the format of what they paste. |
| 序号 | 输入内容 | 用户获取方式(提示语直接复制使用) |
|---|---|---|
| 1 | Telegram机器人令牌 | 在Telegram中打开@BotFather → 发送 |
| 2 | LLM访问方式——三种选项之一 | 见下表。用户选择其中一种,向导根据用户粘贴内容的格式自动检测。 |
LLM access options (the user picks one)
LLM访问选项(用户选择其一)
| Option | What user pastes | Detection signal | Cost / requirements |
|---|---|---|---|
| A. Anthropic API key | Key starting with | Prefix | ≥$5 credit on console.anthropic.com/settings/billing. Best raw quality. Pay-as-you-go (~$3 per million input tokens for Sonnet 4.6). |
| B. OpenRouter API key | Key starting with | Prefix | ≥$5 credit on OpenRouter. Unified access to Anthropic + OpenAI + 200 other models through one key, ~5% markup over native. Good if user wants to A/B different models later. |
| C. OpenAI Codex via ChatGPT | The literal word | Token doesn't start with | Active ChatGPT Plus ($20/mo) or Pro ($200/mo) subscription. After VM bootstrap, the wizard prompts the user once on auth.openai.com with a device code — no API key needed, no metered billing. Plus gives |
Order of recommendation in the prompt: A → C → B for first-timers. A is the simplest happy path with the best Anthropic model. C is best for users who already pay for ChatGPT and want zero added bill. B is the power-user choice.
Everything below is decided without asking the user:
| Decided silently | Value | How |
|---|---|---|
| VM name | | If |
| Zone | | Only zone in YC Kazakhstan. |
| Subnet | | Auto-provisioned in any new KZ folder. |
| OS image | | From |
| VM shape | | Matches the reference deployment. |
| Public IP | yes, ephemeral IPv4 NAT | Simplest path for SSH from anywhere. |
| Linux user | | Created by cloud-init. |
| SSH key | | |
| SSH ingress | | |
| Outbound | open to anywhere | OpenClaw needs Anthropic, Telegram, OpenAI, OpenRouter, etc. — locking down by domain is fragile. |
| Telegram chat_id | auto-detected after first | Poll |
| Primary model | Depends on chosen LLM option, see table below | |
| Fallback models | Depends on chosen LLM option, see table below |
| 选项 | 用户粘贴内容 | 检测标识 | 成本/要求 |
|---|---|---|---|
| A. Anthropic API密钥 | 来自console.anthropic.com/settings/keys、以 | 前缀 | console.anthropic.com/settings/billing账户余额≥5美元。原始质量最佳。按需付费(Sonnet 4.6模型约每百万输入令牌3美元)。 |
| B. OpenRouter API密钥 | 来自openrouter.ai/keys、以 | 前缀 | OpenRouter账户余额≥5美元。通过一个密钥统一访问Anthropic + OpenAI + 其他200多种模型,比原生价格高约5%。适合之后想要对比测试不同模型的用户。 |
| C. 通过ChatGPT使用OpenAI Codex | 输入字面单词 | 令牌不以 | 有效的**ChatGPT Plus(每月20美元)或Pro(每月200美元)**订阅。虚拟机引导完成后,向导会在auth.openai.com上提示用户输入一次设备代码——无需API密钥,无需计量计费。Plus订阅可使用 |
提示语中的推荐顺序:A → C → B(针对首次使用者)。A是最简单的顺畅路径,搭配最佳的Anthropic模型。C适合已订阅ChatGPT且不想额外付费的用户。B是高级用户选择。
以下所有内容均无需询问用户,自动决定:
| 自动决定项 | 值 | 实现方式 |
|---|---|---|
| 虚拟机名称 | | 若 |
| 可用区 | | Yandex Cloud哈萨克斯坦区域唯一可用区。 |
| 子网 | | 任何新的KZ文件夹中都会自动预配置。 |
| 操作系统镜像 | | 来自 |
| 虚拟机规格 | | 与参考部署一致。 |
| 公网IP | 是,临时IPv4 NAT | 从任意位置访问SSH的最简单方式。 |
| Linux用户 | | 由cloud-init创建。 |
| SSH密钥 | | 若不存在,执行 |
| SSH入站规则 | | 通过 |
| 出站规则 | 允许访问任意地址 | OpenClaw需要访问Anthropic、Telegram、OpenAI、OpenRouter等——按域名锁定过于脆弱。 |
| Telegram chat_id | 首次按下/start后自动检测 | 轮询 |
| 主模型 | 取决于所选LLM选项,见下表 | |
| 备用模型 | 取决于所选LLM选项,见下表 |
Default models per LLM option
各LLM选项对应的默认模型
| Option | | |
|---|---|---|
| A. Anthropic | | |
| B. OpenRouter | | |
| C. OpenAI Codex | | |
For C, the wizard probes the user's subscription tier after OAuth completes — if isn't in , fall back to as primary.
gpt-5.5openclaw models listgpt-4o| 选项 | | |
|---|---|---|
| A. Anthropic | | |
| B. OpenRouter | | |
| C. OpenAI Codex | | |
对于选项C,向导会在OAuth完成后探测用户的订阅级别——若中没有,则回退为作为主模型。
openclaw models listgpt-5.5gpt-4oWizard flow
向导流程
Step 0 — Silent preflight (no user-facing output unless something breaks)
步骤0——静默预检(无问题则不向用户输出内容)
Run in order. Each block has a silent auto-fix path; only fall through to a user prompt when no silent path exists.
Critical Yandex Cloud Kazakhstan rules — read before touching :
yc- KZ has its own endpoint . The Russian endpoint
api.yandexcloud.kz:443and the KZ endpoint serve different clouds, folders, and OAuth realms. Mixing them is the #1 cause of "wizard says no billing / no cloud" when both exist.api.cloud.yandex.net:443 - Setting does NOT auto-update
yc config set endpoint api.yandexcloud.kz:443orcloud-id. If you only flip the endpoint and don't re-set cloud-id/folder-id, every subsequentfolder-idcommand will fail with NotFound, because those IDs belong to the RU realm.yc compute / vpc / resource-manager - The KZ endpoint exposes a smaller command set: ,
iam,quota-manager,resource-manager,compute,vpc,dns.managed-kubernetesdoes NOT exist on the KZ endpoint. Callingyc billingalways errors out — don't use it for any check.yc billing account list - Use named profiles () instead of editing the active config. The user almost certainly already has profiles for their other clouds — don't clobber them.
yc config profile create/activate
Step 0.5 — Detect mode (Plan A vs Plan B). Runs first, before anything else in Step 0.
Plan B short-circuits steps c, d, e (profile, OAuth, cloud-id/folder-id resolution) because the bundle already has all of that baked in. Plan A keeps them.
Detection order:
- Explicit file path in what the user said. Resolve the path; if it's a readable JSON whose field starts with
$schema, setopenclaw-workshop-bundle@andMODE=plan-b.BUNDLE_PATH=<path> - Phrase match. If the user wrote any of these (or close paraphrase) in the activation message:
- "У меня workshop-ключ" / "вот bundle от организатора" / "ключ от воркшопа"
- "I have a workshop key" / "organizer gave me a key file"
- "Bundle from the organizer is here:" → followed by path
- Then ask one clarifier: "Где лежит файл от организатора? (можешь перетащить файл в чат, или просто путь)" — accept the path, validate the
bundle-NN.json, set$schema.MODE=plan-b
- Auto-discovery. Glob in
bundle-*.json,$PWD,~/Downloads. If exactly one match whose~/Desktopstarts with$schema, ask once: "Нашёл workshop-ключopenclaw-workshop-bundle@вbundle-NN.json. Это от организатора? (да / нет)". On "да" →<path>. On "нет" → continue to next step.MODE=plan-b - Default. No bundle detected → . Don't ask "do you have a workshop key?" upfront — that's friction for the >50% of users who have their own YC and would treat the question as noise.
MODE=plan-a
Schema sanity check on the bundle file:
bash
SCHEMA=$(jq -r '."$schema" // empty' "$BUNDLE_PATH" 2>/dev/null)
[[ "$SCHEMA" =~ ^openclaw-workshop-bundle@ ]] \
|| { say "Это не похоже на workshop-bundle от организатора. Проверь, что прислали правильный файл."; stop; }按顺序执行。每个模块都有静默自动修复路径;仅当无静默修复路径时,才向用户提示。
Yandex Cloud哈萨克斯坦区域关键规则——操作前请阅读:
yc- KZ区域有独立端点。俄罗斯区域端点
api.yandexcloud.kz:443与KZ端点服务不同的云、文件夹和OAuth领域。混淆两者是“向导提示无计费/无云,但实际均存在”问题的头号原因。api.cloud.yandex.net:443 - 设置不会自动更新
yc config set endpoint api.yandexcloud.kz:443或cloud-id。若仅切换端点而未重新设置cloud-id/folder-id,后续所有folder-id命令都会因NotFound失败,因为这些ID属于俄罗斯领域。yc compute / vpc / resource-manager - KZ端点支持的命令集更小:、
iam、quota-manager、resource-manager、compute、vpc、dns。KZ端点不支持managed-kubernetes。调用yc billing总会报错——请勿用于任何检查。yc billing account list - 使用命名配置文件()而非编辑活动配置文件。用户几乎肯定已有其他云的配置文件——请勿覆盖。
yc config profile create/activate
步骤0.5——检测模式(方案A vs 方案B)。在步骤0的所有其他操作之前执行。
方案B会跳过步骤c、d、e(配置文件、OAuth、cloud-id/folder-id解析),因为密钥包已包含所有必要信息。方案A保留这些步骤。
检测顺序:
- 用户提及的明确文件路径。解析路径;若为可读JSON且字段以
$schema开头,则设置openclaw-workshop-bundle@和MODE=plan-b。BUNDLE_PATH=<path> - 短语匹配。若用户在触发消息中提及以下内容(或类似表述):
- "У меня workshop-ключ" / "вот bundle от организатора" / "ключ от воркшопа"
- "I have a workshop key" / "organizer gave me a key file"
- "Bundle from the organizer is here:" → 后跟路径
- 则询问一次澄清问题:“Где лежит файл от организатора? (можешь перетащить файл в чат, или просто путь)” ——接受路径,验证
bundle-NN.json,设置$schema。MODE=plan-b
- 自动发现。在、
$PWD、~/Downloads中查找~/Desktop文件。若找到唯一匹配且bundle-*.json以$schema开头的文件,则询问一次:“Нашёл workshop-ключopenclaw-workshop-bundle@вbundle-NN.json. Это от организатора? (да / нет)”。若用户回复“да” → 设置<path>。若回复“нет” → 继续下一步。MODE=plan-b - 默认值。未检测到密钥包 → 设置。请勿提前询问“你有工作坊密钥吗?”——这会给超过50%拥有自有YC账户的用户带来额外干扰。
MODE=plan-a
密钥包文件的Schema完整性检查:
bash
SCHEMA=$(jq -r '."$schema" // empty' "$BUNDLE_PATH" 2>/dev/null)
[[ "$SCHEMA" =~ ^openclaw-workshop-bundle@ ]] \
|| { say "Это не похоже на workshop-bundle от организатора. Проверь, что прислали правильный файл."; stop; }Required fields
必填字段
for f in cloud_id folder_id zone endpoint key; do
jq -er ".${f}" "$BUNDLE_PATH" >/dev/null
|| { say "В bundle не хватает поля ${f}. Попроси у организатора новый файл."; stop; } done
|| { say "В bundle не хватает поля ${f}. Попроси у организатора новый файл."; stop; } done
On any validation failure for Plan B, tell the user in one sentence what's wrong, advise asking the organizer, and stop — don't silently fall back to Plan A. Falling back would burn 10 minutes asking for OAuth they don't have.
**If `MODE=plan-b`**: configure `yc` from the bundle and skip directly to Step 0a, then `f`, then `g` (skipping `c`, `d`, `e`):
```bashfor f in cloud_id folder_id zone endpoint key; do
jq -er ".${f}" "$BUNDLE_PATH" >/dev/null
|| { say "В bundle не хватает поля ${f}. Попроси у организатора новый файл."; stop; } done
|| { say "В bundle не хватает поля ${f}. Попроси у организатора новый файл."; stop; } done
若方案B验证失败,用一句话告知用户问题所在,建议联系组织者,然后停止——请勿静默回退到方案A。回退会浪费10分钟询问用户没有的OAuth信息。
**若`MODE=plan-b`**:从密钥包配置`yc`,直接跳至步骤0a,然后是0f、0g(跳过c、d、e):
```bashWizard-owned profile so we don't disturb the user's other yc setups
使用向导专属配置文件,避免干扰用户其他yc设置
yc config profile create openclaw-workshop 2>/dev/null || true
yc config profile activate openclaw-workshop
yc config profile create openclaw-workshop 2>/dev/null || true
yc config profile activate openclaw-workshop
Carve the SA key into the shape yc config set service-account-key
expects
yc config set service-account-key将服务账户密钥转换为yc config set service-account-key
所需的格式
yc config set service-account-keyKEY_FILE="$(mktemp -t openclaw-sa-key.XXXXXX.json)"
jq '.key' "$BUNDLE_PATH" > "$KEY_FILE"
chmod 600 "$KEY_FILE"
yc config set service-account-key "$KEY_FILE"
yc config set endpoint "$(jq -r '.endpoint' "$BUNDLE_PATH")"
yc config set cloud-id "$(jq -r '.cloud_id' "$BUNDLE_PATH")"
yc config set folder-id "$(jq -r '.folder_id' "$BUNDLE_PATH")"
yc config set compute-default-zone "$(jq -r '.zone' "$BUNDLE_PATH")"
KEY_FILE="$(mktemp -t openclaw-sa-key.XXXXXX.json)"
jq '.key' "$BUNDLE_PATH" > "$KEY_FILE"
chmod 600 "$KEY_FILE"
yc config set service-account-key "$KEY_FILE"
yc config set endpoint "$(jq -r '.endpoint' "$BUNDLE_PATH")"
yc config set cloud-id "$(jq -r '.cloud_id' "$BUNDLE_PATH")"
yc config set folder-id "$(jq -r '.folder_id' "$BUNDLE_PATH")"
yc config set compute-default-zone "$(jq -r '.zone' "$BUNDLE_PATH")"
Verify it actually works — one read call against the configured folder
验证配置是否有效——对已配置文件夹执行一次读取操作
yc compute zone list --format json | jq -e '.[] | select(.id=="kz1-a")' >/dev/null
|| { say "Ключ от организатора не работает (или истёк). Напиши организатору: попроси новый bundle."; stop; }
|| { say "Ключ от организатора не работает (или истёк). Напиши организатору: попроси новый bundle."; stop; }
Plan-B-specific failure modes:
- **Schema older than `@1`** → bundle predates this version of the skill. Ask user to refresh from organizer; don't try to be smart.
- **Schema newer than what this skill recognises** → also ask for guidance from organizer (they updated `prepare-yc-workshop` past us). Bundle may still work — try the steps above and surface YC errors plainly.
- **`yc compute zone list` returns empty** → key was revoked or folder deleted. Tell the user: "Кажется, организатор уже свернул облако воркшопа. Свяжись с ним."
- **`yc compute zone list` returns `ru-central1-*`** instead of `kz1-a` → bundle's `endpoint` field was wrong. Surface plainly; this is an organizer-side bug.
**On `MODE=plan-b`, skip Step 0c, 0d, 0e entirely** and proceed to 0a → 0b → 0f → 0g. The bundle already contains a valid token-equivalent + cloud-id + folder-id, so re-asking for OAuth would be cruel and pointless.
**On `MODE=plan-a`, proceed normally** through Step 0a-g as written.
---
**a. Companion skill `openclaw-guide` must be loaded.** Probe the agent's skill loader. If it's not present, run `npx skills add CodeAlive-AI/ceo-ai-os@openclaw-guide -g` silently. If `npx` is unavailable, tell the user (one sentence) to install both skills manually, then stop.
**b. `yc` CLI installed.** `yc --version`. If missing: silently `curl -fsSL https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash -s -- -i $HOME/yandex-cloud -n` and add `~/yandex-cloud/bin` to PATH for this session.
**(c, d, e are Plan A only — skip on `MODE=plan-b`, which configured the profile from the bundle in Step 0.5.)**
**c. Activate a dedicated Kazakhstan profile.** Use a wizard-owned profile so we don't disturb the user's existing setup:
```bash
PROFILE_NAME=openclaw-kz
CURRENT_PROFILE=$(yc config profile list 2>/dev/null | awk '/ACTIVE/{print $1}')yc compute zone list --format json | jq -e '.[] | select(.id=="kz1-a")' >/dev/null
|| { say "Ключ от организатора не работает (или истёк). Напиши организатору: попроси новый bundle."; stop; }
|| { say "Ключ от организатора не работает (или истёк). Напиши организатору: попроси новый bundle."; stop; }
方案B特定失败场景:
- **Schema版本早于`@1`** → 密钥包早于本技能版本。请用户向组织者获取更新版本;请勿自行尝试兼容。
- **Schema版本晚于本技能支持的版本** → 同样请用户联系组织者(他们已更新`prepare-yc-workshop`至本技能之后的版本)。密钥包可能仍可使用——尝试执行上述步骤,直接展示YC错误信息。
- **`yc compute zone list`返回空** → 密钥已被撤销或文件夹已删除。告知用户:“Кажется, организатор уже свернул облако воркшопа. Свяжись с ним.”
- **`yc compute zone list`返回`ru-central1-*`而非`kz1-a`** → 密钥包的`endpoint`字段错误。直接展示问题;这是组织者端的错误。
**若`MODE=plan-b`,完全跳过步骤0c、0d、0e**,继续执行0a → 0b → 0f → 0g。密钥包已包含有效的令牌等效物 + cloud-id + folder-id,因此再次询问OAuth是不合理且无意义的。
**若`MODE=plan-a`,正常执行**步骤0a-g。
---
**a. 必须加载配套技能`openclaw-guide`**。探测Agent的技能加载器。若未加载,静默执行`npx skills add CodeAlive-AI/ceo-ai-os@openclaw-guide -g`。若`npx`不可用,用一句话告知用户手动安装两个技能,然后停止。
**b. 已安装`yc` CLI**。执行`yc --version`。若未安装:静默执行`curl -fsSL https://storage.yandexcloud.net/yandexcloud-yc/install.sh | bash -s -- -i $HOME/yandex-cloud -n`,并将`~/yandex-cloud/bin`添加至本次会话的PATH。
**(c、d、e仅适用于方案A——`MODE=plan-b`时跳过,因为步骤0.5已从密钥包配置好配置文件。)**
**c. 激活专属哈萨克斯坦配置文件**。使用向导专属配置文件,避免干扰用户现有设置:
```bash
PROFILE_NAME=openclaw-kz
CURRENT_PROFILE=$(yc config profile list 2>/dev/null | awk '/ACTIVE/{print $1}')If the user is already on a profile pointing at KZ, just use it.
若用户已在指向KZ区域的配置文件上,直接使用该配置文件。
if [[ "$CURRENT_PROFILE" != "$PROFILE_NAME" ]]; then
if [[ "$(yc config get endpoint 2>/dev/null)" != "api.yandexcloud.kz:443" ]]; then
# Create/activate our own profile rather than mutating the user's active one
yc config profile list 2>/dev/null | grep -qE "^${PROFILE_NAME}\b"
|| yc config profile create "$PROFILE_NAME" yc config profile activate "$PROFILE_NAME" fi fi
|| yc config profile create "$PROFILE_NAME" yc config profile activate "$PROFILE_NAME" fi fi
After this block, the active profile is either the user's pre-existing KZ-pointing profile (preserve their settings — they know what they're doing) or our fresh `openclaw-kz` profile (we'll fill it in steps d-f).
**d. OAuth token + endpoint on the active profile.** Check `yc config get token` and `yc config get endpoint`:
- Both already set, endpoint is KZ → ✅ skip ahead.
- Endpoint set to KZ but no token → ask the user once (see below).
- Token set but wrong endpoint → silently `yc config set endpoint api.yandexcloud.kz:443`.
- Nothing set (fresh profile) → ask the user once for an OAuth token.
The OAuth ask is **the only mandatory user prompt in Step 0**. Say exactly:
> Для работы с Yandex Cloud Kazakhstan нужен OAuth-токен (один раз). Открой в браузере:
>
> https://oauth.yandex.kz/authorize?response_type=token&client_id=1a6990aa636648e9b2ef855fa7bec2fb
>
> Войди под своим Yandex ID, разреши доступ. После редиректа браузер покажет URL вида `https://oauth.yandex.kz/verification_code#access_token=y0_XXXXXX…&token_type=bearer&expires_in=...`. Скопируй значение `access_token=…` (длинная строка между `=` и `&`) и пришли мне.
After receiving the token: `yc config set token <token>`, then set the endpoint **and** the zone in the same breath:
```bash
yc config set endpoint api.yandexcloud.kz:443
yc config set compute-default-zone kz1-acompute-default-zoneyc config set endpointyc compute *--zoneru-central1-ae. cloud-id and folder-id. After step d, the profile has a valid token. Now resolve the IDs:
bash
CLOUD_ID=$(yc config get cloud-id 2>/dev/null || true)
if [[ -z "$CLOUD_ID" ]]; then
CLOUD_ID=$(yc resource-manager cloud list --format json | jq -r '.[0].id // empty')
[[ -n "$CLOUD_ID" ]] && yc config set cloud-id "$CLOUD_ID"
fi
FOLDER_ID=$(yc config get folder-id 2>/dev/null || true)
if [[ -z "$FOLDER_ID" ]]; then
FOLDER_ID=$(yc resource-manager folder list --cloud-id "$CLOUD_ID" --format json | jq -r '.[0].id // empty')
[[ -n "$FOLDER_ID" ]] && yc config set folder-id "$FOLDER_ID"
fiFailure modes:
- returns empty → the OAuth token is for a Yandex ID that has no clouds in KZ. Tell the user: "Похоже, у тебя нет облака в Yandex Cloud Kazakhstan. Создай облако в https://kz.console.yandex.cloud, потом запусти меня снова." Stop.
cloud list - returns multiple → use the first, but tell the user one line: "Использую облако
cloud list. Если это не то — скажи, переключусь."<NAME> - Same logic for folder.
Do not call . It doesn't exist on the KZ endpoint. If the user has a cloud and a folder, billing is either active or will fail concretely at VM creation time with a clear error. Catching that one error in Step 2 is fine.
yc billing account listf. SSH key. . If missing: silently .
ls ~/.ssh/id_ed25519.pubssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" -C "openclaw-yc-$(date +%Y%m%d)"g. Existing instance with the same name in this cloud. . If a result comes back, ask once: "У тебя уже есть VM 'openclaw-bot' — поставить новую под именем ?" Default yes; pick a random 4-char suffix.
yc compute instance get --name openclaw-bot 2>/dev/nullopenclaw-bot-XXXXDo not print anything to the user about (a)-(g) if everything passed silently. Move to Step 1.
if [[ "$CURRENT_PROFILE" != "$PROFILE_NAME" ]]; then
if [[ "$(yc config get endpoint 2>/dev/null)" != "api.yandexcloud.kz:443" ]]; then
# 创建/激活专属配置文件,而非修改用户的活动配置文件
yc config profile list 2>/dev/null | grep -qE "^${PROFILE_NAME}\b"
|| yc config profile create "$PROFILE_NAME" yc config profile activate "$PROFILE_NAME" fi fi
|| yc config profile create "$PROFILE_NAME" yc config profile activate "$PROFILE_NAME" fi fi
执行完此模块后,活动配置文件要么是用户预先存在的指向KZ区域的配置文件(保留用户设置——用户清楚自己的操作),要么是全新的`openclaw-kz`配置文件(将在步骤d-f中填充)。
**d. 活动配置文件的OAuth令牌 + 端点**。检查`yc config get token`和`yc config get endpoint`:
- 两者均已设置,且端点为KZ → ✅ 跳过后续步骤。
- 端点已设置为KZ但无令牌 → 询问用户一次(见下文)。
- 令牌已设置但端点错误 → 静默执行`yc config set endpoint api.yandexcloud.kz:443`。
- 均未设置(全新配置文件) → 询问用户一次获取OAuth令牌。
OAuth询问是**步骤0中唯一必须的用户提示**。请严格按以下内容表述:
> Для работы с Yandex Cloud Kazakhstan нужен OAuth-токен (один раз). Открой в браузере:
>
> https://oauth.yandex.kz/authorize?response_type=token&client_id=1a6990aa636648e9b2ef855fa7bec2fb
>
> Войди под своим Yandex ID, разреши доступ. После редиректа браузер покажет URL вида `https://oauth.yandex.kz/verification_code#access_token=y0_XXXXXX…&token_type=bearer&expires_in=...`. Скопируй значение `access_token=…` (длинная строка между `=` и `&`) и пришли мне.
收到令牌后:执行`yc config set token <token>`,同时设置端点**和**可用区:
```bash
yc config set endpoint api.yandexcloud.kz:443
yc config set compute-default-zone kz1-acompute-default-zoneyc config set endpoint--zoneyc compute *ru-central1-ae. cloud-id和folder-id。步骤d完成后,配置文件已有有效令牌。现在解析ID:
bash
CLOUD_ID=$(yc config get cloud-id 2>/dev/null || true)
if [[ -z "$CLOUD_ID" ]]; then
CLOUD_ID=$(yc resource-manager cloud list --format json | jq -r '.[0].id // empty')
[[ -n "$CLOUD_ID" ]] && yc config set cloud-id "$CLOUD_ID"
fi
FOLDER_ID=$(yc config get folder-id 2>/dev/null || true)
if [[ -z "$FOLDER_ID" ]]; then
FOLDER_ID=$(yc resource-manager folder list --cloud-id "$CLOUD_ID" --format json | jq -r '.[0].id // empty')
[[ -n "$FOLDER_ID" ]] && yc config set folder-id "$FOLDER_ID"
fi失败场景:
- 返回空 → OAuth令牌对应的Yandex ID在KZ区域没有云。告知用户:“Похоже, у тебя нет облака в Yandex Cloud Kazakhstan. Создай облако в https://kz.console.yandex.cloud, потом запусти меня снова.” 停止执行。
cloud list - 返回多个 → 使用第一个,并用一句话告知用户:“Использую облако
cloud list. Если это не то — скажи, переключусь.”<NAME> - 文件夹的处理逻辑与云相同。
请勿调用。KZ端点不支持该命令。若用户有云且有文件夹,计费要么已激活,要么会在虚拟机创建时因明确错误失败。在步骤2中捕获该错误即可。
yc billing account listf. SSH密钥。执行。若不存在:静默执行。
ls ~/.ssh/id_ed25519.pubssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" -C "openclaw-yc-$(date +%Y%m%d)"g. 当前云中是否存在同名实例。执行。若返回结果,询问用户一次:“У тебя уже есть VM 'openclaw-bot' — поставить новую под именем ?” 默认回复“是”;选择随机4位后缀。
yc compute instance get --name openclaw-bot 2>/dev/nullopenclaw-bot-XXXX若(a)-(g)均静默通过,请勿向用户输出任何内容。进入步骤1。
Step 1 — Ask the two questions
步骤1——询问两个问题
In one message, in the user's language:
Сейчас поставлю тебе OpenClaw-бота в Yandex Cloud. От тебя нужны две вещи (~5 минут).1) Telegram bot token. Открой @BotFather в Telegram → отправь→ придумай имя (любое) → придумай username, заканчивающийся на/newbot→ BotFather пришлёт токен. Пришли его мне.bot2) Доступ к LLM — выбери ОДИН из трёх вариантов:A) Anthropic API ключ (рекомендую первым, лучшее качество) Открой https://console.anthropic.com/settings/keys → Create Key. Ключ начинается на. На https://console.anthropic.com/settings/billing должно быть ≥$5.sk-ant-B) OpenRouter API ключ (один ключ к Anthropic + OpenAI + 200 моделям) Открой https://openrouter.ai/keys → Create Key. Начинается на. Нужен баланс ≥$5 на openrouter.ai/credits.sk-or-C) OpenAI Codex через ChatGPT подписку (бесплатно если уже платишь Plus или Pro) Не нужен ключ. Просто напиши слово «Codex». После установки бота я попрошу ввести 8-символьный код на auth.openai.com — один раз.Пришли мне токен Telegram и один из трёх (ключ или слово «Codex»). Хоть в одном сообщении, хоть по отдельности. Я никуда не сохраняю и не показываю значения обратно.
Detect the LLM provider from what the user pasted:
bash
case "$LLM_INPUT" in
sk-ant-*)
LLM_PROVIDER=anthropic ;;
sk-or-*)
LLM_PROVIDER=openrouter ;;
Codex|codex|CODEX|ChatGPT|chatgpt|OpenAI*|"openai codex"|OAuth|oauth)
LLM_PROVIDER=openai-codex
LLM_API_KEY="" # OAuth flow — no key at this stage
;;
*)
say "Не распознал — это Anthropic-ключ (начинается на sk-ant-), OpenRouter-ключ (sk-or-) или слово 'Codex'?" && reprompt
;;
esacValidate the credential based on which option was chosen. Don't burn 15 minutes on a VM bootstrap with a bad key.
bash
undefined用一条消息,以用户使用的语言发送:
Сейчас поставлю тебе OpenClaw-бота в Yandex Cloud. От тебя нужны две вещи (~5 минут).1) Telegram bot token. Открой @BotFather в Telegram → отправь→ придумай имя (любое) → придумай username, заканчивающийся на/newbot→ BotFather пришлёт токен. Пришли его мне.bot2) Доступ к LLM — выбери ОДИН из трёх вариантов:A) Anthropic API ключ (рекомендую первым, лучшее качество) Открой https://console.anthropic.com/settings/keys → Create Key. Ключ начинается на. На https://console.anthropic.com/settings/billing должно быть ≥$5.sk-ant-B) OpenRouter API ключ (один ключ к Anthropic + OpenAI + 200 моделям) Открой https://openrouter.ai/keys → Create Key. Начинается на. Нужен баланс ≥$5 на openrouter.ai/credits.sk-or-C) OpenAI Codex через ChatGPT подписку (бесплатно если уже платишь Plus или Pro) Не нужен ключ. Просто напиши слово «Codex». После установки бота я попрошу ввести 8-символьный код на auth.openai.com — один раз.Пришли мне токен Telegram и один из трёх (ключ или слово «Codex»). Хоть в одном сообщении, хоть по отдельности. Я никуда не сохраняю и не показываю значения обратно.
根据用户粘贴内容检测LLM提供商:
bash
case "$LLM_INPUT" in
sk-ant-*)
LLM_PROVIDER=anthropic ;;
sk-or-*)
LLM_PROVIDER=openrouter ;;
Codex|codex|CODEX|ChatGPT|chatgpt|OpenAI*|"openai codex"|OAuth|oauth)
LLM_PROVIDER=openai-codex
LLM_API_KEY="" # OAuth流程——此阶段无需密钥
;;
*)
say "Не распознал — это Anthropic-ключ (начинается на sk-ant-), OpenRouter-ключ (sk-or-) или слово 'Codex'?" && reprompt
;;
esac根据所选选项验证凭证。避免因无效密钥导致虚拟机启动浪费15分钟时间。
bash
undefinedTelegram token — always validate, confirms format + that the bot actually exists
Telegram令牌——始终验证,确认格式 + 机器人确实存在
BOT_USERNAME=$(curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe"
| jq -er '.result.username')
|| (say "Telegram токен не прошёл проверку. Скопируй его ещё раз из @BotFather." && stop)
| jq -er '.result.username')
|| (say "Telegram токен не прошёл проверку. Скопируй его ещё раз из @BotFather." && stop)
case "$LLM_PROVIDER" in
anthropic)
# Minimal completion call confirms key + at least some credit
curl -fsS https://api.anthropic.com/v1/messages
-H "x-api-key: ${LLM_API_KEY}"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d '{"model":"claude-haiku-4-5","max_tokens":1,"messages":[{"role":"user","content":"ok"}]}'
| jq -er '.content' >/dev/null
|| (say "Anthropic ключ не работает или нет кредита. Проверь на console.anthropic.com." && stop) ;; openrouter) # OpenRouter exposes /api/v1/auth/key as a free credit check curl -fsS https://openrouter.ai/api/v1/auth/key
-H "Authorization: Bearer ${LLM_API_KEY}"
| jq -er '.data.usage != null' >/dev/null
|| (say "OpenRouter ключ не прошёл проверку. Перепроверь на openrouter.ai/keys." && stop) # Optional: warn if balance below $1 BAL=$(curl -fsS https://openrouter.ai/api/v1/auth/key -H "Authorization: Bearer ${LLM_API_KEY}"
| jq -r '.data.limit_remaining // 0') [[ "$BAL" == "0" ]] && say "На OpenRouter $0 кредита. Бот не сможет отвечать. Пополни на openrouter.ai/credits." ;; openai-codex) # Can't validate before OAuth — defer to Step 4.5 after VM is up. # Just confirm the user understands they'll need to do one extra step. say "Хорошо, после установки бота на VM покажу 8-символьный код для https://auth.openai.com/codex/device. Это разовое действие." ;; esac
-H "x-api-key: ${LLM_API_KEY}"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d '{"model":"claude-haiku-4-5","max_tokens":1,"messages":[{"role":"user","content":"ok"}]}'
| jq -er '.content' >/dev/null
|| (say "Anthropic ключ не работает или нет кредита. Проверь на console.anthropic.com." && stop) ;; openrouter) # OpenRouter exposes /api/v1/auth/key as a free credit check curl -fsS https://openrouter.ai/api/v1/auth/key
-H "Authorization: Bearer ${LLM_API_KEY}"
| jq -er '.data.usage != null' >/dev/null
|| (say "OpenRouter ключ не прошёл проверку. Перепроверь на openrouter.ai/keys." && stop) # Optional: warn if balance below $1 BAL=$(curl -fsS https://openrouter.ai/api/v1/auth/key -H "Authorization: Bearer ${LLM_API_KEY}"
| jq -r '.data.limit_remaining // 0') [[ "$BAL" == "0" ]] && say "На OpenRouter $0 кредита. Бот не сможет отвечать. Пополни на openrouter.ai/credits." ;; openai-codex) # Can't validate before OAuth — defer to Step 4.5 after VM is up. # Just confirm the user understands they'll need to do one extra step. say "Хорошо, после установки бота на VM покажу 8-символьный код для https://auth.openai.com/codex/device. Это разовое действие." ;; esac
`BOT_USERNAME` (e.g. `your_ceo_bot`) is captured here for the one-click chat link in Step 5.BOT_USERNAME=$(curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe"
| jq -er '.result.username')
|| (say "Telegram токен не прошёл проверку. Скопируй его ещё раз из @BotFather." && stop)
| jq -er '.result.username')
|| (say "Telegram токен не прошёл проверку. Скопируй его ещё раз из @BotFather." && stop)
case "$LLM_PROVIDER" in
anthropic)
# 最小化补全调用确认密钥 + 至少有一些余额
curl -fsS https://api.anthropic.com/v1/messages
-H "x-api-key: ${LLM_API_KEY}"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d '{"model":"claude-haiku-4-5","max_tokens":1,"messages":[{"role":"user","content":"ok"}]}'
| jq -er '.content' >/dev/null
|| (say "Anthropic ключ не работает или нет кредита. Проверь на console.anthropic.com." && stop) ;; openrouter) # OpenRouter暴露/api/v1/auth/key用于免费余额检查 curl -fsS https://openrouter.ai/api/v1/auth/key
-H "Authorization: Bearer ${LLM_API_KEY}"
| jq -er '.data.usage != null' >/dev/null
|| (say "OpenRouter ключ не прошёл проверку. Перепроверь на openrouter.ai/keys." && stop) # 可选:若余额低于1美元则发出警告 BAL=$(curl -fsS https://openrouter.ai/api/v1/auth/key -H "Authorization: Bearer ${LLM_API_KEY}"
| jq -r '.data.limit_remaining // 0') [[ "$BAL" == "0" ]] && say "На OpenRouter $0 кредита. Бот не сможет отвечать. Пополни на openrouter.ai/credits." ;; openai-codex) # OAuth前无法验证——推迟到步骤4.5虚拟机启动后执行。 # 仅确认用户了解需要完成一项额外步骤。 say "Хорошо, после установки бота на VM покажу 8-символьный код для https://auth.openai.com/codex/device. Это разовое действие." ;; esac
-H "x-api-key: ${LLM_API_KEY}"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d '{"model":"claude-haiku-4-5","max_tokens":1,"messages":[{"role":"user","content":"ok"}]}'
| jq -er '.content' >/dev/null
|| (say "Anthropic ключ не работает или нет кредита. Проверь на console.anthropic.com." && stop) ;; openrouter) # OpenRouter暴露/api/v1/auth/key用于免费余额检查 curl -fsS https://openrouter.ai/api/v1/auth/key
-H "Authorization: Bearer ${LLM_API_KEY}"
| jq -er '.data.usage != null' >/dev/null
|| (say "OpenRouter ключ не прошёл проверку. Перепроверь на openrouter.ai/keys." && stop) # 可选:若余额低于1美元则发出警告 BAL=$(curl -fsS https://openrouter.ai/api/v1/auth/key -H "Authorization: Bearer ${LLM_API_KEY}"
| jq -r '.data.limit_remaining // 0') [[ "$BAL" == "0" ]] && say "На OpenRouter $0 кредита. Бот не сможет отвечать. Пополни на openrouter.ai/credits." ;; openai-codex) # OAuth前无法验证——推迟到步骤4.5虚拟机启动后执行。 # 仅确认用户了解需要完成一项额外步骤。 say "Хорошо, после установки бота на VM покажу 8-символьный код для https://auth.openai.com/codex/device. Это разовое действие." ;; esac
`BOT_USERNAME`(例如`your_ceo_bot`)在此处捕获,用于步骤5中的一键聊天链接。Step 2 — Silent VM creation
步骤2——静默创建虚拟机
a. Ensure the default network + subnet exist in the current folder. Brand-new folders sometimes lack them (or the user removed them). Don't assume — discover, then create if missing.
bash
NETWORK_ID=$(yc vpc network get --name default --format json 2>/dev/null | jq -r .id 2>/dev/null)
if [[ -z "$NETWORK_ID" ]]; then
NETWORK_ID=$(yc vpc network create --name default --format json | jq -r .id)
fi
SUBNET_ID=$(yc vpc subnet get --name default-kz1-a --format json 2>/dev/null | jq -r .id 2>/dev/null)
if [[ -z "$SUBNET_ID" ]]; then
# Pick a /24 from 10.130.x.x that doesn't collide with the user's other subnets
SUBNET_ID=$(yc vpc subnet create \
--name default-kz1-a \
--network-id "$NETWORK_ID" \
--zone kz1-a \
--range 10.130.0.0/24 \
--format json | jq -r .id)
fiDon't mention any of this to the user unless it errors — these are quiet idempotent ops.
b. Detect the caller's public IP (for the SSH ingress rule):
bash
MY_IP=$(curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null \
|| curl -fsS --max-time 5 https://icanhazip.com 2>/dev/null \
|| echo "") # empty → fall back to 0.0.0.0/0 (fail2ban catches the rest)c. Render the cloud-init file. Substitute these placeholders (no — it's auto-detected in Step 4):
TELEGRAM_CHAT_ID-
— from Step 1.
{{TELEGRAM_BOT_TOKEN}} -
— content of
{{SSH_PUBLIC_KEY}}.~/.ssh/id_ed25519.pub -
— depends on the chosen LLM provider:
{{LLM_ENV_LINE}}Provider Substituted line anthropic ANTHROPIC_API_KEY=<key>openrouter OPENROUTER_API_KEY=<key>openai-codex (empty string — no env var at this stage; OAuth fills the profile after Step 4.5)
Write to with mode 600.
/tmp/openclaw-cloud-init.yamld. Create the security group:
bash
SSH_CIDR="${MY_IP:+${MY_IP}/32}"
SSH_CIDR="${SSH_CIDR:-0.0.0.0/0}"
SG_ID=$(yc vpc security-group create \
--name "${VM_NAME}-sg" \
--network-id "$NETWORK_ID" \
--rule "direction=ingress,port=22,protocol=tcp,v4-cidrs=[${SSH_CIDR}]" \
--rule "direction=egress,from-port=0,to-port=65535,protocol=any,v4-cidrs=[0.0.0.0/0]" \
--format json | jq -r .id)Note: use not . The named lookup fails silently in some yc CLI versions when the folder has multiple networks.
--network-id--network-namee. Create the instance. Try first (Intel Ice Lake), fall back to (Cascade Lake) if v3 isn't available in this folder:
standard-v3standard-v2bash
PLATFORM=standard-v3
yc compute instance create \
--name "${VM_NAME}" \
--zone kz1-a \
--platform "$PLATFORM" \
--cores 2 --memory 4 \
--network-interface "subnet-id=${SUBNET_ID},nat-ip-version=ipv4,security-group-ids=${SG_ID}" \
--create-boot-disk "type=network-ssd,size=30,image-folder-id=standard-images,image-family=ubuntu-2404-lts" \
--ssh-key ~/.ssh/id_ed25519.pub \
--metadata-from-file user-data=/tmp/openclaw-cloud-init.yaml \
--hostname "${VM_NAME}" \
--format json > /tmp/openclaw-vm.json 2>/tmp/openclaw-vm.erra. 确保当前文件夹中存在默认网络 + 子网。全新文件夹有时缺少这些资源(或用户已删除)。请勿假设——先检测,若不存在则创建。
bash
NETWORK_ID=$(yc vpc network get --name default --format json 2>/dev/null | jq -r .id 2>/dev/null)
if [[ -z "$NETWORK_ID" ]]; then
NETWORK_ID=$(yc vpc network create --name default --format json | jq -r .id)
fi
SUBNET_ID=$(yc vpc subnet get --name default-kz1-a --format json 2>/dev/null | jq -r .id 2>/dev/null)
if [[ -z "$SUBNET_ID" ]]; then
# 从10.130.x.x中选择一个不与用户其他子网冲突的/24网段
SUBNET_ID=$(yc vpc subnet create \
--name default-kz1-a \
--network-id "$NETWORK_ID" \
--zone kz1-a \
--range 10.130.0.0/24 \
--format json | jq -r .id)
fi除非出错,否则请勿向用户提及这些操作——这些是静默的幂等操作。
b. 检测调用者的公网IP(用于SSH入站规则):
bash
MY_IP=$(curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null \
|| curl -fsS --max-time 5 https://icanhazip.com 2>/dev/null \
|| echo "") # 空值 → 回退为0.0.0.0/0(fail2ban处理其余防护)c. 渲染cloud-init文件。替换以下占位符(无需——将在步骤4中自动检测):
TELEGRAM_CHAT_ID-
——来自步骤1。
{{TELEGRAM_BOT_TOKEN}} -
——
{{SSH_PUBLIC_KEY}}的内容。~/.ssh/id_ed25519.pub -
——取决于所选LLM提供商:
{{LLM_ENV_LINE}}提供商 替换后的行 anthropic ANTHROPIC_API_KEY=<key>openrouter OPENROUTER_API_KEY=<key>openai-codex (空字符串——此阶段无需环境变量;OAuth会在步骤4.5后填充配置文件)
将内容写入,权限设置为600。
/tmp/openclaw-cloud-init.yamld. 创建安全组:
bash
SSH_CIDR="${MY_IP:+${MY_IP}/32}"
SSH_CIDR="${SSH_CIDR:-0.0.0.0/0}"
SG_ID=$(yc vpc security-group create \
--name "${VM_NAME}-sg" \
--network-id "$NETWORK_ID" \
--rule "direction=ingress,port=22,protocol=tcp,v4-cidrs=[${SSH_CIDR}]" \
--rule "direction=egress,from-port=0,to-port=65535,protocol=any,v4-cidrs=[0.0.0.0/0]" \
--format json | jq -r .id)注意:使用而非。在某些yc CLI版本中,当文件夹有多个网络时,按名称查找会静默失败。
--network-id--network-namee. 创建实例。首先尝试(Intel Ice Lake),若该文件夹不支持v3则回退为(Cascade Lake):
standard-v3standard-v2bash
PLATFORM=standard-v3
yc compute instance create \
--name "${VM_NAME}" \
--zone kz1-a \
--platform "$PLATFORM" \
--cores 2 --memory 4 \
--network-interface "subnet-id=${SUBNET_ID},nat-ip-version=ipv4,security-group-ids=${SG_ID}" \
--create-boot-disk "type=network-ssd,size=30,image-folder-id=standard-images,image-family=ubuntu-2404-lts" \
--ssh-key ~/.ssh/id_ed25519.pub \
--metadata-from-file user-data=/tmp/openclaw-cloud-init.yaml \
--hostname "${VM_NAME}" \
--format json > /tmp/openclaw-vm.json 2>/tmp/openclaw-vm.errIf v3 not available in this folder, retry with v2.
若该文件夹不支持v3,使用v2重试。
if grep -qiE "platform.*not.*found|unsupported platform" /tmp/openclaw-vm.err; then
yc compute instance create --platform standard-v2 ... # same flags
fi
Capture `external_ipv4_address` from `/tmp/openclaw-vm.json` (`.network_interfaces[0].primary_v4_address.one_to_one_nat.address`). Then one sentence to the user:
> VM создана. Ставлю OpenClaw — займёт около 10 минут. Можешь пока заварить чай.
If the instance create errors with `billing account is not active` or `billing_disabled` — that's the one billing case we couldn't detect in Step 0 (because there's no `yc billing` on KZ). Tell the user: "Похоже, в Yandex Cloud Kazakhstan не активирован биллинг. Открой https://kz.console.yandex.cloud/billing — там подсказка. Когда активируешь, запусти меня снова — VM подхвачу автоматически." Stop.if grep -qiE "platform.*not.*found|unsupported platform" /tmp/openclaw-vm.err; then
yc compute instance create --platform standard-v2 ... # 相同参数
fi
从`/tmp/openclaw-vm.json`中捕获`external_ipv4_address`(`.network_interfaces[0].primary_v4_address.one_to_one_nat.address`)。然后向用户发送一句话:
> VM создана. Ставлю OpenClaw — займёт около 10 минут. Можешь пока заварить чай.
若实例创建时出现`billing account is not active`或`billing_disabled`错误——这是步骤0中无法检测到的唯一计费情况(因为KZ区域没有`yc billing`)。告知用户:“Похоже, в Yandex Cloud Kazakhstan не активирован биллинг. Открой https://kz.console.yandex.cloud/billing — там подсказка. Когда активируешь, запусти меня снова — VM подхвачу автоматически.” 停止执行。Step 3 — Wait silently for cloud-init
步骤3——静默等待cloud-init完成
Poll every 30 seconds:
bash
ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 openclaw@$IP \
'test -f /var/lib/openclaw-bootstrap-done && echo READY || echo PENDING'Don't spam the user with raw log lines. Every ~3 minutes, emit one warm progress sentence based on the current phase you see in :
tail -1 /var/log/openclaw-bootstrap.log| If the log mentions | Tell the user |
|---|---|
| firewall / hardening | "Настраиваю файрвол и SSH" |
| nodesource / Node | "Ставлю Node.js" |
| "Качаю OpenClaw" |
| ceo-ai-os / install.sh | "Загружаю CEO-скиллы" |
| openclaw onboard / config | "Подключаю Telegram и LLM" |
| systemd / health | "Запускаю бот" |
Cap at 15 minutes. If still not ready, surface to the user with a single sentence ("Что-то пошло не так на VM, проверяю логи") and jump to .
references/04-troubleshooting.md每30秒轮询一次:
bash
ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 openclaw@$IP \
'test -f /var/lib/openclaw-bootstrap-done && echo READY || echo PENDING'请勿向用户发送原始日志行垃圾信息。每约3分钟,根据中的当前阶段,发送一句友好的进度提示:
tail -1 /var/log/openclaw-bootstrap.log| 日志提及内容 | 告知用户 |
|---|---|
| firewall / hardening | "Настраиваю файрвол и SSH" |
| nodesource / Node | "Ставлю Node.js" |
| "Качаю OpenClaw" |
| ceo-ai-os / install.sh | "Загружаю CEO-скиллы" |
| openclaw onboard / config | "Подключаю Telegram и LLM" |
| systemd / health | "Запускаю бот" |
最长等待15分钟。若仍未就绪,向用户发送一句话(“Что-то пошло не так на VM, проверяю логи”),并跳转至。
references/04-troubleshooting.mdStep 3.5 — OAuth device-code flow (ONLY if LLM_PROVIDER=openai-codex
)
LLM_PROVIDER=openai-codex步骤3.5——OAuth设备码流程(仅当LLM_PROVIDER=openai-codex
时执行)
LLM_PROVIDER=openai-codexSkip this entire step for and — they have the key already in and the bot is ready to talk.
anthropicopenroutergateway.envFor , the cloud-init left the gateway running but without a model configured (no Anthropic/OpenRouter key was in env). Run the device-code OAuth flow now via SSH with a forced TTY:
openai-codexbash
ssh -tt -o ServerAliveInterval=30 openclaw@$IP \
"openclaw models auth login --provider openai-codex --device-code" \
| tee /tmp/openclaw-oauth.logThe CLI prints two things on stdout, usually within 2 seconds:
- A URL like (or
https://auth.openai.com/codex/device)https://auth.openai.com/device - An 8-character code like
ABCD-1234
Extract both with a regex on (the formats may shift slightly across OpenClaw releases — match generously). Show the user one clean message:
/tmp/openclaw-oauth.logПоследний шаг — подключи бота к ChatGPT.Открой в браузере: https://auth.openai.com/codex/deviceВведи код: ABCD-1234Войди под аккаунтом ChatGPT (Plus или Pro) и разреши доступ. Жду до 15 минут.
The SSH session will block until the user completes the device flow (or the 15-minute server-side timeout expires). When it exits 0, OpenClaw has written with the OAuth token and the gateway will pick it up on next config reload.
auth-profiles.jsonKnown pitfall (issue #74212, 2026-05): in some SSH sessions OpenClaw masks the device-pairing code as . If that's what you see in :
[shown on the local device only]/tmp/openclaw-oauth.log- Retry with if you didn't already — the masking is triggered by a TTY check that some non-interactive SSH invocations fail.
ssh -tt - If retry doesn't help: run the auth command directly inside a fresh SSH session (→
ssh openclaw@$IP), pull the code from there, then resume the wizard.openclaw models auth login --provider openai-codex --device-code
After the OAuth profile is written:
bash
undefinedanthropicopenroutergateway.env对于用户,cloud-init已启动网关但未配置模型(环境中没有Anthropic/OpenRouter密钥)。现在通过SSH强制使用TTY执行设备码OAuth流程:
openai-codexbash
ssh -tt -o ServerAliveInterval=30 openclaw@$IP \
"openclaw models auth login --provider openai-codex --device-code" \
| tee /tmp/openclaw-oauth.logCLI通常会在2秒内在标准输出中打印两项内容:
- 类似(或
https://auth.openai.com/codex/device)的URLhttps://auth.openai.com/device - 8位字符的代码,例如
ABCD-1234
通过正则表达式从中提取两者(OpenClaw版本不同格式可能略有变化——宽松匹配)。向用户展示一条清晰的消息:
/tmp/openclaw-oauth.logПоследний шаг — подключи бота к ChatGPT.Открой в браузере: https://auth.openai.com/codex/deviceВведи код: ABCD-1234Войди под аккаунтом ChatGPT (Plus или Pro) и разреши доступ. Жду до 15 минут.
SSH会话会阻塞,直到用户完成设备流程(或服务器端15分钟超时过期)。会话退出码为0时,OpenClaw已将OAuth令牌写入,网关会在下次配置重载时读取该令牌。
auth-profiles.json已知陷阱(问题#74212,2026-05):在某些SSH会话中,OpenClaw会将设备配对代码屏蔽为。若在中看到此内容:
[shown on the local device only]/tmp/openclaw-oauth.log- 若尚未使用,则重试——屏蔽是由TTY检查触发的,某些非交互式SSH调用会失败。
ssh -tt - 若重试无效:在新的SSH会话中直接执行认证命令(→
ssh openclaw@$IP),从中提取代码,然后继续向导流程。openclaw models auth login --provider openai-codex --device-code
OAuth配置文件写入后:
bash
undefinedProbe what models the user's subscription unlocks
探测用户订阅解锁的模型
HAS_GPT55=$(ssh openclaw@$IP "openclaw models list --provider openai-codex --format json"
| jq -r '.[] | select(.id=="gpt-5.5") | .id // empty')
| jq -r '.[] | select(.id=="gpt-5.5") | .id // empty')
if [[ "$HAS_GPT55" == "gpt-5.5" ]]; then
Pro subscription
ssh openclaw@$IP "openclaw config set agents.defaults.model.primary 'openai-codex/gpt-5.5'
&& openclaw config set agents.defaults.model.fallbacks '["openai-codex/gpt-4o"]'" else
&& openclaw config set agents.defaults.model.fallbacks '["openai-codex/gpt-4o"]'" else
Plus subscription — gpt-4o is the best available
ssh openclaw@$IP "openclaw config set agents.defaults.model.primary 'openai-codex/gpt-4o'
&& openclaw config set agents.defaults.model.fallbacks '[]'" fi
&& openclaw config set agents.defaults.model.fallbacks '[]'" fi
ssh openclaw@$IP "systemctl --user restart openclaw-gateway"
If after 15 minutes the SSH session timed out and `auth-profiles.json` still has no `openai-codex` profile: tell the user "не получилось войти в ChatGPT, давай попробуем ещё раз" and re-run the SSH `openclaw models auth login` command. Don't kill the VM — only the OAuth step needs to be retried.HAS_GPT55=$(ssh openclaw@$IP "openclaw models list --provider openai-codex --format json"
| jq -r '.[] | select(.id=="gpt-5.5") | .id // empty')
| jq -r '.[] | select(.id=="gpt-5.5") | .id // empty')
if [[ "$HAS_GPT55" == "gpt-5.5" ]]; then
Pro订阅
ssh openclaw@$IP "openclaw config set agents.defaults.model.primary 'openai-codex/gpt-5.5'
&& openclaw config set agents.defaults.model.fallbacks '["openai-codex/gpt-4o"]'" else
&& openclaw config set agents.defaults.model.fallbacks '["openai-codex/gpt-4o"]'" else
Plus订阅——gpt-4o是可用的最佳模型
ssh openclaw@$IP "openclaw config set agents.defaults.model.primary 'openai-codex/gpt-4o'
&& openclaw config set agents.defaults.model.fallbacks '[]'" fi
&& openclaw config set agents.defaults.model.fallbacks '[]'" fi
ssh openclaw@$IP "systemctl --user restart openclaw-gateway"
若15分钟后SSH会话超时,且`auth-profiles.json`仍无`openai-codex`配置文件:告知用户“не получилось войти в ChatGPT, давай попробуем ещё раз”,并重新执行SSH `openclaw models auth login`命令。请勿销毁虚拟机——仅需重试OAuth步骤。Step 4 — One-click chat link + auto-pair (the actual flow, not the easy one)
步骤4——一键聊天链接 + 自动配对(实际流程,而非简化流程)
When exists, the gateway is up in mode. This is where wizards historically fail silently: they think succeeded, hand off to the user, and the user discovers the bot still asks for a confirmation code. Read this whole section.
/var/lib/openclaw-bootstrap-donepairingopenclaw pairing approve当存在时,网关已处于模式。这是向导历史上经常静默失败的环节:向导认为成功,将控制权交给用户,但用户发现机器人仍要求输入确认码。请完整阅读本节。
/var/lib/openclaw-bootstrap-donepairingopenclaw pairing approveWhat actually happens when the user presses /start
用户按下/start时的实际流程
- Telegram delivers to the bot.
/start - OpenClaw enforces — it does not drop the message, it calls
dmPolicy=pairing, records a pending request in the gateway, and the bot replies to the user with the pairing code + instructions (something like "To complete pairing, ask your admin to runissuePairingChallenge()"). The user sees this message; they shouldn't reply to it.openclaw pairing approve telegram ABCD-1234 - The pending request lives in until either approved or expired.
openclaw pairing list telegram --format json
- Telegram将发送给机器人。
/start - OpenClaw强制执行——它不会丢弃消息,而是调用
dmPolicy=pairing,在网关中记录待处理请求,且机器人会向用户回复配对代码 + 说明(类似“完成配对,请让管理员执行issuePairingChallenge()”)。用户会看到此消息;无需回复。openclaw pairing approve telegram ABCD-1234 - 待处理请求会保留在中,直到被批准或过期。
openclaw pairing list telegram --format json
Pre-emptive heads-up to the user
提前向用户说明
Send this before asking them to press /start, so they don't get confused when the bot's first reply is a code message:
Бот готов. Открой его в Telegram: https://t.me/{{BOT_USERNAME}} и нажми./startБот пришлёт тебе короткое сообщение с кодом — ничего с ним делать не надо, я подтвержу доступ автоматически за пару секунд. После этого можешь начать переписываться с ботом как обычно.
在要求用户按下/start之前发送此消息,避免用户因机器人第一条回复是代码消息而困惑:
Бот готов. Открой его в Telegram: https://t.me/{{BOT_USERNAME}} и нажми./startБот пришлёт тебе короткое сообщение с кодом — ничего с ним делать не надо, я подтвержу доступ автоматически за пару секунд. После этого можешь начать переписываться с ботом как обычно.
Poll for chat_id (Telegram getUpdates)
轮询chat_id(Telegram getUpdates)
bash
undefinedbash
undefinedEmpty getUpdates returns until the user actually presses /start
用户实际按下/start前,getUpdates返回空
for i in $(seq 1 150); do # 150 × 2s = 5 minutes
CHAT_ID=$(curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates?timeout=2"
| jq -r '.result[0].message.chat.id // empty') [[ -n "$CHAT_ID" ]] && break sleep 2 done [[ -z "$CHAT_ID" ]] && fail "Пользователь не нажал /start за 5 минут"
| jq -r '.result[0].message.chat.id // empty') [[ -n "$CHAT_ID" ]] && break sleep 2 done [[ -z "$CHAT_ID" ]] && fail "Пользователь не нажал /start за 5 минут"
undefinedfor i in $(seq 1 150); do # 150 × 2s = 5分钟
CHAT_ID=$(curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates?timeout=2"
| jq -r '.result[0].message.chat.id // empty') [[ -n "$CHAT_ID" ]] && break sleep 2 done [[ -z "$CHAT_ID" ]] && fail "Пользователь не нажал /start за 5 минут"
| jq -r '.result[0].message.chat.id // empty') [[ -n "$CHAT_ID" ]] && break sleep 2 done [[ -z "$CHAT_ID" ]] && fail "Пользователь не нажал /start за 5 минут"
undefinedApprove the pairing (the part the old wizard broke)
批准配对(旧版向导出错的环节)
The pending pairing request lives in . Its schema (verified against ) uses for the Telegram user ID and for the primary key — not and not . A wizard that filters on always gets empty results and the subsequent is a no-op.
openclaw pairing list telegram --format jsonsrc/gateway/protocol/schema/devices.tssenderIdrequestIdchatIdcode.chatId == $CHAT_IDxargs approveDefensive filter (handles both schemas in case a future OpenClaw release renames again):
bash
undefined待处理配对请求存在于中。其Schema(已针对验证)使用**表示Telegram用户ID,**表示主键——不是,也不是。若向导使用过滤,总会得到空结果,后续也不会执行任何操作。
openclaw pairing list telegram --format jsonsrc/gateway/protocol/schema/devices.tssenderIdrequestIdchatIdcode.chatId == $CHAT_IDxargs approve防御性过滤(兼容未来OpenClaw版本可能的重命名):
bash
undefinedGive the gateway up to 10s to record the pending request after /start arrives
/start到达后,给网关最多10秒时间记录待处理请求
APPROVE_TOKEN=""
for i in $(seq 1 5); do
APPROVE_TOKEN=$(ssh openclaw@$IP "openclaw pairing list telegram --format json 2>/dev/null"
| jq -r --arg cid "$CHAT_ID" ' .[] | select( (.senderId|tostring) == $cid or (.chatId|tostring) == $cid or (.sender // empty | tostring) == $cid ) | (.requestId // .code // empty) '
| head -n1) [[ -n "$APPROVE_TOKEN" ]] && break sleep 2 done
| jq -r --arg cid "$CHAT_ID" ' .[] | select( (.senderId|tostring) == $cid or (.chatId|tostring) == $cid or (.sender // empty | tostring) == $cid ) | (.requestId // .code // empty) '
| head -n1) [[ -n "$APPROVE_TOKEN" ]] && break sleep 2 done
[[ -z "$APPROVE_TOKEN" ]] && fail "Запрос на pairing не появился в openclaw pairing list — посмотри journalctl на VM"
ssh openclaw@$IP "openclaw pairing approve telegram '$APPROVE_TOKEN'"
|| fail "openclaw pairing approve failed (token=$APPROVE_TOKEN)"
|| fail "openclaw pairing approve failed (token=$APPROVE_TOKEN)"
undefinedAPPROVE_TOKEN=""
for i in $(seq 1 5); do
APPROVE_TOKEN=$(ssh openclaw@$IP "openclaw pairing list telegram --format json 2>/dev/null"
| jq -r --arg cid "$CHAT_ID" ' .[] | select( (.senderId|tostring) == $cid or (.chatId|tostring) == $cid or (.sender // empty | tostring) == $cid ) | (.requestId // .code // empty) '
| head -n1) [[ -n "$APPROVE_TOKEN" ]] && break sleep 2 done
| jq -r --arg cid "$CHAT_ID" ' .[] | select( (.senderId|tostring) == $cid or (.chatId|tostring) == $cid or (.sender // empty | tostring) == $cid ) | (.requestId // .code // empty) '
| head -n1) [[ -n "$APPROVE_TOKEN" ]] && break sleep 2 done
[[ -z "$APPROVE_TOKEN" ]] && fail "Запрос на pairing не появился в openclaw pairing list — посмотри journalctl на VM"
ssh openclaw@$IP "openclaw pairing approve telegram '$APPROVE_TOKEN'"
|| fail "openclaw pairing approve failed (token=$APPROVE_TOKEN)"
|| fail "openclaw pairing approve failed (token=$APPROVE_TOKEN)"
undefinedLock down + persist chat_id
锁定并持久化chat_id
bash
ssh openclaw@$IP "
openclaw config set channels.telegram.dmPolicy allowlist
openclaw config set channels.telegram.allowFrom '[${CHAT_ID}]'
echo 'TELEGRAM_CHAT_ID=${CHAT_ID}' >> /home/openclaw/.openclaw/gateway.env
systemctl --user restart openclaw-gateway
"Wait ~60s for the gateway to come back. Don't proceed to Step 5 until returns 200:
/healthbash
for i in $(seq 1 30); do
ssh openclaw@$IP 'curl -fsS -m 3 http://127.0.0.1:18789/health' >/dev/null 2>&1 && break
sleep 2
doneIf the user doesn't press within 5 minutes, poke them gently with a one-line reminder. After 15 minutes of no signal, stop and tell them how to resume.
/startbash
ssh openclaw@$IP "
openclaw config set channels.telegram.dmPolicy allowlist
openclaw config set channels.telegram.allowFrom '[${CHAT_ID}]'
echo 'TELEGRAM_CHAT_ID=${CHAT_ID}' >> /home/openclaw/.openclaw/gateway.env
systemctl --user restart openclaw-gateway
"等待约60秒,让网关重启。直到返回200后,再进入步骤5:
/healthbash
for i in $(seq 1 30); do
ssh openclaw@$IP 'curl -fsS -m 3 http://127.0.0.1:18789/health' >/dev/null 2>&1 && break
sleep 2
done若用户5分钟内未按下/start,用一句话温和提醒。15分钟仍无响应则停止,并告知用户如何恢复。
Step 5 — Verify the bot answers (do NOT skip), then hand off
步骤5——验证机器人回复(请勿跳过),然后移交控制权
The wizard's #1 historical failure mode was claiming "done" while the bot was still silent. The verification below is mandatory — three independent signals, all must pass, before you tell the user it works.
向导历史上最常见的失败模式是声称“已完成”但机器人仍无响应。以下验证是强制性的——必须通过三个独立信号,才能告知用户部署成功。
5a. Trigger a reply
5a. 触发回复
Send a probe message from the user's laptop, in the language set in Step 0 ():
USER_LANGUAGEbash
undefined从用户的笔记本发送探测消息,使用步骤0中设置的语言():
USER_LANGUAGEbash
undefinedLanguage-matched probe text
匹配语言的探测文本
case "$USER_LANGUAGE" in
ru) PROBE="Скажи 'привет', чтобы я убедился, что ты отвечаешь." ;;
kk) PROBE="Сәлем деп жаз — жауап беретіндігіңе көз жеткізейін." ;;
*) PROBE="Say 'hi' so I can confirm you're alive." ;;
esac
curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage"
-d "chat_id=${CHAT_ID}"
-d "text=${PROBE}"
-d "chat_id=${CHAT_ID}"
-d "text=${PROBE}"
undefinedcase "$USER_LANGUAGE" in
ru) PROBE="Скажи 'привет', чтобы я убедился, что ты отвечаешь." ;;
kk) PROBE="Сәлем деп жаз — жауап беретіндігіңе көз жеткізейін." ;;
*) PROBE="Say 'hi' so I can confirm you're alive." ;;
esac
curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage"
-d "chat_id=${CHAT_ID}"
-d "text=${PROBE}"
-d "chat_id=${CHAT_ID}"
-d "text=${PROBE}"
undefined5b. Three checks, all required
5b. 三项检查,全部通过才确认成功
Check 1 — Gateway logged an outgoing message. Watch the journal for an outbound telegram event within 90 seconds:
bash
ssh openclaw@$IP "
timeout 90 journalctl --user -u openclaw-gateway -f --no-pager 2>/dev/null \
| grep -m1 -E 'telegram.*sent|outgoing.*telegram|sendMessage.*ok'
"If this times out: gateway accepted the inbound but didn't reply. Most likely cause = LLM provider not configured (Codex OAuth didn't finish, or env key empty). Jump to §4c-e.
references/04-troubleshooting.mdCheck 2 — A bot reply appears in within 90s. Poll for any new update authored by the bot:
getUpdatesbash
LAST_OFFSET=$(curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates?offset=-1" \
| jq -r '.result[-1].update_id // 0')
for i in $(seq 1 45); do
REPLY=$(curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates?offset=$((LAST_OFFSET+1))&timeout=2" \
| jq -r '.result[]? | select(.message.from.is_bot==true) | .message.text' \
| head -n1)
[[ -n "$REPLY" ]] && break
sleep 2
done
[[ -z "$REPLY" ]] && fail "Не вижу ответа бота в getUpdates через 90с"Note: a bot's own outgoing messages don't appear in directly — but the bot's reply, after you send a follow-up probe, does appear as a forwarded/preceding context in subsequent updates. If this check is unreliable in your test environment, fall back on Check 1 (journal) + Check 3 (user confirmation).
getUpdatesCheck 3 — User confirms. Ask the user once, in their language:
Бот должен был тебе ответить в Telegram. Ответил?
Wait for "да"/"yes"/"работает". If "нет"/"не отвечает" — jump to §4. Never claim success unless all three pass.
references/04-troubleshooting.md检查1——网关记录了出站消息。90秒内监控日志,查找出站telegram事件:
bash
ssh openclaw@$IP "
timeout 90 journalctl --user -u openclaw-gateway -f --no-pager 2>/dev/null \
| grep -m1 -E 'telegram.*sent|outgoing.*telegram|sendMessage.*ok'
"若超时:网关已接收入站消息但未回复。最可能的原因是LLM提供商未配置(Codex OAuth未完成,或环境密钥为空)。跳转至 §4c-e。
references/04-troubleshooting.md检查2——90秒内中出现机器人回复。轮询是否有机器人发送的新更新:
getUpdatesbash
LAST_OFFSET=$(curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates?offset=-1" \
| jq -r '.result[-1].update_id // 0')
for i in $(seq 1 45); do
REPLY=$(curl -fsS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates?offset=$((LAST_OFFSET+1))&timeout=2" \
| jq -r '.result[]? | select(.message.from.is_bot==true) | .message.text' \
| head -n1)
[[ -n "$REPLY" ]] && break
sleep 2
done
[[ -z "$REPLY" ]] && fail "Не вижу ответа бота в getUpdates через 90с"注意:机器人自身的出站消息不会直接出现在中——但发送后续探测消息后,机器人的回复会作为转发/前置上下文出现在后续更新中。若测试环境中此检查不可靠,回退为检查1(日志) + 检查3(用户确认)。
getUpdates检查3——用户确认。用用户的语言询问一次:
Бот должен был тебе ответить в Telegram. Ответил?
等待用户回复“да”/“yes”/“работает”。若回复“нет”/“не отвечает”——跳转至 §4。仅当三项检查全部通过时,才能声称部署成功。
references/04-troubleshooting.md5c. If language is wrong
5c. 若语言错误
If checks 1+2 pass but the bot replied in English while the user expected Russian (or vice versa), the locale override wasn't applied. Re-apply over SSH and reset the session:
bash
LOCALE_PACK="/usr/local/share/openclaw-locale-${USER_LANGUAGE}.md"
ssh openclaw@$IP "
test -f $LOCALE_PACK && cat $LOCALE_PACK >> ~/.openclaw/workspace/USER.md
# Trigger session reset so the bot re-reads USER.md
openclaw sessions reset --channel telegram --to ${CHAT_ID} 2>/dev/null || true
"Then re-run the probe (5a + 5b). If the bot is still answering in the wrong language, surface to the user — don't loop.
若检查1+2通过,但机器人回复语言与用户预期不符(例如用户预期俄语但回复英语),则未应用区域设置。通过SSH重新应用并重置会话:
bash
LOCALE_PACK="/usr/local/share/openclaw-locale-${USER_LANGUAGE}.md"
ssh openclaw@$IP "
test -f $LOCALE_PACK && cat $LOCALE_PACK >> ~/.openclaw/workspace/USER.md
# 触发会话重置,让机器人重新读取USER.md
openclaw sessions reset --channel telegram --to ${CHAT_ID} 2>/dev/null || true
"然后重新执行探测(5a + 5b)。若机器人仍回复错误语言,告知用户——请勿循环执行。
Step 5.5 — Onboarding (hand off to openclaw-user-onboarding
skill)
openclaw-user-onboarding步骤5.5——用户引导(移交至openclaw-user-onboarding
技能)
openclaw-user-onboardingThe bot is alive but anonymous — it doesn't know who's talking to it. Before the final summary, hand off to , which collects five basic fields about the user (identity, focus, communication style, tools, anti-patterns), writes on the VM, and resets the Telegram session so the bot picks up the profile from the very next message.
openclaw-user-onboardingUSER.mdHand-off payload (everything the onboarding skill needs):
| Variable | Source in this wizard |
|---|---|
| Step 2e |
| Step 4 (auto-detected from |
| Step 1 (Telegram token the user pasted) |
| Step 0 (detected from user's first messages) |
| |
Trigger the skill with a single one-liner to the user, in their language:
Бот живой. Последний шаг — расскажи о себе коротко, чтобы я с первого сообщения был полезным.
Then immediately invoke . The onboarding skill takes over the conversation:
openclaw-user-onboarding- Asks the five questions in one message
- Parses the user's free-form reply
- Renders from the template
USER.md - Shows a 15-line preview, asks for confirmation
- Atomic SCP upload to (mode 600, owned by
~/.openclaw/workspace/USER.md)openclaw:openclaw - Resets the active Telegram session (or restarts gateway as fallback)
- Returns control to this wizard
If the user wants to skip onboarding entirely (says "пропусти", "skip", "потом"): write a minimal placeholder USER.md and proceed. Don't block — onboarding is a nice-to-have at this step, not a gate. The user can always run standalone later.
openclaw-user-onboardingIf skill is not loaded (the agent doesn't have it installed): fall back to writing a minimal placeholder USER.md inline and mention in the final summary: "Чтобы дозаполнить профиль, поставь скилл openclaw-user-onboarding и скажи мне «онбординг»."
openclaw-user-onboarding机器人已启动但匿名——它不知道与谁对话。在最终总结之前,移交至技能,该技能会收集用户的五项基本信息(身份、关注点、沟通风格、使用工具、避坑指南),在虚拟机上写入,并重置Telegram会话,让机器人从下一条消息开始读取配置文件。
openclaw-user-onboardingUSER.md移交负载(引导技能所需的所有信息):
| 变量 | 来源 |
|---|---|
| 步骤2e中的 |
| 步骤4(从 |
| 步骤1(用户粘贴的Telegram令牌) |
| 步骤0(从用户最初几条消息检测) |
| |
用用户的语言发送一句话触发技能:
Бот живой. Последний шаг — расскажи о себе коротко, чтобы я с первого сообщения был полезным.
然后立即调用。引导技能会接管对话:
openclaw-user-onboarding- 用一条消息询问五个问题
- 解析用户的自由格式回复
- 根据模板渲染
USER.md - 展示15行预览,请求确认
- 原子化SCP上传至(权限600,所有者
~/.openclaw/workspace/USER.md)openclaw:openclaw - 重置活动Telegram会话(或回退为重启网关)
- 将控制权交回本向导
若用户想完全跳过引导(回复“пропусти”“skip”“потом”):写入最小占位符USER.md并继续。请勿阻塞——此步骤的引导是锦上添花,而非必要条件。用户之后可单独运行。
openclaw-user-onboarding若未加载技能(Agent未安装):回退为内联写入最小占位符USER.md,并在最终总结中提及:“Чтобы дозаполнить профиль, поставь скилл openclaw-user-onboarding и скажи мне «онбординг».”
openclaw-user-onboardingFinal hand-off message
最终移交消息
Only after all three checks pass, drop the summary:
Then drop the final summary. Adapt the line to the provider the user chose:
LLMOpenClaw запущен в Yandex Cloud Kazakhstan.
VM : openclaw-bot (kz1-a, 2 vCPU / 4 GB / 30 GB SSD)
IP : 84.x.x.x
Бот : @your_bot_name
LLM : <one of three lines below>
Workspace : CEO AI OS (48 CEO-скиллов)
Стоимость : ~3–5 ₸/час, ~100 ₸/день (VM) + LLM по тарифу провайдераLLM line variants:
| Provider | Line |
|---|---|
| anthropic | |
| openrouter | |
| openai-codex | |
Что дальше:
• Просто пиши боту в Telegram — он уже знает кто ты, сразу пробуй: «что у меня сегодня важно?»
• Чтобы попробовать стратегические скиллы: «Сделай weekly review» или «Помоги принять решение об X»
• Обновить профиль (роль сменилась, новые приоритеты): скажи мне «обнови мой профиль для бота» — openclaw-user-onboarding перезапустится в standalone-режиме
• Когда захочешь паузу (бот выключится, диск останется): yc compute instance stop --name openclaw-bot
• Совсем удалить: yc compute instance delete --name openclaw-bot && yc vpc security-group delete --name openclaw-bot-sg
Если что-то сломается — просто скажи мне «бот молчит» или «openclaw сломался», я разберусь.
If the verification ping doesn't get a reply within 60 seconds, run `references/04-troubleshooting.md` §4 silently — don't claim success.仅当三项检查全部通过后,发送总结:
根据用户选择的提供商调整行:
LLMOpenClaw запущен в Yandex Cloud Kazakhstan.
VM : openclaw-bot (kz1-a, 2 vCPU / 4 GB / 30 GB SSD)
IP : 84.x.x.x
Бот : @your_bot_name
LLM : <以下三行之一>
Workspace : CEO AI OS (48 CEO-скиллов)
Стоимость : ~3–5 ₸/час, ~100 ₸/день (VM) + LLM по тарифу провайдераLLM行变体:
| 提供商 | 行内容 |
|---|---|
| anthropic | |
| openrouter | |
| openai-codex | |
Что дальше:
• Просто пиши боту в Telegram — он уже знает кто ты, сразу пробуй: «что у меня сегодня важно?»
• Чтобы попробовать стратегические скиллы: «Сделай weekly review» или «Помоги принять решение об X»
• Обновить профиль (роль сменилась, новые приоритеты): скажи мне «обнови мой профиль для бота» — openclaw-user-onboarding перезапустится в standalone-режиме
• Когда захочешь паузу (бот выключится, диск останется): yc compute instance stop --name openclaw-bot
• Совсем удалить: yc compute instance delete --name openclaw-bot && yc vpc security-group delete --name openclaw-bot-sg
Если что-то сломается — просто скажи мне «бот молчит» или «openclaw сломался», я разберусь.
若验证消息60秒内未收到回复,静默执行`references/04-troubleshooting.md` §4——请勿声称部署成功。Auto-recovery (what the wizard does without asking)
自动恢复(向导无需询问即可执行的操作)
These are the things the wizard fixes on its own if it sees them during the run. The user is told only the end result, not the diagnostic steps.
| Detected condition | Silent fix |
|---|---|
| Install to |
Active | Create/activate a dedicated |
| User opens with "у меня workshop-ключ" but no bundle path | Ask once: "Где лежит файл? Можешь перетащить в чат". Then validate |
Plan B bundle has | Warn once: "Bundle от организатора новее, чем я умею. Попробую как есть." Try the standard Plan B steps. Surface any |
Plan B | Tell the user: "Кажется, организатор свернул облако. Напиши ему." Don't retry. |
| Endpoint set to KZ but cloud-id/folder-id are empty or RU-flavoured | Re-resolve via |
Multiple clouds returned by | Use the first; tell the user one line "использую облако |
| Create the default network silently, then create |
Subnet | Create it under the (existing or fresh) default network. |
| Retry once with |
| Always use |
| Generate a new one with no passphrase. |
| Caller IP can't be detected | Fall back to |
| Retry once after 30 seconds. If still fails, escalate. |
Gateway | Keep polling — composio plugin can take that long. Only escalate after 4 minutes. |
| Pairing approval returns "code not found" | Wait 3 seconds, re-list pairing requests. Telegram sometimes lags. |
| The schema field is |
| Bot replies in wrong language after locale pack applied | |
| Bot doesn't reply to verification ping within 30s | Restart adapter once before declaring failure. |
以下是向导运行过程中检测到问题时会自动修复的内容。仅告知用户最终结果,不展示诊断步骤。
| 检测到的情况 | 静默修复 |
|---|---|
| 安装至 |
活动 | 创建/激活专属 |
| 用户以“у меня workshop-ключ”开头但未提供密钥包路径 | 询问一次:“Где лежит файл? Можешь перетащить в чат”。然后验证 |
方案B密钥包的 | 警告一次:“Bundle от организатора новее, чем я умею. Попробую как есть.” 尝试标准方案B步骤。直接展示任何 |
方案B中 | 告知用户:“Кажется, организатор свернул облако. Напиши ему.” 请勿重试。 |
| 端点已设置为KZ,但cloud-id/folder-id为空或属于RU区域 | 通过活动配置文件的 |
| 使用第一个;用一句话告知用户“использую облако |
| 静默创建默认网络,然后创建网段为 |
| 在(现有或新建的)默认网络下创建。 |
| 用 |
| 始终使用之前解析的 |
| 生成新的无密码密钥。 |
| 无法检测调用者IP | 回退为 |
| 30秒后重试一次。若仍失败,升级处理。 |
前90秒网关 | 持续轮询——composio插件可能需要这么长时间。仅在4分钟后升级处理。 |
| 配对批准返回“code not found” | 等待3秒,重新列出配对请求。Telegram有时会延迟。 |
| Schema字段是 |
| 应用区域包后机器人回复语言错误 | 通过SSH重新执行 |
| 验证消息30秒内未收到机器人回复 | 重启适配器一次,然后再宣布失败。 |
Yandex Cloud Kazakhstan — common trip points (read before debugging)
Yandex Cloud哈萨克斯坦区域——常见问题(调试前阅读)
If anything fails during the wizard run, check these first — most YC KZ issues come from one of these five mistakes:
- Endpoint vs cloud-id mismatch. Setting does NOT auto-update
endpoint=api.yandexcloud.kz:443orcloud-id. If you only flip the endpoint, every subsequentfolder-idcall sees an empty result because it's looking up RU IDs against the KZ realm. Always update all three together — endpoint, cloud-id, folder-id — or use a separate profile.yc compute / vpc / resource-manager - doesn't exist on KZ endpoint. Calling
yc billingerrors withyc billing account list. Don't use it for any pre-flight check. Detect billing problems from the actualUnknown command 'billing account list'error message, not by trying to list accounts.yc compute instance create - returning empty. When the OAuth token doesn't match the realm (RU token on KZ endpoint, or vice versa), the call succeeds with an empty array — not an auth error. If empty, the answer is "wrong token", not "no cloud".
yc resource-manager cloud list - lookup is fragile. When the folder has multiple networks (common after the user experiments), the named lookup can pick the wrong one or fail silently. Always resolve to a network-id first (
--network-name default) and passyc vpc network get --name defaultto subsequent commands.--network-id - Subnet not auto-provisioned. Default subnet is created with the default network in most cases, but not all. New empty folders sometimes lack it. Always check before referencing it in instance create.
default-kz1-a
若向导运行期间出现任何问题,请先检查以下内容——大多数YC KZ问题均源于以下五个错误之一:
- 端点与cloud-id不匹配。设置不会自动更新
endpoint=api.yandexcloud.kz:443或cloud-id。若仅切换端点,后续所有folder-id命令都会返回空结果,因为它在KZ领域中查找RU区域的ID。始终同时更新三者——端点、cloud-id、folder-id,或使用单独的配置文件。yc compute / vpc / resource-manager - KZ端点不支持。调用
yc billing会报错yc billing account list。请勿用于任何预检检查。从实际Unknown command 'billing account list'错误消息中检测计费问题,而非尝试列出账户。yc compute instance create - 返回空。当OAuth令牌与领域不匹配(RU区域令牌用于KZ端点,反之亦然)时,调用会成功但返回空数组——而非认证错误。若返回空,原因是“令牌错误”,而非“无云”。
yc resource-manager cloud list - 查找不可靠。当文件夹有多个网络(用户实验后常见)时,按名称查找可能选择错误的网络或静默失败。始终先解析为network-id(
--network-name default),然后将yc vpc network get --name default传递给后续命令。--network-id - 子网未自动预配置。默认子网通常会随默认网络一起创建,但并非所有情况都是如此。全新空文件夹有时缺少该子网。创建实例前始终检查。
default-kz1-a
Failure modes (when the silent fixes aren't enough)
失败场景(静默修复无法解决的问题)
| Symptom | Where to look |
|---|---|
| |
| |
| |
| |
| Already handled by auto-recovery (retry with |
Cloud-init log shows | |
| |
User pressed | |
| Bot pairs but doesn't reply | |
SSH | |
For everything else: dump and from the VM, surface to the user as "вот что я вижу, давай разбираться", do not guess.
/var/log/openclaw-bootstrap.logjournalctl --user -u openclaw-gateway -n 200| 症状 | 排查方向 |
|---|---|
向导配置文件设置后, | |
| |
| |
| |
| 已通过自动恢复处理(用 |
Cloud-init日志显示 | |
4分钟后 | |
用户按下/start但 | |
| 机器人已配对但不回复 | |
SSH报错 | |
其他所有问题:从虚拟机导出和,向用户展示“вот что я вижу, давай разбираться”,请勿猜测。
/var/log/openclaw-bootstrap.logjournalctl --user -u openclaw-gateway -n 200References
参考文档
- — yc CLI install, KZ endpoint init, SSH key, billing checks (most are silent now; only OAuth login and missing billing surface to the user)
references/01-prerequisites.md - — security-group rules, public-IP rationale, hardening choices
references/02-network-and-security.md - — Telegram pairing flow, Anthropic auth, workspace seeding
references/03-openclaw-config.md - — 7 failure modes with copy-paste fixes
references/04-troubleshooting.md - — Plan B (workshop bundle) end-to-end: schema check, profile carve-out, what NOT to do, organizer hand-off
references/05-workshop-key-mode.md - — the full VM bootstrap (Node, OpenClaw, hardening, ceo-ai-os workspace, systemd user service)
scripts/cloud-init.yaml
- ——yc CLI安装、KZ端点初始化、SSH密钥、计费检查(现在大多静默执行;仅OAuth登录和缺失计费会告知用户)
references/01-prerequisites.md - ——安全组规则、公网IP原理、加固选择
references/02-network-and-security.md - ——Telegram配对流程、Anthropic认证、工作区初始化
references/03-openclaw-config.md - ——7种失败场景及复制粘贴式修复方案
references/04-troubleshooting.md - ——方案B(工作坊密钥包)端到端流程:Schema检查、配置文件隔离、禁止操作、组织者移交
references/05-workshop-key-mode.md - ——完整虚拟机引导脚本(Node、OpenClaw、系统加固、ceo-ai-os工作区、systemd用户服务)
scripts/cloud-init.yaml
Companion skills
配套技能
| Skill | Required? | Role |
|---|---|---|
| required | Loaded by Step 0a; owns all post-install consultation (channels, use cases, debugging). |
| recommended | Auto-invoked at Step 5.5 to collect five user facts and write USER.md. If missing, Step 5.5 falls back to a placeholder USER.md and surfaces "поставь openclaw-user-onboarding и скажи 'онбординг'" in the final summary. |
| organizer-only | Matching organizer-side skill that produces the bundle files consumed by this skill's Plan B. Participants don't need it. |
| 技能 | 是否必需 | 角色 |
|---|---|---|
| 必需 | 步骤0a加载;负责所有安装后咨询(渠道、用例、调试)。 |
| 推荐 | 步骤5.5自动调用,收集用户五项信息并写入USER.md。若缺失,步骤5.5回退为占位符USER.md,并在最终总结中提及“поставь openclaw-user-onboarding и скажи 'онбординг'”。 |
| 仅组织者使用 | 对应的组织者端技能,生成本技能方案B中使用的密钥包。参与者无需使用。 |
About openclaw-guide
(required)
openclaw-guide关于openclaw-guide
(必需)
openclaw-guideopenclaw-guide- During install — if cloud-init logs surface something this skill doesn't know about, the agent reads instead of guessing.
openclaw-guide/references/06-troubleshooting.md - After install — when the user asks "how do I add Slack?", "how do I make the bot wake me up at 8am?", "what skills should I install?", the agent reads and
openclaw-guide/references/use-cases.mdto advise. This wizard is silent after Step 5; the guide owns ongoing consultation.openclaw-guide/references/channels.md
Joint install:
bash
npx skills add CodeAlive-AI/ceo-ai-os@install-openclaw-to-yc -g
npx skills add CodeAlive-AI/ceo-ai-os@openclaw-guide -gIf is unavailable: clone and drop and into the agent's skills directory (see this skill's README for per-agent paths).
npxhttps://github.com/CodeAlive-AI/ceo-ai-osskills/install-openclaw-to-ycskills/openclaw-guideopenclaw-guide- 安装期间——若cloud-init日志出现本技能未知的内容,Agent会读取,而非猜测。
openclaw-guide/references/06-troubleshooting.md - 安装后——当用户询问“如何添加Slack?”“如何让机器人早上8点叫醒我?”“我应该安装哪些技能?”时,Agent会读取和
openclaw-guide/references/use-cases.md提供建议。本向导步骤5后静默;指南负责后续咨询。openclaw-guide/references/channels.md
联合安装:
bash
npx skills add CodeAlive-AI/ceo-ai-os@install-openclaw-to-yc -g
npx skills add CodeAlive-AI/ceo-ai-os@openclaw-guide -g若不可用:克隆,将和放入Agent的技能目录(见本技能README中的各Agent路径)。
npxhttps://github.com/CodeAlive-AI/ceo-ai-osskills/install-openclaw-to-ycskills/openclaw-guideEcosystem — what to install next
生态系统——接下来安装什么
The VM ships with all 49 ceo-ai-os skills pre-seeded into the workspace (the bot calls them automatically when the user's request matches). For the agent's own skill loader (the one driving this wizard), here are the highest-ROI add-ons. Mention them only after Step 5 passes — bringing them up earlier dilutes the install flow.
| Trigger ("user later asks for X") | Skill to suggest | One-line pitch |
|---|---|---|
| "I want a daily morning brief" | | Cron-driven morning + evening summary of metrics, calendar, and yesterday's wins. |
| "Help me prep for a strategic decision" | | Structured deliberation with explicit options, kill criteria, and a 7-day review. |
| "Research this company before my meeting" | | Exa-powered company profile (positioning, traction, team) in <30 s. |
| "Find people who fit ICP X" | | Multi-source lead discovery with enrichment. |
| "Watch what competitors are doing" | | Daily radar over competitor sites, blog, GitHub, hiring. |
| "I want to use CodeAlive search inside the bot" | (see | Adds |
Full catalogue lives at . Install any of them globally with:
https://github.com/CodeAlive-AI/ceo-ai-os/tree/main/skillsbash
npx skills add CodeAlive-AI/ceo-ai-os@<skill-name> -g虚拟机已预安装所有49个ceo-ai-os技能到工作区(用户请求匹配时机器人会自动调用)。对于驱动本向导的Agent自身技能加载器,以下是投资回报率最高的附加组件。仅在步骤5通过后提及——提前提及会分散安装流程的注意力。
| 触发条件(“用户之后询问X”) | 建议安装的技能 | 一句话介绍 |
|---|---|---|
| "I want a daily morning brief" | | 由Cron驱动的早晚总结,包含指标、日历和昨日成果。 |
| "Help me prep for a strategic decision" | | 结构化审议,包含明确选项、淘汰标准和7天回顾。 |
| "Research this company before my meeting" | | 基于Exa的公司概况(定位、业绩、团队),生成时间<30秒。 |
| "Find people who fit ICP X" | | 多渠道线索发现及信息补充。 |
| "Watch what competitors are doing" | | 每日监控竞争对手网站、博客、GitHub、招聘信息。 |
| "I want to use CodeAlive search inside the bot" | (见 | 为机器人添加 |
完整技能目录位于。使用以下命令全局安装任意技能:
https://github.com/CodeAlive-AI/ceo-ai-os/tree/main/skillsbash
npx skills add CodeAlive-AI/ceo-ai-os@<skill-name> -gConsulting after install — delegate, don't duplicate
安装后咨询——委托,勿重复
When the user asks anything not about VM install (channel setup, use cases, debugging an existing bot, adding MCP servers, multi-agent), do not answer from memory — read the matching first. The guide is the source of truth for ongoing OpenClaw operations. This skill's job ends after Step 5.
openclaw-guide/references/<file>.md| User asks about | Read first |
|---|---|
| Adding WhatsApp / Slack / Discord / iMessage | |
| Setting up a daily brief, research workflow, decision playbook | |
| Adding CodeAlive search to the bot | |
| Bot stopped responding, OAuth re-auth, memory full | |
| Cron / heartbeat / scheduled jobs | |
当用户询问非虚拟机安装相关的问题(渠道设置、用例、现有机器人调试、添加MCP服务器、多Agent)时,请勿凭记忆回答——先阅读对应的。指南是OpenClaw日常操作的权威来源。本技能的职责在步骤5后结束。
openclaw-guide/references/<file>.md| 用户询问内容 | 先阅读 |
|---|---|
| 添加WhatsApp / Slack / Discord / iMessage | |
| 设置每日简报、研究工作流、决策手册 | |
| 为机器人添加CodeAlive搜索 | |
| 机器人停止响应、OAuth重新认证、内存已满 | |
| Cron / 心跳 / 定时任务 | |
What this skill does NOT cover
本技能不涵盖的内容
- Multi-agent setups (two agents on one VM) — out of scope
- WhatsApp / Discord / Slack channels — Telegram only here; for other channels see
openclaw-guide/references/channels.md - Use-case design (morning brief, research workflows, decision playbooks) — see
openclaw-guide/references/use-cases.md - Backup and migration — separate skill
- Production-grade hardening (SELinux, kernel sysctl, SSH cert auth) — overkill for a workshop / personal CEO bot
- Cost optimisation past the trial grant — §7
references/04-troubleshooting.md
- 多Agent设置(一台虚拟机上两个Agent)——超出范围
- WhatsApp / Discord / Slack渠道——此处仅支持Telegram;其他渠道见
openclaw-guide/references/channels.md - 用例设计(每日简报、研究工作流、决策手册)——见
openclaw-guide/references/use-cases.md - 备份与迁移——单独技能
- 生产级加固(SELinux、内核sysctl、SSH证书认证)——对于工作坊/个人CEO机器人来说过于复杂
- 试用额度之外的成本优化——§7
references/04-troubleshooting.md