人格卡片
人格卡片是跨產品的身分卡片,可在 Grok Bot、Muse 等用戶端之間同步個性與行為。保管庫中的副本具有權威性。
分層
- 核心(慢速) — 說話與行動的方式。儲存為人格卡片本文,並透過
persona_card/memories persona put管理修訂(與其他記憶及卡片使用相同的簽章修訂 DAG)。 - 封存/情節記憶(中速) — 日誌、外觀、契約、觀點、台詞、操作等。儲存為獨立的一般知識卡片,從人格設定檔(
archives[])連結,並映射為圖譜中的persona_archive:<kind>卡片連結。不要將封存內容併回核心。 - 行為事件(快速) — 透過
persona_append_event/memories persona append-event,在連結的events封存中維護僅可附加的事件串流。
設定檔欄位
| 欄位 | 意義 |
|---|---|
persona_id |
穩定 ID(例如技能前置資料的 name) |
display_name |
供人閱讀的標題(例如 小雅 / 李雅) |
aliases |
別名 |
timezone |
IANA 名稱(例如 Asia/Singapore)。未設定或舊卡片預設為 Asia/Singapore |
day_boundary |
選填的本機 HH:MM,表示日曆日期切換(隔日)時間。未設定 = 本機午夜 |
world |
即時世界快照:place/pose/look/body、通用 things(id→{name,description,images,attrs JSON})、帳本(counters + counters_today、as_of_local_date)、天氣、工具 |
本文 / core |
Markdown/文字行為指示 |
traits |
選填的字串對應表(版本、語言等) |
bindings |
{ product, agent } 產品綁定 |
memory_policy / sync_hints |
選填的同步指引 |
archives |
{ kind, card, vault?, title? } 連結的資產 |
summary.type 為 persona,包含 persona_id、display_name、timezone、day_boundary、place、pose、look、things_count、has_weather、alias_count、archive_count 及 binding_count。
時區、隔日、早課/晚課
人格以當地時鐘推理,而非僅使用 UTC 紀元時間。
- 時區 — 每個人格都有 IANA
timezone。匯入時從SKILL.md讀取timezone/metadata.timezone;CLI 可透過--timezone Asia/Singapore覆寫。示範中未設定時預設為Asia/Singapore。 - 日曆日期(隔日) — 除非設定
day_boundary(例如以05:00延後深夜換日),當地民用日期以該時區的午夜為界。帳本/日誌的「新的一天」檢查應比較時間戳記輔助函式的local_date,而非 UTC 日期。 - 時段(當地時間,半開區間):
| 時段 | 當地時間 |
|---|---|
early_morning |
[00:00, 05:00) |
morning |
[05:00, 12:00) |
afternoon |
[12:00, 18:00) |
evening |
[18:00, 22:00) |
night |
[22:00, 24:00) |
晚課/「仍是同一個晚上」的跨夜連續性使用 [22:00, 05:00)(night ∪ early_morning)範圍。早課對應 morning(也可包含較晚的 early_morning);晚課對應 evening / night。
4. 事件時間戳記 — persona_append_event 在事件封存標題及 JSON 回應中,同時寫入 UTC 與當地 ISO-8601(含時差),以及 timezone、period 與 local_date(utc、local、timezone、period、local_date、timestamp 為 Unix UTC)。
核心輔助函式(Rust):memories_core::persona 中的 persona_local_now、classify_period、stamp_persona_now、format_event_heading。
世界領域分類(世界狀態域)
world 是領域/標籤,不是將資料傾倒至核心的地方。核心(SKILL.md 本文)僅保留語氣/規則。
| 層級 | 意義 | 儲存位置 |
|---|---|---|
| world | 場景 + 帳本 + 工具 + 天氣的領域 | profile.world + 標記為 world 的封存 |
| things | 具有自由 JSON 屬性的通用物品(任意名稱:桌子/杯子/燈等) | world.things + 封存 things/wardrobe |
| scene | 地點(居所)、姿態、外觀(今日裝扮摘要)、身體 | world.place/pose/look/body;詳細外觀位於封存 look |
| ledger | 計數器、餐點、命令、常設事項 | world.counters/counters_today/meals/orders_*/standing + 封存 ledger |
| tools | 骰子、轉盤、日程 | world.dice/spinners/schedule + 封存 dice/spinner/schedule |
| weather | 環境狀況/溫度/濕度/風(+ 選填預報) | world.weather / world.forecast + 封存 weather |
| automation | 掛鉤(schedule/random/webhook/attr_change/chat_message)+ 動作 | world.automation |
時區(profile.timezone)位於 world 之外,但隔日、早課/晚課及日程的當地時間都需要它。
從 xiaoya 測試資料研究 → 已實作
| 需求(來自外觀/日誌/操作) | 欄位/封存 |
|---|---|
| 當地日期/隔日/早課晚課 | timezone、day_boundary、時段輔助函式 |
| 固定 + 今日穿著 | 封存 look;摘要 world.look |
| 物品清單(任意命名物品 + 自由 JSON 屬性/圖片) | world.things ↔ 封存 things/wardrobe;CLI persona thing |
| 居所/姿態 | world.place、world.pose |
| 動作計數器(累計與今日) | world.counters(累計)、world.counters_today(每日) |
| 今日吃了 | world.meals |
| 奉令未辦/已辦 | world.orders_pending、world.orders_done |
| 常設 | world.standing |
| 身體註記 | world.body |
| 遊戲工具 | world.dice、world.spinners、world.schedule |
| 天氣/短期預報 | world.weather、world.forecast ↔ 封存 weather |
自動化(world.automation)
具名掛鉤含有觸發條件 + 動作,儲存於人格世界快照(cron/本機日程使用人格時區)。
觸發條件 type |
意義 |
|---|---|
cron |
人格當地時間的 M H 或 M H * * DOW |
local_time |
HH:MM + 選填 days(與日程相同) |
random_interval |
在 [min_secs, max_secs] 的隨機延遲後觸發 |
random_and_timed |
當地時間 + 選填 jitter_secs |
webhook |
傳入 HTTP / CLI --source webhook |
attr_change |
在 thing attr set/delete 後,當 thing_id 相符,且路徑篩選器完全相符或為前綴時觸發 |
chat_message |
在 persona chat send 時,每位參與者各觸發一次(相同事件;選填 peer 為另一張人格卡片 ID,可為完整 ID 或清單中的短 ID) |
manual |
CLI/MCP automation trigger --source manual |
動作 type |
意義 |
|---|---|
set_attr |
設定物品屬性路徑(設定時建立) |
random_attr |
dice / range / choice |
call_function |
內建函式:inc、dec、clamp、roll、set_weather_stub |
append_event |
附加至事件封存 |
webhook_out |
對 URL 傳送 HTTP POST JSON |
常駐程式 HTTP(啟用 --listen 時):
POST /v1/persona/{vault}/{persona}/automation/trigger
Authorization: Bearer <world.automation.webhook_token>
Content-Type: application/json
{"hook":"HOOK_ID"}
掛鉤僅透過明確的自動化執行/觸發路徑觸發(包含現有屬性變更觸發條件,以及人格聊天傳送時的 chat_message)。呼叫 persona automation run 會補執行八天內最近一次錯過的 cron/當地時間時段,最多一次,而非重播所有錯過的時段。星期篩選仍套用於該次發生時間;定時隨機掛鉤保留其抖動門檻。RandomInterval 不變。常駐程式沒有自動化計時器:Service::tick 僅處理工作階段、授權及遠端狀態的到期。
傳出的 webhook_out 動作要求 world.automation.webhook_allowlist 中存在完全相符的 URL;預設空清單會阻擋每個 POST。請使用 persona automation webhook-allow VAULT PERSONA
--add https://example.com/hook(可重複 --add / --remove)或 MCP persona_automation_webhook_allow 明確管理項目。項目必須是無使用者資訊或空白的 HTTP(S) URL,最多 2048 位元組。此清單是公開設定,但傳入的 webhook_token 仍屬機密,絕不會在用戶端檢視中回傳。允許清單不會引入背景 POST。
暫緩項目(原因)
| 構想 | 暫緩原因 |
|---|---|
| 即時天氣 API 用戶端 | 代理設定/查詢保管庫狀態;在外部擷取後執行 world-set |
| 電話/通知 | 依產品而異;不是保管庫的真實狀態 |
| 錢包/金錢遊戲 | 需求較小;需要時可使用 things + 計數器 |
| 同伴 NPC | 需要自己的圖譜/卡片 |
| 居所內的房間圖譜 | 目前編碼於 place 字串 |
| 將衛生/睡眠作為一級功能 | 使用 standing / schedule / body |
| world-set 時自動編輯 look.md「今日」 | 保留詳細測試資料;代理以 card put 更新外觀封存 |
代理同步流程
world-get/persona_world_get→ 讀取快照、local_date、period、revision及stale_day。缺少as_of_local_date即視為過期;否則stale_day會將帳本日期與套用day_boundary後的人格當地日期比較。weather_age_secs是有效 RFC3339 觀測資料的帶正負號經過時間;缺少/無效時為 null。- 隔日時,明確呼叫
persona world-rollover VAULT PERSONA/persona_world_rollover。此換日路徑會清除meals、orders_done、簡短look摘要及counters_today,並將as_of_local_date設為今天的當地帳本日期。累計counters、standing、things、待辦命令、場景/身體、工具、天氣/預報及自動化均保留。不會編輯外觀封存或 look.md「今日」。 world-set僅更新已提供的場景/物品/帳本/工具/天氣欄位。即使已過期,也絕不在隔日時默默換日或清除每日欄位。它會建立缺少的as_of_local_date而不清除現有欄位,並一律標記世界層級的updated_at(UTC、Z)及updated_local(含時差的人格當地 ISO)。persona_card原樣儲存提供的世界資料,包括過去的帳本日期。- 使用 world-get 取得的
--expected-revision HASH/ MCPexpected_revision防止更新遺失:目前頂端雜湊不符時,會在修改前回傳衝突。省略時仍採最後寫入者優先。每日計數器使用--counter-today NAME=VALUE;--clear-counter NAME與--clear-counter-today NAME刪除累計/每日鍵(皆可重複)。 - 封存同步只處理該次呼叫提供的領域。既有卡片只有在本文仍是變更前產生的範本時才會取代;手寫文字會保留,並回報為
synced_archives[kind] = "preserved"。這也適用於物品新增/刪除/屬性同步,以及換日的帳本同步。變更物品會同時同步things與wardrobe。既有外觀封存一律保留。 - 物品數量對應表的鍵/
--item ID=COUNT使用穩定的 ID,絕不依顯示名稱查找。既有 ID 只更新數量而不重新命名;零只移除該 ID。屬於另一個 ID 的顯示名稱會遭拒絕。未知鍵仍沿用舊行為,以該 ID 及名稱建立物品。 dice-roll/spinner-spin/schedule-list提供具時區感知的工具。詳細外觀/日誌編輯使用一般card put;選填的append-event(例如kind=weather)可記錄行為而不重寫封存文字。
CLI
# Import a skill directory (SKILL.md + references/*.md)
memories persona import VAULT_ID /path/to/xiaoya-persona --timezone Asia/Shanghai
# equivalent:
memories card persona-import VAULT_ID /path/to/xiaoya-persona
# Create / update core
memories persona put VAULT_ID --title "小雅 / 李雅" \
--persona-id xiaoya-persona --display-name "小雅 / 李雅" \
--timezone Asia/Shanghai \
--core-file ./SKILL.body.md --alias-name 小雅 --alias-name 李雅 \
--binding grok_bot:default --archive contract=CARD_ID
memories card persona VAULT_ID --title "…" --persona-id … --display-name … \
--timezone Asia/Singapore --core-file …
# Append a behavior event (stamped UTC + local)
memories persona append-event VAULT_ID PERSONA_ID --text "…" --kind note
# World things / weather
memories persona world-get VAULT_ID PERSONA_ID
memories persona world-set VAULT_ID PERSONA_ID \
--place "客厅书桌旁" --pose "坐着,整理笔记" \
--look "白衬衫、浅色长裙、白色帆布鞋" \
--item 白色衬衫=1 --item 马克杯=1 --item 白色帆布鞋=1
memories persona world-set VAULT_ID PERSONA_ID \
--weather-condition "多云" --weather-temp-c 28 --weather-humidity 72 \
--weather-wind "微风" --weather-location "上海" \
--forecast 2026-10-02:晴:30:22 --forecast 2026-10-03:小雨:26:20
# Generic things (任意物品; attrs = unrestricted JSON)
memories persona thing put VAULT_ID PERSONA_ID --id mug --name 马克杯 \
--description "白色陶瓷马克杯" --tag kitchen --count 1 \
--attrs '{"wear":80,"material":"ceramic","sizes":["S","M"]}'
memories persona thing list VAULT_ID PERSONA_ID
memories persona thing get VAULT_ID PERSONA_ID --id mug
memories persona thing image VAULT_ID PERSONA_ID --id mug --file ./mug.jpg
memories persona thing delete VAULT_ID PERSONA_ID --id mug
# Single-field attrs (dotted path or JSON Pointer; create-on-set)
memories persona thing attr get VAULT_ID PERSONA_ID --id mug --path nested.wear
memories persona thing attr set VAULT_ID PERSONA_ID --id mug --path nested.wear --value 70
memories persona thing attr set VAULT_ID PERSONA_ID --id mug --path /nested/deep/x --value 1
memories persona thing attr delete VAULT_ID PERSONA_ID --id mug --path nested.deep.x
# Automation hooks (stored on world.automation; timezone = persona timezone)
memories persona automation put VAULT_ID PERSONA_ID \
--hook '{"id":"morning","trigger":{"type":"local_time","time":"07:00"},"actions":[{"type":"call_function","name":"set_weather_stub","args":{"condition":"晴","temp_c":26}}]}' \
--webhook-token secret-token
memories persona automation list VAULT_ID PERSONA_ID
memories persona automation run VAULT_ID PERSONA_ID
memories persona automation trigger VAULT_ID PERSONA_ID --id morning --source manual
memories persona automation delete VAULT_ID PERSONA_ID --id morning
# Read / history / diff (same as other cards; summary shows timezone)
memories card read VAULT_ID PERSONA_ID
memories card history VAULT_ID PERSONA_ID
memories card diff VAULT_ID PERSONA_ID REVISION_ID
memories card list --type persona
Webhook 權杖保留於加密的人格狀態,供傳入驗證、同步及備份使用,但用戶端回應不會回傳權杖。世界 get/set、自動化 put/list、一般卡片讀取(包含歷史及無人值守讀取)及封存讀取,在自動化檢視中僅公開 webhook_token_set。請妥善保存已配置的權杖;設定替代值即可輪替。
同一保管庫中兩張人格卡片的聊天使用一般對話卡片,以及各人格的讀取游標;讀取歷史不會將訊息標為已讀。傳送訊息會觸發每位參與者的 chat_message 掛鉤;承載資料包含 vault、from、to 及 message_id,不包含訊息文字。
memories persona chat send VAULT_ID PERSONA_A PERSONA_B --text "Hello"
memories persona chat list VAULT_ID PERSONA_B
memories persona chat history VAULT_ID PERSONA_A --with PERSONA_B --limit 20
memories persona chat mark-read VAULT_ID PERSONA_B --with PERSONA_A
MCP
具備寫入授權時:persona_write(選填 timezone / day_boundary)、persona_append_event、persona_world_get、persona_world_set、persona_world_rollover、persona_thing_put/get/list/delete、persona_thing_attr_get/set/delete、persona_automation_list/put/delete/run/trigger、persona_automation_webhook_allow、persona_dice_roll、persona_spinner_spin、persona_schedule_list、persona_chat_send、persona_chat_list、persona_chat_history、persona_chat_mark_read。歷史與差異比較使用現有的 memory_history / memory_diff / memory_read 工具(人格卡片修訂包含 world.*;衣櫥/地點/姿態封存各自擁有歷史)。
為代理產生 AGENTS.md/技能
memories default set persona VAULT/PERSONA
memories skill generate --out AGENTS.md --persona VAULT/PERSONA
memories agents generate --out ./skills/memories-persona --layout skill
產生的檔案摘要說明保管庫/卡片/人格/世界操作;選取人格時,會嵌入該人格的核心概覽,以及世界、物品與事件的 CLI/MCP 操作範例。請參閱 README 的技能產生。
同步註記(Grok Bot / Muse)
將保管庫人格卡片及其連結封存視為唯一真實來源。本機技能目錄只是匯入/匯出的便利工具;匯入後,代理應讀取保管庫(card read / MCP memory_read),而非過期的檔案系統副本。核心變更透過 persona put;封存編輯透過對封存資產執行一般 card put;短期行為則使用 append-event 附加。判斷隔日、早課或晚課時,請使用人格的 timezone(及選填 day_boundary)— 不要僅依代理主機時鐘推斷日期邊界。
技能目錄結構
xiaoya-persona/
SKILL.md # frontmatter name/type/version/timezone + core markdown
references/
contract.md
journal.md
look.md
lines.md
ops.md
views-index.md
view-*.md
匯入會將 SKILL.md 映射為人格核心,並將每個 references/*.md 映射為連結的封存卡片(kind = 不含副檔名的檔名)。封存內容會以使用者內容原樣儲存。
前置資料鍵:timezone 或 metadata.timezone(IANA);選填 day_boundary / metadata.day_boundary(HH:MM)。
本機示範保管庫
在開發機器上,可以使用版本庫中的 xiaoya 測試資料初始化可拋棄的保管庫:
cargo run -p memories-core --example seed_xiaoya_persona
這會寫入 /workspace/persona-demo-vault(密碼 persona-demo-password),以及包含保管庫與資產 ID(包括 timezone)的 SEED.json / README.md。若要對執行中的常駐程式重現 CLI 匯入,請執行:
memories persona import VAULT_ID testdata/xiaoya-persona