- Recommended (with pairing)
- Explicit links only
How It Works
Quick Start
1
One platform, one user
2
Two platforms, one user (recommended)
3
In-process testing / ephemeral
Choosing Your Resolver
StoreBackedIdentityResolver
StoreBackedIdentityResolver extends the core FileIdentityResolver with a read-through to the gateway pairing store, so users who have already paired share a session out of the box.
Resolution order:
- Explicit link registered via
link()(highest priority) - Pairing-store label for
(user_id, platform)when the channel is paired and carries a non-emptylabel f"{platform}:{user_id}"— safe per-platform fallback (no merging)
link_paired() — Promote Paired Users to Explicit Links
In the gateway (praisonai gateway start)
The flagship WebSocketGateway daemon accepts the same resolver, so a paired user keeps one continuous session across every channel served by one gateway process.
Wire it three ways — YAML block, CLI flag, or Python override.
- YAML (recommended for daemons)
- CLI (--identity-store)
- Python override (always wins)
- A missing block, a non-mapping block, or
enabled: falsekeeps today’s default — per-platform session keys. enabledacceptstrue/false/"1"/"true"/"yes"/"on"(strings coerced case-insensitively).storeis~-expanded;pathis accepted as an alias.- Any failure to build the resolver degrades gracefully to per-platform keys and logs a warning — startup never aborts.
Precedence
WebSocketGateway(identity_resolver=…) > --identity-store > identity: YAML block > default (per-platform keys)
An explicit constructor or CLI resolver is never clobbered by the YAML block, even on hot-reload.
The gateway stamps the resolver onto each channel bot’s session manager at startup and on every hot-reload:
Gateway process: In the
praisonai gateway start daemon, the resolver is stamped onto each channel bot’s session manager via WebSocketGateway._stamp_identity_resolver() (mirrors _stamp_admission_gate). Restarted channels during hot-reload keep the resolver too — see Gateway Config Reload.End-to-end: one session across two platforms
- Operator approves both channels for the same label:
- Operator adds
identity: { enabled: true }togateway.yaml(or passes--identity-store). - Alice on Telegram:
"my favourite colour is octarine". - Hours later, Alice on Discord:
"what's my favourite colour?". - The gateway resolves both to
alice, loads the same session history, and replies"Octarine.".
CLI: praisonai identity
Four subcommands manage identity links from the command line.
Each subcommand accepts:
SessionContext for Tools
Any tool the agent calls can read who is messaging:SessionContext Fields
Use
set_session_context / clear_session_context for advanced custom adapters. Returns a token; reset in a finally block.Concurrent Turns Across Adapters
With an identity resolver configured, near-simultaneous turns from different adapters that resolve to the same unified user run one at a time against that user’s single transcript. Each adapter — Telegram, Discord, Slack — keeps its own session manager, and the identity resolver unifies them onto one persisted session per human. Before this fix, each adapter still guarded its turns separately, so two adapters could run turns for the same human at the same time and scramble the order of their shared transcript.When it matters
- A cron or scheduled outbound delivery lands on platform A while the user replies on platform B — the mirror and the inbound reply serialise cleanly (see Mirror for Outbound Deliveries).
- A user types on Telegram while their smartwatch fires a Slack message in the same second — the second turn waits for the first to commit before appending, so the transcript stays in strict
user → assistant → userorder.
Nothing to configure. This is automatic whenever an identity resolver is wired via
BotOS(identity_resolver=…), the gateway’s identity: YAML block, or --identity-store. Deployments without a resolver are unchanged.Multi-replica gateways: the shared turn lock stamped onto channel bots is in-process only. If you scale the gateway to
replicas > 1, enable a distributed backend — see Gateway Turn Lock.Mirror for Outbound Deliveries
Cron jobs, scheduled deliveries, and cross-platform replies need to mirror the assistant’s outbound message into the user’s history:Parameters
Errors are swallowed and logged — a mirror failure must never break the outbound delivery itself.
Storage & Privacy
FileIdentityResolver defaults to ~/.praisonai/identity.json (override via PRAISONAI_IDENTITY_PATH env var or constructor path=). File is written atomically and chmod 0o600.Running the flagship daemon? See In the gateway (
praisonai gateway start) for wiring the same resolver via the identity: YAML block, --identity-store, or the WebSocketGateway constructor.Best Practices
Use StoreBackedIdentityResolver for production (with pairing)
Use StoreBackedIdentityResolver for production (with pairing)
For production wrapper deployments, use
StoreBackedIdentityResolver.from_env() — it picks up paired channels automatically and falls back to the same safe platform:user_id default. Plain FileIdentityResolver is the right choice only when you do not use the pairing system.Use FileIdentityResolver for explicit-only links
Use FileIdentityResolver for explicit-only links
For production single-host bots without pairing integration,
FileIdentityResolver provides persistent storage with atomic writes and proper file permissions.Implement custom IdentityResolverProtocol for scale
Implement custom IdentityResolverProtocol for scale
For multi-process/multi-host deployments, back it with SQLite, Redis, or a database:
Pair before linking
Pair before linking
Never auto-link based on display name. Always require a DM-verified pairing flow:
Read SessionContext in tools
Read SessionContext in tools
Instead of
os.environ, read SessionContext — concurrent message handlers won’t trample each other:Related
BotOS
Multi-platform bot orchestrator
Messaging Bots
Platform-specific bot guides
Bot Pairing
Secure unknown-user onboarding
Unknown-User Pairing
Inline-button approval for bots
Gateway CLI
--identity-store and other gateway start flagsGateway Config Reload
Hot-reload the
identity: block without dropping turns
