PersonaGenerator in src/core/persona/persona-generator.ts implements the L3 layer, generating or updating the user persona using a four-layer deep scan model and writing persona.md via the LLM agent's file tools.[1] L3 persona generation is triggered every persona.triggerEveryN new memories (default 50), with a maximum of persona.maxScenes scenes processed per run (default 15).[2] The four-layer deep scan model comprises four hierarchical memory levels — raw events, scenes, summaries, and persona — with L3 persona generation synthesizing from scene-level data within this hierarchy.
PersonaGenerator accepts an optional llmRunner?: LLMRunner injection; when provided, it is used instead of CleanContextRunner, decoupling the generator from the OpenClaw runtime. The injected runner must be configured with enableTools: true.[1] PersonaGenerator defaults backupCount to 3, controlling how many rolling backups of persona.md are retained.[1]
PersonaGenerator.generateLocalPersona() uses "incremental" mode when a non-empty persona.md already exists, and "first" mode on the initial run; it skips generation entirely (returning false) when no scene changes have occurred since the last persona update and a persona file already exists.[1] Changed scenes are detected by comparing each scene's updated timestamp against checkpoint.last_persona_time; if either date is unparseable (NaN), the scene is conservatively treated as changed.[1] The LLM agent runs sandboxed to dataDir (not scene_blocks/) with a 180-second timeout, writing persona.md directly via file tools; maxTokens is omitted, so the core resolves the model's limit from its catalog.[1] In "incremental" mode, the LLM agent receives only changed scenes; in "first" mode, it receives all available scene data — determining the agent's context window and prompt construction for each run.
PersonaGenerator emits an l3_persona_generation metric report (via report()) including triggerReason, mode ("incremental" or "initial"), persona content and length, total duration, and a success flag — but only when instanceId is set.[1]
Sources