> ## Documentation Index
> Fetch the complete documentation index at: https://docs.genesiscomputing.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage Management

> See what fills the Genesis data disk, clean up Genesis's own files, delete old content by rule or by person, and restore a deleted chat or mission from a state snapshot.

## Overview

Genesis keeps its state on one data disk: chats and their uploads, Git repositories, missions, apps, datasets, document indexes, logs and temporary files. **Admin → Configuration → Storage** lets an administrator see what uses that disk and free space without shell access to the volume.

The page has five tabs:

| Tab | What it is for |
| - | - |
| [Overview](#overview-tab) | How full the disk is, by content type, by person and by role, and the warning level |
| [System](#system-tab) | Clean up files Genesis makes for itself: temporary files, old logs, unused environments |
| [Retention](#retention-tab) | Rules that delete old chats, missions and apps, and the dataset versions kept; restore a deleted chat or mission |
| [Items](#items-tab) | Every stored item of a type, with its owner and who can see it |
| [Cleanup](#cleanup-tab) | Delete what chosen people or roles made between two dates |

Everything on the page needs the **Access config panel** permission, which the built-in `admin` role holds. Listing or deleting other people's chats and chat uploads (on Items and Cleanup) also needs **See every user's chat threads**. Every change the page makes is written to **Admin → Audit Log** under the `storage` target type.

Before deleting anything people made, set up [state snapshots](https://docs.genesiscomputing.com/docs/deployments/State-Snapshots-And-Migration.md): a deleted chat or mission can be restored only from a snapshot that holds it.

## Overview tab

The Overview shows a bar of used and free space split by content type, then three tables: by content type, by person and by role. Each content type has an **Open** button that goes to the page that owns that content (Chat, Git, Apps, Datasets, Documents, Context Graph, Missions). A person counts in each of their roles.

Genesis measures the disk every six hours and when you press **Measure now**. The footer says when the last measurement ran.

Limits:

* A measurement stops after a time budget (`storage.usage_scan.budget_seconds`, 120 seconds by default). When it runs out, the footer says so and the totals cover only what was measured.
* Content no person owns (logs, temporary files, environments) is counted under **System**. An item whose owner cannot be found is counted under **Unknown owner**.
* An app's `node_modules` and Python environment count as "Python and Node environments", not as the app owner's, because Genesis can rebuild them.
* The metadata database is shown on its own line. When it is in Postgres, its size is the database's size.
* If the Git folder is on a different disk from the storage folder, the free part of the bar is approximate.

### Warning level

**Warning level** sets when the disk counts as low: free space below a size (`disk_guard.warn_free_bytes`), or use at or above a percentage (`disk_guard.warn_used_percent`, 85% by default; 0 turns the percentage off). When the disk crosses the level, the Storage page shows a banner and every administrator gets one bell notification. They get another only after the disk recovers and crosses it again; after a restart, a disk that is still low is announced once more.

## System tab

The System tab cleans up content Genesis makes for itself. Each kind has an age; a scheduled cleanup (daily by default, `system_cleanup.interval_seconds`) removes items of the kinds turned on, and **Review** shows exactly what a run would remove before you remove it.

| Kind | Daily by default | Age (days) |
| - | - | - |
| Temporary files | On | 7 |
| Old logs (rotated copies of Genesis's own logs) | On | 30 |
| Unused agent Python environments | On | 30 |
| Context Graph copies (re-cloned by the next scan) | On | 14 |
| Worktrees of deleted repositories | On | 7 |
| Agent folders set aside by the agent folder check | Off | 30 |
| Files of apps deleted earlier | Off | 30 |

Change the kinds and ages in **Cleanup settings**. The tab also lists cleanup jobs that have their own settings (orphaned uploads, expired datasets, notifications, cost records, app runtime folders, the thread archive and the agent folder check), with their next run.

Limits:

* An item's age is the newest change inside it. An item whose age cannot be read is kept, an item in use is kept, and symbolic links are never followed or removed.
* **Old logs** are only rotated copies of Genesis's own log files, never the current ones and never other files in the folder.
* A review lists the largest 500 items. Its count and size, and the run, cover all of them.
* A run removes exactly the list you reviewed. If what would be removed changed since the review, the run is refused and the list is shown again.
* dbt runtimes and the pip cache are not cleaned here (they have their own limits), and saved query results have no cleanup.

## Retention tab

The chat, mission and app rules delete content that nobody has used for longer than an age you set. Each of these is off by default; turned on, it runs once a day (`retention.interval_seconds`). **Review** shows exactly what the rule would delete now, with each item's owner, who can see it and its size; deleting from the review deletes that list and nothing else.

Dataset versions work differently: they have no switch and are always pruned, on the dataset cleanup's own schedule and on each refresh (see [Dataset versions](#dataset-versions)).

| Rule | Deletes | Can be restored |
| - | - | - |
| Chat threads | Chats idle past the age, with their uploads and generated files | Yes, from the snapshot that holds it |
| Missions | Finished missions idle past the age, with their own chat and replay | Yes, from the snapshot that holds it |
| Apps | Apps nobody has opened or run past the age, with their code, saved versions and change history | No: deleted for good |
| Dataset versions | Older versions of each dataset, and expired query caches | No: deleted for good, and a dataset can no longer be rolled back to them |

Set the chat, mission and app rules' ages and daily switches, the snapshot location, and how many dataset versions are kept in **Retention settings**.

### Chats and missions: deleted only once a snapshot holds them

A chat or mission is deleted only when the newest complete state snapshot at `retention.snapshot_location` holds every one of its files (matched by SHA-256 against the snapshot's signed manifest) and every one of its rows. Anything changed since that snapshot is listed under **Waiting for the next snapshot** and is deleted only once a later snapshot holds it. With no snapshot location set, these rules delete nothing.

Each deleted chat or mission is listed under **Deleted, recoverable** (and, for missions, under the Missions page's status filter). **Restore** puts that one item back from the snapshot named beside it: its files, its rows, its owner and who could see it. The restore is refused, and nothing changes, when the item exists again or when its snapshot is no longer at the snapshot location.

Limits:

* These rules delete only where the metadata database is genesis.db, chats are stored as files and durable SQLite copies are off. On any other deployment, the rule says why it deletes nothing.
* Message times are stored without a time zone, so a chat or mission counts as changed until a snapshot taken at least 14 hours after its last message holds it. Recent work waits for a later snapshot.
* A mission's Git repository is never deleted by the missions rule: a snapshot cannot restore a repository's access record.
* A restore does not bring back a chat's skill-use history, its room subscriptions or its mailbox. Rows deleted from the item after the snapshot was taken come back with the restore.
* The snapshot location is read with the instance's own cloud identity (IRSA, instance profile or Workload Identity). A named connection cannot be used.
* If the server stops while a restore is downloading, the restore is not applied; run it again once the server is back.
* Pinned chats, chats a mission runs in, unfinished missions and `demo:protected` missions are never deleted by a rule.

### Apps: deleted for good

A snapshot cannot restore one app on its own, so the apps rule deletes for good. Its review says so, and **Delete** works only after you tick **Delete these apps for good. They cannot be restored.** (with the count, or "this app" for one) The daily run deletes apps only when you turn the rule's daily switch on; that switch is your consent to deleting for good.

Limits:

* An app's age is the time since it was last opened, run or saved as a version (any of its versions counts), or since it was made if it was never used.
* Apps that ship with Genesis, and apps the system owns, are never deleted by the rule. On an instance with sign-in switched off every app is owned by the system, so the rule deletes nothing there.
* An app deployed remotely is kept: opening it there is not recorded, so Genesis cannot tell it is unused.
* Shared apps are listed with **Shared** under "Who sees it" so you can keep them.
* The size shown is the app's workspace and runtime folders.
* An app opened, kept or handed to someone else after the review is left as it is when the rule runs.

### Dataset versions

Each dataset keeps its newest versions. The dataset versions rule shows the dataset cleanup's own settings, which keep working exactly as before:

* **Keep the newest** (`datasets.snapshot_keep_last`, 30 by default) and **Delete versions older than** (`datasets.snapshot_max_age_days`, off by default). 0 turns either limit off. The version in use is never deleted.
* These apply to datasets whose refresh settings do not set their own time to live (`ttl_seconds`). A dataset's own time to live replaces them.
* Query caches expire after seven days, and the built-in datasets keep their newest 20 versions for up to seven days. These are not settings on this page.

The dataset cleanup deletes what **Review** lists on its own schedule, every six hours (`GENESIS_DATASET_CLEANUP_INTERVAL_S`). A run deletes in batches (`jobs.dataset_cleanup.batch_size`) until nothing is left or its time budget (`jobs.dataset_cleanup.pass_budget_seconds`, ten minutes) runs out; the rest waits for the next run. Refreshing a dataset also deletes its own versions past the limits, whether or not the cleanup is scheduled. The cleanup is off where the storage folder is a Snowflake stage mount, and the rule then says it is not scheduled. There is no "delete now" for dataset versions, and `retention.protected_types` does not apply to them.

Lowering a limit deletes the versions past it at the next refresh or cleanup, for good: review them first.

### Keep and protected content

Some content is never deleted by a rule:

* **Protected types** (`retention.protected_types`): agent memory, wiki, Context Graph, skills and blueprints by default. A rule whose own type is listed (for example `apps`) deletes nothing. Only a person's own delete removes protected content.
* **Kept items.** An administrator keeps an item with **Keep** in a rule's review, and stops keeping it under **Kept**. The owner of a chat, mission or app can keep it through the API, `PUT /api/storage/holds/{type}/{id}` (and `DELETE` to stop); there is no Keep button on the Chat, Missions or Apps pages yet. A mission whose own chat is kept counts as kept.

### How retention relates to state snapshots

A deleted chat or mission can be restored only while the snapshot that holds it is kept. Later snapshots do not hold deleted items, and snapshots are removed by your bucket's lifecycle rules. So:

* **Keep snapshots at least as long as your audit period.** The recovery window for a deleted item ends when the snapshot named beside it is removed.
* The Retention tab shows the newest snapshot (what rules rely on) and the oldest snapshot still held (where the recovery window ends).
* Take snapshots regularly: content changed since the newest snapshot waits for the next one.

See [State Snapshots and Migration](https://docs.genesiscomputing.com/docs/deployments/State-Snapshots-And-Migration.md) for taking and keeping snapshots.

## Items tab

The Items tab lists every stored item of one type, newest first: chats, chat uploads, Git repositories, missions, apps, datasets, document indexes, skills and blueprints. Each row shows the owner, who can see it (Personal, Shared, the roles it is shared with, or System), when it was made and last used, its size where the type records one, and why it is kept, if it is. Filter by owner and by who can see it.

Limits:

* At most 1,000 items are listed; the total counts all of them.
* Git repositories record no creation time. The first time the Items tab or a cleanup sees a repository, its folder's change time is kept as its creation time.
* Owner and visibility columns on the Chat, Git, Apps, Datasets and Documents pages themselves are not part of this release.

## Cleanup tab

The Cleanup tab deletes what chosen people, or anyone in chosen roles, made between two dates, for example after a training week.

1. Choose people or roles, a creation date range (both days included, UTC) and content types.
2. **Review** sorts every selected item into one of three groups:
   * **Restorable after deleting:** a chat or mission the newest snapshot holds. It is deleted as a retention rule deletes it and can be restored from the Retention tab.
   * **No snapshot holds these:** chats or missions changed since the newest snapshot, and every repository, app, dataset and document index. These are deleted for good, and only when you tick **Also delete these for good**.
   * **Kept:** protected types, kept and protected items, items in use, and chat uploads, skills and blueprints, which a cleanup never deletes.
3. Type `delete` to confirm. The cleanup runs in the background and records each item's outcome.

A cleanup survives a restart: one cut off by a restart is shown as interrupted, and **Run again** finishes its own remaining items, never a new selection. Only one cleanup or retention run happens at a time.

Limits:

* An item is matched on its owner field only. Content the system owns is never selected, and an item whose creation time is unknown is never selected by a date range.
* Each review lists at most 500 items per group; its counts, sizes and the run cover all of them.
* Each item is checked again just before it is deleted. One whose owner changed, that came into use, or that was kept since the review is skipped and recorded.
* Team leads cannot run a cleanup for their own role; only administrators can.

## Audit records

Every action on the page writes an `admin_audit_log` row with target type `storage`: the person (or `system` for a scheduled run), the time, the item's type, id and owner, and the bytes freed. Titles and paths are never recorded. The actions are:

| Action | Written when |
| - | - |
| `storage.measure_requested`, `storage.warning_level_changed` | A measurement is started; the warning level changes |
| `storage.system_cleanup_ran`, `storage.system_cleanup_settings_changed` | A system cleanup runs; its settings change |
| `storage.retention_deleted` | A rule or cleanup deletes a chat or mission, with the snapshot that holds it |
| `storage.retention_removed` | The apps rule deletes an app for good |
| `storage.retention_restored` | A chat or mission is restored from its snapshot |
| `storage.keep_marked`, `storage.keep_removed` | An item is kept or stops being kept |
| `storage.retention_settings_changed` | Retention settings change |
| `storage.cleanup_started`, `storage.cleanup_resumed`, `storage.cleanup_item`, `storage.cleanup_finished` | A cleanup starts or runs again, acts on each item, and ends |

If the server process is killed rather than stopped (for example by the node running out of memory), the audit rows of its last moments can be missing. A cleanup's own record of each item, under **Cleanup**, is kept and shows what was removed.

## Settings reference

| Setting | Default | What it does |
| - | - | - |
| `storage.usage_scan.interval_seconds` | 21600 | How often the disk is measured |
| `storage.usage_scan.budget_seconds` | 120 | Longest a measurement runs |
| `disk_guard.warn_free_bytes`, `disk_guard.warn_used_percent` | 5 GiB, 85% | The warning level |
| `system_cleanup.interval_seconds` | 86400 | How often the system cleanup runs |
| `system_cleanup.<kind>.enabled`, `.max_age_days` | See the table above | Each system cleanup kind |
| `retention.snapshot_location`, `retention.snapshot_region` | Empty | Where state snapshots are written; empty: chats and missions are never deleted |
| `retention.interval_seconds` | 86400 | How often retention rules run |
| `retention.protected_types` | Agent memory, wiki, Context Graph, skills, blueprints | Types no rule deletes |
| `retention.threads`, `.missions`, `.apps` (`enabled`, `age_days`) | Off, 365 days | Each rule |
| `datasets.snapshot_keep_last`, `datasets.snapshot_max_age_days` | 30, 0 | The dataset versions kept |

Full descriptions are in the [Configuration Reference](https://docs.genesiscomputing.com/docs/Setup/Configuration-Reference.md).
