Tarjetas de persona
Las tarjetas de persona son tarjetas de identidad entre productos que sincronizan la personalidad y el comportamiento entre clientes como Grok Bot y Muse. La copia de la bóveda es la autoridad.
Capas
- Núcleo (lento) — cómo hablar y actuar. Se guarda como cuerpo de la tarjeta de persona y se versiona mediante
persona_card/memories persona put(el mismo DAG de revisiones firmadas que las demás memorias y tarjetas). - Archivos / episódicos (medio) — diario, apariencia, contrato, opiniones, frases, operaciones y similares. Se guardan como tarjetas de conocimiento normales separadas, enlazadas desde el perfil de persona (
archives[]) y reflejadas como enlaces de tarjetaspersona_archive:<kind>para el grafo. No reincorpore el contenido de los archivos al núcleo. - Eventos de comportamiento (rápido) — flujo de solo adición en un archivo
eventsenlazado mediantepersona_append_event/memories persona append-event.
Campos del perfil
| Campo | Significado |
|---|---|
persona_id |
ID estable (p. ej., name en los metadatos iniciales de la habilidad) |
display_name |
Título legible (p. ej., 小雅 / 李雅) |
aliases |
Nombres alternativos |
timezone |
Nombre IANA (p. ej., Asia/Singapore). Predeterminado: Asia/Singapore si no se establece o en tarjetas antiguas |
day_boundary |
HH:MM local opcional en que cambia el día del calendario. Sin establecer = medianoche local |
world |
Instantánea actual del mundo: place/pose/look/body, objetos genéricos things (id→{name,description,images,attrs JSON}), registro (counters + counters_today, as_of_local_date), tiempo meteorológico, herramientas |
cuerpo / core |
Instrucciones de comportamiento en Markdown/texto |
traits |
Mapa opcional de cadenas (versión, idioma, …) |
bindings |
Vinculaciones de producto { product, agent } |
memory_policy / sync_hints |
Orientaciones opcionales de sincronización |
archives |
Recursos enlazados { kind, card, vault?, title? } |
summary.type es persona, con persona_id, display_name, timezone, day_boundary, place, pose, look, things_count, has_weather, alias_count, archive_count y binding_count.
Zona horaria, cambio de día y sesiones matutinas / nocturnas
Las personas razonan con la hora local del reloj, no con épocas UTC sin contexto.
- Zona horaria — cada persona tiene una
timezoneIANA. La importación leetimezone/metadata.timezonedeSKILL.md; CLI puede sobrescribirla con--timezone Asia/Singapore. Valor predeterminado de la demostración si no se establece:Asia/Singapore. - Día del calendario — la fecha civil local cambia a medianoche en esa zona horaria, salvo que se establezca
day_boundary(p. ej.,05:00para un cambio de día de madrugada). Las comprobaciones de «nuevo día» del registro o diario deben compararlocal_datede las funciones de marcas temporales, no la fecha UTC. - Períodos del día (hora local, intervalos semiabiertos):
| Período | Horas locales |
|---|---|
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) |
La continuidad nocturna para las sesiones nocturnas o «sigue siendo la misma noche» usa [22:00, 05:00) (night ∪ early_morning). La sesión matutina corresponde a morning (y opcionalmente al final de early_morning); la sesión nocturna corresponde a evening / night.
4. Marcas de eventos — persona_append_event escribe tanto UTC como ISO-8601 local (con desplazamiento), además de timezone, period y local_date, en el encabezado del archivo de eventos y la respuesta JSON (utc, local, timezone, period, local_date, timestamp Unix UTC).
Funciones del núcleo (Rust): persona_local_now, classify_period, stamp_persona_now, format_event_heading en memories_core::persona.
Taxonomía de dominios del mundo
world es un dominio/etiqueta, no un volcado en el núcleo. El núcleo (cuerpo de SKILL.md) solo contiene voz y reglas.
| Capa | Significado | Almacenamiento |
|---|---|---|
| world | Dominio para escena + registro + herramientas + tiempo meteorológico | profile.world + archivos etiquetados world |
| things | Objetos genéricos (cualquier nombre: mesa/taza/lámpara/…) con atributos JSON libres | world.things + archivo things/wardrobe |
| scene | lugar (residencia), postura, apariencia (resumen del atuendo de hoy), cuerpo | world.place/pose/look/body; apariencia detallada en el archivo look |
| ledger | contadores, comidas, órdenes, condiciones permanentes | world.counters/counters_today/meals/orders_*/standing + archivo ledger |
| tools | dados, ruleta, agenda | world.dice/spinners/schedule + archivos dice/spinner/schedule |
| weather | Condiciones ambientales / temperatura / humedad / viento (+ pronóstico opcional) | world.weather / world.forecast + archivo weather |
| automation | Hooks (schedule/random/webhook/attr_change/chat_message) + acciones | world.automation |
La zona horaria (profile.timezone) está fuera de world, pero es necesaria para el cambio de día, las sesiones matutinas/nocturnas y las horas locales de la agenda.
Investigado a partir de las muestras xiaoya → implementado
| Necesidad (de apariencia/diario/operaciones) | Campo / archivo |
|---|---|
| Día local / cambio de día / sesiones matutinas y nocturnas | timezone, day_boundary, funciones de períodos |
| Atuendo fijo + atuendo de hoy | archivo look; resumen world.look |
| Inventario (cualquier objeto con nombre + atributos JSON/imágenes libres) | world.things ↔ archivo things/wardrobe; CLI persona thing |
| Residencia / postura | world.place, world.pose |
| Contadores de acciones (acumulados y de hoy) | world.counters (acumulados), world.counters_today (diarios) |
| Comidas de hoy | world.meals |
| Órdenes pendientes / completadas | world.orders_pending, world.orders_done |
| Condiciones permanentes | world.standing |
| Nota sobre el cuerpo | world.body |
| Utilidades de juego | world.dice, world.spinners, world.schedule |
| Tiempo meteorológico / pronóstico breve | world.weather, world.forecast ↔ archivo weather |
Automatización (world.automation)
Hooks con nombre, desencadenadores y acciones, guardados en la instantánea del mundo de la persona (zona horaria de la persona para cron y horarios locales).
Desencadenador type |
Significado |
|---|---|
cron |
M H o M H * * DOW en hora local de la persona |
local_time |
HH:MM + days opcional (igual que la agenda) |
random_interval |
se activa tras un retraso aleatorio en [min_secs, max_secs] |
random_and_timed |
hora local + jitter_secs opcional |
webhook |
HTTP entrante / CLI --source webhook |
attr_change |
después de thing attr set/delete cuando coincide thing_id y el filtro de ruta es exacto o un prefijo |
chat_message |
al ejecutar persona chat send, una vez por participante (mismo evento; peer opcional es el ID de la tarjeta de la otra persona, completo o abreviado del listado) |
manual |
CLI/MCP automation trigger --source manual |
Acción type |
Significado |
|---|---|
set_attr |
establece la ruta de atributos del objeto (crea al establecer) |
random_attr |
dice / range / choice |
call_function |
funciones integradas: inc, dec, clamp, roll, set_weather_stub |
append_event |
añade al archivo de eventos |
webhook_out |
HTTP POST JSON a una URL |
HTTP del daemon (cuando está activo --listen):
POST /v1/persona/{vault}/{persona}/automation/trigger
Authorization: Bearer <world.automation.webhook_token>
Content-Type: application/json
{"hook":"HOOK_ID"}
Los hooks solo se activan por rutas explícitas de ejecución o activación de automatización (incluidos los desencadenadores existentes de cambios de atributos y chat_message al enviar chats de persona). Invocar persona automation run recupera la última ocurrencia cron/de hora local omitida dentro de ocho días, como máximo una vez, en lugar de reproducir todas las ocurrencias omitidas. Los filtros de días de la semana siguen aplicándose a la ocurrencia; los hooks de tiempo con aleatoriedad mantienen su condición de fluctuación temporal. RandomInterval no cambia. No hay un temporizador de automatización en el daemon: Service::tick solo hace caducar sesiones, autorizaciones y estado remoto.
Las acciones salientes webhook_out requieren una URL exacta en world.automation.webhook_allowlist; la lista vacía predeterminada bloquea todos los POST. Gestione las entradas explícitamente con persona automation webhook-allow VAULT PERSONA
--add https://example.com/hook (--add / --remove repetibles) o MCP persona_automation_webhook_allow. Las entradas deben ser URL HTTP(S) sin información de usuario ni espacios en blanco, de como máximo 2048 bytes. La lista es configuración pública, pero el webhook_token entrante permanece secreto y nunca se devuelve en las vistas de clientes. La lista de permitidos no introduce POST en segundo plano.
Pospuesto (motivos)
| Idea | Motivo para posponer |
|---|---|
| Cliente de API meteorológica en vivo | Los agentes establecen/consultan el estado de la bóveda; obtienen datos fuera y usan world-set |
| Teléfono / notificaciones | Específico de cada producto; no es la verdad de la bóveda |
| Cartera / juego con dinero | Uso especializado; puede usar things + contadores si hace falta |
| NPC acompañantes | Necesitan su propio grafo/tarjetas |
| Grafo de habitaciones de la residencia | Por ahora se codifica en la cadena place |
| Higiene / sueño como entidades propias | Usar standing / schedule / body |
| Editar automáticamente «Hoy» de look.md al ejecutar world-set | Conserva la muestra detallada; los agentes usan card put en el archivo de apariencia |
Flujo de sincronización de agentes
world-get/persona_world_get→ lee la instantánea,local_date,period,revisionystale_day. La ausencia deas_of_local_dateindica obsolescencia; en otro caso,stale_daycompara la fecha del registro con la fecha local de la persona después deday_boundary.weather_age_secses la antigüedad con signo de una observación RFC3339 válida, o null si falta o es inválida.- Al cambiar de día, invoque explícitamente
persona world-rollover VAULT PERSONA/persona_world_rollover. Esta ruta de transición de día borrameals,orders_done, el resumen brevelookycounters_today, y estableceas_of_local_datea la fecha local del registro de hoy. Se conservan loscountersacumulados,standing,things, órdenes pendientes, escena/cuerpo, herramientas, tiempo/pronóstico y automatización. No se edita ningún archivo de apariencia ni la sección «Hoy» de look.md. world-setsolo actualiza los campos proporcionados de escena/objetos/registro/herramientas/tiempo. Nunca cambia el día silenciosamente ni borra campos diarios al cambiar de día, aunque estén obsoletos. Establece unas_of_local_dateausente sin borrar campos existentes, y siempre marcaupdated_at(UTC,Z) yupdated_local(ISO local de la persona con desplazamiento) del mundo.persona_cardguarda literalmente el mundo proporcionado, incluida una fecha pasada del registro.- Use
--expected-revision HASH/ MCPexpected_revisionde world-get para evitar perder actualizaciones: un hash de cabecera actual distinto devuelve un conflicto antes de modificar. Omitirlo conserva la regla de prevalencia de la última escritura. Los contadores diarios usan--counter-today NAME=VALUE;--clear-counter NAMEy--clear-counter-today NAMEeliminan claves acumuladas/diarias (todos repetibles). - La sincronización de archivos solo toca los dominios proporcionados por esa llamada. Las tarjetas existentes se sustituyen únicamente si su cuerpo sigue siendo la plantilla generada anterior al cambio; la prosa escrita manualmente se conserva y se informa como
synced_archives[kind] = "preserved". Esto también se aplica a la sincronización de creación/eliminación/atributos de objetos y a la sincronización del registro al cambiar de día. Cambiar objetos sincroniza tantothingscomowardrobe. Los archivos de apariencia existentes siempre se conservan. - Las claves del mapa de cantidades de objetos /
--item ID=COUNTusan ID estables, nunca búsquedas por nombre visible. Los ID existentes actualizan cantidades sin renombrar; cero elimina solo ese ID. Se rechaza un nombre visible perteneciente a otro ID. Las claves desconocidas siguen creando, por compatibilidad heredada, un objeto con ese ID y nombre. dice-roll/spinner-spin/schedule-listofrecen herramientas conscientes de la zona horaria. Las ediciones detalladas de apariencia/diario usancard putnormal;append-eventopcional (p. ej.,kind=weather) registra comportamiento sin reescribir la prosa de los archivos.
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
Los tokens webhook permanecen en el estado cifrado de la persona para la autenticación entrante, sincronización y copias de seguridad, pero las respuestas de clientes no los devuelven. World get/set, automation put/list, lecturas normales de tarjetas (incluidas las históricas y desatendidas) y lecturas de archivos solo exponen webhook_token_set en las vistas de automatización. Guarde el token aprovisionado de forma segura; establezca uno nuevo para rotarlo.
El chat entre dos tarjetas de persona en la misma bóveda usa una tarjeta de conversación normal y cursores de lectura por persona; leer el historial no marca mensajes como leídos. Enviar un mensaje activa los hooks chat_message de cada participante; la carga incluye vault, from, to y message_id, y omite el texto del mensaje.
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
Con una autorización de escritura: persona_write (timezone / day_boundary opcionales), 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. El historial y las diferencias usan las herramientas existentes memory_history / memory_diff / memory_read (las revisiones de tarjetas de persona incluyen world.*; los archivos de vestuario/lugar/postura tienen su propio historial).
Generar AGENTS.md / habilidad para agentes
memories default set persona VAULT/PERSONA
memories skill generate --out AGENTS.md --persona VAULT/PERSONA
memories agents generate --out ./skills/memories-persona --layout skill
El archivo generado resume las operaciones de bóvedas/tarjetas/personas/mundo y, cuando se selecciona una persona, incorpora una descripción de su núcleo y ejemplos CLI/MCP para el mundo, objetos y eventos. Véase Generación de habilidades en README.
Nota de sincronización (Grok Bot / Muse)
Trate la tarjeta de persona de la bóveda y sus archivos enlazados como fuente de verdad. Los directorios locales de habilidades facilitan la importación/exportación; después de importar, los agentes deben leer la bóveda (card read / MCP memory_read) en lugar de una copia obsoleta del sistema de archivos. Realice los cambios de núcleo mediante persona put; edite archivos mediante card put normal sobre el recurso del archivo; añada comportamiento de corta duración con append-event. Para decidir el cambio de día o las sesiones matutinas o nocturnas, use la timezone de la persona (y day_boundary opcional); no deduzca los límites del día únicamente del reloj del host del agente.
Estructura del directorio de habilidades
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
La importación asigna SKILL.md → núcleo de persona y cada references/*.md → tarjeta de archivo enlazada (kind = nombre del archivo sin extensión). El contenido del archivo se guarda literalmente como contenido del usuario.
Claves de metadatos iniciales: timezone o metadata.timezone (IANA); day_boundary / metadata.day_boundary opcionales (HH:MM).
Bóveda local de demostración
En un equipo de desarrollo puede inicializar una bóveda desechable con la muestra xiaoya incluida en el repositorio:
cargo run -p memories-core --example seed_xiaoya_persona
Esto escribe /workspace/persona-demo-vault (contraseña persona-demo-password) y SEED.json / README.md con los ID de bóveda y recursos (incluida timezone). Reproduzca la importación CLI contra un daemon en ejecución con:
memories persona import VAULT_ID testdata/xiaoya-persona