Repository navigation
Epic: cloud-ready storage — move all persistence onto tinystoragedrivers ports #7419
Description
Goal
Prepare OpenHuman for cloud use: stateless pods sharing one backend (MongoDB for documents and streams, an object store for blobs, KMS for keys), with all user state behind the tinystoragedrivers ports. That means StorageBackend → ScopedStorage → DocumentStore / StreamStore / BlobStore / SearchIndex / SecretStore, through the host adapter crates/openhuman-core/src/storage/. One OPENHUMAN_STORAGE_URL should move everything. Today it moves about half.
Related: #7390 (core shrink).
Sub-issues
| Track | Issues |
|---|---|
| Drivers (tinystoragedrivers) | #7420 S3 blobs + streaming/presigned · #7421 KMS keys · #7422 schema versioning, watch, fencing |
| Stateless-pod blockers | #7423 run ledger · #7424 threads · #7425 blobs (attachments/artifacts/media) · #7426 sub-agent durability · #7427 memory side-state |
| Remaining state | #7428 workspace content + bootstrap split · #7429 skills · #7430 vendored stores · #7431 small stores |
| Endpoints & tenancy | #7432 endpoints (incl. reset not purging the backend) · #7433 process-global singletons |
| Guardrails & cleanup | #7434 CI bypass ratchet · #7435 retire legacy paths |
| Definition of done | #7436 two-core MongoDB + MinIO read-only e2e |
Audit summary
How the switch works
storage/config.rs mode_from() returns one of three modes: Url / Default / Classic. openhuman-rpc/src/session_store/mod.rs install_for_host installs the backend plus DriverSessionStores. Domains then branch per call on storage::installed() / Repo::current().
Already on the ports when a URL is set
- Approvals, devices, notifications, task sources (with an import from legacy SQLite).
- Cron jobs and policies; the flow catalog, drafts and checkpoints; delegation graph checkpoints.
- Artifact metadata.
- Subagent sessions and the task ledger.
- The Composio file store.
- The cost ledger.
- Secrets and credential profiles.
- The profile registry and leases.
- Config (
DocumentConfigSource). - Session transcripts, turn states, kv and journal.
Not on the ports, even with OPENHUMAN_STORAGE_URL=mongodb://…
| State | Where | Sub-issue |
|---|---|---|
| Run ledger: runs, workflow runs, teams, telemetry, tool effects | session_db/sessions.db (tinyagents-session) |
run ledger |
| Chat threads + search index | memory/conversations/*.jsonl + in-process trigram index |
threads |
| Attachments, artifact bytes, generated media, downloads, docs/slides | uploads/, ~/OpenHuman/projects/Files (no BlobStore consumer exists) |
blobs |
| Sub-agent lifecycle, pause checkpoints, background completions, sub-agent transcripts | .openhuman/*, flock + hard-link CAS |
sub-agent durability |
Memory job queue, sources, deletions, channel threads, local_root, tool-write FIFO |
memory/*.json, process RUNNING sets |
memory side-state |
Persona files, onboarding flags, app_state user part, channel allowlist (reads ~/.openhuman) |
workspace / home dir | workspace content |
| User skills, bundles, webhook routes, run logs | skills/, ~/.openhuman/skills |
skills |
| MCP registry + audit, connector prefs, x402 ledger, tinybox store, tinyjuice stash | vendored crates' own SQLite / JSON | vendored stores |
| tinymemes, browser sites/reports, security audit log, jev cache | JSON / rotated logs | small stores |
Driver gaps (vendor/tinyagents/vendor/tinystoragedrivers)
- Missing drivers: no S3/GCS blob driver, no Postgres.
- Blob API: no streaming and no presigned URLs.
- Secrets: no KMS key provider; the master key is a local file cached in a process
OnceLock. - Documents: no schema versioning and no watch / change streams.
- Fencing: not enforced on standalone MongoDB or on GridFS blobs.
Endpoints that assume one local node
http_host.*and its static file server.config.get_data_paths/get_agent_pathsreturn absolute paths;threads.update_working_dirtakes one.ai.*_artifactreturnsArtifactMeta.path.config.reset_local_datadoes not purge the installed backend.web_queue_*holds its queue in memory.- Large attachments ride base64 in the 43 MiB
/rpcbody.
Multi-tenancy
192 statics in core. Single-user globals include CURRENT_USER, ACTIVE_WORKSPACE, ATTACHMENTS_DIR and DEFAULT_WORKSPACE. Others are in-memory registries that must be shared across pods or need sticky routing. INTEGRATIONS_CACHE is keyed only by name.
CI
scripts/ci/check-storage-bypass.mjs covers only crates/openhuman-core/src and a narrow set of write patterns, so vendored stores and helper writers slip past it.
Must stay local (by design)
- Bootstrap config: the
[storage]table, the bootstrap part ofapp_state. - The master key source on desktop.
- Per-process tokens (injected via env in cloud).
- The agent's action dir and workspace, and sandbox scratch.
- Local model weights, module installs, regenerable catalogs.
- OS service units.
- Logs (stdout/OTLP in cloud).
- Desktop shell state.
- The vault watcher.
Suggested order
- Drivers: S3 blobs and KMS keys first; schema versioning, watch and fencing next.
- CI ratchet extension, so progress can be measured.
- Run ledger, threads, blobs, sub-agent durability, memory side-state. These are the stateless-pod blockers.
- Workspace content, skills, vendored stores, small stores.
- Endpoints and singletons.
- Retire legacy paths.
- Cloud e2e as the definition of done.
Rule: changes to vendored stores ship as an upstream PR first, then the gitlink bump. Every migration needs an import path for existing desktop data and a regression test.
Activity
tinysweeper commentedon Oct 11, 2026
Epic #7419 is a roadmap/tracking issue: move all remaining persistence (run ledger, threads, blobs, sub-agent durability, memory side-state, workspace, skills, vendored stores) behind the tinystoragedrivers ports so pods can be stateless against MongoDB/S3/KMS via a single OPENHUMAN_STORAGE_URL, plus driver gaps (S3 blobs, KMS, schema versioning/watch/fencing), endpoint and singleton cleanup, CI ratchet extension, and a two-core e2e as definition of done. It is not a single defect report; the five candidates are its own child sub-issues (#7420-#7433), not duplicates, so no prior art is named. As a large enhancement/refactor roadmap with workarounds still available (desktop-local storage keeps functioning), it is p3.
Labelled
priority: p3.