Back to Blog
Guide

assistant.threads.setStatus vs agents.sessions.setStatus: Both Tested in Slack

We called assistant.threads.setStatus and agents.sessions.setStatus on a test app before and after turning on the agent feature, clicked the stop button, and timed how long the status line stays. Every response, the stop event, and what Slack showed.

Slack Green Team
October 2, 2026
October 2, 2026
4 min read
Share:
slack api
developers
ai
agents

assistant.threads.setStatus puts an "(app name) is working..." line under a thread in Slack while your bot prepares a reply. Slack now recommends agents.sessions.setStatus instead, which tracks a session with four states (active, processing, suspended, closed), shows a stop button, and gives the thread a title. On 2 October 2026 we tested both with a bot token in our own test workspace, on one app before and after we added the agent_view feature to its manifest. The old method worked on a plain app; the new one returned not_authorized until the feature was on.

On a plain app: only the old method works

Our app had a bot user, the messages tab and the chat:write and assistant:write scopes, but no agent feature. We sent it a DM, then called both methods on that message:

CallResponse
assistant.threads.setStatus with status: "is reading the notes..."{"ok": true}
agents.sessions.setStatus with status: "processing"{"ok": false, "error": "not_authorized"}

Slack showed the line under the user's message, but not with our text. It read "sglabw2 is working...":

Slack web DM: the user's message

Slack's reference says the status disappears after two minutes if the app sends no message. In our test it was still there at 290 seconds and gone at 305 seconds, checked every 15 seconds in an open Slack web tab. Do not count on the line clearing itself; clear it with an empty status or by replying.

Turn on the agent feature

We added this to the app manifest with apps.manifest.update and subscribed to the agent_session_stopped bot event:

"features": {
  "agent_view": {"agent_description": "Throwaway test agent for status tests"}
}

The app's DM header then labelled it AGENT instead of APP. A run on 1 October with assistant_view instead of agent_view got the same label, plus a banner on the app's settings page: "The agentic app experience is changing. You'll need to update your app to the new experience."

The agent session lifecycle

This is the script we ran with slack_sdk 3.x, against a new DM message from the user:

import os, time
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError

bot = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
DM, THREAD = os.environ["DM_ID"], os.environ["THREAD_TS"]   # the user's message in the app DM

def call(label, method, **kw):
    try:
        r = bot.api_call(method, json=kw).data
        print(f"{label:30} ok  status={r.get('status')} title={r.get('title')!r} warning={r.get('warning')}")
    except SlackApiError as e:
        d = e.response.data
        print(f"{label:30} {d['error']} {d.get('response_metadata', {}).get('messages', '')}")

session = {"channel_id": DM, "thread_ts": THREAD}
call("processing + title", "agents.sessions.setStatus", **session, status="processing", title="Release notes")
time.sleep(5)
call("rename", "agents.sessions.rename", **session, title="Release notes, 4.53 changes")
call("processing, new title", "agents.sessions.setStatus", **session, status="processing", title="Ignored")
call("suspended", "agents.sessions.setStatus", **session, status="suspended")
call("active", "agents.sessions.setStatus", **session, status="active")
call("closed", "agents.sessions.setStatus", **session, status="closed")
call("status=thinking", "agents.sessions.setStatus", **session, status="thinking")
call("no thread_ts", "agents.sessions.setStatus", channel_id=DM, status="processing")

Output:

processing + title             ok  status=processing title='Release notes' warning=None
rename                         ok  status=None title='Release notes, 4.53 changes' warning=None
processing, new title          ok  status=processing title='Release notes, 4.53 changes' warning=None
suspended                      ok  status=suspended title='Release notes, 4.53 changes' warning=None
active                         ok  status=active title='Release notes, 4.53 changes' warning=None
closed                         ok  status=closed title='Release notes, 4.53 changes' warning=None
status=thinking                invalid_arguments ['[ERROR] must be a valid enum value [json-pointer:/status]']
no thread_ts                   thread_ts_required

title only counts when the session is created. Our second processing call passed a new title and the response kept the old one; agents.sessions.rename is the way to change it. Slack showed the title as the header of the thread panel, which it opened for the user on its own:

Slack thread panel titled

What each status looked like in Slack web:

statusUnder the user's message
processing"sglabw2 is working...", plus a stop button on hover
suspendedNothing
activeNothing
closedNothing

A processing session showed its line for as long as we watched: 6 minutes 24 seconds with no reply from the app. It also survived a page reload. Unlike the old method, it does not clear itself, so set active or closed when your agent finishes or fails.

Never appear "away" on Slack again

Cloud-based. No downloads. Works 24/7 even when your laptop is off.

The stop button and agent_session_stopped

Because the app subscribed to agent_session_stopped, hovering over the status showed a stop button:

Slack thread panel: the status line replaced on hover by a round stop icon and the text

When we clicked it, our Socket Mode listener got this event:

{
  "type": "agent_session_stopped",
  "channel": "D0C673PTGJE",
  "user": "U0B7L4YK420",
  "streaming_message_ts": [],
  "thread_ts": "1790926995.881459",
  "event_ts": "1790927010.765847"
}

Slack then showed "Stopping sglabw2..." and left it there:

The same thread panel after the click:

33 seconds later it still read "Stopping". Only when our app called agents.sessions.setStatus with active did the line go away. Clicking stop does not end the session; your handler has to stop the work and set the status. In the 1 October run, without the event subscription, the same processing call returned ok with the warning missing_agent_session_stopped_event_subscription and no stop button appeared.

The old method on an agent app

On the same app with agent_view, assistant.threads.setStatus still returned ok. It opened the thread panel (titled "Thread", since there was no session title) and showed "sglabw2 is working..." again, without our custom text. A call with loading_messages: ["Reading release notes", "Comparing versions"] also returned ok, but neither string appeared in 26 seconds of checks; the 1 October run on assistant_view showed its first loading message a few seconds after the call. There was no stop button, because no session existed.

Errors we got

CallResponse
status: "thinking"invalid_arguments: must be a valid enum value [json-pointer:/status]
No thread_ts, in a DM or a public channelthread_ts_required
A user token, for either methodnot_allowed_token_type
agents.sessions.rename with title: ""invalid_arguments: must be more than 0 characters
agents.sessions.rename with 201 charactersinvalid_arguments: must be less than 201 characters
agents.sessions.rename on a thread that has no sessionnot_authorized
agents.sessions.setStatus on a made-up thread_tsok, and a session was created

The last row means the API does not check that the thread exists. Use the ts from the event that started the work.

Our listener setup is in the Socket Mode guide. For the Slackbot side of Slack's AI features, see Slackbot as an MCP client.

FAQ

Do I need the assistant:write scope? Not for the new method. Slack's reference lists chat:write for agents.sessions.setStatus, and assistant.threads.setStatus accepts either assistant:write or chat:write for now. Our app had both.

Can a user token set the status? No. Both methods returned not_allowed_token_type with our user token.

Always Active

Stop Jiggling Your Mouse.

Join hundreds of remote workers who never worry about their Slack status. Set it up once, stay green forever.

Related Articles

Guide

Slack Slash Command Payload: Every Field, Responses, and response_url Limits

We caught the payload a slash command sends, answered it as ephemeral, in_channel, plain text and empty, posted to its response_url until it failed, and typed the command inside a thread. Every result is from a test app on 2 October 2026.

Slack Green Team
Guide

Slackbot MCP Client: We Connected a 17-Line MCP Server and Slackbot Called It

We wrote a one-tool MCP server, added it to a Slack app with the mcp_servers manifest field, switched it on in Slackbot and asked for the time. Every request Slackbot sent to the server, the permission prompt, and what Slackbot said when the server was down.

Slack Green Team
Guide

Slack Image Block: Formats, Size Limits and Errors We Measured

We posted image blocks pointing at our own server with PNG, JPG, GIF, WebP and SVG files, a 404, a redirect, slow responses and files from 2 MB to 42 MB, then used slack_file uploads. What rendered, what failed with downloading image failed, and where the 20 MB line sits.

Slack Green Team