Persona-Karten
Persona-Karten sind produktübergreifende Identitätskarten zur Synchronisierung von Persönlichkeit und Verhalten zwischen Clients wie Grok Bot und Muse. Die Kopie im Tresor ist maßgeblich.
Ebenen
- Kern (langsam) — wie gesprochen und gehandelt wird. Wird als Inhalt der Persona-Karte gespeichert und über
persona_card/memories persona putversioniert (derselbe signierte Revisions-DAG wie bei anderen Erinnerungen und Karten). - Archive / episodisch (mittel) — Journal, Erscheinungsbild, Vertrag, Ansichten, Zeilen, Operationen und Ähnliches. Werden als separate gewöhnliche Wissenskarten gespeichert, vom Persona-Profil (
archives[]) verknüpft und für den Graphen als Kartenlinkspersona_archive:<kind>gespiegelt. Führen Sie Archivinhalte nicht wieder mit dem Kern zusammen. - Verhaltensereignisse (schnell) — nur anhängbarer Datenstrom in einem verknüpften
events-Archiv überpersona_append_event/memories persona append-event.
Profilfelder
| Feld | Bedeutung |
|---|---|
persona_id |
Stabile ID (z. B. Skill-Frontmatter name) |
display_name |
Menschenlesbarer Titel (z. B. 小雅 / 李雅) |
aliases |
Alternative Namen |
timezone |
IANA-Name (z. B. Asia/Singapore). Standard Asia/Singapore, wenn nicht gesetzt / bei älteren Karten |
day_boundary |
Optionale lokale Zeit HH:MM für den Wechsel des Kalendertags (隔日). Nicht gesetzt = lokale Mitternacht |
world |
Aktueller Welt-Snapshot: place/pose/look/body, allgemeine things (id→{name,description,images,attrs JSON}), Tagesbuch (counters + counters_today, as_of_local_date), Wetter, Werkzeuge |
Inhalt / core |
Verhaltensanweisungen in Markdown/Text |
traits |
Optionale String-Map (Version, Sprache, …) |
bindings |
{ product, agent }-Produktbindungen |
memory_policy / sync_hints |
Optionale Synchronisierungshinweise |
archives |
{ kind, card, vault?, title? } verknüpfte Assets |
summary.type ist persona mit persona_id, display_name, timezone, day_boundary, place, pose, look, things_count, has_weather, alias_count, archive_count und binding_count.
Zeitzone, Tageswechsel (隔日), Morgen- / Abendroutine (早课 / 晚课)
Personas berücksichtigen die lokale Uhrzeit, nicht bloße UTC-Epochenwerte.
- Zeitzone — jede Persona hat eine IANA-
timezone. Der Import liesttimezone/metadata.timezoneausSKILL.md; die CLI kann mit--timezone Asia/Singaporeüberschreiben. Demo-Standard, wenn nicht gesetzt:Asia/Singapore. - Kalendertag (隔日) — das lokale bürgerliche Datum wechselt um Mitternacht in dieser Zeitzone, sofern
day_boundarynicht gesetzt ist (z. B.05:00für einen späten nächtlichen Wechsel). Prüfungen auf einen „neuen Tag“ im Tagesbuch/Journal solltenlocal_dateaus den Zeitstempel-Hilfsfunktionen vergleichen, nicht das UTC-Datum. - Tagesabschnitte (lokale Stunde, halboffene Intervalle):
| Abschnitt | Lokale Stunden |
|---|---|
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) |
Nächtliche Kontinuität für 晚课 / „noch dieselbe Nacht“ verwendet die Spanne [22:00, 05:00) (night ∪ early_morning). 早课 entspricht morning (und optional spätem early_morning); 晚课 entspricht evening / night.
4. Ereigniszeitstempel — persona_append_event schreibt sowohl UTC als auch lokales ISO-8601 (mit Offset), zusätzlich timezone, period und local_date in die Überschrift des Ereignisarchivs und in die JSON-Antwort (utc, local, timezone, period, local_date, timestamp Unix-UTC).
Core-Hilfsfunktionen (Rust): persona_local_now, classify_period, stamp_persona_now, format_event_heading in memories_core::persona.
Taxonomie der Weltdomänen (世界状态域)
world ist eine Domäne/ein Tag, kein Sammelbehälter im Kern. Der Kern (Inhalt von SKILL.md) enthält weiterhin ausschließlich Stimme/Regeln.
| Ebene | Bedeutung | Speicherung |
|---|---|---|
| world | Domäne für Szene + Tagesbuch + Werkzeuge + Wetter | profile.world + mit world markierte Archive |
| things | Allgemeine Gegenstände (beliebige Namen: Tisch/Tasse/Lampe/…) mit freien JSON-Attributen | world.things + Archiv things/wardrobe |
| scene | Ort (居所), Haltung (姿态), Erscheinungsbild (Zusammenfassung der heutigen Kleidung), Körper | world.place/pose/look/body; detailliertes Erscheinungsbild im Archiv look |
| ledger | Zähler, Mahlzeiten, Aufträge, Dauerhaftes (常设) | world.counters/counters_today/meals/orders_*/standing + Archiv ledger |
| tools | Würfel, Drehscheibe/转盘, Zeitplan/日程 | world.dice/spinners/schedule + Archive dice/spinner/schedule |
| weather | Umgebungsbedingungen / Temperatur / Luftfeuchtigkeit / Wind (+ optionale Vorhersage) | world.weather / world.forecast + Archiv weather |
| automation | Hooks (schedule/random/webhook/attr_change/chat_message) + Aktionen | world.automation |
Zeitzone (profile.timezone) liegt außerhalb von world, ist aber für Tageswechsel (隔日), Morgen-/Abendroutine (早课/晚课) und lokale Zeitplanzeiten erforderlich.
Aus xiaoya-Fixtures ermittelt → implementiert
| Bedarf (aus look/journal/ops) | Feld / Archiv |
|---|---|
| Lokaler Tag / 隔日 / 早课晚课 | timezone, day_boundary, Tagesabschnitt-Hilfsfunktionen |
| Feste + heutige Kleidung | Archiv look; Zusammenfassung world.look |
| Inventar (beliebiger benannter Gegenstand + freie JSON-Attribute/Bilder) | world.things ↔ Archiv things/wardrobe; CLI persona thing |
| Wohnort / Haltung (居所 / 姿态) | world.place, world.pose |
| Aktionszähler (kumulativ und heute) | world.counters (kumulativ), world.counters_today (täglich) |
| Heute gegessen | world.meals |
| Beauftragtes ausstehend / erledigt | world.orders_pending, world.orders_done |
| Dauerhaftes | world.standing |
| Körpernotiz | world.body |
| Spielwerkzeuge | world.dice, world.spinners, world.schedule |
| Wetter / kurze Vorhersage | world.weather, world.forecast ↔ Archiv weather |
Automatisierung (world.automation)
Benannte Hooks mit Auslösern + Aktionen, gespeichert im Welt-Snapshot der Persona (Persona-Zeitzone für cron/lokale Zeitpläne).
Auslöser-type |
Bedeutung |
|---|---|
cron |
M H oder M H * * DOW in lokaler Persona-Zeit |
local_time |
HH:MM + optionale days (wie beim Zeitplan) |
random_interval |
Auslösen nach zufälliger Verzögerung in [min_secs, max_secs] |
random_and_timed |
lokale Zeit + optionale jitter_secs |
webhook |
eingehendes HTTP / CLI --source webhook |
attr_change |
nach thing attr set/delete, wenn thing_id übereinstimmt und der Pfadfilter exakt oder ein Präfix ist |
chat_message |
bei persona chat send, einmal pro Teilnehmer (dasselbe Ereignis; optionales peer ist die ID der anderen Persona-Karte, vollständig oder die kurze ID aus list) |
manual |
CLI/MCP automation trigger --source manual |
Aktions-type |
Bedeutung |
|---|---|
set_attr |
Attributpfad eines Gegenstands setzen (beim Setzen erstellen) |
random_attr |
dice / range / choice |
call_function |
eingebaute Funktionen: inc, dec, clamp, roll, set_weather_stub |
append_event |
an Ereignisarchiv anhängen |
webhook_out |
HTTP POST JSON an URL |
Daemon-HTTP (wenn --listen aktiviert ist):
POST /v1/persona/{vault}/{persona}/automation/trigger
Authorization: Bearer <world.automation.webhook_token>
Content-Type: application/json
{"hook":"HOOK_ID"}
Hooks werden ausschließlich über ausdrückliche Automatisierungs-Ausführungs-/Auslösungspfade ausgelöst (einschließlich bestehender Attributänderungs-Auslöser und chat_message beim Senden eines Persona-Chats). Der Aufruf von persona automation run holt den letzten verpassten cron-/lokalen Zeitslot innerhalb von acht Tagen höchstens einmal nach, statt alle verpassten Slots erneut auszuführen. Wochentagfilter gelten weiterhin für das Vorkommnis; zeitgesteuerte Zufalls-Hooks behalten ihre Jitter-Schranke. RandomInterval bleibt unverändert. Es gibt keinen Automatisierungsticker im Daemon: Service::tick lässt ausschließlich Sitzungen, Freigaben und Remote-Zustand ablaufen.
Ausgehende webhook_out-Aktionen erfordern eine exakte URL in world.automation.webhook_allowlist; die standardmäßig leere Liste blockiert jeden POST. Verwalten Sie Einträge ausdrücklich mit persona automation webhook-allow VAULT PERSONA
--add https://example.com/hook (wiederholbares --add / --remove) oder MCP persona_automation_webhook_allow. Einträge müssen HTTP(S)-URLs ohne Benutzerinformationen oder Leerraum und höchstens 2048 Bytes lang sein. Die Liste ist öffentliche Konfiguration, aber das eingehende webhook_token bleibt geheim und wird niemals durch Client-Ansichten zurückgegeben. Die Allowlist führt keine Hintergrund-POSTs ein.
Zurückgestellt (Begründung)
| Idee | Warum zurückgestellt |
|---|---|
| Client für Live-Wetter-API | Agenten setzen/fragen Tresorzustand ab; extern abrufen und world-set |
| Telefon / Benachrichtigungen | Produktspezifisch; keine Tresorwahrheit |
| Geldbörse / Geldspiel | Nische; bei Bedarf things + Zähler |
| Begleitende NPCs | Benötigen eigenen Graphen/eigene Karten |
| Raumgraph innerhalb des Wohnorts | Vorerst als place-String kodieren |
| Hygiene / Schlaf als eigenständiges Konzept | standing / schedule / body verwenden |
| Automatische Bearbeitung von look.md „Heute“ bei world-set | Bewahrt detaillierte Fixture; Agenten verwenden card put für das look-Archiv |
Synchronisierungsablauf für Agenten
world-get/persona_world_get→ Snapshot,local_date,period,revisionundstale_daylesen. Fehlendesas_of_local_dategilt als veraltet; andernfalls vergleichtstale_daydas Tagesbuchdatum mit dem lokalen Persona-Datum nachday_boundary.weather_age_secsist das vorzeichenbehaftete Alter einer gültigen RFC3339-Beobachtung oder null, wenn sie fehlt/ungültig ist.- Beim Tageswechsel (隔日) ausdrücklich
persona world-rollover VAULT PERSONA/persona_world_rolloveraufrufen. Dieser Tagesübergangspfad leertmeals,orders_done, die kurzelook-Zusammenfassung undcounters_todayund setztas_of_local_dateauf das heutige lokale Tagesbuchdatum. Kumulativecounters,standing,things, ausstehende Aufträge, Szene/Körper, Werkzeuge, Wetter/Vorhersage und Automatisierung bleiben erhalten. Kein look-Archiv und kein look.md „Heute“ wird bearbeitet. world-setaktualisiert ausschließlich mitgelieferte Szene-/Gegenstands-/Tagesbuch-/Werkzeug-/Wetterfelder. Es wechselt niemals stillschweigend den Tag und löscht keine Tagesfelder beim Tageswechsel (隔日), auch nicht bei veraltetem Zustand. Es setzt fehlendesas_of_local_date, ohne bestehende Felder zu löschen, und versieht die Weltebene immer mitupdated_at(UTC,Z) undupdated_local(lokales Persona-ISO mit Offset).persona_cardspeichert eine mitgelieferte Welt unverändert, einschließlich eines vergangenen Tagesbuchdatums.- Verwenden Sie
--expected-revision HASH/ MCPexpected_revisionaus world-get, um verlorene Aktualisierungen zu verhindern: Ein abweichender aktueller Head-Hash liefert vor der Änderung einen Konflikt. Ohne diese Angabe gilt weiterhin „letzter Schreibvorgang gewinnt“. Tageszähler verwenden--counter-today NAME=VALUE;--clear-counter NAMEund--clear-counter-today NAMElöschen kumulative/tägliche Schlüssel (alle wiederholbar). - Archivsynchronisierung berührt ausschließlich Domänen, die der Aufruf mitliefert. Bestehende Karten werden nur ersetzt, wenn ihr Inhalt noch die generierte Vorlage vor der Änderung ist; handgeschriebener Text bleibt erhalten und wird als
synced_archives[kind] = "preserved"gemeldet. Das gilt auch für put/delete/Attribut-Synchronisierung von Gegenständen und die Tagesbuch-Synchronisierung beim Tageswechsel. Gegenstandsänderungen synchronisieren sowohlthingsals auchwardrobe. Bestehende look-Archive bleiben immer erhalten. - Schlüssel der Gegenstandszähler-Map /
--item ID=COUNTverwenden stabile IDs, niemals eine Suche nach Anzeigenamen. Bestehende IDs aktualisieren die Anzahl ohne Umbenennung; null entfernt nur diese ID. Ein Anzeigename, der zu einer anderen ID gehört, wird zurückgewiesen. Unbekannte Schlüssel erstellen aus Kompatibilitätsgründen weiterhin einen Gegenstand mit dieser ID und diesem Namen. dice-roll/spinner-spin/schedule-listbieten zeitzonenbewusste Werkzeuge. Detaillierte look-/Journal-Bearbeitungen verwenden gewöhnlichescard put; optionalesappend-event(z. B.kind=weather) zeichnet Verhalten auf, ohne Archivtext umzuschreiben.
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-Tokens bleiben zur eingehenden Authentifizierung, Synchronisierung und Sicherung im verschlüsselten Persona-Zustand, werden aber nicht in Client-Antworten zurückgegeben. World get/set, automation put/list, gewöhnliches Lesen von Karten (einschließlich historischer und unbeaufsichtigter Lesezugriffe) sowie Archiv-Lesezugriffe zeigen ausschließlich webhook_token_set in Automatisierungsansichten. Bewahren Sie das eingerichtete Token sicher auf; setzen Sie zum Rotieren einen Ersatz.
Chat zwischen zwei Persona-Karten im selben Tresor verwendet eine gewöhnliche Gesprächskarte und Lesecursor pro Persona; Lesen des Verlaufs markiert Nachrichten nicht als gelesen. Das Senden einer Nachricht löst die chat_message-Hooks jedes Teilnehmers aus; die Nutzdaten enthalten vault, from, to und message_id, jedoch keinen Nachrichtentext.
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
Mit Schreibfreigabe: persona_write (optionale 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. Verlauf und Diffs verwenden die bestehenden Werkzeuge memory_history / memory_diff / memory_read (Revisionen von Persona-Karten enthalten world.*; wardrobe-/place-/pose-Archive besitzen ihren eigenen Verlauf).
AGENTS.md / Skill für Agenten generieren
memories default set persona VAULT/PERSONA
memories skill generate --out AGENTS.md --persona VAULT/PERSONA
memories agents generate --out ./skills/memories-persona --layout skill
Die generierte Datei fasst Tresor-/Karten-/Persona-/Weltoperationen zusammen und bettet bei ausgewählter Persona deren Kernübersicht sowie CLI/MCP-Anleitungen für Welt, Gegenstände und Ereignisse ein. Siehe README Skill-Generierung.
Synchronisierungshinweis (Grok Bot / Muse)
Behandeln Sie die Persona-Karte im Tresor und ihre verknüpften Archive als maßgebliche Quelle. Lokale Skill-Verzeichnisse dienen dem bequemen Import/Export; nach dem Import sollten Agenten den Tresor lesen (card read / MCP memory_read) statt einer veralteten Dateisystemkopie. Führen Sie Kernänderungen über persona put aus; Archivbearbeitungen über gewöhnliches card put am Archiv-Asset; kurzlebiges Verhalten hängen Sie mit append-event an. Verwenden Sie bei Entscheidungen über Tageswechsel (隔日), Morgenroutine (早课) oder Abendroutine (晚课) die Persona-timezone (und optionales day_boundary) — leiten Sie Tagesgrenzen nicht allein aus der Uhr des Agenten-Hosts ab.
Aufbau des Skill-Verzeichnisses
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
Der Import ordnet SKILL.md → Persona-Kern und jede references/*.md → eine verknüpfte Archivkarte zu (kind = Dateiname ohne Erweiterung). Archivinhalte werden unverändert als Benutzerinhalt gespeichert.
Frontmatter-Schlüssel: timezone oder metadata.timezone (IANA); optional day_boundary / metadata.day_boundary (HH:MM).
Lokaler Demo-Tresor
Auf einem Entwicklungsrechner können Sie einen entbehrlichen Tresor mit der eingecheckten xiaoya-Fixture initialisieren:
cargo run -p memories-core --example seed_xiaoya_persona
Dies schreibt /workspace/persona-demo-vault (Passwort persona-demo-password) sowie SEED.json / README.md mit Tresor- und Asset-IDs (einschließlich timezone). Reproduzieren Sie den CLI-Import gegen einen laufenden Daemon mit:
memories persona import VAULT_ID testdata/xiaoya-persona