Skip to main content
opensre keeps everything on your laptop by default. Turn on remote sync and it also mirrors your conversation history and memory to an object store you own, so a second machine picks up where the first left off. Your cloud credentials are read from the usual places — environment, profile, SSO session. opensre never stores them.

What is mirrored

Credentials stay on the machine. On a second laptop you run the integration setup again; everything else is already there.

Turn it on

Writes remote_sync into ~/.opensre/config.yml. Ambient credentials stay in the environment — opensre never stores them.

Environment variables

Naming a bucket is not enough on its own — OPENSRE_REMOTE_SYNC has to be set too, so a bucket variable left over from another tool never starts uploading. --region are AWS-only, while —profile is used by AWS and Azure — opensre remote-sync setup rejects either one for a provider that doesn’t use it, rather than saving it silently and never reading it back. (Their env-var equivalents, OPENSRE_REMOTE_SYNC_REGION/PROFILE, are read the same way regardless of provider and are simply ignored by a provider that has no use for them.) You can also persist settings under remote_sync in ~/.opensre/config.yml (enabled, bucket, provider, prefix, …) — that is what remote-sync setup writes. Credentials are never written there; they stay in your cloud CLI’s usual places. Environment variables still win for a single run.
Every machine that should share your history needs the same provider, store, and prefix (and for Vercel, a token for that store). Change the prefix only when you want a separate, isolated set of conversations — a different prefix is a different history, not a backup of the same one.
All surfaces share one remote-sync engine entry point:
This mirrors a personal machine. Turns that belong to an organization — Slack and Discord, which bind an org principal — are refused, because object keys carry no organization or member id and every member would otherwise share the same keys. Organization history already persists through the mounted context root (OPENSRE_CONTEXT_ROOT); it does not need this.
Check what would move before moving it:
Then sync:
On a terminal, a progress bar (Pulling/Pushing, a count of how many files are done, and the current file) shows a large sessions/ tree moving instead of looking hung; piped or scripted output stays to the final summary line only. The interactive shell shows the same thing as a live-updating bar.

Exclude paths

By default every session and every memory file mirrors. Patterns hold some of them back:
Or, to keep it between machines, in ~/.opensre/config.yml:
When the environment variable holds patterns, it replaces the stored list for that run rather than adding to it. To sync everything once, including the paths you normally hold back:
Blanking OPENSRE_REMOTE_SYNC_EXCLUDE does not do this — an empty value counts as not setting it at all, and your stored list stays in force. That is deliberate: a script expanding a name that turns out to be unset should not quietly upload what you meant to keep local. Switching exclusions off is a separate variable so it has to be done on purpose. Patterns match the key inside the store — sessions/… or memory/…, always with forward slashes — and are case-sensitive, so one settings file means the same thing on every machine. * crosses directory separators, so memory/* covers nested files too. Check your patterns took effect before trusting them — status shows how many files under each root are currently held back, so a root you expected to shrink still showing no count means nothing matched:
An excluded path is held back in both directions: not uploaded from this machine, and not downloaded onto it if another machine already put it there.
Exclusions only ever remove things from the sync. There is no !pattern syntax to add something back — opensre rejects a pattern starting with ! — so no setting you write can send credentials to the store. Anything already uploaded before you added a pattern stays there; sync never deletes. Remove it in the store yourself if you want it gone.

Providers

The sync engine talks only to a small object-store interface. Built-in backends today: Other clouds (GCS, …) are community additions: implement ObjectStore, call register_object_store("<name>", factory), and set OPENSRE_REMOTE_SYNC_PROVIDER — the engine, CLI, and REPL do not change.

AWS / S3 (default)

Any private bucket works. Uploads request server-side encryption, so a bucket that requires encryption accepts them unchanged. Minimum permissions on the prefix you use:
s3:DeleteObject is not needed — sync never deletes anything. Add s3:GetBucketPolicyStatus (bucket-level, not prefix-scoped) so status can warn you if the bucket is publicly readable — see The store.

Google Cloud Storage

Set OPENSRE_REMOTE_SYNC_PROVIDER=gcs and point OPENSRE_REMOTE_SYNC_BUCKET at any private bucket. Credentials come from Application Default Credentials — run this once per machine and sign in with the account that owns the bucket:
Minimum permissions on the bucket (a bucket-scoped roles/storage.objectUser binding covers all four):
opensre never deletes anything, but GCS still requires storage.objects.delete to replace an existing object — without it the first changed session or memory file fails with a 403. Objects are encrypted at rest by default; there is nothing to configure. Add storage.buckets.getIamPolicy (bucket-level) so status can warn you if the bucket is publicly readable — see The store. Without it, status shows “could not confirm it is private” instead of failing.

Vercel Blob

Use a private Blob store. Objects are written private (not public URLs). OPENSRE_REMOTE_SYNC_BUCKET is the store name or id for status output; auth is the read-write token, not the bucket string.
Create a private store and token with the Vercel dashboard or CLI (vercel blob create-store my-store --access private, then connect the store to a project so BLOB_READ_WRITE_TOKEN is available — or paste the token from the store’s settings).
BLOB_READ_WRITE_TOKEN is scoped to one store. Point every machine that should share history at the same token (or an equivalent token for that store), plus the same prefix.
Access mode (private or public) is set once, for the whole store, when you create it — Vercel does not let you change it afterward. status can check this and warn you if the store came out public, but it needs a different, broader credential than BLOB_READ_WRITE_TOKEN: a Vercel account/team API token, since the store-management API does not accept a Blob read-write token at all. If you already use the vercel integration for observability, this is the same VERCEL_API_TOKEN (and optional VERCEL_TEAM_ID for a token spanning several teams) — nothing new to set up. Entirely optional: without it, status shows “could not confirm it is private” instead of failing.

Azure Blob Storage

Any private Azure Storage container works. OPENSRE_REMOTE_SYNC_BUCKET is your Container name, and OPENSRE_REMOTE_SYNC_PROFILE maps to your Storage Account Name. Authentication relies entirely on Azure’s ambient credentials (DefaultAzureCredential). This means you can authenticate via the Azure CLI (az login), Managed Identities, or environment variables (AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET). opensre will never store these credentials directly. The authenticated principal must have the Storage Blob Data Contributor role assignment on the storage account. The generic “Contributor” role is insufficient as it only grants control-plane access, not data-plane access.

The store

Keep the store private. It holds your incident conversations and everything opensre has remembered about your systems. Prefer a private S3 bucket or a private Vercel Blob store — never a public one.
status checks this for you on every built-in provider: the bucket policy (S3), the bucket IAM policy (GCS), or the store’s access mode (Vercel Blob, via the optional VERCEL_API_TOKEN above) — if any of them say public, opensre remote-sync status / /remote-sync status opens with a warning instead of silently mirroring your history into it. Without the permission or credential the check needs, status shows “could not confirm it is private” instead of failing; it never blocks the rest of the command.

How conflicts resolve

Sync pulls first, then pushes. A file that exists on only one side is copied to the other. When both sides changed the same file, the more recently written one wins. Nothing is ever deleted, on either side. A machine that has been offline for a month cannot erase work done elsewhere — worst case it re-uploads an old copy under the same name, and the newer one wins on the next sync. Deleting a session or a memory on one machine does not remove it from the store or from your other machines. Delete it in the store too if you want it gone everywhere.