# How the Auto-Improvement Scheduler Works in ai-memory: Session Review and Proposal Approval

> Discover how the auto-improvement scheduler in akitaonrails/ai-memory operates. Learn about session review, LLM proposal generation, and approval workflows for enhanced AI memory management.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: internals
- Published: 2026-08-19

---

**The auto-improvement scheduler in akitaonrails/ai-memory runs a background tick loop that claims completed sessions, generates wiki edit proposals through a read-only LLM review, and either auto-approves them or leaves them pending based on the `require_approval` configuration.**

The `ai-memory` project implements an **audit-first** background pipeline for continuously improving wiki documentation. The **auto-improvement scheduler** periodically inspects finished sessions, turns them into durable proposals, and applies or stages them according to operator-defined safety settings.

## Auto-Improvement Scheduler Startup and Scope Watermarking

When the server starts via `ai-memory serve`, the function `initialize_auto_improve_scheduler_scopes` seeds a **watermark** for every workspace-project pair. This prevents historic sessions from being auto-reviewed on upgrade. The initialization logic lives in [`crates/ai-memory-consolidate/src/auto_improve_schedule.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-consolidate/src/auto_improve_schedule.rs) at lines 48–76.

## The Auto-Improvement Scheduler Tick Loop

Each periodic invocation of `run_auto_improve_scheduler_tick` (defined in [`auto_improve_schedule.rs`](https://github.com/akitaonrails/ai-memory/blob/main/auto_improve_schedule.rs) at lines 124–166) executes a strict nine-step sequence. The scheduler is strictly separated from the approval logic: disabling the scheduler does not force manual approvals, and enabling manual approval does not stop the scheduler from running.

1. Reads all scopes.
2. Ensures scheduler state exists for each scope.
3. Queries `auto_improve_candidate_sessions` for new completed sessions, respecting `min_session_age_secs` and `max_sessions_per_tick`.
4. Claims each candidate atomically via `claim_auto_improve_scheduler_session`.
5. Invokes the read-only reviewer `run_auto_improve_review`.
6. Converts the review report into `NewAutoImproveProposal`s through `scheduled_auto_improve_new_proposals`.
7. Stages the proposals in the store via `stage_auto_improve_run_for_owner`.
8. Writes a side-car markdown file for each staged proposal via `write_auto_improve_sidecar`.
9. If `require_approval` is `false`, calls `Wiki::approve_auto_improve_proposal`; otherwise leaves proposals pending.

### Querying and Claiming Candidate Sessions

On every tick, the scheduler queries `auto_improve_candidate_sessions` and claims each candidate atomically via `claim_auto_improve_scheduler_session`. This prevents concurrent ticks from reviewing the same session twice. The query also respects `min_session_age_secs` and `max_sessions_per_tick` to bound workload.

### Reviewing Sessions with the Read-Only Pipeline

Claimed sessions are passed to `run_auto_improve_review` in [`crates/ai-memory-consolidate/src/auto_improve.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-consolidate/src/auto_improve.rs) at lines 94–121. This function is **read-only**: it inspects session observations, fetches recent wiki pages, builds an LLM prompt, calls the configured model, validates the response, and optionally runs an external eval gate (`apply_eval_gate`). It returns an `AutoImproveReport` containing validated proposals and any rejections. No database writes occur in this phase.

### Staging Proposals and Writing Side-Car Files

Valid proposals are converted into `NewAutoImproveProposal` objects via `scheduled_auto_improve_new_proposals`. The scheduler then persists them by calling `stage_auto_improve_run_for_owner`, which stores the run in the pending-writes table (`StageAutoImproveRun`) alongside metadata such as provider, model, and configuration. A human-readable **side-car markdown file** is written to `_pending/auto-improve/` via `write_auto_improve_sidecar`, creating an audit trail before any mutation reaches the wiki.

## How the Auto-Improvement Scheduler Approves Proposals

Approval behavior is controlled by the `require_approval` flag in the `[auto_improve]` configuration section.

### Auto-Approval vs Manual Approval

By default, `require_approval` is `false`. In this mode, the scheduler immediately calls `Wiki::approve_auto_improve_proposal` for each staged proposal. This wiki mutation path in [`crates/ai-memory-wiki/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/lib.rs) enforces authentication, admission checks, and audit logging while preserving the actor name `"auto_improve_scheduler_auto_approve"`.

When `require_approval` is set to `true`, proposals remain in the pending state. Operators can inspect, diff, approve, or reject them through the `ai-memory pending-writes` CLI commands.

```toml

# In .ai-memory.toml

[auto_improve]
require_approval = true

```

### Conflict Handling and Deduplication

If the store already contains a pending proposal targeting the same page, the new proposal is skipped. The scheduler logs a warning (`scheduled auto-improve proposal was not staged`), increments the `conflicts` counter in the tick outcome, and surfaces the result as `ApproveAutoImproveProposalResult::Conflict`. This **deduplication** guard prevents overlapping edits from colliding in the pipeline.

### Optional External Eval Gate

Before staging, proposals whose paths match `eval.targets` can be vetted by a user-provided external command inside `run_auto_improve_review`. Failures at this gate move the proposal to the `rejected_candidates` list, preventing it from ever reaching the pending-writes store.

## Monitoring Tick Outcomes

After each tick, the scheduler returns a `ScheduledAutoImproveTickOutcome` (defined in [`auto_improve_schedule.rs`](https://github.com/akitaonrails/ai-memory/blob/main/auto_improve_schedule.rs) at lines 94–107). The struct summarizes scopes processed, sessions reviewed, proposals staged, approvals executed, pending items left, conflicts encountered, skips due to store-level deduplication, and any errors. This data feeds the `auto-improve-report` telemetry and can be inspected via the CLI.

```bash
ai-memory auto-improve-report

```

You can also run the scheduler manually for testing or catch-up scenarios:

```bash

# Review the newest completed session

ai-memory auto-improve

# Review a specific session and auto-approve

ai-memory auto-improve --session-id 0123abcd

```

When operating in manual approval mode, use the pending-writes commands:

```bash

# List pending auto-improve proposals

ai-memory pending-writes list

# Show a diff for a specific proposal

ai-memory pending-writes diff <proposal-id>

# Approve a pending proposal manually

ai-memory pending-writes approve <proposal-id>

```

For programmatic access, an illustrative Rust call to the tick function looks like this:

```rust
let outcome = run_auto_improve_scheduler_tick(
    &reader, &writer, &wiki, &llm, &settings
).await?;
println!("Reviewed {} sessions, {} approved", outcome.reviewed, outcome.approved);

```

## Summary

- The **auto-improvement scheduler** is initialized at server startup with workspace-project watermarks to avoid re-processing historic sessions.
- Each tick claims completed sessions atomically, runs a **read-only LLM review** (`run_auto_improve_review`), and **stages** proposals with audit side-cars before any wiki mutation occurs.
- Proposals are **auto-approved** by default through `Wiki::approve_auto_improve_proposal`, but setting `require_approval = true` leaves them in the pending-writes store for human review.
- The scheduler handles **conflicts** via store-level deduplication and supports an **optional external eval gate** to reject low-quality proposals before staging.
- Every tick produces a `ScheduledAutoImproveTickOutcome` that exposes detailed metrics for observability.

## Frequently Asked Questions

### What triggers the auto-improvement scheduler?

The scheduler is triggered by a background timer that invokes `run_auto_improve_scheduler_tick` while the `ai-memory serve` process is running. It does not run offline. You can also invoke review manually with the `ai-memory auto-improve` CLI command.

### How can I disable automatic approval of proposals?

Set `require_approval = true` under the `[auto_improve]` table in your configuration file. This keeps all generated proposals in the pending state without stopping the scheduler from reviewing sessions and staging new proposals.

### What happens if two proposals target the same wiki page?

The store enforces deduplication. If a pending proposal already exists for the target page, the new proposal is skipped and recorded as a conflict (`ApproveAutoImproveProposalResult::Conflict`). The scheduler increments its internal `conflicts` counter and continues processing other candidates.

### Where are pending proposals stored before approval?

Staged proposals are stored in the `StageAutoImproveRun` pending-writes table and accompanied by a side-car markdown file under `_pending/auto-improve/`. This dual storage provides both a machine-readable queue and a human-readable audit trail for every proposed edit.