install-openclaw-to-yc

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Install 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
/start
in Telegram once, and — only for Codex — confirm a device code on auth.openai.com. Everything else is silent.
本向导可帮助非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.
  1. 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.
  2. 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).
  3. 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…", "Проверяю что бот отвечает…".
  4. Validate inputs upfront with a one-call test (Telegram
    /getMe
    , LLM key probe). Don't burn 15 minutes on a VM bootstrap with a bad key.
  5. Auto-fix prerequisites silently when it's safe — install
    yc
    CLI, generate an SSH key, switch endpoint to Kazakhstan. Only stop and ask the user when something can't be done without their input (
    yc init
    OAuth login, no billing account).
  6. 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
    {{USER_LANGUAGE}}
    (ISO 639-1:
    ru
    /
    en
    /
    kk
    /...), and the bootstrap script appends a localization block to the bot's
    USER.md
    . Default if you can't tell:
    ru
    (workshop audience).
  7. No emojis in user-facing text unless the user used them first.
这些规则优先于文档其他内容,请先阅读。
  1. 仅提两个问题。仅向用户请求Telegram机器人令牌LLM访问方式(三种选项之一——见步骤1)。其余所有内容——虚拟机名称、可用区、镜像、SSH密钥、安全组入站规则、chat_id——均通过安全默认值自动决定或自动检测。
  2. 绝不询问“是否确定”。对于本向导自身范围内的操作(创建专属虚拟机、专属安全组、专属机器人配对),无需确认。仅当要销毁用户可能需要保留的内容(同名现有虚拟机)时,才需确认。
  3. 绝不向用户展示Shell命令、参数、路径或堆栈跟踪,除非用户明确询问“你执行了什么命令?”。进度用通俗易懂的语言展示:“正在创建虚拟机…”、“正在安装OpenClaw…”、“正在验证机器人回复…”。
  4. 提前验证输入。通过单次调用测试(Telegram
    /getMe
    、LLM密钥探测)。避免因无效密钥导致虚拟机启动浪费15分钟时间。
  5. 安全时自动静默修复前置条件——安装
    yc
    CLI、生成SSH密钥、切换至哈萨克斯坦端点。仅当无法在无用户输入的情况下完成操作时(如
    yc init
    OAuth登录、无计费账户),才停止并询问用户。
  6. 单一语言——机器人也使用该语言。若用户用俄语与Agent交流,所有向导提示均为俄语,OpenClaw机器人自身也会配置为俄语回复。从用户最初几条消息中检测语言,将其作为
    {{USER_LANGUAGE}}
    (ISO 639-1格式:
    ru
    /
    en
    /
    kk
    /...)传递给cloud-init,引导脚本会将本地化块追加到机器人的
    USER.md
    中。若无法检测语言,默认使用
    ru
    (工作坊受众常用语言)。
  7. 用户界面文本中不使用表情符号,除非用户先使用。

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 askWhyWhat to do instead
Telegram chat_idAuto-detected in Step 4 from
getUpdates
after the user presses
/start
. Asking for it makes the user open
@userinfobot
, copy a number, paste — pure friction.
Poll
https://api.telegram.org/bot<TOKEN>/getUpdates
every 2s in Step 4. Pluck
result[0].message.chat.id
.
VM nameDefault is
openclaw-bot
. If taken, append
-<random4>
.
Set silently. Tell user the name only in the final summary.
SSH IP restrictionDefault is "current laptop IP, lock SSH to it". Detected via
curl https://api.ipify.org
. Fallback
0.0.0.0/0
+ fail2ban if detection fails.
Set silently.
Zone / region / subnet / image / VM shapeAll 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 VMAlways
openclaw
.
Use it without asking.
Anthropic / OpenRouter / OpenAI billing balanceCaught 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中通过
getUpdates
自动检测。询问该信息会让用户打开
@userinfobot
、复制数字、粘贴——完全是额外操作。
在步骤4中每2秒轮询
https://api.telegram.org/bot<TOKEN>/getUpdates
。提取
result[0].message.chat.id
虚拟机名称默认名称为
openclaw-bot
。若已被占用,追加
-<random4>
静默设置。仅在最终总结中告知用户名称。
SSH IP限制默认设置为“当前笔记本IP,仅允许该IP访问SSH”。通过
curl https://api.ipify.org
检测。若检测失败,回退为
0.0.0.0/0
+ fail2ban防护。
静默设置。
可用区/区域/子网/镜像/虚拟机规格均为Yandex Cloud哈萨克斯坦区域硬编码配置(kz1-a、ubuntu-2404-lts、standard-v3、2 vCPU / 4 GB内存 / 30 GB存储)。不向用户展示。
虚拟机上的Linux用户名固定为
openclaw
直接使用,无需询问。
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
    openclaw/install.sh
    in this repo (the user runs it on their laptop)
  • 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
    prepare-yc-workshop
    (the matching organizer-side skill) — this skill is for the participant
在用户提及以下内容时触发:“在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.
ModeWhenWhat the user suppliesSkill does
Plan A — own YC account (default)The user has (or is willing to create) a Yandex Cloud Kazakhstan account.OAuth token from
oauth.yandex.kz
(asked once in Step 0d).
yc init
-equivalent on a wizard-owned profile + own cloud-id/folder-id.
Plan B — workshop bundleThe user is at a workshop, the organizer DM'd them a
bundle-NN.json
file, and they don't want / don't have time to set up their own YC.
Path to the
bundle-NN.json
file the organizer sent them.
Parses the bundle, configures
yc
with the embedded service-account key + cloud-id + folder-id. No OAuth, no personal YC account needed.
Plan B is recognised by detecting a workshop bundle file in any of these ways (auto-detected in Step 0.5 below):
  1. The user pasted a file path that resolves to a JSON whose
    $schema
    starts with
    openclaw-workshop-bundle@
    .
  2. The user said one of: "у меня workshop-ключ", "вот bundle от организатора", "I have a workshop key", "organizer gave me a key file", "у меня нет своего Yandex Cloud, есть только ключ от воркшопа".
  3. A file matching
    bundle-*.json
    is present in the user's current working directory or
    ~/Downloads
    (offered with a one-line confirmation).
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哈萨克斯坦账户。
oauth.yandex.kz
的OAuth令牌(步骤0d中询问一次)。
在向导专属配置文件中执行等效
yc init
操作 + 设置自有cloud-id/folder-id。
方案B——工作坊密钥包用户正在参加工作坊,组织者已通过私信发送
bundle-NN.json
文件,且用户不想/没时间设置自有YC账户。
组织者发送的
bundle-NN.json
文件路径。
解析密钥包,使用嵌入的服务账户密钥 + cloud-id + folder-id配置
yc
。无需OAuth,无需个人YC账户。
通过以下任意方式自动检测方案B(在步骤0.5中自动检测):
  1. 用户粘贴的文件路径指向一个JSON文件,其
    $schema
    openclaw-workshop-bundle@
    开头。
  2. 用户提及以下内容之一:“у меня workshop-ключ”“вот bundle от организатора”“I have a workshop key”“organizer gave me a key file”“у меня нет своего Yandex Cloud, есть только ключ от воркшопа”。
  3. 用户当前工作目录或
    ~/Downloads
    中存在匹配
    bundle-*.json
    的文件(用单行消息确认后使用)。
若以上均不匹配,向导默认使用方案A。
步骤0.5之后,两个分支合并——无论使用哪种模式,步骤1、2、3、4、5均完全一致。方案A和方案B最终都会生成指向某个文件夹的有效YC配置文件;后续所有操作仅需使用该配置文件。

Inputs (the only two questions you ask)

输入内容(仅需询问的两个问题)

#InputHow user gets it (paste this verbatim in your prompt)
1Telegram bot tokenOpen @BotFather in Telegram → send
/newbot
→ pick any display name → pick a username ending in
bot
→ copy the token (looks like
7892341234:AAFhJk2mNopq…
).
2LLM access — one of three optionsSee the table below. The user picks ONE option, the wizard auto-detects which one from the format of what they paste.
序号输入内容用户获取方式(提示语直接复制使用)
1Telegram机器人令牌在Telegram中打开@BotFather → 发送
/newbot
→ 选择任意显示名称 → 选择以
bot
结尾的用户名 → 复制令牌(格式类似
7892341234:AAFhJk2mNopq…
)。
2LLM访问方式——三种选项之一见下表。用户选择其中一种,向导根据用户粘贴内容的格式自动检测。

LLM access options (the user picks one)

LLM访问选项(用户选择其一)

OptionWhat user pastesDetection signalCost / requirements
A. Anthropic API keyKey starting with
sk-ant-…
from console.anthropic.com/settings/keys
Prefix
sk-ant-
≥$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 keyKey starting with
sk-or-…
from openrouter.ai/keys
Prefix
sk-or-
≥$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 ChatGPTThe literal word
Codex
(or
codex
,
chatgpt
,
oauth
) — not a key
Token doesn't start with
sk-
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
gpt-4.5
/
gpt-4o
/
o3
; Pro gives
gpt-5.5
.
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 silentlyValueHow
VM name
openclaw-bot
(or
openclaw-bot-<random4>
if taken)
If
yc compute instance get --name openclaw-bot
returns a result, append a random 4-char suffix and try again.
Zone
kz1-a
Only zone in YC Kazakhstan.
Subnet
default-kz1-a
Auto-provisioned in any new KZ folder.
OS image
ubuntu-2404-lts
(latest)
From
standard-images
folder.
VM shape
standard-v3
, 2 vCPU, 4 GB RAM, 30 GB SSD
Matches the reference deployment.
Public IPyes, ephemeral IPv4 NATSimplest path for SSH from anywhere.
Linux user
openclaw
(sudo, no password)
Created by cloud-init.
SSH key
~/.ssh/id_ed25519.pub
(or auto-generate if missing)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
if absent.
SSH ingress
<current public IP>/32
curl -s https://api.ipify.org
. If you can't reach ipify, fall back to
0.0.0.0/0
+ fail2ban defense.
Outboundopen to anywhereOpenClaw needs Anthropic, Telegram, OpenAI, OpenRouter, etc. — locking down by domain is fragile.
Telegram chat_idauto-detected after first
/start
Poll
https://api.telegram.org/bot<TOKEN>/getUpdates
. Never asked.
Primary modelDepends on chosen LLM option, see table below
Fallback modelsDepends on chosen LLM option, see table below
选项用户粘贴内容检测标识成本/要求
A. Anthropic API密钥来自console.anthropic.com/settings/keys、以
sk-ant-…
开头的密钥
前缀
sk-ant-
console.anthropic.com/settings/billing账户余额≥5美元。原始质量最佳。按需付费(Sonnet 4.6模型约每百万输入令牌3美元)。
B. OpenRouter API密钥来自openrouter.ai/keys、以
sk-or-…
开头的密钥
前缀
sk-or-
OpenRouter账户余额≥5美元。通过一个密钥统一访问Anthropic + OpenAI + 其他200多种模型,比原生价格高约5%。适合之后想要对比测试不同模型的用户。
C. 通过ChatGPT使用OpenAI Codex输入字面单词
Codex
(或
codex
chatgpt
oauth
)——不是密钥
令牌不以
sk-
开头
有效的**ChatGPT Plus(每月20美元)Pro(每月200美元)**订阅。虚拟机引导完成后,向导会在auth.openai.com上提示用户输入一次设备代码——无需API密钥,无需计量计费。Plus订阅可使用
gpt-4.5
/
gpt-4o
/
o3
;Pro订阅可使用
gpt-5.5
提示语中的推荐顺序:A → C → B(针对首次使用者)。A是最简单的顺畅路径,搭配最佳的Anthropic模型。C适合已订阅ChatGPT且不想额外付费的用户。B是高级用户选择。
以下所有内容均无需询问用户,自动决定:
自动决定项实现方式
虚拟机名称
openclaw-bot
(若已被占用,则为
openclaw-bot-<random4>
yc compute instance get --name openclaw-bot
返回结果,则追加随机4位后缀后重试。
可用区
kz1-a
Yandex Cloud哈萨克斯坦区域唯一可用区。
子网
default-kz1-a
任何新的KZ文件夹中都会自动预配置。
操作系统镜像
ubuntu-2404-lts
(最新版)
来自
standard-images
文件夹。
虚拟机规格
standard-v3
、2 vCPU、4 GB内存、30 GB SSD
与参考部署一致。
公网IP是,临时IPv4 NAT从任意位置访问SSH的最简单方式。
Linux用户
openclaw
(拥有sudo权限,无密码)
由cloud-init创建。
SSH密钥
~/.ssh/id_ed25519.pub
(若不存在则自动生成)
若不存在,执行
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
SSH入站规则
<当前公网IP>/32
通过
curl -s https://api.ipify.org
获取。若无法访问ipify,回退为
0.0.0.0/0
+ fail2ban防护。
出站规则允许访问任意地址OpenClaw需要访问Anthropic、Telegram、OpenAI、OpenRouter等——按域名锁定过于脆弱。
Telegram chat_id首次按下/start后自动检测轮询
https://api.telegram.org/bot<TOKEN>/getUpdates
。绝不询问用户。
主模型取决于所选LLM选项,见下表
备用模型取决于所选LLM选项,见下表

Default models per LLM option

各LLM选项对应的默认模型

Option
agents.defaults.model.primary
agents.defaults.model.fallbacks
A. Anthropic
anthropic/claude-sonnet-4-6
["anthropic/claude-haiku-4-5"]
B. OpenRouter
openrouter/moonshotai/kimi-k2.6
["openrouter/openai/gpt-5.5", "openrouter/anthropic/claude-haiku-4-5"]
C. OpenAI Codex
openai-codex/gpt-5.5
(Pro) or
openai-codex/gpt-4o
(Plus only)
["openai-codex/gpt-4o"]
For C, the wizard probes the user's subscription tier after OAuth completes — if
gpt-5.5
isn't in
openclaw models list
, fall back to
gpt-4o
as primary.
选项
agents.defaults.model.primary
agents.defaults.model.fallbacks
A. Anthropic
anthropic/claude-sonnet-4-6
["anthropic/claude-haiku-4-5"]
B. OpenRouter
openrouter/moonshotai/kimi-k2.6
["openrouter/openai/gpt-5.5", "openrouter/anthropic/claude-haiku-4-5"]
C. OpenAI Codex
openai-codex/gpt-5.5
(Pro订阅)或
openai-codex/gpt-4o
(仅Plus订阅)
["openai-codex/gpt-4o"]
对于选项C,向导会在OAuth完成后探测用户的订阅级别——若
openclaw models list
中没有
gpt-5.5
,则回退为
gpt-4o
作为主模型。

Wizard 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
    api.yandexcloud.kz:443
    . The Russian endpoint
    api.cloud.yandex.net:443
    and 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.
  • Setting
    yc config set endpoint api.yandexcloud.kz:443
    does NOT auto-update
    cloud-id
    or
    folder-id
    . If you only flip the endpoint and don't re-set cloud-id/folder-id, every subsequent
    yc compute / vpc / resource-manager
    command will fail with NotFound, because those IDs belong to the RU realm.
  • The KZ endpoint exposes a smaller command set:
    iam
    ,
    quota-manager
    ,
    resource-manager
    ,
    compute
    ,
    vpc
    ,
    dns
    ,
    managed-kubernetes
    .
    yc billing
    does NOT exist on the KZ endpoint.
    Calling
    yc billing account list
    always errors out — don't use it for any check.
  • Use named profiles (
    yc config profile create/activate
    ) instead of editing the active config. The user almost certainly already has profiles for their other clouds — don't clobber them.
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:
  1. Explicit file path in what the user said. Resolve the path; if it's a readable JSON whose
    $schema
    field starts with
    openclaw-workshop-bundle@
    , set
    MODE=plan-b
    and
    BUNDLE_PATH=<path>
    .
  2. 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: "Где лежит файл
      bundle-NN.json
      от организатора? (можешь перетащить файл в чат, или просто путь)" — accept the path, validate the
      $schema
      , set
      MODE=plan-b
      .
  3. Auto-discovery. Glob
    bundle-*.json
    in
    $PWD
    ,
    ~/Downloads
    ,
    ~/Desktop
    . If exactly one match whose
    $schema
    starts with
    openclaw-workshop-bundle@
    , ask once: "Нашёл workshop-ключ
    bundle-NN.json
    в
    <path>
    . Это от организатора? (да / нет)". On "да" →
    MODE=plan-b
    . On "нет" → continue to next step.
  4. Default. No bundle detected →
    MODE=plan-a
    . 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.
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
    。俄罗斯区域端点
    api.cloud.yandex.net:443
    与KZ端点服务不同的云、文件夹和OAuth领域。混淆两者是“向导提示无计费/无云,但实际均存在”问题的头号原因。
  • 设置
    yc config set endpoint api.yandexcloud.kz:443
    不会自动更新
    cloud-id
    folder-id
    。若仅切换端点而未重新设置cloud-id/folder-id,后续所有
    yc compute / vpc / resource-manager
    命令都会因NotFound失败,因为这些ID属于俄罗斯领域。
  • KZ端点支持的命令集更小
    iam
    quota-manager
    resource-manager
    compute
    vpc
    dns
    managed-kubernetes
    KZ端点不支持
    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保留这些步骤。
检测顺序:
  1. 用户提及的明确文件路径。解析路径;若为可读JSON且
    $schema
    字段以
    openclaw-workshop-bundle@
    开头,则设置
    MODE=plan-b
    BUNDLE_PATH=<path>
  2. 短语匹配。若用户在触发消息中提及以下内容(或类似表述):
    • "У меня 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
  3. 自动发现。在
    $PWD
    ~/Downloads
    ~/Desktop
    中查找
    bundle-*.json
    文件。若找到唯一匹配且
    $schema
    openclaw-workshop-bundle@
    开头的文件,则询问一次:“Нашёл workshop-ключ
    bundle-NN.json
    в
    <path>
    . Это от организатора? (да / нет)”。若用户回复“да” → 设置
    MODE=plan-b
    。若回复“нет” → 继续下一步。
  4. 默认值。未检测到密钥包 → 设置
    MODE=plan-a
    。请勿提前询问“你有工作坊密钥吗?”——这会给超过50%拥有自有YC账户的用户带来额外干扰。
密钥包文件的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

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`):

```bash
for f in cloud_id folder_id zone endpoint key; do jq -er ".${f}" "$BUNDLE_PATH" >/dev/null
|| { say "В bundle не хватает поля ${f}. Попроси у организатора новый файл."; stop; } done

若方案B验证失败,用一句话告知用户问题所在,建议联系组织者,然后停止——请勿静默回退到方案A。回退会浪费10分钟询问用户没有的OAuth信息。

**若`MODE=plan-b`**:从密钥包配置`yc`,直接跳至步骤0a,然后是0f、0g(跳过c、d、e):

```bash

Wizard-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
所需的格式

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")"
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; }

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; }

方案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

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-a
compute-default-zone
is decoupled from endpoint —
yc config set endpoint
doesn't touch it. Without it set, any
yc compute *
command that omits
--zone
falls back to whatever was there before (often
ru-central1-a
from a previous RU init) and fails with "zone not found".
e. 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"
fi
Failure modes:
  • cloud list
    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: "Использую облако
    <NAME>
    . Если это не то — скажи, переключусь."
  • Same logic for folder.
Do not call
yc billing account list
.
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.
f. SSH key.
ls ~/.ssh/id_ed25519.pub
. If missing: silently
ssh-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.
yc compute instance get --name openclaw-bot 2>/dev/null
. If a result comes back, ask once: "У тебя уже есть VM 'openclaw-bot' — поставить новую под именем
openclaw-bot-XXXX
?" Default yes; pick a random 4-char suffix.
Do 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

执行完此模块后,活动配置文件要么是用户预先存在的指向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-a
compute-default-zone
与端点解耦——
yc config set endpoint
不会修改它。若未设置,任何省略
--zone
yc compute *
命令都会回退到之前的设置(通常是之前RU区域初始化时的
ru-central1-a
),并因“可用区未找到”失败。
e. 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
失败场景:
  • cloud list
    返回空 → OAuth令牌对应的Yandex ID在KZ区域没有云。告知用户:“Похоже, у тебя нет облака в Yandex Cloud Kazakhstan. Создай облако в https://kz.console.yandex.cloud, потом запусти меня снова.” 停止执行。
  • cloud list
    返回多个 → 使用第一个,并用一句话告知用户:“Использую облако
    <NAME>
    . Если это не то — скажи, переключусь.”
  • 文件夹的处理逻辑与云相同。
请勿调用
yc billing account list
。KZ端点不支持该命令。若用户有云且有文件夹,计费要么已激活,要么会在虚拟机创建时因明确错误失败。在步骤2中捕获该错误即可。
f. SSH密钥。执行
ls ~/.ssh/id_ed25519.pub
。若不存在:静默执行
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" -C "openclaw-yc-$(date +%Y%m%d)"
g. 当前云中是否存在同名实例。执行
yc compute instance get --name openclaw-bot 2>/dev/null
。若返回结果,询问用户一次:“У тебя уже есть VM 'openclaw-bot' — поставить новую под именем
openclaw-bot-XXXX
?” 默认回复“是”;选择随机4位后缀。
若(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 → отправь
/newbot
→ придумай имя (любое) → придумай username, заканчивающийся на
bot
→ BotFather пришлёт токен. Пришли его мне.
2) Доступ к LLM — выбери ОДИН из трёх вариантов:
A) Anthropic API ключ (рекомендую первым, лучшее качество) Открой https://console.anthropic.com/settings/keys → Create Key. Ключ начинается на
sk-ant-
. На https://console.anthropic.com/settings/billing должно быть ≥$5.
B) OpenRouter API ключ (один ключ к Anthropic + OpenAI + 200 моделям) Открой https://openrouter.ai/keys → Create Key. Начинается на
sk-or-
. Нужен баланс ≥$5 на openrouter.ai/credits.
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
    ;;
esac
Validate 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 → отправь
/newbot
→ придумай имя (любое) → придумай username, заканчивающийся на
bot
→ BotFather пришлёт токен. Пришли его мне.
2) Доступ к LLM — выбери ОДИН из трёх вариантов:
A) Anthropic API ключ (рекомендую первым, лучшее качество) Открой https://console.anthropic.com/settings/keys → Create Key. Ключ начинается на
sk-ant-
. На https://console.anthropic.com/settings/billing должно быть ≥$5.
B) OpenRouter API ключ (один ключ к Anthropic + OpenAI + 200 моделям) Открой https://openrouter.ai/keys → Create Key. Начинается на
sk-or-
. Нужен баланс ≥$5 на openrouter.ai/credits.
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
undefined

Telegram 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)
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

`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)
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

`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)
fi
Don'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
TELEGRAM_CHAT_ID
— it's auto-detected in Step 4):
  • {{TELEGRAM_BOT_TOKEN}}
    — from Step 1.
  • {{SSH_PUBLIC_KEY}}
    — content of
    ~/.ssh/id_ed25519.pub
    .
  • {{LLM_ENV_LINE}}
    — depends on the chosen LLM provider:
    ProviderSubstituted 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
/tmp/openclaw-cloud-init.yaml
with mode 600.
d. 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
--network-id
not
--network-name
. The named lookup fails silently in some yc CLI versions when the folder has multiple networks.
e. Create the instance. Try
standard-v3
first (Intel Ice Lake), fall back to
standard-v2
(Cascade Lake) if v3 isn't available in this folder:
bash
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.err
a. 确保当前文件夹中存在默认网络 + 子网。全新文件夹有时缺少这些资源(或用户已删除)。请勿假设——先检测,若不存在则创建。
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文件。替换以下占位符(无需
TELEGRAM_CHAT_ID
——将在步骤4中自动检测):
  • {{TELEGRAM_BOT_TOKEN}}
    ——来自步骤1。
  • {{SSH_PUBLIC_KEY}}
    ——
    ~/.ssh/id_ed25519.pub
    的内容。
  • {{LLM_ENV_LINE}}
    ——取决于所选LLM提供商:
    提供商替换后的行
    anthropic
    ANTHROPIC_API_KEY=<key>
    openrouter
    OPENROUTER_API_KEY=<key>
    openai-codex(空字符串——此阶段无需环境变量;OAuth会在步骤4.5后填充配置文件)
将内容写入
/tmp/openclaw-cloud-init.yaml
,权限设置为600。
d. 创建安全组
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)
注意:使用
--network-id
而非
--network-name
。在某些yc CLI版本中,当文件夹有多个网络时,按名称查找会静默失败。
e. 创建实例。首先尝试
standard-v3
(Intel Ice Lake),若该文件夹不支持v3则回退为
standard-v2
(Cascade Lake):
bash
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.err

If 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 mentionsTell the user
firewall / hardening"Настраиваю файрвол и SSH"
nodesource / Node"Ставлю Node.js"
npm install
openclaw
"Качаю 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"
npm install
openclaw
"Качаю OpenClaw"
ceo-ai-os / install.sh"Загружаю CEO-скиллы"
openclaw onboard / config"Подключаю Telegram и LLM"
systemd / health"Запускаю бот"
最长等待15分钟。若仍未就绪,向用户发送一句话(“Что-то пошло не так на VM, проверяю логи”),并跳转至
references/04-troubleshooting.md

Step 3.5 — OAuth device-code flow (ONLY if
LLM_PROVIDER=openai-codex
)

步骤3.5——OAuth设备码流程(仅当
LLM_PROVIDER=openai-codex
时执行)

Skip this entire step for
anthropic
and
openrouter
— they have the key already in
gateway.env
and the bot is ready to talk.
For
openai-codex
, 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:
bash
ssh -tt -o ServerAliveInterval=30 openclaw@$IP \
  "openclaw models auth login --provider openai-codex --device-code" \
  | tee /tmp/openclaw-oauth.log
The CLI prints two things on stdout, usually within 2 seconds:
  • A URL like
    https://auth.openai.com/codex/device
    (or
    https://auth.openai.com/device
    )
  • An 8-character code like
    ABCD-1234
Extract both with a regex on
/tmp/openclaw-oauth.log
(the formats may shift slightly across OpenClaw releases — match generously). Show the user one clean message:
Последний шаг — подключи бота к 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
auth-profiles.json
with the OAuth token and the gateway will pick it up on next config reload.
Known pitfall (issue #74212, 2026-05): in some SSH sessions OpenClaw masks the device-pairing code as
[shown on the local device only]
. If that's what you see in
/tmp/openclaw-oauth.log
:
  • Retry with
    ssh -tt
    if you didn't already — the masking is triggered by a TTY check that some non-interactive SSH invocations fail.
  • If retry doesn't help: run the auth command directly inside a fresh SSH session (
    ssh openclaw@$IP
    openclaw models auth login --provider openai-codex --device-code
    ), pull the code from there, then resume the wizard.
After the OAuth profile is written:
bash
undefined
anthropic
openrouter
用户跳过此步骤——他们的密钥已在
gateway.env
中,机器人已准备就绪。
对于
openai-codex
用户,cloud-init已启动网关但未配置模型(环境中没有Anthropic/OpenRouter密钥)。现在通过SSH强制使用TTY执行设备码OAuth流程:
bash
ssh -tt -o ServerAliveInterval=30 openclaw@$IP \
  "openclaw models auth login --provider openai-codex --device-code" \
  | tee /tmp/openclaw-oauth.log
CLI通常会在2秒内在标准输出中打印两项内容:
  • 类似
    https://auth.openai.com/codex/device
    (或
    https://auth.openai.com/device
    )的URL
  • 8位字符的代码,例如
    ABCD-1234
通过正则表达式从
/tmp/openclaw-oauth.log
中提取两者(OpenClaw版本不同格式可能略有变化——宽松匹配)。向用户展示一条清晰的消息:
Последний шаг — подключи бота к 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
中看到此内容:
  • 若尚未使用
    ssh -tt
    ,则重试——屏蔽是由TTY检查触发的,某些非交互式SSH调用会失败。
  • 若重试无效:在新的SSH会话中直接执行认证命令(
    ssh openclaw@$IP
    openclaw models auth login --provider openai-codex --device-code
    ),从中提取代码,然后继续向导流程。
OAuth配置文件写入后:
bash
undefined

Probe 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')
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

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
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')
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

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
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
/var/lib/openclaw-bootstrap-done
exists, the gateway is up in
pairing
mode. This is where wizards historically fail silently: they think
openclaw pairing approve
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-done
存在时,网关已处于
pairing
模式。这是向导历史上经常静默失败的环节:向导认为
openclaw pairing approve
成功,将控制权交给用户,但用户发现机器人仍要求输入确认码。请完整阅读本节。

What actually happens when the user presses /start

用户按下/start时的实际流程

  1. Telegram delivers
    /start
    to the bot.
  2. OpenClaw enforces
    dmPolicy=pairing
    — it does not drop the message, it calls
    issuePairingChallenge()
    , 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 run
    openclaw pairing approve telegram ABCD-1234
    "). The user sees this message; they shouldn't reply to it.
  3. The pending request lives in
    openclaw pairing list telegram --format json
    until either approved or expired.
  1. Telegram将
    /start
    发送给机器人。
  2. OpenClaw强制执行
    dmPolicy=pairing
    ——它不会丢弃消息,而是调用
    issuePairingChallenge()
    ,在网关中记录待处理请求,且机器人会向用户回复配对代码 + 说明(类似“完成配对,请让管理员执行
    openclaw pairing approve telegram ABCD-1234
    ”)。用户会看到此消息;无需回复。
  3. 待处理请求会保留在
    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
undefined
bash
undefined

Empty 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 минут"
undefined
for 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 минут"
undefined

Approve the pairing (the part the old wizard broke)

批准配对(旧版向导出错的环节)

The pending pairing request lives in
openclaw pairing list telegram --format json
. Its schema (verified against
src/gateway/protocol/schema/devices.ts
) uses
senderId
for the Telegram user ID and
requestId
for the primary key — not
chatId
and not
code
. A wizard that filters on
.chatId == $CHAT_ID
always gets empty results and the subsequent
xargs approve
is a no-op.
Defensive filter (handles both schemas in case a future OpenClaw release renames again):
bash
undefined
待处理配对请求存在于
openclaw pairing list telegram --format json
中。其Schema(已针对
src/gateway/protocol/schema/devices.ts
验证)使用**
senderId
表示Telegram用户ID,
requestId
**表示主键——不是
chatId
,也不是
code
。若向导使用
.chatId == $CHAT_ID
过滤,总会得到空结果,后续
xargs approve
也不会执行任何操作。
防御性过滤(兼容未来OpenClaw版本可能的重命名):
bash
undefined

Give 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
[[ -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)"
undefined
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
[[ -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)"
undefined

Lock 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
/health
returns 200:
bash
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
If the user doesn't press
/start
within 5 minutes, poke them gently with a one-line reminder. After 15 minutes of no signal, stop and tell them how to resume.
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
"
等待约60秒,让网关重启。直到
/health
返回200后,再进入步骤5:
bash
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_LANGUAGE
):
bash
undefined
从用户的笔记本发送探测消息,使用步骤0中设置的语言(
USER_LANGUAGE
):
bash
undefined

Language-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}"
undefined
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}"
undefined

5b. 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
references/04-troubleshooting.md
§4c-e.
Check 2 — A bot reply appears in
getUpdates
within 90s. Poll for any new update authored by the bot:
bash
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
getUpdates
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).
Check 3 — User confirms. Ask the user once, in their language:
Бот должен был тебе ответить в Telegram. Ответил?
Wait for "да"/"yes"/"работает". If "нет"/"не отвечает" — jump to
references/04-troubleshooting.md
§4. Never claim success unless all three pass.
检查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未完成,或环境密钥为空)。跳转至
references/04-troubleshooting.md
§4c-e。
检查2——90秒内
getUpdates
中出现机器人回复
。轮询是否有机器人发送的新更新:
bash
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с"
注意:机器人自身的出站消息不会直接出现在
getUpdates
中——但发送后续探测消息后,机器人的回复作为转发/前置上下文出现在后续更新中。若测试环境中此检查不可靠,回退为检查1(日志) + 检查3(用户确认)。
检查3——用户确认。用用户的语言询问一次:
Бот должен был тебе ответить в Telegram. Ответил?
等待用户回复“да”/“yes”/“работает”。若回复“нет”/“не отвечает”——跳转至
references/04-troubleshooting.md
§4。仅当三项检查全部通过时,才能声称部署成功。

5c. 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)

步骤5.5——用户引导(移交至
openclaw-user-onboarding
技能)

The bot is alive but anonymous — it doesn't know who's talking to it. Before the final summary, hand off to
openclaw-user-onboarding
, which collects five basic fields about the user (identity, focus, communication style, tools, anti-patterns), writes
USER.md
on the VM, and resets the Telegram session so the bot picks up the profile from the very next message.
Hand-off payload (everything the onboarding skill needs):
VariableSource in this wizard
IP
Step 2e
external_ipv4_address
CHAT_ID
Step 4 (auto-detected from
getUpdates
)
BOT_TOKEN
Step 1 (Telegram token the user pasted)
USER_LANGUAGE
Step 0 (detected from user's first messages)
AGENT_TYPE
main
(this wizard always installs the main agent)
Trigger the skill with a single one-liner to the user, in their language:
Бот живой. Последний шаг — расскажи о себе коротко, чтобы я с первого сообщения был полезным.
Then immediately invoke
openclaw-user-onboarding
. The onboarding skill takes over the conversation:
  1. Asks the five questions in one message
  2. Parses the user's free-form reply
  3. Renders
    USER.md
    from the template
  4. Shows a 15-line preview, asks for confirmation
  5. Atomic SCP upload to
    ~/.openclaw/workspace/USER.md
    (mode 600, owned by
    openclaw:openclaw
    )
  6. Resets the active Telegram session (or restarts gateway as fallback)
  7. 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
openclaw-user-onboarding
standalone later.
If
openclaw-user-onboarding
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
技能,该技能会收集用户的五项基本信息(身份、关注点、沟通风格、使用工具、避坑指南),在虚拟机上写入
USER.md
,并重置Telegram会话,让机器人从下一条消息开始读取配置文件。
移交负载(引导技能所需的所有信息):
变量来源
IP
步骤2e中的
external_ipv4_address
CHAT_ID
步骤4(从
getUpdates
自动检测)
BOT_TOKEN
步骤1(用户粘贴的Telegram令牌)
USER_LANGUAGE
步骤0(从用户最初几条消息检测)
AGENT_TYPE
main
(本向导始终安装主Agent)
用用户的语言发送一句话触发技能:
Бот живой. Последний шаг — расскажи о себе коротко, чтобы я с первого сообщения был полезным.
然后立即调用
openclaw-user-onboarding
。引导技能会接管对话:
  1. 用一条消息询问五个问题
  2. 解析用户的自由格式回复
  3. 根据模板渲染
    USER.md
  4. 展示15行预览,请求确认
  5. 原子化SCP上传至
    ~/.openclaw/workspace/USER.md
    (权限600,所有者
    openclaw:openclaw
  6. 重置活动Telegram会话(或回退为重启网关)
  7. 将控制权交回本向导
若用户想完全跳过引导(回复“пропусти”“skip”“потом”):写入最小占位符USER.md并继续。请勿阻塞——此步骤的引导是锦上添花,而非必要条件。用户之后可单独运行
openclaw-user-onboarding
若未加载
openclaw-user-onboarding
技能(Agent未安装):回退为内联写入最小占位符USER.md,并在最终总结中提及:“Чтобы дозаполнить профиль, поставь скилл openclaw-user-onboarding и скажи мне «онбординг».”

Final hand-off message

最终移交消息

Only after all three checks pass, drop the summary:
Then drop the final summary. Adapt the
LLM
line to the provider the user chose:
OpenClaw запущен в 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:
ProviderLine
anthropic
LLM          : Anthropic Claude Sonnet 4.6 (API key, ~$3/M tokens)
openrouter
LLM          : OpenRouter → Moonshot Kimi K2.6 (API key, +5% markup)
openai-codex
LLM          : OpenAI Codex / gpt-5.5 (ChatGPT Pro подписка)
or
gpt-4o (Plus подписка)
depending on what got resolved in Step 3.5
Что дальше: • Просто пиши боту в 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.
仅当三项检查全部通过后,发送总结:
根据用户选择的提供商调整
LLM
行:
OpenClaw запущен в 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
LLM          : Anthropic Claude Sonnet 4.6 (API key, ~$3/M tokens)
openrouter
LLM          : OpenRouter → Moonshot Kimi K2.6 (API key, +5% markup)
openai-codex
LLM          : OpenAI Codex / gpt-5.5 (ChatGPT Pro подписка)
gpt-4o (Plus подписка)
,取决于步骤3.5中解析的结果
Что дальше: • Просто пиши боту в 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 conditionSilent fix
yc
CLI missing
Install to
$HOME/yandex-cloud/bin
, add to PATH for this session.
Active
yc
profile points at RU but user has a KZ cloud
Create/activate a dedicated
openclaw-kz
profile, set token + endpoint + cloud-id + folder-id. Don't touch the user's existing profiles.
User opens with "у меня workshop-ключ" but no bundle pathAsk once: "Где лежит файл? Можешь перетащить в чат". Then validate
$schema
. Don't auto-fall-back to Plan A — the user already told us they have a key, asking for OAuth would be wrong.
Plan B bundle has
$schema
newer than
openclaw-workshop-bundle@1
Warn once: "Bundle от организатора новее, чем я умею. Попробую как есть." Try the standard Plan B steps. Surface any
yc
error plainly.
Plan B
yc compute zone list
returns empty (key revoked / folder gone)
Tell the user: "Кажется, организатор свернул облако. Напиши ему." Don't retry.
Endpoint set to KZ but cloud-id/folder-id are empty or RU-flavouredRe-resolve via
yc resource-manager cloud list
/
folder list
on the active profile, then
yc config set
.
Multiple clouds returned by
cloud list
Use the first; tell the user one line "использую облако
<NAME>
".
yc vpc network get --name default
returns nothing
Create the default network silently, then create
default-kz1-a
subnet with range
10.130.0.0/24
.
Subnet
default-kz1-a
missing
Create it under the (existing or fresh) default network.
--platform standard-v3
rejected as "not supported in folder"
Retry once with
--platform standard-v2
.
--network-name default
silently picks the wrong network
Always use
--network-id
/
--subnet-id
(resolved earlier), never the
-name
variant.
~/.ssh/id_ed25519.pub
missing
Generate a new one with no passphrase.
Caller IP can't be detectedFall back to
0.0.0.0/0
ingress with fail2ban defense (one-line note to user).
npm install -g openclaw
failed once
Retry once after 30 seconds. If still fails, escalate.
Gateway
/health
returns non-200 for first 90 seconds
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.
openclaw pairing list
returns entries but jq filter on
.chatId
returns empty
The schema field is
.senderId
/
.requestId
, not
.chatId
/
.code
. The wizard's Step 4 uses a defensive filter that tries both — don't simplify it.
Bot replies in wrong language after locale pack applied
cat
the locale pack again over SSH +
openclaw sessions reset --channel telegram --to <CHAT_ID>
to force USER.md re-read. See Step 5c.
Bot doesn't reply to verification ping within 30sRestart adapter once before declaring failure.
以下是向导运行过程中检测到问题时会自动修复的内容。仅告知用户最终结果,不展示诊断步骤。
检测到的情况静默修复
yc
CLI未安装
安装至
$HOME/yandex-cloud/bin
,添加至本次会话的PATH。
活动
yc
配置文件指向RU区域,但用户有KZ区域云
创建/激活专属
openclaw-kz
配置文件,设置令牌 + 端点 + cloud-id + folder-id。请勿修改用户现有配置文件。
用户以“у меня workshop-ключ”开头但未提供密钥包路径询问一次:“Где лежит файл? Можешь перетащить в чат”。然后验证
$schema
。请勿自动回退到方案A——用户已告知有密钥,询问OAuth是错误的。
方案B密钥包的
$schema
版本晚于
openclaw-workshop-bundle@1
警告一次:“Bundle от организатора новее, чем я умею. Попробую как есть.” 尝试标准方案B步骤。直接展示任何
yc
错误。
方案B中
yc compute zone list
返回空(密钥已撤销 / 文件夹已删除)
告知用户:“Кажется, организатор свернул облако. Напиши ему.” 请勿重试。
端点已设置为KZ,但cloud-id/folder-id为空或属于RU区域通过活动配置文件的
yc resource-manager cloud list
/
folder list
重新解析,然后执行
yc config set
cloud list
返回多个云
使用第一个;用一句话告知用户“использую облако
<NAME>
”。
yc vpc network get --name default
返回空
静默创建默认网络,然后创建网段为
10.130.0.0/24
default-kz1-a
子网。
default-kz1-a
子网缺失
在(现有或新建的)默认网络下创建。
--platform standard-v3
被拒绝为“not supported in folder”
--platform standard-v2
重试一次。
--network-name default
静默选择了错误的网络
始终使用之前解析的
--network-id
/
--subnet-id
,绝不使用
-name
变体。
~/.ssh/id_ed25519.pub
缺失
生成新的无密码密钥。
无法检测调用者IP回退为
0.0.0.0/0
入站规则 + fail2ban防护(用一句话告知用户)。
npm install -g openclaw
失败一次
30秒后重试一次。若仍失败,升级处理。
前90秒网关
/health
返回非200
持续轮询——composio插件可能需要这么长时间。仅在4分钟后升级处理。
配对批准返回“code not found”等待3秒,重新列出配对请求。Telegram有时会延迟。
openclaw pairing list
返回条目,但jq过滤
.chatId
返回空
Schema字段是
.senderId
/
.requestId
,而非
.chatId
/
.code
。向导步骤4使用了防御性过滤,尝试两种字段——请勿简化。
应用区域包后机器人回复语言错误通过SSH重新执行
cat
区域包命令 +
openclaw sessions reset --channel telegram --to <CHAT_ID>
强制重新读取USER.md。见步骤5c。
验证消息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:
  1. Endpoint vs cloud-id mismatch. Setting
    endpoint=api.yandexcloud.kz:443
    does NOT auto-update
    cloud-id
    or
    folder-id
    . If you only flip the endpoint, every subsequent
    yc compute / vpc / resource-manager
    call 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.
  2. yc billing
    doesn't exist on KZ endpoint.
    Calling
    yc billing account list
    errors with
    Unknown command 'billing account list'
    . Don't use it for any pre-flight check. Detect billing problems from the actual
    yc compute instance create
    error message, not by trying to list accounts.
  3. yc resource-manager cloud list
    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".
  4. --network-name default
    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 (
    yc vpc network get --name default
    ) and pass
    --network-id
    to subsequent commands.
  5. Subnet not auto-provisioned. Default subnet
    default-kz1-a
    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.
若向导运行期间出现任何问题,请先检查以下内容——大多数YC KZ问题均源于以下五个错误之一:
  1. 端点与cloud-id不匹配。设置
    endpoint=api.yandexcloud.kz:443
    不会自动更新
    cloud-id
    folder-id
    。若仅切换端点,后续所有
    yc compute / vpc / resource-manager
    命令都会返回空结果,因为它在KZ领域中查找RU区域的ID。始终同时更新三者——端点、cloud-id、folder-id,或使用单独的配置文件。
  2. KZ端点不支持
    yc billing
    。调用
    yc billing account list
    会报错
    Unknown command 'billing account list'
    。请勿用于任何预检检查。从实际
    yc compute instance create
    错误消息中检测计费问题,而非尝试列出账户。
  3. yc resource-manager cloud list
    返回空
    。当OAuth令牌与领域不匹配(RU区域令牌用于KZ端点,反之亦然)时,调用会成功但返回空数组——而非认证错误。若返回空,原因是“令牌错误”,而非“无云”。
  4. --network-name default
    查找不可靠
    。当文件夹有多个网络(用户实验后常见)时,按名称查找可能选择错误的网络或静默失败。始终先解析为network-id(
    yc vpc network get --name default
    ),然后将
    --network-id
    传递给后续命令。
  5. 子网未自动预配置。默认子网
    default-kz1-a
    通常会随默认网络一起创建,但并非所有情况都是如此。全新空文件夹有时缺少该子网。创建实例前始终检查。

Failure modes (when the silent fixes aren't enough)

失败场景(静默修复无法解决的问题)

SymptomWhere to look
yc compute zone list
returns
ru-central1-*
or empty after the wizard's profile setup
references/04-troubleshooting.md
§1a — endpoint still RU
yc resource-manager cloud list
returns
[]
even though the cloud is visible in https://kz.console.yandex.cloud
references/04-troubleshooting.md
§1b — cloud-id/folder-id still RU, or §1c — OAuth token from wrong realm
yc compute instance create
errors with
billing account is not active
references/04-troubleshooting.md
§1d — billing genuinely missing
yc compute instance create
errors with
quota_exceeded
references/01-prerequisites.md
§5
yc compute instance create
errors with
platform … not supported
Already handled by auto-recovery (retry with
standard-v2
). If it still fails,
references/04-troubleshooting.md
§2
Cloud-init log shows
npm install -g openclaw
failed twice
references/04-troubleshooting.md
§2
openclaw gateway status
shows
RPC probe: failed
after 4 min
references/04-troubleshooting.md
§3
User pressed
/start
but
getUpdates
returns no chat
references/04-troubleshooting.md
§4a-b
Bot pairs but doesn't reply
references/04-troubleshooting.md
§4c-e (key, credit, model)
SSH
Permission denied (publickey)
references/04-troubleshooting.md
§5
For everything else: dump
/var/log/openclaw-bootstrap.log
and
journalctl --user -u openclaw-gateway -n 200
from the VM, surface to the user as "вот что я вижу, давай разбираться", do not guess.
症状排查方向
向导配置文件设置后,
yc compute zone list
返回
ru-central1-*
或空
references/04-troubleshooting.md
§1a ——端点仍为RU区域
yc resource-manager cloud list
返回
[]
,但https://kz.console.yandex.cloud中可见云
references/04-troubleshooting.md
§1b ——cloud-id/folder-id仍为RU区域,或§1c ——OAuth令牌来自错误领域
yc compute instance create
报错
billing account is not active
references/04-troubleshooting.md
§1d ——确实缺少计费
yc compute instance create
报错
quota_exceeded
references/01-prerequisites.md
§5
yc compute instance create
报错
platform … not supported
已通过自动恢复处理(用
standard-v2
重试)。若仍失败,
references/04-troubleshooting.md
§2
Cloud-init日志显示
npm install -g openclaw
失败两次
references/04-troubleshooting.md
§2
4分钟后
openclaw gateway status
显示
RPC probe: failed
references/04-troubleshooting.md
§3
用户按下/start但
getUpdates
返回无chat
references/04-troubleshooting.md
§4a-b
机器人已配对但不回复
references/04-troubleshooting.md
§4c-e(密钥、余额、模型)
SSH报错
Permission denied (publickey)
references/04-troubleshooting.md
§5
其他所有问题:从虚拟机导出
/var/log/openclaw-bootstrap.log
journalctl --user -u openclaw-gateway -n 200
,向用户展示“вот что я вижу, давай разбираться”,请勿猜测。

References

参考文档

  • references/01-prerequisites.md
    — 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/02-network-and-security.md
    — security-group rules, public-IP rationale, hardening choices
  • references/03-openclaw-config.md
    — Telegram pairing flow, Anthropic auth, workspace seeding
  • references/04-troubleshooting.md
    — 7 failure modes with copy-paste fixes
  • references/05-workshop-key-mode.md
    — Plan B (workshop bundle) end-to-end: schema check, profile carve-out, what NOT to do, organizer hand-off
  • scripts/cloud-init.yaml
    — the full VM bootstrap (Node, OpenClaw, hardening, ceo-ai-os workspace, systemd user service)
  • references/01-prerequisites.md
    ——yc CLI安装、KZ端点初始化、SSH密钥、计费检查(现在大多静默执行;仅OAuth登录和缺失计费会告知用户)
  • references/02-network-and-security.md
    ——安全组规则、公网IP原理、加固选择
  • references/03-openclaw-config.md
    ——Telegram配对流程、Anthropic认证、工作区初始化
  • references/04-troubleshooting.md
    ——7种失败场景及复制粘贴式修复方案
  • references/05-workshop-key-mode.md
    ——方案B(工作坊密钥包)端到端流程:Schema检查、配置文件隔离、禁止操作、组织者移交
  • scripts/cloud-init.yaml
    ——完整虚拟机引导脚本(Node、OpenClaw、系统加固、ceo-ai-os工作区、systemd用户服务)

Companion skills

配套技能

SkillRequired?Role
openclaw-guide
requiredLoaded by Step 0a; owns all post-install consultation (channels, use cases, debugging).
openclaw-user-onboarding
recommendedAuto-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.
prepare-yc-workshop
organizer-onlyMatching organizer-side skill that produces the bundle files consumed by this skill's Plan B. Participants don't need it.
技能是否必需角色
openclaw-guide
必需步骤0a加载;负责所有安装后咨询(渠道、用例、调试)。
openclaw-user-onboarding
推荐步骤5.5自动调用,收集用户五项信息并写入USER.md。若缺失,步骤5.5回退为占位符USER.md,并在最终总结中提及“поставь openclaw-user-onboarding и скажи 'онбординг'”。
prepare-yc-workshop
仅组织者使用对应的组织者端技能,生成本技能方案B中使用的密钥包。参与者无需使用。

About
openclaw-guide
(required)

关于
openclaw-guide
(必需)

openclaw-guide
(sibling) — must be installed alongside this one. The wizard refuses to start without it loaded. Two reasons:
  1. During install — if cloud-init logs surface something this skill doesn't know about, the agent reads
    openclaw-guide/references/06-troubleshooting.md
    instead of guessing.
  2. 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
    openclaw-guide/references/use-cases.md
    and
    openclaw-guide/references/channels.md
    to advise. This wizard is silent after Step 5; the guide owns ongoing consultation.
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 -g
If
npx
is unavailable: clone
https://github.com/CodeAlive-AI/ceo-ai-os
and drop
skills/install-openclaw-to-yc
and
skills/openclaw-guide
into the agent's skills directory (see this skill's README for per-agent paths).
openclaw-guide
(同级技能)——必须与本技能一起安装。向导未加载该技能时会拒绝启动。原因有二:
  1. 安装期间——若cloud-init日志出现本技能未知的内容,Agent会读取
    openclaw-guide/references/06-troubleshooting.md
    ,而非猜测。
  2. 安装后——当用户询问“如何添加Slack?”“如何让机器人早上8点叫醒我?”“我应该安装哪些技能?”时,Agent会读取
    openclaw-guide/references/use-cases.md
    openclaw-guide/references/channels.md
    提供建议。本向导步骤5后静默;指南负责后续咨询。
联合安装:
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
npx
不可用:克隆
https://github.com/CodeAlive-AI/ceo-ai-os
,将
skills/install-openclaw-to-yc
skills/openclaw-guide
放入Agent的技能目录(见本技能README中的各Agent路径)。

Ecosystem — 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 suggestOne-line pitch
"I want a daily morning brief"
daily-recap
Cron-driven morning + evening summary of metrics, calendar, and yesterday's wins.
"Help me prep for a strategic decision"
decision-playbook
Structured deliberation with explicit options, kill criteria, and a 7-day review.
"Research this company before my meeting"
exa-company-research
Exa-powered company profile (positioning, traction, team) in <30 s.
"Find people who fit ICP X"
exa-lead-gen
Multi-source lead discovery with enrichment.
"Watch what competitors are doing"
competitive-analysis
Daily radar over competitor sites, blog, GitHub, hiring.
"I want to use CodeAlive search inside the bot"(see
openclaw-guide/references/codealive-context-engine.md
)
Adds
codealive__semantic_search
/
grep_search
/
chat
MCP tools to the bot — bot can answer questions about any indexed repo.
Full catalogue lives at
https://github.com/CodeAlive-AI/ceo-ai-os/tree/main/skills
. Install any of them globally with:
bash
npx skills add CodeAlive-AI/ceo-ai-os@<skill-name> -g
虚拟机已预安装所有49个ceo-ai-os技能到工作区(用户请求匹配时机器人会自动调用)。对于驱动本向导的Agent自身技能加载器,以下是投资回报率最高的附加组件。仅在步骤5通过后提及——提前提及会分散安装流程的注意力。
触发条件(“用户之后询问X”)建议安装的技能一句话介绍
"I want a daily morning brief"
daily-recap
由Cron驱动的早晚总结,包含指标、日历和昨日成果。
"Help me prep for a strategic decision"
decision-playbook
结构化审议,包含明确选项、淘汰标准和7天回顾。
"Research this company before my meeting"
exa-company-research
基于Exa的公司概况(定位、业绩、团队),生成时间<30秒。
"Find people who fit ICP X"
exa-lead-gen
多渠道线索发现及信息补充。
"Watch what competitors are doing"
competitive-analysis
每日监控竞争对手网站、博客、GitHub、招聘信息。
"I want to use CodeAlive search inside the bot"(见
openclaw-guide/references/codealive-context-engine.md
)
为机器人添加
codealive__semantic_search
/
grep_search
/
chat
MCP工具——机器人可回答任何已索引仓库的问题。
完整技能目录位于
https://github.com/CodeAlive-AI/ceo-ai-os/tree/main/skills
。使用以下命令全局安装任意技能:
bash
npx skills add CodeAlive-AI/ceo-ai-os@<skill-name> -g

Consulting 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
openclaw-guide/references/<file>.md
first. The guide is the source of truth for ongoing OpenClaw operations. This skill's job ends after Step 5.
User asks aboutRead first
Adding WhatsApp / Slack / Discord / iMessage
openclaw-guide/references/channels.md
Setting up a daily brief, research workflow, decision playbook
openclaw-guide/references/use-cases.md
Adding CodeAlive search to the bot
openclaw-guide/references/codealive-context-engine.md
Bot stopped responding, OAuth re-auth, memory full
openclaw-guide/references/06-troubleshooting.md
Cron / heartbeat / scheduled jobs
openclaw-guide/references/03-cron-heartbeat.md
当用户询问虚拟机安装相关的问题(渠道设置、用例、现有机器人调试、添加MCP服务器、多Agent)时,请勿凭记忆回答——先阅读对应的
openclaw-guide/references/<file>.md
。指南是OpenClaw日常操作的权威来源。本技能的职责在步骤5后结束。
用户询问内容先阅读
添加WhatsApp / Slack / Discord / iMessage
openclaw-guide/references/channels.md
设置每日简报、研究工作流、决策手册
openclaw-guide/references/use-cases.md
为机器人添加CodeAlive搜索
openclaw-guide/references/codealive-context-engine.md
机器人停止响应、OAuth重新认证、内存已满
openclaw-guide/references/06-troubleshooting.md
Cron / 心跳 / 定时任务
openclaw-guide/references/03-cron-heartbeat.md

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 —
    references/04-troubleshooting.md
    §7
  • 多Agent设置(一台虚拟机上两个Agent)——超出范围
  • WhatsApp / Discord / Slack渠道——此处仅支持Telegram;其他渠道见
    openclaw-guide/references/channels.md
  • 用例设计(每日简报、研究工作流、决策手册)——见
    openclaw-guide/references/use-cases.md
  • 备份与迁移——单独技能
  • 生产级加固(SELinux、内核sysctl、SSH证书认证)——对于工作坊/个人CEO机器人来说过于复杂
  • 试用额度之外的成本优化——
    references/04-troubleshooting.md
    §7