{% extends "base.html" %} {% from '_ui.html' import page_header, empty_state, id_chip %} {% from '_learning_tabs.html' import learning_tabs %} {% block title %}Persona evolution - Memorizz{% endblock %} {% block body_attrs %} data-sidebar-scope="learning" data-sidebar-default="collapsed"{% endblock %} {% block head %}{% endblock %} {% block content %} {% set pe_description = "Review how one account's approach adapts from its conversations: what changed, why, and the evidence behind it. Suggestions wait for approval, apply from the next turn and can be undone." %} {% set tabs = learning_tabs('persona-evolution') %} {% set history = (profile.persona.evolution_history or []) if profile else [] %} {% if profile %} {#- Account-wide commands. Approve and dismiss live with the suggestion itself. -#} {% call page_header('Persona evolution', pe_description, 'Continual learning', nav=tabs) %} {% if history and history[-1].action != 'undo' %}{% endif %} {% endcall %} {% else %} {{ page_header('Persona evolution', pe_description, 'Continual learning', nav=tabs) }} {% endif %}

To resolve an email address to its verified account ID, use the account lookup in Observability.

{% if error %}{% endif %} {% if not connected %} {{ empty_state("Connect your application's persona adapter"|safe, "Memorizz reads each account's canonical profile from your application. Pass a persona adapter to create_app(persona_evolution=...) to enable this page; docs/persona-evolution-hosts.md describes the adapter contract. A shared agent's persona is not a per-user profile.") }} {% elif not profile %} {{ empty_state('Start with an account', "Enter an account ID above to review its approved approach, any pending reflection and its change history.") }} {% else %} {% set agent_q = profile.agent_id|default('', true)|urlencode %} {% set user_q = user_id|urlencode %}
Approachv{{ profile.persona.version }}
Status{{ view.status }}
Pending{{ 1 if view.pending else 0 }}
Evidence{{ view.evidence }}
Changes{{ view.changes }}
Undone{{ view.undos }}
Reflections{{ view.reviews }}
Failed{{ view.failed_reviews }}
Last review{{ relative_time(view.last_review_at, now) if view.last_review_at else (view.last_review or 'Never') }}
{% if profile.daily_enabled is defined %}
Daily review{{ ('Paused' if profile.paused else 'On') if profile.daily_enabled else 'Off' }}
{% endif %}
{#- The account's current state: rendered once, placed beside or under the activity grid. -#} {% set state_panels %}

Current approach

Version {{ profile.persona.version }}

{{ profile.persona.name }} · {{ profile.persona.role }}

{{ profile.persona.goals }}

Stable foundation
Source grounding · Application rules · Explicit user preferences

Review
{{ 'Daily and manual' if profile.daily_enabled else 'Manual' }}; approval required
Status
{{ 'Paused' if profile.paused else 'Awaiting your decision' if profile.pending else 'Ready to reflect' }}
Last review
{{ profile.last_review_at or 'Not yet reviewed' }}

Reflect now reviews recent user-authored memory. It does not force a change.

{% if not writable %}

Inspection only. Persona actions must be explicitly enabled by the host.

{% elif trace_read_only %}

Trace editing stays disabled. Host persona actions may append their own audit traces.

{% endif %}

Latest reflection

{% if profile.pending %}Awaiting your decision{% elif profile.review_state == 'no_change' %}No change needed{% elif profile.review_state == 'failed' %}Failed{% elif profile.review_state == 'reviewing' %}Reviewing{% endif %}
{% if profile.pending %}

A suggestion is waiting for your decision. Nothing changes until you approve it; select it in the activity grid to compare the change and read its evidence.

{% else %}

{{ 'The reviewed conversations did not support a durable change. Your current approach stays in place.' if profile.review_state == 'no_change' else 'No suggestion is pending. When conversations support a better approach, the suggestion and its evidence appear here before anything changes.' }}

{% if profile.review_state == 'failed' %}{% endif %} {% if profile.review_state == 'reviewing' %}

Reflection is running. Refresh this page to check its result.

{% endif %} {% endif %} {% if profile.daily_enabled is defined %}

Daily reflection

Check every 24 hours, only after new conversations. Suggestions always wait for approval. This is not a midnight job; busy workers may check later.

{% if profile.daily_enabled %}

{{ 'Checks paused' if profile.paused else 'Awaiting your decision' if profile.pending else 'Next check no earlier than ' ~ (profile.next_daily_check_at or 'the next worker check') }}

{% endif %} {% if profile.last_daily_check_at %}

Last daily check: {{ profile.last_daily_check_at }} · {{ profile.last_daily_outcome|replace('_', ' ') }}

{% endif %}
{% endif %}
{% endset %} {% if view.rows %}
{% for tag, label, count in view.chips %}{% endfor %}

j k movet trace/ filter

{% for row in view.rows %} {% set entry = row.entry %} {% set trace = entry.trace if entry.trace is mapping else none %} {% endfor %}
Suggestions, approved changes and reflection attempts for this account, pending first, then newest first. Select a row to see the change and its evidence.
Version Reason By Status
{% if row.recorded %}{{ row.recorded }}{{ row.recorded[5:] if row.recorded_at else row.recorded }}{% else %}—{% endif %} {{ row.kind_label }} {{ ('v' ~ row.version) if row.version is not none else '—' }} {{ row.summary or '—' }} {{ row.evidence_count if row.evidence_count is not none else '—' }} {{ row.actor or '—' }} {{ row.status_label }}

Approved changes and reflection attempts, newest first. The latest {{ profile.history_limit }} changes and reflection attempts are retained. This is an adaptation history, not model training.

{{ state_panels }}
{% else %} {{ empty_state('No approved changes yet', 'Reflection suggestions change the persona only after approval.' ~ (' Select Reflect now to review recent conversations.' if writable else '')) }} {{ state_panels }} {% endif %} {% endif %} {% endblock %} {% block scripts %}{{ super() }}{% endblock %}