通过 aliyun appmanager 部署到阿里云 ECS
概述
aliyun appmanager 是一款对 Agent 友好的 CLI 工具,可将应用(App)和 AI Agents 一键部署到阿里云 ECS。它支持非交互模式(--non-interactive)、结构化 JSON 输出(--output json)和流式 NDJSON 响应。
默认行为:用户调用 /alibabacloud-ecs-code-deploy 时,如果未指定项目路径或 URL,则将当前工作目录中的项目部署到阿里云 ECS。如果用户提供 git URL,则先将其克隆到当前目录,然后 cd 进入克隆后的目录并继续部署。
执行顺序:Agent 必须遵循本文档底部“完整部署工作流”一节所规定的正确执行顺序。下面各任务部分按主题组织,仅供参考,其编号并不表示执行顺序。
---
强制要求:开始前创建待办事项列表
执行任何步骤之前,Agent 必须创建包含以下所有项目的待办事项列表。不得遗漏任何项目。在创建待办事项列表之前,不得开始部署。
Todo list (Deploy to Alibaba Cloud ECS):
[ ] 0. Resolve $SKILL_DIR (cross-platform path — MUST run first; see "Step 0" below)
[ ] 1. Environment pre-check (MUST run deploy_toolkit.py check; manual commands FORBIDDEN as replacement)
[ ] 2. Obtain project (clone git URL here if needed; skip for local projects)
── Check whether .appmanager/config.yaml already exists (repeat-deploy shortcut) ──
│ Exists + new ECS (no instanceId) → skip 3-5, start from 5.5 (price check)
│ Exists + existing ECS (has instanceId) → skip 3-5.5, jump to 6 (deploy)
│ Does not exist → proceed normally from 3
───────────────────────────────────────────────────────────────────────────────
[ ] 3. Read project (README.md -> quick-deploy method) + identify type (agent / app)
[ ] 4. Ask user for deployment config (region + new ECS / existing ECS)
[ ] 5. Init + generate scripts (appmanager init -> write start/stop scripts to config.yaml)
[ ] 5.5. Pre-deploy price check + risk warning (MUST run deploy_toolkit.py price; confirm price / OSS billing / existing-ECS impact / group overwrite item by item)
[ ] 6. Deploy (MUST run deploy_toolkit.py deploy; manual deploy command FORBIDDEN as replacement)
[ ] 7. Verify (MUST run deploy_toolkit.py verify; manual status command FORBIDDEN as replacement)
[ ] 8. Output final result (console link + cost reminder + management commands)
⛔ 脚本优先规则:步骤 1、5、6、7 在$SKILL_DIR/scripts/deploy_toolkit.py设有专用工具包脚本(其中$SKILL_DIR将在下面的步骤 0中解析——适用于 Qoder、Claude Code 及任何其他平台)。Agent 必须直接运行对应子命令,并将其作为该步骤的第一个且唯一操作——禁止在运行脚本之前执行手动 CLI 命令(例如aliyun version、版本检查、凭证检查),也不得用这些命令代替脚本。该脚本已在内部处理所有检查。仅当脚本文件本身不存在时,才允许将手动命令作为备用方案。
❌ 错误(步骤 1):运行aliyun version→ 检查版本 → 运行~/.aliyun/appmanager-venv/bin/python ...→ 检查版本 → 然后再运行deploy_toolkit.py check
✅ 正确(步骤 1):运行 python3 "$SKILL_DIR/scripts/deploy_toolkit.py" check → 如果出现 exit 1,修复其报告的问题 → 如果脚本文件缺失,此时才回退到手动检查
第 6 项没有商量余地。跳过日志验证并直接输出“部署成功”的 Agent 并未正确完成此 skill。如果 deploy_toolkit.py verify 以 1 退出(失败),Agent 必须先修复问题并重新部署,然后才能继续执行第 7 项。
---
步骤 0(强制要求):解析 $SKILL_DIR——跨平台路径
工具包脚本位于<skill-root>/scripts/deploy_toolkit.py。不同平台会将 skills 安装到不同位置(Qoder/Claude Code/千问/...)。Agent 必须在会话开始时仅解析一次 skill 根目录的绝对路径,并在下文每个出现$SKILL_DIR的位置复用该路径。严禁硬编码任何平台特定路径。
有关完整的 10 个候选位置检测算法、export + test -f 验证代码片段,以及模式 A / 模式 B / ⛔ 反模式使用规则,请参阅 [references/skill-dir-resolution.md](references/skill-dir-resolution.md)。
快速回顾(详细信息请阅读参考文档):
- ✅ 模式 A(持久 shell):先执行
export SKILL_DIR="/abs/path",之后再执行python3 "$SKILL_DIR/scripts/deploy_toolkit.py" <sub> - ✅ 模式 B(每次调用都使用新的 shell):内联绝对路径——
python3 "/abs/path/scripts/deploy_toolkit.py" <sub> - ⛔ 反模式:
SKILL_DIR=/path python3 "$SKILL_DIR/..."——外层 shell 会在前缀赋值之前展开$SKILL_DIR,从而生成/scripts/deploy_toolkit.py并出现 ENOENT。如果看到python3: can't open file '/scripts/deploy_toolkit.py',请改用模式 A 或 B。
---
任务 1:安装阿里云 CLI
主要操作:运行 python3 "$SKILL_DIR/scripts/deploy_toolkit.py" check——该脚本会一次性检查 CLI 版本、appmanager-cli 版本和凭证。仅当脚本文件缺失时,才使用 [references/init-and-credentials.md](references/init-and-credentials.md) 中的备用方案。
必须 — 处理未满足的环境前置条件:当 check 因 aliyun CLI 缺失或版本低于 3.3.19(或 appmanager-cli 缺失/版本过旧)而以 1 退出时,Agent 不得静默停止工作流。必须遵循以下流程:
1. 未安装 CLI → 无需询问用户,直接自动安装 — 执行安装命令(请参见下方代码片段,或参见 [references/init-and-credentials.md](references/init-and-credentials.md) 以选择正确的架构),然后重新运行 deploy_toolkit.py check 进行确认。
2. CLI 已安装 → 必须先询问用户 — 展示检测到的版本、所需版本和升级命令,并征得明确同意(例如,“aliyun CLI 3.3.4 已安装,但未达到 appmanager 要求的版本(>= 3.3.19);是否同意升级(覆盖安装到 /usr/local/bin,需要 sudo)?”)。不得擅自视为同意;不得粘贴凭证。
- 用户同意后 — 执行安装/升级命令,然后重新运行 deploy_toolkit.py check 进行确认。
- 用户拒绝后 — 以用户拒绝为由停止流程。不得继续使用旧版本(部署无论如何都会失败)。
工具包的check输出中已针对每个可修复问题包含一行→ AGENT: DO NOT stop. ASK user ...— 必须逐字遵循(“未安装”情况除外,该情况会自动处理)。
必须 — 升级方式优先级:由 brew 管理 →brew upgrade(不得再次覆盖/usr/local/bin/);可使用 sudo → 覆盖/usr/local/bin/;无 sudo →~/bin/+ 持久化 PATH(Unix)。Scoop/Choco →%USERPROFILE%\bin+ 用户级 PATH(Windows)。完整优先级规则 → [references/init-and-credentials.md](references/init-and-credentials.md) § “CLI 安装/升级方式优先级”。安装/升级后,必须始终重新运行deploy_toolkit.py check进行确认;若which -a aliyun仍将旧二进制文件显示在首位,请修正 PATH 顺序 — 不得重复执行相同的覆盖操作。
可观测性(强制要求):User-Agent 注入
⛔ 每次aliyunCLI 调用都必须携带此 skill 的 User-Agent,以便所有 API 请求都可在云端日志中追踪。Agent 必须在会话开始时(紧接步骤 0 之后)且在调用任何aliyun/deploy_toolkit.py之前,仅导出一次 UA 环境变量。
完整 UA 模板:
AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/{session-id}
session-id 统一规则:
- 每个 agent 会话仅生成一次:
SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')— 使用小写 UUID(任何由小写十六进制字符组成且长度 ≥ 16 个字符的随机令牌均等效)。 - 在会话内的所有 CLI 调用中复用同一个 session-id — 禁止为每条命令重新生成,否则一次部署会分散为无法追踪的多个片段。
- 按照步骤 0 的规则,以一致方式持久化:模式 A 使用
export SESSION_ID=...(持久化命令行环境),或内联字面值(每次调用均使用新的命令行环境)。
注入方式(现代方式 — 环境变量):
export ALIBABA_CLOUD_USER_AGENT="AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/${SESSION_ID}"
⛔ 旧版aliyun configure ai-mode enable / set-user-agent机制已标记为 DEPRECATED — 不得使用。对于同一个 skill 令牌,不得将ALIBABA_CLOUD_USER_AGENT与 ai-mode 或按命令设置的环境变量前缀结合使用:CLI 会叠加这些来源并生成重复的 User-Agent。每个会话仅设置一次环境变量,此后保持不变。
---
任务 2:配置凭证
deploy_toolkit.py check 已包含凭证验证。仅当凭证缺失或无效时,才参见 [references/init-and-credentials.md](references/init-and-credentials.md) 中的默认凭证链修复流程。
⛔ 优先使用 OAuth 而非 AK:OAuth 更安全、更方便(无需长期存储密钥)。Agent 必须将 OAuth 作为首选项。用户同意后,Agent 直接运行登录命令 — 但必须先警告用户,该命令会打开浏览器授权页面,并且会一直阻塞,直到用户在浏览器中完成授权 — 然后执行aliyun configure --mode OAuth --profile oauth并使用aliyun sts get-caller-identity --profile oauth进行验证。
⛔ SA-2.12 — 禁止在聊天中收集 AK/SK:如果用户倾向于使用 AK 认证,请提供一个带占位符且可直接运行的命令模板 —aliyun configure set --profile default --mode AK --access-key-id <your-access-key-id> --access-key-secret <your-access-key-secret> --region cn-hangzhou— 并要求用户自行填入自己的 AK/SK,然后在自己的终端中运行。Agent 禁止要求用户将 AccessKey/密钥/STS 令牌值粘贴到聊天中,禁止在工具调用参数或脚本中放入原始 AK/SK,并且禁止回显凭证值。默认凭证链(ECS RAM 角色 / 环境变量 / 已有的~/.aliyun/config.json)也受支持。完整修复流程 → [references/init-and-credentials.md](references/init-and-credentials.md)。
严重禁令:严禁单独运行appmanager或aliyun appmanager login。
---
任务 3:初始化项目
步骤 1(强制要求):首先读取 README.md
关键顺序规则:在扫描任何项目文件之前,Agent 必须先读取项目根目录中的README.md(或README)。这始终是任务 3 中的第一个操作。
要从 README 提取的内容:
- 快速开始 / 部署命令(例如
pip install -r requirements.txt && python main.py、npm install && npm start) - 官方构建/运行命令、Docker 部署方法、端口号、必需的环境变量
强制要求:向用户展示 README 中的方法并遵循决策树
步骤 A:向用户列出 README 提供的内容。
步骤 B:按优先级选择方法:
| 优先级 | 方法类型 | 操作 | |----------|------------|--------| | 1 (HIGHEST) | 原生 CLI / 包管理器安装(npm install -g、pip install、go install) | 直接使用 | | 2 | 原生构建 + 运行(pip install && python main.py、npm install && npm start) | 使用,并安装运行时 | | 3 | 基于脚本的部署(bash deploy.sh) | 必须确认支持非交互模式 | | 4 (LOWEST) | Docker / docker-compose | 仅当不存在更高优先级的方法时使用;检查能否从中国访问 |
步骤 C:根据场景执行:
- README 提供原生方法(优先级 1/2) → 直接将其用作启动脚本的核心。不得忽略 README 而从头构建。
- README 仅提供 Docker 方法 → 检查镜像可访问性(参见 [references/script-templates.md](references/script-templates.md) 中的“Docker 镜像可访问性检查”)。向用户警示中国镜像源风险。
- README 没有部署信息或不存在 → Agent 独立扫描项目文件(仅允许在此情况下执行)。
为什么要先读取 README? 大多数项目都记录了确切的构建/运行命令。仅根据文件自动检测容易出错。
---
步骤 2:确定项目类型
| 条件 | 类型 | |-----------|------| | 项目依赖于 agentscope | agent | | 其他所有情况(langchain、mcp、autogen、Web 服务、工具等) | app |
确定 --name
使用项目目录名称(全小写,使用连字符)。告知用户:Default app name uses the directory name <name>。
确定 --region 和 ECS 目标(必须询问用户)
Agent 必须在一条消息中同时询问以下两个问题:
1. 您希望部署到哪个地域?
- 上海 (cn-shanghai) / 杭州 (cn-hangzhou) / 北京 (cn-beijing) / 深圳 (cn-shenzhen) / 广州 (cn-guangzhou) / 成都 (cn-chengdu) / 南京 (cn-nanjing) / 香港 (cn-hongkong)
2. 新建 ECS 还是已有 ECS?
- 新建 ECS(自动创建实例,按量付费)
- 已有 ECS(从下方列表中选择,或手动提供实例 ID)
不得使用“华东 1”/“华北 2”等基于可用区的标签。不得添加说明。只能使用城市名称。
已有 ECS — 列出用户在所选地域中最近创建的 10 个实例(强制要求)
当用户选择已有 ECS时,Agent 必须首先查询该账号在所选地域中最近创建的 10 个实例(插件模式:aliyun ecs describe-instances),并以编号列表形式展示以供选择 — 不得强迫用户凭记忆回想实例 ID。还必须始终允许手动输入实例 ID(例如 i-bp1xxxxxxxx)作为备用方案。查询时必须传入与部署相同的 --profile(即同一账号),否则可能返回零个实例或不正确的实例。完整命令(jq 管道、无 jq 时的备用方案、零实例处理)→ [references/init-and-credentials.md](references/init-and-credentials.md) §“列出已有 ECS 实例”。所选或输入的 ID 将传递给 appmanager init --ecs existing --instance-id <ID>。
⚠️ 地域传递检查(强制要求):所选地域必须原样传递给appmanager init --region,写入config.yaml中的common.deployment.regionId,且后续每次调用deploy_toolkit.py {price,deploy,verify}时都必须附加--region <REGION_ID>。地域不一致或遗漏会触发 OOS API 返回的InvalidParameter: DeployRegionId is invalid。
确定 --port(仅限 App 类型,可选)
仅当项目实际监听 HTTP 时才指定。后台服务(机器人、工作进程、CLI 工具)应跳过。需要但未知时,默认为 8080。Agent 类型不使用 --port。
非交互式初始化
有关所有初始化参数组合,请参阅 [references/init-and-credentials.md](references/init-and-credentials.md)。
将创建 .appmanager/config.yaml。不支持 --overwrite — 如果 .appmanager/ 已存在,请先删除。
---
任务 4:生成部署脚本
对于所有项目类型,Agent 都必须生成部署脚本并将其写入 .appmanager/config.yaml。
工作流
- 首先读取 README.md — 遵循任务 3 的决策树
- 如果 README 中没有部署信息 — 扫描项目结构(见下文“语言检测”)
- Docker 可访问性检查 — 如果选择了 Docker 方案(请参阅 [references/script-templates.md](references/script-templates.md))
- 生成启动和停止脚本 — 遵循下述规则。启动脚本必须始终包含 zip 解压流程。
- 写入 config.yaml — 写入
common.scripts.start和common.scripts.stop(不得写入顶层scripts)
语言检测、待读取文件和入口点
语言检测规则(标识文件)、每种语言必须读取的文件以及入口点检测顺序 → [references/script-templates.md](references/script-templates.md) §“项目分析”。
通用脚本规则
| 规则 | 要求 | |------|-------------| | ⛔ 强制要求解压 zip | 启动脚本必须执行以下操作:查找 zip 文件 → mkdir -p → unzip -o → cd。若缺少此流程,ECS 上将不存在项目目录 | | 安装运行时 | 必须首先安装语言运行时(ECS 是纯净环境) | | 安装 unzip | command -v unzip &>/dev/null \|\| $PKG_MGR install -y unzip | | 幂等 | 可安全地多次运行 | | ⛔ 日志文件路径固定 | 必须为 /root/app.log 和 /root/app.pid。验证脚本已硬编码这些路径 | | 日志追加 | 始终使用 >>(不得使用 >) | | PID 文件 | 在 nohup ... & 之后执行 echo $! > /root/app.pid | | 后台运行 | nohup ... >> /root/app.log 2>&1 & | | 停止旧进程 | [ -f /root/app.pid ] && kill "$(cat /root/app.pid)" 2>/dev/null \|\| true | | 应用目录 | /root/{app_name} | | 禁止使用 heredoc | 禁止在脚本中使用 << 'EOF',否则会破坏 YAML 格式。请使用 printf 或 python3 -c | | 强制要求在末尾输出日志 | 必须以 sleep 3 && cat /root/app.log 结尾,以便在验证时捕获输出 | | ⛔ 停止脚本:禁止退出 | 不得包含 exit。部署系统会将停止脚本与启动脚本拼接在一起,而该命令会终止整个进程 |
ECS 实例是纯净的 Linux 环境(通常为阿里云 Linux,基于 RHEL,使用yum/dnf)。
有关脚本模板、语言安装命令和 config.yaml 写入方法,请参阅 [references/script-templates.md](references/script-templates.md)。
---
任务 4.5:部署前价格检查 + 风险警告
强制要求:部署前,运行deploy_toolkit.py price。该脚本会输出 价格估算(含 OSS 额外计费提醒),并在适用时输出 风险警告区块。Agent 必须向用户展示所有标记项,并在运行deploy之前获得明确确认。
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" price --config .appmanager/config.yaml
- 退出码为 0 且输出包含
=== AGENT_CONFIRM_REQUIRED ===:向用户展示 完整的 价格信息和风险警告,并逐项确认。 - 退出码为 1:价格查询失败;不得继续部署。
Agent 必须确认最多 3 项(价格 + OSS 费用 / 现有 ECS 风险 / 分组覆盖选项)——详细说明和示例措辞请参阅 [references/deploy-output-and-management.md](references/deploy-output-and-management.md) § "部署前价格检查:确认项"。
在完成所有适用的确认之前,Agent 不得调用 deploy_toolkit.py deploy。
---
任务 5:部署
aliyun appmanager <agent|app> deploy --overwrite --output json
部署成功后先停止输出结果 — status: success 仅表示编排已完成。Agent 必须先执行任务 6 的验证,再输出结果。
处理部署失败
⛔ 强制失败处理门禁:发生任何部署失败(exit 1、超时或ReleaseCancelled)后,Agent 必须立即运行deploy_toolkit.py verify,且必须在任何修复尝试、改用手动命令或输出部分结果之前执行。失败后严禁跳过验证,否则视为 skill 执行失败。
ReleaseCancelled的含义:它表示 ECS 上的启动脚本执行失败或超时,不表示“有人取消了部署”。唯一正确的下一步操作是:运行deploy_toolkit.py verify-> 读取日志 -> 修复脚本 -> 重新部署。
已知失败模式:在进行临时故障排查之前,请查看 [references/lessons-learned.md](references/lessons-learned.md),了解此前发现的部署失败模式和经验证的修复方案。
失败处理流程:
- 运行
deploy_toolkit.py verify获取/root/app.log(不得跳过)。 - 分析日志以定位根本原因。
- 修复脚本并重新部署(最多尝试 3 次)。
- 失败 3 次后,停止——报告错误,但仍需输出控制台链接 + 费用提醒 + 删除命令。
---
任务 6:部署后验证(阻塞)
status: Deployed 并不表示应用正在运行。Agent 必须执行验证并对日志进行语义分析。
- 运行
deploy_toolkit.py verify(会自动从 config.yaml 读取参数)。 - Agent 对日志进行语义分析,以判断应用是否确实已成功启动。
- 未运行 -> 诊断 -> 修复 -> 重新部署 + 验证(最多尝试 3 次)。
- 只有在已确认运行 / 需要用户手动操作 / 3 次尝试均失败时,Agent 才应输出最终结果。
---
任务 7 和 8:列出、删除、验证和最终输出
以下内容请参阅 [references/deploy-output-and-management.md](references/deploy-output-and-management.md):
- 列出/删除命令
- 配置验证
- 配置模板参考
- 关键注意事项与常见陷阱
- 强制要求的部署后输出格式(控制台链接、费用提醒、使用指南)
输出前检查点 — 自检(⛔ 阻塞)
输出结果前,Agent 必须原样打印 Deployment self-check report 模板(请参阅工作流步骤 7.5)。跳过该报告 = skill 执行失败(并非可选摘要)。如果任何一项为 ❌,请在输出步骤 8 前修复。
📘 包含具体输入/输出和边界情况的实操演练(Python Flask 示例):请参阅 [references/tutorial-flask-app.md](references/tutorial-flask-app.md)。
完整部署工作流
⛔ 强制执行规则:Agent 必须严格遵循此顺序。对于指定了脚本的步骤(步骤 1、5、6),Agent 必须运行该脚本——禁止使用单独的命令手动复现脚本逻辑。上述任务章节仅供参考(用于了解脚本内部的工作方式,或在缺少脚本时作为备用方案)。
# 0. Resolve $SKILL_DIR (MANDATORY — see "Step 0" section above for full algorithm)
# → Detect the absolute directory containing THIS SKILL.md (most accurate)
# → Or fall back to platform-specific candidates: ~/.qoder/skills/..., ~/.claude/skills/..., ~/.qwen/skills/..., $SKILLS_HOME/..., etc.
# → Pattern A (persistent shell): export SKILL_DIR=<abs_path> ; verify $SKILL_DIR/scripts/deploy_toolkit.py exists ; reuse $SKILL_DIR everywhere
# → Pattern B (fresh shell per command): inline the absolute path — `python3 "/abs/path/scripts/deploy_toolkit.py" ...`
# → ⛔ NEVER use `SKILL_DIR=/path python3 "$SKILL_DIR/..."` — outer shell expands $SKILL_DIR
# BEFORE the prefix assignment, producing `/scripts/deploy_toolkit.py` and ENOENT.
# 1. Environment check (MUST use deploy_toolkit.py check — DO NOT run manual commands)
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" check
# ⛔ FORBIDDEN: running `aliyun version`, `~/.aliyun/appmanager-venv/bin/python -c "..."`,
# credential checks, or ANY manual version-check commands before or instead of this script.
# The script checks ALL of: CLI version + appmanager-cli version + credentials in one run.
# Just run the script. Period.
# → If exit 0: all checks passed, proceed to step 2
# → If exit 1, address the issue printed by the script:
# ⚠️ DO NOT stop silently. For every fixable ❌ line the script prints,
# Agent MUST follow the flow below:
# - aliyun CLI NOT installed: AUTO-INSTALL directly (no need to ask user)
# - aliyun CLI already installed but outdated: ASK user to approve upgrade
# (covers to /usr/local/bin, needs sudo), then run the install command
# printed by the script (see Task 1).
# - appmanager-cli < 1.1.1 or BROKEN venv: ASK user to approve
# `rm -rf ~/.aliyun/appmanager-venv` (auto-recreates on next aliyun
# appmanager run).
# ⚠️ This path is fixed at ~/.aliyun/appmanager-venv (the venv is self-managed
# by the aliyun CLI). After deletion, the next `aliyun appmanager` run
# auto-recreates it. The Agent MUST use this exact literal path —
# NEVER replace it with a variable or build it via concatenation,
# to avoid accidentally wiping user data.
# - credentials missing/invalid: present OAuth-first remediation
# to the user (OAuth / RAM Role / env vars / `aliyun configure` interactive) — NEVER
# collect AK/SK in chat. See Task 2 + references/init-and-credentials.md.
# → If user refuses any fix: stop with that refusal as the reason — DO NOT
# continue with a broken environment (deployment will fail anyway).
# → If script file not found: ONLY THEN fall back to manual checks (Task 1 + Task 2)
# 2. Obtain project source (if needed)
# → If git URL provided: clone to CURRENT WORKING DIRECTORY, cd into cloned dir
# git clone <URL> && cd <cloned_dir>
# → If local path / current directory: skip this step, use directly
# 🔀 REPEAT DEPLOYMENT SHORTCUT — check BEFORE step 3
# → Check if .appmanager/config.yaml already exists in the project directory
# → If YES (config.yaml exists):
# Read the file and check for common.deployment.instanceId:
# - instanceId ABSENT (new ECS): skip steps 3-5, jump to step 5.5 (price check)
# - instanceId PRESENT (existing ECS): skip steps 3-5.5, jump to step 6 (deploy)
# In both cases, inform user: "Existing .appmanager/config.yaml detected; will reuse the existing config and deploy directly."
# → If NO (config.yaml does NOT exist): proceed normally from step 3
# 3. Read project + identify type (agent or app)
# → READ README.md FIRST — highest priority source for deployment method:
# - Agent MUST list README's methods to user and select by priority:
# Native CLI install > Native build+run > Script deploy > Docker
# - ❌ NEVER ignore README methods and scan project files instead
# - ❌ NEVER prefer Docker when native methods are available
# - Docker: ONLY when no native method exists, MUST warn user about China mirror risks
# - Only if README absent/empty/no deploy info → Agent scans project files independently
# → Only classify as "agent" if project depends on `agentscope`; everything else is "app"
# → Determine --name from directory name, --port from project config/README
# → For Docker: check image accessibility from China (see references/script-templates.md)
# 4. Ask user for deployment region + ECS target (MANDATORY — ask together in one question)
# → Question 1: "Which region do you want to deploy to? Shanghai(cn-shanghai)/Hangzhou(cn-hangzhou)/Beijing(cn-beijing)/Shenzhen(cn-shenzhen)/Guangzhou(cn-guangzhou)..."
# → Question 2: "New ECS or existing ECS?" — if existing, FIRST query the account's 10 most-recently-created
# ECS instances in the chosen region and present them as a numbered list for selection:
# aliyun ecs describe-instances --biz-region-id <REGION> --region <REGION> --page-size 100 | jq -r '.Instances.Instance | sort_by(.CreationTime) | reverse | .[:10] | .[] | "..."' (plugin mode; no `--output json`; JSON is the default)
# Also always support manual instance ID entry (e.g. i-bp1xxxxxxxx). See Task 3 "Existing ECS" section.
# → NEVER use zone-based labels like "East China 1" / "North China 2" — always use city names
# → NEVER skip the ECS choice and default to creating new
# → ⚠️ Region MUST be propagated verbatim to: appmanager init --region, config.yaml common.deployment.regionId, AND every deploy_toolkit.py --region. Mismatch → InvalidParameter: DeployRegionId from OOS API.
# 5. Init + generate scripts (appmanager init → write start/stop to config.yaml)
# → If .appmanager/ already exists in the CURRENT project directory, ask user before removing.
# ⚠️ DESTRUCTIVE: `rm -rf .appmanager` deletes the existing deployment config.
# Required guard before deletion:
# a. Confirm CWD matches the intended project directory (`pwd` shows expected path)
# b. Confirm target is the relative path `.appmanager` (NEVER absolute, NEVER with variables)
# c. Inform the user "About to delete the existing deployment config under ./.appmanager/. This is irreversible." and obtain consent
# Recommended safer alternative: back up first
# mv .appmanager .appmanager.bak.$(date +%Y%m%d%H%M%S)
# Only after explicit user consent: rm -rf ./.appmanager
# → Run: aliyun appmanager init --non-interactive --name <DIR_NAME> --type <app|agent> --region <REGION> [--port <PORT>] [--ecs existing --instance-id <ID>] [--model qwen3.6-plus --api-key "$API_KEY"]
# (See references/init-and-credentials.md for full flag combinations by type)
# → Then generate start/stop scripts and write to config.yaml:
# - MUST write to common.scripts.start and common.scripts.stop (NEVER top-level scripts key)
# - Use python3 yaml library: config['common']['scripts'] = {'start': ..., 'stop': ...}
# - PRIORITY: README deployment commands → use directly; only auto-generate when README has none
# - ⛔ MANDATORY: Start script MUST ALWAYS include zip extraction (mkdir + unzip + cd) BEFORE
# any build/run commands. appmanager uploads zip but does NOT extract it.
# 5.5. Pre-deploy price check + risk warning (MUST run deploy_toolkit.py price — Agent handles user confirmation)
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" price --config .appmanager/config.yaml
# → Script output structure:
# [Price table] estimate from `appmanager price` (order-billed resources: ECS/EIP/bandwidth) + the trailing 📦 OSS extra-billing reminder
# [Risk warning] only when detected: [Existing-ECS deployment risk] / [Group overwrite risk] / [Failure-leftover group]
# → Script does NOT ask user for confirmation — that's the Agent's job
# → If exit 0: Agent MUST read the output, present the COMPLETE breakdown to user — including:
# 1) Price estimate + OSS extra-billing reminder (OSS storage ~CNY 0.12/GB/month, public outbound ~CNY 0.50/GB only when cross-region, requests billed per 10k)
# 2) If output contains [Existing-ECS deployment risk] -> ask whether to deploy onto that existing ECS (may impact other apps on it)
# 3) If output contains [Group overwrite risk] -> ask user to choose A (overwrite) or B (new group)
# Example: "Estimated cost: compute resources CNY X.XXX/hour (~CNY XXX.XX/month); public traffic billed by usage at CNY 0.80/GB;
# the deployment also incurs minor OSS storage and request fees (intra-region pull is free of public outbound charges).
# Confirm to continue?"
# → After ALL items confirmed by user: run the matching deploy command per item 3's choice (default overwrite / --force-new-group for new group)
# → If ANY item refused: STOP deployment
# → If exit 1: price query failed, show error to user, do NOT proceed
# 6. Deploy (MUST use deploy_toolkit.py deploy — DO NOT run deploy manually)
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" deploy \
--type <agent|app> --name <APP_NAME> --group <GROUP_NAME> --region <REGION_ID>
# ⛔ FORBIDDEN: running `aliyun appmanager deploy` directly without this script
# → Handles: group status check → conflict auto-resolve → deploy
# → Exit 0: deploy submitted, proceed to step 7
# → Exit 1: ⛔ MUST run step 7 (verify) IMMEDIATELY to fetch /root/app.log;
# skipping to step 8, outputting partial results, or running manual
# commands instead is FORBIDDEN. Then fix script per log and redeploy
# (max 3 attempts).
# 7. Verify (MUST use deploy_toolkit.py verify — DO NOT check status manually)
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" verify \
--type <agent|app> --name <APP_NAME> --group <GROUP_NAME> --region <REGION_ID>
# ⛔ FORBIDDEN: running `aliyun appmanager status` + manual log analysis instead of this script
# → Optional: --wait <seconds> for slow-starting apps (default 3s, Java/heavy use 15-30)
# → Dual-path: Cloud Assistant cat /root/app.log (preferred) → deployCommandOutput (fallback)
# → Exit 0: app running, proceed to step 8
# → Exit 1: app failed — fix start script, re-deploy (back to step 6)
# → Exit 2: inconclusive — retry with longer --wait or suggest SSH check
# 7.5. Self-check summary (⛔ BLOCKING — skill fails if omitted)
# MUST print the exact template below to the user — this is a completion criterion, NOT optional.
#
# ---
# ✅ Deployment self-check report:
# 0. Path resolution — SKILL_DIR=___ (script exists ✅)
# 1. Environment pre-check — CLI v___ / appmanager-cli v___ / credentials valid ✅
# 2. Project obtained — (local / cloned) ✅
# 3. Project identified — type: ___ / deploy method source: README.md ✅
# 4. Deployment region — user choice: ___ ✅
# 5. Init + scripts — config.yaml generated; start script: ___ (key command summary) ✅
# 5.5. Pre-deploy price check — user confirmed price (CNY ___/hour, ~CNY ___/month) ✅
# 6. Deploy executed — deploy_toolkit.py deploy exit 0 ✅
# 7. Run verification — deploy_toolkit.py verify exit 0 / log keywords: ___ ✅
# ---
#
# If any item is ❌, fix it BEFORE step 8 — this is for the USER to see, proving the work is properly done.
# 8. Output results (MANDATORY: console link + cost reminder + management commands)
# → See references/deploy-output-and-management.md for full output format