Fiches de persona
Les fiches de persona sont des fiches d'identité communes à plusieurs produits qui synchronisent la personnalité et le comportement entre des clients tels que Grok Bot et Muse. La copie du coffre fait autorité.
Couches
- Noyau (lent) — manière de parler et d'agir. Stocké dans le corps de la fiche
de persona et versionné via
persona_card/memories persona put(même DAG de révisions signées que les autres souvenirs et fiches). - Archives / épisodes (moyen) — journal, apparence, contrat, opinions, répliques,
opérations et éléments similaires. Stockés comme fiches de connaissances ordinaires distinctes
liées depuis le profil de persona (
archives[]) et reflétées par des liens de fichespersona_archive:<kind>pour le graphe. Ne réintégrez pas les archives dans le noyau. - Événements comportementaux (rapide) — flux à ajout uniquement sur une archive
eventsliée, viapersona_append_event/memories persona append-event.
Champs du profil
| Champ | Signification |
|---|---|
persona_id |
Identifiant stable (par exemple name dans les métadonnées initiales de la compétence) |
display_name |
Titre lisible (par exemple 小雅 / 李雅) |
aliases |
Autres noms |
timezone |
Nom IANA (par exemple Asia/Singapore). Par défaut Asia/Singapore si absent / sur les anciennes fiches |
day_boundary |
Heure locale HH:MM facultative du changement de jour civil. Absente = minuit local |
world |
Instantané actuel du monde : place/pose/look/body, objets génériques things (id→{name,description,images,attrs JSON}), registre (counters + counters_today, as_of_local_date), météo, outils |
corps / core |
Instructions comportementales Markdown/texte |
traits |
Table facultative de chaînes (version, langue, …) |
bindings |
Associations aux produits { product, agent } |
memory_policy / sync_hints |
Consignes de synchronisation facultatives |
archives |
Ressources liées { kind, card, vault?, title? } |
summary.type vaut persona avec persona_id, display_name, timezone,
day_boundary, place, pose, look, things_count, has_weather, alias_count,
archive_count et binding_count.
Fuseau horaire, changement de jour, séance matinale / séance du soir
Les personas raisonnent selon l'heure civile locale, et non de simples horodatages UTC.
- Fuseau horaire — chaque persona possède un
timezoneIANA. L'importation littimezone/metadata.timezonedansSKILL.md; la CLI peut le remplacer avec--timezone Asia/Singapore. Valeur de démonstration par défaut si absent :Asia/Singapore. - Jour civil — la date civile locale change à minuit dans ce fuseau, sauf si
day_boundaryest défini (par exemple05:00pour un changement tard dans la nuit). Les vérifications de « nouveau jour » du registre/journal doivent comparerlocal_datefourni par les fonctions d'horodatage, et non la date UTC. - Périodes du jour (heure locale, intervalles semi-ouverts) :
| Période | Heures 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 continuité nocturne de la séance du soir / « toujours la même nuit » utilise
l'intervalle [22:00, 05:00) (night ∪ early_morning). La séance matinale
correspond à morning (et éventuellement à la fin de early_morning) ; la
séance du soir correspond à evening / night.
4. Horodatages d'événement — persona_append_event écrit l'heure UTC et l'heure
locale ISO-8601 (avec décalage), plus timezone, period et local_date dans le
titre de l'archive d'événements et la réponse JSON (utc, local, timezone,
period, local_date, timestamp Unix UTC).
Fonctions du noyau (Rust) : persona_local_now, classify_period, stamp_persona_now,
format_event_heading dans memories_core::persona.
Taxonomie du domaine du monde
world est un domaine/une étiquette, pas un déversement dans le noyau. Le noyau
(corps de SKILL.md) reste limité à la voix et aux règles.
| Couche | Signification | Stockage |
|---|---|---|
| monde | Domaine de la scène + registre + outils + météo | profile.world + archives étiquetées world |
| objets | Objets génériques (nom quelconque : table/tasse/lampe/…) avec attributs JSON libres | world.things + archive things/wardrobe |
| scène | lieu (résidence), posture, apparence (résumé de la tenue du jour), corps | world.place/pose/look/body ; apparence détaillée dans l'archive look |
| registre | compteurs, repas, ordres, dispositions permanentes | world.counters/counters_today/meals/orders_*/standing + archive ledger |
| outils | dés, roue, programme | world.dice/spinners/schedule + archives dice/spinner/schedule |
| météo | Conditions ambiantes / température / humidité / vent (+ prévisions facultatives) | world.weather / world.forecast + archive weather |
| automatisation | Déclencheurs (schedule/random/webhook/attr_change/chat_message) + actions | world.automation |
Le fuseau horaire (profile.timezone) est extérieur au monde, mais nécessaire
au changement de jour, aux séances matinales/du soir et aux heures locales du programme.
Étudié à partir des données de test xiaoya → implémenté
| Besoin (apparence/journal/opérations) | Champ / archive |
|---|---|
| Jour local / changement de jour / séances matinales et du soir | timezone, day_boundary, fonctions de période |
| Tenue fixe + tenue du jour | archive look ; résumé world.look |
| Inventaire (tout objet nommé + attributs JSON/images libres) | world.things ↔ archive things/wardrobe ; CLI persona thing |
| Résidence / posture | world.place, world.pose |
| Compteurs d'actions (cumulés et du jour) | world.counters (cumulés), world.counters_today (quotidiens) |
| Repas du jour | world.meals |
| Ordres en attente / exécutés | world.orders_pending, world.orders_done |
| Dispositions permanentes | world.standing |
| Note sur le corps | world.body |
| Utilitaires de jeu | world.dice, world.spinners, world.schedule |
| Météo / prévisions courtes | world.weather, world.forecast ↔ archive weather |
Automatisation (world.automation)
Déclencheurs nommés avec conditions + actions, stockés dans l'instantané du monde de la persona (fuseau de la persona pour cron et les programmes locaux).
type de déclenchement |
Signification |
|---|---|
cron |
M H ou M H * * DOW en heure locale de la persona |
local_time |
HH:MM + days facultatif (comme le programme) |
random_interval |
déclenchement après un délai aléatoire dans [min_secs, max_secs] |
random_and_timed |
heure locale + jitter_secs facultatif |
webhook |
HTTP entrant / CLI --source webhook |
attr_change |
après thing attr set/delete lorsque thing_id correspond et que le filtre de chemin est exact ou un préfixe |
chat_message |
lors de persona chat send, une fois par participant (même événement ; peer facultatif est l'identifiant de fiche de l'autre persona, complet ou court provenant de la liste) |
manual |
CLI/MCP automation trigger --source manual |
type d'action |
Signification |
|---|---|
set_attr |
définir le chemin des attributs d'un objet (création à l'affectation) |
random_attr |
dice / range / choice |
call_function |
fonctions intégrées : inc, dec, clamp, roll, set_weather_stub |
append_event |
ajouter à l'archive d'événements |
webhook_out |
POST HTTP JSON vers une URL |
HTTP du démon (lorsque --listen est activé) :
POST /v1/persona/{vault}/{persona}/automation/trigger
Authorization: Bearer <world.automation.webhook_token>
Content-Type: application/json
{"hook":"HOOK_ID"}
Les déclencheurs s'activent uniquement via les chemins explicites d'exécution/
déclenchement de l'automatisation (y compris les déclenchements existants de changement
d'attribut et chat_message lors de l'envoi de conversation de persona). L'appel de
persona automation run rattrape le dernier créneau cron/heure locale manqué dans
les huit jours, au maximum une fois, sans rejouer tous les créneaux manqués. Les filtres
de jour de semaine s'appliquent toujours à l'occurrence ; les déclencheurs aléatoires
horaires conservent leur condition de décalage aléatoire. RandomInterval reste inchangé.
Il n'existe aucun minuteur d'automatisation du démon : Service::tick expire uniquement
les sessions, autorisations et états distants.
Les actions sortantes webhook_out nécessitent une URL exacte dans
world.automation.webhook_allowlist ; la liste vide par défaut bloque tous les POST.
Gérez explicitement les entrées avec persona automation webhook-allow VAULT PERSONA
--add https://example.com/hook (--add / --remove répétables) ou MCP
persona_automation_webhook_allow. Les entrées doivent être des URL HTTP(S) sans
informations utilisateur ni espaces, de 2048 octets maximum. La liste est une
configuration publique, mais le webhook_token entrant reste secret et n'est jamais
renvoyé par les vues clients. La liste d'autorisation n'introduit aucun POST en arrière-plan.
Différé (raisons)
| Idée | Raison du report |
|---|---|
| Client d'API météo en direct | Les agents définissent/interrogent l'état du coffre ; récupération externe puis world-set |
| Téléphone / notifications | Propre au produit ; ne représente pas la vérité du coffre |
| Portefeuille / jeu monétaire | Usage de niche ; peut utiliser things + compteurs si nécessaire |
| PNJ compagnons | Nécessitent leurs propres graphes/fiches |
| Graphe des pièces de la résidence | Encodage dans la chaîne place pour l'instant |
| Hygiène / sommeil comme éléments dédiés | Utiliser standing / schedule / body |
| Modification automatique de la section « aujourd'hui » de look.md lors de world-set | Préserve les données de test détaillées ; les agents utilisent card put pour l'archive d'apparence |
Flux de synchronisation des agents
world-get/persona_world_get→ lire l'instantané,local_date,period,revisionetstale_day. L'absence deas_of_local_datesignifie un état périmé ; sinonstale_daycompare la date du registre à la date locale de la persona aprèsday_boundary.weather_age_secsest l'âge signé d'une observation RFC3339 valide, ou null lorsqu'elle est absente/invalide.- Au changement de jour, appeler explicitement
persona world-rollover VAULT PERSONA/persona_world_rollover. Ce chemin de transition de jour effacemeals,orders_done, le résumé courtlooketcounters_today, et fixeas_of_local_dateà la date locale du registre d'aujourd'hui. Lescounterscumulés,standing,things, ordres en attente, scène/corps, outils, météo/prévisions et automatisation demeurent. Aucune archive d'apparence ni section « aujourd'hui » de look.md n'est modifiée. world-setmet à jour uniquement les champs fournis de scène/objets/registre/ outils/météo. Il ne change jamais silencieusement le jour et n'efface jamais les champs quotidiens au changement de jour, même si l'état est périmé. Il initialiseas_of_local_dateabsent sans effacer les champs existants, et horodate toujours le monde avecupdated_at(UTC,Z) etupdated_local(ISO local de la persona avec décalage).persona_cardstocke le monde fourni tel quel, y compris une date de registre passée.- Utilisez
--expected-revision HASH/ MCPexpected_revisionprovenant de world-get pour éviter la perte de mises à jour : une empreinte de tête actuelle différente renvoie un conflit avant modification. Son omission conserve la règle du dernier écrivain. Les compteurs quotidiens utilisent--counter-today NAME=VALUE;--clear-counter NAMEet--clear-counter-today NAMEsuppriment les clés cumulées/ quotidiennes (tous répétables). - La synchronisation des archives touche uniquement les domaines fournis par cet
appel. Les fiches existantes sont remplacées uniquement lorsque leur corps est
toujours le modèle généré avant modification ; la prose rédigée manuellement est
conservée et signalée par
synced_archives[kind] = "preserved". Cela s'applique aussi à la synchronisation des ajouts/suppressions/ attributs d'objets et du registre lors du changement de jour. Modifier les objets synchronisethingsetwardrobe. Les archives d'apparence existantes sont toujours préservées. - Les clés de la table des nombres d'objets /
--item ID=COUNTutilisent des identifiants stables, jamais une recherche par nom d'affichage. Les identifiants existants mettent à jour le nombre sans renommage ; zéro supprime seulement cet identifiant. Un nom d'affichage appartenant à un autre identifiant est rejeté. Les clés inconnues créent toujours, selon le comportement historique, un objet avec cet identifiant et ce nom. dice-roll/spinner-spin/schedule-listfournissent des outils tenant compte du fuseau horaire. Les modifications détaillées d'apparence/journal utilisentcard putordinaire ;append-eventfacultatif (par exemplekind=weather) enregistre le comportement sans réécrire la prose des archives.
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
Les jetons de webhook restent dans l'état chiffré de la persona pour l'authentification
entrante, la synchronisation et la sauvegarde, mais les réponses clients ne les
renvoient pas. La lecture/modification du monde, l'ajout/la liste d'automatisations,
les lectures ordinaires de fiches (y compris historiques et sans surveillance) et
les lectures archivées exposent uniquement webhook_token_set dans les vues
d'automatisation. Conservez le jeton provisionné en sécurité ; définissez un remplacement pour le renouveler.
La conversation entre deux fiches de persona du même coffre utilise une fiche de
conversation ordinaire et des curseurs de lecture propres à chaque persona ; lire
l'historique ne marque pas les messages comme lus. L'envoi d'un message déclenche les
hooks chat_message de chaque participant ; la charge utile inclut vault, from,
to et message_id, et omet le texte du message.
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
Avec une autorisation d'écriture : persona_write (timezone / day_boundary facultatifs),
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. L'historique et
les différences utilisent les outils existants memory_history / memory_diff /
memory_read (les révisions de fiches de persona incluent world.* ; les archives
de garde-robe/lieu/posture ont leur propre historique).
Générer AGENTS.md / une compétence pour les agents
memories default set persona VAULT/PERSONA
memories skill generate --out AGENTS.md --persona VAULT/PERSONA
memories agents generate --out ./skills/memories-persona --layout skill
Le fichier généré résume les opérations de coffre/fiche/persona/monde et, lorsqu'une persona est sélectionnée, intègre un aperçu de son noyau plus des recettes CLI/MCP pour le monde, les objets et les événements. Voir Génération de compétences dans le README.
Note de synchronisation (Grok Bot / Muse)
Considérez la fiche de persona du coffre et ses archives liées comme la source de
vérité. Les répertoires locaux de compétences facilitent l'import/export ; après
importation, les agents doivent lire le coffre (card read / MCP memory_read)
plutôt qu'une copie périmée du système de fichiers. Appliquez les modifications du
noyau via persona put ; les modifications d'archives via card put ordinaire sur
la ressource d'archive ; ajoutez les comportements éphémères avec append-event.
Pour déterminer le changement de jour, la séance matinale ou la séance du soir,
utilisez le timezone de la persona (et day_boundary facultatif) — ne déduisez
pas les limites du jour uniquement de l'horloge de la machine hôte de l'agent.
Structure du répertoire de compétence
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
L'importation associe SKILL.md → noyau de persona et chaque references/*.md →
une fiche d'archive liée (kind = nom du fichier sans extension). Le contenu des
archives est stocké tel quel comme contenu utilisateur.
Clés des métadonnées initiales : timezone ou metadata.timezone (IANA) ;
day_boundary / metadata.day_boundary facultatif (HH:MM).
Coffre de démonstration local
Sur une machine de développement, vous pouvez initialiser un coffre jetable avec les données de test xiaoya incluses dans le dépôt :
cargo run -p memories-core --example seed_xiaoya_persona
Cela écrit /workspace/persona-demo-vault (mot de passe persona-demo-password)
ainsi que SEED.json / README.md contenant les identifiants du coffre et des
ressources (y compris timezone). Reproduisez l'importation CLI avec un démon en cours d'exécution :
memories persona import VAULT_ID testdata/xiaoya-persona