Principal-scoped storage (Slack team installs)
For a Slack user in a team workspace, OpenSRE resolves one principal (the Clerk organization that owns the install) and one actor (the Slack user). Team integrations and billing follow the principal. Conversation sessions follow the actor — the same private context a laptop CLI user keeps under~/.opensre.
Local CLI and Telegram stay on the flat host home when no org scope is bound.
Who owns the turn
If the install catalog is unreadable, or there is neither an install row nor a
silo org id, the Slack turn is refused rather than billed to the wrong owner.
On-disk layout
A laptop user keeps everything in~/.opensre. A Slack user gets the same
private conversation context, filed under their organization.
Deployed, the organization root is the mounted S3 Files volume named by
OPENSRE_CONTEXT_ROOT (/workspace/memories). The infrastructure chroots that
mount to one organization through a per-org access point, so OpenSRE adds no
org segment of its own:
~/.opensre layout, unchanged.
What changes for Slack
- Resolve
StorageScope(principal+actor) at the start of each Slack turn. - Bind the scope for the turn (
bound_storage_scope). - Resolve paths: org home for integrations, member home for sessions.
- Look up / create session bindings with
(platform, chat_id, principal_id, actor_id). - Consume credits against
principal.id(the org).
Other surfaces
principal and actor are optional on the binding store and resolver. Callers
that omit them — Telegram, and anything else on main’s path — key bindings by
empty principal/actor ids, which is exactly the behavior they had before.
Registering a workspace
Nothing in this change writesslack_installs rows: there is no OAuth or
control-plane hook yet. Until one exists, give a workspace an owner in one of
two ways.
Set the silo organization, which every workspace without a row falls back to:
Upgrading an existing deployment
Session bindings moved out of the hoststate.db into a per-organization
bindings.db beside that organization’s context. Opening the new database once
adopts any rows from the old one — including databases written before scoping
existed, which have neither principal_id nor actor_id; those adopt as
unscoped rows and keep working for Telegram and the CLI. A silo whose context
moved onto a mounted volume also adopts from the host database.
Slack members still get a new session on their first turn after upgrade: an
adopted row carries an empty actor id, so it no longer matches a member-scoped
lookup. The transcript survives and remains readable.
Session transcripts and integrations.json are not copied automatically. To
keep continuity on a silo, copy them once:
Related env vars
Non-goals (this change)
- CLI emulation of a Slack member
- Per-user integration credentials or LLM auth
- Nesting
opensre.json, investigations, or REPL history under member homes - Changing local CLI individual home layout
- Postgres session bindings
- OAuth writer for
slack_installs