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
Setup command (recommended)
Writesremote_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.
Check what would move before moving it:
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:~/.opensre/config.yml:
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:
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
SetOPENSRE_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:
roles/storage.objectUser
binding covers all four):
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.
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.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
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.