Channels

Reach it where people already work.

Connect Slack to a project and a message in a thread starts a session. The agent picks up its own cloud computer, does the work, and answers in the same thread. Nobody has to open a new tool to ask for something.

Slack today · Teams, email and voice behind a switch

Live today
Slack
A thread is
Exactly one session
The reply lands
In the same thread
Approve or deny
On a card, in the thread
The surfaces

One is live. Three are behind a switch. We will say which.

A channel is a chat platform bound to a project — a closed set of four, not an open field. Here is the real state of each one, including the parts a marketing page usually leaves out.

  • SlackLive

    On by default, no flag. Connect from the dashboard or the CLI, invite the bot to a channel, and mention it. Everything else on this page describes Slack.

  • Microsoft TeamsOperator switch

    Code complete and off by default. Your deployment turns it on and supplies Microsoft app credentials; a tenant admin then consents once. Same sessions, same identity rules as Slack.

  • EmailExperimental

    A project inbox, so a message to an address starts a session and a reply continues it. Opt in per project under Customize → Settings → Experimental. Real, and not finished.

  • VoiceExperimental

    A realtime call the agent speaks in. Same per-project opt-in. It spawns a room and shares the link — it does not dial into a meeting you already started.

What is not a channel

Telegram, WhatsApp, SMS and Discord are not channels, and this page will not imply they are on a roadmap it cannot promise. There is also no build-your-own-channel API — the platform list is a closed enum. What there is instead is a signed webhook trigger, and we would rather tell you its limits than sell you the word "extensible".

The honest alternative →
Thread to session

A thread is a session. One, and only one.

The first message in a thread creates a session. Every later message in that thread reaches the same session — after the sandbox stops overnight, after the person who started it goes home. That mapping is a unique index in the database, not a convention two services agree to honour.

#acme-launch
  • Dana@kortix draft the Q3 launch note from the changelog and put it in the repo
  • kortixReading the changelog since v0.9. Drafting launch-note.md on this session’s branch.
  • kortixlaunch-note.md
session9f4c2b7ecloud computer booted · branch cut · agent running

Open a change request against main?

launch-note.md · +64 −0

ApproveAsk for changesDeny
Illustration. Acme is a placeholder, not a customer.
  1. 00

    Someone mentions the bot

    In a channel it has been invited to, or in a direct message. A bare mention with no task gets a reminder to add one, rather than a session nobody asked for.

  2. 01

    A session starts

    Kortix cuts a branch and boots its own isolated cloud computer, exactly as it would for a session started from the dashboard or the CLI. You get a reaction on your own message, not a bot post saying “on it”.

  3. 02

    The agent works

    It has a shell, a filesystem, the network, and whichever connectors and secrets its agent block grants it. The thread is where you watch. The machine is where the work happens.

  4. 03

    It answers in the thread

    The reply streams into the message it started, in the thread the question was asked in. Two people can watch. Neither had to open anything.

Two events for the same brand-new thread arriving at once do not produce two sessions: the second joins the first and is delivered as a follow-up. One Slack workspace bound to more than one project shows a project picker on the first mention instead of guessing.

Connect it

Install it, invite it, mention it.

On a host with the shared Slack app configured, kortix channels connect prints an install link and you are three clicks from done. On a deployment with no shared app, the same command falls back to manual mode by itself and hands you an app manifest to paste.

kortix channels
# managed: an install link, then pick the workspace$ kortix channels connect --wait→ connected: slack workspace acme-hq # self-hosting? the same command falls back to manual$ kortix channels manifest > slack-app.json$ kortix channels connect --manual \    --bot-token xoxb-... --signing-secret ... # check it, or take it away$ kortix channels status$ kortix channels disconnect
  • Installing is not the last step: invite the bot to a channel and mention it. Nothing happens in a channel it has not been invited to.
  • Connecting writes a channel connector into kortix.yaml for you. You never hand-write that entry.
  • The dashboard uses the same install flow as the CLI. Neither one is the real one.
The round trip

What comes back is the work, not a transcript.

A channel is only worth connecting if the answer arrives where the question was asked. Files go both directions, and the decisions an agent needs from you are buttons in the thread rather than a link to somewhere else.

The answer, streamed

The reply lands in the thread as one message that fills in, not a wall of updates. The agent finalises that message rather than posting a second one underneath it.

Files, both directions

A file dropped in the thread is pulled into the agent’s cloud computer. A file the agent produces is uploaded back into the same thread. The deck lands where you asked for the deck.

Approve, deny, ask for changes

When the agent needs a decision, it posts a card with buttons instead of blocking a turn forever. Your click is the verdict, and the session resumes from it in the same thread.

One honest limit: the card carries the decision and a link back into Kortix. Reading the actual diff of a change request happens in the web app, where a diff belongs — Slack is not a code review tool and we are not going to pretend it is.

From the thread

Run the project without leaving the conversation.

Type these as /kortix <command> in Slack, or as plain text in a direct message. Most of what you would otherwise open the dashboard for is one line in the channel.

login, logout
Link or unlink your chat identity to your Kortix account
switch, unbind
Rebind this channel to a different project, or unbind it
projects
List the projects you can bind this channel to
sessions
List the recent sessions started from this workspace
agent <name>, model <id>
Set the agent and the model this channel uses
policy <mode>
Set who may start a session here
whoami
Show the panel: project, agent, model, policy, linked identity

Three answers to “who may start a session here”

project_open
The default. Any project member who mentions the bot gets a session.
owner_approval
A session starts only once the channel owner approves the request.
owner_only
Only the owner. Everyone else gets nothing, predictably.
Same rules

A chat surface is not a side door.

A message in Slack gets no privileges a session in the dashboard would not get. The surface changes. Nothing underneath it does.

Every sender is a known person
Kortix links a chat sender to a Kortix account before the agent runs for them. Run /kortix login and sign in. An unlinked sender gets a prompt to link, not a session — so a stranger in a shared channel cannot spend your compute.
The bot token never enters a sandbox
A connected channel’s token is a connector-scoped secret. It does not appear on the project’s Secrets page, and Kortix never injects it into a cloud computer. It is resolved server-side at the moment the agent sends a message.
It runs as an agent you chose
A channel names its agent and model, and inherits that agent’s deny-by-default reach into connectors, secrets and skills. Change either with one line in the thread.
Nothing merges itself
The agent answers in the thread. Work it means to keep is committed on the session’s own branch and reaches main only through a change request a person reviews.
Everything else

No channel for your platform? Here is the honest path.

There is no build-your-own-channel API — the platform list is a closed enum and we will not dress a gap up as a plug-in system. What ships is a signed webhook trigger that starts a session per conversation. It solves the inbound half well, and we will tell you exactly what it does not do.

kortix.yaml
# any conversational source, without channel-specific codetriggers:  - slug: support-inbox    type: webhook    agent: support    secret_env: WEBHOOK_SECRET     # one session per conversation, not one per message    session_mode: keyed    session_key: "{{ body.data.conversation_id }}"     # ignore the agent’s own outbound messages    filter:      "body.data.direction": "inbound"     prompt: "{{ body.data.text }}"

What you get

One session per conversation. session_key renders from the payload, so a single trigger fans out into a session per chat, per customer, or per repository — separate threads rather than one blended transcript.

And a loop breaker

A source that reports both sides of a conversation would otherwise fire the agent on its own reply. filter drops those deliveries with a 200 and no session. Signed with HMAC-SHA256, like every Kortix webhook.

What you do not get

No reply relay. A real channel streams the answer back for you; here the agent has to send the outbound message itself, through a connector you have granted it. Inbound is solved. Outbound is your wiring.

See how triggers work
Connect it

Put it in the thread people already use.

Open source and self-hostable. Any model, your keys. Kortix Cloud, your own VPC, or fully on-prem.

Kortix Channels | Kortix