feat(memory): prepend editable AGENTS.md as system prompt - #9
Conversation
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>
📝 WalkthroughWalkthroughThis PR adds persistent ChangesPersistent AGENTS.md Support
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
pkg/memory/markdown_tiered_test.go (1)
152-154: ⚡ Quick winAdd 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 afterClear().✅ 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
📒 Files selected for processing (3)
pkg/memory/README.mdpkg/memory/markdown_tiered.gopkg/memory/markdown_tiered_test.go
| 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) | ||
| } |
There was a problem hiding this comment.
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.
| - 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). |
There was a problem hiding this comment.
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.
| - 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.
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
Documentation