Connect a Slack bot to Linear

Verified August 26, 2026

This gives a Slack bot access to Linear. Ask it a question in a channel and it will read and file issues in your Linear workspace and answer in the thread.

What you need

  • A Slack workspace where you can install apps
  • A Linear account
  • An OpenRouter account

Install the CLI

npm i -g @substructure.ai/cli

Write the config

Save this as subs.toml.

subs.toml
name = "planner-bot"

[llm.openrouter]
type = "openrouter"

[mcp.linear]
url = "https://mcp.linear.app/mcp"

[agent.planner]
llm = "openrouter"
model = "z-ai/glm-5.2"
system = "You are the planning assistant. Answer questions about Linear issues and file them when asked."
mcp = ["linear"]

[agent.planner.slack]
name = "Planner"

[remote]
url = "https://api.substructure.ai"

[agent.planner] declares the agent: its model, its prompt, and the connections it can reach. The Slack bot is how you talk to it.

The file holds the server URL and the agent that uses it. It holds no tokens.

[remote] is the deployment the CLI talks to. subs apply writes the org and the project back under it.

Create the project

subs apply

This creates the project from the file and writes the project id back into it. If you are not signed in yet, the command opens your browser first. Run subs apply again after any edit to the file.

Add your LLM key

subs auth llm.openrouter

The agent's model runs through OpenRouter, so it needs an OpenRouter API key. Create one at openrouter.ai/keys if you do not have one. The command stores the key with your deployment. It never goes in the config file.

Authorize Linear

subs auth mcp.linear

This opens Linear's consent page. Approve it and the credential goes to your deployment.

Run subs list to check the connection is authorized.

Set up the Slack app

subs auth agent.planner.slack

The command prints an app manifest. Go to api.slack.com/apps, choose Create New App, then From a manifest, and paste it in. Create the app and install it to your workspace.

Slack then shows you two values. Paste them back when the command asks.

  • The Bot User OAuth Token, under OAuth & Permissions.
  • The Signing Secret, under Basic Information.

The bot is live once both are in.

Ask it something

Invite the bot to a channel and mention it.

  • "what is in this cycle?"
  • "file a bug about the login redirect"

Each tool call shows in the thread as a task card. Open a card to see the arguments and the result.

Limit the tools

An id on its own takes every tool the server offers. A model picks worse as the tool list grows. Use the table form to take fewer.

subs.toml
[agent.planner]
mcp = [{ id = "linear", tools = { read_only = true } }]

If it does not answer

  • Connection not authorized. Run subs list. A declared connection with no credential reaches nothing.
  • The Slack app has no values yet. Run subs list. An app with nothing set never replies.
  • Bot not invited. Invite it to the channel before you mention it.
  • Tools missing. The engine fetches the tool list once per session. Start a new thread after you change the filter.
  • Anything else. Run subs doctor.

Add another server

Declare it and name it on the agent.

subs.toml
[mcp.linear]
url = "https://mcp.linear.app/mcp"

[mcp.linear]
url = "https://mcp.linear.app/mcp"

[agent.planner]
mcp = ["linear", "linear"]

Tools arrive prefixed with the connection id, such as linear__search.

The same setup works for Sentry, GitHub, Notion, Stripe, and each has its own guide. See all guides.

Next steps