Subject Snapshots — Admin Operations Guide
Audience: Operators, platform admins, advanced internal users.
Not part of the public developer API. Gated behindSTATEWAVE_ENABLE_SNAPSHOTS=true.
What Subject Snapshots Are
Subject Snapshots allow operators to capture a subject's full state (episodes + compiled memories) and restore it into new subjects instantly (~200ms vs ~5s for re-ingestion + compilation).
They are an advanced admin/bootstrap capability — a way to clone known-good subject state for operational purposes.
What They Are For
- Demo environments — instant persona bootstrapping without re-running LLM compilation
- Staging/QA — reproduce known subject states for testing
- Onboarding templates — pre-built starter subjects for new tenants
- Migration/backup — snapshot before destructive operations
- Development — seed realistic data into dev environments
What They Are NOT
- Not the normal beginner workflow — developers build subjects by ingesting episodes and compiling memories
- Not part of the public
/v1API — lives under/adminonly - Not exposed in SDKs — neither statewave-py nor statewave-ts include snapshot methods
- Not documented in getting-started or beginner materials — intentionally hidden from the simple product story
- Not a replacement for the episode→compile→context lifecycle — snapshots produce subjects that went through that lifecycle, they don't replace it
Architecture
Source subject → create_snapshot() → _snapshot/{name}/v{version}
↓
SubjectSnapshotRow (metadata)
↓
restore_snapshot() → target subject (new UUIDs)Snapshot source data lives under _snapshot/* prefixes and is:
- Hidden from
GET /v1/subjects(filtered inlist_subjects) - Protected from cleanup (explicitly excluded)
- Never exposed to end-user API calls
Feature Flag
# Enable (production, staging)
STATEWAVE_ENABLE_SNAPSHOTS=true
# Disable (default — public-facing instances)
STATEWAVE_ENABLE_SNAPSHOTS=falseWhen disabled, all /admin/snapshots* and /admin/cleanup endpoints return 404.
Endpoints
GET /admin/snapshots
List all available snapshots.
POST /admin/snapshots/{snapshot_id}/restore
Restore a snapshot by UUID into a target subject.
{ "target_subject_id": "live_sarah_1234567890" }POST /admin/snapshots/restore-by-name
Restore by snapshot name (uses latest version).
{ "name": "sarah-startup", "target_subject_id": "live_sarah_1234567890" }POST /admin/cleanup
Clean up stale ephemeral subjects (e.g., abandoned demo sessions).
Query params: prefix (default live_), max_age_hours (default 24).
Restore Behavior
When a snapshot is restored:
- New UUIDs — all episode and memory IDs are regenerated
- Provenance remapped —
source_episode_idsin memories point to new episode IDs - Timestamps shifted — relative offsets preserved, newest episode anchored to
now() - Metadata annotated — provenance includes
restored_from_snapshotandoriginal_episode_id
The restored subject is indistinguishable from one built organically.
Creating Snapshots
Snapshot creation is done via the service layer (not exposed as API endpoint in v1):
from server.services.snapshots import create_snapshot
snap = await create_snapshot(
name="sarah-startup",
source_subject_id="some-source-subject",
version=1,
metadata={"persona": "startup founder"},
)See scripts/bootstrap_snapshots.py for the production bootstrap script.
Cleanup Loop
When enabled, the app runs an hourly background loop that calls cleanup_ephemeral_subjects(). This deletes live_* subjects older than 24 hours (configurable).
Snapshot source subjects (_snapshot/*) are explicitly excluded from cleanup regardless of age.
Deployment
On Fly.io:
fly secrets set STATEWAVE_ENABLE_SNAPSHOTS=trueBootstrap snapshots after deploy:
STATEWAVE_URL=https://statewave-api.fly.dev \
STATEWAVE_API_KEY=<key> \
python scripts/bootstrap_snapshots.pySafety Guarantees
- Snapshots are append-only (no update/delete API in v1)
_snapshot/*subjects never appear in user-facing endpoints- Feature flag prevents accidental exposure on public instances
- Cleanup never touches snapshot data
- Restore always creates new IDs (no collision risk)