Skip to content

feat(memory): entry-policy convention, Agents template, memory template updates, and memory tool description improvements - #307

Merged
aliasunder merged 4 commits into
mainfrom
worktree-memory-entry-policy-templates
Jul 11, 2026
Merged

feat(memory): entry-policy convention, Agents template, memory template updates, and memory tool description improvements#307
aliasunder merged 4 commits into
mainfrom
worktree-memory-entry-policy-templates

Conversation

@aliasunder

@aliasunder aliasunder commented Jul 11, 2026

Copy link
Copy Markdown
Owner

What

Memory files gain a machine-readable entry-policy frontmatter property — append-only (the default; an absent property means this) or living (a current-state file whose expired entries are pruned rather than left as history) — and the bootstrap template set grows to six files with a new Agents template for agent-facing directives.

Why

Append-only was previously an unconditional statement in tool descriptions and the templates README, with no way for a file (or a user-created memory file) to declare an exception. Current-state content — upcoming plans, active commitments — structurally can't be append-only: without pruning, expired plans mislead every agent that reads them. Separately, lived-in memory layers drift toward mixing directives for agents with facts about the user; the Agents template gives directives a first-class home from day one, with the routing test documented in the templates README (who is the subject of the entry?).

Changes

  • memory-store.tsMemoryEntryPolicy type; MemoryFileOutline gains entry_policy (unrecognized values resolve to append-only, the safe reading); template specs gain the Agents file, per-spec policy, section-enumerating scope callouts, and cross-file related links; programmatically-created files default to append-only; shrink-guard floor recalibrated 200 → 1300 B to stay above the new largest empty template (Routines 1228 B)
  • memory-tools.tsvault_update_memory / vault_delete_memory descriptions state the default and the living exception; vault_list_memory_files documents the new entry_policy field
  • memory-review-prompt.ts — structural overview labels each file's policy; new reflection step 6 scoped to living files only (propose pruning expired entries); the never-prune contract now explicitly binds append-only files
  • templates/memory/ — new Agents.md; all templates declare entry-policy and enumerate sections; Routines restructured as the living example (Active commitments / Upcoming / Daily-weekly rhythm / Recent past); README documents both conventions
  • Docs — AGENTS.md + ARCHITECTURE.md memory-review contract reconciled; deploy READMEs' bootstrap file list corrected (previously omitted Routines) + policy pointer; .devin/wiki.json prompt purpose updated
  • Tests — bootstrap suite covers the 5-file set, Agents sections, Routines living policy; listMemoryFiles covers default/living/unrecognized policy values; prompt exact-output updated + a living-file overview test; tool-definition descriptions assert the entry-policy contract

No new tools — counts across README/server.json unchanged.

Notes for review

  • The memory-review prompt behavior change (step 6) goes one step beyond pure surfacing: without it, the prompt's "never prunes" contract would contradict the living policy the same PR introduces (convention docs stay in lockstep with code).
  • Coordination: the in-flight vault_memory_recall work (Phase 3) plans to hydrate entry_policy into recall results at query time; whichever branch lands second reconciles README/ARCHITECTURE touch points.

Verification

  • npm test — 1644/1644 across 50 files
  • npm run lint — 0 errors
  • npm run build — clean
  • Empty-template byte sizes measured empirically (tsx script) to set the shrink floor

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for append-only and living memory policies.
    • Living memory files can have expired entries pruned, while append-only files preserve history.
    • New default memory templates include Agents.md and Routines.md.
    • Memory listings now show each file’s policy and additional metadata.
  • Documentation

    • Updated memory setup, template, and review guidance to explain policies, file organization, and maintenance behavior.

Memory files gain a machine-readable entry-policy frontmatter property:
append-only (the default; absent means this) or living (a current-state
file whose expired entries are pruned rather than left as history).

- vault_list_memory_files surfaces entry_policy per file (unrecognized
  values resolve to append-only — the safe reading)
- vault_update_memory / vault_delete_memory descriptions state the
  default and the living exception; vault_delete_memory now names the
  case where deletion is intended maintenance
- memory-review prompt labels each file's policy in its structural
  overview and gains a living-files-only reflection step for expired
  entries; append-only files keep the never-prune contract
- New Agents template (6th memory file): directives for how agents
  communicate, work, and verify — split from facts about the user;
  templates README documents the who-is-the-subject routing test
- Routines template becomes the living example, restructured to
  Active commitments / Upcoming / Daily-weekly rhythm / Recent past
- All templates (in-code specs + templates/memory/) declare their
  policy, enumerate their sections in the scope callout, and
  cross-reference Agents; shrink-guard floor recalibrated to sit above
  the new largest empty template (Routines 1228 B)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • The SHRINK_FLOOR_BYTES comment now depends on specific template sizes (Routines, Agents, Me, Opinions, Principles); consider deriving this threshold from actual template files at runtime or a shared constant so future template changes don’t silently invalidate the guard.
  • entryPolicyFromFrontmatter currently treats anything except the exact string "living" as append-only; if you ever expand policies, it may be safer to validate against an explicit union (or enum) and surface invalid values to callers rather than silently coercing them to append-only.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The SHRINK_FLOOR_BYTES comment now depends on specific template sizes (Routines, Agents, Me, Opinions, Principles); consider deriving this threshold from actual template files at runtime or a shared constant so future template changes don’t silently invalidate the guard.
- entryPolicyFromFrontmatter currently treats anything except the exact string "living" as append-only; if you ever expand policies, it may be safer to validate against an explicit union (or enum) and surface invalid values to callers rather than silently coercing them to append-only.

## Individual Comments

### Comment 1
<location path="src/vault-mcp/mcp-core/__tests__/tool-definitions.test.ts" line_range="172-180" />
<code_context>
+    )
+  })
+
+  it("memory tool descriptions document the entry-policy contract", () => {
+    // Append-only is the default; the living opt-in must be discoverable from
+    // the tools that write, delete, and list memory — not only from templates.
+    const [, updateConfig] = requireCall(TOOL_NAMES.VAULT_UPDATE_MEMORY)
+    expect(updateConfig.description).toContain("entry-policy: living")
+    const [, deleteConfig] = requireCall(TOOL_NAMES.VAULT_DELETE_MEMORY)
+    expect(deleteConfig.description).toContain("entry-policy: living")
+    const [, listConfig] = requireCall(TOOL_NAMES.VAULT_LIST_MEMORY_FILES)
+    expect(listConfig.description).toContain(
+      'entry_policy is "append-only" (the default',
     )
</code_context>
<issue_to_address>
**suggestion (testing):** Strengthen the memory tools contract test by also asserting the append-only default wording for update/delete tools.

The test now checks that all three memory tools mention `entry-policy: living` and that `vault_list_memory_files` documents the default append-only behavior. To fully capture the contract, also assert that `vault_update_memory` and `vault_delete_memory` include the explicit "append-only by default" wording (e.g., `expect(updateConfig.description).toContain("append-only by default")` and similarly for `deleteConfig`). This will better guard against regressions where the append-only default is omitted from their descriptions.
</issue_to_address>

### Comment 2
<location path="templates/memory/Routines.md" line_range="20" />
<code_context>
+> **Contains:** Active commitments, upcoming plans, recurring rhythms, and recent-past events kept for context — the time-sensitive logistics of the user's current life. A **current-state snapshot**, not a history ledger.
+> **Does NOT contain:** One-off events or reference material, identity facts (→ Me), principles (→ Principles), directives for AI agents (→ Agents).
+> **Section structure:** Active commitments, Upcoming, Daily/weekly rhythm, Recent past — each suffixed "(newest first)".
+> **Convention:** append newest first; ISO dates only. Entry policy: **living** (declared in frontmatter) — a deliberate exception to the memory layer's append-only default. When an Upcoming or Active-commitments entry expires, delete it and, if the outcome is worth keeping, append it to Recent past. Recent past entries are dated history and are not pruned.

-## Daily (newest first)
</code_context>
<issue_to_address>
**suggestion (typo):** Fix the hyphenation in “Active-commitments entry” to match the section name.

The hyphen makes the phrase look like a typo and inconsistent with the `Active commitments (newest first)` header; removing it will align the wording and improve readability.

```suggestion
> **Convention:** append newest first; ISO dates only. Entry policy: **living** (declared in frontmatter) — a deliberate exception to the memory layer's append-only default. When an Upcoming or Active commitments entry expires, delete it and, if the outcome is worth keeping, append it to Recent past. Recent past entries are dated history and are not pruned.
```
</issue_to_address>

### Comment 3
<location path="templates/memory/README.md" line_range="56-59" />
<code_context>
+
+Mixing the two is the most common drift in a lived-in memory layer: directives
+accumulate inside Principles and Me because they _feel_ like values. Route them
+to Agents.md from the start — it doubles as the highest-value always-read for
+any agent session.
+
+## Entry policy
</code_context>
<issue_to_address>
**nitpick (typo):** Clarify the noun phrase “highest-value always-read” for better grammar.

Consider clarifying what is meant by “always-read” by adding a specific noun, e.g., “highest-value always-read file” or “always-read document,” so the phrase is grammatically clear to readers.

```suggestion
Mixing the two is the most common drift in a lived-in memory layer: directives
accumulate inside Principles and Me because they _feel_ like values. Route them
to Agents.md from the start — it doubles as the highest-value always-read file
for any agent session.
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/vault-mcp/mcp-core/__tests__/tool-definitions.test.ts
Comment thread templates/memory/Routines.md Outdated
Comment thread templates/memory/README.md Outdated
@umm-actually

umm-actually Bot commented Jul 11, 2026

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Lower shrink floor to guard files with one entry

The SHRINK_FLOOR_BYTES was raised from 200 to 1300 to accommodate the new, larger
templates (Routines ~1228 B, Agents ~1081 B). However, the comment says "a file with
no real content is never guarded, while a file that has accumulated real entries
beyond the skeleton is." With a 1300-byte floor, a Routines template (1228 B) plus a
single short entry (~50 B) would be ~1278 B — still below the floor and therefore
unguarded. This means a catastrophic shrink that clobbers a Routines file with one
real entry would not be caught. The floor should be set just above the largest empty
template, not above the template-plus-entries threshold, to match the stated intent.

src/vault-mcp/vault-operations/memory-store.ts [26]

-const SHRINK_FLOOR_BYTES = 1300
+// The 1250-byte floor sits just above the largest empty memory template
+// (Routines 1228 B; Agents 1081 B; Me/Opinions/Principles ~900 B —
+// frontmatter + scope callout + headings, no entries), so a file with no
+// real content is never guarded, while a file with even one dated entry
+// (~1278 B+) is.
+const SHRINK_FLOOR_BYTES = 1250
Suggestion importance[1-10]: 8

__

Why: The floor constant at 1300 leaves a Routines file with a single short entry (~1278 B) unguarded, contradicting the comment’s intent that “a file that has accumulated real entries … is [guarded]”. Lowering to 1250 ensures even minimally populated files are protected, making the catastrophic‑shrink guard work as described.

Medium
General
Add type guard for frontmatter entry-policy value

The entryPolicyFromFrontmatter function treats any non-"living" value as
"append-only", which is the safe default. However, YAML frontmatter can produce
non-string values (e.g., entry-policy: true or entry-policy: 123). The current check
value === "living" will correctly reject these, but the function should also handle
the case where value is an array (YAML entry-policy: [living]), which would pass the
strict equality check for the string "living" but is semantically invalid. Consider
adding a runtime type guard to ensure value is a string before comparing.

src/vault-mcp/vault-operations/memory-store.ts [102-103]

 const entryPolicyFromFrontmatter = (value: unknown): MemoryEntryPolicy =>
-  value === "living" ? "living" : "append-only"
+  typeof value === "string" && value === "living" ? "living" : "append-only"
Suggestion importance[1-10]: 2

__

Why: The current value === "living" already treats non‑string values as the safe default (append‑only). Adding a typeof check is a minimal defensive improvement that doesn’t change any behavior; the suggestion has low impact.

Low

Comment thread src/vault-mcp/vault-operations/memory-store.ts Outdated
Comment thread src/vault-mcp/vault-operations/memory-store.ts Outdated
@aliasunder

Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds explicit append-only and living memory policies, exposes them through memory outlines and MCP tools, updates review prompts and templates, expands bootstrap files, and revises related tests and documentation.

Changes

Memory entry policy and templates

Layer / File(s) Summary
Policy storage and bootstrap templates
src/vault-mcp/vault-operations/memory-store.ts, src/vault-mcp/vault-operations/__tests__/memory-store.test.ts, templates/memory/*
Memory files resolve entry-policy as append-only or living; seeded and created files write policies, bootstrap includes Agents and Routines, and template metadata and sections are updated.
MCP policy exposure and review flow
src/vault-mcp/mcp-core/prompts/memory-review-prompt.ts, src/vault-mcp/mcp-core/tools/memory-tools.ts, src/vault-mcp/mcp-core/__tests__/*
Memory outlines and tool descriptions expose policies, while memory review permits expired-entry pruning only for living files and tests the resulting prompt output.
Documentation and setup contracts
.devin/wiki.json, AGENTS.md, ARCHITECTURE.md, deploy/*/README.md, templates/memory/README.md
Prompt conventions, setup instructions, and memory documentation describe policy semantics and the expanded default template set.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested labels: Review effort 2/5

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main memory-policy, Agents template, and docs/tool-description updates in the PR.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-memory-entry-policy-templates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/vault-mcp/mcp-core/prompts/memory-review-prompt.ts`:
- Around line 206-208: Resolve the contradiction between step 6 and the
subsequent change instruction in the memory-review prompt. Update the
instruction near “Propose every change” so expired entries from living files are
removed via vault_delete_memory, while vault_update_memory remains required for
other edits and all operations still require confirmation before writing.

In `@src/vault-mcp/vault-operations/memory-store.ts`:
- Around line 21-26: Lower SHRINK_FLOOR_BYTES from 1300 to approximately 1250 so
a Routines file with one dated entry exceeds the guard threshold while empty
templates remain below it. Update the adjacent explanatory comment to reflect
the revised threshold and preserved empty-template behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5629a339-f988-4842-8c26-fb488142446b

📥 Commits

Reviewing files that changed from the base of the PR and between f6d8610 and 46da7f2.

📒 Files selected for processing (17)
  • .devin/wiki.json
  • AGENTS.md
  • ARCHITECTURE.md
  • deploy/local/README.md
  • deploy/remote/README.md
  • src/vault-mcp/mcp-core/__tests__/memory-review-prompt.test.ts
  • src/vault-mcp/mcp-core/__tests__/tool-definitions.test.ts
  • src/vault-mcp/mcp-core/prompts/memory-review-prompt.ts
  • src/vault-mcp/mcp-core/tools/memory-tools.ts
  • src/vault-mcp/vault-operations/__tests__/memory-store.test.ts
  • src/vault-mcp/vault-operations/memory-store.ts
  • templates/memory/Agents.md
  • templates/memory/Me.md
  • templates/memory/Opinions.md
  • templates/memory/Principles.md
  • templates/memory/README.md
  • templates/memory/Routines.md

Comment thread src/vault-mcp/mcp-core/prompts/memory-review-prompt.ts Outdated
Comment thread src/vault-mcp/vault-operations/memory-store.ts Outdated
- Lower SHRINK_FLOOR_BYTES from 1300 to 1250 so single-entry Routines
  files (~1270 B) are guarded by the catastrophic-shrink check
- Add typeof guard to entryPolicyFromFrontmatter for defense-in-depth
- Fix memory-review prompt to mention vault_delete_memory alongside
  vault_update_memory (step 6 introduces deletion but the final
  instruction only mentioned updates)
- Fix "Active-commitments" → "Active commitments" hyphenation to match
  section heading (template + MEMORY_TEMPLATE_SPECS)
- Fix "highest-value always-read" → "always-read file" (missing noun)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@aliasunder

Copy link
Copy Markdown
Owner Author

Responding to the two Overall Comments from the Sourcery review:

1. Derive SHRINK_FLOOR_BYTES at runtime from templates

The threshold is deliberately a static constant measured against the rendered (bootstrapped) template sizes, not the raw template files. Runtime derivation would add fs reads at import time and async init complexity for a value that changes only when templates are edited — and the comment documents which templates were measured, so drift is caught in review. The static approach is the right tradeoff.

2. Validate entryPolicyFromFrontmatter against an explicit union

The conservative default (any non-"living" → append-only) is deliberate and documented: append-only forbids destructive maintenance, so it's the safe reading for unknown/misspelled/missing values. Surfacing invalid values to callers would add error handling for a non-error condition — an unknown policy should be treated conservatively, not rejected. That said, I did add a typeof value === "string" guard (3feabb0) for defense-in-depth as a separate finding.


🔍 ship-check · pr-monitor · Claude Opus 4.6 (1M context)

aliasunder and others added 2 commits July 11, 2026 18:03
…_memory Errors

The duplicate no-op contract is already documented in the opening
paragraph ("Idempotent — an exact duplicate is a no-op"), the Returns
section, and the idempotentHint annotation. The Errors bullet was
triple-redundancy placed in a misleading section — a "not an error"
note inside "Errors:" contradicts its own framing and contributes to
the Conciseness (Co=4) TDQS ding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The PR replaced the generic "H2 sections by theme/topic/cadence" lines
with specific heading names (e.g. "Identity, Interests, Context"). These
will go stale as agents add new H2 sections — vault_list_memory_files
already surfaces the live heading structure, so the scope callout should
describe the pattern, not enumerate the headings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@aliasunder aliasunder changed the title feat(memory): per-file entry-policy + Agents directives template feat(memory): entry-policy convention, Agents template, and memory tool description improvements Jul 11, 2026
@aliasunder aliasunder changed the title feat(memory): entry-policy convention, Agents template, and memory tool description improvements feat(memory): entry-policy convention, Agents template, memory template updates, and memory tool description improvements Jul 11, 2026
@aliasunder
aliasunder merged commit 3665f9b into main Jul 11, 2026
16 checks passed
@aliasunder
aliasunder deleted the worktree-memory-entry-policy-templates branch July 11, 2026 22:20
aliasunder added a commit that referenced this pull request Jul 26, 2026
…onciliation, heading levels

- Shrink guard floor: 200 B → 1250 B (drifted when PR #307 raised
  SHRINK_FLOOR_BYTES; doc now also states why the threshold sits just
  above the largest empty template)
- Layer 2 auth attribution: requireBearerAuth is applied in
  mcp-core/mcp-router.ts, not server.ts
- README leading-callouts claim reconciled with the opt-in
  include_leading_callout semantics on vault_search
- Secure-by-default constraint scoped to the client-facing endpoint —
  the doc itself documents the default plaintext gateway→instance hop
- Hybrid Search subsections promoted #### → ### to match every other
  h2's subsection level (slugs unchanged; no inbound links affected)
- Capabilities base surface now lists property discovery + daily notes
- One-vault constraint names both currency mechanisms (bind mount
  locally, Obsidian Sync remotely)
- DOCKERHUB.md regenerated (table padding normalization only)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant