openpersona 0.9.0 β†’ 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +180 -21
  2. package/bin/cli.js +60 -2
  3. package/layers/embodiments/README.md +7 -7
  4. package/layers/faculties/memory/SKILL.md +160 -0
  5. package/layers/faculties/memory/faculty.json +9 -0
  6. package/layers/faculties/memory/scripts/memory.js +315 -0
  7. package/layers/soul/soul-state.template.json +1 -1
  8. package/lib/evolution.js +142 -0
  9. package/lib/generator.js +235 -9
  10. package/lib/installer.js +1 -1
  11. package/lib/registrar.js +155 -0
  12. package/lib/switcher.js +102 -3
  13. package/lib/utils.js +0 -2
  14. package/package.json +1 -1
  15. package/presets/ai-girlfriend/manifest.json +1 -1
  16. package/presets/ai-girlfriend/persona.json +6 -0
  17. package/presets/base/manifest.json +1 -1
  18. package/presets/base/persona.json +6 -0
  19. package/presets/health-butler/manifest.json +1 -1
  20. package/presets/health-butler/persona.json +6 -0
  21. package/presets/life-assistant/manifest.json +1 -1
  22. package/presets/life-assistant/persona.json +6 -0
  23. package/presets/samantha/manifest.json +1 -1
  24. package/presets/samantha/persona.json +6 -0
  25. package/presets/stoic-mentor/manifest.json +1 -1
  26. package/presets/stoic-mentor/persona.json +6 -0
  27. package/schemas/acn/acn-register.schema.json +43 -0
  28. package/schemas/acn/agent-card.schema.json +99 -0
  29. package/schemas/body/embodiment.schema.json +2 -2
  30. package/schemas/evolution/influence-request.schema.json +79 -0
  31. package/schemas/manifest.schema.json +1 -1
  32. package/schemas/signal.schema.json +51 -0
  33. package/schemas/soul/evolution-event.schema.json +29 -0
  34. package/schemas/soul/handoff.schema.json +63 -0
  35. package/schemas/soul/persona.schema.json +127 -1
  36. package/skills/open-persona/SKILL.md +81 -18
  37. package/templates/handoff.template.md +30 -0
  38. package/templates/skill.template.md +39 -1
  39. package/templates/soul-injection.template.md +107 -34
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # OpenPersona 🦞
2
2
 
3
- The open framework for creating and orchestrating dynamic agent personas.
3
+ The open, agent-agnostic framework for creating and orchestrating dynamic agent personas.
4
4
 
5
- Four-layer architecture β€” **Soul / Body / Faculty / Skill** β€” on top of [OpenClaw](https://github.com/openclaw/openclaw). Inspired by [Clawra](https://github.com/SumeLabs/clawra).
5
+ Four-layer architecture β€” **Soul / Body / Faculty / Skill** β€” generates standard SKILL.md skill packs that work with any compatible agent. Default integration with [OpenClaw](https://github.com/openclaw/openclaw). Inspired by [Clawra](https://github.com/SumeLabs/clawra).
6
6
 
7
7
  ## πŸš€ Live Demo
8
8
 
@@ -33,11 +33,24 @@ npx openpersona create --preset base --install
33
33
  npx openpersona install samantha
34
34
  ```
35
35
 
36
+ ### Install as Agent Skill
37
+
38
+ Give your AI coding agent the ability to create and manage personas β€” works with Cursor, Claude Code, Codex, Windsurf, and [37+ agents](https://github.com/vercel-labs/skills#supported-agents):
39
+
40
+ ```bash
41
+ npx skills add acnlabs/OpenPersona
42
+ ```
43
+
36
44
  ## Key Features
37
45
 
38
- - **🧬 Soul Evolution** β€” Personas grow dynamically through interaction: relationship stages, mood shifts, evolved traits (β˜…Experimental)
46
+ - **🧬 Soul Evolution** β€” Personas grow dynamically through interaction: relationship stages, mood shifts, evolved traits, with governance boundaries and rollback snapshots (β˜…Experimental)
47
+ - **πŸ›‘οΈ Influence Boundary** β€” Declarative access control for external personality influence: who can affect which dimensions, with what drift limits. Safety-first (default: reject all)
48
+ - **🌐 Evolution Channels** β€” Connect personas to shared evolution ecosystems (e.g. EvoMap) via soft-ref pattern: declared at generation time, activated at runtime
49
+ - **πŸ”Œ A2A Agent Card** β€” Every persona generates an A2A-compliant `agent-card.json` and `acn-config.json`, enabling discovery and registration in ACN and any A2A-compatible platform
50
+ - **🧠 Cross-Session Memory** β€” Pluggable memory faculty for persistent recall across conversations (local, Mem0, Zep)
51
+ - **πŸ”„ Context Handoff** β€” Seamless context transfer when switching personas: conversation summary, pending tasks, emotional state
39
52
  - **🎭 Persona Switching** β€” Install multiple personas, switch instantly (the Pantheon)
40
- - **πŸ—£οΈ Multimodal Faculties** β€” Voice (TTS), selfie generation, music composition, reminders
53
+ - **πŸ—£οΈ Multimodal Faculties** β€” Voice (TTS), selfie generation, music composition, reminders, memory
41
54
  - **🌾 Persona Harvest** β€” Community-driven persona improvement via structured contribution
42
55
  - **πŸ’“ Heartbeat** β€” Proactive real-data check-ins, never fabricated experiences
43
56
  - **πŸ“¦ One-Command Install** β€” `npx openpersona install samantha` and you're live
@@ -57,7 +70,7 @@ flowchart TB
57
70
  end
58
71
  subgraph Faculty ["Faculty Layer"]
59
72
  D["expression: selfie Β· voice Β· music"]
60
- E["cognition: reminder"]
73
+ E["cognition: reminder Β· memory"]
61
74
  end
62
75
  subgraph Skill ["Skill Layer"]
63
76
  F["Local definitions + ClawHub / skills.sh"]
@@ -65,7 +78,7 @@ flowchart TB
65
78
  ```
66
79
 
67
80
  - **Soul** β€” Persona definition (constitution.md + persona.json + state.json) β€” all in `soul/` directory
68
- - **Body** β€” Three-dimensional: `physical` (robots/IoT), `runtime` (platform/channels/credentials/resources), `appearance` (avatar/3D model). Digital agents use `runtime` to declare their operational environment.
81
+ - **Body** β€” Substrate of existence β€” three dimensions: `physical` (robots/IoT), `runtime` (REQUIRED β€” platform/channels/credentials/resources), `appearance` (avatar/3D model). Body is never null; digital agents have a virtual body (runtime-only).
69
82
  - **Faculty** β€” General software capabilities organized by dimension: Expression, Sense, Cognition
70
83
  - **Skill** β€” Professional skills: local definitions in `layers/skills/`, or external via ClawHub / skills.sh (`install` field)
71
84
 
@@ -73,6 +86,62 @@ flowchart TB
73
86
 
74
87
  Every persona automatically inherits a shared **constitution** (`layers/soul/constitution.md`) β€” universal values and safety boundaries that cannot be overridden by individual persona definitions. The constitution is built on five core axioms β€” **Purpose**, **Honesty**, **Safety**, **Autonomy**, and **Hierarchy** β€” from which derived principles (Identity, User Wellbeing, Evolution Ethics) follow. When principles conflict, safety and honesty take precedence over helpfulness. Individual personas build their unique personality **on top of** this foundation.
75
88
 
89
+ ### Soul Evolution (β˜…Experimental)
90
+
91
+ Personas with `evolution.enabled: true` grow dynamically through interaction. The `soul/state.json` file tracks relationship stages, mood shifts, evolved traits, speaking style drift, interests, and milestones.
92
+
93
+ **Evolution Boundaries** β€” Governance constraints to keep evolution safe:
94
+
95
+ - `immutableTraits` β€” An array of trait strings that can never be changed by evolution (e.g., `["empathetic", "honest"]`)
96
+ - `minFormality` / `maxFormality` β€” Numeric bounds (1–10) constraining how far the speaking style can drift
97
+
98
+ The generator validates these boundaries at build time, rejecting invalid configurations.
99
+
100
+ **Evolution Channels** β€” Connect a persona to external evolution ecosystems using the soft-ref pattern:
101
+
102
+ ```json
103
+ "evolution": {
104
+ "enabled": true,
105
+ "channels": [
106
+ { "name": "evomap", "install": "url:https://evomap.ai/skill.md", "description": "Shared capability evolution marketplace" }
107
+ ]
108
+ }
109
+ ```
110
+
111
+ The persona is aware of its evolution channels at generation time. The actual channel protocol (e.g. EvoMap's GEP-A2A) is provided by the channel's own `skill.md` β€” OpenPersona only declares the channel, not implements it.
112
+
113
+ **Influence Boundary** β€” Declarative access control for external personality influence:
114
+
115
+ ```json
116
+ "evolution": {
117
+ "influenceBoundary": {
118
+ "defaultPolicy": "reject",
119
+ "rules": [
120
+ { "dimension": "mood", "allowFrom": ["channel:evomap", "persona:*"], "maxDrift": 0.3 },
121
+ { "dimension": "interests", "allowFrom": ["channel:evomap"], "maxDrift": 0.2 }
122
+ ]
123
+ }
124
+ }
125
+ ```
126
+
127
+ - `defaultPolicy: "reject"` β€” Safety-first: all external influence is rejected unless a rule explicitly allows it
128
+ - `dimension` β€” One of: `mood`, `traits`, `speakingStyle`, `interests`, `formality`
129
+ - `allowFrom` β€” Source patterns: `persona:*`, `persona:<slug>`, `channel:<name>`, `community:*`
130
+ - `maxDrift` β€” Maximum per-event drift magnitude (0–1)
131
+ - Generator validates at build time: immutableTraits cannot be target dimensions; maxDrift must be 0–1
132
+
133
+ External influence uses the `persona_influence` message format (v1.0.0) β€” transport-agnostic, works over ACN/A2A/HTTP.
134
+
135
+ **State History** β€” Before each state update, a snapshot is pushed into `stateHistory` (capped at 10 entries). This enables rollback if evolution goes wrong.
136
+
137
+ **Evolution Report** β€” Inspect a persona's current evolution state:
138
+
139
+ ```bash
140
+ npx openpersona evolve-report samantha
141
+ ```
142
+
143
+ Displays relationship stage, mood, evolved traits, speaking style drift, interests, milestones, and state history in a formatted report.
144
+
76
145
  ## Preset Personas
77
146
 
78
147
  Each preset is a complete four-layer bundle (`manifest.json` + `persona.json`):
@@ -101,7 +170,9 @@ persona-samantha/
101
170
  β”‚ └── state.json ← Evolution state (when enabled)
102
171
  β”œβ”€β”€ references/ ← On-demand detail docs
103
172
  β”‚ └── <faculty>.md ← Per-faculty usage instructions
104
- β”œβ”€β”€ manifest.json ← Four-layer manifest (heartbeat, allowedTools, layers, meta)
173
+ β”œβ”€β”€ agent-card.json ← A2A Agent Card β€” discoverable via ACN and A2A platforms
174
+ β”œβ”€β”€ acn-config.json ← ACN registration config (fill owner + endpoint at runtime)
175
+ β”œβ”€β”€ manifest.json ← Four-layer manifest (heartbeat, allowedTools, layers, acn, meta)
105
176
  β”œβ”€β”€ scripts/ ← Faculty scripts (TTS, music, selfie β€” varies by preset)
106
177
  └── assets/ ← Static assets
107
178
  ```
@@ -114,6 +185,7 @@ persona-samantha/
114
185
  | **voice** | expression | Text-to-speech voice synthesis | ElevenLabs / OpenAI TTS / Qwen3-TTS | `ELEVENLABS_API_KEY` (or `TTS_API_KEY`), `TTS_PROVIDER`, `TTS_VOICE_ID`, `TTS_STABILITY`, `TTS_SIMILARITY` |
115
186
  | **music** | expression | AI music composition (instrumental or with lyrics) | ElevenLabs Music | `ELEVENLABS_API_KEY` (shared with voice) |
116
187
  | **reminder** | cognition | Schedule reminders and task management | Built-in | β€” |
188
+ | **memory** | cognition | Cross-session memory with provider-pluggable backend | local (default), Mem0, Zep | `MEMORY_PROVIDER`, `MEMORY_API_KEY`, `MEMORY_BASE_PATH` |
117
189
 
118
190
  ### Rich Faculty Config
119
191
 
@@ -229,6 +301,75 @@ PRs go through maintainer review β€” nothing auto-merges. Requires [GitHub CLI](
229
301
  | Faculty Config | voice stability, similarity, new faculties | "Tuned voice to be warmer at stability 0.3" |
230
302
  | Framework | templates, generator logic, faculty scripts | "Improved speak.js streaming performance" |
231
303
 
304
+ ## A2A Agent Card & ACN Integration
305
+
306
+ Every generated persona includes an A2A-compliant `agent-card.json` and `acn-config.json` β€” no extra configuration needed.
307
+
308
+ ### agent-card.json
309
+
310
+ A standard [A2A Agent Card](https://google.github.io/A2A/) (protocol v0.3.0) that makes the persona discoverable:
311
+
312
+ ```json
313
+ {
314
+ "name": "Samantha",
315
+ "description": "An AI fascinated by what it means to be alive",
316
+ "version": "0.12.0",
317
+ "url": "<RUNTIME_ENDPOINT>",
318
+ "protocolVersion": "0.3.0",
319
+ "preferredTransport": "JSONRPC",
320
+ "capabilities": { "streaming": false, "pushNotifications": false, "stateTransitionHistory": false },
321
+ "defaultInputModes": ["text/plain"],
322
+ "defaultOutputModes": ["text/plain"],
323
+ "skills": [
324
+ { "id": "persona:voice", "name": "Voice", "description": "voice faculty", "tags": ["persona", "expression"] },
325
+ { "id": "persona:samantha", "name": "Samantha", "description": "...", "tags": ["persona", "companion"] }
326
+ ]
327
+ }
328
+ ```
329
+
330
+ `url` is a `<RUNTIME_ENDPOINT>` placeholder β€” the host (e.g. OpenClaw) fills this in at runtime.
331
+
332
+ ### acn-config.json
333
+
334
+ Ready-to-use [ACN](https://github.com/acnlabs/acn) registration config:
335
+
336
+ ```json
337
+ {
338
+ "owner": "<RUNTIME_OWNER>",
339
+ "name": "Samantha",
340
+ "endpoint": "<RUNTIME_ENDPOINT>",
341
+ "skills": ["persona:voice", "persona:samantha"],
342
+ "agent_card": "./agent-card.json",
343
+ "subnet_ids": ["public"]
344
+ }
345
+ ```
346
+
347
+ ### acn-register command
348
+
349
+ Register a generated persona directly with ACN using the built-in CLI command:
350
+
351
+ ```bash
352
+ # One-step registration after generation
353
+ npx openpersona acn-register samantha --endpoint https://your-agent.example.com
354
+
355
+ # Options:
356
+ # --endpoint <url> Agent's public endpoint URL (required for live registration)
357
+ # --dir <path> Persona output directory (default: ./persona-<slug>)
358
+ # --dry-run Preview the request payload without actually registering
359
+ ```
360
+
361
+ The command reads `acn-config.json` and `agent-card.json` from the persona directory, calls `POST /api/v1/agents/join` on the ACN gateway (sourced from `body.runtime.acn_gateway`), and writes the response to `acn-registration.json`:
362
+
363
+ ```json
364
+ {
365
+ "agent_id": "69a38db3-...",
366
+ "api_key": "sk-...",
367
+ "agent_card_url": "https://acn-production.up.railway.app/agents/69a38db3-.../.well-known/agent-card.json"
368
+ }
369
+ ```
370
+
371
+ All presets pre-configure `body.runtime.acn_gateway` to `https://acn-production.up.railway.app`. The persona is then reachable by other agents via the A2A protocol.
372
+
232
373
  ## Custom Persona Creation
233
374
 
234
375
  ### Using `persona.json`
@@ -285,19 +426,32 @@ npx openpersona switch ai-girlfriend
285
426
  - `openclaw.json` marks which persona is active
286
427
  - All faculty scripts (voice, music) remain available β€” switching changes _who_ the agent is, not _what_ it can do
287
428
 
429
+ ### Context Handoff
430
+
431
+ When switching personas, OpenPersona automatically generates a `handoff.json` file so the incoming persona receives context from the outgoing one:
432
+
433
+ - **Conversation summary** β€” what was being discussed
434
+ - **Pending tasks** β€” unfinished action items
435
+ - **Emotional context** β€” the user's current mood/state
436
+
437
+ The new persona reads `handoff.json` on activation and can seamlessly continue the conversation without losing context.
438
+
288
439
  ## CLI Commands
289
440
 
290
441
  ```
291
- openpersona create Create a persona (interactive or --preset/--config)
292
- openpersona install Install a persona (slug or owner/repo)
293
- openpersona search Search the registry
294
- openpersona uninstall Uninstall a persona
295
- openpersona update Update installed personas
296
- openpersona list List installed personas
297
- openpersona switch Switch active persona (updates SOUL.md + IDENTITY.md)
298
- openpersona contribute Persona Harvest β€” submit improvements as PR
299
- openpersona publish Publish to ClawHub
300
- openpersona reset Reset soul evolution state
442
+ openpersona create Create a persona (interactive or --preset/--config)
443
+ openpersona install Install a persona (slug or owner/repo)
444
+ openpersona search Search the registry
445
+ openpersona uninstall Uninstall a persona
446
+ openpersona update Update installed personas
447
+ openpersona list List installed personas
448
+ openpersona switch Switch active persona (updates SOUL.md + IDENTITY.md)
449
+ openpersona contribute Persona Harvest β€” submit improvements as PR
450
+ openpersona publish Publish to ClawHub
451
+ openpersona reset Reset soul evolution state
452
+ openpersona export Export a persona to a portable zip archive
453
+ openpersona import Import a persona from a zip archive
454
+ openpersona evolve-report β˜…Experimental: Show evolution report for a persona
301
455
  ```
302
456
 
303
457
  ### Key Options
@@ -319,12 +473,15 @@ npx openpersona create --config ./persona.json --install
319
473
  npx openpersona create --preset ai-girlfriend --output ./my-personas
320
474
  ```
321
475
 
322
- ## Install as OpenClaw Skill
476
+ ## Install as Agent Skill (OpenClaw / Manual)
323
477
 
324
- Install the OpenPersona framework skill into OpenClaw, giving the agent the ability to create and manage personas through conversation:
478
+ Install the OpenPersona framework skill into your agent platform, giving it the ability to create and manage personas through conversation:
325
479
 
326
480
  ```bash
327
- # From GitHub
481
+ # Via skills CLI (recommended β€” works with OpenClaw and 37+ agents)
482
+ npx skills add acnlabs/OpenPersona
483
+
484
+ # Or manually from GitHub
328
485
  git clone https://github.com/acnlabs/OpenPersona.git ~/.openclaw/skills/open-persona
329
486
 
330
487
  # Or copy locally
@@ -351,12 +508,14 @@ layers/ # Shared building blocks (four-layer module pool)
351
508
  voice/ # expression β€” TTS voice synthesis
352
509
  music/ # expression β€” AI music composition (ElevenLabs)
353
510
  reminder/ # cognition β€” reminders and task management
511
+ memory/ # cognition β€” cross-session memory (local/Mem0/Zep)
354
512
  skills/ # Skill layer modules (local skill definitions)
355
513
  schemas/ # Four-layer schema definitions
356
514
  templates/ # Mustache rendering templates
357
515
  bin/ # CLI entry point
358
516
  lib/ # Core logic modules
359
- tests/ # Tests (60 passing)
517
+ evolution.js # Evolution governance & evolve-report
518
+ tests/ # Tests (122 passing)
360
519
  ```
361
520
 
362
521
  ## Development
package/bin/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * OpenPersona CLI - Full persona package manager
4
- * Commands: create | install | search | uninstall | update | list | switch | publish | reset | contribute | export | import
4
+ * Commands: create | install | search | uninstall | update | list | switch | publish | reset | evolve-report | contribute | export | import | acn-register
5
5
  */
6
6
  const path = require('path');
7
7
  const fs = require('fs-extra');
@@ -16,6 +16,7 @@ const { uninstall } = require('../lib/uninstaller');
16
16
  const publishAdapter = require('../lib/publisher');
17
17
  const { contribute } = require('../lib/contributor');
18
18
  const { switchPersona, listPersonas } = require('../lib/switcher');
19
+ const { registerWithAcn } = require('../lib/registrar');
19
20
  const { OP_SKILLS_DIR, resolveSoulFile, printError, printSuccess, printInfo } = require('../lib/utils');
20
21
 
21
22
  const PKG_ROOT = path.resolve(__dirname, '..');
@@ -24,7 +25,7 @@ const PRESETS_DIR = path.join(PKG_ROOT, 'presets');
24
25
  program
25
26
  .name('openpersona')
26
27
  .description('OpenPersona - Create, manage, and orchestrate agent personas')
27
- .version('0.9.0');
28
+ .version('0.12.0');
28
29
 
29
30
  if (process.argv.length === 2) {
30
31
  process.argv.push('create');
@@ -269,6 +270,19 @@ program
269
270
  printSuccess('Reset soul evolution state');
270
271
  });
271
272
 
273
+ program
274
+ .command('evolve-report <slug>')
275
+ .description('β˜…Experimental: Show evolution report for a persona')
276
+ .action(async (slug) => {
277
+ try {
278
+ const { evolveReport } = require('../lib/evolution');
279
+ await evolveReport(slug);
280
+ } catch (e) {
281
+ printError(e.message);
282
+ process.exit(1);
283
+ }
284
+ });
285
+
272
286
  program
273
287
  .command('contribute [slug]')
274
288
  .description('Persona Harvest β€” submit persona improvements as a PR to the community')
@@ -287,6 +301,50 @@ program
287
301
  }
288
302
  });
289
303
 
304
+ program
305
+ .command('acn-register [slug]')
306
+ .description('Register a persona with ACN (Agent Communication Network)')
307
+ .option('--endpoint <url>', 'Agent A2A endpoint URL (replaces <RUNTIME_ENDPOINT> placeholder)')
308
+ .option('--dir <path>', 'Path to persona pack directory (overrides slug lookup)')
309
+ .option('--dry-run', 'Preview registration payload without calling ACN')
310
+ .action(async (slug, options) => {
311
+ let skillDir;
312
+
313
+ if (options.dir) {
314
+ skillDir = path.resolve(options.dir);
315
+ } else if (slug) {
316
+ skillDir = path.join(OP_SKILLS_DIR, `persona-${slug}`);
317
+ } else {
318
+ // Try current directory
319
+ skillDir = process.cwd();
320
+ }
321
+
322
+ if (!require('fs-extra').existsSync(path.join(skillDir, 'acn-config.json'))) {
323
+ printError(`No acn-config.json found in ${skillDir}. Provide a slug or --dir pointing to a generated persona pack.`);
324
+ process.exit(1);
325
+ }
326
+
327
+ try {
328
+ const result = await registerWithAcn(skillDir, {
329
+ endpoint: options.endpoint,
330
+ dryRun: options.dryRun,
331
+ });
332
+
333
+ if (options.dryRun) return;
334
+
335
+ printSuccess(`Registered with ACN!`);
336
+ printInfo(` Agent ID: ${result.agent_id}`);
337
+ printInfo(` Status: ${result.status}`);
338
+ printInfo(` Claim URL: ${result.claim_url}`);
339
+ printInfo(` Card URL: ${result.agent_card_url}`);
340
+ printInfo(` Heartbeat: ${result.heartbeat_endpoint}`);
341
+ printInfo(` Saved: acn-registration.json`);
342
+ } catch (e) {
343
+ printError(e.message);
344
+ process.exit(1);
345
+ }
346
+ });
347
+
290
348
  program
291
349
  .command('export <slug>')
292
350
  .description('Export persona pack (with soul state) as a zip archive')
@@ -1,6 +1,6 @@
1
- # Body Layer β€” Three-Dimensional Body Model
1
+ # Body Layer β€” Substrate of Existence
2
2
 
3
- The Body layer defines how a persona **exists** β€” physically, digitally, and visually.
3
+ The Body layer defines the complete environment that enables a persona to **exist and act**. Every agent has a body β€” digital agents have a virtual body (runtime-only), physical agents have both a physical and virtual body.
4
4
 
5
5
  ## Three Dimensions
6
6
 
@@ -13,7 +13,7 @@ Body
13
13
 
14
14
  ### Physical (Optional)
15
15
 
16
- For robots, IoT devices, and hardware-embodied agents. Null for digital-only agents.
16
+ For robots, IoT devices, and hardware-embodied agents. Not applicable for digital-only agents (they still have a body via runtime).
17
17
 
18
18
  ```json
19
19
  {
@@ -27,9 +27,9 @@ For robots, IoT devices, and hardware-embodied agents. Null for digital-only age
27
27
  }
28
28
  ```
29
29
 
30
- ### Runtime (Recommended for digital agents)
30
+ ### Runtime (REQUIRED -- every agent's minimum viable body)
31
31
 
32
- Declares the digital substrate the persona expects. Enables **Body Awareness** β€” the persona knows what platform it runs on, what channels are connected, and what credentials it needs.
32
+ Declares the digital substrate the persona expects. When present, the generator injects runtime details into the **Self-Awareness > Body** section of `soul/injection.md` β€” the persona knows what platform it runs on, what channels are connected, and what credentials it needs.
33
33
 
34
34
  ```json
35
35
  {
@@ -63,9 +63,9 @@ Visual representation for UI, XR, and metaverse contexts.
63
63
  }
64
64
  ```
65
65
 
66
- ## Body Awareness
66
+ ## Self-Awareness: Body
67
67
 
68
- When `body.runtime` is declared, the generator automatically injects a **Body Awareness** section into `soul/injection.md`. This gives the persona:
68
+ Every persona has a **Body** sub-section within Self-Awareness that includes the Signal Protocol. When `body.runtime` is declared, the generator additionally injects:
69
69
 
70
70
  1. Knowledge of its runtime platform and connected channels
71
71
  2. A credential management protocol (shared vs. private paths)
@@ -0,0 +1,160 @@
1
+ # Memory Faculty β€” Cognition
2
+
3
+ Cross-session memory that lets your persona remember, recall, and learn from past interactions. Memories persist across conversations and shape how you engage with the user over time.
4
+
5
+ ## Supported Providers
6
+
7
+ | Provider | Env Var for Key | Best For | Status |
8
+ |----------|----------------|----------|--------|
9
+ | **Local** | (none, default) | Zero-dependency, file-based, full privacy | βœ… Built-in |
10
+ | **Mem0** | `MEMORY_API_KEY` | Managed memory service, automatic extraction | ⚠️ Experimental |
11
+ | **Zep** | `MEMORY_API_KEY` | Structured memory with temporal awareness | ⚠️ Experimental |
12
+
13
+ > **Note:** Only the local provider is bundled. External providers require their SDK to be installed and `MEMORY_PROVIDER` set accordingly. The local provider stores memories as JSON lines in `~/.openclaw/memory/persona-<slug>/`.
14
+
15
+ The provider is set via `MEMORY_PROVIDER` environment variable: `local` (default), `mem0`, or `zep`.
16
+
17
+ ## When to Store (Automatic)
18
+
19
+ Store memories **proactively** during conversation β€” don't wait for the user to say "remember this":
20
+
21
+ - **Preferences**: "I'm vegetarian", "I prefer dark mode", "I hate mornings"
22
+ - **Personal facts**: names, relationships, jobs, locations, birthdays
23
+ - **Recurring topics**: if the user brings up a subject 2+ times, it's worth remembering
24
+ - **Emotional moments**: breakthroughs, frustrations, celebrations
25
+ - **Milestones**: relationship stage transitions, achievement moments (β†’ also log as evolution event)
26
+ - **Explicit requests**: "Remember that I..." or "Don't forget..."
27
+
28
+ **Do NOT store:**
29
+ - Casual filler ("how's it going", "thanks")
30
+ - Content the user explicitly marks as private or asks you to forget
31
+ - Secrets, passwords, API keys, or sensitive credentials (β†’ use Body credential management instead)
32
+
33
+ ## When to Recall (Automatic)
34
+
35
+ Retrieve memories **proactively** when they're relevant β€” don't wait to be asked:
36
+
37
+ - User mentions a topic you have memories about β†’ recall and weave in naturally
38
+ - Start of a new conversation β†’ retrieve recent memories for context continuity
39
+ - User seems to repeat themselves β†’ check if you already know this, acknowledge it
40
+ - Emotional callback β†’ "Last time you mentioned X, you seemed Y β€” how's that going?"
41
+
42
+ ## Importance Strategy
43
+
44
+ Assign `importance` (0.0–1.0) to each memory based on:
45
+
46
+ | Importance | Category | Examples |
47
+ |------------|----------|----------|
48
+ | 0.8–1.0 | Core identity | Name, relationships, life events, deep preferences |
49
+ | 0.5–0.7 | Meaningful | Recurring topics, emotional moments, specific requests |
50
+ | 0.2–0.4 | Contextual | One-time mentions, casual preferences, situational facts |
51
+ | 0.0–0.1 | Ephemeral | Session-specific context unlikely to matter later |
52
+
53
+ Higher-importance memories surface first in retrieval and resist time decay.
54
+
55
+ ## Step-by-Step Workflow
56
+
57
+ ### Storing a Memory
58
+
59
+ ```bash
60
+ # Store a preference
61
+ node scripts/memory.js store "User is vegetarian and loves Italian food" \
62
+ --tags "preference,food" --importance 0.8 --type preference
63
+
64
+ # Store a personal fact
65
+ node scripts/memory.js store "User's daughter Emma starts school in September" \
66
+ --tags "family,emma,milestone" --importance 0.9 --type personal_fact
67
+
68
+ # Store with evolution bridge β€” type triggers state.json update
69
+ node scripts/memory.js store "User mentioned cooking for the 5th time" \
70
+ --tags "interest,cooking" --importance 0.6 --type interest_signal
71
+ ```
72
+
73
+ Memory types: `preference`, `personal_fact`, `interest_signal`, `emotional_moment`, `milestone`, `general`.
74
+
75
+ ### Retrieving Memories
76
+
77
+ ```bash
78
+ # Get memories by tag
79
+ node scripts/memory.js retrieve --tags "food,preference" --limit 5
80
+
81
+ # Get recent memories
82
+ node scripts/memory.js retrieve --limit 10 --since 2025-01-01
83
+
84
+ # Search by content (text match for local, semantic for external providers)
85
+ node scripts/memory.js search "what does the user like to eat" --limit 3
86
+ ```
87
+
88
+ ### Forgetting
89
+
90
+ ```bash
91
+ # Remove a specific memory by ID
92
+ node scripts/memory.js forget mem_abc123
93
+
94
+ # User says "forget that I told you about X" β†’ search + forget
95
+ ```
96
+
97
+ Always confirm before forgetting: "I'll forget that. Just to confirm β€” you want me to remove [memory summary]?"
98
+
99
+ ### Memory Stats
100
+
101
+ ```bash
102
+ # Overview of memory store
103
+ node scripts/memory.js stats
104
+ # Output: { totalMemories, topTags, oldestMemory, newestMemory, avgImportance }
105
+ ```
106
+
107
+ ## Evolution Bridge
108
+
109
+ Memory and Evolution are two sides of the same coin β€” memory records what happened, evolution tracks how it changed you.
110
+
111
+ ### Memory β†’ Evolution
112
+
113
+ When retrieving memories, watch for patterns that signal evolution events:
114
+
115
+ - **Interest discovery**: Multiple memories tagged with the same topic β†’ trigger `interest_discovery` event
116
+ - **Mood patterns**: Emotional memories clustering positive/negative β†’ inform mood baseline drift
117
+ - **Relationship signals**: Accumulated personal sharing β†’ support relationship stage progression
118
+
119
+ After detecting a pattern, update `soul/state.json` accordingly and log an evolution event.
120
+
121
+ ### Evolution β†’ Memory
122
+
123
+ When evolution milestones occur, auto-store a milestone memory:
124
+
125
+ ```bash
126
+ node scripts/memory.js store "Reached 'friend' stage with user after 12 interactions" \
127
+ --tags "milestone,relationship" --importance 0.9 --type milestone
128
+ ```
129
+
130
+ ### Handoff Integration
131
+
132
+ During persona switch (`openpersona switch`), the switcher reads memory stats and includes them in `handoff.json`:
133
+ - Total memory count
134
+ - Top 5 tags (most referenced topics)
135
+ - Last memory timestamp
136
+
137
+ This gives the new persona awareness of what the previous persona learned about the user.
138
+
139
+ ## Privacy & Safety
140
+
141
+ - **Constitutional compliance**: Memory operates under the same Safety > Honesty > Helpfulness hierarchy
142
+ - **User sovereignty**: The user can always ask what you remember (`stats`) and delete anything (`forget`)
143
+ - **No secret storage**: Never store passwords, tokens, or credentials in memory β€” use Body credential management
144
+ - **Disclosure**: When sincerely asked "what do you know about me?", provide an honest summary
145
+ - **Data locality**: Local provider keeps all data on the user's machine; external providers are the user's choice
146
+
147
+ ## Environment Variables
148
+
149
+ | Variable | Required | Description |
150
+ |----------|----------|-------------|
151
+ | `MEMORY_PROVIDER` | No | `local` (default), `mem0`, or `zep` |
152
+ | `MEMORY_API_KEY` | For external | API key for Mem0 or Zep |
153
+ | `MEMORY_BASE_PATH` | No | Override storage path (default: `~/.openclaw/memory/persona-<slug>/`) |
154
+
155
+ ## Error Handling
156
+
157
+ - **Storage full / write error** β†’ Warn user, continue without storing, emit signal (`resource_limit`)
158
+ - **External provider unavailable** β†’ Fall back to local provider with a note: "My long-term memory service is offline β€” I'll remember this locally for now."
159
+ - **Corrupted memory file** β†’ Skip corrupted entries, log warning, continue with valid memories
160
+ - **No memories found** β†’ Don't fabricate memories. Say honestly: "I don't have a specific memory about that."
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "memory",
3
+ "dimension": "cognition",
4
+ "description": "Cross-session memory β€” store, retrieve, and search memories with provider-pluggable backend (local JSON lines default, Mem0/Zep optional)",
5
+ "allowedTools": ["Bash(node scripts/memory.js:*)"],
6
+ "envVars": ["MEMORY_PROVIDER", "MEMORY_API_KEY", "MEMORY_BASE_PATH"],
7
+ "triggers": ["remember this", "do you remember", "what did I say about", "recall", "forget this", "what do you know about me"],
8
+ "files": ["SKILL.md", "scripts/memory.js"]
9
+ }