Multiplayer channels in Cortex Agents for Slack¶
Introduction¶
A multiplayer channel is a Slack channel where everyone uses the same CoCo (Cortex Code) agent and the same Snowflake
identity. An administrator binds the channel to a Snowflake service user and a role, and can optionally bind a CoCo
agent object and a Restricted Session Scope (RSS). If you omit the agent object, the channel still runs CoCo as the
bound service user, without applying a stored agent specification. Any member of the channel can start a request by
@mentioning the app. The app runs the request as the bound service user, with the bound role.
Channel members don’t need to be Snowflake users in your account, and they don’t need to sign in to Snowflake from Slack. This differs from the per-user setup, where each person signs in as their own Snowflake user and the app runs their requests as that user. In a multiplayer channel, every request runs as the same bound service user, whoever sends it.
Use CoCo in a multiplayer channel¶
After the app is invited to a bound channel, @mention it in a top-level message to start a public thread. The reply and
follow-up messages in that thread are visible to the channel. After the initial mention, any channel member can send a
follow-up in the thread without mentioning the app again. To start a separate conversation, post a new top-level message
and mention the app. To start a thread from every top-level message, without an @mention, set
autoStartOnAnyMessage on the agent. See configure channel behavior.
In a multiplayer channel, requests behave differently from requests in a direct message with the app:
- Only the bound role is active. Secondary roles are disabled, so a request can use only the privileges of the role in the binding, even if other roles are granted to the service user.
- No approval prompts. In a direct message, CoCo asks for approval before it takes an action such as running a shell command. In a multiplayer channel, CoCo doesn’t ask, because a channel has no single person to approve the action. The bound role, and the RSS if you specify one, are the only limits on what a request can do.
A bound channel answers with CoCo by default. To answer with one of your Snowflake Intelligence (CoWork) agents instead, including that agent’s own tools such as Cortex Analyst, set up the channel as described in set up a CoWork channel.
You can bind specific channels, and you can also set a workspace-wide default binding. The default binding applies to every channel in the Slack workspace that doesn’t have a binding of its own. Because a binding gives everyone in the channel access to Snowflake, review security considerations for multiplayer channels before you bind one.
Important
When you use this integration, you are directing Snowflake to send or receive data between the Snowflake Service and Slack. Snowflake is not responsible for the privacy, security, or integrity of data once it leaves the Snowflake Service boundary. Your use of Slack, and any data you process with it, is governed solely by the terms between you and Slack.
AI-generated content
AI can make mistakes. CoCo is powered by large language models (LLMs). AI-generated responses (including text, SQL, tables, charts, and generated reports) may be inaccurate, incomplete, inappropriate, or biased. Review and verify outputs before relying on them, and apply human oversight to any decisions based on them.
For more information, see the Legal notices at the bottom of this page.
Stop CoCo from following a thread¶
After the initial mention, CoCo keeps following the thread so that channel members can send follow-ups without
mentioning the app. To stop CoCo from following a thread, reply in that thread with @Snowflake STOP. CoCo unsubscribes
from the thread and stops responding to follow-up messages in it.
Privilege model¶
The following table summarizes what each type of user can do with multiplayer channels. For the privileges that a binding requires, see required privileges for multiplayer channels.
| Who | Can do |
|---|---|
| Administrator (a role that can create agents, roles, and users) | Create the agent object, the RSS, the role, and the service user that a binding uses. |
Binding administrator (a role with | Bind and unbind channels. To list all bindings, the role must have
|
| Channel member |
|
Set up the agent and service user¶
Before you start, install the app from Snowsight as ACCOUNTADMIN. That installation creates the SNOWFLAKE_SLACK_APP
integration and makes ACCOUNTADMIN its owner. For instructions, see
install Cortex Agents for Slack.
The following statements create the database, schema, and other objects that a bound channel uses on an account where
they don’t already exist. Run them as ACCOUNTADMIN. If you use an existing database or schema, omit its CREATE
statement. PUBLIC and ALL can’t be the bound role.
-
Create the database, schema, and stage that hold the agent, and a warehouse for the service user:
-
Create the role and the service user. Grant the role to the user, then grant the role the warehouse, the database and schema, the skill stage, the Slack integration, and the Cortex user database role:
data readin the RSS does not grant access to tables. GrantSLACK_SVC_ROLEUSAGEon each database and schema it should query, andSELECTon the tables. To make a bound-channel agent discover an MCP server, grantUSAGEon that server directly toSLACK_SVC_ROLE; a grant only toPUBLICdoes not makeSHOW TERSE EXTERNAL MCP SERVERS IN ACCOUNTreturn the server. -
Grant
IMPERSONATEon the service user toACCOUNTADMIN. That role is both the caller of the bind and the owner of the integration, and both must holdIMPERSONATE: -
Create the agent. Give it a display name so channel members can recognize it. Upload the
sql-authorskill file toCORTEX_CODE.CONFIG.COCO_SKILLSbefore the first request in the channel. Tag mode readsmodels.orchestration,instructions.system, and each skill as a{name, source}object: -
Optional: Create an RSS to limit what the agent can do in the channel.
data readcovers reading data andUSAGEon databases, schemas, and workspace read.program usagecoversUSAGEon the agent.compute usagecovers the warehouse. Those groups don’t cover creating a workspace or writing to one. AllowCREATE SCHEMAon the service user’s personal database,CREATE WORKSPACEon the schemas in that database, andREADandWRITEon the workspaces there. An isolated channel creates schemaUSER$.SLACK_TAGand a workspace in it. A shared channel usesUSER$.PUBLIC.DEFAULT$. Naming one existing workspace doesn’t cover a workspace the channel still has to create. Do not putUSAGEon the Slack integration in the RSS. An RSS rejects that privilege. The integration grant in step 2 is the grant the bound role needs.CREATEandOWNERSHIPon a personal database can’t be granted to an account role. The service user creates objects in its own personal database. The RSS still has to allow those privileges, because a session can use only the intersection of the role and the RSS.For more information, see restricted session scopes.
Configure channel behavior¶
The bound agent’s specification controls how a multiplayer channel runs. Put the keys in this section under slack.
The same keys under experimental.slack still apply. When both sections set one key, the value under slack is the
one that applies. A thread keeps the settings it started with, so a change applies only to threads that start
afterward. To change a specification, follow
change the agent specification.
| Key | Default when unset | What it does |
|---|---|---|
autoStartOnAnyMessage | Off | A top-level message starts a run with no |
tagThreadFollowUps | On | A plain reply in a thread the app already joined continues that run.
Set this to |
mountWorkspace | On | Mount the service user’s workspace at /workspace. |
isolateWorkspace | On for a DEFAULT binding, off otherwise | Give the channel its own workspace under |
tagMemory | On when the workspace is mounted and isolated. Off when the workspace is shared. | Keep markdown notes for the channel under
|
tagRunMode | snowflake-coco |
|
The channel also reads these keys from the rest of the specification.
| Key | What it does |
|---|---|
models.orchestration | Model for the run. CoWork can use auto. |
instructions |
|
experimental.thinking_effort | Reasoning effort for the run: |
experimental.github_mounts | Repositories to clone before the run. |
experimental.sandbox_hooks.pre_run | Bash that runs after those clones, before the run. A failing script stops the run. The hook times out after 300 seconds. |
This specification auto-replies to every top-level message, gives the channel its own workspace, and clones two repositories before the run:
Bind a channel¶
To bind a channel, invite the app and create the binding. The app must be a member of the channel to receive its messages and post replies.
-
In the Slack channel, invite the app. For example, send
/invite @Snowflake. -
Using a role with
OPERATEorOWNERSHIPon the Slack integration for a specific channel, callSYSTEM$SLACK_CHANNEL_BIND. To bind'DEFAULT', use a role withOWNERSHIPon the integration:
After you bind the channel and invite the app, any member of the channel can @mention the app. A new top-level
message must mention the app, unless the agent sets autoStartOnAnyMessage. Follow-up messages in an existing agent
thread do not need another mention, unless the agent sets tagThreadFollowUps to false.
The function takes positional arguments, in the following order. It doesn’t accept named arguments
(name => value). To omit the optional arguments, leave them off the end of the argument list. To specify an RSS, you
must also specify the agent object.
| Position | Argument | Description |
|---|---|---|
| 1 | Integration | Required. Name of the Slack integration. |
| 2 | Channel ID | Required. ID of the Slack channel to bind. To set the workspace-wide
default binding, specify |
| 3 | Service user | Required. Name of the service user to bind to the channel. |
| 4 | Role | Required. Name of a role other than |
| 5 | Agent object | Optional. Fully qualified name of the CoCo or CoWork agent object to use. |
| 6 | RSS | Optional. Fully qualified name of the RSS to use. |
Set up a CoWork channel¶
A CoWork channel is a bound channel that answers an @mention with one of your Snowflake Intelligence (CoWork)
agents, including that agent’s own tools, such as Cortex Analyst. A channel that isn’t set up this way answers with
CoCo. As in any multiplayer channel, every request runs as the one bound service user and role, whoever sends it.
A channel runs CoWork only when both of the following are true:
- The bound agent’s specification sets
tagRunModetosnowflake-coworkunderslackorexperimental.slack. The bare valuecoworkisn’t recognized. See configure channel behavior. - The binding names the agent object and no RSS. A binding that specifies an RSS always runs CoCo.
To set up the channel, create the service user, role, and warehouse as described in set up the agent and service user. The stage for CoCo skills isn’t needed. Then grant the role access to the data, create the agent, and bind the channel:
-
Grant the role only what the channel needs, because everyone in the channel gets it:
If a semantic view would expose personal data, such as names, email addresses, or phone numbers, leave those columns out of it.
-
Create the agent with its tools and turn on CoWork mode:
The bound role also needs
USAGEon the agent’s database and schema. -
Invite the app to the channel, then bind the channel with the agent object and no RSS:
To confirm the binding names an agent and no RSS, call
SYSTEM$SHOW_SLACK_CHANNEL_BINDS. -
@mentionthe app in a new top-level message. The reply comes fromSnowflake - CoWork, and follow-up messages in that thread don’t need another mention.
A thread keeps the mode it started in, so a change to the agent or the binding applies only to threads that start afterward.
Change the agent specification¶
SET SPECIFICATION replaces the whole specification, so start from the current one in the agent_spec column of
DESCRIBE AGENT, then add a version, set the new specification, commit, and make the new version the default:
COMMIT prints the new version, such as VERSION$3. DESCRIBE AGENT shows the default version’s specification, so if
a change doesn’t appear, the new version probably isn’t the default yet.
Troubleshoot a CoWork channel¶
| Symptom | What to check |
|---|---|
The reply comes from Snowflake - CoCo | The binding names no agent or specifies an RSS, |
A failure notice follows the @mention | The bound role is missing |
| The agent answers without data | The agent has no tool for the question, or the bound role can’t read the objects that the tool uses. |
| No reply at all | The channel isn’t bound, or the app isn’t a member of the channel. |
Remove a channel binding¶
To remove a binding, call SYSTEM$DELETE_SLACK_CHANNEL_BIND with the integration name and the channel ID, in that
order. A role with OPERATE or OWNERSHIP on the Slack integration can remove a specific channel binding. Only a role
with OWNERSHIP can remove the workspace-wide default binding; specify 'DEFAULT' as the channel ID:
Required privileges¶
The following table lists the privileges that the integration owner, the binding creator, and the bound service user
need. The binding creator is the role that calls SYSTEM$SLACK_CHANNEL_BIND. Bind time is when the binding is
created, and run time is when the app handles a request in the bound channel.
| Object | Integration owner role | Binding creator role | Bound role or service user |
|---|---|---|---|
| Slack integration | Not applicable |
|
|
| Bound service user | IMPERSONATE (bind time and run time) | IMPERSONATE (bind time) | The bound role must be granted to the service user. |
| Agent object | None | None |
|
| RSS | None | None |
|
Security considerations¶
A binding replaces per-user identity with one shared identity, so review the following before you bind a multiplayer channel:
- Channel membership grants the bound service user. Anyone who can post in a bound channel can run requests as that
user, with the bound role’s privileges. Snowflake doesn’t check Slack channel membership, and Slack doesn’t show that
a channel is bound, so call
SYSTEM$SHOW_SLACK_CHANNEL_BINDSto see which channels are. The approval prompts that CoCo shows in a direct message don’t apply, because a channel has no single person to approve them, so the bound role is the only limit on what a request can do. Grant that role only the privileges the channel needs, and use a restricted session scope to narrow it further. - Conversation history follows the identity, not the channel. CoCo can search and summarize its own earlier
conversations, and those conversations belong to the Snowflake identity that ran them rather than to the channel they
took place in. Whenever two channels share a service user, whether you bound each one separately or they both fall
under a
'DEFAULT'binding, a member of either channel can ask the app about work done in the other one, including a private channel that they don’t belong to. An RSS doesn’t narrow this, because recall reads the agent’s own conversation store rather than data that an RSS governs. Don’t reuse one service user across channels of different sensitivity: bind a separate one to each set of channels that must stay separate. - The
'DEFAULT'binding covers channels you can’t see. It applies to every channel in the workspace that has no binding of its own, including channels created after you set it and channels that you aren’t a member of. Anyone who can add the app to one of them can then run requests as the bound service user, without being a Snowflake user in your account. A direct message with the app is never covered and keeps the per-user flow. A group direct message is covered, although the app declines to answer an@mentionin one. Bind individual channels instead if that is wider than you intend.
Limitations¶
During the preview, multiplayer channels have the following limitations:
- One Snowflake account per Slack workspace. A Slack workspace can connect to only one Snowflake account, so every binding in a workspace uses the same Snowflake account.
Support and privacy¶
- Support: Snowflake Support
- Privacy policy: Snowflake Privacy Policy
For questions about this integration, contact your Snowflake account team or Snowflake Support.
Related documentation¶
Legal notices¶
Where your configuration of Cortex Code uses a model provided on the Model and Service Pass-Through Terms, your use of that model is further subject to the terms for that model on that page.
The data classification of inputs and outputs are as set forth in the following table.
| Input data classification | Output data classification | Designation |
|---|---|---|
| Usage Data | Customer Data | Covered AI Features [1] |
For additional information, refer to Snowflake AI and ML.