Skip to main content

Memory & Sessions

Global Agent Identity

A single .agent/IDENTITY.md file defines the agent's persona, tone, and base posture for every project and conversation -- it is the first block of the system prompt.

  • Edit it to rebrand the assistant.
  • Delete it and the runtime regenerates a sensible default on next start.
  • No environment variable, fixed path; read-only hosts (containers) fall back to the built-in default instead of failing to boot.

User Preference Memory

The agent keeps a small, durable profile of how you like to be helped (preferences, communication style, expectations, workflow habits) in a single .agent/USER.md file, rendered into the system prompt right after the Identity.

  • The agent maintains the file itself during chats via an inline memory tool (add / replace / remove / consolidate). It reconciles rather than just appends: a newer explicit preference supersedes a conflicting older one, so mutually exclusive preferences (like your default answer language) stay a single line instead of piling up.
  • A deterministic filter blocks secrets and sensitive personal data from ever being stored, and the file is kept small (USER_CHAR_LIMIT, default 1375).
  • Each session reads a frozen snapshot taken at session start, so prompts stay cache-stable and consistent across reloads; anything learned mid-session takes effect from your next session.

On by default; set USER_PROFILE_ENABLED=false to turn it off. Fixed path; read-only hosts fall back to a built-in default.

note

Temporary Chat never reads or writes this profile, so throwaway conversations do not shape personalization.

Background reconciliation (optional)

Let the memory maintain itself. When enabled, a background pass periodically distills your recent conversation and reconciles the whole profile -- merging duplicates, resolving contradictions, dropping reversed or outdated preferences, and integrating new ones -- so it never drifts into a pile of conflicting lines.

USER_MEMORY_EXTRACTION=true # default: false (off, byte-for-byte prior behavior)
USER_MEMORY_EXTRACTION_EVERY_N_TURNS=4 # run at most once every N new user turns

The extraction model is assigned in the Model Offering Catalog under Model Settings -> Task model assignments (the roles.user_memory_extraction binding, or chatwalaau models role set user_memory_extraction <offering-id>). Leave it unset to use the chat's own model. The dedicated USER_MEMORY_EXTRACTION_MODEL variable was removed in v0.109.0.

  • Requires USER_PROFILE_ENABLED=true. Runs in the background and never blocks or delays your message.
  • Uses the same safety as the inline tool (secret/PII filter, size cap, and a backup of the previous file); an empty or unchanged result never wipes or needlessly rewrites your memory.
  • Temporary Chat and demo mode never trigger it. Changes take effect from your next session (the running session keeps its frozen snapshot).

Agent Memory

Alongside the user-preference memory ("about you"), the agent keeps a second curated memory about the work in a single .agent/MEMORY.md file: durable, reusable facts about your environment and project -- conventions ("this project uses pnpm"), commands ("run tests with uv run pytest"), tool quirks, and stable operating rules. It is rendered into the system prompt as an <agent-memory> block, right after the user profile.

It is stored as a list of independent entries (not one long note), which keeps it easy to de-duplicate, reconcile, and edit one fact at a time.

There are two ways it gets filled:

  • The assistant notes things itself. During a chat it can record a durable fact via an inline manage_memory tool (add / remove / modify a single entry / batch).
  • You give a turn a thumbs-up. A "remember this turn" like sits on every message (user and assistant); clicking it runs a lightweight background pass that distills that turn into the memory. The like shows a live saving / saved / failed status and is saved with the chat, so it stays filled when you reload. Liking either message of a turn processes the pair as one set.

Every write shares the same safety as the user memory -- a deterministic filter blocks secrets and sensitive data, the file is capped (MEMORY_CHAR_LIMIT, default 2200), and the previous file is backed up first -- plus a hardened write (exact duplicates are rejected; writes are atomic and lock-guarded).

AGENT_MEMORY_ENABLED=true # default: true (matches USER_PROFILE_ENABLED)
MEMORY_CHAR_LIMIT=2200 # cap on the curated memory body

The curation model is assigned in the Model Offering Catalog under Model Settings -> Task model assignments (roles.agent_memory_curation); leave it unset to use the chat's own model. The dedicated AGENT_MEMORY_CURATION_MODEL variable was removed in v0.109.0.

On by default, but a fresh MEMORY.md is empty and adds nothing to the prompt, so a new install is unchanged until something is actually remembered. Changes take effect from your next session (the running session keeps its frozen snapshot). Temporary Chat and demo mode never trigger curation. Set AGENT_MEMORY_ENABLED=false to turn the whole feature off.

note

This memory is about the work; your personal preferences live in the separate User Preference Memory (.agent/USER.md). The like never writes to your preference memory.

Editing your memory files

Open the Agent Memory panel from the brain icon in the sidebar footer to view and edit all three built-in memory files yourself:

  • Identity (.agent/IDENTITY.md) -- the assistant's persona and tone
  • Preferences (.agent/USER.md) -- what it remembers about you
  • Notes (.agent/MEMORY.md) -- its own notes about your project

Each file opens in a Markdown editor with syntax highlighting and a live character-count against its limit. Saving writes a timestamped backup first, so a previous version is always recoverable, and closing with unsaved edits asks for confirmation. Edits apply from your next chat (the identity applies on the next restart) -- the running conversation keeps its frozen snapshot.

note

This editor is for you, the operator: your edits are saved as written (only a size limit is enforced -- the secret/PII filter that guards the assistant's own writes is not applied to your direct edits). Access is protected by the same sign-in as the rest of the app.

Session management

Conversations are saved as JSON files on your machine. You can save, search, organize into folders, pin, archive, fork, and rename them.

The chat sidebar

  • The Folders and Chats sections each collapse from their header, so you can fold one away and give the other the whole panel. Both start expanded, and the choice is remembered per device.
  • Rows are compact. At rest a row shows only its title; hover it to see when it was last updated and its message / image counts. (The row does not change height when you hover, so the list never shifts under your cursor. The chat you currently have open keeps that line visible.) The API and Teams badges stay visible at all times -- they tell you the conversation did not come from the web UI.
  • Times are shown as YYYY/MM/DD HH:mm in 24-hour form, the same on every machine regardless of the browser's language.
  • The chat list loads as you scroll rather than all at once, so the sidebar stays responsive with hundreds of conversations; skeleton rows show where the incoming chats will land. A folder's chats are loaded when you open it.
  • Pinned chats always come first, then the most recently updated. That ordering now comes from the server, so it is the same in the web UI and in chatwalaau sessions list.
Large histories

The server keeps a small index of chat metadata (.sessions/index.json) so listing your chats does not have to open and re-read every conversation file. It is a cache: deleting it is always safe -- the next listing simply rebuilds it.

  • Assign a color from a preset palette (on create, or later via the folder menu)
  • Reorder folders by drag-and-drop
  • Folders are collapsed by default, with open/closed state remembered per device
  • The folder list self-heals if its saved color/order values are ever corrupted

Export & import

Move a single chat between instances (or back it up / share it) as one self-contained file.

  • Export -- open a chat's 3-dot menu and choose Export. The chat downloads as a .zip bundle that contains the conversation and every image it references, so it stays intact when re-imported on another machine.
  • Import -- click the upload icon in the Chats sidebar section and pick a bundle. A spinner shows while it uploads; the new chat then appears in the list and is selected.

Import is safe by design: it always creates a new chat (never overwrites an existing one), validates the file before saving anything, and drops the exporter's personalization -- an imported chat lands unfiled, unpinned, and de-personalized (your user-preference memory is never carried in the bundle). SESSION_IMPORT_MAX_BYTES (default 25 MiB) caps the accepted upload size.

Auto chat titles (optional)

Set SESSION_TITLE_MODE=llm and a new chat is named by a short LLM summary of your opening exchange instead of the first message's leading text.

SESSION_TITLE_MODE=llm # default: truncate (previous behavior, byte-for-byte)

The title model is assigned in the Model Offering Catalog under Model Settings -> Task model assignments (roles.session_title, or chatwalaau models role set session_title <offering-id>); leave it unset to use the chat's own model. The dedicated SESSION_TITLE_MODEL variable was removed in v0.109.0.

  • The chat appears in the sidebar the instant you send (with a spinner while the title generates) and updates in real time when ready -- pushed over a WebSocket, no reload.
  • Generation runs in the background and never blocks or delays your message; on any failure the simple truncated title remains.
  • The spinner always resolves -- if the first reply errors, is stopped, or produces no text, the sidebar clears the pending state (keeping the simple title) instead of spinning forever.
  • The WebSocket push is the primary way titles refresh, so an open chat does not continuously re-fetch the session list. If that channel is unavailable (for example an API-key-only LAN setup where the WebSocket cannot authenticate), the sidebar falls back to a periodic list refresh until the title resolves -- so titles still appear everywhere, just without the live push.