You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The agent owner has no consistent way to answer: "who is allowed to talk to this agent?"
As a result, per-channel auth drifts apart, user memory (MEM-001) can't flow across channels, and there's no single enforcement point for access policy.
Design principle
Verified email is the single unit of identity across every channel. Each adapter is responsible only for translating its native identifier into a verified email. After that, every downstream concern (access control, memory, audit, rate limiting) runs off the same key.
The design reuses existing primitives wherever they already fit and introduces exactly one new table and one new adapter method.
Reuse map
Existing primitive
Role in this design
agent_ownership
Policy lives here — add require_email, open_access as an agent-settings mixin (architectural invariant #2)
agent_sharing(agent_name, shared_with_email)
Per-agent allow-list — unchanged, becomes the source of truth for cross-channel access
User replies with code → db.verify_code → adapter writes verified_email onto the telegram_chat_links row
Subsequent messages resolve to the verified email automatically
Router-level enforcement (single gate)
In adapters/message_router.py, before execute_task:
email = adapter.resolve_verified_email(message)
if policy.require_email and not email:
adapter.prompt_auth(message); return
if is_owner(email, agent) or is_admin(email) or email in agent_sharing(agent):
proceed
elif policy.open_access:
proceed
else:
upsert access_requests(agent, email, status=pending)
notify owner
adapter.reply("Your access request is pending approval.")
return
After success, source_user_email = email flows into execute_task, and memory injection (MEM-001 parity for all channels) uses public_user_memory(agent_name, email) directly.
Slack, WhatsApp, and any future channel inherit the whole flow by implementing only resolve_verified_email.
Net delta vs the first draft
❌ No new channel_user_auth table → extend telegram_chat_links (2 columns)
❌ No new agent_access_policy table → 2 bool columns on agent_ownership via settings mixin
❌ No new allow_list concept → agent_sharingis the allow-list
✅ One new table: access_requests
✅ One new adapter method: resolve_verified_email
✅ One router-level gate
✅ MEM-001 becomes cross-channel without a schema change
Sub-tasks
Migrate agent_ownership with require_email, open_access (settings mixin)
Roles model (ROLE-001): end-user access control is orthogonal to platform roles — roles govern platform capabilities, access control governs agent end-user access. Admins still bypass. creator owning an agent still must /login to bind their Telegram identity — desirable, not a regression.
Problem
Each channel today grows its own identity and access model:
The agent owner has no consistent way to answer: "who is allowed to talk to this agent?"
As a result, per-channel auth drifts apart, user memory (MEM-001) can't flow across channels, and there's no single enforcement point for access policy.
Design principle
Verified email is the single unit of identity across every channel. Each adapter is responsible only for translating its native identifier into a verified email. After that, every downstream concern (access control, memory, audit, rate limiting) runs off the same key.
The design reuses existing primitives wherever they already fit and introduces exactly one new table and one new adapter method.
Reuse map
agent_ownershiprequire_email,open_accessas an agent-settings mixin (architectural invariant #2)agent_sharing(agent_name, shared_with_email)telegram_chat_linksverified_email,verified_atcolumnsemail_verification_codes+db.create_verification/db.verify_code/loginverification — no new verification codepublic_chat_sessions.session_identifierpublic_user_memory(agent_name, user_email)email_serviceOwnedAgentByNamedependencyWhat is actually new
One table:
Approval flow:
status=approved→ insert intoagent_sharing→ delete or archive the request.One adapter method (
ChannelAdapterbase):telegram_chat_links.verified_emailfor thetelegram_user_id; if absent, sends auth prompt and the router early-returnsusers.info— Slack's workspace email is already verified, no 6-digit code neededpublic_chat_sessions.session_identifierwhenidentifier_type='email'Telegram
/loginstate machine (in the Telegram adapter only):telegram_user_idsends a message → adapter replies with auth prompt/login user@example.com→db.create_verification→email_servicesends 6-digit codedb.verify_code→ adapter writesverified_emailonto thetelegram_chat_linksrowRouter-level enforcement (single gate)
In
adapters/message_router.py, beforeexecute_task:After success,
source_user_email = emailflows intoexecute_task, and memory injection (MEM-001 parity for all channels) usespublic_user_memory(agent_name, email)directly.Slack, WhatsApp, and any future channel inherit the whole flow by implementing only
resolve_verified_email.Net delta vs the first draft
channel_user_authtable → extendtelegram_chat_links(2 columns)agent_access_policytable → 2 bool columns onagent_ownershipvia settings mixinallow_listconcept →agent_sharingis the allow-listaccess_requestsresolve_verified_emailSub-tasks
agent_ownershipwithrequire_email,open_access(settings mixin)public_links.require_email→ inherit from agent policy (question for feat: Public chat link email whitelist and access requests #252: keep per-link override or drop?)access_requeststable + owner inbox UI + approval endpoint (inserts intoagent_sharing)telegram_chat_linkswithverified_email,verified_at/loginstate machine intelegram_adapter.pyresolve_verified_emailonChannelAdapterbase + implementations (Telegram, Slack, Web)message_router.py, replacing per-channel ad-hoc authAcceptance criteria
require_email+ anagent_sharingentry on an agent gates chat identically on web, Telegram, and Slackagent_sharingand the user can chat immediately across any channelpublic_user_memoryrecordresolve_verified_email; access control and memory work without additional codeaccess_requestsArchitectural alignment
agent_settingsmixincreatorowning an agent still must/loginto bind their Telegram identity — desirable, not a regression.Related