Install
openclaw skills install @vincentlau2046-sudo/atomcode-delegation通过 atomcode CLI 无头模式委派独立代码任务,支持单任务/批量并发、监控、超时、续会话。
openclaw skills install @vincentlau2046-sudo/atomcode-delegation通过 atomcode CLI 无头模式委派独立代码任务。
当用户说以下关键词时激活:
command -v atomcode >/dev/null 2>&1 || { echo "ERROR: atomcode not found in PATH"; exit 1; }
mkdir -p /tmp/atomcode-tasks /tmp/prompts
atomcode -C "<workdir>" \
--prompt-file "<prompt_file>" \
-y \
--provider "<provider>" \
--max-turns <N>
提示:优先用
--prompt-file而非-p "$(cat ...)":
- 不丢失末尾换行、不触发 shell 分裂/通配符展开、不截断内容
| 参数 | 必选 | 说明 |
|---|---|---|
-C <dir> | ✅ | 工作目录(务必引号包裹) |
--prompt-file <path> | ✅ | 从文件读取 prompt(推荐) |
-p <prompt> | ✅ | 直接传 prompt 字符串(替代 --prompt-file) |
-y | ✅ | 跳过权限确认(后台任务必加,否则挂起) |
--provider | ✅ | 模型后端(见下方 Provider 选择) |
--max-turns | ✅ | 回合限制(简单=12,复杂=20-30) |
--model | 可选 | 覆盖 provider 中的 model 名称 |
--engine | 可选 | 引擎选择:v2(默认)/ v1(legacy 回退) |
-c | 可选 | 续接上一次中断的会话 |
--dev | 推荐 | 禁用自动更新(批量任务推荐) |
-v | 可选 | stderr 显示工具调用、token 用量、回合摘要 |
--no-telemetry | 可选 | 禁用本次调用的遥测 |
--lang <lang> | 可选 | 设置界面语言:en / zh-CN / zh |
--disable-tools <names> | 可选 | 排除指定的工具(逗号分隔) |
Provider 名称来自
~/.atomcode/config.toml中[providers.*]的标识符。
| Provider | 模型 | 场景 |
|---|---|---|
AtomGit-deepseek-v4-flash | deepseek-v4-flash | 代码修改、bug fix、重构(默认,100 万 token 窗口) |
AtomGit-GLM-5.2 | GLM-5.2 | 复杂架构设计、多文件协调(20 万 token) |
AtomGit-Qwen-Qwen3-VL-8B-Instruct | Qwen/Qwen3-VL-8B-Instruct | 图像理解、视觉分析任务(6.4 万 token) |
cat > "/tmp/prompts/<task_id>.txt" << 'PROMPT'
# 任务标题
## 背景
问题描述、涉及的代码位置、预期行为 vs 实际行为。
## 修改要求
1. 先 read 相关文件,理解当前实现
2. 具体修改内容(不要只说"修复 bug",要说明改什么、怎么改)
3. 保持现有代码风格和注释
## 约束
- 不要新增不必要的依赖
- 不要修改未在要求中列出的文件
## 验证
python3 -c "import ast; ast.parse(open('<file>').read())"
PROMPT
if [ ! -s "/tmp/prompts/<task_id>.txt" ]; then
echo "ERROR: prompt file is empty or was not written"; exit 1
fi
Prompt 规范:
| 原则 | 说明 |
|---|---|
| 角色设定 | prompt 开头给 agent 一个角色 |
| 先读后改 | 要求 agent 先 read_file 再着手修改 |
| 具体不要模糊 | ❌ "修复性能" → ✅ "将 list 推导替换为 generator" |
| 约束在前 | 明确"不改什么"比"改什么"更重要 |
| 验证命令附后 | 末尾嵌可运行的验证命令 |
| --prompt-file 优先 | 比 -p "$(cat ...)" 更安全(无截断风险、保留末尾换行) |
if [ ! -d "<workdir>" ]; then
echo "ERROR: workdir <workdir> does not exist"; exit 1
fi
cd "<workdir>"
git rev-parse --git-dir >/dev/null 2>&1 || echo "WARNING: not a git repo"
# 单任务 —— 保存 PID 以便监控和清理
LOG="/tmp/atomcode-tasks/<task_id>.log"
atomcode -C "<workdir>" \
--prompt-file "/tmp/prompts/<task_id>.txt" \
-y --dev \
--provider AtomGit-deepseek-v4-flash \
--max-turns 12 \
> "$LOG" 2>&1 &
ATOMCODE_PID=$!
# 批量并行(≤4 并发保守;≤6 在 RAM ≥16GB 可尝试)
declare -A TASK_PIDS
for tid in r1 r2 r3 r4; do
LOG="/tmp/atomcode-tasks/${tid}.log"
atomcode -C "<workdir>" \
--prompt-file "/tmp/prompts/${tid}.txt" \
-y --dev \
--provider AtomGit-deepseek-v4-flash \
--max-turns 12 \
> "$LOG" 2>&1 &
TASK_PIDS[$tid]=$!
done
# 单个任务
wait $ATOMCODE_PID; EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ] && grep -q "\[done\]" "$LOG" 2>/dev/null; then
echo "✅ completed"
elif [ $EXIT_CODE -eq 0 ]; then
echo "⚠️ exit=0 but no [done] — check git diff for partial changes"
else
echo "❌ FAILED (exit=$EXIT_CODE)"; tail -20 "$LOG"
fi
# 批量检查(精确 PID 匹配,避免 pgrep 子串竞态)
for tid in r1 r2 r3 r4; do
PID=${TASK_PIDS[$tid]}
LOG="/tmp/atomcode-tasks/${tid}.log"
if kill -0 "$PID" 2>/dev/null; then
echo "⏳ ${tid}: PID=$PID running ($(wc -l < "$LOG") lines)"
else
wait "$PID" 2>/dev/null; EC=$?
if [ $EC -eq 0 ] && grep -q "\[done\]" "$LOG" 2>/dev/null; then
echo "✅ ${tid}: $(grep '\[done\]' "$LOG" | tail -1)"
elif [ $EC -eq 0 ]; then
echo "⚠️ ${tid}: exit=0, no [done]"
else
echo "❌ ${tid}: exit=$EC"
fi
fi
done
完成检测优先级:
[done] marker 且 exit=0 → 确认完成[done] → --max-turns 耗尽,检查 git diffTIMEOUT=300
(
sleep $TIMEOUT
if kill -0 $ATOMCODE_PID 2>/dev/null; then
echo "TIMEOUT: killing PID=$ATOMCODE_PID after ${TIMEOUT}s"
kill -TERM $ATOMCODE_PID; sleep 5
kill -0 $ATOMCODE_PID 2>/dev/null && kill -9 $ATOMCODE_PID
fi
) &
WATCHDOG_PID=$!
# ⚠️ 任务完成后清理: wait $ATOMCODE_PID; kill $WATCHDOG_PID 2>/dev/null
cd "<workdir>"
python3 -c "
import ast, sys
for f in ['file1.py', 'file2.py']:
try:
ast.parse(open(f).read()); print(f'✅ {f}')
except SyntaxError as e:
print(f'❌ {f}: {e}'); sys.exit(1)
"
git diff --stat
| 症状 | 原因 | 处理 |
|---|---|---|
| 进程卡住无输出 | 卡在 shell tool | kill <PID> 并重试,或加 --engine v1 |
无 [done] 但 exit=0 | --max-turns 耗尽 | 检查 git diff;用 -c 续接继续 |
| 语法错误 | 输出不完整 | 手动修复或降低 --max-turns 重试 |
| token 超限 | 任务太复杂或 prompt 过长 | 拆分为更小的子任务 |
| v2 引擎异常 | 新版引擎 bug | 加 --engine v1 回退 legacy |
| atomcode 不可用 | 未安装或不在 PATH | 检查 command -v atomcode |
| prompt 为空 | heredoc 写入失败 | 检查文件权限、磁盘空间 |
-y 会永久挂起atomcode -C <dir> -c -y --max-turns 12 续接中断任务-p "$(cat ...)" 更安全$!,不用 pgrep 子串匹配rm -f /tmp/atomcode-tasks/<task_id>.log /tmp/prompts/<task_id>.txtTASK_ID="fix_auth_bug"; WORKDIR="$HOME/code/my-project"
command -v atomcode >/dev/null || exit 1
mkdir -p /tmp/atomcode-tasks /tmp/prompts
cat > "/tmp/prompts/${TASK_ID}.txt" << 'PROMPT'
# 修复 auth.py token 过期判断
## 修改要求
1. read auth.py 确认当前实现
2. 修改 check_token(): 比较 current_time 与 token.expires_at
3. 输出 git diff --stat
## 验证
python3 -c "import ast; ast.parse(open('auth.py').read())"
PROMPT
[ -d "$WORKDIR" ] || exit 1
LOG="/tmp/atomcode-tasks/${TASK_ID}.log"
atomcode -C "$WORKDIR" --prompt-file "/tmp/prompts/${TASK_ID}.txt" -y --dev \
--provider AtomGit-deepseek-v4-flash --max-turns 12 > "$LOG" 2>&1 &
PID=$!
(sleep 300; kill -TERM $PID 2>/dev/null; sleep 5; kill -9 $PID 2>/dev/null) &
WD_PID=$!
wait $PID; EXIT=$?; kill $WD_PID 2>/dev/null
if [ $EXIT -eq 0 ]; then
echo "✅ $TASK_ID"; cd "$WORKDIR" && git diff --stat
else
echo "❌ $TASK_ID: exit=$EXIT"; tail -10 "$LOG"
echo "💡 续接: atomcode -C $WORKDIR -c -y --max-turns 8 --provider AtomGit-deepseek-v4-flash"
fi
rm -f "$LOG" "/tmp/prompts/${TASK_ID}.txt"