Connect Slack, Linear and Claude
Replace the fakes with a real Slack app, a Linear workspace and the Claude Code harness.
This guide moves the example organisation from the fakes to a real Slack workspace, a real Linear team and the Claude Code harness backed by an Anthropic model. The deployment workflow stays the same. Only the credentials and a few variables change.
What you need
| Item | Who provides it | Used for |
|---|---|---|
| A Slack workspace where you can install apps | Slack workspace admin | Human ↔ representative conversations |
| A Linear workspace and team, plus an API key with write access | Linear admin | Projects and tasks created by agents |
| An Anthropic API key | Your Anthropic account | Model inference for the Claude Code harness |
The Slack member IDs (U…) of at least two people | Each person: Slack profile → ⋮ → Copy member ID | Channel bindings |
1. Create the Slack app
Go to api.slack.com/apps, choose Create New App → From a manifest, select your workspace and paste slack-app-manifest.yaml. The manifest enables Socket Mode, the App Home messages tab, the bot scopes
chat:write,im:history,im:read,im:writeandusers:read, and themessage.imevent.Under Basic Information → App-Level Tokens, create a token with the
connections:writescope. This is yourxapp-…token.Under Install App, install the app to the workspace and copy the Bot User OAuth Token (
xoxb-…).Note the workspace's team ID (
T…). It appears in the workspace URL, or in theauth.testresponse.
Socket Mode means Slack never has to reach your cluster: the platform opens an outbound websocket. One app installation serves every representative.
2. Prepare Linear
Create an API key under Settings → Security & access → Personal API keys (or a workspace key) with write access, and find the ID of the team agents should work in. Start with a dedicated team, because agents with project.create really do create projects.
3. Provide the credentials
Credentials go into the foundation stage only. It stores them as Kubernetes Secrets in steadmesh-system, where only the platform service can read them. The organisation stage refers to them by name, for example k8s:slack-credentials, so they never appear in its plans or state.
export TF_VAR_slack_bot_token=xoxb-…
export TF_VAR_slack_app_token=xapp-…
export TF_VAR_linear_api_key=lin_api_…
export TF_VAR_model_api_keys='{anthropic="sk-ant-…"}' # one per model endpoint, e.g. openai, selfhosted
The Kubernetes provider stores Secret values in the foundation stage's Terraform state, so protect that state. Alternatively, create the Secrets slack-credentials (keys bot_token, app_token), linear-credentials (api_key) and one <key>-credentials per model endpoint, such as anthropic-credentials (api_key), out of band, and leave the placeholder defaults. Vault is also supported: set secret_ref = "vault:<path>" and enable Vault in the chart values.
4. Configure the organisation
unset TF_VAR_slack_endpoint_ref TF_VAR_linear_endpoint_ref # use the real services
export TF_VAR_harness=claude-code
export TF_VAR_model='{connection="anthropic",id="claude-sonnet-5-5"}'
export TF_VAR_slack_workspace_id=T0123ABCD
export TF_VAR_linear_team_id=<team id>
export TF_VAR_humans='{sean={slack_user_id="U0SEAN123"},alex={slack_user_id="U0ALEX456"}}'
harness = "claude-code" switches every seat to the Claude Code image, and model selects the model and the connection that serves it (declared from model_connections). Each seat is implicitly allowed model.infer on that connection, for that model only. To give seats different harnesses, set seat_harnesses, for example { engineer = { adapter = "codex", model = { connection = "openai", id = "gpt-5.5" } } }; see Harnesses and models.
5. Apply
make kind-up kind-load provider build
make -C examples apply
Readiness now checks the real services:
- Slack
auth.testpasses, and the team matchesaccount_id. users.infosucceeds for every bound human.- The Socket Mode connection is up.
- The Linear
viewerquery succeeds. - A one-token request for the selected model succeeds at Anthropic, and each seat passes a probe turn that calls a platform tool.
If anything is missing, the apply stops and names it, for example:
OperationalReady False ConnectionsAuthenticated connection slack: unauthorized: invalid_auth
6. Talk to your representative
In Slack, open the app (Apps → Steadmesh) and send it a direct message. Your representative replies in the same DM. Try asking it to remember a preference, delegate something to engineering, or create a Linear project for a small task.
How the Claude Code harness runs
- One process per turn. Each delivered message runs one
claude -pprocess that resumes the seat's session. The session files live on the seat's persistent volume, so the conversation continues across restarts. - Tools. Platform tools are exposed over MCP by
steadmesh-tools mcp(they appear asmcp__steadmesh__memory_searchand so on). Built-in tools default to Bash, Edit and Read in the seat's workspace. - Model access. Requests go through a local forwarder to the platform's model proxy. The seat authenticates with its own rotating identity token, and the platform swaps it for the real Anthropic key. The API key never enters the sandbox, and the seat can only request its configured model.
- Unattended operation. There are no permission prompts. The sandbox (network policy, non-root, read-only image, resource limits) and the platform's grant checks are the boundary.
- Version pinning. The Claude Code version is pinned exactly in
build/seat-claudecode.Dockerfile. A version change is treated as a session format change: the seat resumes from a portable handoff and records that it did.
Run the live acceptance test
make live automates this guide. It needs the variables above plus user tokens for two test humans, so it can message the bot as them. See tests/live/README.md for the exact list. Use test accounts and a dedicated Linear team.