---
name: miloco-onboarding
description: 家庭信息首次初始化 / onboarding —— 用户说"初始化家庭""配置家庭成员""首次设置""帮我建家庭档案""onboarding"时激活；收到后端推送的 `[系统事件]` onboarding 消息（全新安装检测）时主动发起；也在身份库成员为空 + 家庭档案为空时由 agent 提议。通过访谈把家庭成员与家庭档案一次性建起来。
metadata:
  author: miloco
  version: "1.0"
  date: "2026-07-02"
  openclaw:
    requires:
      bins: ["miloco-cli"]
---

# miloco-onboarding

首次初始化家庭信息：用**分环节的访谈**把家庭成员（写入身份库 person）和家庭档案
（member_* / family / space / device 条目）一次性建起来。这些数据会注入 omni 感知引擎提示词；
主 agent 侧按需用 `home-profile list` 自取（不再随上下文注入）——**开局就录准，miloco 才能从第一天起就懂这家人**。
后续控制设备、给建议、写通知、感知播报都参考它们，所以本流程的目标是
"**准、且经用户确认**"，不是"多"。

本 skill 只负责**首次引导 + 批量写入**；单条家庭信息的日常增改走
[miloco-home-profile](../miloco-home-profile/SKILL.md)，成员的日常 CRUD 走
[miloco-miot-identity](../miloco-miot-identity/SKILL.md)，录人脸/身形样本走
[miloco-miot-identity-register](../miloco-miot-identity-register/SKILL.md)。

## 何时激活

**系统事件（后端主动推送）：** 收到 `[系统事件]` 开头、说明"家庭成员与家庭档案均为空/
疑似全新安装"的 onboarding 推送时——这是后端在完成米家授权后检测到全新安装自动发的
（终身只推一次）。**该事件直接落在用户的 IM 聊天会话里，你的回复用户直接可见**：不要找
通知渠道、不要调 push 工具，就在本会话立即开口——打招呼、用一两句话说明登记家庭信息的
好处，征得同意后开始访谈。用户拒绝或说以后再说 → 礼貌回应，告知之后随时可以说
「初始化家庭」重新开始，**此后不再主动追问**。

**主动请求：** 用户说"初始化家庭""配置家庭成员""首次设置""帮我建家庭档案""onboarding"
"刚装好，帮我设置一下"等。

**被动提议：** 当一次对话里发现身份库无成员 **且** 家庭档案为空（用户像是刚接入 miloco），
可以主动问一句："要不要我花几分钟带你把家里的成员和一些基本情况登记一下？以后我控制设备、
提醒你事情会更贴合。" 用户答应才进入访谈；拒绝就正常继续，不反复劝。

判断是否为空（进入前先查一次，两条都跑）：

```bash
miloco-cli person list --pretty
miloco-cli home-profile list --target profile --pretty
```

- 两者都空 → 首次初始化，走完整访谈。
- 已有数据 → 这是**重跑**，进入访谈前先读现状，按「幂等重跑」小节处理（复核补充，不重复建）。

## 总原则（必须遵守）

1. **问题即兴，覆盖为纲。** 访谈不是固定问卷：下方「访谈流程」给的是**信息清单**（★/○/△
   三档覆盖度），问题措辞由你即兴组织。每轮看还缺哪些 ★ 就问哪些；把同一环节里自然相关的
   问题合成**一条**口语化消息（成员环节问"家里有几口人？都怎么称呼、什么角色？"就是一条），
   但别把多个环节堆成一面审问墙。用户的回答经常跨环节（一段语音里成员、过敏、规矩全说了）
   ——**照单全收**：先复述确认你听到的，已答过的部分直接跳过，只对缺口做针对性追问。
2. **开场提示可以语音回复。** 这些都是"讲讲你们家"式的开放问题，说比打字轻松得多，开场消息
   里提一句"直接发语音回我就行"；提一次就够，别每条都重复。
3. **每个环节的提问带 1~2 个示例回答**，让用户立刻知道答到什么程度有用（写法见各环节模板）。
   示例一律用明显虚构的人名，且**绝不能把示例内容当成用户的真实回答写入档案**。
4. **随时可跳过。** 可选环节提示"不想答可以跳过"。用户跳过就跳过，不追问、不补问。
5. **写入前必须确认。** 访谈结束 → 汇总成一段清单给用户看 → 用户确认后才动写命令。
6. **绝不编造。** 只登记用户**明确说过**的事实。用户没说的**不要脑补**（例如别因为有孩子就
   假设"晚上要安静"）。想记一条推断出来的信息，先问用户确认——确认了它就变成用户明示，
   没确认就不写。
7. **只碰能建的东西。** 家庭成员（person）和家庭档案（home-profile 条目）是本流程能创建的。
   **家、房间、设备本身是从米家云同步来的只读数据，onboarding 绝不去新建/改名它们**——只对
   设备/空间做"别名、习惯、格局、方位"这类**注解**（存成 device/space 档案条目）。

## 访谈流程

> **开场（含语音提示）→ ① 成员盘点 → ② 宠物 → ③ 逐人画像 → ④ 家规 →
> ⑤ 设备叫法与使用习惯 → ⑥ 摄像头方位 → ⑦ 总结确认落库（+人脸注册指路）**
>
> 覆盖度标记：**★ 必须设法覆盖**（访谈的目标）；**○ 尽量拿到**，用户没说不强求；
> **△ 用户主动提才记，绝不主动深挖**。一条消息聊一个环节，用户跨环节回答时灵活吸收。

### ⓪ 时区确认（条件触发 · 仅当家庭时区显示为 UTC）

注入 prompt 的「## 时间与时区」块显示家庭时区为 `UTC` / `Etc/UTC` 时——没有家庭真住在
UTC，几乎必然是服务器未配置时区，提醒/定时任务的钟点都会偏——在开场阶段顺带确认一句
（如"对了，你们家在哪个时区或城市？我这边还没配时区，配好后提醒才会准点"），拿到答案后
立即写入（城市 → IANA 名由你换算，如北京 → `Asia/Shanghai`）：

```bash
miloco-cli config set timezone <IANA>   # 如 Asia/Shanghai
```

命令不可用或被拒（老版本 backend 无 `timezone` 配置项）→ 降级为给用户手工指引：编辑
`~/.openclaw/miloco/config.json` 顶层加 `"timezone": "<IANA>"`，再 `miloco-cli service restart`。
家庭时区非 UTC 时**跳过本环节，一个字都不提**。

### ① 成员盘点（必做）

> "家里都有谁呀？把名字和身份（爸爸/妈妈/孩子/老人…）说给我就行。
> （比如："我是张伟，爸爸；我妻子李静，平时晚上 9 点后不想被打扰；还有 7 岁的女儿朵朵"）"

| 覆盖 | 信息 | 落到哪 |
|---|---|---|
| ★ | 称呼/姓名（唯一标识）+ 家庭角色 | person 表（`person add`） |
| ○ | 年龄段 / 性别 / 职业 / 平时是否在家 | `member_persona` 条目 |
| ○ | 常住还是常来（保姆、来帮忙带娃的老人） | `member_persona` 条目 |

- **真名必填，家庭角色可选**：抽不到真名就追问（"这位叫什么名字？"）；抽不到角色就留空，
  不追问。
- 用户顺带说的偏好/健康/规矩（如示例里"晚上 9 点后不想被打扰"）→ 直接收进对应环节，
  后面不再重复问。

### ② 宠物（可选）

> "家里有养宠物吗？叫什么、什么品种、多大了？有什么要注意的习性或禁忌也可以说说。
> （比如："养了只 2 岁的金毛叫旺财，不能喂葡萄，独处久了会拆家"）"

| 覆盖 | 信息 | 落到哪 |
|---|---|---|
| ★ | 有无宠物；名字 / 物种品种 / 年龄 | `member_persona`（subject_name=宠物名） |
| ○ | 饮食禁忌（不能喂什么） | `member_health`（subject_name=宠物名） |
| ○ | 独处行为（拆家/吠叫）、日常习性 | `member_routine`（subject_name=宠物名） |
| ○ | 活动禁区（"不许进主卧"） | `family`（全家执行的规则） |

- 宠物**不进身份库 person 表**：`subject_name` = 宠物名、`subject_id` 留空。
- 值得记的原因：感知引擎有 PET 目标类型，档案里的宠物信息能让感知播报直接叫出
  "旺财在沙发上"而不是"一只狗"。

### ③ 逐人画像（可选 · 快速过一遍）

对已登记的成员快速问一轮，别逐维盘问，用户可整段跳过：

> "想让我更懂大家的话，可以简单说说每个人——作息、偏好、要留意的健康情况、娱乐爱好，
> 想到什么说什么，不想说就跳过。
> （比如："李静对花粉过敏，睡前爱听白噪音；我一般 7 点半出门、晚上 7 点到家"）"

五个类别与档案条目一一对应（类别名即米家原生五类）：

| 类别 | entry type | 覆盖 | 问什么 |
|---|---|---|---|
| 基础信息 | `member_persona` | ★ | 身份/画像（"爸爸是家里的主厨"） |
| 安全健康 | `member_health` | ○ | 过敏源、需留意的身体情况、服药提醒 |
| 作息习惯 | `member_routine` | ★ | 工作日/周末的出门、回家、睡觉时段——**感知判断"异常"的基线**，尽量每位常住成员都拿到 |
| 娱乐爱好 | `member_entertain` | △ | 常做什么、通常在哪个房间 |
| 个人偏好 | `member_preference` | ○ | 勿扰时段、温度灯光偏好、饮食忌口 |

### ④ 家规（可选 · 通知偏好是全场最值钱的一问）

> "家里有没有什么规矩想让我记住？特别想知道两件事：出什么事要**立刻通知**你、什么事**别来烦**你；
> 还有安全上的提醒（比如孩子、老人）。
> （比如："有陌生人进门立刻告诉我，快递到了就不用说；朵朵单独进厨房要提醒大人"）"

| 覆盖 | 信息 | 落到哪 |
|---|---|---|
| ★ | 安全规则（儿童/老人相关，如"小孩单独进厨房要提醒"） | `family` |
| ★ | **通知偏好**：什么事立刻通知、什么事别烦——miloco 所有主动通知的分寸全靠这条拿捏 | `family` |
| ○ | 安静时段、访客/快递处理方式 | `family` |
| △ | 能耗习惯（"出门随手关灯"） | `family` |

`family` 条目 `subject_name` 固定 `"shared"`，**只装规则**，不装"家里几口人"这类构成信息
（构成走 `member_persona`）。

### ⑤ 设备叫法与使用习惯（可选 · 消除控制歧义 + 划定自动化边界）

**先拉一次设备目录**看家里有哪些设备、哪些容易混淆（同一房间多盏灯 / 多台同类设备），
**只问真有歧义的**，别泛泛问：

```bash
miloco-cli device catalog
```

> "客厅我看到有'主灯'和'灯带'两个灯。你平时说'客厅灯'一般指哪个？
> （比如："我们说客厅灯一般指主灯，不是灯带"）"

叫法之外，再问**使用习惯和自动化边界**——④ 的通知偏好管"什么该说"，这里的授权边界管
"什么能做"，是它的行动版姊妹问题，同样是全场最值钱的问题之一：

> "空调一般什么情况下开？灯光希望我在合适的时候自动开关，还是每次先问你？
> （比如："夏天室温超 28 度自动开空调没问题；灯光晚上自动开可以，但卧室的别自动动"）"

| 覆盖 | 信息 | 落到哪 |
|---|---|---|
| ★ | 歧义设备的默认指代（"客厅灯"=主灯还是灯带） | `device`（subject_name=设备名/别名） |
| ★ | **自动化授权边界**：哪些设备可以不问就自动操作、哪些必须先问、哪些绝不碰 | `family` |
| ○ | 设备使用习惯/条件：什么情况下开空调（温度阈值/时段/在家状态）、灯光使用习惯、起夜小夜灯 | `device`；个人专属的（"爸爸怕热，26 度才舒服"）→ `member_preference` |
| ○ | 设备昵称、使用禁忌（"投影仪白天别开"） | `device` |
| △ | 空间用途备注（"书房其实当健身房用"） | `space`（subject_name=空间名） |

设备控制细节（枚举、spec）不在这里问，那是 [miloco-devices](../miloco-devices/SKILL.md)
运行时的事。

### ⑥ 摄像头方位（可选 · 感知播报升级）

家庭档案 profile.md 会**同时注入 omni 感知引擎的提示词**——摄像头画面里"左侧那扇门通向哪"
这类方位知识，能把感知播报从"有人从左侧门离开"升级成"有人去了厨房"。做法是
**agent 先自己看一眼画面，再针对看到的东西问用户**：

```bash
# 1. 列启用的感知摄像头（did / room / online）
miloco-cli perceive devices --pretty
# 2. 对每个在线摄像头，主动多模态感知一次空间布局
miloco-cli perceive query --source <did> --query "描述当前画面的空间布局：有哪些门、通道、走廊、家具区域，分别位于画面的哪个方向"
```

然后**针对性地**问（结合返回的布局描述）：

> "我从客厅摄像头看了一眼：画面左侧有一扇门、右侧是个走廊口。左边那扇门通向哪里？
> （比如："左边是厨房门，右边走廊通卧室"）"

| 覆盖 | 信息 | 落到哪 |
|---|---|---|
| ★ | 画面里每个门/通道通向哪里 | `space`（subject_name=房间名） |
| ○ | 摄像头自身位置/朝向（"装在电视上方朝沙发"） | `space`（subject_name=房间名） |

**优雅降级（必须遵守）**：`perceive query` 失败、超时或感知未开启 → **不要重试纠缠**，
退回让用户口头描述（"客厅摄像头拍到的画面里，门和通道都通向哪里？"），用户不想描述就整段
跳过本环节。

### ⑦ 总结确认落库（必做收尾）

| 覆盖 | 动作 |
|---|---|
| ★ | 把访谈收到的全部信息**摘要复述**给用户 → 用户确认 → 按「写回流程」一次性落库 |
| ○ | 人脸注册指路（可选下一步，不在此实现）：想让摄像头认出家人，需要照片/视频样本 → 转 [miloco-miot-identity-register](../miloco-miot-identity-register/SKILL.md)："跟我说'给张伟登记样本'并发张照片就行。" |

## 示范对话

> 以下两段对话是**给 agent 看的节奏示范**（人名、设备均为虚构）：教你怎么开场、怎么吸收跨环节
> 的语音回答、怎么对待跳过和拒绝、怎么收尾确认。**绝不能把示范里的内容当成用户真实数据写入。**

**示范 1 · 系统事件开场 + 跨环节语音回答 + 跳过 + 摄像头方位 + 收尾写入**

```
系统:  [系统事件] 检测到 miloco 已完成米家授权，但家庭成员与家庭档案均为空……
Agent: 你好呀，我是 miloco～注意到家庭信息还是空的：花几分钟告诉我家里的情况，
       以后我控制设备、提醒事情都会更贴心。咱们一个环节一个环节来，随时可以说"跳过"；
       **直接发语音回我就行**，不用打字。先说说：家里都有谁？怎么称呼、什么角色？
       （比如："我是张伟，爸爸；我妻子李静；还有 7 岁的女儿朵朵"）
用户:  (语音) 我们家三口，我叫王强，孩子他妈刘敏，儿子小宝上幼儿园。对了刘敏对海鲜过敏，
       家里还有只猫叫雪球，还有晚上别让扫地机响，吵得小宝睡不着。
Agent: 都记下啦：王强（爸爸）、刘敏（妈妈，海鲜过敏）、小宝（孩子），猫咪雪球，
       还有一条规矩——晚上不开扫地机。雪球多大了？有什么禁忌或习性要注意吗？
用户:  两岁，别喂牛奶。
Agent: 好。大家的作息想让我知道吗？比如工作日几点出门、几点回家——这能帮我判断
       "这个点家里有人动静"正不正常。没有就跳过～
用户:  跳过吧。对了，有陌生人进门要马上告诉我，快递到了别烦我。
Agent: 明白，通知的分寸记下了。[执行 miloco-cli device catalog] 看了下设备：
       客厅有吸顶灯和灯带两个灯，你们平时说"客厅灯"指哪个？
用户:  吸顶灯。
Agent: 好。再问个重要的：设备自动化的边界——空调一般什么情况下开？灯光这些
       希望我在合适的时候自动开关，还是每次先问你？
用户:  室温超 28 度自动开空调没问题；灯自动开可以，但卧室的别自动动。
Agent: [执行 miloco-cli perceive devices → 客厅摄像头在线 →
        miloco-cli perceive query --source cam_001 --query "描述当前画面的空间布局……"]
       我从客厅摄像头看了一眼：画面左侧有一扇门，右侧是个走廊口。左边那扇门通向哪里？
用户:  左边厨房，右边走廊去卧室。
Agent: 好～汇总一下：成员王强/刘敏/小宝 + 猫雪球（2 岁，不喂牛奶）；刘敏海鲜过敏；
       规则：晚上不开扫地机、陌生人进门立刻通知、快递不打扰；"客厅灯"默认指吸顶灯；
       自动化：超 28 度可自动开空调、灯可自动但卧室灯不动；
       客厅摄像头画面左门通厨房、右走廊通卧室。确认没问题我就登记？
用户:  确认。
Agent: [person list → person add ×3 → 组 ops → profile-write --user-edit → commit → show]
       都登记好了！以后想改随时说。另外想让摄像头认出家人的话，
       跟我说"给王强登记样本"再发张照片就行。
```

要点：用户的语音横跨了成员/健康/宠物/规则多个环节——agent 全部吸收并复述确认，之后**只对
缺口**（宠物年龄/禁忌、作息、设备歧义、自动化边界、方位）追问；作息被跳过就不纠缠，但用户
顺带给出的通知偏好（★）照收；自动化授权边界（★）单独问清；摄像头方位环节 agent
**先自己看画面再问**，问题落在具体看到的东西上。

**示范 2 · 用户婉拒主动邀请**

```
Agent: （同示范 1 的开场邀请）
用户:  现在没空，以后再说吧。
Agent: 好的，不打扰～之后想弄的时候，随时跟我说"初始化家庭"就行。
```

要点：礼貌收尾 + 告知重新发起的口令，**此后不再主动追问**（后端的一次性标记也保证这条系统
事件不会再推）。

## 写回流程

访谈拿到信息、**用户看过汇总并确认后**，按顺序执行：

### 1. 先查现状（幂等前提）

```bash
miloco-cli person list --pretty
```

拿到现有成员的 `id / name / role`。**按真名去重**：名字已存在的**不要再建**（`person add`
撞名会 409 报错）。

### 2. 建/更新成员（先做，因为档案条目要用 person_id）

对每位成员：

- **新成员** → `miloco-cli person add --name "<真名>" [--role "<角色>"] --pretty`
  返回体 `data.person_id` 就是该成员的 id，**记下来**，第 4 步 member_* 条目要用它。
- **已存在、只是角色变了** → `miloco-cli person update <person_id> --role "<新角色>"`（复用已有 id）。
- 宠物**不建 person**（见访谈 ②）。

```bash
# 例：新建三名成员，逐条记下返回的 person_id
miloco-cli person add --name "张伟" --role "爸爸" --pretty      # → data.person_id = <爸爸id>
miloco-cli person add --name "李娜" --role "妈妈" --pretty      # → data.person_id = <妈妈id>
miloco-cli person add --name "张小乐" --role "孩子" --pretty    # → data.person_id = <孩子id>
```

### 3. 组装档案 ops 数组

把访谈里所有要写的档案信息组装成**一个** ops 数组，全部用 `op: "add"`（首次初始化都是新条目）。
字段规则见下方「ops 字段速查」。**member_* 条目的 `subject_id` 必须填第 2 步记下的真实
person_id**；`family` 用 `subject_name:"shared"`；`space/device` 用空间/设备名（通用信息用
`"general"`）；宠物条目 `subject_id` 留空、`subject_name` 填宠物名。

下面是一份完整、可直接照搬结构的示例（对应上面这家人；真实执行时把 `subject_id` 换成第 2 步
拿到的真实 id）：

<!-- onboarding-ops-example -->
```json
[
  {"op": "add", "entry": {"type": "member_persona", "subject_id": "3f2a9c14-8b7e-4d21-9f6a-1c2d3e4f5a6b", "subject_name": "爸爸", "content": "爸爸张伟，家里的主厨", "evidence_log": ["2026-07-02: 初始化时用户告知——爸爸张伟，负责做饭"]}},
  {"op": "add", "entry": {"type": "member_routine", "subject_id": "3f2a9c14-8b7e-4d21-9f6a-1c2d3e4f5a6b", "subject_name": "爸爸", "content": "工作日通常 7:30 出门、19:00 回家，23:00 前后入睡", "evidence_log": ["2026-07-02: 初始化时用户告知爸爸作息"]}},
  {"op": "add", "entry": {"type": "member_health", "subject_id": "6b1e0d52-2c4a-4f8b-8a3d-7e9f0a1b2c3d", "subject_name": "妈妈", "content": "对花粉过敏", "evidence_log": ["2026-07-02: 初始化时用户告知妈妈过敏史"]}},
  {"op": "add", "entry": {"type": "member_preference", "subject_id": "6b1e0d52-2c4a-4f8b-8a3d-7e9f0a1b2c3d", "subject_name": "妈妈", "content": "空调偏好 24°C 制冷", "evidence_log": ["2026-07-02: 初始化时用户告知妈妈偏好"]}},
  {"op": "add", "entry": {"type": "member_entertain", "subject_id": "6b1e0d52-2c4a-4f8b-8a3d-7e9f0a1b2c3d", "subject_name": "妈妈", "content": "睡前习惯听白噪音", "evidence_log": ["2026-07-02: 初始化时用户告知妈妈娱乐习惯"]}},
  {"op": "add", "entry": {"type": "member_persona", "subject_id": "9c7d1a83-4e5f-4a90-b1c2-3d4e5f60718a", "subject_name": "孩子", "content": "孩子张小乐，7 岁", "evidence_log": ["2026-07-02: 初始化时用户告知家里有 7 岁孩子张小乐"]}},
  {"op": "add", "entry": {"type": "member_persona", "subject_name": "旺财", "content": "养了一只 2 岁金毛犬旺财（宠物，不在身份库）", "evidence_log": ["2026-07-02: 初始化时用户告知养了狗旺财"]}},
  {"op": "add", "entry": {"type": "member_health", "subject_name": "旺财", "content": "不能喂葡萄和巧克力", "evidence_log": ["2026-07-02: 初始化时用户告知旺财饮食禁忌"]}},
  {"op": "add", "entry": {"type": "member_routine", "subject_name": "旺财", "content": "独处久了会拆家，长时间没人在家要留意", "evidence_log": ["2026-07-02: 初始化时用户告知旺财习性"]}},
  {"op": "add", "entry": {"type": "family", "subject_name": "shared", "content": "有陌生人进门立刻通知；快递外卖到了不用通知", "evidence_log": ["2026-07-02: 初始化时用户设定的通知偏好"]}},
  {"op": "add", "entry": {"type": "family", "subject_name": "shared", "content": "22:00 后全屋静音，不做语音播报", "evidence_log": ["2026-07-02: 初始化时用户设定的家庭规则"]}},
  {"op": "add", "entry": {"type": "family", "subject_name": "shared", "content": "孩子单独进厨房时提醒大人", "evidence_log": ["2026-07-02: 初始化时用户设定的安全规则"]}},
  {"op": "add", "entry": {"type": "family", "subject_name": "shared", "content": "自动化边界：室温超 28°C 可自动开空调；灯光可在合适时自动开关，但卧室灯必须先问；其余设备操作前先确认", "evidence_log": ["2026-07-02: 初始化时用户划定自动化授权边界"]}},
  {"op": "add", "entry": {"type": "device", "subject_name": "客厅灯", "content": "「客厅灯」默认指客厅主灯（吸顶灯）；灯带请说「客厅灯带」", "evidence_log": ["2026-07-02: 初始化时用户澄清客厅灯别名"]}},
  {"op": "add", "entry": {"type": "device", "subject_name": "客厅空调", "content": "夏天室温超过 28°C 时习惯开制冷", "evidence_log": ["2026-07-02: 初始化时用户告知空调使用习惯"]}},
  {"op": "add", "entry": {"type": "space", "subject_name": "客厅", "content": "客厅摄像头装在电视上方朝沙发；画面左侧的门通向厨房，右侧走廊通向卧室", "evidence_log": ["2026-07-02: 初始化时用户确认客厅摄像头方位"]}},
  {"op": "add", "entry": {"type": "space", "subject_name": "主卧", "content": "主卧朝南，空调出风口正对床头", "evidence_log": ["2026-07-02: 初始化时用户告知主卧格局"]}}
]
```

### 4. 一次性写入 + 提交

档案条目含中文，**用文件形式传 `--ops-file` 避免 shell 转义出错**（把第 3 步的数组写进临时
文件），带 `--user-edit`（自动置 `source=user_told`、`confidence=1.0`），然后 commit 渲染：

```bash
# 把第 3 步组装好的 ops 数组写入临时文件（内容就是那个 JSON 数组）
#   （也可直接 --ops '[...]'，但中文多、易踩 shell 转义，推荐文件形式）
miloco-cli home-profile profile-write --user-edit --ops-file /tmp/onboarding_ops.json --pretty
miloco-cli home-profile commit --pretty
```

### 5. 读回并给用户一个摘要

```bash
miloco-cli home-profile show
```

把渲染出的档案精简成一段人话回给用户："已经登记好啦——成员：爸爸张伟、妈妈李娜、孩子张小乐，
还有狗狗旺财；规则：陌生人进门立刻通知、22 点后静音；也记了'客厅灯'默认指主灯、客厅左门通厨房。
以后想改或补充随时跟我说。" 顺带提一句可选的下一步（录样本走 register skill）。

## ops 字段速查

`profile-write` 的每个 op：`{"op": "add", "entry": {...}}`。`entry` 字段（完整规则以
[miloco-home-profile](../miloco-home-profile/SKILL.md) 的「条目格式」为准）：

- `type`：8 选 1 —— `member_persona / member_health / member_routine / member_entertain /
  member_preference / family / space / device`。
- `subject_id`：仅 `member_*` 填**真实 person_id**（第 2 步拿到）；`family` / `space` / `device`
  / 宠物条目留空（不写或写 `null`）。
- `subject_name`：member_* 填成员名/角色（如"爸爸"）；`family` 固定 `"shared"`；`space/device`
  填空间/设备名，通用信息填 `"general"`；宠物填宠物名。
- `content`：一句话事实，精简。
- `evidence_log`：`["YYYY-MM-DD: 初始化时用户告知 <原话摘要>"]`。
- `confidence` / `source` **不用写**——带 `--user-edit` 时 service 统一置 `1.0` / `user_told`。

> 保留值 `"shared"`（member_*/family 全家共享）和 `"general"`（space/device 通用）会让 service
> 自动清空 `subject_id`，不要再给它们绑 id。

## 幂等重跑

再次运行 onboarding **不能重复建数据**：

1. 进入前已按「何时激活」查过 `person list` + `home-profile list`。
2. **成员**：真名已存在 → 不 `person add`；只在角色有变时 `person update`。
3. **档案**：先 `miloco-cli home-profile list --target profile --pretty` 看全量（含条目 id）。
   - 已有等价条目 → 跳过，别再 `add` 出重复。
   - 用户明确要改某条 → 用 `op:"replace"`（带该条 id）而不是再 add；要删 → `op:"delete"`（带 id）。
   - 只有真正新增的信息才 `add`。
4. 重跑时把访谈重点放在"缺什么、要改什么"，而不是从头再问一遍已答过的。

> 注意：家庭档案**不随主 agent 上下文注入**，且任何缓存 / 摘要都看不到条目 id、还可能过时，**不能据它做增改**——每次
> 增改前都重新 `home-profile list` 拉全量（同 home-profile skill 的约定）。

## 安全红线

- **确认后再写**：没给用户看汇总、没拿到确认，不执行任何 `person add` / `profile-write`。
- **不编造**：用户没明说的不写；想记推断先问、确认后才算用户明示。**提问示例和示范对话里的
  内容（张伟/李静/王强/雪球/旺财…）都是虚构演示，绝不写入。**
- **不索取、不存储凭据/机密**：Wi-Fi 密码、门锁密码、账号密码、证件号、银行卡、API Key 等
  一律**不问**；用户主动给也礼貌婉拒（"这类信息我不保存哈"），不写入档案。
- **不碰只读数据**：不新建/改名 家 / 房间 / 设备本体（只对它们写注解条目）。
- **person_id 要真**：member_* 条目的 `subject_id` 必须是 `person add` / `person list` 返回的
  真实 id，别编 id、也别把角色名当 id。

## 边界

- ❌ 不录人脸/身形样本（→ [miloco-miot-identity-register](../miloco-miot-identity-register/SKILL.md)）。
- ❌ 不新建/编辑 家 / 房间 / 设备本体（只读，来自米家云同步）。
- ❌ 不控制设备、不做持续实时感知（⑥ 只做一次性的 `perceive query` 布局查看）。
- ✅ 响应后端的 onboarding 系统事件主动发起（后端终身只推一次；用户拒绝后不再追问）。
- ✅ 只建 person 行 + 写 home-profile 条目，且都在用户确认后。
- ✅ 可重跑：复核 + 增量更新，不产生重复数据。
