Skip to content

feat: add optional memory frontmatter tools - #1761

Open
TyceHerrman wants to merge 2 commits into
oraios:mainfrom
TyceHerrman:memory-frontmatter-current-main
Open

feat: add optional memory frontmatter tools#1761
TyceHerrman wants to merge 2 commits into
oraios:mainfrom
TyceHerrman:memory-frontmatter-current-main

Conversation

@TyceHerrman

@TyceHerrman TyceHerrman commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • port the memory frontmatter work from Issue #1055: Add minimal frontmatter parser for memory files #1119 onto the current memory-manager architecture
  • add optional memory_get_frontmatter and memory_add_frontmatter tools
  • recognize metadata only through explicitly marked, versioned Serena frontmatter
  • keep read_memory body-only and keep the default list_memories response unchanged
  • include non-empty metadata in list_memories only when the get-frontmatter tool is active
  • preserve the exact serialized metadata prefix across body writes, edits, and reference autofixes
  • update individual metadata fields without reserializing unrelated lines
  • enforce current ignored-memory and read-only rules

Compatibility and format

Managed frontmatter has the following scalar-only shape:

---
serena_frontmatter_version: 1
type: "Serena Memory"
description: "Short summary"
---

serena_frontmatter_version: 1 must be the first field, and type must be non-empty. The marker is reserved for Serena and is omitted from metadata tool and listing output. Newly created blocks default to type: "Serena Memory".

Unmarked legacy content remains ordinary memory body content, including valid-looking, empty, and malformed leading --- blocks. Parsing is independent of active tools, so identical files read consistently in every tool context. Marked blocks are hidden from read_memory; their original quotes, whitespace, field order, and newline style are retained during body-only writes. Field updates replace only the selected value or insert one line before the closing delimiter, rendering new values as reversible JSON-style quoted strings.

Duplicate keys, malformed marked blocks, missing or empty type, unsupported Serena frontmatter versions, and writes to the reserved marker fail before the file is modified.

Minimal OKF alignment

While addressing the compatibility feedback, this also takes the opportunity for minimal field-level alignment with Google's Open Knowledge Format v0.2: Serena uses the useful field names type and description where applicable.

This does not claim OKF bundle conformance. Serena does not use okf_version, does not implement reserved index.md or log.md behavior, and keeps structured OKF fields outside this scalar-only feature.

Validation

  • 171 passed across the focused frontmatter, memory-manager, and memory-tool suites
  • poe lint
  • poe type-check
  • poe doc-build
  • python -m compileall on changed Python files
  • git diff --check

The new-head GitHub Actions runs for commit 85086235 are final: 10 checks passed, 6 failed, 6 were cancelled, and 2 were skipped. Every non-green executable check failed before repository checkout: GitHub either did not acquire a hosted runner after multiple attempts or returned Service Unavailable / Failed to resolve action download info while resolving actions. No repository code or tests failed; notably, the JVM matrix passed on Linux, Windows, and macOS. Runs: Tests, Python Versions, CodeQL Advanced, Codespell, and Docs Build.

The local macOS sandbox limitations remain recorded separately in #1817 and #1818.

Original implementation: #1119 by @Meh10t.

@opcode81

Copy link
Copy Markdown
Contributor

Thanks, @TyceHerrman, @MischaPanch and I will evaluate whether the spec that is implemented here still fits with what happened within the memory system in the meantime.

Comment thread src/serena/memories/frontmatter.py Outdated
Port and update the frontmatter work from oraios#1119 for the current memory manager architecture.

Co-authored-by: Mehdi Ait Kajaoud <102723977+Meh10t@users.noreply.github.com>
@TyceHerrman
TyceHerrman force-pushed the memory-frontmatter-current-main branch from cfbce85 to d2c3b5c Compare July 29, 2026 22:26

@AmirF194 AmirF194 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

load_memory/save_memory (memory_manager.py:223-243) run FrontmatterParser.parse() unconditionally on every read, not just when the new opt-in frontmatter tools are active. ReadMemoryTool.apply calls load_memory directly, so this changes what the existing read_memory tool returns for any pre-existing memory whose body happens to open with a line-exact ---, one or more key: value lines, and a closing --- (a plausible shape: a markdown horizontal rule followed by a short status block, e.g. after a heading).

Docker repro against this PR's head (d2c3b5c), no mocks, real MemoryManager:

original = (
    "---\n"
    "replicas: 3\n"
    "image: myapp:latest\n"
    "---\n"
    "This is the actual body text a user wrote, describing a k8s manifest above.\n"
)
mgr._save_memory_raw("k8s-notes", original, is_tool_context=False)
loaded = mgr.load_memory("k8s-notes")

Output:

loaded == 'This is the actual body text a user wrote, describing a k8s manifest above.\n'
loaded != original   # True: the replicas/image lines are gone

read_memory silently drops that block for a memory nobody ever opted into frontmatter for. It happens to survive a load-then-save round trip here because render() reconstructs it, but that reconstruction isn't guaranteed to be byte-identical (render trims whitespace and never re-adds quotes, so a quoted value like url: "https://x.com:443" loses its quotes on the next round trip and can then mis-split at the extra colon).

Given the CHANGELOG frames this as "opt-in," would it make more sense to only parse frontmatter when at least one of the new tools is active, or to require an explicit marker so existing memory bodies that start with --- aren't reinterpreted?

@TyceHerrman

Copy link
Copy Markdown
Contributor Author

Thanks for the concrete reproduction. This is addressed in 85086235 by requiring an explicit, persisted Serena marker instead of making parsing depend on which tools are active:

  • only a block whose first field is serena_frontmatter_version: 1 is treated as managed metadata
  • unmarked legacy --- content, including the reproduction shape, remains byte-for-byte body content through read/save cycles
  • marked metadata is hidden from read_memory and its exact serialized prefix is retained regardless of active tools
  • duplicate keys, malformed marked blocks, unsupported versions, and missing/empty type fail before writing
  • field updates replace only the selected value or insert one line, preserving unrelated quotes, whitespace, ordering, and newline style
  • newly written values use reversible JSON-style quoting, while existing simple unquoted scalar values and colon-containing values remain accepted
  • adding metadata to a legacy memory wraps the complete original bytes beneath the new marked block

While addressing this feedback, I also took the opportunity for minimal alignment with Google's Open Knowledge Format v0.2 field names: new blocks require type (defaulting to "Serena Memory") and use description where applicable. This is only field-level alignment, not OKF bundle conformance: Serena does not use okf_version, reserve index.md/log.md, or implement structured OKF fields in this PR.

Focused validation is 171 passed, plus Ruff formatting/lint, full ty checks, the docs build, compileall, and git diff --check.

@TyceHerrman

Copy link
Copy Markdown
Contributor Author

the failing ci checks on commit 85086235 seem to be a GitHub Actions hosted-infrastructure incident, not a failure introduced by this PR:

Multiple unrelated repositories reported the same action-resolution and runner-assignment failures during the same UTC window

@MischaPanch

Copy link
Copy Markdown
Member

Thanks for the PR. @opcode81 and I still haven't decided whether we want to support this, as it brings serena's memories a bit away from "just standard md working with any memory", and the memory tool proliferation also carries a cost. Just a heads up on why there was no comment from us yet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants