# How ai-memory Handles Destructive Operations: Safe Purging and Resetting Data

> Learn how ai-memory safely handles destructive operations like purging and resetting data. Discover its multi-stage safety protocol and logical delete approach.

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

---

**ai-memory implements a controlled, multi-stage safety protocol for destructive operations that guards against live processes, validates deletions through admission webhooks, performs logical deletes by default, and only physically removes data when explicitly requested via the `--compact` flag.**

The `akitaonrails/ai-memory` repository treats data removal as a critical, irreversible action requiring multiple safeguards. Whether you are resetting a local workspace or purging an entire project, the system employs a **controlled, multi-stage process** that prioritizes data integrity through live-process detection, pre-deletion validation hooks, and atomic transaction handling.

## The Six-Stage Safety Protocol

Every destructive operation in ai-memory follows a rigorous pipeline designed to prevent accidental data loss.

### Stage 1: Guarding Against Live Processes

Before touching any on-disk database or wiki files, ai-memory verifies that no other process holds the SQLite inode. In [`crates/ai-memory-cli/src/commands/reset.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/reset.rs), the `sibling_processes` function scans for concurrent ai-memory instances. If a sibling process is detected, the operation aborts immediately with a `busy_message` error to prevent database corruption during active sessions.

```rust
// Guard against a running sibling process (reset command)
let siblings = sibling_processes();
if !siblings.is_empty() {
    bail!(busy_message("reset", &siblings));
}

```

### Stage 2: Admission Webhook Validation

For project-wide purges (`purge-project`, `purge-session`, `delete-workspace`), the system runs an **admission webhook** before executing any SQL `DELETE` statements. As implemented in [`crates/ai-memory-mcp/src/admin.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/admin.rs) within the `handle_purge_project` function, this webhook can reject the operation based on external policy checks, keeping source data entirely intact if validation fails.

```rust
// Admission webhook check before purge-project (simplified)
let pre_checkpoint = checkpoint_or_500(&state.wiki,
    format!("pre-purge-project {label}"));
/* … webhook runs, may reject … */
let checkpoint = checkpoint_or_warn(&state.wiki,
    format!("purge-project {label}"));

```

### Stage 3: Logical Deletion (Soft Delete)

By default, purging records a **tombstone** entry rather than immediately erasing rows. The implementation in [`crates/ai-memory-store/src/ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs) marks records as deleted while preserving the corresponding wiki directory structure temporarily. This soft-delete approach maintains referential integrity and allows for potential recovery until a compaction run occurs.

### Stage 4: Optional Compact Mode for Hard Deletion

When the caller passes `--compact`, the system converts logical deletes into physical ones. According to **docs/lifecycle-ops.md**, this triggers an FTS index rebuild and a SQLite `VACUUM` operation, permanently removing tombstoned records and reclaiming disk space.

### Stage 5: Atomicity and Ordering

The purge executes inside a **single-writer SQLite actor** that guarantees no other writes interleave during the transaction. File cleanup occurs after the database transaction commits; any filesystem removal failure is reported via structured logging but does **not** rollback the committed database purge. This logic resides in [`crates/ai-memory-wiki/src/wiki.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/wiki.rs) within the `purge_*` helper functions.

### Stage 6: Logging and Observability

Every step emits structured logs using `tracing::info!(path = …, "purge")` and fires mirror-notification events (`X-Memory-Op: purge_project`). Downstream services can subscribe to these events to react to deletions in real-time, as documented in **docs/marker-file.md**.

## Resetting the ai-memory Environment

The `ai-memory reset` command provides a safe mechanism for wiping local data stores.

By default, reset runs as a **dry-run**, displaying the directories that would be removed without modifying the filesystem. When you supply the `--confirm` flag, the command executes the full safety protocol:

1. **Runs the live-process guard** (`sibling_processes`) to ensure exclusive database access
2. **Wipes three data sub-directories**: `wiki/`, `db/`, and `raw/`
3. **Preserves the `logs/` directory** for audit trails
4. **Emits structured logs** via `tracing::info!` for each removed path

```bash

# Dry-run a reset (shows what would be removed)

ai-memory reset

# Perform a full reset (must be alone, no other ai-memory process)

ai-memory reset --confirm

```

## Purging Projects, Sessions, and Workspaces

### Project-Level Purge Operations

The `purge-project` command removes the UUID-namespaced wiki root and raw workstream segments for the selected project. It succeeds only when no managed work-stream lease is active, unless you override this with `--force`. The thin client wrapper in [`crates/ai-memory-cli/src/commands/purge_project.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/purge_project.rs) forwards these requests to the `/admin/purge-project` MCP endpoint.

```bash

# Logical purge of a project (default, keeps tombstones)

ai-memory purge-project --workspace default --project my-project --confirm

# Hard purge + rebuild indexes

ai-memory purge-project --workspace default --project my-project --confirm --compact

```

### Session and Workspace Scope

`purge-session` and `delete-workspace` operate with identical safety semantics, scoped to a single session or the entire workspace respectively. As noted in **docs/lifecycle-ops.md** (lines 32-34), these commands follow the same admission-before-delete pattern and support `--compact` for hard deletion.

## Summary

- **Live-process detection** in [`reset.rs`](https://github.com/akitaonrails/ai-memory/blob/main/reset.rs) prevents destructive operations against active databases using inode-locking checks.
- **Admission webhooks** in [`admin.rs`](https://github.com/akitaonrails/ai-memory/blob/main/admin.rs) allow external validation to block purges before SQL execution.
- **Logical deletion** is the default behavior, creating tombstones rather than immediate erasure.
- **Physical deletion** requires the explicit `--compact` flag, which runs `VACUUM` and FTS rebuilds.
- **Atomic execution** inside a single-writer SQLite actor ensures transactional integrity during purges.
- **Comprehensive logging** via `tracing` and `X-Memory-Op` events provides full audit trails of destructive actions.

## Frequently Asked Questions

### What happens if I run ai-memory reset without --confirm?

The command executes a dry-run that lists all files and directories slated for removal without actually deleting them. You must explicitly add `--confirm` to execute the destructive operation, at which point the system also checks for sibling processes to ensure safe execution.

### How does ai-memory prevent data corruption during concurrent access?

Before any destructive operation, the system calls `sibling_processes()` to detect other ai-memory instances holding the SQLite database inode. If detected, the operation aborts with a busy error. Additionally, all writes route through a single-writer SQLite actor that serializes access and prevents interleaved transactions.

### What is the difference between purging and compacting in ai-memory?

**Purging** (the default) performs a logical delete that marks records with tombstones and removes wiki directories, but leaves database rows intact for potential recovery. **Compacting** (invoked with `--compact`) physically removes tombstoned records, rebuilds the FTS search indexes, and runs SQLite's `VACUUM` command to reclaim disk space permanently.

### Can I recover data after running purge-project?

Data recovery is possible only if you have not run the command with `--compact`. The default logical delete preserves database tombstones and wiki structures temporarily. Once you execute a compact operation or run `VACUUM` manually, the data is permanently erased from both the database and filesystem.