# How LLM-Driven Page Rewrite Works with `memory_consolidate`

> Discover how LLM-driven page rewrite works with memory_consolidate. This subsystem transforms raw observations into markdown, preserving history through Git-backed versioning.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: how-to-guide
- Published: 2026-09-01

---

**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`](https://github.com/akitaonrails/ai-memory/blob/main/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`:

```rust
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):

```rust
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:

```rust
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`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-consolidate/prompts/single_consolidate_system.md) at compile time. The function then invokes the LLM at lines 190-191:

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

```

The `complete_structured` helper, defined in [`crates/ai-memory-llm/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/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`](https://github.com/akitaonrails/ai-memory/blob/main/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`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/wiki.rs):

```rust
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`](https://github.com/akitaonrails/ai-memory/blob/main/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:

```rust
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:

```rust
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`](https://github.com/akitaonrails/ai-memory/blob/main/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.