How to Use `memory_lint` to Find Contradictions in AI Memory Wikis
memory_lint is the linting subsystem of ai-memory that scans wiki pages for contradictions, stale claims, and logical errors using both rule-based checks and optional LLM-driven analysis.
The memory_lint system in the akitaonrails/ai-memory repository helps developers maintain coherent knowledge bases by automatically detecting when memory pages contain conflicting information. This guide explains how to run contradiction detection from the CLI, integrate linting into Rust applications, and interpret the generated reports.
Two-Layer Linting Architecture
memory_lint operates through complementary detection layers that can run independently or together.
Rule-Based Checks (Always Active)
These fast, deterministic validations flag structural and metadata problems:
- Stale episodic pages exceeding their decay threshold
- Empty page bodies
- Duplicate titles across the wiki
- Pinned pages with contradictory expiration dates
- Pages that appear to be durable rules but lack proper tagging
LLM-Driven Contradiction Detection (Opt-In)
When a language model provider is configured, memory_lint performs deeper semantic analysis. The system:
- Identifies up to 20 high-access semantic or procedural pages (configurable via
LLM_CLUSTER_CAP) - Builds a structured prompt with page previews
- Sends the prompt to the LLM via
complete_structured - Parses the JSON response into a
LintReportcontaining contradictions and stale claims
Running memory_lint from the Command Line
The CLI interface lives in crates/ai-memory-cli/src/commands/lint.rs and provides three invocation patterns.
Basic Lint with LLM Contradiction Detection
ai-memory lint --workspace my_ws --project my_proj
This triggers the full two-layer analysis and writes findings to wiki/_lint/<YYYY-MM-DD>.md.
Dry-Run Mode (No File Output)
ai-memory lint --dry-run
Use this to preview findings without persisting the report.
Rule-Based Only (Skip LLM)
ai-memory lint --no-llm
Disable the LLM pass when you need fast feedback or lack API credits.
Programmatic Integration in Rust
For embedding memory_lint into larger applications, import run_lint from ai-memory-consolidate and construct a LintOptions configuration.
use ai_memory_consolidate::{run_lint, LintOptions};
use ai_memory_store::ReaderPool;
use ai_memory_wiki::Wiki;
use std::sync::Arc;
use ai_memory_llm::LlmProvider;
async fn lint_my_project(
reader: &ReaderPool,
wiki: &Wiki,
llm: Option<Arc<dyn LlmProvider>>
) {
let opts = LintOptions {
dry_run: false,
use_llm: true,
decay_lambda: 0.02,
};
let report = run_lint(
reader,
wiki,
llm.as_ref(),
workspace_id,
project_id,
opts
)
.await
.expect("lint failed");
println!("Found {} issue(s)", report.findings.len());
}
The run_lint function in crates/ai-memory-consolidate/src/lint.rs (lines 43-56) orchestrates the full pipeline: gathering decay candidates, executing rule_based_findings, and conditionally invoking contradiction_pass.
How the Contradiction Pass Works
The LLM-driven analysis in contradiction_pass (lines 66-84) follows a precise data flow:
- Page Selection — Ranks pages by access frequency, caps at
LLM_CLUSTER_CAP(20) - Prompt Construction — Embeds page content with the system prompt from
crates/ai-memory-consolidate/prompts/lint_system.md - Structured Completion — Calls
complete_structuredfromai-memory-llmfor JSON output - Report Deserialization — Parses into
LintReportstructs (defined lines 35-62) - Finding Merge — Combines with rule-based results
The system prompt enforces security boundaries and output format constraints, preventing prompt injection while ensuring parseable results.
Understanding Lint Reports
Reports are written by write_report_page (lines 14-48) to markdown files in wiki/_lint/. Here's a sample contradiction finding:
# Lint findings
2 finding(s).
## 1 — contradiction (warning)
Episodic page `sessions/2024-09-30.md` claims "The server runs on port 8080", but another page asserts "The server always uses port 80".
Pages:
- `sessions/2024-09-30.md`
- `concepts/server-port.md`
Store these reports in version control to track knowledge base health over time. The markdown format supports grepping for specific issue types or affected pages.
Key Source Files
| File | Purpose |
|---|---|
crates/ai-memory-consolidate/src/lint.rs |
Core run_lint entry point, contradiction_pass, rule_based_findings, write_report_page |
crates/ai-memory-cli/src/commands/lint.rs |
CLI argument parsing and HTTP client for ai-memory lint command |
crates/ai-memory-consolidate/prompts/lint_system.md |
LLM system prompt with security boundaries and output schema |
crates/ai-memory-wiki/src/lib.rs |
Wiki::write_page implementation for persisting reports |
crates/ai-memory-llm/src/lib.rs |
LlmProvider trait and complete_structured helper |
Summary
memory_lintcombines rule-based and LLM analysis to detect contradictions in ai-memory wikis- CLI usage:
ai-memory lintwith--dry-runor--no-llmflags for flexible execution - Programmatic usage: Import
run_lintandLintOptionsfromai-memory-consolidate - Reports land in
wiki/_lint/<date>.mdwith structured markdown for version control review - Key constant:
LLM_CLUSTER_CAP = 20limits pages sent to the LLM for cost control
Frequently Asked Questions
What types of contradictions can memory_lint detect?
memory_lint finds logical contradictions (conflicting facts about the same entity), temporal inconsistencies (outdated claims in newer pages), and rule violations (pages violating declared durable rules). The LLM pass specifically targets semantic conflicts that rule-based checks cannot identify, such as "the API uses REST" versus "the API uses GraphQL exclusively."
Does memory_lint require an LLM provider to work?
No. Rule-based checks run without any LLM configuration. However, contradiction detection requires a configured provider. Pass --no-llm to skip the LLM pass entirely, or ensure your environment has a valid LLM provider set up for ai-memory-llm to use with complete_structured.
How does memory_lint decide which pages to analyze for contradictions?
The contradiction_pass function ranks pages by access frequency (recent and frequent reads indicate high relevance) and selects the top LLM_CLUSTER_CAP entries—defaulting to 20. This prioritizes actively-used knowledge over archival content, keeping LLM costs predictable while surfaces likely sources of user-facing contradictions.
Can I customize the lint output location or format?
The report path wiki/_lint/<YYYY-MM-DD>.md is currently hardcoded in write_report_page at lines 14-48 of lint.rs. The markdown format is standardized to support consistent parsing. For custom integrations, call run_lint programmatically and process the returned LintReport struct directly before it reaches write_report_page.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →