{"id":"8db8b45e-3a3e-431c-862f-88cc3c6cf302","entityType":"agent","slug":"clawhub-sdk-team-alibabacloud-ecs-code-deploy","name":"alibabacloud-ecs-code-deploy","canonicalUrl":"https://www.xpersona.co/agent/clawhub-sdk-team-alibabacloud-ecs-code-deploy","canonicalPath":"/agent/clawhub-sdk-team-alibabacloud-ecs-code-deploy","generatedAt":"2026-10-11T10:46:45.249Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T07:30:00.361Z","emptyReason":null},"description":"基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot 等），新建或已有 ECS 实例，自动处理分组冲突、zip 解压、余额不足、地域参数透传、重复部署免初始化。触发词：部署到ECS、部署项目到ECS、部署到云服务器、把这个项目部署上去、上线到ECS、把仓库部署到ECS、当前目录部署、阿里云ECS部署、appmanager部署、aliyun appmanager、一键部署App、部署AI Agent、deploy to ECS、code deploy、deploy app、deploy agent、appmanager deploy、ECS code deploy、跑一下这个项目、把代码跑到ECS上、ECS上线。 Skill: alibabacloud-ecs-code-deploy Owner: sdk-team Summary: 基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot 等），新建或已有 ECS 实例，自动处理分组冲突、zip 解压、余额不足、地域参数透传、重复部署免初始化。触发词：部署到ECS、部署项目到ECS、部署到云服务器、把这个项目部署上去、上线到ECS、把仓库部署到ECS、当前目录部署、阿里云ECS部署、appmanager部署、aliyun appmanager、一键部署App、部署AI Agent、deploy to ECS、code deplo","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s173swjet2yrebzqrp6hjkvmy583mxef:alibabacloud-ecs-code-deploy","sourceUrl":"https://clawhub.ai/sdk-team/alibabacloud-ecs-code-deploy","homepage":"https://clawhub.ai/sdk-team/skills/alibabacloud-ecs-code-deploy","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/sdk-team/alibabacloud-ecs-code-deploy","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/sdk-team/skills/alibabacloud-ecs-code-deploy","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:30:00.361Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:30:00.361Z","emptyReason":null},"stars":null,"forks":null,"downloads":1123,"packageName":null,"latestVersion":"1.0.3","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:30:00.347Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T07:30:00.361Z","lastCrawledAt":"2026-10-11T07:30:00.347Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T07:30:00.347Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.3","createdAt":"2026-08-13T02:03:22.919Z","changelog":"alibabacloud-ecs-code-deploy v1.0.3 - SKILL.md majorly updated: now features a full Chinese description and expanded trigger keywords. - Added mandatory User-Agent environment variable injection for all `aliyun` CLI calls (observability section). - Enhanced CLI upgrade method priority instructions for both Unix and Windows, detailing correct install/upgrade flows. - Updated documentation and references for clearer cross-platform path resolution and workflow compliance. - Removed the deprecated skill-card.md file.","fileCount":12,"zipByteSize":57988},{"version":"1.0.1","createdAt":"2026-06-08T02:54:11.108Z","changelog":"alibabacloud-ecs-code-deploy 1.0.1 - Changed minimum required aliyun CLI version from 3.3.14 to 3.3.19 in skill logic and documentation. - Now requires auto-install of aliyun CLI if missing (without asking user); upgrades for existing installations still require user approval. - Updated environment-check and CLI install/upgrade flow in SKILL.md for improved automation and clarity. - Corrected AI-Mode configuration instructions: note that `deploy_toolkit.py check` auto-configures AI-Mode; manual steps are a fallback. - Removed redundant file: skill-card.md.","fileCount":12,"zipByteSize":52290},{"version":"1.0.0","createdAt":"2026-05-28T03:19:20.085Z","changelog":"alibabacloud-ecs-code-deploy 1.0.0 - Initial release with comprehensive ECS deployment workflow via Alibaba Cloud CLI (aliyun) and automated toolkit scripts. - Added full step-by-step deployment instructions, including mandatory todo list, script-first enforcement, and precise upgrade/remediation flows. - Introduced references for credential configuration, deployment output/management, lessons learned, and a Flask app deployment tutorial. - Included scripts for deployment automation and strict rules for environment setup, AI-Mode, and repeated-deploy detection. - Removed deprecated/legacy documentation, ensuring up-to-date best practices throughout.","fileCount":12,"zipByteSize":50614},{"version":"0.0.1-beta.1","createdAt":"2026-05-27T06:41:42.942Z","changelog":"- Initial beta release enabling deployment of applications and AI agents to Alibaba Cloud ECS using the aliyun appmanager CLI. - Enforces a strict, ordered deployment workflow via a required todo list, including environment checks, project acquisition, config generation, pricing confirmation, deployment, and verification. - Integrates a dedicated toolkit script (deploy_toolkit.py) for critical steps, ensuring cross-platform compatibility and encapsulating all checks and commands. - Automatically handles skill directory resolution for script execution, prohibiting platform-specific hardcoding. - Explicitly requires AI-Mode configuration for traceability in all Alibaba Cloud CLI API calls. - Enforces use of the default Alibaba Cloud credential chain, explicitly forbidding handling of AccessKey/SecretKey within the skill.","fileCount":9,"zipByteSize":41648}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s173swjet2yrebzqrp6hjkvmy583mxef:alibabacloud-ecs-code-deploy","setupComplexity":"low","setupSteps":["Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T10:46:45.245Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-sdk-team-alibabacloud-ecs-code-deploy/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T07:30:00.361Z","emptyReason":null},"readme":"Skill: alibabacloud-ecs-code-deploy\n\nOwner: sdk-team\n\nSummary: 基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot 等），新建或已有 ECS 实例，自动处理分组冲突、zip 解压、余额不足、地域参数透传、重复部署免初始化。触发词：部署到ECS、部署项目到ECS、部署到云服务器、把这个项目部署上去、上线到ECS、把仓库部署到ECS、当前目录部署、阿里云ECS部署、appmanager部署、aliyun appmanager、一键部署App、部署AI Agent、deploy to ECS、code deploy、deploy app、deploy agent、appmanager deploy、ECS code deploy、跑一下这个项目、把代码跑到ECS上、ECS上线。\n\nTags: latest:1.0.3\n\nVersion history:\n\nv1.0.3 | 2026-08-13T02:03:22.919Z | auto\n\nalibabacloud-ecs-code-deploy v1.0.3\n\n- SKILL.md majorly updated: now features a full Chinese description and expanded trigger keywords.\n- Added mandatory User-Agent environment variable injection for all `aliyun` CLI calls (observability section).\n- Enhanced CLI upgrade method priority instructions for both Unix and Windows, detailing correct install/upgrade flows.\n- Updated documentation and references for clearer cross-platform path resolution and workflow compliance.\n- Removed the deprecated skill-card.md file.\n\nv1.0.1 | 2026-06-08T02:54:11.108Z | auto\n\nalibabacloud-ecs-code-deploy 1.0.1\n\n- Changed minimum required aliyun CLI version from 3.3.14 to 3.3.19 in skill logic and documentation.\n- Now requires auto-install of aliyun CLI if missing (without asking user); upgrades for existing installations still require user approval.\n- Updated environment-check and CLI install/upgrade flow in SKILL.md for improved automation and clarity.\n- Corrected AI-Mode configuration instructions: note that `deploy_toolkit.py check` auto-configures AI-Mode; manual steps are a fallback.\n- Removed redundant file: skill-card.md.\n\nv1.0.0 | 2026-05-28T03:19:20.085Z | auto\n\nalibabacloud-ecs-code-deploy 1.0.0\n\n- Initial release with comprehensive ECS deployment workflow via Alibaba Cloud CLI (aliyun) and automated toolkit scripts.\n- Added full step-by-step deployment instructions, including mandatory todo list, script-first enforcement, and precise upgrade/remediation flows.\n- Introduced references for credential configuration, deployment output/management, lessons learned, and a Flask app deployment tutorial.\n- Included scripts for deployment automation and strict rules for environment setup, AI-Mode, and repeated-deploy detection.\n- Removed deprecated/legacy documentation, ensuring up-to-date best practices throughout.\n\nv0.0.1-beta.1 | 2026-05-27T06:41:42.942Z | auto\n\n- Initial beta release enabling deployment of applications and AI agents to Alibaba Cloud ECS using the aliyun appmanager CLI.\n- Enforces a strict, ordered deployment workflow via a required todo list, including environment checks, project acquisition, config generation, pricing confirmation, deployment, and verification.\n- Integrates a dedicated toolkit script (deploy_toolkit.py) for critical steps, ensuring cross-platform compatibility and encapsulating all checks and commands.\n- Automatically handles skill directory resolution for script execution, prohibiting platform-specific hardcoding.\n- Explicitly requires AI-Mode configuration for traceability in all Alibaba Cloud CLI API calls.\n- Enforces use of the default Alibaba Cloud credential chain, explicitly forbidding handling of AccessKey/SecretKey within the skill.\n\nArchive index:\n\nArchive v1.0.3: 12 files, 57988 bytes\n\nFiles: references/deploy-output-and-management.md (9574b), references/init-and-credentials.md (20436b), references/lessons-learned.md (3191b), references/ram-policies.md (5352b), references/script-templates.md (13104b), references/skill-dir-resolution.md (4676b), references/tutorial-flask-app.md (5476b), scripts/deploy_toolkit.py (53013b), scripts/requirements.txt (238b), skill-card.md (2734b), SKILL.md (33941b), _meta.json (147b)\n\nFile v1.0.3:SKILL.md\n\n---\nname: alibabacloud-ecs-code-deploy\ndescription: 基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot 等），新建或已有 ECS 实例，自动处理分组冲突、zip 解压、余额不足、地域参数透传、重复部署免初始化。触发词：部署到ECS、部署项目到ECS、部署到云服务器、把这个项目部署上去、上线到ECS、把仓库部署到ECS、当前目录部署、阿里云ECS部署、appmanager部署、aliyun appmanager、一键部署App、部署AI Agent、deploy to ECS、code deploy、deploy app、deploy agent、appmanager deploy、ECS code deploy、跑一下这个项目、把代码跑到ECS上、ECS上线。\n---\n\n# Deploy to Alibaba Cloud ECS via aliyun appmanager\n\n## Overview\n\n`aliyun appmanager` is an Agent-friendly CLI tool for one-click deployment of applications (App) and AI Agents to Alibaba Cloud ECS. It supports non-interactive mode (`--non-interactive`), structured JSON output (`--output json`), and streaming NDJSON responses.\n\n**Default behavior**: When user invokes `/alibabacloud-ecs-code-deploy` without specifying a project path or URL, deploy the **current working directory** project to Alibaba Cloud ECS. If user provides a git URL, clone it to the current directory first, then `cd` into the cloned directory and proceed with deployment.\n\n> **EXECUTION ORDER**: The Agent MUST follow the \"Complete Deployment Workflow\" section at the bottom of this document for the correct execution sequence. The Task sections below are organized by topic for reference — their numbering does NOT imply execution order.\n\n---\n\n## MANDATORY: Create Todo List Before Starting\n\n**Before executing any step**, the Agent MUST create a todo list with ALL of the following items. Do NOT omit any item. Do NOT start deployment until the todo list is created.\n\n```\nTodo list (Deploy to Alibaba Cloud ECS):\n  [ ] 0. Resolve $SKILL_DIR (cross-platform path — MUST run first; see \"Step 0\" below)\n  [ ] 1. Environment pre-check (MUST run deploy_toolkit.py check; manual commands FORBIDDEN as replacement)\n  [ ] 2. Obtain project (clone git URL here if needed; skip for local projects)\n  ── Check whether .appmanager/config.yaml already exists (repeat-deploy shortcut) ──\n  │  Exists + new ECS (no instanceId)      → skip 3-5, start from 5.5 (price check)\n  │  Exists + existing ECS (has instanceId) → skip 3-5.5, jump to 6 (deploy)\n  │  Does not exist                        → proceed normally from 3\n  ───────────────────────────────────────────────────────────────────────────────\n  [ ] 3. Read project (README.md -> quick-deploy method) + identify type (agent / app)\n  [ ] 4. Ask user for deployment config (region + new ECS / existing ECS)\n  [ ] 5. Init + generate scripts (appmanager init -> write start/stop scripts to config.yaml)\n  [ ] 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)\n  [ ] 6. Deploy (MUST run deploy_toolkit.py deploy; manual deploy command FORBIDDEN as replacement)\n  [ ] 7. Verify (MUST run deploy_toolkit.py verify; manual status command FORBIDDEN as replacement)\n  [ ] 8. Output final result (console link + cost reminder + management commands)\n```\n\n> **⛔ SCRIPT-FIRST RULE**: Steps 1, 5, 6, 7 have a dedicated toolkit script at `$SKILL_DIR/scripts/deploy_toolkit.py` (where `$SKILL_DIR` is resolved in **Step 0** below — works on Qoder, Claude Code, and any other platform). The Agent MUST run the corresponding subcommand DIRECTLY as the FIRST and ONLY action for that step — NEVER run manual CLI commands (like `aliyun version`, version checks, credential checks) BEFORE or INSTEAD of the script. The script already handles ALL checks internally. Manual commands are ONLY allowed as fallback if the script file itself does not exist.\n>\n> **❌ WRONG (Step 1)**: Run `aliyun version` → check version → run `~/.aliyun/appmanager-venv/bin/python ...` → check version → THEN run `deploy_toolkit.py check`\n> **✅ CORRECT (Step 1)**: Run `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check` → if exit 1, fix the issue it reports → if script file missing, THEN fall back to manual checks\n\n> Item 6 is **NON-NEGOTIABLE**. An Agent that skips log verification and directly outputs \"deployment succeeded\" has NOT completed this skill correctly. If `deploy_toolkit.py verify` exits 1 (failed), the Agent MUST fix the issue and re-deploy before proceeding to item 7.\n\n---\n\n## Step 0 (MANDATORY): Resolve `$SKILL_DIR` — Cross-Platform Path\n\n> The toolkit script lives at `<skill-root>/scripts/deploy_toolkit.py`. Different platforms install skills to different locations (Qoder/Claude Code/Qwen/...). The Agent MUST resolve the absolute skill root **once** at session start and reuse it everywhere `$SKILL_DIR` appears below. **Hardcoding any platform-specific path is FORBIDDEN.**\n\n**See [references/skill-dir-resolution.md](references/skill-dir-resolution.md) for the full 10-candidate detection algorithm, the `export + test -f` verify snippet, and Pattern A / Pattern B / ⛔ Anti-pattern usage rules.**\n\nQuick recap (read the reference for details):\n\n- ✅ **Pattern A** (persistent shell): `export SKILL_DIR=\"/abs/path\"` then later `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" <sub>`\n- ✅ **Pattern B** (fresh shell per call): inline the absolute path — `python3 \"/abs/path/scripts/deploy_toolkit.py\" <sub>`\n- ⛔ **Anti-pattern**: `SKILL_DIR=/path python3 \"$SKILL_DIR/...\"` — outer shell expands `$SKILL_DIR` BEFORE the prefix assignment, producing `/scripts/deploy_toolkit.py` and ENOENT. If you see `python3: can't open file '/scripts/deploy_toolkit.py'`, switch to Pattern A or B.\n\n---\n\n## Task 1: Install Alibaba Cloud CLI\n\n**Primary action**: Run `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check` — it checks CLI version + appmanager-cli version + credentials in one run. Only if the script file is missing, use the fallback in [references/init-and-credentials.md](references/init-and-credentials.md).\n\n> **MUST — Handling unmet environment prerequisites**: When `check` exits 1 because the aliyun CLI is missing or older than 3.3.19 (or appmanager-cli is missing/outdated), the Agent **MUST NOT stop the workflow silently**. The required flow is:\n> 1. **CLI NOT installed** → **Auto-install directly without asking user** — execute the install command (see snippet below or [references/init-and-credentials.md](references/init-and-credentials.md) for the right arch), then re-run `deploy_toolkit.py check` to confirm.\n> 2. **CLI already installed** → **ASK the user first** — show the detected version + the required version + the upgrade command, and ask for explicit consent (e.g. \"aliyun CLI 3.3.4 is already installed but below the required >= 3.3.19 for appmanager; approve upgrade (overwrite-install into /usr/local/bin, requires sudo)?\"). Never assume yes; never paste credentials.\n>    - **On approval** — execute the install/upgrade command, then re-run `deploy_toolkit.py check` to confirm.\n>    - **On refusal** — stop with the refusal as the reason. Do NOT continue with the older version (deployment will fail anyway).\n>\n> The toolkit's `check` output already includes an `→ AGENT: DO NOT stop. ASK user ...` line for each fixable issue — follow it verbatim (except for the \"not installed\" case, which is auto-handled).\n>\n> **MUST — Upgrade method priority**: brew-managed → `brew upgrade` (do NOT overwrite `/usr/local/bin/` again); sudo → overwrite `/usr/local/bin/`; no sudo → `~/bin/` + PATH persist (Unix). Scoop/Choco → `%USERPROFILE%\\bin` + User PATH (Windows). Full priority rules → [references/init-and-credentials.md](references/init-and-credentials.md) § \"CLI Install/Upgrade Method Priority\". After install/upgrade, ALWAYS rerun `deploy_toolkit.py check` to confirm; if `which -a aliyun` still shows the old binary first, fix PATH order — DO NOT repeat the same overwrite.\n\n## Observability (MANDATORY): User-Agent Injection\n\n> **⛔ Every `aliyun` CLI call MUST carry this skill's User-Agent** so all API requests are traceable in cloud-side logs. The Agent MUST export the UA env var ONCE at session start (right after Step 0), before any `aliyun` / `deploy_toolkit.py` invocation.\n\n**Full UA template:**\n\n```\nAlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/{session-id}\n```\n\n**session-id unified rules:**\n- Generate ONCE per agent session: `SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')` — lowercase UUID (any lowercase-hex random token ≥ 16 chars is equivalent).\n- Reuse the SAME session-id for ALL CLI calls within the session — NEVER regenerate per command, otherwise one deployment scatters into untraceable fragments.\n- Persist consistently with the Step 0 rules: Pattern A `export SESSION_ID=...` (persistent shell) or inline the literal value (fresh shell per call).\n\n**Injection method (modern — env var):**\n\n```bash\nexport ALIBABA_CLOUD_USER_AGENT=\"AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/${SESSION_ID}\"\n```\n\n> ⛔ The legacy `aliyun configure ai-mode enable / set-user-agent` mechanism is DEPRECATED — do NOT use it. Do NOT combine `ALIBABA_CLOUD_USER_AGENT` with ai-mode or per-command env prefixes for the same skill token: the CLI stacks these sources and produces duplicate UAs. Set the env var ONCE per session and leave it.\n\n---\n\n## Task 2: Configure Credentials\n\n`deploy_toolkit.py check` already validates credentials. Only if credentials are missing/invalid, see [references/init-and-credentials.md](references/init-and-credentials.md) for the default-credential-chain remediation flow.\n\n> **⛔ PREFER OAuth OVER AK**: OAuth is more secure and convenient (no long-term secret storage). The Agent MUST present OAuth as the first option. When the user agrees, the Agent **runs the login command directly** — but MUST first warn the user that the command opens a browser authorization page and **blocks until the user completes authorization in the browser** — then execute `aliyun configure --mode OAuth --profile oauth` and verify with `aliyun sts get-caller-identity --profile oauth`.\n>\n> **⛔ SA-2.12 — DO NOT collect AK/SK in chat**: If the user prefers AK auth, give **one** ready-to-run command template with placeholders — `aliyun configure set --profile default --mode AK --access-key-id <your-access-key-id> --access-key-secret <your-access-key-secret> --region cn-hangzhou` — and ask the user to fill in their own AK/SK and run it **in their own terminal**. The Agent **NEVER** asks the user to paste AccessKey/Secret/STS-Token values into the chat, **NEVER** puts raw AK/SK in tool-call arguments or scripts, and **NEVER** echoes credential values. The default credential chain (ECS RAM Role / env vars / pre-existing `~/.aliyun/config.json`) is also honored. Full remediation flow → [references/init-and-credentials.md](references/init-and-credentials.md).\n>\n> **CRITICAL PROHIBITION**: NEVER run standalone `appmanager` or `aliyun appmanager login`.\n\n---\n\n## Task 3: Initialize Project\n\n### Step 1 (MANDATORY): Read README.md FIRST\n\n> **CRITICAL ORDERING RULE**: Before scanning any project files, the Agent MUST read `README.md` (or `README`) in the project root. This is ALWAYS the first action in Task 3.\n\n**What to extract from README:**\n- Quick-start / deploy commands (e.g. `pip install -r requirements.txt && python main.py`, `npm install && npm start`)\n- Official build/run commands, Docker deploy methods, port number, required environment variables\n\n#### MANDATORY: Present README Methods to User and Follow Decision Tree\n\n**Step A**: List what README provides to the user.\n\n**Step B**: Select method by priority:\n\n| Priority | Method Type | Action |\n|----------|------------|--------|\n| 1 (HIGHEST) | **Native CLI / package manager install** (`npm install -g`, `pip install`, `go install`) | Use directly |\n| 2 | **Native build + run** (`pip install && python main.py`, `npm install && npm start`) | Use, install runtime |\n| 3 | **Script-based deploy** (`bash deploy.sh`) | Must confirm non-interactive |\n| 4 (LOWEST) | **Docker / docker-compose** | Only when no higher priority exists; check China accessibility |\n\n**Step C**: Execute based on scenario:\n- **README has native method (priority 1/2)** → Use it directly as start script core. NEVER ignore README and build from scratch.\n- **README only has Docker** → Check image accessibility (see [references/script-templates.md](references/script-templates.md) \"Docker Image Accessibility Check\"). Warn user about China mirror risks.\n- **README has no deploy info / absent** → Agent scans project files independently (only allowed case).\n\n> **Why README first?** Most projects document the exact build/run commands. Auto-detecting from files alone is error-prone.\n\n---\n\n### Step 2: Determine project type\n\n| Condition | Type |\n|-----------|------|\n| Project depends on `agentscope` | `agent` |\n| **Everything else** (langchain, mcp, autogen, web services, tools, etc.) | `app` |\n\n### Determine `--name`\n\nUse the **project directory name** (lowercased, hyphens). Inform user: `Default app name uses the directory name <name>`.\n\n### Determine `--region` and ECS target (MUST ask user)\n\n**Agent MUST ask both questions together in ONE message:**\n\n> **1. Which region do you want to deploy to?**\n> - Shanghai (cn-shanghai) / Hangzhou (cn-hangzhou) / Beijing (cn-beijing) / Shenzhen (cn-shenzhen) / Guangzhou (cn-guangzhou) / Chengdu (cn-chengdu) / Nanjing (cn-nanjing) / Hong Kong (cn-hongkong)\n>\n> **2. New ECS or existing ECS?**\n> - New ECS (auto-create instance, pay-as-you-go)\n> - Existing ECS (choose from the list below, or provide an instance ID manually)\n\nNEVER use zone-based labels like \"East China 1\" / \"North China 2\". NEVER add descriptions. City names only.\n\n#### Existing ECS — list the user's latest 10 instances in the chosen region (MANDATORY)\n\nWhen the user picks **existing ECS**, the Agent MUST first query the account's 10 most-recently-created instances **in the chosen region** (plugin mode: `aliyun ecs describe-instances`) and present them as a numbered list for selection — do NOT force the user to recall an instance ID from memory. **Always** also allow manual instance ID entry (e.g. `i-bp1xxxxxxxx`) as a fallback. The query MUST pass the same `--profile` as deployment (same account), otherwise it may return zero / wrong instances. Full command (jq pipeline, no-jq fallback, zero-instance handling) → [references/init-and-credentials.md](references/init-and-credentials.md) § \"Listing existing ECS instances\". The selected/entered ID is passed to `appmanager init --ecs existing --instance-id <ID>`.\n\n> ⚠️ **REGION PROPAGATION CHECK** (MANDATORY): The chosen region MUST be passed verbatim to `appmanager init --region`, written into `config.yaml` `common.deployment.regionId`, AND attached as `--region <REGION_ID>` to every subsequent `deploy_toolkit.py {price,deploy,verify}` invocation. Mismatch / omission triggers `InvalidParameter: DeployRegionId is invalid` from the OOS API.\n\n### Determine `--port` (App type only, OPTIONAL)\n\nOnly specify when the project actually listens on HTTP. Skip for background services (bots, workers, CLI tools). If needed but unknown, default to `8080`. Agent type does NOT use `--port`.\n\n### Non-interactive init\n\nSee [references/init-and-credentials.md](references/init-and-credentials.md) for all init flag combinations.\n\nCreates `.appmanager/config.yaml`. Does NOT support `--overwrite` — delete `.appmanager/` first if exists.\n\n---\n\n## Task 4: Generate Deploy Scripts\n\nFor ALL project types, the Agent MUST generate deployment scripts and write them into `.appmanager/config.yaml`.\n\n### Workflow\n\n1. **Read README.md FIRST** — follow Task 3 decision tree\n2. **If README has no deploy info** — scan project structure (Language Detection below)\n3. **Docker accessibility check** — if Docker path selected (see [references/script-templates.md](references/script-templates.md))\n4. **Generate start & stop scripts** — following rules below. Start script MUST ALWAYS include zip extraction sequence.\n5. **Write to config.yaml** — under `common.scripts.start` and `common.scripts.stop` (NEVER top-level `scripts`)\n\n### Language Detection, Files to Read & Entry Points\n\nLanguage detection rules (indicator files), MUST-read files per language, and entry point detection order → [references/script-templates.md](references/script-templates.md) § \"Project Analysis\".\n\n### General Script Rules\n\n| Rule | Requirement |\n|------|-------------|\n| **⛔ MANDATORY zip extract** | Start script MUST: find zip → `mkdir -p` → `unzip -o` → `cd`. Without this, project dir DOES NOT EXIST on ECS |\n| **Runtime install** | MUST install language runtime FIRST (ECS is bare) |\n| **Install unzip** | `command -v unzip &>/dev/null \\|\\| $PKG_MGR install -y unzip` |\n| **Idempotent** | Safe to run multiple times |\n| **⛔ Log file FIXED path** | MUST be `/root/app.log` and `/root/app.pid`. verify script hardcodes these paths |\n| **Log append** | Always `>>` (never `>`) |\n| **PID file** | `echo $! > /root/app.pid` after `nohup ... &` |\n| **Background run** | `nohup ... >> /root/app.log 2>&1 &` |\n| **Stop old process** | `[ -f /root/app.pid ] && kill \"$(cat /root/app.pid)\" 2>/dev/null \\|\\| true` |\n| **App dir** | `/root/{app_name}` |\n| **No heredoc** | NEVER use `<< 'EOF'` inside scripts — breaks YAML. Use `printf` or `python3 -c` |\n| **MANDATORY tail log** | End with `sleep 3 && cat /root/app.log` for verification capture |\n| **⛔ Stop script: NO exit** | MUST NOT contain `exit`. Deploy system concatenates stop+start — exit kills the entire process |\n\n> ECS instances are bare Linux (typically Alibaba Cloud Linux, RHEL-based, uses `yum`/`dnf`).\n\nFor script templates, language install commands, and config.yaml writing method, see [references/script-templates.md](references/script-templates.md).\n\n---\n\n## Task 4.5: Pre-deploy Price Check + Risk Warning\n\n> **MANDATORY**: Before deploying, run `deploy_toolkit.py price`. The script outputs the **price estimate (with OSS extra-billing reminder)** and, when applicable, a **risk warning** block. The Agent MUST present every flagged item to the user and obtain explicit confirmation BEFORE running `deploy`.\n\n```bash\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" price --config .appmanager/config.yaml\n```\n\n- Exit 0 + `=== AGENT_CONFIRM_REQUIRED ===`: present the **complete** price + risk warning to the user, confirm item by item.\n- Exit 1: price query failed; do NOT proceed to deploy.\n\nThe Agent MUST confirm up to 3 items (price + OSS fees / existing-ECS risk / group overwrite choice) — see [references/deploy-output-and-management.md](references/deploy-output-and-management.md) § \"Pre-deploy Price Check: Confirmation Items\" for detailed descriptions and example phrasing.\n\n> Until ALL applicable confirmations are complete, the Agent MUST NOT invoke `deploy_toolkit.py deploy`.\n\n---\n\n## Task 5: Deploy\n\n```\naliyun appmanager <agent|app> deploy --overwrite --output json\n```\n\n> **STOP after deploy success** — `status: success` only means orchestration completed. Agent MUST run Task 6 verification before outputting results.\n\n### Handling deployment failure\n\n> ⛔ **MANDATORY FAILURE GATE**: After ANY deploy failure (exit 1, timeout, or `ReleaseCancelled`), the Agent MUST run `deploy_toolkit.py verify` IMMEDIATELY — BEFORE any fix attempt, fallback to manual commands, or partial output. Skipping verify after a failure is **FORBIDDEN** and counts as skill failure.\n\n> **Semantics of `ReleaseCancelled`**: it means the start script on ECS failed or timed out. It does **NOT** mean \"someone cancelled the deploy\". The only correct next action: run `deploy_toolkit.py verify` -> read the log -> fix the script -> redeploy.\n\n> **Known failure patterns**: Before ad-hoc troubleshooting, check [references/lessons-learned.md](references/lessons-learned.md) for previously identified deployment failure patterns and proven fixes.\n\n**Failure-handling flow:**\n1. Run `deploy_toolkit.py verify` to fetch `/root/app.log` (DO NOT skip).\n2. Analyze the log to locate root cause.\n3. Fix scripts and redeploy (max 3 attempts).\n4. After 3 failures, stop — report the error, but still output console link + cost reminder + delete command.\n\n---\n\n## Task 6: Post-deploy Verification (BLOCKING)\n\n> `status: Deployed` does NOT mean the application is running. The Agent MUST run verify and semantically analyze the log.\n\n1. Run `deploy_toolkit.py verify` (auto-reads parameters from config.yaml).\n2. Agent semantically analyzes the log to decide whether the application actually started successfully.\n3. Not running -> diagnose -> fix -> redeploy + verify (max 3 attempts).\n4. Only when running is confirmed / user manual action required / 3 attempts failed should the Agent output the final result.\n\n---\n\n## Task 7 & 8: List, Delete, Validate & Final Output\n\nSee [references/deploy-output-and-management.md](references/deploy-output-and-management.md) for:\n- List/Delete commands\n- Config validation\n- Config template reference\n- Critical notes & pitfalls\n- MANDATORY post-deploy output format (console link, cost reminder, usage guide)\n\n### Pre-output Gate — Self-check (⛔ BLOCKING)\n\nBefore outputting results, Agent MUST print the exact `Deployment self-check report` template (see Workflow Step 7.5). **Skipping the report = skill failure** (not an optional summary). If any item is ❌, fix it BEFORE outputting Step 8.\n\n> 📘 Hands-on walk-through with concrete inputs/outputs and edge cases (Python Flask example): see [references/tutorial-flask-app.md](references/tutorial-flask-app.md).\n\n## Complete Deployment Workflow\n\n> **⛔ MANDATORY EXECUTION RULE**: The Agent MUST follow this sequence exactly. For steps that specify a script (steps 1, 5, 6), the Agent MUST run the script — NEVER manually replicate the script's logic with individual commands. The Task sections above are REFERENCE ONLY (for understanding what the scripts do internally or as fallback if scripts are missing).\n\n```bash\n# 0. Resolve $SKILL_DIR (MANDATORY — see \"Step 0\" section above for full algorithm)\n# → Detect the absolute directory containing THIS SKILL.md (most accurate)\n# → Or fall back to platform-specific candidates: ~/.qoder/skills/..., ~/.claude/skills/..., ~/.qwen/skills/..., $SKILLS_HOME/..., etc.\n# → Pattern A (persistent shell): export SKILL_DIR=<abs_path> ; verify $SKILL_DIR/scripts/deploy_toolkit.py exists ; reuse $SKILL_DIR everywhere\n# → Pattern B (fresh shell per command): inline the absolute path — `python3 \"/abs/path/scripts/deploy_toolkit.py\" ...`\n# → ⛔ NEVER use `SKILL_DIR=/path python3 \"$SKILL_DIR/...\"` — outer shell expands $SKILL_DIR\n#    BEFORE the prefix assignment, producing `/scripts/deploy_toolkit.py` and ENOENT.\n\n# 1. Environment check (MUST use deploy_toolkit.py check — DO NOT run manual commands)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check\n# ⛔ FORBIDDEN: running `aliyun version`, `~/.aliyun/appmanager-venv/bin/python -c \"...\"`,\n#    credential checks, or ANY manual version-check commands before or instead of this script.\n#    The script checks ALL of: CLI version + appmanager-cli version + credentials in one run.\n#    Just run the script. Period.\n# → If exit 0: all checks passed, proceed to step 2\n# → If exit 1, address the issue printed by the script:\n#    ⚠️ DO NOT stop silently. For every fixable ❌ line the script prints,\n#       Agent MUST follow the flow below:\n#       - aliyun CLI NOT installed: AUTO-INSTALL directly (no need to ask user)\n#       - aliyun CLI already installed but outdated: ASK user to approve upgrade\n#         (covers to /usr/local/bin, needs sudo), then run the install command\n#         printed by the script (see Task 1).\n#       - appmanager-cli < 1.1.1 or BROKEN venv: ASK user to approve\n#         `rm -rf ~/.aliyun/appmanager-venv` (auto-recreates on next aliyun\n#         appmanager run).\n#         ⚠️ This path is fixed at ~/.aliyun/appmanager-venv (the venv is self-managed\n#            by the aliyun CLI). After deletion, the next `aliyun appmanager` run\n#            auto-recreates it. The Agent MUST use this exact literal path —\n#            NEVER replace it with a variable or build it via concatenation,\n#            to avoid accidentally wiping user data.\n#       - credentials missing/invalid: present OAuth-first remediation\n#         to the user (OAuth / RAM Role / env vars / `aliyun configure` interactive) — NEVER\n#         collect AK/SK in chat. See Task 2 + references/init-and-credentials.md.\n# → If user refuses any fix: stop with that refusal as the reason — DO NOT\n#   continue with a broken environment (deployment will fail anyway).\n# → If script file not found: ONLY THEN fall back to manual checks (Task 1 + Task 2)\n\n# 2. Obtain project source (if needed)\n# → If git URL provided: clone to CURRENT WORKING DIRECTORY, cd into cloned dir\n#    git clone <URL> && cd <cloned_dir>\n# → If local path / current directory: skip this step, use directly\n\n# 🔀 REPEAT DEPLOYMENT SHORTCUT — check BEFORE step 3\n# → Check if .appmanager/config.yaml already exists in the project directory\n# → If YES (config.yaml exists):\n#    Read the file and check for common.deployment.instanceId:\n#      - instanceId ABSENT (new ECS): skip steps 3-5, jump to step 5.5 (price check)\n#      - instanceId PRESENT (existing ECS): skip steps 3-5.5, jump to step 6 (deploy)\n#    In both cases, inform user: \"Existing .appmanager/config.yaml detected; will reuse the existing config and deploy directly.\"\n# → If NO (config.yaml does NOT exist): proceed normally from step 3\n\n# 3. Read project + identify type (agent or app)\n# → READ README.md FIRST — highest priority source for deployment method:\n#    - Agent MUST list README's methods to user and select by priority:\n#      Native CLI install > Native build+run > Script deploy > Docker\n#    - ❌ NEVER ignore README methods and scan project files instead\n#    - ❌ NEVER prefer Docker when native methods are available\n#    - Docker: ONLY when no native method exists, MUST warn user about China mirror risks\n#    - Only if README absent/empty/no deploy info → Agent scans project files independently\n# → Only classify as \"agent\" if project depends on `agentscope`; everything else is \"app\"\n# → Determine --name from directory name, --port from project config/README\n# → For Docker: check image accessibility from China (see references/script-templates.md)\n\n# 4. Ask user for deployment region + ECS target (MANDATORY — ask together in one question)\n# → 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)...\"\n# → Question 2: \"New ECS or existing ECS?\" — if existing, FIRST query the account's 10 most-recently-created\n#   ECS instances in the chosen region and present them as a numbered list for selection:\n#     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)\n#   Also always support manual instance ID entry (e.g. i-bp1xxxxxxxx). See Task 3 \"Existing ECS\" section.\n# → NEVER use zone-based labels like \"East China 1\" / \"North China 2\" — always use city names\n# → NEVER skip the ECS choice and default to creating new\n# → ⚠️ 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.\n\n# 5. Init + generate scripts (appmanager init → write start/stop to config.yaml)\n# → If .appmanager/ already exists in the CURRENT project directory, ask user before removing.\n#   ⚠️ DESTRUCTIVE: `rm -rf .appmanager` deletes the existing deployment config.\n#      Required guard before deletion:\n#        a. Confirm CWD matches the intended project directory (`pwd` shows expected path)\n#        b. Confirm target is the relative path `.appmanager` (NEVER absolute, NEVER with variables)\n#        c. Inform the user \"About to delete the existing deployment config under ./.appmanager/. This is irreversible.\" and obtain consent\n#      Recommended safer alternative: back up first\n#        mv .appmanager .appmanager.bak.$(date +%Y%m%d%H%M%S)\n#      Only after explicit user consent: rm -rf ./.appmanager\n# → 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\"]\n#   (See references/init-and-credentials.md for full flag combinations by type)\n# → Then generate start/stop scripts and write to config.yaml:\n#   - MUST write to common.scripts.start and common.scripts.stop (NEVER top-level scripts key)\n#   - Use python3 yaml library: config['common']['scripts'] = {'start': ..., 'stop': ...}\n#   - PRIORITY: README deployment commands → use directly; only auto-generate when README has none\n#   - ⛔ MANDATORY: Start script MUST ALWAYS include zip extraction (mkdir + unzip + cd) BEFORE\n#     any build/run commands. appmanager uploads zip but does NOT extract it.\n\n# 5.5. Pre-deploy price check + risk warning (MUST run deploy_toolkit.py price — Agent handles user confirmation)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" price --config .appmanager/config.yaml\n# → Script output structure:\n#    [Price table] estimate from `appmanager price` (order-billed resources: ECS/EIP/bandwidth) + the trailing 📦 OSS extra-billing reminder\n#    [Risk warning] only when detected: [Existing-ECS deployment risk] / [Group overwrite risk] / [Failure-leftover group]\n# → Script does NOT ask user for confirmation — that's the Agent's job\n# → If exit 0: Agent MUST read the output, present the COMPLETE breakdown to user — including:\n#    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)\n#    2) If output contains [Existing-ECS deployment risk] -> ask whether to deploy onto that existing ECS (may impact other apps on it)\n#    3) If output contains [Group overwrite risk] -> ask user to choose A (overwrite) or B (new group)\n#    Example: \"Estimated cost: compute resources CNY X.XXX/hour (~CNY XXX.XX/month); public traffic billed by usage at CNY 0.80/GB;\n#             the deployment also incurs minor OSS storage and request fees (intra-region pull is free of public outbound charges).\n#             Confirm to continue?\"\n# → After ALL items confirmed by user: run the matching deploy command per item 3's choice (default overwrite / --force-new-group for new group)\n# → If ANY item refused: STOP deployment\n# → If exit 1: price query failed, show error to user, do NOT proceed\n\n# 6. Deploy (MUST use deploy_toolkit.py deploy — DO NOT run deploy manually)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" deploy \\\n  --type <agent|app> --name <APP_NAME> --group <GROUP_NAME> --region <REGION_ID>\n# ⛔ FORBIDDEN: running `aliyun appmanager deploy` directly without this script\n# → Handles: group status check → conflict auto-resolve → deploy\n# → Exit 0: deploy submitted, proceed to step 7\n# → Exit 1: ⛔ MUST run step 7 (verify) IMMEDIATELY to fetch /root/app.log;\n#           skipping to step 8, outputting partial results, or running manual\n#           commands instead is FORBIDDEN. Then fix script per log and redeploy\n#           (max 3 attempts).\n\n# 7. Verify (MUST use deploy_toolkit.py verify — DO NOT check status manually)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" verify \\\n  --type <agent|app> --name <APP_NAME> --group <GROUP_NAME> --region <REGION_ID>\n# ⛔ FORBIDDEN: running `aliyun appmanager status` + manual log analysis instead of this script\n# → Optional: --wait <seconds> for slow-starting apps (default 3s, Java/heavy use 15-30)\n# → Dual-path: Cloud Assistant cat /root/app.log (preferred) → deployCommandOutput (fallback)\n# → Exit 0: app running, proceed to step 8\n# → Exit 1: app failed — fix start script, re-deploy (back to step 6)\n# → Exit 2: inconclusive — retry with longer --wait or suggest SSH check\n\n# 7.5. Self-check summary (⛔ BLOCKING — skill fails if omitted)\n# MUST print the exact template below to the user — this is a completion criterion, NOT optional.\n#\n# ---\n# ✅ Deployment self-check report:\n#   0. Path resolution — SKILL_DIR=___ (script exists ✅)\n#   1. Environment pre-check — CLI v___ / appmanager-cli v___ / credentials valid ✅\n#   2. Project obtained — (local / cloned) ✅\n#   3. Project identified — type: ___ / deploy method source: README.md ✅\n#   4. Deployment region — user choice: ___ ✅\n#   5. Init + scripts — config.yaml generated; start script: ___ (key command summary) ✅\n#   5.5. Pre-deploy price check — user confirmed price (CNY ___/hour, ~CNY ___/month) ✅\n#   6. Deploy executed — deploy_toolkit.py deploy exit 0 ✅\n#   7. Run verification — deploy_toolkit.py verify exit 0 / log keywords: ___ ✅\n# ---\n#\n# If any item is ❌, fix it BEFORE step 8 — this is for the USER to see, proving the work is properly done.\n\n# 8. Output results (MANDATORY: console link + cost reminder + management commands)\n# → See references/deploy-output-and-management.md for full output format\n```\n\nFile v1.0.3:_meta.json\n\n{\n  \"ownerId\": \"kn74p5w8ywv6prh40g0s82gmqh83nw54\",\n  \"slug\": \"alibabacloud-ecs-code-deploy\",\n  \"version\": \"1.0.3\",\n  \"publishedAt\": 1786586602919\n}\n\nFile v1.0.3:references/deploy-output-and-management.md\n\n# Deploy Output & Management Reference\n\n## Common Deploy Options\n\n| Flag | Description |\n|------|-------------|\n| `--config PATH` | Custom config file (default: `.appmanager/config.yaml`) |\n| `--overwrite` | Force overwrite existing files in OSS |\n| `--dry-run` | Validate only, do not execute deployment |\n| `--output json` | Output NDJSON stream (Agent-friendly) |\n| `--name TEXT` | Override app name |\n| `--group_name TEXT` | Override group name |\n| `--region TEXT` | Override deployment region |\n| `--revision_id TEXT` | Redeploy using existing artifact |\n\n### Deploy output format\n\n`--overwrite --output json` is the **standard deploy invocation**. Always use both flags.\n\nOutput format (NDJSON, one JSON per line):\n```\n{\"type\":\"step\", \"step\":1, \"total\":9, \"message\":\"Validating config...\"}\n{\"type\":\"step\", \"step\":2, \"total\":9, \"message\":\"Uploading to OSS...\"}\n{\"type\":\"result\", \"status\":\"success\", \"data\":{\"revision_id\":\"rev-xxx\", ...}}\n```\n\n---\n\n## MANDATORY: Post-deploy Output\n\nWhen the self-check passes (all items OK), output the following to the user:\n\n### 1. Deployment summary table\n\nIncludes app name, deployment region, group name, deployment status, Revision ID, and ECS instance ID.\n\n### 2. Console link\n\nRead the `console_url` field from the deploy result; if missing, build the URL with the formats below:\n- On success: `https://computenest.console.aliyun.com/app/detail?tabKey=overview&appName=<APP_NAME>&groupName=<GROUP_NAME>`\n- On failure / pending confirmation (ReleaseWaiting, script execution failure, etc.): `https://computenest.console.aliyun.com/app/detail?tabKey=flow&appName=<APP_NAME>&groupName=<GROUP_NAME>` (jumps to the execution-flow page)\n\n### 3. Resource cost reminder (MUST include the delete command)\n\n> Resource cost reminder: this deployment uses ECS instances and OSS storage (pay-as-you-go). Delete the resources when you no longer need them to avoid recurring charges:\n> ```bash\n> aliyun appmanager <agent|app> delete --name <APP_NAME> --group_name <GROUP_NAME>\n> ```\n\n### 4. Status query command\n\n> ```bash\n> aliyun appmanager <agent|app> status --name <APP_NAME> --group_name <GROUP_NAME>\n> ```\n\n### 5. Usage guidance\n\nThe Agent MUST tailor the usage guidance to the project type and the deploy log:\n\n| Project usage type | Detection signal | Usage guidance |\n|--------------------|------------------|----------------|\n| **Web service** (HTTP listener) | Deploy log shows \"Listening on port X\"; project uses flask / fastapi / express / spring / django | Provide access URL: `http://<ECS_PUBLIC_IP>:<PORT>` (extract ECS public IP from `status` output) |\n| **API service** | Project defines REST / GraphQL endpoints | Provide API base URL + sample `curl` command |\n| **CLI tool / library** | Project is a command-line tool, SDK, or library (e.g. agentscope) | Provide SSH login command + a verification command |\n| **Background service / worker** | Project is a queue consumer, scheduled job, or daemon | Inform the user the service is running in background; provide log-tail command |\n| **Static site / frontend** | Project contains HTML/CSS/JS served by nginx / serve | Provide access URL: `http://<ECS_PUBLIC_IP>:<PORT>` |\n\n**Get the ECS public IP**: extract `public_ip` or `instance_ip` from `aliyun appmanager <agent|app> status --output json` output.\n\n> **WARNING**: Omitting the console link or cost reminder is FORBIDDEN.\n\n---\n\n## List & Delete\n\n### List applications\n\n```\naliyun appmanager agent list\naliyun appmanager agent list --name my-agent  # list groups under app\naliyun appmanager app list\n```\n\n### Delete\n\n```\n# Delete a group first\naliyun appmanager agent delete --name my-agent --group_name default-cn-beijing\n# Then delete the application\naliyun appmanager agent delete --name my-agent\n```\n\n> In `--output json` mode, confirmation is skipped automatically.\n\n---\n\n## Validate Config\n\n```\naliyun appmanager config validate\naliyun appmanager config validate --config path/to/config.yaml --output json\n```\n\n---\n\n## Config Template Reference\n\nGenerated by `aliyun appmanager init --print-template`. Below is a unified template (use `type: agent` or `type: app`):\n\n```yaml\nmetadata:\n  name: my-app                    # Required: app/agent name\n  type: app                       # \"app\" or \"agent\"\n  groupName: default-cn-beijing   # NEVER use bare \"default\" — always include region suffix\n  regionId: cn-beijing            # Required: deployment region\n\ncommon:\n  deployment:\n    # Option 1: New ECS (auto-created)\n    ecsInstanceType: ecs.u1-c1m2.large\n    systemDiskSize: 40\n    internetMaxBandwidthOut: 5\n    # Option 2: Existing ECS (uncomment below, remove Option 1)\n    # instanceId: i-bp1xxxxxxxx\n\n  scripts:                        # REQUIRED: Agent-generated scripts (MUST be under common.scripts)\n    start: |\n      #!/bin/bash\n      # Agent generates start script based on project analysis (see SKILL.md Task 4)\n    stop: |\n      #!/bin/bash\n      # Agent generates stop script (MUST NOT contain 'exit' statement)\n\n# Agent-specific config (ONLY for type: agent, remove for type: app)\nagent:\n  model:\n    name: qwen3.6-plus\n    apiKey: \"sk-xxx\"              # REQUIRED for agent type — deployment fails without this\n```\n\n---\n\n## Critical Notes & Pitfalls\n\n1. **NEVER use standalone `appmanager` or `aliyun appmanager login`**: Only `aliyun appmanager <cmd>` is valid. **SA-2.12** — credentials must come from the aliyun CLI/SDK default credential chain (ECS RAM Role / env vars / pre-existing `~/.aliyun/config.json` set up out-of-band by the user); the Agent MUST NOT collect AK/SK in chat or pass them via `--access-key-*` flags.\n\n2. **Agent type REQUIRES `apiKey`**: Deploying type `agent` without `agent.model.apiKey` in config.yaml will fail.\n\n3. **Both types generate deploy scripts locally**: Agent generates scripts by scanning project → writes to `common.scripts` in config.yaml. No API Key needed for script generation.\n\n4. **First run auto-installs**: First `aliyun appmanager` auto-creates venv at `~/.aliyun/appmanager-venv/` — Agent should NEVER interact with this venv directly.\n\n5. **ECS zone compatibility**: Not all instance types available in every zone. If zone-related errors occur, try a different region or instance type.\n\n6. **OSS Bucket name conflict**: Bucket named `<app_name>-<region>` is globally unique. If `AccessDenied` at `upload_to_oss` → change `--name` to a more unique value and re-run `init` + `deploy`.\n\n7. **`groupName` MUST include region suffix**: NEVER use bare `default`. Always `default-<regionId>` (e.g., `default-cn-hangzhou`).\n\n8. **Pre-deploy group check**: Handled automatically by `deploy_toolkit.py deploy`.\n\n9. **Insufficient balance (`NotEnoughBalance`)**: account balance < CNY 100 cannot create pay-as-you-go ECS. Tell the user to top up at https://usercenter2.aliyun.com/finance/fund-management, or switch to deploying onto an existing ECS instance.\n\n---\n\n## Pre-deploy Price Check: Confirmation Items\n\nThe Agent MUST confirm each applicable item with the user **one by one** before invoking `deploy_toolkit.py deploy`.\n\n### 1. Price confirmation (including OSS extra fees — ALWAYS required)\n\nThe price output has two parts:\n- The estimate from `appmanager price` for \"order-billed\" resources (ECS / EIP / public bandwidth, etc.) in hourly/monthly form.\n- A `OSS extra billing` notice — these items are **NOT covered** by `appmanager price` but always occur during deployment:\n  - OSS standard storage ~CNY 0.12 / GB / month (project archives are usually KB-MB scale, so the amount is tiny but non-zero)\n  - OSS public-network outbound traffic ~CNY 0.50 / GB (**when ECS and OSS are in the same region, intra-region pull is free of public traffic charges**; only cross-region transfer incurs the fee — therefore the deployment region SHOULD match the default OSS bucket region)\n  - OSS Put/Get requests are billed per 10k requests (negligible amount)\n\nThe Agent MUST relay both parts. Example phrasing: \"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?\"\n\n### 2. Existing-ECS deployment impact (only when script outputs `[Existing-ECS deployment risk]`)\n\nWhen `config.yaml` contains `common.deployment.instanceId`, the script lists the risk items. The Agent MUST ask:\n\"About to deploy to the existing ECS instance `i-xxx`. The deployment runs stop -> upload -> start scripts and may stop or overwrite other applications already running on this instance. Confirm to continue?\"\n- User refuses -> STOP and recommend switching to \"new ECS\"\n- User agrees -> proceed to item 3 (if applicable) or directly to deploy\n\n### 3. Group overwrite vs new group (only when script outputs `[Group overwrite risk]`)\n\nWhen the target `groupName` already exists and is associated with active ECS, the script asks for an A/B choice:\n- **A) Overwrite the existing group**: `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" deploy` (default; uses `--overwrite` to replace code / restart processes)\n- **B) Create a new group**: `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" deploy --force-new-group` (the script auto-appends a suffix to allocate a new group name and writes it back to config.yaml; the existing deployment is unaffected)\n\nThe Agent MUST clearly explain the impact of A vs B; **do NOT default to A on the user's behalf**.\n\n> Until ALL applicable confirmations are complete, the Agent MUST NOT invoke `deploy_toolkit.py deploy`.\n\nFile v1.0.3:references/init-and-credentials.md\n\n# Init & Credentials Reference\n\n## Observability: User-Agent Injection (MANDATORY before any CLI call)\n\n> **⛔ Every `aliyun` CLI call MUST carry this skill's User-Agent** so all API requests are traceable in cloud-side logs. Export the UA env var ONCE at session start, before any `aliyun` / `deploy_toolkit.py` invocation.\n\n**Full UA template:**\n\n```\nAlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/{session-id}\n```\n\n**session-id unified rules:**\n- Generate ONCE per agent session: `SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')` — lowercase UUID (any lowercase-hex random token ≥ 16 chars is equivalent).\n- Reuse the SAME session-id for ALL CLI calls within the session — NEVER regenerate per command, otherwise one deployment scatters into untraceable fragments.\n\n**Injection method (modern — env var):**\n\n```bash\n# Run ONCE per session (persistent shell); or prefix each command with the same literal value\nexport SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')\nexport ALIBABA_CLOUD_USER_AGENT=\"AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/${SESSION_ID}\"\n```\n\n> ⛔ The legacy `aliyun configure ai-mode enable / set-user-agent / show / disable` mechanism is DEPRECATED — do NOT use it. Do NOT combine `ALIBABA_CLOUD_USER_AGENT` with ai-mode or per-command env prefixes for the same skill token: the CLI stacks these sources and produces duplicate UAs. Set the env var ONCE per session and leave it.\n\n---\n\n## CLI Install/Upgrade Method Priority\n\n> Avoid the \"repeated upgrade\" pitfall: `/usr/local/bin/` is often shadowed by earlier PATH entries like `/opt/homebrew/bin`.\n\n**On Linux/macOS (Unix):**\n1. brew-managed (`check` prints \"managed by Homebrew\") -> `brew upgrade aliyun-cli`; do NOT overwrite `/usr/local/bin/` again.\n2. sudo available -> overwrite into `/usr/local/bin/`, then verify: `hash -r && which -a aliyun && aliyun version`.\n3. No sudo -> install to `~/bin/`, ask user to approve appending `export PATH=\"$HOME/bin:$PATH\"` to `~/.zshrc` / `~/.bashrc`.\n\n**On Windows (PowerShell)** — no `brew`/`sudo`/`.zshrc`; `check` auto-detects `os.name == \"nt\"` and prints PowerShell guidance:\n1. Scoop/Chocolatey managed -> `scoop update aliyun-cli` or `choco upgrade aliyun-cli -y`.\n2. Otherwise download the official zip and extract into `%USERPROFILE%\\bin` (no admin rights), then persist the **User** PATH via `[Environment]::SetEnvironmentVariable(\"PATH\", \"$dest;$userPath\", \"User\")` (full snippet in the \"Windows (PowerShell) install\" section below).\n3. After install/upgrade, open a **NEW** terminal so the updated User PATH takes effect, then re-run check.\n\nAfter install/upgrade, ALWAYS rerun `deploy_toolkit.py check` to confirm. On Unix, if `which -a aliyun` still shows the old binary first, fix PATH order — DO NOT repeat the same overwrite.\n\n---\n\n## Fallback: Manual CLI Verification & Install (only when deploy_toolkit.py unavailable)\n\n**Version requirements**: aliyun CLI >= 3.3.19, appmanager-cli >= 1.1.1\n\n> **🪟 Windows users**: The `curl | sudo tar xz`, `brew`, `~/.zshrc`/`~/.bashrc` PATH and `~/.aliyun/appmanager-venv/bin/python` snippets in this section are **Unix-only (Linux/macOS)**. On native Windows (cmd/PowerShell), skip them and jump to the **\"Windows (PowerShell) install\"** subsection below. `deploy_toolkit.py check` auto-detects the platform (`os.name == \"nt\"`) and already prints the correct Windows PowerShell guidance — the manual steps here are only for when the toolkit script is unavailable.\n\n> **⚠️ Privilege requirement (Unix)**: The install commands below extract to `/usr/local/bin/`, which requires elevated privileges (`sudo` on Linux/macOS for non-root users). If running as a non-root user, prepend `sudo` to the `tar` step. Alternatively, extract to a user-writable directory in `$PATH` (e.g., `~/.local/bin`). On Windows there is no `sudo`; install into `%USERPROFILE%\\bin` (no admin rights needed) — see the Windows subsection.\n> **⚠️ Supply chain note**: The downloads come from Alibaba Cloud's official OSS bucket over HTTPS. For higher assurance, verify the binary's SHA256 checksum against the version listed at https://help.aliyun.com/document_detail/121541.html before adding to `$PATH`.\n\n> **⚠️ PATH conflict pitfall (MUST READ)**: On macOS Apple Silicon, `/opt/homebrew/bin` is ahead of `/usr/local/bin` by default. If brew already installed `aliyun-cli`, extracting a fresh build into `/usr/local/bin/` will be shadowed by the brew-installed older version. Symptom: \"the upgrade looks successful right after install, but the next shell session reverts to the old version -> repeated upgrades\". Before AND after any install/upgrade, run `which -a aliyun` to list **all** matching binaries on PATH and confirm the one resolved by `aliyun version` is the new one.\n\n```bash\n# 0. List all aliyun binaries on PATH (the first one wins). Detect any conflict.\nwhich -a aliyun\naliyun version 2>&1     # the version actually in effect right now\n\n# 1. Check aliyun CLI version\naliyun version 2>&1\n# → Not found or < 3.3.19: install below. >= 3.3.19: skip to step 2.\n\n# 2. Check appmanager-cli version (only if ~/.aliyun/appmanager-venv exists)\n~/.aliyun/appmanager-venv/bin/python -c \"from importlib.metadata import version; print(version('appmanager-cli'))\" 2>/dev/null\n# → < 1.1.1 or fails: rm -rf ~/.aliyun/appmanager-venv (auto-recreates on next run)\n\n# 3. Install aliyun CLI — choose ONE path below by priority\n#    Priority A: macOS already manages aliyun-cli via Homebrew -> upgrade with brew\n#                (avoids being shadowed by PATH ordering)\nbrew list --formula | grep -qx aliyun-cli && brew upgrade aliyun-cli\n\n#    Priority B: system-directory install (recommended; writing to /usr/local/bin needs sudo)\n#    macOS Apple Silicon:\ncurl --connect-timeout 30 --max-time 120 -fsSL https://aliyun-cli.oss-cn-hangzhou.aliyuncs.com/aliyun-cli-macosx-latest-arm64.tgz | sudo tar xz -C /usr/local/bin/\n#    macOS Intel:\ncurl --connect-timeout 30 --max-time 120 -fsSL https://aliyun-cli.oss-cn-hangzhou.aliyuncs.com/aliyun-cli-macosx-latest-amd64.tgz | sudo tar xz -C /usr/local/bin/\n#    Linux amd64:\ncurl --connect-timeout 30 --max-time 120 -fsSL https://aliyun-cli.oss-cn-hangzhou.aliyuncs.com/aliyun-cli-linux-latest-amd64.tgz | sudo tar xz -C /usr/local/bin/\n#    Linux arm64:\ncurl --connect-timeout 30 --max-time 120 -fsSL https://aliyun-cli.oss-cn-hangzhou.aliyuncs.com/aliyun-cli-linux-latest-arm64.tgz | sudo tar xz -C /usr/local/bin/\n\n#    Priority C: no-sudo fallback (only when B is not viable) — install into ~/bin and persist PATH in shell rc\nmkdir -p ~/bin\ncurl --connect-timeout 30 --max-time 120 -fsSL <platform-specific URL> | tar xz -C ~/bin/\n# ⚠️ `export PATH` only affects the current shell session; it MUST also be appended to the shell rc\n#    file, otherwise the next session reverts to the old version:\ngrep -q 'HOME/bin' ~/.zshrc 2>/dev/null || echo 'export PATH=\"$HOME/bin:$PATH\"' >> ~/.zshrc\n# bash users edit ~/.bashrc instead. Then refresh the current session immediately:\nhash -r    # zsh users: rehash\nexport PATH=\"$HOME/bin:$PATH\"\n\n# 4. Mandatory post-install/upgrade re-verification (skipping this causes the \"repeated upgrade\" loop)\nwhich -a aliyun                     # the first entry MUST be the dir you just installed into (/usr/local/bin or ~/bin)\naliyun version                       # MUST be >= 3.3.19\n# If the first entry of `which -a` is still the old version (e.g. /opt/homebrew/bin/aliyun), the PATH conflict\n# is unresolved:\n#   - if the old version is from brew, switch to Priority A: brew upgrade aliyun-cli\n#   - otherwise, manually `rm` the old binary, or fix PATH order in ~/.zshrc\n```\n\n### Windows (PowerShell) install\n\n> On native Windows there is no `curl | sudo tar` / `brew` / `.zshrc`. Use PowerShell to download the official Windows zip, extract into `%USERPROFILE%\\bin`, and persist the **User** PATH (no admin rights required). Pick amd64 or arm64 to match your CPU.\n\n```powershell\n# 1. Check current version (skip install if >= 3.3.19)\naliyun version 2>$null\n\n# 2. Download + extract the official Windows build into %USERPROFILE%\\bin\n$u    = \"https://aliyun-cli.oss-cn-hangzhou.aliyuncs.com/aliyun-cli-windows-latest-amd64.zip\"  # arm64: replace amd64 -> arm64\n$zip  = \"$env:TEMP\\aliyun-cli.zip\"\n$dest = \"$env:USERPROFILE\\bin\"\nInvoke-WebRequest -Uri $u -OutFile $zip\nNew-Item -ItemType Directory -Force -Path $dest | Out-Null\nExpand-Archive -Path $zip -DestinationPath $dest -Force\n\n# 3. Persist PATH at the User scope (survives new terminals; no admin needed)\n$userPath = [Environment]::GetEnvironmentVariable(\"PATH\",\"User\")\nif ($userPath -notlike \"*$dest*\") { [Environment]::SetEnvironmentVariable(\"PATH\", \"$dest;$userPath\", \"User\") }\n$env:PATH = \"$dest;$env:PATH\"   # take effect in the current session immediately\n\n# 4. Verify (open a NEW terminal so the persisted User PATH is picked up)\naliyun version   # MUST be >= 3.3.19\n```\n\n> **Package-manager alternative** (if Scoop or Chocolatey is installed): `scoop install aliyun-cli`  or  `choco install aliyun-cli -y`.\n>\n> **appmanager-cli venv on Windows**: the self-managed venv lives at `%USERPROFILE%\\.aliyun\\appmanager-venv`, and its interpreter is `Scripts\\python.exe` (NOT `bin/python`). To check the version:\n> ```powershell\n> & \"$env:USERPROFILE\\.aliyun\\appmanager-venv\\Scripts\\python.exe\" -c \"from importlib.metadata import version; print(version('appmanager-cli'))\"\n> ```\n> If it is `< 1.1.1` or fails, delete the folder `%USERPROFILE%\\.aliyun\\appmanager-venv` (it auto-recreates on the next `aliyun appmanager` run).\n\n---\n\n## Configure Credentials\n\n> **⛔ PREFER OAuth OVER AK**: This skill SHOULD guide users to use **OAuth authentication** as the PRIMARY method for providing Alibaba Cloud permissions. OAuth is more secure and convenient than AccessKey (no long-term secret storage needed). The Agent MUST present OAuth as the first option before mentioning AK-based methods.\n>\n> **⛔ SA-2.12 — DO NOT explicitly handle AK/SK**: This skill MUST rely on the **default credential chain** of the aliyun CLI/SDK. The Agent:\n> - **MUST NOT** ask the user to paste AccessKey ID / Secret / STS Token values into the chat\n> - **MUST NOT** put raw AK/SK/Token in tool-call arguments, command lines, scripts, or any persisted file (logs, ran_scripts, outputs)\n> - **MUST NOT** print or echo credential values, even partially, except for the masked profile diagnostic that `deploy_toolkit.py check` already produces\n> - **MUST** instead instruct the user to configure credentials **out-of-band** (in their own terminal / shell profile / RAM role / secrets vault) and only verify by an identity-check call\n>\n> The ONLY accepted Agent action is: **detect whether some credential source is already in place**, and if not, tell the user how to set one up **themselves**.\n\n> **CRITICAL PROHIBITION**: NEVER run standalone `appmanager` or `aliyun appmanager login`. Credentials must come from the default credential chain below — never from interactive Agent prompts that collect AK/SK.\n\n### Default credential chain (aliyun CLI / SDK auto-resolves in this order)\n\nThe Agent only needs ONE of the sources below to be in place:\n\n1. **OAuth** (RECOMMENDED — most secure and convenient) — the Agent **may run the login command directly**. Before executing, warn the user (verbatim): “⚠️ About to run the OAuth login command. It will open a browser authorization page. **Please complete the authorization in the browser** — otherwise the command keeps blocking and the Agent gets stuck at this step.” Then run:\n   ```bash\n   aliyun configure --mode OAuth --profile oauth\n   ```\n   This opens a browser authorization link, then prompts for region (e.g. `cn-hangzhou`) and language (e.g. `zh`). After setup, verify with:\n   ```bash\n   aliyun sts get-caller-identity --profile oauth\n   ```\n2. **ECS RAM Role** (recommended on Alibaba Cloud ECS) — instance metadata service auto-provides rotating STS credentials. The user configures it once with `aliyun configure --mode EcsRamRole --ram-role-name <role>` (`<role>` is an identifier, **not a secret**). No AK/SK ever leaves the instance.\n3. **Environment variables** — `ALIBABA_CLOUD_ACCESS_KEY_ID`, `ALIBABA_CLOUD_ACCESS_KEY_SECRET`, optionally `ALIBABA_CLOUD_SECURITY_TOKEN`. Set by the **user** in their shell profile, secrets manager, or CI vault — outside the Agent session. The Agent MUST NOT read or echo these values.\n4. **Pre-existing profile** in `~/.aliyun/config.json` — created in advance by the user with interactive `aliyun configure` (NOT by the Agent passing flags). The skill reads only the profile name and a masked AK preview for diagnostics.\n\n### Verification (the ONLY Agent action — never reads raw credential values)\n\n```bash\n# Identity check — succeeds iff some credential source in the default chain is valid.\n# Output reveals only Account / RoleArn / UserId, never AK/SK material.\naliyun sts get-caller-identity --output json >/dev/null 2>&1 \\\n  && echo \"✅ credentials valid via default credential chain\" \\\n  || echo \"❌ no usable credentials — see remediation below\"\n```\n\n`deploy_toolkit.py check` already runs an equivalent check. If it exits 1 due to missing credentials, the Agent MUST stop and execute the remediation flow below — it MUST NOT prompt the user for AK/SK in the chat.\n\n### Remediation when credentials are missing\n\nThe Agent MUST present these self-service options to the user **verbatim** and wait for the user to confirm completion in their own terminal. **Do not collect AK/SK in the chat under any circumstance.**\n\n> No usable credentials were detected. Please configure them yourself in your own terminal **using one of the methods below** (do NOT paste the AccessKey into this chat or any file):\n>\n> - **Method A · OAuth** (RECOMMENDED — most secure and convenient, no long-term secret storage). The Agent may run this directly after warning the user to authorize in the browser (otherwise the command blocks and the Agent gets stuck):\n>   `aliyun configure --mode OAuth --profile oauth`\n>   (This opens a browser authorization link, then prompts for region like `cn-hangzhou` and language like `zh`)\n> - **Method B · ECS RAM Role** (recommended on Alibaba Cloud ECS; no AK/SK):\n>   `aliyun configure --mode EcsRamRole --ram-role-name <your-role-name>`\n> - **Method C · Environment variables** (write into your `~/.zshrc` / `~/.bashrc` / CI Secret; effective after re-login):\n>   `export ALIBABA_CLOUD_ACCESS_KEY_ID=...`\n>   `export ALIBABA_CLOUD_ACCESS_KEY_SECRET=...`\n>   (For temporary credentials also set `export ALIBABA_CLOUD_SECURITY_TOKEN=...`)\n> - **Method D · AccessKey one-liner** (a single command — fill in your own AK/SK and run it **in your own terminal**; credentials only land in local `~/.aliyun/config.json`):\n>   `aliyun configure set --profile default --mode AK --access-key-id <your-access-key-id> --access-key-secret <your-access-key-secret> --region cn-hangzhou`\n>   (Replace `cn-hangzhou` with the target region. Do NOT paste real AK/SK into this chat — run the command yourself.)\n>\n> When done, reply \"ready\" and I will rerun `aliyun sts get-caller-identity` to verify. **You will never need to paste any AK/SK value into this conversation.**\n\nAfter the user confirms, the Agent re-runs the verification command above. If it still fails, ask the user to double-check the configuration — do not offer to \"help\" by accepting AK/SK in chat.\n\n### API Key for Agent type (separate from cloud control-plane credentials)\n\n`$ALIYUN_DASHSCOPE_API_KEY` (matches `sk-*`) is required for the AgentScope runtime — it's a model-service key, **not** a cloud AK/SK, but the handling rule is identical:\n\n- The Agent verifies presence with `[ -n \"$ALIYUN_DASHSCOPE_API_KEY\" ] && echo \"set\" || echo \"missing\"` (never echoes the value).\n- If missing, instruct the user to obtain one at https://bailian.console.aliyun.com/cn-beijing?tab=model#/api-key and persist it in their own shell profile.\n- The skill never asks the user to paste the key value into the chat.\n\n### Fixing credential errors\n\n`InvalidSecurityToken.Expired` / `InvalidAccessKeyId` → instruct the user to refresh credentials via the same out-of-band methods (A / B / C). Re-verify with `aliyun sts get-caller-identity`. Never accept new AK/SK in the chat.\n\n---\n\n## Non-interactive Init Examples\n\n**For App type (new ECS — default):**\n```\naliyun appmanager init --non-interactive \\\n  --name my-app \\\n  --type app \\\n  --region cn-beijing \\\n  --port 8080\n```\n\n**For App type (existing ECS — user provided instance ID):**\n```\naliyun appmanager init --non-interactive \\\n  --name my-app \\\n  --type app \\\n  --ecs existing \\\n  --instance-id i-bp1xxxxxxxx \\\n  --region cn-beijing \\\n  --port 8080\n```\n\n**For Agent type (new ECS):**\n```\naliyun appmanager init --non-interactive \\\n  --name my-agent \\\n  --type agent \\\n  --region cn-beijing \\\n  --model qwen3.6-plus \\\n  --api-key sk-xxxxxxxx\n```\n\n**For Agent type (existing ECS):**\n```\naliyun appmanager init --non-interactive \\\n  --name my-agent \\\n  --type agent \\\n  --ecs existing \\\n  --instance-id i-bp1xxxxxxxx \\\n  --region cn-beijing \\\n  --model qwen3.6-plus \\\n  --api-key sk-xxxxxxxx\n```\n\n> **Note**: `--port` is optional for App type — omit it for background services that don't listen on HTTP. App type does NOT need `--api-key`. Agent type REQUIRES `--api-key` for the AI model runtime. Agent type does NOT use `--port`. `--ecs existing --instance-id` is only needed when user chooses to deploy to an existing ECS instance.\n\n### Listing existing ECS instances before `--ecs existing`\n\nWhen the user chooses existing ECS, query the account's 10 most-recently-created instances **in the chosen region** and present them for selection (also support manual instance ID entry):\n\n```bash\n# aliyun CLI outputs JSON by default for OpenAPI calls — do NOT add `--output json`\n# Plugin mode: lowercase-hyphenated command + kebab-case params.\n# ⚠️ Region param is --biz-region-id; ALSO pass --region <REGION> to override the\n#    endpoint (otherwise the profile's default region endpoint rejects the call\n#    with InvalidOperation.NotSupportedEndpoint).\n# ⚠️ Use --profile <DEPLOY_PROFILE> (same account as deployment); if omitted, the CLI\n#    falls back to its default profile, which may point to a different account.\naliyun ecs describe-instances --biz-region-id <REGION> --region <REGION> --page-size 100 --profile <DEPLOY_PROFILE> \\\n  | jq -r '.Instances.Instance | sort_by(.CreationTime) | reverse | .[:10] | .[]\n      | \"\\(.InstanceId)\\t\\(.InstanceName)\\t\\(.Status)\\t\\(.CreationTime)\\t\\(.PublicIpAddress.IpAddress[0] // \"-\")\"'\n```\n\n- Present as a numbered list (InstanceId / Name / Status / CreationTime / PublicIP); user picks by number OR types an instance ID manually.\n- **⚠️ Profile must match deployment**: use the same `--profile` (same account) as the deploy step; otherwise the CLI falls back to its default profile, which may point to a different account/site and return zero / wrong instances. `aliyun configure list` shows the available profiles.\n- `jq` unavailable → fall back to `aliyun ecs describe-instances --biz-region-id <REGION> --region <REGION> --page-size 10 --profile <DEPLOY_PROFILE> --output cols=InstanceId,InstanceName,Status,CreationTime 'rows=Instances.Instance[]'` (quote `rows=...[]` so the shell does not glob the `[]`; ordering not guaranteed).\n- **⚠️ Plugin prerequisite**: `ecs describe-instances` requires the `aliyun-cli-ecs` plugin. If the CLI prompts \"Plugin ... not installed\", enable auto-install ONCE: `aliyun configure set --auto-plugin-install true` (or `aliyun plugin install --name ecs`). Without this, non-interactive scripts hang on the prompt.\n- Zero instances in region → tell the user, then ask for a manual ID or switch to New ECS.\n- Pass the chosen ID to `aliyun appmanager init ... --ecs existing --instance-id <ID>`.\n\n### JSON mode (full config passthrough)\n\n```\naliyun appmanager init --from-json '{\n  \"metadata\": {\"name\": \"my-app\", \"type\": \"agent\", \"regionId\": \"cn-beijing\"},\n  \"agent\": {\"model\": {\"name\": \"qwen3.6-plus\", \"apiKey\": \"sk-xxx\"}}\n}' --output json\n```\n\n### Output\n\nCreates `.appmanager/config.yaml` in the current directory with deployment configuration.\n\n> **WARNING**: `aliyun appmanager init` does NOT support `--overwrite` flag. If config already exists, delete `.appmanager/` directory first or edit the YAML directly.\n\nFile v1.0.3:references/lessons-learned.md\n\n# Lessons Learned — Deployment Failure Patterns & Fixes\n\n> This document is auto-populated by the batch deployment test (see `tests/batch-deploy-100.md`).\n> When an Agent encounters a deployment issue, it SHOULD consult this file first for known\n> patterns and proven fixes before attempting ad-hoc troubleshooting.\n\n## How to Use This File\n\n1. **Before deploying**: Skim the error signatures below. If the project matches a known\n   trigger scenario, apply the fix proactively.\n2. **After a failure**: Search this file for the error message or signature. If found,\n   apply the documented fix and retry.\n3. **Contributing new lessons**: When a new failure pattern is observed >= 2 times across\n   different projects, add a new entry following the format below.\n\n## Entry Format\n\nEach lesson follows this structure:\n\n```markdown\n### <Error Signature>\n\n- **Phase**: check / init / deploy / verify\n- **Trigger Scenario**: <what type of project or condition triggers this>\n- **Symptom**: <exact error message or observable behavior>\n- **Root Cause**: <why it happens>\n- **Fix**: <what the Agent should do — specific commands or decision changes>\n- **Affected Projects**: <list of test project numbers/names that hit this>\n- **First Observed**: <date or test round>\n```\n\n---\n\n## Lessons\n\n(The following entries are auto-appended by the Agent during batch deployment testing.\nDo not manually edit below this line unless correcting an inaccuracy.)\n\n---\n\n### `Java-Build-Use-Release-JAR`\n\n- **Phase**: deploy / verify\n- **Trigger Scenario**: Spring Boot or any Java/Gradle/Maven project on 2C4G ECS where `appmanager init` generated a default start script and the project requires `mvn package` / `gradle bootJar` to produce a runnable JAR.\n- **Symptom**:\n  - Round 1: `Error: Unable to access jarfile *.jar` (default `java -jar *.jar` finds no JAR in the cloned source tree).\n  - Round 2 (if Agent retries with `gradle bootJar`): `ReleaseFailed` or `ReleaseCancelled` after the 15-minute deploy budget elapses; `gradle clean bootJar` typically OOM's or runs >15 min on 2 vCPU + 4 GiB RAM.\n- **Root Cause**: 2C4G is too small to build large Java projects in the deploy window.\n- **Fix**: Skip source build. Replace `common.scripts.start` with the pattern below. NOTE: `<app>.jar` and `<version>` are placeholders — substitute the target project's own release artifact name and version (validated concrete example: halo project, `<app>` = `halo`, `<version>` = `2.20.12`):\n  ```yaml\n  common:\n    scripts:\n      start: |\n        : > /root/app.log\n        mkdir -p /root && cd /root\n        if [ ! -f <app>.jar ]; then\n          curl -fSL \"https://github.com/<owner>/<repo>/releases/download/v<version>/<app>-<version>.jar\" -o /root/<app>.jar\n        fi\n        pkill -f '<app>.jar' || true\n        nohup java -Xmx384m -jar /root/<app>.jar --server.port=8090 >> /root/app.log 2>&1 &\n  ```\n  Always set `-Xmx` ≤ 384 m (heap > 50 % of 4 GiB triggers OOM-killer when paired with the JVM's other memory regions).\n- **Affected Projects**: #1 halo (validated Round 3 SUCCESS); also recommended for #81 spring-petclinic, #85 stirling-pdf.\n- **First Observed**: Batch Round 1 (#1 halo Round 1).\n\n---\n\nFile v1.0.3:references/ram-policies.md\n\n# RAM Policies Reference\n\n## Required RAM Permissions\n\nThe `alibabacloud-ecs-code-deploy` skill requires the following Alibaba Cloud RAM permissions for the configured AccessKey (AK/SK) or STS Token.\n\n> **⚠️ Least-privilege principle**: This skill's RAM permission strategy follows the\n> \"minimum permissions necessary\" rule. The **recommended primary policy** is the custom\n> least-privilege policy below. `FullAccess` system policies are listed only as a\n> convenience fallback for development/testing — production deployments MUST use the\n> custom policy.\n\n### Recommended (PRIMARY): Custom Least-Privilege Policy\n\nThis policy enumerates only the specific Actions the skill actually invokes (verified\nagainst `deploy_toolkit.py` and `aliyun appmanager` source). No wildcard `*` is used.\n\n```json\n{\n  \"Version\": \"1\",\n  \"Statement\": [\n    {\n      \"Sid\": \"ECSInstanceLifecycle\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ecs:CreateInstance\",\n        \"ecs:RunInstances\",\n        \"ecs:StartInstance\",\n        \"ecs:StopInstance\",\n        \"ecs:DeleteInstance\",\n        \"ecs:DescribeInstances\",\n        \"ecs:DescribeInstanceStatus\",\n        \"ecs:ModifyInstanceAttribute\",\n        \"ecs:AllocatePublicIpAddress\",\n        \"ecs:DescribeRegions\",\n        \"ecs:DescribeZones\",\n        \"ecs:DescribeAvailableResource\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Sid\": \"ECSCloudAssistant\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ecs:RunCommand\",\n        \"ecs:InvokeCommand\",\n        \"ecs:DescribeInvocations\",\n        \"ecs:DescribeInvocationResults\",\n        \"ecs:DescribeCloudAssistantStatus\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Sid\": \"ECSSecurityAndStorage\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ecs:CreateSecurityGroup\",\n        \"ecs:DescribeSecurityGroups\",\n        \"ecs:DescribeSecurityGroupAttribute\",\n        \"ecs:AuthorizeSecurityGroup\",\n        \"ecs:JoinSecurityGroup\",\n        \"ecs:CreateDisk\",\n        \"ecs:DescribeDisks\",\n        \"ecs:AttachDisk\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Sid\": \"OSSArtifactUpload\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"oss:PutObject\",\n        \"oss:GetObject\",\n        \"oss:ListObjects\",\n        \"oss:ListBuckets\",\n        \"oss:CreateBucket\",\n        \"oss:GetBucketInfo\",\n        \"oss:GetBucketLocation\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Sid\": \"VPCNetwork\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"vpc:CreateVpc\",\n        \"vpc:CreateVSwitch\",\n        \"vpc:DescribeVpcs\",\n        \"vpc:DescribeVSwitches\",\n        \"vpc:DescribeVpcAttribute\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Sid\": \"ComputeNestServiceInstance\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"computenest:CreateServiceInstance\",\n        \"computenest:DeleteServiceInstance\",\n        \"computenest:GetServiceInstance\",\n        \"computenest:ListServiceInstances\",\n        \"computenest:UpdateServiceInstance\",\n        \"computenest:ContinueDeployServiceInstance\",\n        \"computenest:GetServiceTemplateParameterConstraints\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}\n```\n\n> **Note on omitted Actions**:\n> - `oss:DeleteObject` is **not included** — the skill only uploads deploy artifacts; cleanup is performed by `aliyun appmanager <type> delete`, which goes through `computenest:DeleteServiceInstance` rather than direct OSS DELETE.\n> - No wildcard Action (e.g. `ecs:*`, `oss:*`, `computenest:*`) is used.\n\n### Fallback (DEV / TESTING ONLY): System FullAccess Policies\n\n> **⛔ NOT RECOMMENDED FOR PRODUCTION**: These policies grant broad permissions that\n> exceed what the skill actually needs and violate the least-privilege principle. Use\n> them ONLY for quick local prototyping, then switch to the custom policy above before\n> any non-throwaway use.\n\n| Policy Name | Type | Purpose (subset actually used by this skill) |\n|-------------|------|----------------------------------------------|\n| `AliyunECSFullAccess` | System | ECS instance / SG / disk lifecycle + Cloud Assistant |\n| `AliyunOSSFullAccess` | System | Upload deployment artifacts |\n| `AliyunVPCFullAccess` | System | Create VPC / vSwitch for new ECS |\n| `AliyunCloudAssistantFullAccess` | System | Run shell commands on ECS via Cloud Assistant |\n\n### Permission Verification\n\nThe `deploy_toolkit.py check` script verifies credential validity by calling `aliyun appmanager app status`. If this call returns `Forbidden` or `NoPermission`, the user's RAM role/policy is insufficient.\n\n**Common permission errors and resolutions:**\n\n| Error Code | Cause | Fix |\n|-----------|-------|-----|\n| `Forbidden.RAM` | Missing RAM policy | Attach the custom policy above (or required policies) |\n| `NoPermission` | Action not allowed | Verify the failing Action is enumerated in the custom policy |\n| `InvalidAccessKeyId.NotFound` | AK does not exist | Regenerate AK in RAM console |\n| `SignatureDoesNotMatch` | Secret key mismatch | Re-configure with correct SK |\n\n### Credential Types Supported\n\n| Type | Config Method | Use Case |\n|------|--------------|----------|\n| AK (long-term) | `aliyun configure --mode AK` (interactive) | Development/testing |\n| STS Token (temporary) | `aliyun configure --mode StsToken` (interactive) | Production (recommended) |\n| ECS RAM Role | `aliyun configure --mode EcsRamRole --ram-role-name <role>` | Running on ECS itself |\n\nFile v1.0.3:references/script-templates.md\n\n# Script Templates & Language Reference\n\n## Project Analysis: Language Detection, Files to Read & Entry Points\n\n### Language Detection Rules\n\n| Indicator Files | Language |\n|-----------------|----------|\n| `package.json` / `*.js` / `*.ts` | Node.js |\n| `requirements.txt` / `pyproject.toml` / `*.py` | Python |\n| `pom.xml` / `build.gradle` / `*.java` | Java |\n| `go.mod` / `*.go` | Go |\n| `composer.json` / `*.php` | PHP |\n| `docker-compose.yml` / `Dockerfile` | Docker |\n\n### Files to Read (MUST read content, not just detect presence)\n\n| Language | Must Read | Why |\n|----------|-----------|-----|\n| Python | `pyproject.toml`, `requirements.txt` | Entry point, deps |\n| Node.js | `package.json` | `scripts.start`, `main` field |\n| Java | `pom.xml` or `build.gradle` | JAR name |\n| Go | `go.mod` | Module → binary name |\n| PHP | `composer.json` | Framework detection |\n| Docker | `docker-compose.yml` / `Dockerfile` | Services, ports |\n\n### Entry Point Detection Order\n\n- **Python**: `[project.scripts]` in pyproject.toml → `main.py` → `app.py` → `manage.py`\n- **Node.js**: `scripts.start` → `main` field → `index.js` → `server.js`\n- **Java**: `find ... -name \"*.jar\" | head -1` → `java -jar`\n- **Go**: Pre-compiled binary: `find ... -type f -perm /111`\n- **PHP**: `composer install --no-dev` → `php artisan serve` or `php -S`\n- **Docker Compose**: `docker compose up -d` / `docker compose down`\n\n---\n\n## Start Script Template (Generic)\n\n> Replace `{app_name}` with the actual `--name` value used in `init`. Replace `{INSTALL_RUNTIME}`, `{INSTALL_DEPS}`, `{START_CMD}` with language-specific commands from the Language Reference Table below.\n\n```bash\n#!/bin/bash\nset -e\nAPP_DIR=/root/{app_name}\nZIP_FILE=$(ls /root/project_*.zip 2>/dev/null | tail -1)\nLOG_FILE=/root/app.log\nPID_FILE=/root/app.pid\n\n# Stop existing process\n[ -f \"$PID_FILE\" ] && kill \"$(cat $PID_FILE)\" 2>/dev/null || true\nrm -f \"$PID_FILE\"\n\n# Detect package manager\nif command -v dnf &>/dev/null; then\n  PKG_MGR=\"dnf\"\nelif command -v yum &>/dev/null; then\n  PKG_MGR=\"yum\"\nelif command -v apt-get &>/dev/null; then\n  PKG_MGR=\"apt-get\"\nelse\n  echo \"ERROR: No supported package manager found\" && exit 1\nfi\n\n# Install unzip if missing\nif ! command -v unzip &>/dev/null; then\n  $PKG_MGR install -y unzip\nfi\n\n# {INSTALL_RUNTIME} — see Language Reference Table below\n\n# Decompress (MANDATORY — appmanager uploads zip but does NOT extract)\nmkdir -p \"$APP_DIR\"\n[ -n \"$ZIP_FILE\" ] && unzip -o \"$ZIP_FILE\" -d \"$APP_DIR\"\n\ncd \"$APP_DIR\"\n\n# {INSTALL_DEPS} — see Language Reference Table below\n\n# Start\nnohup {START_CMD} >> \"$LOG_FILE\" 2>&1 &\necho $! > \"$PID_FILE\"\n\n# MANDATORY: output log for verification\nsleep 3 && cat /root/app.log\n```\n\n## Language Reference Table\n\n> **⚠️ Supply chain security**: Some rows below use `curl ... | bash` or `curl ... | php` patterns to install runtimes. These are convenience patterns from upstream vendors (NodeSource, Composer, Go) — they execute remote code without local verification and are vulnerable to MITM/supply-chain attacks if the source is compromised. Mitigations applied below:\n> - **NodeSource (Node.js)**: HTTPS-only, official `nodesource.com` domain. For high-security environments, prefer the distro package: `dnf module install -y nodejs:22` (RHEL 9) / `apt-get install -y nodejs npm`.\n> - **Go**: SHA256 checksum verification added before extraction. Reject if mismatch.\n> - **Composer**: SHA-384 installer signature verification added (per upstream guidance at https://getcomposer.org/download/). Reject and abort if signature mismatch.\n> - **All `/usr/local` writes**: Run as root inside ECS deploy context (start script executes as root via Cloud Assistant). Outside ECS, prepend `sudo`.\n\n| Language | Check | Install Runtime (RHEL/yum) | Install Runtime (Debian/apt) | Install Deps | Start Command |\n|----------|-------|---------------------------|------------------------------|--------------|---------------|\n| **Python** | `command -v pip3` | `$PKG_MGR install -y python3 python3-pip` | `apt-get update -qq && apt-get install -y -qq python3 python3-pip python3-venv` | `pip3 install -r requirements.txt -q` or `pip3 install -e . -q` | `python3 main.py` |\n| **Node.js** | `command -v node` | `curl --connect-timeout 30 --max-time 120 -fsSL https://rpm.nodesource.com/setup_22.x \\| bash - && $PKG_MGR install -y nodejs` (HTTPS official NodeSource; prefer distro package for stricter envs) | `curl --connect-timeout 30 --max-time 120 -fsSL https://deb.nodesource.com/setup_22.x \\| bash - && apt-get install -y -qq nodejs` | `npm install --production` or `pnpm install --frozen-lockfile && pnpm build` | `node dist/index.js` or `npm start` |\n| **Java** | `command -v java` | `$PKG_MGR install -y java-17-openjdk` | `apt-get update -qq && apt-get install -y -qq default-jdk` | N/A (pre-built JAR) | `java -jar $(find $APP_DIR -name \"*.jar\" \\| head -1)` |\n| **Go** | `command -v go` | See **Go install snippet** below (with SHA256 verification) | (same) | `go build -o app .` (if source) or N/A (pre-compiled) | `./app` or `$(find $APP_DIR -type f -perm /111 -not -name \"*.sh\" \\| head -1)` |\n| **PHP** | `command -v php` | `$PKG_MGR install -y php php-cli php-mbstring php-xml` + see **Composer install snippet** below (with signature verification) | `apt-get update -qq && apt-get install -y -qq php php-cli php-mbstring php-xml composer` | `composer install --no-dev --optimize-autoloader` | `php artisan serve --host=0.0.0.0 --port=8080` |\n| **Docker** | (pre-installed on ECS) | N/A | N/A | N/A | `docker compose up -d` (no PID/nohup needed) |\n\n> **Pattern**: Wrap runtime install in `if ! {Check} &>/dev/null; then ... fi` for idempotency. For Go on China ECS, MUST use `golang.google.cn` mirror and set `GOPROXY=https://goproxy.cn,direct`.\n\n### Go install snippet (with SHA256 verification)\n\n```bash\nGO_VERSION=1.22.0\nGO_TGZ=go${GO_VERSION}.linux-amd64.tar.gz\n# SHA256 from https://go.dev/dl/  (update when bumping GO_VERSION)\nGO_SHA256=f6c8a87aa03b92c4b0bf3d558e28ea03006eb29db78917daec5cfb6ec1046265\ncurl --connect-timeout 30 --max-time 120 -fsSLO https://golang.google.cn/dl/${GO_TGZ}\necho \"${GO_SHA256}  ${GO_TGZ}\" | sha256sum -c - || { echo \"Go checksum mismatch — refusing to install\" >&2; exit 1; }\ntar -C /usr/local -xzf ${GO_TGZ} && rm -f ${GO_TGZ}\nexport PATH=$PATH:/usr/local/go/bin\nexport GOPROXY=https://goproxy.cn,direct\n```\n\n### Composer install snippet (with signature verification)\n\nFollows official guidance at <https://getcomposer.org/download/>:\n\n```bash\nEXPECTED_CHECKSUM=$(curl --connect-timeout 30 --max-time 60 -fsS https://composer.github.io/installer.sig)\ncurl --connect-timeout 30 --max-time 60 -fsSO https://getcomposer.org/installer\nACTUAL_CHECKSUM=$(php -r \"echo hash_file('sha384', 'installer');\")\nif [ \"$EXPECTED_CHECKSUM\" != \"$ACTUAL_CHECKSUM\" ]; then\n    echo \"Composer installer signature mismatch — aborting\" >&2\n    rm -f installer\n    exit 1\nfi\nphp installer --install-dir=/usr/local/bin --filename=composer\nrm -f installer\n```\n\n## Stop Script Template\n\n> **CRITICAL**: Stop script MUST NOT contain `exit 0` or any `exit` statement. The deploy system concatenates stop+start into a single shell execution. If stop script has `exit`, the start script will NEVER run and deployment will produce zero logs.\n\n> **Safety notes**:\n> - **Graceful-then-force termination**: The script first sends `SIGTERM` (`kill \"$PID\"`) and waits 3 seconds for the process to flush state and exit cleanly. `kill -9` (SIGKILL) is only used as a fallback when graceful termination fails. Do NOT remove the 3-second grace window — long-running processes may need time to flush data.\n> - **Destructive cleanup guard**: `rm -rf \"$APP_DIR\"` is dangerous if `$APP_DIR` is empty or set to a wrong path (e.g. `/`). The template includes hard guards: `[ -n \"$APP_DIR\" ]`, `$APP_DIR` length check, and a strict prefix check (`/root/<app_name>`). Do NOT loosen these.\n\n```bash\n#!/bin/bash\nPID_FILE=/root/app.pid\nAPP_DIR=/root/{app_name}\n\nif [ -f \"$PID_FILE\" ]; then\n    PID=$(cat \"$PID_FILE\")\n    if kill -0 \"$PID\" 2>/dev/null; then\n        # Graceful shutdown first — give the process 3s to flush state\n        kill \"$PID\"\n        sleep 3\n        # Fallback: force-kill ONLY if still alive after grace period\n        kill -0 \"$PID\" 2>/dev/null && kill -9 \"$PID\"\n    fi\n    rm -f \"$PID_FILE\"\nfi\n\n# Clean up project directory for re-deploy.\n# Hard guards prevent catastrophic deletion if APP_DIR is empty or misconfigured.\nif [ -n \"$APP_DIR\" ] && [ \"${#APP_DIR}\" -gt 6 ] && [[ \"$APP_DIR\" == /root/* ]] && [ -d \"$APP_DIR\" ]; then\n    rm -rf \"$APP_DIR\"\nfi\n# DO NOT add \"exit 0\" here — it will kill the entire deployment process\n```\n\n## Writing Scripts to config.yaml\n\nAfter generating scripts, the Agent MUST write them into `.appmanager/config.yaml` under `common.scripts`:\n\n> **CRITICAL**: The deploy system ONLY reads `common.scripts.start` and `common.scripts.stop`.\n> A top-level `scripts:` key is IGNORED. If scripts are placed at the wrong level, deployment will use the auto-generated default scripts (which will fail).\n\n**Recommended method — use Python yaml library** (avoids YAML formatting issues):\n\n```python\nimport yaml\nconfig_path = '.appmanager/config.yaml'\nwith open(config_path, 'r') as f:\n    config = yaml.safe_load(f)\n\nconfig['common']['scripts'] = {\n    'start': '#!/bin/bash\\nset -e\\n...',\n    'stop': '#!/bin/bash\\n...'\n}\n\nwith open(config_path, 'w') as f:\n    yaml.dump(config, f, default_flow_style=False, allow_unicode=True)\n```\n\n**Resulting YAML structure (correct)**:\n\n```yaml\ncommon:\n  deployment:\n    ecsInstanceType: ecs.u1-c1m2.large\n    ...\n  scripts:\n    start: |\n      #!/bin/bash\n      set -e\n      APP_DIR=/root/my-app\n      ...\n    stop: |\n      #!/bin/bash\n      PID_FILE=/root/app.pid\n      ...\n```\n\n**WRONG structure (deploy system IGNORES this)**:\n\n```yaml\ncommon:\n  deployment: ...\nscripts:    # ← WRONG! Top-level key, NOT read by deploy system\n  start: ...\n  stop: ...\n```\n\n## Docker Image Accessibility Check (MANDATORY for Docker projects)\n\nWhen a project contains `docker-compose.yml` or `Dockerfile`, the Agent MUST check whether the required Docker images are accessible from China ECS with mirror acceleration before choosing the Docker deployment path.\n\n**Step 1: Identify required images**\n\nScan `Dockerfile` for `FROM` directives and `docker-compose.yml` for `image:` fields. Extract all image references (e.g., `node:24-bookworm`, `oven/bun:1.3.13`, `python:3.12-slim`).\n\n**Step 2: Assess China accessibility**\n\n| Image Source | Accessible via China Mirrors? | Action |\n|-------------|-------------------------------|--------|\n| Official Docker Hub images (`library/*` like `node`, `python`, `nginx`, `redis`, `postgres`) | YES — available on Aliyun/Tencent mirrors | Use Docker with mirror config |\n| Popular third-party images (`mysql`, `mongo`, `elasticsearch`) | LIKELY YES | Use Docker with mirror config |\n| Niche/uncommon images (`oven/bun`, custom registries, `ghcr.io/*`, `quay.io/*`) | NO — China mirrors don't mirror these | **Fallback to native build** |\n| Images pinned by SHA256 digest (`image@sha256:abc...`) | RISKY — mirrors may not resolve digests | **Fallback to native build** |\n\n**Step 3: Decision**\n\n- If ALL images are accessible → Use Docker Compose / Dockerfile deployment with China mirror configuration.\n- If ANY image is NOT accessible → **Fallback to native build** (install runtime, build from source, run directly).\n\n**Docker mirror configuration (MUST include in start script when using Docker):**\n\n> **⚠️ System config modification**: This step writes to `/etc/docker/daemon.json` (system-level, requires root). The snippet below performs a **safe merge** that preserves any existing keys (e.g. `data-root`, `log-driver`) and creates a timestamped backup before any change. Do NOT use a naive `printf > daemon.json` that would clobber existing config.\n\n```bash\n# Configure China Docker registry mirrors (safe merge, preserves existing config)\nmkdir -p /etc/docker\nDAEMON_JSON=/etc/docker/daemon.json\nMIRRORS='[\"https://registry.cn-hangzhou.aliyuncs.com\", \"https://mirror.ccs.tencentyun.com\"]'\n\nif [ -f \"$DAEMON_JSON\" ]; then\n    # Backup existing config with timestamp\n    cp -p \"$DAEMON_JSON\" \"${DAEMON_JSON}.bak.$(date +%Y%m%d%H%M%S)\"\n    # Merge: only add registry-mirrors if missing or empty\n    python3 -c \"\nimport json, sys\np = '$DAEMON_JSON'\ntry:\n    with open(p) as f: cfg = json.load(f)\nexcept Exception:\n    cfg = {}\nmirrors = json.loads('$MIRRORS')\nexisting = cfg.get('registry-mirrors') or []\n# Union without duplicates, preserve order\nfor m in mirrors:\n    if m not in existing:\n        existing.append(m)\ncfg['registry-mirrors'] = existing\nwith open(p, 'w') as f: json.dump(cfg, f, indent=2)\n\"\nelse\n    printf '{\"registry-mirrors\": %s}\\n' \"$MIRRORS\" > \"$DAEMON_JSON\"\nfi\n\n# Reload Docker only if config actually changed\nsystemctl restart docker\nsleep 3\n```\n\n> **IMPORTANT**: Even with mirrors configured, SHA256-pinned images and niche registries (oven/bun, ghcr.io) will FAIL. Always fallback to native build in those cases.\n\nFile v1.0.3:references/skill-dir-resolution.md\n\n# Step 0: Resolve `$SKILL_DIR` — Cross-Platform Path\n\n> **Why**: This skill ships a Python toolkit at `<skill-root>/scripts/deploy_toolkit.py`. Different agent platforms install skills to different locations:\n> - **Qoder**: `~/.qoder/skills/alibabacloud-ecs-code-deploy/` (or alias `~/.qoder/skills/deploy-to-ecs/`)\n> - **Claude Code**: `~/.claude/skills/<name>/` (user-scope) or `<project>/.claude/skills/<name>/` (project-scope)\n> - **Qwen**: `~/.qwen/skills/<name>/` or `<project>/.qwen/skills/<name>/`\n> - **Other / custom**: anywhere reachable via `$SKILLS_HOME` or explicit env var\n>\n> The Agent MUST resolve the absolute skill root **once** at session start and reuse it everywhere `$SKILL_DIR` appears in `SKILL.md`. **Hardcoding `~/.qoder/...` or any platform-specific path is FORBIDDEN.**\n\n## Resolution algorithm — use the FIRST path that exists\n\nThe Agent MUST check these candidates in order and pick the first one whose `scripts/deploy_toolkit.py` exists:\n\n1. **The directory the Agent loaded THIS `SKILL.md` from** (PRIMARY — Agent runtime metadata; most accurate, platform-independent)\n2. `$ALIBABACLOUD_ECS_CODE_DEPLOY_SKILL_DIR` (explicit override env var)\n3. `$SKILLS_HOME/alibabacloud-ecs-code-deploy` (generic skills home env var)\n4. `~/.qoder/skills/alibabacloud-ecs-code-deploy` (Qoder default)\n5. `~/.qoder/skills/deploy-to-ecs` (Qoder alias)\n6. `~/.claude/skills/alibabacloud-ecs-code-deploy` (Claude Code user-scope)\n7. `./.claude/skills/alibabacloud-ecs-code-deploy` (Claude Code project-scope, relative to CWD)\n8. `~/.qwen/skills/alibabacloud-ecs-code-deploy` (Qwen user-scope)\n9. `./.qwen/skills/alibabacloud-ecs-code-deploy` (Qwen project-scope, relative to CWD)\n10. `~/.config/skills/alibabacloud-ecs-code-deploy` (XDG-style fallback)\n\n## Export and verify (run ONCE at session start, before Step 1)\n\n```bash\n# Replace <ABSOLUTE_PATH> with the path resolved above (NEVER guess — verify it exists first)\nexport SKILL_DIR=\"<ABSOLUTE_PATH>\"\n\n# Sanity check — script file must exist\ntest -f \"$SKILL_DIR/scripts/deploy_toolkit.py\" || {\n  echo \"❌ Toolkit script not found at: $SKILL_DIR/scripts/deploy_toolkit.py\"\n  echo \"   Agent: ask the user where the skill is installed, OR fall back to manual CLI commands.\"\n  exit 1\n}\necho \"✅ SKILL_DIR=$SKILL_DIR\"\n```\n\n## Usage convention\n\nAll `SKILL.md` commands write `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" <subcmd>`. The Agent must turn that template into a real, working command **using ONE of the two patterns below**. A third pattern that LOOKS correct but silently breaks is documented as a forbidden anti-pattern.\n\n### ✅ Pattern A — persistent shell (recommended when the platform reuses one shell)\n\n```bash\n# Run ONCE at session start (e.g. after Step 0 verification)\nexport SKILL_DIR=\"/absolute/path/to/skill\"\n\n# Then every later command can reference $SKILL_DIR normally\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check\n```\n\n### ✅ Pattern B — fresh shell per tool call (recommended when each command is a NEW shell)\n\nInline the absolute path directly. **Do NOT use `$SKILL_DIR` in this case.**\n\n```bash\npython3 \"/home/user/.qwen/skills/alibabacloud-ecs-code-deploy/scripts/deploy_toolkit.py\" check\n```\n\nIf you really want a variable for readability, set + use it inside ONE shell invocation:\n\n```bash\nbash -c 'SKILL_DIR=\"/home/user/.qwen/skills/alibabacloud-ecs-code-deploy\"; python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check'\n```\n\n### ⛔ Anti-pattern — DO NOT USE (silently fails)\n\n```bash\n# THIS DOES NOT WORK. $SKILL_DIR is expanded by the OUTER shell BEFORE the\n# command-prefix assignment takes effect, so it expands to the empty string and\n# python3 ends up trying to open \"/scripts/deploy_toolkit.py\" → ENOENT.\nSKILL_DIR=\"/home/user/.qwen/skills/alibabacloud-ecs-code-deploy\" \\\n  python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check\n```\n\nWhy it fails: in POSIX shells, command-prefix variable assignments (`VAR=value command ...`) only populate the child process's environment. Quoted `\"$VAR\"` on the same line is expanded by the parent shell **before** the assignment is applied — at which point `$VAR` is still unset/empty. The error you'll see looks like:\n\n```\npython3: can't open file '/scripts/deploy_toolkit.py': [Errno 2] No such file or directory\n```\n\nIf you ever see that exact error, the cause is this anti-pattern — switch to Pattern A or B.\n\n## Fallback\n\nIf none of the candidates above contain `scripts/deploy_toolkit.py`, the Agent MUST stop and either ask the user where the skill is installed, or follow the manual CLI flow documented in `SKILL.md` Task 1/Task 2. Do NOT silently re-implement the toolkit logic with raw commands.\n\nFile v1.0.3:references/tutorial-flask-app.md\n\n# Step-by-Step Tutorial: Deploy a Python Flask App\n\n> A concrete walk-through that satisfies SHOULD 1.2.4. The example shows the inputs the Agent should send and the expected outputs at each step. Use this together with the workflow rules in [SKILL.md](../SKILL.md).\n\n## Prerequisites\n\n- Local project at `~/projects/my-flask-app/` containing `app.py` and `requirements.txt`.\n- Alibaba Cloud account with the default credential chain configured (RAM Role / env vars / `~/.aliyun/config.json`).\n- `python3` available; the `aliyun` CLI may or may not be installed (Step 2 takes care of it).\n\n## Step 1: Enter the project directory\n\nInput:\n```bash\ncd ~/projects/my-flask-app && ls\n```\n\nExpected output:\n```\nDockerfile  README.md  app.py  requirements.txt\n```\n\n## Step 2: Resolve `$SKILL_DIR` and run environment check\n\nInput:\n```bash\nexport SKILL_DIR=\"$HOME/.qoder/skills/alibabacloud-ecs-code-deploy\"\ntest -f \"$SKILL_DIR/scripts/deploy_toolkit.py\" && echo OK\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check\n```\n\nExpected output (success path):\n```\nOK\n=== Environment Check ===\n✅ aliyun CLI: 3.3.19 (>=3.3.19) [active: /usr/local/bin/aliyun]\n✅ appmanager-cli: 1.1.1 (>=1.1.1)\n✅ credentials: profile=default region=cn-beijing ak=LTAI***abcd\n=== Environment Check Done ===\n\n✅ All checks passed. Ready to deploy.\n```\n\nIf any check exits 1, follow the script's `→ AGENT: DO NOT stop. ASK user ...` hint verbatim before proceeding.\n\n## Step 3: Initialize `.appmanager/config.yaml`\n\nAsk the user for region + ECS target (see Task 3 in SKILL.md), then run:\n```bash\naliyun appmanager init --non-interactive \\\n  --name my-flask-app \\\n  --type app \\\n  --region cn-beijing \\\n  --port 8080\n```\n\nExpected: `.appmanager/config.yaml` is created. Edit it to add `common.scripts.start` / `common.scripts.stop`. Key fragment:\n```yaml\nmetadata:\n  name: my-flask-app\n  type: app\n  groupName: default-cn-beijing\n  regionId: cn-beijing\ncommon:\n  deployment:\n    ecsInstanceType: ecs.u1-c1m2.large\n    systemDiskSize: 40\n    internetMaxBandwidthOut: 5\n  scripts:\n    start: |\n      #!/bin/bash\n      set -e\n      command -v unzip >/dev/null || yum install -y unzip\n      ZIP=$(find /root -maxdepth 2 -name 'my-flask-app*.zip' | head -1)\n      mkdir -p /root/my-flask-app && unzip -o \"$ZIP\" -d /root/my-flask-app\n      cd /root/my-flask-app\n      command -v python3 >/dev/null || yum install -y python3\n      pip3 install -r requirements.txt\n      [ -f /root/app.pid ] && kill \"$(cat /root/app.pid)\" 2>/dev/null || true\n      nohup python3 app.py >> /root/app.log 2>&1 &\n      echo $! > /root/app.pid\n      sleep 3 && cat /root/app.log\n    stop: |\n      #!/bin/bash\n      [ -f /root/app.pid ] && kill \"$(cat /root/app.pid)\" 2>/dev/null || true\n```\n\n## Step 4: Pre-deploy price check + user confirmation\n\nInput:\n```bash\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" price --config .appmanager/config.yaml\n```\n\nExpected output (excerpt — the Agent must relay both the price block and the OSS notice to the user):\n```\n==================================================\n📊 Deployment Price Estimate\n==================================================\nRegion        : cn-beijing\n...\n💰 Total: CNY 0.06000/hour\n   Monthly estimate: CNY 43.20/month (30 days x 24 hours)\n==================================================\n\n📦 OSS extra billing (not covered by `appmanager price`; relay to the user):\n    - OSS standard storage: ~CNY 0.12/GB/month ...\n=== AGENT_CONFIRM_REQUIRED ===\n```\n\nAgent then asks the user (example wording — see Task 4.5 in SKILL.md): \"Estimated cost: CNY 0.06/hour (~CNY 43.20/month); the deployment also incurs minor OSS storage/request fees. Confirm to continue?\"\n\n## Step 5: Deploy and verify\n\nInput:\n```bash\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" deploy \\\n  --type app --name my-flask-app --group default-cn-beijing --region cn-beijing\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" verify \\\n  --type app --name my-flask-app --group default-cn-beijing --region cn-beijing --wait 10\n```\n\nExpected (success):\n```\n--- Deploy command completed (exit 0) ---\n✅ Deploy submitted. Use 'deploy_toolkit.py verify' to check if app is actually running.\n...\n=== Post-deploy Verification ===\nECS Public IP: 47.95.xxx.xxx\n--- Application Log (source: cloud_assistant) ---\n * Serving Flask app 'app'\n * Running on http://0.0.0.0:8080\n=== AGENT_ANALYZE_REQUIRED ===\nlog_source: cloud_assistant\necs_instance: i-2zexxxxxxxxxxxxxxxxxxx\n```\n\nThe Agent then prints the self-check report and the final output (console link + cost reminder + management commands).\n\n## Edge cases\n\n| Situation | What to do |\n|-----------|-----------|\n| `ReleaseCancelled` returned by deploy | The start script failed/timed out on ECS. Run `verify` -> read `/root/app.log` -> fix the start script -> redeploy (max 3 retries). |\n| `NotEnoughBalance` error | Pay-as-you-go ECS requires balance >= CNY 100. Direct the user to https://usercenter2.aliyun.com/finance/fund-management or switch to existing ECS. |\n| `AccessDenied` at `upload_to_oss` | OSS bucket name `<app_name>-<region>` is globally unique. Change `--name` to a more unique value, delete `.appmanager/`, and re-init + redeploy. |\n| Existing-ECS impact warning | Ask the user explicitly: deploying may stop/overwrite other apps on the instance. STOP if user refuses. |\n| Cloud Assistant log fetch fails | Surface the SSH fallback `ssh root@<ECS_IP> 'tail -100 /root/app.log'` and the HTTP port probe result printed by `verify`. |\n\nFile v1.0.3:scripts/requirements.txt\n\n# Do NOT pin to 6.0.2: it requires Python >=3.8, while bare ECS may ship an\n# older system python3 (e.g. 3.6) where pip finds no matching wheel and the\n# deploy start script aborts. >=6.0.1 lets pip pick a compatible build.\nPyYAML>=6.0.1\n\nFile v1.0.3:skill-card.md\n\n## Description:\n\nDeploys application and AI agent projects to Alibaba Cloud ECS with aliyun appmanager, including environment checks, pricing, initialization, deployment, verification, and retry guidance.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[sdk-team](https://clawhub.ai/user/sdk-team)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and engineers use this skill to deploy local projects or cloned repositories as Alibaba Cloud ECS applications or AI agents. It guides the agent through CLI checks, credential setup, configuration generation, cost confirmation, deployment, verification, and operational follow-up.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can deploy projects to Alibaba Cloud ECS and create or modify paid cloud resources.\n\nMitigation: Require explicit user approval before deployment, price acceptance, existing-ECS use, group overwrite, or resource deletion.\n\nRisk: Cloud credentials and model API keys could be exposed if users paste secrets into chat or command arguments.\n\nMitigation: Use OAuth, RAM roles, environment variables, or a secrets manager, and keep AccessKeys and model API keys out of chat and command examples.\n\nRisk: CLI installation, appmanager environment repair, Docker configuration, and root-runtime actions can change local or remote system state.\n\nMitigation: Ask for approval before upgrades, virtual environment deletion, Docker or system configuration changes, and destructive .appmanager operations.\n\n## Reference(s):\n\n- [Deploy Output & Management Reference](references/deploy-output-and-management.md)\n- [Init & Credentials Reference](references/init-and-credentials.md)\n- [RAM Policies Reference](references/ram-policies.md)\n- [Script Templates & Language Reference](references/script-templates.md)\n- [Skill Directory Resolution Reference](references/skill-dir-resolution.md)\n- [Deployment Failure Lessons](references/lessons-learned.md)\n- [Step-by-Step Flask Deployment Tutorial](references/tutorial-flask-app.md)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, shell commands, configuration, code]\n\n**Output Format:** [Markdown guidance with shell commands and YAML or Python snippets]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May create or modify .appmanager/config.yaml and deployment start/stop scripts during use.]\n\n## Skill Version(s):\n\n1.0.3 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.1: 12 files, 52290 bytes\n\nFiles: references/deploy-output-and-management.md (9574b), references/init-and-credentials.md (13331b), references/lessons-learned.md (2951b), references/ram-policies.md (5352b), references/script-templates.md (11724b), references/skill-dir-resolution.md (4676b), references/tutorial-flask-app.md (5476b), scripts/deploy_toolkit.py (46942b), scripts/requirements.txt (14b), skill-card.md (3191b), SKILL.md (32705b), _meta.json (147b)\n\nFile v1.0.1:SKILL.md\n\n---\nname: alibabacloud-ecs-code-deploy\ndescription: Install Alibaba Cloud CLI (aliyun) and deploy projects to Alibaba Cloud ECS using aliyun appmanager commands. Use when the user wants to deploy applications or AI agents to ECS, set up aliyun CLI, or use appmanager init/deploy/status/delete commands.\n---\n\n# Deploy to Alibaba Cloud ECS via aliyun appmanager\n\n## Overview\n\n`aliyun appmanager` is an Agent-friendly CLI tool for one-click deployment of applications (App) and AI Agents to Alibaba Cloud ECS. It supports non-interactive mode (`--non-interactive`), structured JSON output (`--output json`), and streaming NDJSON responses.\n\n**Default behavior**: When user invokes `/alibabacloud-ecs-code-deploy` without specifying a project path or URL, deploy the **current working directory** project to Alibaba Cloud ECS. If user provides a git URL, clone it to the current directory first, then `cd` into the cloned directory and proceed with deployment.\n\n> **EXECUTION ORDER**: The Agent MUST follow the \"Complete Deployment Workflow\" section at the bottom of this document for the correct execution sequence. The Task sections below are organized by topic for reference — their numbering does NOT imply execution order.\n\n---\n\n## MANDATORY: Create Todo List Before Starting\n\n**Before executing any step**, the Agent MUST create a todo list with ALL of the following items. Do NOT omit any item. Do NOT start deployment until the todo list is created.\n\n```\nTodo list (Deploy to Alibaba Cloud ECS):\n  [ ] 0. Resolve $SKILL_DIR (cross-platform path — MUST run first; see \"Step 0\" below)\n  [ ] 1. Environment pre-check (MUST run deploy_toolkit.py check; manual commands FORBIDDEN as replacement)\n  [ ] 2. Obtain project (clone git URL here if needed; skip for local projects)\n  ── Check whether .appmanager/config.yaml already exists (repeat-deploy shortcut) ──\n  │  Exists + new ECS (no instanceId)      → skip 3-5, start from 5.5 (price check)\n  │  Exists + existing ECS (has instanceId) → skip 3-5.5, jump to 6 (deploy)\n  │  Does not exist                        → proceed normally from 3\n  ───────────────────────────────────────────────────────────────────────────────\n  [ ] 3. Read project (README.md -> quick-deploy method) + identify type (agent / app)\n  [ ] 4. Ask user for deployment config (region + new ECS / existing ECS)\n  [ ] 5. Init + generate scripts (appmanager init -> write start/stop scripts to config.yaml)\n  [ ] 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)\n  [ ] 6. Deploy (MUST run deploy_toolkit.py deploy; manual deploy command FORBIDDEN as replacement)\n  [ ] 7. Verify (MUST run deploy_toolkit.py verify; manual status command FORBIDDEN as replacement)\n  [ ] 8. Output final result (console link + cost reminder + management commands)\n```\n\n> **⛔ SCRIPT-FIRST RULE**: Steps 1, 5, 6, 7 have a dedicated toolkit script at `$SKILL_DIR/scripts/deploy_toolkit.py` (where `$SKILL_DIR` is resolved in **Step 0** below — works on Qoder, Claude Code, and any other platform). The Agent MUST run the corresponding subcommand DIRECTLY as the FIRST and ONLY action for that step — NEVER run manual CLI commands (like `aliyun version`, version checks, credential checks) BEFORE or INSTEAD of the script. The script already handles ALL checks internally. Manual commands are ONLY allowed as fallback if the script file itself does not exist.\n>\n> **❌ WRONG (Step 1)**: Run `aliyun version` → check version → run `~/.aliyun/appmanager-venv/bin/python ...` → check version → THEN run `deploy_toolkit.py check`\n> **✅ CORRECT (Step 1)**: Run `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check` → if exit 1, fix the issue it reports → if script file missing, THEN fall back to manual checks\n\n> Item 6 is **NON-NEGOTIABLE**. An Agent that skips log verification and directly outputs \"deployment succeeded\" has NOT completed this skill correctly. If `deploy_toolkit.py verify` exits 1 (failed), the Agent MUST fix the issue and re-deploy before proceeding to item 7.\n\n---\n\n## Step 0 (MANDATORY): Resolve `$SKILL_DIR` — Cross-Platform Path\n\n> The toolkit script lives at `<skill-root>/scripts/deploy_toolkit.py`. Different platforms install skills to different locations (Qoder/Claude Code/Qwen/...). The Agent MUST resolve the absolute skill root **once** at session start and reuse it everywhere `$SKILL_DIR` appears below. **Hardcoding any platform-specific path is FORBIDDEN.**\n\n**See [references/skill-dir-resolution.md](references/skill-dir-resolution.md) for the full 10-candidate detection algorithm, the `export + test -f` verify snippet, and Pattern A / Pattern B / ⛔ Anti-pattern usage rules.**\n\nQuick recap (read the reference for details):\n\n- ✅ **Pattern A** (persistent shell): `export SKILL_DIR=\"/abs/path\"` then later `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" <sub>`\n- ✅ **Pattern B** (fresh shell per call): inline the absolute path — `python3 \"/abs/path/scripts/deploy_toolkit.py\" <sub>`\n- ⛔ **Anti-pattern**: `SKILL_DIR=/path python3 \"$SKILL_DIR/...\"` — outer shell expands `$SKILL_DIR` BEFORE the prefix assignment, producing `/scripts/deploy_toolkit.py` and ENOENT. If you see `python3: can't open file '/scripts/deploy_toolkit.py'`, switch to Pattern A or B.\n\n---\n\n## Task 1: Install Alibaba Cloud CLI\n\n**Primary action**: Run `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check` — it checks CLI version + appmanager-cli version + credentials in one run. Only if the script file is missing, use the fallback in [references/init-and-credentials.md](references/init-and-credentials.md).\n\n> **MUST — Handling unmet environment prerequisites**: When `check` exits 1 because the aliyun CLI is missing or older than 3.3.19 (or appmanager-cli is missing/outdated), the Agent **MUST NOT stop the workflow silently**. The required flow is:\n> 1. **CLI NOT installed** → **Auto-install directly without asking user** — execute the install command (see snippet below or [references/init-and-credentials.md](references/init-and-credentials.md) for the right arch), then re-run `deploy_toolkit.py check` to confirm.\n> 2. **CLI already installed** → **ASK the user first** — show the detected version + the required version + the upgrade command, and ask for explicit consent (e.g. \"aliyun CLI 3.3.4 is already installed but below the required >= 3.3.19 for appmanager; approve upgrade (overwrite-install into /usr/local/bin, requires sudo)?\"). Never assume yes; never paste credentials.\n>    - **On approval** — execute the install/upgrade command, then re-run `deploy_toolkit.py check` to confirm.\n>    - **On refusal** — stop with the refusal as the reason. Do NOT continue with the older version (deployment will fail anyway).\n>\n> The toolkit's `check` output already includes an `→ AGENT: DO NOT stop. ASK user ...` line for each fixable issue — follow it verbatim (except for the \"not installed\" case, which is auto-handled).\n>\n> **MUST — Upgrade method priority** (avoid the \"repeated upgrade\" pitfall: `/usr/local/bin/` is often shadowed by earlier PATH entries like `/opt/homebrew/bin`):\n> 1. brew-managed (`check` prints \"managed by Homebrew\") -> `brew upgrade aliyun-cli`; do NOT overwrite `/usr/local/bin/` again.\n> 2. sudo available -> overwrite into `/usr/local/bin/`, then verify: `hash -r && which -a aliyun && aliyun version`.\n> 3. No sudo -> install to `~/bin/`, ask user to approve appending `export PATH=\"$HOME/bin:$PATH\"` to `~/.zshrc` / `~/.bashrc`.\n>\n> After install/upgrade, ALWAYS rerun `deploy_toolkit.py check` to confirm. If `which -a aliyun` still shows the old binary first, fix PATH order — DO NOT repeat the same overwrite.\n\n### AI-Mode Configuration (MANDATORY after CLI install)\n\n> **⛔ MUST configure AI-Mode**: Agent MUST ensure AI-Mode is properly configured before running any `aliyun appmanager` commands. `deploy_toolkit.py check` handles this internally; the commands below are for manual fallback only.\n\n```bash\naliyun configure ai-mode enable\naliyun configure ai-mode set-user-agent --user-agent \"AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy\"\naliyun plugin update\naliyun configure ai-mode show   # verify: enabled=true, user-agent set\naliyun configure ai-mode disable # only when troubleshooting\n```\n\n---\n\n## Task 2: Configure Credentials\n\n`deploy_toolkit.py check` already validates credentials. Only if credentials are missing/invalid, see [references/init-and-credentials.md](references/init-and-credentials.md) for the default-credential-chain remediation flow.\n\n> **⛔ PREFER OAuth OVER AK**: This skill SHOULD guide users to use **OAuth authentication** as the PRIMARY method for providing Alibaba Cloud permissions. OAuth is more secure and convenient than AccessKey (no long-term secret storage needed). The Agent MUST present OAuth as the first option before mentioning AK-based methods.\n>\n> **OAuth Login Guide**: Instruct the user to run the following command in their terminal:\n> ```bash\n> aliyun configure --mode OAuth --profile oauth\n> ```\n> This is an interactive command that will:\n> 1. Open a browser with an authorization link — user clicks to authorize\n> 2. Prompt for region (e.g. `cn-hangzhou`, `cn-beijing`) — user enters their preferred region\n> 3. Prompt for language (e.g. `zh`) — user enters their preferred language\n>\n> After OAuth setup completes, verify with: `aliyun sts get-caller-identity --profile oauth`\n>\n> **⛔ SA-2.12 — DO NOT explicitly handle AK/SK**: This skill MUST rely on the aliyun CLI/SDK **default credential chain** (OAuth / ECS RAM Role / env vars / pre-existing `~/.aliyun/config.json`). The Agent **NEVER** asks the user to paste AccessKey/Secret/STS-Token values into the chat, **NEVER** puts raw AK/SK in tool-call arguments or scripts, and **NEVER** echoes credential values. When credentials are missing, instruct the user to configure them out-of-band (their own terminal/shell profile/RAM role) and only re-verify via `aliyun sts get-caller-identity`. Full remediation flow → [references/init-and-credentials.md](references/init-and-credentials.md).\n>\n> **CRITICAL PROHIBITION**: NEVER run standalone `appmanager` or `aliyun appmanager login`.\n\n---\n\n## Task 3: Initialize Project\n\n### Step 1 (MANDATORY): Read README.md FIRST\n\n> **CRITICAL ORDERING RULE**: Before scanning any project files, the Agent MUST read `README.md` (or `README`) in the project root. This is ALWAYS the first action in Task 3.\n\n**What to extract from README:**\n- Quick-start / deploy commands (e.g. `pip install -r requirements.txt && python main.py`, `npm install && npm start`)\n- Official build/run commands, Docker deploy methods, port number, required environment variables\n\n#### MANDATORY: Present README Methods to User and Follow Decision Tree\n\n**Step A**: List what README provides to the user.\n\n**Step B**: Select method by priority:\n\n| Priority | Method Type | Action |\n|----------|------------|--------|\n| 1 (HIGHEST) | **Native CLI / package manager install** (`npm install -g`, `pip install`, `go install`) | Use directly |\n| 2 | **Native build + run** (`pip install && python main.py`, `npm install && npm start`) | Use, install runtime |\n| 3 | **Script-based deploy** (`bash deploy.sh`) | Must confirm non-interactive |\n| 4 (LOWEST) | **Docker / docker-compose** | Only when no higher priority exists; check China accessibility |\n\n**Step C**: Execute based on scenario:\n- **README has native method (priority 1/2)** → Use it directly as start script core. NEVER ignore README and build from scratch.\n- **README only has Docker** → Check image accessibility (see [references/script-templates.md](references/script-templates.md) \"Docker Image Accessibility Check\"). Warn user about China mirror risks.\n- **README has no deploy info / absent** → Agent scans project files independently (only allowed case).\n\n> **Why README first?** Most projects document the exact build/run commands. Auto-detecting from files alone is error-prone.\n\n---\n\n### Step 2: Determine project type\n\n| Condition | Type |\n|-----------|------|\n| Project depends on `agentscope` | `agent` |\n| **Everything else** (langchain, mcp, autogen, web services, tools, etc.) | `app` |\n\n### Determine `--name`\n\nUse the **project directory name** (lowercased, hyphens). Inform user: `Default app name uses the directory name <name>`.\n\n### Determine `--region` and ECS target (MUST ask user)\n\n**Agent MUST ask both questions together in ONE message:**\n\n> **1. Which region do you want to deploy to?**\n> - Shanghai (cn-shanghai) / Hangzhou (cn-hangzhou) / Beijing (cn-beijing) / Shenzhen (cn-shenzhen) / Guangzhou (cn-guangzhou) / Chengdu (cn-chengdu) / Nanjing (cn-nanjing) / Hong Kong (cn-hongkong)\n>\n> **2. New ECS or existing ECS?**\n> - New ECS (auto-create instance, pay-as-you-go)\n> - Existing ECS (please provide the instance ID, e.g. `i-bp1xxxxxxxx`)\n\nNEVER use zone-based labels like \"East China 1\" / \"North China 2\". NEVER add descriptions. City names only.\n\n> ⚠️ **REGION PROPAGATION CHECK** (MANDATORY): The chosen region MUST be passed verbatim to `appmanager init --region`, written into `config.yaml` `common.deployment.regionId`, AND attached as `--region <REGION_ID>` to every subsequent `deploy_toolkit.py {price,deploy,verify}` invocation. Mismatch / omission triggers `InvalidParameter: DeployRegionId is invalid` from the OOS API.\n\n### Determine `--port` (App type only, OPTIONAL)\n\nOnly specify when the project actually listens on HTTP. Skip for background services (bots, workers, CLI tools). If needed but unknown, default to `8080`. Agent type does NOT use `--port`.\n\n### Non-interactive init\n\nSee [references/init-and-credentials.md](references/init-and-credentials.md) for all init flag combinations.\n\nCreates `.appmanager/config.yaml`. Does NOT support `--overwrite` — delete `.appmanager/` first if exists.\n\n---\n\n## Task 4: Generate Deploy Scripts\n\nFor ALL project types, the Agent MUST generate deployment scripts and write them into `.appmanager/config.yaml`.\n\n### Workflow\n\n1. **Read README.md FIRST** — follow Task 3 decision tree\n2. **If README has no deploy info** — scan project structure (Language Detection below)\n3. **Docker accessibility check** — if Docker path selected (see [references/script-templates.md](references/script-templates.md))\n4. **Generate start & stop scripts** — following rules below. Start script MUST ALWAYS include zip extraction sequence.\n5. **Write to config.yaml** — under `common.scripts.start` and `common.scripts.stop` (NEVER top-level `scripts`)\n\n### Language Detection Rules\n\n| Indicator Files | Language |\n|-----------------|----------|\n| `package.json` / `*.js` / `*.ts` | Node.js |\n| `requirements.txt` / `pyproject.toml` / `*.py` | Python |\n| `pom.xml` / `build.gradle` / `*.java` | Java |\n| `go.mod` / `*.go` | Go |\n| `composer.json` / `*.php` | PHP |\n| `docker-compose.yml` / `Dockerfile` | Docker |\n\n### Files to Read (MUST read content, not just detect presence)\n\n| Language | Must Read | Why |\n|----------|-----------|-----|\n| Python | `pyproject.toml`, `requirements.txt` | Entry point, deps |\n| Node.js | `package.json` | `scripts.start`, `main` field |\n| Java | `pom.xml` or `build.gradle` | JAR name |\n| Go | `go.mod` | Module → binary name |\n| PHP | `composer.json` | Framework detection |\n| Docker | `docker-compose.yml` / `Dockerfile` | Services, ports |\n\n### Entry Point Detection Order\n\n- **Python**: `[project.scripts]` in pyproject.toml → `main.py` → `app.py` → `manage.py`\n- **Node.js**: `scripts.start` → `main` field → `index.js` → `server.js`\n- **Java**: `find ... -name \"*.jar\" | head -1` → `java -jar`\n- **Go**: Pre-compiled binary: `find ... -type f -perm /111`\n- **PHP**: `composer install --no-dev` → `php artisan serve` or `php -S`\n- **Docker Compose**: `docker compose up -d` / `docker compose down`\n\n### General Script Rules\n\n| Rule | Requirement |\n|------|-------------|\n| **⛔ MANDATORY zip extract** | Start script MUST: find zip → `mkdir -p` → `unzip -o` → `cd`. Without this, project dir DOES NOT EXIST on ECS |\n| **Runtime install** | MUST install language runtime FIRST (ECS is bare) |\n| **Install unzip** | `command -v unzip &>/dev/null \\|\\| $PKG_MGR install -y unzip` |\n| **Idempotent** | Safe to run multiple times |\n| **⛔ Log file FIXED path** | MUST be `/root/app.log` and `/root/app.pid`. verify script hardcodes these paths |\n| **Log append** | Always `>>` (never `>`) |\n| **PID file** | `echo $! > /root/app.pid` after `nohup ... &` |\n| **Background run** | `nohup ... >> /root/app.log 2>&1 &` |\n| **Stop old process** | `[ -f /root/app.pid ] && kill \"$(cat /root/app.pid)\" 2>/dev/null \\|\\| true` |\n| **App dir** | `/root/{app_name}` |\n| **No heredoc** | NEVER use `<< 'EOF'` inside scripts — breaks YAML. Use `printf` or `python3 -c` |\n| **MANDATORY tail log** | End with `sleep 3 && cat /root/app.log` for verification capture |\n| **⛔ Stop script: NO exit** | MUST NOT contain `exit`. Deploy system concatenates stop+start — exit kills the entire process |\n\n> ECS instances are bare Linux (typically Alibaba Cloud Linux, RHEL-based, uses `yum`/`dnf`).\n\nFor script templates, language install commands, and config.yaml writing method, see [references/script-templates.md](references/script-templates.md).\n\n---\n\n## Task 4.5: Pre-deploy Price Check + Risk Warning\n\n> **MANDATORY**: Before deploying, run `deploy_toolkit.py price`. The script outputs the **price estimate (with OSS extra-billing reminder)** and, when applicable, a **risk warning** block. The Agent MUST present every flagged item to the user and obtain explicit confirmation BEFORE running `deploy`.\n\n```bash\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" price --config .appmanager/config.yaml\n```\n\n- Exit 0 + `=== AGENT_CONFIRM_REQUIRED ===`: present the **complete** price + risk warning to the user, confirm item by item.\n- Exit 1: price query failed; do NOT proceed to deploy.\n\nThe Agent MUST confirm up to 3 items (price + OSS fees / existing-ECS risk / group overwrite choice) — see [references/deploy-output-and-management.md](references/deploy-output-and-management.md) § \"Pre-deploy Price Check: Confirmation Items\" for detailed descriptions and example phrasing.\n\n> Until ALL applicable confirmations are complete, the Agent MUST NOT invoke `deploy_toolkit.py deploy`.\n\n---\n\n## Task 5: Deploy\n\n```\naliyun appmanager <agent|app> deploy --overwrite --output json\n```\n\n> **STOP after deploy success** — `status: success` only means orchestration completed. Agent MUST run Task 6 verification before outputting results.\n\n### Handling deployment failure\n\n> ⛔ **MANDATORY FAILURE GATE**: After ANY deploy failure (exit 1, timeout, or `ReleaseCancelled`), the Agent MUST run `deploy_toolkit.py verify` IMMEDIATELY — BEFORE any fix attempt, fallback to manual commands, or partial output. Skipping verify after a failure is **FORBIDDEN** and counts as skill failure.\n\n> **Semantics of `ReleaseCancelled`**: it means the start script on ECS failed or timed out. It does **NOT** mean \"someone cancelled the deploy\". The only correct next action: run `deploy_toolkit.py verify` -> read the log -> fix the script -> redeploy.\n\n> **Known failure patterns**: Before ad-hoc troubleshooting, check [references/lessons-learned.md](references/lessons-learned.md) for previously identified deployment failure patterns and proven fixes.\n\n**Failure-handling flow:**\n1. Run `deploy_toolkit.py verify` to fetch `/root/app.log` (DO NOT skip).\n2. Analyze the log to locate root cause.\n3. Fix scripts and redeploy (max 3 attempts).\n4. After 3 failures, stop — report the error, but still output console link + cost reminder + delete command.\n\n---\n\n## Task 6: Post-deploy Verification (BLOCKING)\n\n> `status: Deployed` does NOT mean the application is running. The Agent MUST run verify and semantically analyze the log.\n\n1. Run `deploy_toolkit.py verify` (auto-reads parameters from config.yaml).\n2. Agent semantically analyzes the log to decide whether the application actually started successfully.\n3. Not running -> diagnose -> fix -> redeploy + verify (max 3 attempts).\n4. Only when running is confirmed / user manual action required / 3 attempts failed should the Agent output the final result.\n\n---\n\n## Task 7 & 8: List, Delete, Validate & Final Output\n\nSee [references/deploy-output-and-management.md](references/deploy-output-and-management.md) for:\n- List/Delete commands\n- Config validation\n- Config template reference\n- Critical notes & pitfalls\n- MANDATORY post-deploy output format (console link, cost reminder, usage guide)\n\n### Pre-output Gate — Self-check (⛔ BLOCKING)\n\nBefore outputting results, Agent MUST print the exact `Deployment self-check report` template (see Workflow Step 7.5). **Skipping the report = skill failure** (not an optional summary). If any item is ❌, fix it BEFORE outputting Step 8.\n\n> 📘 Hands-on walk-through with concrete inputs/outputs and edge cases (Python Flask example): see [references/tutorial-flask-app.md](references/tutorial-flask-app.md).\n\n## Complete Deployment Workflow\n\n> **⛔ MANDATORY EXECUTION RULE**: The Agent MUST follow this sequence exactly. For steps that specify a script (steps 1, 5, 6), the Agent MUST run the script — NEVER manually replicate the script's logic with individual commands. The Task sections above are REFERENCE ONLY (for understanding what the scripts do internally or as fallback if scripts are missing).\n\n# 0. Resolve $SKILL_DIR (MANDATORY — see \"Step 0\" section above for full algorithm)\n# → Detect the absolute directory containing THIS SKILL.md (most accurate)\n# → Or fall back to platform-specific candidates: ~/.qoder/skills/..., ~/.claude/skills/..., ~/.qwen/skills/..., $SKILLS_HOME/..., etc.\n# → Pattern A (persistent shell): export SKILL_DIR=<abs_path> ; verify $SKILL_DIR/scripts/deploy_toolkit.py exists ; reuse $SKILL_DIR everywhere\n# → Pattern B (fresh shell per command): inline the absolute path — `python3 \"/abs/path/scripts/deploy_toolkit.py\" ...`\n# → ⛔ NEVER use `SKILL_DIR=/path python3 \"$SKILL_DIR/...\"` — outer shell expands $SKILL_DIR\n#    BEFORE the prefix assignment, producing `/scripts/deploy_toolkit.py` and ENOENT.\n\n# 1. Environment check (MUST use deploy_toolkit.py check — DO NOT run manual commands)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check\n# ⛔ FORBIDDEN: running `aliyun version`, `~/.aliyun/appmanager-venv/bin/python -c \"...\"`,\n#    credential checks, or ANY manual version-check commands before or instead of this script.\n#    The script checks ALL of: CLI version + appmanager-cli version + credentials in one run.\n#    Just run the script. Period.\n# → If exit 0: all checks passed, proceed to step 2\n# → If exit 1, address the issue printed by the script:\n#    ⚠️ DO NOT stop silently. For every fixable ❌ line the script prints,\n#       Agent MUST follow the flow below:\n#       - aliyun CLI NOT installed: AUTO-INSTALL directly (no need to ask user)\n#       - aliyun CLI already installed but outdated: ASK user to approve upgrade\n#         (covers to /usr/local/bin, needs sudo), then run the install command\n#         printed by the script (see Task 1).\n#       - appmanager-cli < 1.1.1 or BROKEN venv: ASK user to approve\n#         `rm -rf ~/.aliyun/appmanager-venv` (auto-recreates on next aliyun\n#         appmanager run).\n#         ⚠️ This path is fixed at ~/.aliyun/appmanager-venv (the venv is self-managed\n#            by the aliyun CLI). After deletion, the next `aliyun appmanager` run\n#            auto-recreates it. The Agent MUST use this exact literal path —\n#            NEVER replace it with a variable or build it via concatenation,\n#            to avoid accidentally wiping user data.\n#       - credentials missing/invalid: present OAuth-first remediation\n#         to the user (OAuth / RAM Role / env vars / `aliyun configure` interactive) — NEVER\n#         collect AK/SK in chat. See Task 2 + references/init-and-credentials.md.\n# → If user refuses any fix: stop with that refusal as the reason — DO NOT\n#   continue with a broken environment (deployment will fail anyway).\n# → If script file not found: ONLY THEN fall back to manual checks (Task 1 + Task 2)\n\n# 2. Obtain project source (if needed)\n# → If git URL provided: clone to CURRENT WORKING DIRECTORY, cd into cloned dir\n#    git clone <URL> && cd <cloned_dir>\n# → If local path / current directory: skip this step, use directly\n\n# 🔀 REPEAT DEPLOYMENT SHORTCUT — check BEFORE step 3\n# → Check if .appmanager/config.yaml already exists in the project directory\n# → If YES (config.yaml exists):\n#    Read the file and check for common.deployment.instanceId:\n#      - instanceId ABSENT (new ECS): skip steps 3-5, jump to step 5.5 (price check)\n#      - instanceId PRESENT (existing ECS): skip steps 3-5.5, jump to step 6 (deploy)\n#    In both cases, inform user: \"Existing .appmanager/config.yaml detected; will reuse the existing config and deploy directly.\"\n# → If NO (config.yaml does NOT exist): proceed normally from step 3\n\n# 3. Read project + identify type (agent or app)\n# → READ README.md FIRST — highest priority source for deployment method:\n#    - Agent MUST list README's methods to user and select by priority:\n#      Native CLI install > Native build+run > Script deploy > Docker\n#    - ❌ NEVER ignore README methods and scan project files instead\n#    - ❌ NEVER prefer Docker when native methods are available\n#    - Docker: ONLY when no native method exists, MUST warn user about China mirror risks\n#    - Only if README absent/empty/no deploy info → Agent scans project files independently\n# → Only classify as \"agent\" if project depends on `agentscope`; everything else is \"app\"\n# → Determine --name from directory name, --port from project config/README\n# → For Docker: check image accessibility from China (see references/script-templates.md)\n\n# 4. Ask user for deployment region + ECS target (MANDATORY — ask together in one question)\n# → 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)...\"\n# → Question 2: \"New ECS or existing ECS?\" — for existing, the user must provide the instance ID, e.g. i-bp1xxxxxxxx\n# → NEVER use zone-based labels like \"East China 1\" / \"North China 2\" — always use city names\n# → NEVER skip the ECS choice and default to creating new\n# → ⚠️ 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.\n\n# 5. Init + generate scripts (appmanager init → write start/stop to config.yaml)\n# → If .appmanager/ already exists in the CURRENT project directory, ask user before removing.\n#   ⚠️ DESTRUCTIVE: `rm -rf .appmanager` deletes the existing deployment config.\n#      Required guard before deletion:\n#        a. Confirm CWD matches the intended project directory (`pwd` shows expected path)\n#        b. Confirm target is the relative path `.appmanager` (NEVER absolute, NEVER with variables)\n#        c. Inform the user \"About to delete the existing deployment config under ./.appmanager/. This is irreversible.\" and obtain consent\n#      Recommended safer alternative: back up first\n#        mv .appmanager .appmanager.bak.$(date +%Y%m%d%H%M%S)\n#      Only after explicit user consent: rm -rf ./.appmanager\n# → 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\"]\n#   (See references/init-and-credentials.md for full flag combinations by type)\n# → Then generate start/stop scripts and write to config.yaml:\n#   - MUST write to common.scripts.start and common.scripts.stop (NEVER top-level scripts key)\n#   - Use python3 yaml library: config['common']['scripts'] = {'start': ..., 'stop': ...}\n#   - PRIORITY: README deployment commands → use directly; only auto-generate when README has none\n#   - ⛔ MANDATORY: Start script MUST ALWAYS include zip extraction (mkdir + unzip + cd) BEFORE\n#     any build/run commands. appmanager uploads zip but does NOT extract it.\n\n# 5.5. Pre-deploy price check + risk warning (MUST run deploy_toolkit.py price — Agent handles user confirmation)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" price --config .appmanager/config.yaml\n# → Script output structure:\n#    [Price table] estimate from `appmanager price` (order-billed resources: ECS/EIP/bandwidth) + the trailing 📦 OSS extra-billing reminder\n#    [Risk warning] only when detected: [Existing-ECS deployment risk] / [Group overwrite risk] / [Failure-leftover group]\n# → Script does NOT ask user for confirmation — that's the Agent's job\n# → If exit 0: Agent MUST read the output, present the COMPLETE breakdown to user — including:\n#    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)\n#    2) If output contains [Existing-ECS deployment risk] -> ask whether to deploy onto that existing ECS (may impact other apps on it)\n#    3) If output contains [Group overwrite risk] -> ask user to choose A (overwrite) or B (new group)\n#    Example: \"Estimated cost: compute resources CNY X.XXX/hour (~CNY XXX.XX/month); public traffic billed by usage at CNY 0.80/GB;\n#             the deployment also incurs minor OSS storage and request fees (intra-region pull is free of public outbound charges).\n#             Confirm to continue?\"\n# → After ALL items confirmed by user: run the matching deploy command per item 3's choice (default overwrite / --force-new-group for new group)\n# → If ANY item refused: STOP deployment\n# → If exit 1: price query failed, show error to user, do NOT proceed\n\n# 6. Deploy (MUST use deploy_toolkit.py deploy — DO NOT run deploy manually)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" deploy \\\n  --type <agent|app> --name <APP_NAME> --group <GROUP_NAME> --region <REGION_ID>\n# ⛔ FORBIDDEN: running `aliyun appmanager deploy` directly without this script\n# → Handles: group status check → conflict auto-resolve → deploy\n# → Exit 0: deploy submitted, proceed to step 7\n# → Exit 1: ⛔ MUST run step 7 (verify) IMMEDIATELY to fetch /root/app.log;\n#           skipping to step 8, outputting partial results, or running manual\n#           commands instead is FORBIDDEN. Then fix script per log and redeploy\n#           (max 3 attempts).\n\n# 7. Verify (MUST use deploy_toolkit.py verify — DO NOT check status manually)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" verify \\\n  --type <agent|app> --name <APP_NAME> --group <GROUP_NAME> --region <REGION_ID>\n# ⛔ FORBIDDEN: running `aliyun appmanager status` + manual log analysis instead of this script\n# → Optional: --wait <seconds> for slow-starting apps (default 3s, Java/heavy use 15-30)\n# → Dual-path: Cloud Assistant cat /root/app.log (preferred) → deployCommandOutput (fallback)\n# → Exit 0: app running, proceed to step 8\n# → Exit 1: app failed — fix start script, re-deploy (back to step 6)\n# → Exit 2: inconclusive — retry with longer --wait or suggest SSH check\n\n# 7.5. Self-check summary (⛔ BLOCKING — skill fails if omitted)\n# MUST print the exact template below to the user — this is a completion criterion, NOT optional.\n#\n# ---\n# ✅ Deployment self-check report:\n#   0. Path resolution — SKILL_DIR=___ (script exists ✅)\n#   1. Environment pre-check — CLI v___ / appmanager-cli v___ / credentials valid ✅\n#   2. Project obtained — (local / cloned) ✅\n#   3. Project identified — type: ___ / deploy method source: README.md ✅\n#   4. Deployment region — user choice: ___ ✅\n#   5. Init + scripts — config.yaml generated; start script: ___ (key command summary) ✅\n#   5.5. Pre-deploy price check — user confirmed price (CNY ___/hour, ~CNY ___/month) ✅\n#   6. Deploy executed — deploy_toolkit.py deploy exit 0 ✅\n#   7. Run verification — deploy_toolkit.py verify exit 0 / log keywords: ___ ✅\n# ---\n#\n# If any item is ❌, fix it BEFORE step 8 — this is for the USER to see, proving the work is properly done.\n\n# 8. Output results (MANDATORY: console link + cost reminder + management commands)\n# → See references/deploy-output-and-management.md for full output format\n\nFile v1.0.1:_meta.json\n\n{\n  \"ownerId\": \"kn74p5w8ywv6prh40g0s82gmqh83nw54\",\n  \"slug\": \"alibabacloud-ecs-code-deploy\",\n  \"version\": \"1.0.1\",\n  \"publishedAt\": 1780887251108\n}\n\nFile v1.0.1:references/deploy-output-and-management.md\n\n# Deploy Output & Management Reference\n\n## Common Deploy Options\n\n| Flag | Description |\n|------|-------------|\n| `--config PATH` | Custom config file (default: `.appmanager/config.yaml`) |\n| `--overwrite` | Force overwrite existing files in OSS |\n| `--dry-run` | Validate only, do not execute deployment |\n| `--output json` | Output NDJSON stream (Agent-friendly) |\n| `--name TEXT` | Override app name |\n| `--group_name TEXT` | Override group name |\n| `--region TEXT` | Override deployment region |\n| `--revision_id TEXT` | Redeploy using existing artifact |\n\n### Deploy output format\n\n`--overwrite --output json` is the **standard deploy invocation**. Always use both flags.\n\nOutput format (NDJSON, one JSON per line):\n```\n{\"type\":\"step\", \"step\":1, \"total\":9, \"message\":\"Validating config...\"}\n{\"type\":\"step\", \"step\":2, \"total\":9, \"message\":\"Uploading to OSS...\"}\n{\"type\":\"result\", \"status\":\"success\", \"data\":{\"revision_id\":\"rev-xxx\", ...}}\n```\n\n---\n\n## MANDATORY: Post-deploy Output\n\nWhen the self-check passes (all items OK), output the following to the user:\n\n### 1. Deployment summary table\n\nIncludes app name, deployment region, group name, deployment status, Revision ID, and ECS instance ID.\n\n### 2. Console link\n\nRead the `console_url` field from the deploy result; if missing, build the URL with the formats below:\n- On success: `https://computenest.console.aliyun.com/app/detail?tabKey=overview&appName=<APP_NAME>&groupName=<GROUP_NAME>`\n- On failure / pending confirmation (ReleaseWaiting, script execution failure, etc.): `https://computenest.console.aliyun.com/app/detail?tabKey=flow&appName=<APP_NAME>&groupName=<GROUP_NAME>` (jumps to the execution-flow page)\n\n### 3. Resource cost reminder (MUST include the delete command)\n\n> Resource cost reminder: this deployment uses ECS instances and OSS storage (pay-as-you-go). Delete the resources when you no longer need them to avoid recurring charges:\n> ```bash\n> aliyun appmanager <agent|app> delete --name <APP_NAME> --group_name <GROUP_NAME>\n> ```\n\n### 4. Status query command\n\n> ```bash\n> aliyun appmanager <agent|app> status --name <APP_NAME> --group_name <GROUP_NAME>\n> ```\n\n### 5. Usage guidance\n\nThe Agent MUST tailor the usage guidance to the project type and the deploy log:\n\n| Project usage type | Detection signal | Usage guidance |\n|--------------------|------------------|----------------|\n| **Web service** (HTTP listener) | Deploy log shows \"Listening on port X\"; project uses flask / fastapi / express / spring / django | Provide access URL: `http://<ECS_PUBLIC_IP>:<PORT>` (extract ECS public IP from `status` output) |\n| **API service** | Project defines REST / GraphQL endpoints | Provide API base URL + sample `curl` command |\n| **CLI tool / library** | Project is a command-line tool, SDK, or library (e.g. agentscope) | Provide SSH login command + a verification command |\n| **Background service / worker** | Project is a queue consumer, scheduled job, or daemon | Inform the user the service is running in background; provide log-tail command |\n| **Static site / frontend** | Project contains HTML/CSS/JS served by nginx / serve | Provide access URL: `http://<ECS_PUBLIC_IP>:<PORT>` |\n\n**Get the ECS public IP**: extract `public_ip` or `instance_ip` from `aliyun appmanager <agent|app> status --output json` output.\n\n> **WARNING**: Omitting the console link or cost reminder is FORBIDDEN.\n\n---\n\n## List & Delete\n\n### List applications\n\n```\naliyun appmanager agent list\naliyun appmanager agent list --name my-agent  # list groups under app\naliyun appmanager app list\n```\n\n### Delete\n\n```\n# Delete a group first\naliyun appmanager agent delete --name my-agent --group_name default-cn-beijing\n# Then delete the application\naliyun appmanager agent delete --name my-agent\n```\n\n> In `--output json` mode, confirmation is skipped automatically.\n\n---\n\n## Validate Config\n\n```\naliyun appmanager config validate\naliyun appmanager config validate --config path/to/config.yaml --output json\n```\n\n---\n\n## Config Template Reference\n\nGenerated by `aliyun appmanager init --print-template`. Below is a unified template (use `type: agent` or `type: app`):\n\n```yaml\nmetadata:\n  name: my-app                    # Required: app/agent name\n  type: app                       # \"app\" or \"agent\"\n  groupName: default-cn-beijing   # NEVER use bare \"default\" — always include region suffix\n  regionId: cn-beijing            # Required: deployment region\n\ncommon:\n  deployment:\n    # Option 1: New ECS (auto-created)\n    ecsInstanceType: ecs.u1-c1m2.large\n    systemDiskSize: 40\n    internetMaxBandwidthOut: 5\n    # Option 2: Existing ECS (uncomment below, remove Option 1)\n    # instanceId: i-bp1xxxxxxxx\n\n  scripts:                        # REQUIRED: Agent-generated scripts (MUST be under common.scripts)\n    start: |\n      #!/bin/bash\n      # Agent generates start script based on project analysis (see SKILL.md Task 4)\n    stop: |\n      #!/bin/bash\n      # Agent generates stop script (MUST NOT contain 'exit' statement)\n\n# Agent-specific config (ONLY for type: agent, remove for type: app)\nagent:\n  model:\n    name: qwen3.6-plus\n    apiKey: \"sk-xxx\"              # REQUIRED for agent type — deployment fails without this\n```\n\n---\n\n## Critical Notes & Pitfalls\n\n1. **NEVER use standalone `appmanager` or `aliyun appmanager login`**: Only `aliyun appmanager <cmd>` is valid. **SA-2.12** — credentials must come from the aliyun CLI/SDK default credential chain (ECS RAM Role / env vars / pre-existing `~/.aliyun/config.json` set up out-of-band by the user); the Agent MUST NOT collect AK/SK in chat or pass them via `--access-key-*` flags.\n\n2. **Agent type REQUIRES `apiKey`**: Deploying type `agent` without `agent.model.apiKey` in config.yaml will fail.\n\n3. **Both types generate deploy scripts locally**: Agent generates scripts by scanning project → writes to `common.scripts` in config.yaml. No API Key needed for script generation.\n\n4. **First run auto-installs**: First `aliyun appmanager` auto-creates venv at `~/.aliyun/appmanager-venv/` — Agent should NEVER interact with this venv directly.\n\n5. **ECS zone compatibility**: Not all instance types available in every zone. If zone-related errors occur, try a different region or instance type.\n\n6. **OSS Bucket name conflict**: Bucket named `<app_name>-<region>` is globally unique. If `AccessDenied` at `upload_to_oss` → change `--name` to a more unique value and re-run `init` + `deploy`.\n\n7. **`groupName` MUST include region suffix**: NEVER use bare `default`. Always `default-<regionId>` (e.g., `default-cn-hangzhou`).\n\n8. **Pre-deploy group check**: Handled automatically by `deploy_toolkit.py deploy`.\n\n9. **Insufficient balance (`NotEnoughBalance`)**: account balance < CNY 100 cannot create pay-as-you-go ECS. Tell the user to top up at https://usercenter2.aliyun.com/finance/fund-management, or switch to deploying onto an existing ECS instance.\n\n---\n\n## Pre-deploy Price Check: Confirmation Items\n\nThe Agent MUST confirm each applicable item with the user **one by one** before invoking `deploy_toolkit.py deploy`.\n\n### 1. Price confirmation (including OSS extra fees — ALWAYS required)\n\nThe price output has two parts:\n- The estimate from `appmanager price` for \"order-billed\" resources (ECS / EIP / public bandwidth, etc.) in hourly/monthly form.\n- A `OSS extra billing` notice — these items are **NOT covered** by `appmanager price` but always occur during deployment:\n  - OSS standard storage ~CNY 0.12 / GB / month (project archives are usually KB-MB scale, so the amount is tiny but non-zero)\n  - OSS public-network outbound traffic ~CNY 0.50 / GB (**when ECS and OSS are in the same region, intra-region pull is free of public traffic charges**; only cross-region transfer incurs the fee — therefore the deployment region SHOULD match the default OSS bucket region)\n  - OSS Put/Get requests are billed per 10k requests (negligible amount)\n\nThe Agent MUST relay both parts. Example phrasing: \"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?\"\n\n### 2. Existing-ECS deployment impact (only when script outputs `[Existing-ECS deployment risk]`)\n\nWhen `config.yaml` contains `common.deployment.instanceId`, the script lists the risk items. The Agent MUST ask:\n\"About to deploy to the existing ECS instance `i-xxx`. The deployment runs stop -> upload -> start scripts and may stop or overwrite other applications already running on this instance. Confirm to continue?\"\n- User refuses -> STOP and recommend switching to \"new ECS\"\n- User agrees -> proceed to item 3 (if applicable) or directly to deploy\n\n### 3. Group overwrite vs new group (only when script outputs `[Group overwrite risk]`)\n\nWhen the target `groupName` already exists and is associated with active ECS, the script asks for an A/B choice:\n- **A) Overwrite the existing group**: `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" deploy` (default; uses `--overwrite` to replace code / restart processes)\n- **B) Create a new group**: `python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" deploy --force-new-group` (the script auto-appends a suffix to allocate a new group name and writes it back to config.yaml; the existing deployment is unaffected)\n\nThe Agent MUST clearly explain the impact of A vs B; **do NOT default to A on the user's behalf**.\n\n> Until ALL applicable confirmations are complete, the Agent MUST NOT invoke `deploy_toolkit.py deploy`.\n\nFile v1.0.1:references/init-and-credentials.md\n\n# Init & Credentials Reference\n\n## AI-Mode Configuration (MANDATORY after CLI install)\n\n> **⛔ MUST configure AI-Mode**: Agent MUST ensure AI-Mode is properly configured before running any `aliyun appmanager` commands. All subsequent `aliyun` CLI calls automatically carry the configured User-Agent header — no per-command `--user-agent` flag needed.\n\n```bash\n# 1. Enable AI-Mode (MUST — enables User-Agent tracking in all API calls)\naliyun configure ai-mode enable\n\n# 2. Set User-Agent for skill traceability (MUST — identi\n\nArchive v1.0.0: 12 files, 50614 bytes\n\nFiles: references/deploy-output-and-management.md (6889b), references/init-and-credentials.md (11097b), references/lessons-learned.md (2951b), references/ram-policies.md (5352b), references/script-templates.md (11724b), references/skill-dir-resolution.md (4676b), references/tutorial-flask-app.md (5476b), scripts/deploy_toolkit.py (46298b), scripts/requirements.txt (14b), skill-card.md (2897b), SKILL.md (34501b), _meta.json (147b)\n\nArchive v0.0.1-beta.1: 9 files, 41648 bytes\n\nFiles: references/deploy-output-and-management.md (6722b), references/init-and-credentials.md (8968b), references/ram-policies.md (5352b), references/script-templates.md (11724b), references/skill-dir-resolution.md (4676b), scripts/deploy_toolkit.py (34534b), skill-card.md (2999b), SKILL.md (28186b), _meta.json (154b)","readmeExcerpt":"Skill: alibabacloud-ecs-code-deploy Owner: sdk-team Summary: 基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot 等），新建或已有 ECS 实例，自动处理分组冲突、zip 解压、余额不足、地域参数透传、重复部署免初始化。触发词：部署到ECS、部署项目到ECS、部署到云服务器、把这个项目部署上去、上线到ECS、把仓库部署到ECS、当前目录部署、阿里云ECS部署、appmanager部署、aliyun appmanager、一键部署App、部署AI Agent、deploy to ECS、code deplo","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"Todo list (Deploy to Alibaba Cloud ECS):\n  [ ] 0. Resolve $SKILL_DIR (cross-platform path — MUST run first; see \"Step 0\" below)\n  [ ] 1. Environment pre-check (MUST run deploy_toolkit.py check; manual commands FORBIDDEN as replacement)\n  [ ] 2. Obtain project (clone git URL here if needed; skip for local projects)\n  ── Check whether .appmanager/config.yaml already exists (repeat-deploy shortcut) ──\n  │  Exists + new ECS (no instanceId)      → skip 3-5, start from 5.5 (price check)\n  │  Exists + existing ECS (has instanceId) → skip 3-5.5, jump to 6 (deploy)\n  │  Does not exist                        → proceed normally from 3\n  ───────────────────────────────────────────────────────────────────────────────\n  [ ] 3. Read project (README.md -> quick-deploy method) + identify type (agent / app)\n  [ ] 4. Ask user for deployment config (region + new ECS / existing ECS)\n  [ ] 5. Init + generate scripts (appmanager init -> write start/stop scripts to config.yaml)\n  [ ] 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)\n  [ ] 6. Deploy (MUST run deploy_toolkit.py deploy; manual deploy command FORBIDDEN as replacement)\n  [ ] 7. Verify (MUST run deploy_toolkit.py verify; manual status command FORBIDDEN as replacement)\n  [ ] 8. Output final result (console link + cost reminder + management commands)"},{"language":"text","snippet":"AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/{session-id}"},{"language":"bash","snippet":"export ALIBABA_CLOUD_USER_AGENT=\"AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/${SESSION_ID}\""},{"language":"bash","snippet":"python3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" price --config .appmanager/config.yaml"},{"language":"text","snippet":"aliyun appmanager <agent|app> deploy --overwrite --output json"},{"language":"bash","snippet":"# 0. Resolve $SKILL_DIR (MANDATORY — see \"Step 0\" section above for full algorithm)\n# → Detect the absolute directory containing THIS SKILL.md (most accurate)\n# → Or fall back to platform-specific candidates: ~/.qoder/skills/..., ~/.claude/skills/..., ~/.qwen/skills/..., $SKILLS_HOME/..., etc.\n# → Pattern A (persistent shell): export SKILL_DIR=<abs_path> ; verify $SKILL_DIR/scripts/deploy_toolkit.py exists ; reuse $SKILL_DIR everywhere\n# → Pattern B (fresh shell per command): inline the absolute path — `python3 \"/abs/path/scripts/deploy_toolkit.py\" ...`\n# → ⛔ NEVER use `SKILL_DIR=/path python3 \"$SKILL_DIR/...\"` — outer shell expands $SKILL_DIR\n#    BEFORE the prefix assignment, producing `/scripts/deploy_toolkit.py` and ENOENT.\n\n# 1. Environment check (MUST use deploy_toolkit.py check — DO NOT run manual commands)\npython3 \"$SKILL_DIR/scripts/deploy_toolkit.py\" check\n# ⛔ FORBIDDEN: running `aliyun version`, `~/.aliyun/appmanager-venv/bin/python -c \"...\"`,\n#    credential checks, or ANY manual version-check commands before or instead of this script.\n#    The script checks ALL of: CLI version + appmanager-cli version + credentials in one run.\n#    Just run the script. Period.\n# → If exit 0: all checks passed, proceed to step 2\n# → If exit 1, address the issue printed by the script:\n#    ⚠️ DO NOT stop silently. For every fixable ❌ line the script prints,\n#       Agent MUST follow the flow below:\n#       - aliyun CLI NOT installed: AUTO-INSTALL directly (no need to ask user)\n#       - aliyun CLI already installed but outdated: ASK user to approve upgrade\n#         (covers to /usr/local/bin, needs sudo), then run the install command\n#         printed by the script (see Task 1).\n#       - appmanager-cli < 1.1.1 or BROKEN venv: ASK user to approve\n#         `rm -rf ~/.aliyun/appmanager-venv` (auto-recreates on next aliyun\n#         appmanager run).\n#         ⚠️ This path is fixed at ~/.aliyun/appmanager-venv (the venv is self-managed\n#            by the aliyun CLI). After "}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: alibabacloud-ecs-code-deploy\ndescription: 基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot 等），新建或已有 ECS 实例，自动处理分组冲突、zip 解压、余额不足、地域参数透传、重复部署免初始化。触发词：部署到ECS、部署项目到ECS、部署到云服务器、把这个项目部署上去、上线到ECS、把仓库部署到ECS、当前目录部署、阿里云ECS部署、appmanager部署、aliyun appmanager、一键部署App、部署AI Agent、deploy to ECS、code deploy、deploy app、deploy agent、appmanager deploy、ECS code deploy、跑一下这个项目、把代码跑到ECS上、ECS上线。\n---\n\n# Deploy to Alibaba Cloud ECS via aliyun appmanager\n\n## Overview\n\n`aliyun appmanager` is an Agent-friendly CLI tool for one-click deployment of applications (App) and AI Agents to Alibaba Cloud ECS. It supports non-interactive mode (`--non-interactive`), structured JSON output (`--output json`), and streaming NDJSON responses.\n\n**Default behavior**: When user invokes `/alibabacloud-ecs-code-deploy` without specifying a project path or URL, deploy the **current working directory** project to Alibaba Cloud ECS. If user provides a git URL, clone it to the current directory first, then `cd` into the cloned directory and proceed with deployment.\n\n> **EXECUTION ORDER**: The Agent MUST follow the \"Complete Deployment Workflow\" section at the bottom of this document for the correct execution sequence. The Task sections below are organized by topic for reference — their numbering does NOT imply execution order.\n\n---\n\n## MANDATORY: Create Todo List Before Starting\n\n**Before executing any step**, the Agent MUST create a todo list with ALL of the following items. Do NOT omit any item. Do NOT start deployment until the todo list is created.\n\n```\nTodo list (Deploy to Alibaba Cloud ECS):\n  [ ] 0. Resolve $SKILL_DIR (cross-platform path — MUST run first; see \"Step 0\" below)\n  [ ] 1. Environment pre-check (MUST run deploy_toolkit.py check; manual commands FORBIDDEN as replacement)\n  [ ] 2. Obtain project (clone git URL here if needed; skip for local projects)\n  ── Check whether .appmanager/config.yaml already exists (repeat-deploy shortcut) ──\n  │  Exists + new ECS (no instanceId)      → skip 3-5, start from 5.5 (price check)\n  │  Exists + existing ECS (has instanceId) → skip 3-5.5, jump to 6 (deploy)\n  │  Does not exist                        → proceed normally from 3\n  ───────────────────────────────────────────────────────────────────────────────\n  [ ] 3. Read project (README.md -> quick-deploy method) + identify type (agent / app)\n  [ ] 4. Ask user for deployment config (region + new ECS / existing ECS)\n  [ ] 5. Init + generate scripts (appmanager init -> write start/stop scripts to config.yaml)\n  [ ] 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)\n  [ ] 6. Deploy (MUST run deploy_toolkit.py deploy; manual deploy command FORBIDDEN as replacement)\n  [ ] 7. Verify (MUST run deploy_toolkit.py verify; manual status command FORBIDDEN as replacement)\n  [ ] 8. Outp"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn74p5w8ywv6prh40g0s82gmqh83nw54\",\n  \"slug\": \"alibabacloud-ecs-code-deploy\",\n  \"version\": \"1.0.3\",\n  \"publishedAt\": 1786586602919\n}"},{"path":"references/deploy-output-and-management.md","content":"# Deploy Output & Management Reference\n\n## Common Deploy Options\n\n| Flag | Description |\n|------|-------------|\n| `--config PATH` | Custom config file (default: `.appmanager/config.yaml`) |\n| `--overwrite` | Force overwrite existing files in OSS |\n| `--dry-run` | Validate only, do not execute deployment |\n| `--output json` | Output NDJSON stream (Agent-friendly) |\n| `--name TEXT` | Override app name |\n| `--group_name TEXT` | Override group name |\n| `--region TEXT` | Override deployment region |\n| `--revision_id TEXT` | Redeploy using existing artifact |\n\n### Deploy output format\n\n`--overwrite --output json` is the **standard deploy invocation**. Always use both flags.\n\nOutput format (NDJSON, one JSON per line):\n```\n{\"type\":\"step\", \"step\":1, \"total\":9, \"message\":\"Validating config...\"}\n{\"type\":\"step\", \"step\":2, \"total\":9, \"message\":\"Uploading to OSS...\"}\n{\"type\":\"result\", \"status\":\"success\", \"data\":{\"revision_id\":\"rev-xxx\", ...}}\n```\n\n---\n\n## MANDATORY: Post-deploy Output\n\nWhen the self-check passes (all items OK), output the following to the user:\n\n### 1. Deployment summary table\n\nIncludes app name, deployment region, group name, deployment status, Revision ID, and ECS instance ID.\n\n### 2. Console link\n\nRead the `console_url` field from the deploy result; if missing, build the URL with the formats below:\n- On success: `https://computenest.console.aliyun.com/app/detail?tabKey=overview&appName=<APP_NAME>&groupName=<GROUP_NAME>`\n- On failure / pending confirmation (ReleaseWaiting, script execution failure, etc.): `https://computenest.console.aliyun.com/app/detail?tabKey=flow&appName=<APP_NAME>&groupName=<GROUP_NAME>` (jumps to the execution-flow page)\n\n### 3. Resource cost reminder (MUST include the delete command)\n\n> Resource cost reminder: this deployment uses ECS instances and OSS storage (pay-as-you-go). Delete the resources when you no longer need them to avoid recurring charges:\n> ```bash\n> aliyun appmanager <agent|app> delete --name <APP_NAME> --group_name <GROUP_NAME>\n> ```\n\n### 4. Status query command\n\n> ```bash\n> aliyun appmanager <agent|app> status --name <APP_NAME> --group_name <GROUP_NAME>\n> ```\n\n### 5. Usage guidance\n\nThe Agent MUST tailor the usage guidance to the project type and the deploy log:\n\n| Project usage type | Detection signal | Usage guidance |\n|--------------------|------------------|----------------|\n| **Web service** (HTTP listener) | Deploy log shows \"Listening on port X\"; project uses flask / fastapi / express / spring / django | Provide access URL: `http://<ECS_PUBLIC_IP>:<PORT>` (extract ECS public IP from `status` output) |\n| **API service** | Project defines REST / GraphQL endpoints | Provide API base URL + sample `curl` command |\n| **CLI tool / library** | Project is a command-line tool, SDK, or library (e.g. agentscope) | Provide SSH login command + a verification command |\n| **Background service / worker** | Project is a queue consumer, scheduled job, or daemon | Inform the user the service is running in backgro"},{"path":"references/init-and-credentials.md","content":"# Init & Credentials Reference\n\n## Observability: User-Agent Injection (MANDATORY before any CLI call)\n\n> **⛔ Every `aliyun` CLI call MUST carry this skill's User-Agent** so all API requests are traceable in cloud-side logs. Export the UA env var ONCE at session start, before any `aliyun` / `deploy_toolkit.py` invocation.\n\n**Full UA template:**\n\n```\nAlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/{session-id}\n```\n\n**session-id unified rules:**\n- Generate ONCE per agent session: `SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')` — lowercase UUID (any lowercase-hex random token ≥ 16 chars is equivalent).\n- Reuse the SAME session-id for ALL CLI calls within the session — NEVER regenerate per command, otherwise one deployment scatters into untraceable fragments.\n\n**Injection method (modern — env var):**\n\n```bash\n# Run ONCE per session (persistent shell); or prefix each command with the same literal value\nexport SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')\nexport ALIBABA_CLOUD_USER_AGENT=\"AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/${SESSION_ID}\"\n```\n\n> ⛔ The legacy `aliyun configure ai-mode enable / set-user-agent / show / disable` mechanism is DEPRECATED — do NOT use it. Do NOT combine `ALIBABA_CLOUD_USER_AGENT` with ai-mode or per-command env prefixes for the same skill token: the CLI stacks these sources and produces duplicate UAs. Set the env var ONCE per session and leave it.\n\n---\n\n## CLI Install/Upgrade Method Priority\n\n> Avoid the \"repeated upgrade\" pitfall: `/usr/local/bin/` is often shadowed by earlier PATH entries like `/opt/homebrew/bin`.\n\n**On Linux/macOS (Unix):**\n1. brew-managed (`check` prints \"managed by Homebrew\") -> `brew upgrade aliyun-cli`; do NOT overwrite `/usr/local/bin/` again.\n2. sudo available -> overwrite into `/usr/local/bin/`, then verify: `hash -r && which -a aliyun && aliyun version`.\n3. No sudo -> install to `~/bin/`, ask user to approve appending `export PATH=\"$HOME/bin:$PATH\"` to `~/.zshrc` / `~/.bashrc`.\n\n**On Windows (PowerShell)** — no `brew`/`sudo`/`.zshrc`; `check` auto-detects `os.name == \"nt\"` and prints PowerShell guidance:\n1. Scoop/Chocolatey managed -> `scoop update aliyun-cli` or `choco upgrade aliyun-cli -y`.\n2. Otherwise download the official zip and extract into `%USERPROFILE%\\bin` (no admin rights), then persist the **User** PATH via `[Environment]::SetEnvironmentVariable(\"PATH\", \"$dest;$userPath\", \"User\")` (full snippet in the \"Windows (PowerShell) install\" section below).\n3. After install/upgrade, open a **NEW** terminal so the updated User PATH takes effect, then re-run check.\n\nAfter install/upgrade, ALWAYS rerun `deploy_toolkit.py check` to confirm. On Unix, if `which -a aliyun` still shows the old binary first, fix PATH order — DO NOT repeat the same overwrite.\n\n---\n\n## Fallback: Manual CLI Verification & Install (only when deploy_toolkit.py unavailable)\n\n**Version requirements**: aliyun CLI >= 3.3.19, appmanager-cli >= 1.1.1\n\n> **🪟 Windows users**: The `curl | sudo tar "},{"path":"references/lessons-learned.md","content":"# Lessons Learned — Deployment Failure Patterns & Fixes\n\n> This document is auto-populated by the batch deployment test (see `tests/batch-deploy-100.md`).\n> When an Agent encounters a deployment issue, it SHOULD consult this file first for known\n> patterns and proven fixes before attempting ad-hoc troubleshooting.\n\n## How to Use This File\n\n1. **Before deploying**: Skim the error signatures below. If the project matches a known\n   trigger scenario, apply the fix proactively.\n2. **After a failure**: Search this file for the error message or signature. If found,\n   apply the documented fix and retry.\n3. **Contributing new lessons**: When a new failure pattern is observed >= 2 times across\n   different projects, add a new entry following the format below.\n\n## Entry Format\n\nEach lesson follows this structure:\n\n```markdown\n### <Error Signature>\n\n- **Phase**: check / init / deploy / verify\n- **Trigger Scenario**: <what type of project or condition triggers this>\n- **Symptom**: <exact error message or observable behavior>\n- **Root Cause**: <why it happens>\n- **Fix**: <what the Agent should do — specific commands or decision changes>\n- **Affected Projects**: <list of test project numbers/names that hit this>\n- **First Observed**: <date or test round>\n```\n\n---\n\n## Lessons\n\n(The following entries are auto-appended by the Agent during batch deployment testing.\nDo not manually edit below this line unless correcting an inaccuracy.)\n\n---\n\n### `Java-Build-Use-Release-JAR`\n\n- **Phase**: deploy / verify\n- **Trigger Scenario**: Spring Boot or any Java/Gradle/Maven project on 2C4G ECS where `appmanager init` generated a default start script and the project requires `mvn package` / `gradle bootJar` to produce a runnable JAR.\n- **Symptom**:\n  - Round 1: `Error: Unable to access jarfile *.jar` (default `java -jar *.jar` finds no JAR in the cloned source tree).\n  - Round 2 (if Agent retries with `gradle bootJar`): `ReleaseFailed` or `ReleaseCancelled` after the 15-minute deploy budget elapses; `gradle clean bootJar` typically OOM's or runs >15 min on 2 vCPU + 4 GiB RAM.\n- **Root Cause**: 2C4G is too small to build large Java projects in the deploy window.\n- **Fix**: Skip source build. Replace `common.scripts.start` with the pattern below. NOTE: `<app>.jar` and `<version>` are placeholders — substitute the target project's own release artifact name and version (validated concrete example: halo project, `<app>` = `halo`, `<version>` = `2.20.12`):\n  ```yaml\n  common:\n    scripts:\n      start: |\n        : > /root/app.log\n        mkdir -p /root && cd /root\n        if [ ! -f <app>.jar ]; then\n          curl -fSL \"https://github.com/<owner>/<repo>/releases/download/v<version>/<app>-<version>.jar\" -o /root/<app>.jar\n        fi\n        pkill -f '<app>.jar' || true\n        nohup java -Xmx384m -jar /root/<app>.jar --server.port=8090 >> /root/app.log 2>&1 &\n  ```\n  Always set `-Xmx` ≤ 384 m (heap > 50 % of 4 GiB triggers OOM-killer when paired with the JVM's other memory regions).\n"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot 等），新建或已有 ECS 实例，自动处理分组冲突、zip 解压、余额不足、地域参数透传、重复部署免初始化。触发词：部署到ECS、部署项目到ECS、部署到云服务器、把这个项目部署上去、上线到ECS、把仓库部署到ECS、当前目录部署、阿里云ECS部署、appmanager部署、aliyun appmanager、一键部署App、部署AI Agent、deploy to ECS、code deploy、deploy app、deploy agent、appmanager deploy、ECS code deploy、跑一下这个项目、把代码跑到ECS上、ECS上线。 Skill: alibabacloud-ecs-code-deploy Owner: sdk-team Summary: 基于 aliyun appmanager 一键把项目代码部署到阿里云 ECS 云服务器，覆盖环境预检、询价、部署、日志验证、失败诊断重试全流程。支持 App / AI Agent（LangChain / AutoGen / AgentScope / MCP / FastAPI / Flask / Spring Boot 等），新建或已有 ECS 实例，自动处理分组冲突、zip 解压、余额不足、地域参数透传、重复部署免初始化。触发词：部署到ECS、部署项目到ECS、部署到云服务器、把这个项目部署上去、上线到ECS、把仓库部署到ECS、当前目录部署、阿里云ECS部署、appmanager部署、aliyun appmanager、一键部署App、部署AI Agent、deploy to ECS、code deplo","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1186,"uniquenessScore":49,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T07:30:00.361Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T07:30:00.361Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:46:45.249Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}