Understanding the ai-memory Feedback System: How It Controls Page Salience and Linting

The ai-memory feedback system lets agents record explicit judgments about page versions in an append-only page_feedback table, which directly adjusts a bounded salience score for retrieval ranking and surfaces unresolved signals as feedback_flagged lint findings.

The akitaonrails/ai-memory project implements a lightweight but precise feedback loop that gives agents quantitative control over long-term memory retention. By recording structured judgments through the memory_feedback MCP tool, the system updates per-page importance metrics and exposes quality issues without ever deleting source content.

How Feedback Is Recorded

Agents submit feedback through the memory_feedback MCP tool. On the server side, the handler in crates/ai-memory-mcp/src/server.rs validates the payload and delegates to record_page_feedback in crates/ai-memory-store/src/ops.rs.

That function inserts a new row into the append-only page_feedback table, computes an updated salience value, and writes it back to the pages.salience column for the targeted version.

// Example payload sent to the MCP "memory_feedback" tool
{
  "workspace_id": "w1",
  "project_id": "p1",
  "path": "/docs/overview.md",
  "kind": "helpful",               // one of: helpful, not_helpful, stale, wrong
  "reason": "The explanation is clear",
  "author_id": "u42"
}
// In crates/ai-memory-mcp/src/server.rs → memory_feedback
let reason = sanitize_feedback_reason(&self.sanitizer, args.reason.as_deref());
store
    .writer
    .record_page_feedback(
        ws,
        proj,
        &args.path,
        args.kind.into(),
        reason,
        args.author_id,
        &params,
    )
    .await?;

The FeedbackKind enum, defined in crates/ai-memory-core/src/page.rs, restricts inputs to four variants: Helpful, NotHelpful, Stale, and Wrong. Each variant maps to a string stored in the kind column.

How Feedback Affects Page Salience

Salience is a bounded float that expresses how important a page version is for retrieval. When feedback is recorded, the pure function salience_after_feedback in crates/ai-memory-store/src/decay.rs applies a deterministic step:

  • FeedbackKind::Helpful increases salience.
  • FeedbackKind::NotHelpful decreases salience.

The result is clamped to the range [SALINCE_MIN, SALINCE_MAX] and persisted. During retrieval, the scorer automatically multiplies the term score by page.salience when salience-aware ranking is enabled.

let result = store
    .searcher
    .search(
        query,
        SearchOptions {
            // the scorer automatically multiplies the term score by
            // page.salience (which reflects any feedback adjustments)
            use_salience: true,
            ..Default::default()
        },
    )
    .await?;

This mechanism lets agents tilt retention toward explicitly useful pages and away from stale or wrong content without removing any data.

How Feedback Surfaces in Linting

During a lint run (memory_lint), the consolidator scans page_feedback for open signals. The reader helper open_feedback_findings in crates/ai-memory-store/src/reader.rs returns any feedback still attached to the latest page version.

The lint pass in crates/ai-memory-consolidate/src/lint.rs then emits a feedback_flagged finding, which appears in the JSON lint output.

let feedback_findings = store
    .reader
    .open_feedback_findings(workspace_id, project_id)
    .await?;   // returns Vec<FeedbackFinding>

These findings act as actionable reminders that a specific version has been explicitly marked as stale or wrong and may need human or agent attention.

Retirement Rules on Page Rewrite

When a page is rewritten and a new version supersedes the old one, the previous feedback is retired automatically. As noted in the comments around record_page_feedback, the new version starts with the default salience again.

Because the lint finder only reports feedback attached to the latest version, feedback_flagged findings disappear from the lint output once the rewrite is committed. This creates a clean lifecycle: feedback applies to a specific version, not the conceptual page indefinitely.

Summary

Frequently Asked Questions

What are the valid feedback kinds in ai-memory?

The FeedbackKind enum in crates/ai-memory-core/src/page.rs defines four variants: Helpful, NotHelpful, Stale, and Wrong. Each maps to a string stored in the kind column of the page_feedback table.

How does feedback change a page's retrieval rank?

When feedback is recorded, salience_after_feedback adjusts the page version's bounded salience score up or down depending on the kind. The retrieval scorer then multiplies the base term score by this salience value, making helpful pages rank higher and unhelpful pages rank lower.

Why do lint findings disappear after a page rewrite?

Old feedback is retired automatically when a new version is created. Since open_feedback_findings only scans the latest version, the lint pass in crates/ai-memory-consolidate/src/lint.rs stops emitting feedback_flagged entries once the superseded version is no longer current.

Is feedback data ever deleted?

No. The page_feedback table is append-only. Even after a rewrite retires the salience impact, the historical feedback row remains in storage. Only the active salience adjustment and lint surface area are affected.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →