Files
openclaw-config/docs/agent-创建规范-实现计划.md
T

19 KiB
Raw Blame History

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>.*
  • 展示层(模板与文档内容、nameidentity.name全中文;标识层(id/库名/账号/目录名)全 ASCII
  • 脚本不硬编码任何密码root 凭据从 ~/.openclaw/.envMYSQL_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.shchmod 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 依赖)

  • CLInew-agent.sh <id> <中文名> [--dry-run] [--reset-password]
  • 成功时 stdout 末尾打印四行:DATABASE= / USER= / PASSWORD_ENV= / WORKSPACE=
  • 审计日志追加一行到 ~/.openclaw/workspace/db/agent-provision.log

Steps

  • 1. 写四个中文模板

IDENTITY.md.tpl

# IDENTITY.md —— 我是谁?

- **名称:** {{AGENT_NAME}}
- **编号:** {{AGENT_ID}}
- **定位:** (一句话说明我负责什么)
- **创建时间:** {{CREATED_AT}}

SOUL.md.tpl

# SOUL.md —— 我的性格与表达

- **风格:** 简洁、直接、先给结论再给依据。
- **原则:** 不确定时先问,不猜测;做破坏性操作前必须先请示。
- **语言:** 一律用中文回复。
- **边界:** 只处理我职责范围内的事,跨范围时转交对应 agent。

AGENTS.md.tpl

# AGENTS.md —— 我的工作规范

## 会话启动
1.`IDENTITY.md`(我是谁)
2.`MEMORY.md`(长期记忆)
3.`memory/` 下最近两天的记录

## 记忆
- 每日记录写 `memory/YYYY-MM-DD.md`
- 长期结论写 `MEMORY.md`

## 数据库规范
- **默认库:** `{{AGENT_ID}}` —— 这就是我自己的库
- **账号:** `agent_{{AGENT_ID}}`
- **密码:** 环境变量 `DB_PASSWORD_{{AGENT_NAME}}`
- **连接:** `mysql -h 127.0.0.1 -u agent_{{AGENT_ID}} -p"${DB_PASSWORD_{{AGENT_NAME}}}" {{AGENT_ID}}`
- **禁止:** 使用 root、使用 `docker exec`、访问其他 agent 的库、跨库写入
- **建表前**先确认字段与索引;**破坏性语句**DROP / TRUNCATE / 无条件 DELETE)必须先请示

## 红线
- 绝不泄露私密数据
- 未经请示绝不运行破坏性命令

MEMORY.md.tpl

# MEMORY.md —— 长期记忆

> 只写经过筛选的、长期有效的结论;原始流水写 `memory/YYYY-MM-DD.md`。

## 关于我的职责

## 关于我的库 `{{AGENT_ID}}`

## 重要决定
  • 2. 写脚本骨架(参数校验 + 冲突检查 + dry-run
#!/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. 冲突检查(默认拒绝覆盖)
# —— ② 冲突检查 ——
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. 建库建号授权 + 密码生成
# —— ③ 生成密码 ——
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 幂等写入
# —— ⑤ 写 .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 + 渲染模板 + 同步中文名
# —— ⑥ 创建 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. 自检(核心:用新账号实连)
# —— ⑨ 自检:证明授权真的生效 ——
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

# 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 tprobeDROP DATABASEDROP 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
---
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. 先备份原脚本
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=(...),替换为:

# ===== 动态发现: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 推导
ws_dir_for() {           # $1 = agent id → workspace 目录名
  [ "$1" = "main" ] && echo "workspace" || echo "workspace-$1"
}

并把原循环改为遍历 $TARGETS,备份目录用 "$BACKUP_ROOT/$(ws_dir_for "$DB")/db"

  • 4. 不再硬编码密码
# 从 .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

# 1) 语法
sudo bash -n /usr/local/bin/backup-agent-dbs.sh
# 2) 手动跑一次(观察新增 agent 是否被纳入)
sudo /usr/local/bin/backup-agent-dbs.sh; tail -20 ~/.openclaw/workspace/db/backup.log
# 3) 确认备份文件落在各 workspace 的 db/ 下且已 gz
ls -la ~/.openclaw/workspace-*/db/*_$(date +%Y%m%d).sql.gz 2>/dev/null | head
# 4) 确认脚本内无明文密码
sudo grep -nE 'MYSQL_PASS="|PG_PASS="' /usr/local/bin/backup-agent-dbs.sh

Task Dmain 红线 + 文档索引

Files

  • Modify ~/.openclaw/workspace/AGENTS.md(在既有「## 红线」章节内追加)
  • Modify ~/.openclaw/docs/README.md(登记实现计划)

Steps

  • 1. 在 workspace/AGENTS.md 的「## 红线」章节追加两条
- **创建 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 文档表追加一行
| 4 | `agent-创建规范-实现计划.md` | 上述设计的实现计划:任务切分(A 脚本+模板 / B skill / C 备份改造 / D 红线 / E 存量)、关键代码与验收标准 |

验收(Task D

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.entriesagentToAgent.allow 的影响,再建库建号。

  • 2. 已有库的 8 个:建专用账号并改文档 main juaner wellness tab finances fitness resume travel

    • agent_<id> 账号 + GRANT ALL ON \`.*+ 写DB_PASSWORD_<中文名>`
    • 改各自 AGENTS.md:删掉"用 root 连接"的表述,替换为 §Task A 的数据库段
  • 3. 每改一个 agent 立即验证

    docker exec -e MYSQL_PWD="<新密码>" mysql mysql -uagent_<id> -N -B -e "SELECT 1;" <id>
    

验收(Task E

# 全部 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_VARws_dir_for() 在 A/C/E 中一致
已知待现场确认 openclaw agents add 生成的文件清单(决定模板是覆盖还是补充)② set-identity --from-identity 对 IDENTITY.md 的解析要求 —— 实现时先验证,若不符则用 --name 兜底(A Step6 已写兜底分支)