How LLM-Driven Page Rewrite Works with `memory_consolidate`

The memory_consolidate subsystem rewrites wiki pages by feeding a session's raw observations to an LLM and persisting the generated markdown as a new atomic version, preserving the complete supersession chain through Git-backed versioning.

The ai-memory repository by akitaonrails implements this LLM-driven page rewrite mechanism in Rust, enabling autonomous agents to transform scattered session observations into coherent, structured documentation. The system guarantees atomicity and version control by treating each rewrite as a new revision rather than a destructive overwrite.

Single-Page Consolidation Pipeline

The consolidate_session function in crates/ai-memory-consolidate/src/consolidator.rs orchestrates the rewrite through a rigorous twelve-step workflow.

Observation Retrieval and Context Resolution

First, the consolidator loads all observations belonging to the target session_id. At lines 138-140, if the session contains no data, the function returns EmptySession:

let observations = self.reader.observations_for_session(session_id).await?;

Next, the system resolves the target workspace and project via resolve_target (lines 143-144), then fetches the originating AgentKind for front-matter attribution (lines 144-146):

let (ws, proj) = self.resolve_target(session_id).await?;
let agent_kind = self.resolve_agent_origin(session_id).await?;

Permission Preflight and Dry-Run Mode

Before invoking the LLM, the system performs an admission check at lines 150-154 via preflight_admission to verify the caller's authorization for Consolidate operations. This cheap-fails mechanism prevents unnecessary API costs on permission errors.

If dry_run is enabled (lines 158-169), the function returns a preview ConsolidationOutcome without contacting the LLM, allowing clients to validate the operation beforehand.

LLM Request Construction and Invocation

The consolidator reads the current page body at lines 171-176, defaulting to empty if the page does not exist:

let current_body = self.wiki.read_page(...).map(|md| md.body).unwrap_or_default();

At lines 177-182, build_request assembles a ChatRequest containing the session ID, token-budgeted observations, optional project-wide instructions, and the current page body. The system prompt is loaded from crates/ai-memory-consolidate/prompts/single_consolidate_system.md at compile time. The function then invokes the LLM at lines 190-191:

let page: ConsolidatedPage = complete_structured(&*self.llm, request).await?;

The complete_structured helper, defined in crates/ai-memory-llm/src/lib.rs, deserializes the response into a strongly-typed ConsolidatedPage struct defined in crates/ai-memory-consolidate/src/types.rs.

Atomic Page Persistence

The system constructs JSON front-matter at lines 192-199, stamping the session origin via stamp_session_origin and setting consolidated: true. The actual write occurs at lines 204-218 through Wiki::write_page in crates/ai-memory-wiki/src/wiki.rs:

let id = self.wiki.write_page(WritePageRequest { ... }).await?;

This creates a new revision of sessions/<id>.md within an atomic write-then-commit flow. Finally, lines 222-227 auto-commit the change with a message like consolidate(session …): <title>, ensuring the rewrite is permanently recorded in Git.

Multi-Page Batch Consolidation

For complex sessions requiring multiple page updates, consolidate_session_multi processes batches atomically. This function utilizes build_batch_request_with_slots to request up to five ConsolidatedPageUpdate objects from the LLM, using the system prompt at crates/ai-memory-consolidate/prompts/batch_consolidate_system.md.

Key differences from single-page mode include:

  • Slot Snapshots: The LLM receives slot_snapshots to decide whether to update _slots/… pages
  • Project Instructions: The request includes project-wide instructions via render_slot_snapshots
  • Path Override: For rule pages, the LLM-generated path is canonicalized to _rules/<slug>.md
  • All-or-Nothing Semantics: The Wiki::apply_batch method ensures that if any write fails, the entire transaction rolls back

Prompt Budgeting and Truncation

Both consolidation modes employ PromptBudgets to constrain input size within the provider's context window. The system uses clip_project_instructions and clip_current_body_for_prompt to safely truncate content while maintaining valid JSON schema structure. The render_current_body_section function handles projection of the current page state, ensuring the LLM always receives well-formed requests even with large observation sets.

Safety Mechanisms and Versioning

The implementation enforces several critical invariants:

  • Admission Pre-flight: Unauthorized rewrites are blocked before LLM invocation via preflight_admission
  • Supersession Chain: Git-based versioning through Wiki::write_page guarantees no data loss
  • Slot Update Guards: should_skip_high_resistance_slot_update protects invariant slots and per-user namespaces
  • Summary Validation: The usable_summary filter discards malformed LLM outputs before persistence

Implementation Examples

The following example demonstrates initializing the consolidator and executing a single-page rewrite:

use ai_memory_consolidate::Consolidator;
use ai_memory_store::{ReaderPool, WriterHandle};
use ai_memory_wiki::Wiki;
use std::sync::Arc;
use ai_memory_llm::LlmProvider;

async fn rewrite_session_example(
    reader: ReaderPool,
    writer: WriterHandle,
    wiki: Wiki,
    llm: Arc<dyn LlmProvider>,
    workspace_id: ai_memory_core::WorkspaceId,
    project_id: ai_memory_core::ProjectId,
    session_id: ai_memory_core::SessionId,
) -> anyhow::Result<()> {
    // Construct the consolidator (reuse across many sessions)
    let consolidator = Consolidator::new(reader, writer, wiki, llm, workspace_id, project_id);

    // Run a real consolidation (dry_run = false)
    let outcome = consolidator
        .consolidate_session(
            session_id,
            false,                     // not a dry-run
            ai_memory_core::ActorContext::default(),
            None,                      // no explicit author
            None,                      // no per-call instructions
        )
        .await?;

    println!("Session rewritten to {}", outcome.path);
    println!("New title: {}", outcome.new_title);
    Ok(())
}

For batch operations involving multiple pages:

async fn batch_consolidate_example(
    consolidator: &Consolidator,
    session_id: ai_memory_core::SessionId,
) -> anyhow::Result<()> {
    let outcomes = consolidator
        .consolidate_session_multi(
            session_id,
            false,
            ai_memory_core::ActorContext::default(),
            None,
            None,
        )
        .await?;

    for o in outcomes {
        println!("Updated {} ({} bytes)", o.path, o.new_body_markdown.len());
    }
    Ok(())
}

Summary

  • The memory_consolidate system transforms raw session observations into structured markdown via LLM processing in crates/ai-memory-consolidate/src/consolidator.rs
  • Single-page rewrites follow a twelve-step atomic pipeline from observation loading to Git-commit versioning
  • Multi-page batches guarantee all-or-nothing consistency through Wiki::apply_batch and atomic transactions
  • Prompt budgeting via PromptBudgets and truncation functions ensures reliable operation within LLM context limits
  • Safety mechanisms including admission pre-flight, supersession chains, and slot guards prevent unauthorized or destructive operations

Frequently Asked Questions

What happens if a session has no observations when consolidating?

The consolidate_session function returns EmptySession immediately after querying the store at consolidator.rs#L138-L140, preventing unnecessary LLM calls and preserving system resources.

How does the system handle partial failures in batch consolidation?

Batch operations use Wiki::apply_batch which implements all-or-nothing semantics. If any single page write fails within the batch, the entire transaction is rolled back, ensuring consistency across the multi-page update.

Is the original page content preserved during an LLM-driven rewrite?

Yes. The system treats each rewrite as a new Git revision through Wiki::write_page and commit_all. The supersession chain is automatically recorded, allowing complete version history recovery and preventing destructive overwrites.

What prevents unauthorized agents from triggering consolidations?

An admission pre-flight check at consolidator.rs#L150-L154 validates the caller's scope and actor permissions via preflight_admission before any LLM invocation occurs, providing cheap-fail security for Consolidate operations.

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 →