Skip to content

feat(memory): prepend editable AGENTS.md as system prompt - #9

Merged
vearne merged 1 commit into
mainfrom
cursor/markdown-agents-md
May 27, 2026
Merged

feat(memory): prepend editable AGENTS.md as system prompt#9
vearne merged 1 commit into
mainfrom
cursor/markdown-agents-md

Conversation

@vearne

@vearne vearne commented May 27, 2026

Copy link
Copy Markdown
Owner

Load basePath/AGENTS.md on each GetMemory/GetMessages/ToStrList call; document that Size counts stored tiers only, not the virtual system line.

Summary by CodeRabbit

  • New Features

    • Introduced MarkdownTieredMemory backend with file-backed tiered storage for short-term and long-term memory data
    • Added support for persistent instructions that remain available even after clearing memory
  • Documentation

    • Updated implementation documentation with usage examples and behavior specifications for the new backend

Review Change Stack

Load basePath/AGENTS.md on each GetMemory/GetMessages/ToStrList call;
document that Size counts stored tiers only, not the virtual system line.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR adds persistent AGENTS.md file support to MarkdownTieredMemory. The implementation ensures an AGENTS.md file exists at the store root during initialization, prepends its contents as a virtual system message on all read operations, preserves it across clear operations, and documents how size counts differ from message counts visible to models.

Changes

Persistent AGENTS.md Support

Layer / File(s) Summary
Constants, type documentation, and setup
pkg/memory/markdown_tiered.go
Adds file-level constants agentsMDFilename and agentsMDSourceMeta, and updates MarkdownTieredMemory type and NewMarkdownTieredMemory documentation to declare that AGENTS.md is ensured and used as persistent instructions.
AGENTS.md file management helpers
pkg/memory/markdown_tiered.go
Introduces getAgentsMDPath, ensureAgentsMDExists, readAgentsMD, and newAgentsMDMessage helper methods to locate, create if missing, read contents, and convert the file into a virtual system message.Msg with metadata.
Integration into read paths
pkg/memory/markdown_tiered.go
Changes GetMessages to delegate to GetMemory (which prepends AGENTS.md), modifies the read path to post-process results, updates ToStrList to build from GetMemory with error handling, and documents that AGENTS.md is always prepended on read.
Contract updates and test validation
pkg/memory/markdown_tiered.go, pkg/memory/markdown_tiered_test.go
Updates Clear comment to state AGENTS.md is not removed, updates Size comment to clarify it excludes the virtual system message, and adds TestMarkdownTieredMemory_AgentsMD test that validates file creation, message prepending with metadata, ToStrList output, and preservation across clear.
User-facing documentation
pkg/memory/README.md
Adds a new MarkdownTieredMemory backend section documenting configuration, behavior for AGENTS.md re-reading, message handling, clear semantics, and explicit clarification of Size() versus GetMemory() count differences.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A persistent note in AGENTS.md now dwells,
Each read whispers instructions like magic spells,
Virtual messages dance, never stored nor cleared,
Just prepended with care, always endeared!
The memory now speaks with instructions sincere. 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(memory): prepend editable AGENTS.md as system prompt' directly and clearly summarizes the main change: adding functionality to load and prepend an editable AGENTS.md file as a system prompt in the MarkdownTieredMemory implementation.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 cursor/markdown-agents-md

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 and usage tips.

@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

🧹 Nitpick comments (1)
pkg/memory/markdown_tiered_test.go (1)

152-154: ⚡ Quick win

Add explicit Size() assertions for the AGENTS.md exclusion contract.

The new test verifies read behavior well, but it does not assert that Size() excludes the virtual AGENTS.md system message before and after Clear().

✅ Suggested assertions
 	if len(msgs) != 2 {
 		t.Fatalf("expected system + user, got %d", len(msgs))
 	}
+	if mem.Size() != 1 {
+		t.Fatalf("expected Size() to exclude AGENTS.md, got %d", mem.Size())
+	}
 	if msgs[0].Role != "system" || msgs[0].GetTextContent() != content {
 		t.Fatalf("unexpected system prompt: role=%q content=%q", msgs[0].Role, msgs[0].GetTextContent())
 	}
@@
 	if len(msgs) != 1 || msgs[0].GetTextContent() != content {
 		t.Fatalf("after clear expected only system prompt, got %+v", msgs)
 	}
+	if mem.Size() != 0 {
+		t.Fatalf("expected Size() == 0 after Clear(), got %d", mem.Size())
+	}

Also applies to: 167-179

🤖 Prompt for 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.

In `@pkg/memory/markdown_tiered_test.go` around lines 152 - 154, Add explicit
Size() assertions to verify the AGENTS.md virtual system message is excluded:
after you check len(msgs) == 2, assert that the memory tier's Size() returns 1
(only the user message counted), and after calling Clear() assert Size() returns
0; use the same memory-tier test instance you already call Clear() on and the
existing msgs variable, calling its Size() method before and after Clear().
🤖 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 `@pkg/memory/markdown_tiered.go`:
- Around line 163-171: The ensureAgentsMD function should treat an existing
non-regular file (e.g., a directory) as an error and wrap all returned errors
with context; change the existence check to call os.Stat(path), if err == nil
inspect fi.Mode().IsRegular() and if not regular return
fmt.Errorf("ensureAgentsMD: %s exists but is not a file", path), if
os.IsNotExist(err) proceed to create the file, and wrap any Stat or WriteFile
errors as fmt.Errorf("ensureAgentsMD: stat %s: %w", path, err) or
fmt.Errorf("ensureAgentsMD: write %s: %w", path, err). Apply the same non-file
check and contextual error wrapping approach to the related functions/blocks
referenced in the diff (e.g., other code around lines 173-179) and use
agentsMDPath() to locate the file.

In `@pkg/memory/README.md`:
- Line 130: The sentence "Can be combined with `WithReActSystemPrompt` (both
system messages are sent; AGENTS.md is typically first)." is missing an explicit
subject; update the bullet so it reads clearly (e.g., "This option can be
combined with `WithReActSystemPrompt`...") to make the subject explicit and
improve readability while keeping the parenthetical note and
`WithReActSystemPrompt` reference intact.

---

Nitpick comments:
In `@pkg/memory/markdown_tiered_test.go`:
- Around line 152-154: Add explicit Size() assertions to verify the AGENTS.md
virtual system message is excluded: after you check len(msgs) == 2, assert that
the memory tier's Size() returns 1 (only the user message counted), and after
calling Clear() assert Size() returns 0; use the same memory-tier test instance
you already call Clear() on and the existing msgs variable, calling its Size()
method before and after Clear().
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 30bee7fc-e25c-4cb5-b0cf-5ade61a3cdca

📥 Commits

Reviewing files that changed from the base of the PR and between 8b19b15 and 50e2c1b.

📒 Files selected for processing (3)
  • pkg/memory/README.md
  • pkg/memory/markdown_tiered.go
  • pkg/memory/markdown_tiered_test.go

Comment on lines +163 to +171
func (m *MarkdownTieredMemory) ensureAgentsMD() error {
path := m.agentsMDPath()
if _, err := os.Stat(path); err == nil {
return nil
} else if !os.IsNotExist(err) {
return err
}
return os.WriteFile(path, nil, 0o644)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle non-file AGENTS.md and add contextual error wrapping.

If basePath/AGENTS.md exists as a directory, Line 165 currently treats it as valid and later reads fail on every memory fetch. Also, raw return err at Line 168/179 drops failure context.

🔧 Proposed fix
func (m *MarkdownTieredMemory) ensureAgentsMD() error {
	path := m.agentsMDPath()
-	if _, err := os.Stat(path); err == nil {
+	if info, err := os.Stat(path); err == nil {
+		if info.IsDir() {
+			return fmt.Errorf("AGENTS.md path is a directory: %s", path)
+		}
 		return nil
 	} else if !os.IsNotExist(err) {
-		return err
+		return fmt.Errorf("stat AGENTS.md: %w", err)
 	}
-	return os.WriteFile(path, nil, 0o644)
+	if err := os.WriteFile(path, nil, 0o644); err != nil {
+		return fmt.Errorf("create AGENTS.md: %w", err)
+	}
+	return nil
}

func (m *MarkdownTieredMemory) readAgentsMDLocked() (string, error) {
	data, err := os.ReadFile(m.agentsMDPath())
	if err != nil {
		if os.IsNotExist(err) {
			return "", nil
		}
-		return "", err
+		return "", fmt.Errorf("read AGENTS.md: %w", err)
	}
	return strings.TrimSpace(string(data)), nil
}

As per coding guidelines, "Wrap errors with fmt.Errorf("context: %w", err) and use plain error returns without custom error types".

Also applies to: 173-179

🤖 Prompt for 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.

In `@pkg/memory/markdown_tiered.go` around lines 163 - 171, The ensureAgentsMD
function should treat an existing non-regular file (e.g., a directory) as an
error and wrap all returned errors with context; change the existence check to
call os.Stat(path), if err == nil inspect fi.Mode().IsRegular() and if not
regular return fmt.Errorf("ensureAgentsMD: %s exists but is not a file", path),
if os.IsNotExist(err) proceed to create the file, and wrap any Stat or WriteFile
errors as fmt.Errorf("ensureAgentsMD: stat %s: %w", path, err) or
fmt.Errorf("ensureAgentsMD: write %s: %w", path, err). Apply the same non-file
check and contextual error wrapping approach to the related functions/blocks
referenced in the diff (e.g., other code around lines 173-179) and use
agentsMDPath() to locate the file.

Comment thread pkg/memory/README.md
- Created as an empty file on first open if missing; edit it by hand to add rules, tone, language, and so on.
- `GetMemory`, `GetMessages`, and `ToStrList` re-read the file on each call and prepend a `system` message when content is non-empty (not affected by mark filters).
- `Add` does not persist that message; `Clear` removes conversation files but keeps `AGENTS.md`.
- Can be combined with `WithReActSystemPrompt` (both system messages are sent; AGENTS.md is typically first).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify the sentence at Line 130 for readability.

This bullet is missing an explicit subject and reads abruptly.

✍️ Suggested wording
-- Can be combined with `WithReActSystemPrompt` (both system messages are sent; AGENTS.md is typically first).
+- It can be combined with `WithReActSystemPrompt` (both system messages are sent; AGENTS.md is typically first).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Can be combined with `WithReActSystemPrompt` (both system messages are sent; AGENTS.md is typically first).
- It can be combined with `WithReActSystemPrompt` (both system messages are sent; AGENTS.md is typically first).
🧰 Tools
🪛 LanguageTool

[style] ~130-~130: To form a complete sentence, be sure to include a subject.
Context: ...ersation files but keeps AGENTS.md. - Can be combined with `WithReActSystemPrompt...

(MISSING_IT_THERE)

🤖 Prompt for 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.

In `@pkg/memory/README.md` at line 130, The sentence "Can be combined with
`WithReActSystemPrompt` (both system messages are sent; AGENTS.md is typically
first)." is missing an explicit subject; update the bullet so it reads clearly
(e.g., "This option can be combined with `WithReActSystemPrompt`...") to make
the subject explicit and improve readability while keeping the parenthetical
note and `WithReActSystemPrompt` reference intact.

@vearne
vearne merged commit c6c67ef into main May 27, 2026
1 check passed
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