Files
openclaw-config/docs/agent-创建规范-实现计划.md
T
openclaw-314 707d116758 feat(agent): 存量改造 + 凭据可达性修正
- scripts/db-conn.sh:agent 访问自己专属库的统一入口(口令经 MYSQL_PWD 环境转发,不进 argv、不打印)
- scripts/new-agent.sh:新增 --adopt 模式,为已存在 agent 补建库与账号
- 11 个 AGENTS.md:数据库口径对齐(专用账号 + helper),消除文档与实现不一致
- 修正架构缺陷:中文键名无法作为环境变量暴露给 agent —— 实测进程环境无该变量、
  MANAGED_ENV_KEYS 白名单不含且键随 agent 增长、官方 secrets store 要求纯大写 ASCII;
  故改用统一 helper 从 .env 读取(设计文档附录 A 第 8 条)
2026-09-16 11:31:05 +08:00

527 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# agent 创建规范与数据库自动化 —— 实现计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use subagent-driven-development to implement this plan task-by-task.
>
> **Goal:** 让 main 一条命令创建带专属 MySQL 库与全中文配置的新 agent,并让新建库自动进入每日备份。
>
> **Architecture:** 特权操作全部收敛到 `new-agent.sh`(建库 → 建号 → 授权 → 写 .env → 创建 agent → 渲染中文模板 → 自检);skill 只负责触发与约束;备份脚本由硬编码清单改为动态发现。
>
> **Spec:** `~/.openclaw/docs/agent-创建规范与自动化-设计.md`(执行者需同时读此文档)
>
> **执行环境:** ⚠️ **所有文件位于 bk02,不是本机**。通过 `sshpass -p '<密码>' ssh yangxuan@bk02` 操作;本地写好的文件用 `scp` 传给 bk02 再 `mv` 到目标路径。
>
> **Global Constraints**
> - `agent_id` 必须匹配 `^[a-z][a-z0-9-]{0,23}$`
> - 库名 = `agent_id`;账号 = `agent_<id>`**只授权 `<id>.*`**
> - 展示层(模板与文档内容、`name`、`identity.name`**全中文**;标识层(id/库名/账号/目录名)**全 ASCII**
> - 脚本**不硬编码任何密码**root 凭据从 `~/.openclaw/.env` 的 `MYSQL_PWD_ROOT` 读
> - **默认拒绝覆盖**:库 / agent 条目 / workspace 任一已存在即失败退出
> - 改动提交到 `~/.openclaw` 仓库(分支 `314`)并 **push**(该仓库 auto-commit 在无变更时不推送)
---
## 任务依赖图
```
Task A(脚本+模板)──► Task E(存量改造,串行)
Task Bskill
Task C(备份改造) ├─ 与 A 无文件冲突,可并行
Task D(红线+索引) ┘
```
---
## Task Aprovisioning 脚本 + 中文模板
**Files**
- Create `~/.openclaw/scripts/new-agent.sh``chmod 755`
- Create `~/.openclaw/scripts/agent-templates/IDENTITY.md.tpl`
- Create `~/.openclaw/scripts/agent-templates/SOUL.md.tpl`
- Create `~/.openclaw/scripts/agent-templates/AGENTS.md.tpl`
- Create `~/.openclaw/scripts/agent-templates/MEMORY.md.tpl`
**InterfacesProducesTask B/E 依赖)**
- CLI`new-agent.sh <id> <中文名> [--dry-run] [--reset-password]`
- 成功时 stdout 末尾打印四行:`DATABASE=` / `USER=` / `PASSWORD_ENV=` / `WORKSPACE=`
- 审计日志追加一行到 `~/.openclaw/workspace/db/agent-provision.log`
**Steps**
- [ ] **1. 写四个中文模板**
`IDENTITY.md.tpl`
```markdown
# IDENTITY.md —— 我是谁?
- **名称:** {{AGENT_NAME}}
- **编号:** {{AGENT_ID}}
- **定位:** (一句话说明我负责什么)
- **创建时间:** {{CREATED_AT}}
```
`SOUL.md.tpl`
```markdown
# SOUL.md —— 我的性格与表达
- **风格:** 简洁、直接、先给结论再给依据。
- **原则:** 不确定时先问,不猜测;做破坏性操作前必须先请示。
- **语言:** 一律用中文回复。
- **边界:** 只处理我职责范围内的事,跨范围时转交对应 agent。
```
`AGENTS.md.tpl`
```markdown
# AGENTS.md —— 我的工作规范
## 会话启动
1.`IDENTITY.md`(我是谁)
2.`MEMORY.md`(长期记忆)
3.`memory/` 下最近两天的记录
## 记忆
- 每日记录写 `memory/YYYY-MM-DD.md`
- 长期结论写 `MEMORY.md`
## 数据库规范
- **默认库:** `{{AGENT_ID}}` —— 这就是我自己的库
- **账号:** `agent_{{AGENT_ID}}`
- **连接(推荐):** `~/.openclaw/scripts/db-conn.sh {{AGENT_ID}}`(交互式)或 `~/.openclaw/scripts/db-conn.sh {{AGENT_ID}} --sql "select database()"`
- **口令:** 由该脚本自动从 `~/.openclaw/.env` 读取(键名 `DB_PASSWORD_{{AGENT_NAME}}`),口令不会出现在命令行中
- **禁止:** 使用 root、使用 `docker exec`、访问其他 agent 的库、跨库写入
- **建表前**先确认字段与索引;**破坏性语句**DROP / TRUNCATE / 无条件 DELETE)必须先请示
## 红线
- 绝不泄露私密数据
- 未经请示绝不运行破坏性命令
```
`MEMORY.md.tpl`
```markdown
# MEMORY.md —— 长期记忆
> 只写经过筛选的、长期有效的结论;原始流水写 `memory/YYYY-MM-DD.md`。
## 关于我的职责
## 关于我的库 `{{AGENT_ID}}`
## 重要决定
```
- [ ] **2. 写脚本骨架(参数校验 + 冲突检查 + dry-run**
```bash
#!/usr/bin/env bash
# 新建 OpenClaw agent:建库 → 建号 → 授权 → 写 .env → 创建 agent → 渲染中文模板 → 自检
set -euo pipefail
ENV_FILE="$HOME/.openclaw/.env"
TEMPLATE_DIR="$HOME/.openclaw/scripts/agent-templates"
OPENCLAW_ROOT="$HOME/.openclaw"
LOG_DIR="$OPENCLAW_ROOT/workspace/db"
LOG_FILE="$LOG_DIR/agent-provision.log"
MYSQL_CONTAINER="mysql"
AGENT_ID="${1:-}"; AGENT_NAME="${2:-}"; shift 2 2>/dev/null || true
DRY_RUN=0; RESET_PASSWORD=0
for arg in "$@"; do
case "$arg" in
--dry-run) DRY_RUN=1 ;;
--reset-password) RESET_PASSWORD=1 ;;
*) echo "未知参数: $arg" >&2; exit 2 ;;
esac
done
usage() { echo "用法: new-agent.sh <id> <中文名> [--dry-run] [--reset-password]"; }
# —— ① 入参校验 ——
[[ -n "$AGENT_ID" && -n "$AGENT_NAME" ]] || { usage; exit 2; }
[[ "$AGENT_ID" =~ ^[a-z][a-z0-9-]{0,23}$ ]] || { echo "id 非法:只允许小写字母开头、[a-z0-9-]、最长 24 字符"; exit 2; }
[[ "$AGENT_NAME" =~ ^[^[:space:]]{2,20}$ ]] || { echo "中文名非法:2–20 个字符且不含空白"; exit 2; }
WORKSPACE="$OPENCLAW_ROOT/workspace-$AGENT_ID"
DB_USER="agent_$AGENT_ID"
PASSWORD_VAR="DB_PASSWORD_$AGENT_NAME"
# —— root 凭据:从 .env 读,绝不硬编码 ——
MYSQL_ROOT_PWD="$(grep -E '^MYSQL_PWD_ROOT=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"'"'"'')"
[[ -n "$MYSQL_ROOT_PWD" ]] || { echo "无法从 $ENV_FILE 读取 MYSQL_PWD_ROOT"; exit 1; }
mysql_root() { docker exec -e MYSQL_PWD="$MYSQL_ROOT_PWD" "$MYSQL_CONTAINER" mysql -uroot -N -B -e "$1"; }
```
- [ ] **3. 冲突检查(默认拒绝覆盖)**
```bash
# —— ② 冲突检查 ——
DB_EXISTS="$(mysql_root "select count(*) from information_schema.schemata where schema_name='$AGENT_ID';")"
USER_EXISTS="$(mysql_root "select count(*) from mysql.user where user='$DB_USER';")"
AGENT_EXISTS="$(python3 -c "
import json
d=json.load(open('$OPENCLAW_ROOT/openclaw.json'))
print(1 if '$AGENT_ID' in (d.get('agents') or {}).get('entries',{}) else 0)
")"
WS_EXISTS=$([[ -d "$WORKSPACE" ]] && echo 1 || echo 0)
if [[ "$RESET_PASSWORD" == "1" ]]; then
[[ "$USER_EXISTS" == "1" ]] || { echo "账号 $DB_USER 不存在,无法重置密码"; exit 1; }
else
[[ "$DB_EXISTS" == "0" ]] || { echo "❌ 库 $AGENT_ID 已存在 —— 已存在请使用 --reset-password,或改用 new-agent.sh 管理"; exit 1; }
[[ "$USER_EXISTS" == "0" ]] || { echo "❌ 账号 $DB_USER 已存在 —— 请使用 --reset-password"; exit 1; }
[[ "$AGENT_EXISTS" == "0" ]] || { echo "❌ agent 条目 $AGENT_ID 已存在"; exit 1; }
[[ "$WS_EXISTS" == "0" ]] || { echo "❌ 目录 $WORKSPACE 已存在"; exit 1; }
fi
```
- [ ] **4. 建库建号授权 + 密码生成**
```bash
# —— ③ 生成密码 ——
NEW_PWD="$(openssl rand -base64 24 | tr -d '/+=' | cut -c1-32)"
# —— ④ SQLdry-run 只打印)——
SQL_CREATE_DB="CREATE DATABASE \`$AGENT_ID\` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;"
SQL_CREATE_USER="CREATE USER '$DB_USER'@'%' IDENTIFIED BY '$NEW_PWD';"
SQL_GRANT="GRANT ALL PRIVILEGES ON \`$AGENT_ID\`.* TO '$DB_USER'@'%';"
if [[ "$DRY_RUN" == "1" ]]; then
echo "[dry-run] 将执行:"; echo " $SQL_CREATE_DB"; echo " $SQL_CREATE_USER"; echo " $SQL_GRANT"
echo "[dry-run] 将写入 $ENV_FILE$PASSWORD_VAR=<32位随机>"
echo "[dry-run] 将创建 workspace$WORKSPACE"
echo "[dry-run] 将执行:openclaw agents add $AGENT_ID --workspace $WORKSPACE --non-interactive"
exit 0
fi
mysql_root "$SQL_CREATE_DB" >/dev/null
if [[ "$RESET_PASSWORD" == "1" ]]; then
mysql_root "ALTER USER '$DB_USER'@'%' IDENTIFIED BY '$NEW_PWD';" >/dev/null
else
mysql_root "$SQL_CREATE_USER" >/dev/null
fi
mysql_root "$SQL_GRANT" >/dev/null
```
- [ ] **5. .env 幂等写入**
```bash
# —— ⑤ 写 .env(同键覆盖,不重复追加)——
if grep -q "^${PASSWORD_VAR}=" "$ENV_FILE"; then
python3 - "$ENV_FILE" "$PASSWORD_VAR" "$NEW_PWD" <<'PY'
import sys
path, key, val = sys.argv[1], sys.argv[2], sys.argv[3]
lines = open(path, encoding='utf-8').read().splitlines()
out = [f'{key}={val}' if l.startswith(key + '=') else l for l in lines]
open(path, 'w', encoding='utf-8').write('\n'.join(out) + '\n')
PY
else
printf '%s=%s\n' "$PASSWORD_VAR" "$NEW_PWD" >> "$ENV_FILE"
fi
chmod 600 "$ENV_FILE"
```
- [ ] **6. 创建 agent + 渲染模板 + 同步中文名**
```bash
# —— ⑥ 创建 agent ——
export NVM_DIR="$HOME/.nvm"; . "$NVM_DIR/nvm.sh"; nvm use 26 >/dev/null 2>&1
openclaw agents add "$AGENT_ID" --workspace "$WORKSPACE" --non-interactive >/dev/null
# —— ⑦ 渲染中文模板(覆盖 openclaw 生成的英文骨架)——
CREATED_AT="$(date '+%Y-%m-%d')"
for tpl in IDENTITY SOUL AGENTS MEMORY; do
sed -e "s/{{AGENT_ID}}/$AGENT_ID/g" \
-e "s/{{AGENT_NAME}}/$AGENT_NAME/g" \
-e "s/{{CREATED_AT}}/$CREATED_AT/g" \
"$TEMPLATE_DIR/$tpl.md.tpl" > "$WORKSPACE/$tpl.md"
done
mkdir -p "$WORKSPACE/memory"
# —— ⑧ 中文名同步进配置 ——
openclaw agents set-identity --agent "$AGENT_ID" --from-identity >/dev/null 2>&1 || \
openclaw agents set-identity --agent "$AGENT_ID" --name "$AGENT_NAME" >/dev/null
```
- [ ] **7. 自检(核心:用新账号实连)**
```bash
# —— ⑨ 自检:证明授权真的生效 ——
if docker exec -e MYSQL_PWD="$NEW_PWD" "$MYSQL_CONTAINER" mysql -u"$DB_USER" -N -B -e "SELECT 1;" "$AGENT_ID" >/dev/null 2>&1; then
SELFCHECK="ok"
else
SELFCHECK="FAILED"
fi
mkdir -p "$LOG_DIR"
printf '[%s] id=%s name=%s user=%s selfcheck=%s dry_run=%s\n' \
"$(date '+%Y-%m-%d %H:%M:%S')" "$AGENT_ID" "$AGENT_NAME" "$DB_USER" "$SELFCHECK" "$DRY_RUN" >> "$LOG_FILE"
cat <<EOF
✅ 已创建 agent$AGENT_NAME$AGENT_ID
DATABASE=$AGENT_ID
USER=$DB_USER
PASSWORD_ENV=$PASSWORD_VAR
WORKSPACE=$WORKSPACE
自检=$SELFCHECK
EOF
[[ "$SELFCHECK" == "ok" ]] || { echo "⚠️ 自检失败:请检查授权"; exit 1; }
```
**验收(Task A**
```bash
# 1) 语法与 dry-run
bash -n ~/.openclaw/scripts/new-agent.sh
bash ~/.openclaw/scripts/new-agent.sh tprobe 测试探针 --dry-run
# 2) 实跑一个临时 agent,验证三件事,然后清理
bash ~/.openclaw/scripts/new-agent.sh tprobe 测试探针
# → 库存在? docker exec -e MYSQL_PWD=... mysql mysql -uroot -e "show databases like 'tprobe';"
# → 账号只对本库有权限? docker exec ... mysql -uroot -e "show grants for 'agent_tprobe'@'%';"
# → 模板全中文? head -3 ~/.openclaw/workspace-tprobe/AGENTS.md
# 3) 幂等:再跑一次应被拒绝(提示已存在)
# 4) 清理:删除测试 agent / 库 / 账号 / workspace / .env 行 / 日志行
```
> ⚠️ 清理必须彻底:`openclaw agents delete tprobe`、`DROP DATABASE`、`DROP USER`、删 workspace、删 `.env` 中的 `DB_PASSWORD_测试探针`。
---
## Task Bskill `agent-provisioning`
**Files**
- Create `~/.openclaw/skills/agent-provisioning/SKILL.md`
**Interfaces**
- ConsumesTask A 的 CLI 契约(`new-agent.sh <id> <中文名>`
- Producesmain 在相应语境下加载本 skill 并调用脚本
**Steps**
- [ ] **1. 写 SKILL.md**
```markdown
---
name: agent-provisioning
description: "新建 OpenClaw agent 的唯一正确流程:当用户说「新建 agent」「创建 agent」「加一个 agent」「给某人开一个助手」时使用。负责为 agent 建专属 MySQL 库、专用账号、中文配置与 workspace。禁止绕过本流程手工建库。"
---
# 新建 agent(唯一正确流程)
## 何时使用
用户表达"新建 / 创建 / 增加一个 agent(助手 / 机器人 / 专属助理)"时。
## 唯一正确做法
```bash
bash ~/.openclaw/scripts/new-agent.sh <id> <中文名>
```
- `<id>`ASCII,小写字母开头,只含 `[a-z0-9-]`,≤24 字符(例:`reading`
- `<中文名>`220 字符,不含空白(例:`阅读`
先与用户确认这两个值,再执行。
## 红线(禁止)
- ❌ 禁止自行拼 SQL 建库、建账号
- ❌ 禁止用 `mysql` / `docker exec` 直接操作数据库来创建 agent
- ❌ 禁止为建库读取或使用 root 凭据
- ❌ 禁止手工创建 `workspace-*` 目录或手改 `openclaw.json` 的 agents 条目
以上任一被绕过,都会造成"库存在但未被备份登记 / 账号缺失 / 配置中英混杂"的不一致。
## 执行后
脚本会输出四行结果(`DATABASE` / `USER` / `PASSWORD_ENV` / `WORKSPACE`)。
把结果转述给用户,并提示:新库将在**次日 03:00 自动进入每日备份**。
## 参数
| 参数 | 用途 |
|---|---|
| `--dry-run` | 只打印将执行的 SQL 与文件操作,不落地(先给用户看过再执行) |
| `--reset-password` | 仅重置已存在 agent 的账号密码(库/账号已存在时用) |
```
**验收(Task B**
```bash
# 1) frontmatter 合法(name + description 齐备,否则会被跳过)
head -5 ~/.openclaw/skills/agent-provisioning/SKILL.md
# 2) 重启后不再出现 Skipping invalid skill,且该 skill 被加载
export NVM_DIR=$HOME/.nvm; . $NVM_DIR/nvm.sh; nvm use 26 >/dev/null
openclaw gateway restart && sleep 20
journalctl --user -u openclaw-gateway --since "2 min ago" | grep -iE 'agent-provisioning|Skipping invalid'
```
---
## Task C:每日备份脚本改造(动态发现)
**Files**
- Modify `/usr/local/bin/backup-agent-dbs.sh`(需 `sudo`
**Interfaces**
- ConsumesMySQL 中由 Task A 创建的 `agent_<id>` 账号与 `<id>`
- Produces:所有 agent 库每日备份,无需人工登记
**Steps**
- [ ] **1. 先备份原脚本**
```bash
sudo cp /usr/local/bin/backup-agent-dbs.sh /usr/local/bin/backup-agent-dbs.sh.bak-20260916
```
- [ ] **2. 把硬编码 `DB_MAP` 换成动态发现**
删除原 `declare -A DB_MAP=(...)`,替换为:
```bash
# ===== 动态发现:agents.entries 的 id ∩ MySQL 实际库(排除系统库)=====
SYSTEM_DBS="mysql|information_schema|performance_schema|sys"
AGENT_IDS="$(python3 -c "
import json
d=json.load(open('/home/yangxuan/.openclaw/openclaw.json'))
print('\n'.join(sorted((d.get('agents') or {}).get('entries',{}).keys())))
")"
DB_LIST="$(mysql_root "select schema_name from information_schema.schemata where schema_name not regexp '^(${SYSTEM_DBS})\$';")"
# 交集:只备份「配置里存在的 agent」且「库真实存在」的
TARGETS=""
while IFS= read -r db; do
[ -n "$db" ] || continue
echo "$AGENT_IDS" | grep -qx "$db" && TARGETS="$TARGETS $db"
done <<< "$DB_LIST"
TARGETS="$(echo $TARGETS)"
echo "[${TIMESTAMP}] 备份目标:${TARGETS}" >> "$LOG_FILE"
```
- [ ] **3. 目录映射改为按 id 推导**
```bash
ws_dir_for() { # $1 = agent id → workspace 目录名
[ "$1" = "main" ] && echo "workspace" || echo "workspace-$1"
}
```
并把原循环改为遍历 `$TARGETS`,备份目录用 `"$BACKUP_ROOT/$(ws_dir_for "$DB")/db"`
- [ ] **4. 不再硬编码密码**
```bash
# 从 .env 读(脚本内不再出现明文)
ENV_FILE="/home/yangxuan/.openclaw/.env"
MYSQL_PASS="$(grep -E '^MYSQL_PWD_ROOT=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"'"'"'')"
PG_PASS="$(grep -E '^PGPASSWORD=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"'"'"'')"
```
- [ ] **5. 30 天清理与 git 提交段改为遍历动态目录**
原清理循环 `for WS in workspace workspace-resume ...` 改为遍历 `$TARGETS` 推导出的目录。
`git add "workspace-${WS}/db/"` 同理。
**验收(Task C**
> ⚠️ **实测教训(2026-09-16,已造成真实故障)**
> **绝不要用 `sudo` 跑本脚本**:生产路径是 **yangxuan 的 crontab**root crontab 为空)。
> 用 `sudo` 跑会生成 **root 属主**的备份目录/文件,导致**次日 3:00 的 yangxuan cron 写不进去**
> 备份从此天天失败。实测证据:`workspace-{juaner,wellness,tab}/db` 曾是 root 属主,
> 这 3 个库自 **2026-08-26** 起每天 `❌ 备份失败`(日志 `workspace/db/backup.log`)。
```bash
# 0) 前置:修复 root 属主的 db 目录(否则这 3 个库必然继续失败)
for d in /home/yangxuan/.openclaw/workspace*/db; do
[ -d "$d" ] && [ "$(stat -c %U "$d")" = "root" ] && sudo -n chown -R yangxuan:yangxuan "$d"
done
stat -c '%U:%G %n' /home/yangxuan/.openclaw/workspace*/db # 应全部为 yangxuan:yangxuan
# 1) 语法
bash -n /usr/local/bin/backup-agent-dbs.sh
# 2) 手动跑一次(以 yangxuan 身份,**不加 sudo**
/usr/local/bin/backup-agent-dbs.sh; tail -20 ~/.openclaw/workspace/db/backup.log
# → 期望日志出现「备份目标:…」且成功的库数 = 库真实存在且已在 agents.entries 中的 agent 数
# 3) 确认备份文件落在各 workspace 的 db/ 下且已 gz、属主为 yangxuan
ls -la ~/.openclaw/workspace-*/db/*_$(date +%Y%m%d).sql.gz 2>/dev/null | head
# 4) 确认脚本内无明文密码
grep -nE 'MYSQL_PASS="|PG_PASS="' /usr/local/bin/backup-agent-dbs.sh
```
> **另一处必须知道的差异**`.env` 中**没有** `MYSQL_PWD_ROOT`(只有 `MYSQL_PWD`)。
> 正确写法是「优先 `MYSQL_PWD_ROOT`、回退 `MYSQL_PWD`」,这样 Task A/E 之后补上该键会自动生效。
> 另注意:`openclaw` 不在 `agents.entries`(当前只有 11 个 id),**它必须先进入该配置才会被动态发现**(Task E 处理)。
---
## Task Dmain 红线 + 文档索引
**Files**
- Modify `~/.openclaw/workspace/AGENTS.md`(在既有「## 红线」章节内追加)
- Modify `~/.openclaw/docs/README.md`(登记实现计划)
**Steps**
- [ ] **1. 在 `workspace/AGENTS.md` 的「## 红线」章节追加两条**
```markdown
- **创建 agent 红线**:新建 agent 必须且只能执行 `bash ~/.openclaw/scripts/new-agent.sh <id> <中文名>`
禁止自行拼 SQL、禁止用 `mysql`/`docker exec` 建库、禁止为建库读取任何 root 凭据、禁止手工创建 `workspace-*` 或手改 agents 配置。
- **数据库红线**:每个 agent 只能访问自己的库(库名 = 自己的 agent id),账号为 `agent_<id>`;禁止使用 root、禁止跨库写入。
```
- [ ] **2. `docs/README.md` 文档表追加一行**
```markdown
| 4 | `agent-创建规范-实现计划.md` | 上述设计的实现计划:任务切分(A 脚本+模板 / B skill / C 备份改造 / D 红线 / E 存量)、关键代码与验收标准 |
```
**验收(Task D**
```bash
grep -n '创建 agent 红线' ~/.openclaw/workspace/AGENTS.md
grep -c 'agent-创建规范-实现计划' ~/.openclaw/docs/README.md # 期望 1
```
---
## Task E:存量改造(12 个 agent,依赖 A)
**Files**
- Modify `~/.openclaw/.env`(补变量)
- Modify 各 `~/.openclaw/workspace-<id>/AGENTS.md`(补/改数据库段)
**Steps**
- [ ] **1. 已缺库的 4 个:按 A 的流程补建**
`note`(笔记)、`pbs`(PBS备份) 直接走 `new-agent.sh` 的**建库建号部分**(因 agent 已存在,需用 `--reset-password` 之外的分支 → 实际用 `--adopt-existing` 或分步执行:建库建号授权 + 手工补文档)。
`sql`(SQL):保留远程 VPS 业务库定位,另建私有库。
`openclaw`:先确认纳入 `agents.entries``agentToAgent.allow` 的影响,再建库建号。
- [ ] **2. 已有库的 8 个:建专用账号并改文档**
`main` `juaner` `wellness` `tab` `finances` `fitness` `resume` `travel`
-`agent_<id>` 账号 + `GRANT ALL ON \`<id>\`.*` + 写 `DB_PASSWORD_<中文名>`
- **改各自 `AGENTS.md`**:删掉"用 root 连接"的表述,替换为 §Task A 的数据库段
- [ ] **3. 每改一个 agent 立即验证**
```bash
docker exec -e MYSQL_PWD="<新密码>" mysql mysql -uagent_<id> -N -B -e "SELECT 1;" <id>
```
**验收(Task E**
```bash
# 全部 12 个 agent 都有库与账号
docker exec -e MYSQL_PWD="$MYSQL_PWD_ROOT" mysql mysql -uroot -e \
"select user from mysql.user where user like 'agent\_%';"
# 各 workspace 的 AGENTS.md 不再出现 root 直连表述
grep -rn 'u root' ~/.openclaw/workspace*/AGENTS.md
```
---
## Self-Review(计划自查)
| 检查 | 结果 |
|---|---|
| Spec 覆盖 | §2 命名→A 的校验;§3 组件→A/B;§4 九步→A 的 ①–⑨;§5 模板→A Step1;§6 幂等安全→A Step3/5;§7 验证→A 自检;**§8 存量→E**;§10 备份→C**§11 六条→B(2) + D(1) + A(日志/提示)** ✅ |
| 占位符扫描 | 无 TBD/TODO;所有代码块均给出可执行内容 |
| 类型/命名一致 | `agent_<id>`、`DB_PASSWORD_<中文名>`、`$PASSWORD_VAR`、`ws_dir_for()` 在 A/C/E 中一致 ✅ |
| 已知待现场确认 | ① `openclaw agents add` 生成的文件清单(决定模板是覆盖还是补充)② `set-identity --from-identity` 对 IDENTITY.md 的解析要求 —— 实现时先验证,若不符则用 `--name` 兜底(A Step6 已写兜底分支) |