Customer-readable description
What this skill can do
Aliyun Drive atomic operation layer: install/login to aliyunpan, explicit driveId dual-drive operations, directory browsing, move/rename/delete, download/upload, capacity query, full-drive JSONL scan. Serves as the underlying dependency of curator
| What the customer wants | What the skill will do | What the customer can see |
|---|---|---|
| Complete the work covered by this skill | Read the user request, necessary context, and this skill's body workflow, and execute the minimum reliable steps | The customer will see Obsidian/vault file changes, terminal logs, generated artifact paths, and the final receipt. |
| Missing dependencies, permissions, configuration, or keys | Stop actions that require external state, and clearly state what is missing | Install commands, application addresses, configuration paths, or questions that require customer confirmation |
| Execution completed | Summarize successes, skips, failures, file changes, and verification results | A completion receipt that can be copied into a ticket/log |
How the customer uses it
- Describe the goal in natural language and provide the necessary inputs: files, URLs, repos, workspaces, proposals, vaults, or platform account status.
- The Agent first determines whether this skill is triggered, then checks dependencies, configuration, permissions, and risky actions.
- For actions that can be dry-run or previewed, provide a preview first; for actions involving deletion, overwriting, sending, publishing, or writing remote state, seek customer confirmation first.
- After execution, verify the real output; do not substitute "looks successful" for evidence.
- The final reply must give the customer a visible summary: what was done, log summary, file changes, issues, and next steps.
Dependencies and installation
Install this skill (single skill):
npx skills add soia-team/soia-open-pkm-clip-skills -g -a '*' -s soia-pkm-alipan-drive-ops -y
Configuration conventions:
~/.config/soia-skills/soia-pkm-alipan-drive-ops/config.yml
SOIA_PKM_ALIPAN_DRIVE_OPS_CONFIG_FILE=<custom-config-path>
- If this skill does not require private configuration, you may skip creating
config.yml。 - If an API key, cookie, session, provider home, or local path is required, it may only be placed in the private
config.yml, the process environment, or the provider's own login state; it must not be written into the repository, vault body, or logs. - Strong dependencies, optional dependencies, and third-party skill relationships must be based on this
SKILL.md's subsequent "dependencies / prerequisites / resources / boundaries" description; if it is not clearly written, add the description first or ask the customer, and do not guess. - Third-party skills may only declare dependencies and installation methods; do not directly modify third-party skill files.
Private configuration loading and command entry point
The following commands are executed from this skill's directory; if the current directory is different, replace scripts/run_with_env.py with <skill-dir>/scripts/run_with_env.py. When running aliyunpan , prioritize using this skill's wrapper to load the private configuration, then execute the command:
python3 scripts/run_with_env.py -- aliyunpan who
python3 scripts/run_with_env.py -- aliyunpan quota
python3 scripts/run_with_env.py -- aliyunpan ls --driveId "$DRIVE_ID" "/目标目录/"
The wrapper will only launch aliyunpan、aliyunpan.exe or an absolute path whose basename is one of the two; it will reject env, shell, and any other arbitrary commands. The wrapper will read this skill's private config.yml of env: mappings, and load it in the child process
ALIYUNPAN_CONFIG_DIR. This way, the aliyunpan installed by Homebrew will also use the same specified login state, avoiding forming two sets of sessions with the default ~/.config/aliyunpan/ . The configuration file should only be read by the wrapper;alipan_env.py is only meant for scripts to load as a module, and running it directly will not output the configuration. Do not run cat config.yml、env、printenv or set -x to troubleshoot the configuration.
Running aliyunpan <command> directly remains compatible, suitable for scenarios using the provider's default login state; but after configuring a private ALIYUNPAN_CONFIG_DIR , prefer using the wrapper above to avoid commands falling into another login state. Logs and replies may only state whether the configuration exists or whether the command succeeded,must not print tokens, cookies, sessions, or the values of any environment variables。
Logs and completion receipts
Every execution must let the client see the process and the result. Minimum receipt format:
完成:<一句话说明本次完成了什么>。
日志摘要:
- started: <检查到的输入/配置/依赖,不打印秘密值>
- processed: <数量或范围>
- created/updated: <数量或路径>
- skipped/failed: <数量和原因>
文件变化:
- <绝对路径或“未改动文件”>
验证:
- <运行过的检查、命令或人工核对点>
问题与下一步:
- <缺 key / 缺依赖 / 需要客户确认 / 建议下一条命令;没有则写“无”>
Positioning
Benchmark against what weread-skills is to WeChat Reading: provide onlyreliable atomic operations, and do not make business judgments. Leave higher-level work such as organizing strategies and study plans to soia-pkm-alipan-curator。
Three onboarding steps (new user guidance)
# 1. 安装(macOS,brew 官方 formula)
brew install aliyunpan # 更新: brew upgrade aliyunpan
# 2. 登录(扫码,需用户本人在终端操作)
python3 scripts/run_with_env.py -- aliyunpan login
# 3. 验证
python3 scripts/run_with_env.py -- aliyunpan who
python3 scripts/run_with_env.py -- aliyunpan quota
If a private ALIYUNPAN_CONFIG_DIRhas not yet been configured, the above login and verification commands can also be written directly as aliyunpan login、aliyunpan who and aliyunpan quota。
Remote collaboration recovery for expired login
When a cloud drive command returns "Attempt to log in failed, please use the login command to log in again", the login state is determined to be invalid; this is not a hard blocker requiring the user to scan a QR code on the terminal where the agent is located. Recover remotely according to the following process:
- Start
python3 scripts/run_with_env.py -- aliyunpan loginwith a pty in a non-interactive environment, and keep its stdin readable;must notredirect stdin to</dev/null, otherwise the login program will fail after reading EOF at "press Enter to continue". For the verifiedtail -fkeep-alive scheme and complete commands, see ops-playbook §1.4。 - Capture the complete authorization link from the pty output "up to the space"; do not truncate it with a character whitelist regex:
scopeparameter contains:、,. Push only the complete link to the authorized user of this task; never print tokens, cookies, sessions, or other credentials. - Clearly state that the link is valid only for 5 minutes; after it expires, restart login and send anew link, and do not let the user retry the old link. After the user completes the two steps of authorization and QR code scanning in the browser, confirm that it is complete.
- Only after receiving user confirmation, feed one Enter to the keep-alive stdin to let the login process continue; then use
python3 scripts/run_with_env.py -- aliyunpan whoto verify the returned UID, and clean up the correspondingtail -fhelper process. - Long tasks continue via the existing ledger, progress, or checkpoint-resume mechanism; while waiting for authorization, prioritize work that does not depend on the cloud drive, and do not wait idly or rerun from the beginning. If the failure occurs during high-density concurrent listing, the resumed scan must reduce workers and comply with a throttling of at least 300 ms for batch listing; see ops-playbook "API Rate Limiting and 429 Discipline"。
Discipline: never attempt to read, copy, or forward login credential files; the authorization link may only be sent to the authorized user of that task.
Dual-drive model (key concept)
One account, two drives,sharing the same capacity quota(use aliyunpan quota to see the total):
- Backup drive / Resource library:
aliyunpan driveList each drive's DriveID - All
ls/mv/renameonly apply tocurrent drive; cross-drive moves are not supported by the CLI and require manual operation in the App - ⚠️ Do not use
aliyunpan drive <driveId>for global switching: this command writes the global config, and when multiple agents/scripts run concurrently they will pollute each other's current drive context. The iron rule isevery command must explicitly include--driveId(e.g.,aliyunpan ls --driveId <id> "/路径"), rather than switching first and then running commands without a drive parameter. Seereferences/ops-playbook.mdsection 1.5.
Common commands
| Operation | Command | Note |
|---|---|---|
| List directory | aliyunpan ls "/路径" |
Quote Chinese paths |
| Move | aliyunpan mv "/源" "/目标目录/" |
Supports multiple sources; same drive only |
| Rename | aliyunpan rename "/旧全路径" "/新全路径" |
Must be within the same directory |
| Create directory | aliyunpan mkdir "/路径" |
One at a time is most reliable |
| Delete | aliyunpan rm "/路径" |
Goes to recycle bin, recoverable within 30 days |
| Download | aliyunpan download "/路径" --saveto <本地目录> |
Large files take time; inform the user |
| Capacity | aliyunpan quota |
Remind the user to clean up at 87%+ |
Output parsing (required reading for scripting)
ls output is a table:序号 · 文件大小(目录为"-") · 日期 时间 · 名称(目录以/结尾,可能带尾随空格).
Reliable sed for extracting directory names:
aliyunpan ls "$DIR" </dev/null 2>/dev/null | \
sed -nE 's#^[[:space:]]+[0-9]+[[:space:]]+-[[:space:]]+[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}[[:space:]]+(.*)$#\1#p' | \
sed -E 's#[[:space:]]+$##; s#/$##'
- Add to every aliyunpan command inside the loop
</dev/null, to prevent it from swallowing the while loop's stdin - After batch operationsmust verify the final state(re-run ls to compare), echo "✓/✗" for each item
Safety rules (lessons from practice, must follow)
- Tool output cannot be blindly trusted: if physically impossible results appear (multiple items with the same name in the same directory, line count contradicting byte count) → suspect output pollution, cross-validate via another channel (Read vs Bash), or ask the user to verify in the App before continuing.
- Before deleting/overwriting, look first:
rmbefore, firstlsconfirm the contents; name conflicts automatically add a(1)suffix—check whether the target already exists before moving, to avoid creatingxxx(1)duplicate directories. - Keep a human in the loop for high-risk operations: emptying directories, batch deletion, manual cross-drive migration—list the items and ask the user to confirm or do it themselves.
- Credentials: login state belongs to the aliyunpan provider, by default in
~/.config/aliyunpan/, do not move it into the skill, and do not cat-print the token. If you need to change the login state directory, put only theALIYUNPAN_CONFIG_DIRoverride into this skill's private config:~/.config/soia-skills/soia-pkm-alipan-drive-ops/config.yml(seeconfig.example.yml). For running commands, prefer usingpython3 scripts/run_with_env.py -- aliyunpan <command>to load that override; no logs, diagnostic output, or final receipts may print the token or env values. - Confirm before deleting/moving/renaming: a matching path, an explicit skill invocation, or any default configuration is only a recommended input and does not justify skipping confirmation; the only condition for skipping is when the customer's current message explicitly says "delete directly/no confirmation needed"; after skipping, state in the receipt the scope assumptions used this time.
- Probe with a small sample before batching: before batch
mv/rm/rename, first run once with the smallest sample (e.g., 1 item) and report the estimated total; after the customer confirms the scale is correct, proceed with full execution; do not directly take on directories of unknown size. - Obey rate limits first, then resume:Batch write operations are throttled to 200–300 ms each time, and batch listing is no less than 300 ms each time; upon receiving 429, read
x-retry-afterand wait, never retry consecutively. See the "API Rate Limiting and 429 Discipline" section of the ops-playbook for details.
In-Depth Practical Handbook
When encountering the following scenarios, first read references/ops-playbook.md(practical insights from the 2026-07 cloud drive organization campaign), do not re-trial-and-error:
- Installation/login details: two-step authorization + QR code scanning process, symptoms and handling of login state expiring in about 3 days, and the first step of standard remote recovery in non-interactive environments (pseudo-terminal pty / long-running process reading stdout); for the complete recovery process see "Remote Collaboration Recovery for Login Expiration" above
--driveIdIron rule for explicit parameter passing: why you must never usealiyunpan drive <id>to switch the global drive (multiple agents running concurrently will pollute each other's current drive context)- Practical pitfalls of batch operations and rate-limiting discipline: the cd dependency pitfall of batch rename, API buckets and 429 waiting,
llFILE ID in the output and how to construct direct links, moving/renaming does not change file_id but cross-drive moves do change file_id, deletion goes to the recycle bin for 30 days and quota is only truly released when the recycle bin is emptied - CLI hard limitation for sibling directories with the same name:
ls/llonly addresses by path, cannot enter one of them by file_id; after temporarily moving one out, the CLI cannot restore the dual same-name state as-is. Convergence is only allowed when content-level evidence proves one side is redundant and the user explicitly authorizes deletion; otherwise suspend and wait for the user to adjudicate naming or switch to the open API - Full-drive JSONL crawler:has been scripted as
scripts/scan_drive.py(parameterized DFS + thread pool + retry + resumable scan + aggregation pruning + no drilling down into sensitive directories); output preserves the original consecutive spaces in directory names, and records file_id, size, and SHA-1. Sibling directories with the same name will each be markedambiguous_name: trueand all will not be drilled down,.errorssidecar synchronously recordsAMBIGUOUS_NAME, making the consumer side fail-closed; for disambiguation, targeted rescan, and non-restorable limitations see ops-playbook §2.7. For usage see ops-playbook §3.Complete library pipeline =scan_drive.py(live drive→JSONL) → alipan-curator'sgen_catalog.py(JSONL→collapsed tree overview + full-text search). For handling of the three pitfalls—instant login disconnection, historical parser collapsing special spaces, and same-name shadowing—see the ops-playbook.scan_drive.pyproduced.errors/.progress/.donesidecar is deliberately placed in the same directory and shares the same lifecycle as the--outmain output—resumable scan (--resume) relies on the sidecar to locate progress (.donerecords line by line the directories that have been fully listed, and is the authoritative checkpoint for resuming the scan), and quality verification must match the main output; this is by design, not an omission, do not move it to a temporary directory - Discipline to prevent agent hangs: always write long content to files via scripts, and limit chat replies to 15 lines