Slack Bot v0.46.0
Drive Tracker from Slack. Mention @trackerbot make me an app that… and it starts a pipeline in a thread, streams notifications and clarifying questions to that thread, and delivers the result — arbitrarily many runs at once, each isolated. This page takes you from zero to your first run.
What it looks like
One mention starts a run. The thread becomes the run’s home: the ack, any human gates (rendered as buttons or a reply), progress notifications, and the final deliverable all land there. Here is a full conversation, start to finish.
Ask & Execute — I’ll keep you posted here.Budget: up to $5.00.
📦 Artifacts:
~/runs/1721574_042/Mention me again to iterate.
The live status card is one message that updates in place as the run happens, so the thread
stays a single dashboard instead of a wall of per-step posts. A freeform gate instead asks you to reply in
the thread (βοΈ <question>); an interview asks one question at a time.
Prerequisites
A Slack workspace
Where you can install a custom app — you’ll need permission to create apps and add them to a channel.
Go 1.24+
To build the trackerbot binary from source (go build ./cmd/trackerbot). It ships in the same repo as tracker.
A provider key (optional)
An ANTHROPIC_API_KEY (or other provider) enables natural-language intent and native agent runs. Without one, the bot still works with the explicit run <workflow> grammar and the claude-code backend.
Create the Slack app
trackerbot connects over Socket Mode — an outbound WebSocket — so you need no public URL, ingress, or request-URL verification. Two tokens do it: an app-level token for the socket and a bot token for posting.
Create the app
Go to api.slack.com/apps → Create New App → From scratch. Name it and pick your workspace.
Enable Socket Mode
Settings → Socket Mode → toggle on. When prompted, generate an App-Level Token with the
connections:writescope — this is yourxapp-…token. Copy it.Add bot token scopes
Features → OAuth & Permissions → Bot Token Scopes. Add all four:
Scope Why app_mentions:readsee @trackerbotmentionschat:writepost acks, gates, notifications, results channels:historyread thread replies (freeform gates) in public channels groups:historysame, for private channels Subscribe to events
Features → Event Subscriptions → toggle on (Socket Mode needs no request URL). Under Subscribe to bot events, add:
app_mention,message.channels,message.groups.Turn on interactivity
Features → Interactivity & Shortcuts → toggle on. This lets gate buttons send their clicks back over the socket. No request URL needed.
Install & grab the bot token
Install App → install to the workspace. Copy the Bot User OAuth Token (
xoxb-…).Invite the bot to a channel
In Slack:
/invite @yourbot. It only sees channels it’s a member of.
You now have two secrets: SLACK_APP_TOKEN (xapp-) and SLACK_BOT_TOKEN (xoxb-).
Install & run
Build the binary, export the two tokens (plus a provider key), and start it. The bot logs a line when the socket connects.
# build from the repo root go build -o trackerbot ./cmd/trackerbot # the two Slack secrets from the app setup export SLACK_APP_TOKEN=xapp-1-... export SLACK_BOT_TOKEN=xoxb-... # a provider key powers agent runs + natural-language intent export ANTHROPIC_API_KEY=sk-ant-... # recommended from day one β see Security & cost below export TRACKERBOT_ALLOWED_USERS=U012ABC,U034DEF # where run workdirs live (isolated per thread) export TRACKERBOT_RUNS=/var/tmp/trackerbot-runs ./trackerbot # trackerbot: connecting via Socket Mode (max 8 concurrent runs; runs under /var/tmp/trackerbot-runs)β¦
Workflows. The bot resolves a request to a workflow by name (built-ins like
ask_and_execute and build_product, or a local <name>.dip under
TRACKERBOT_WORKDIR). See the workflows catalog.
No API key? Set TRACKERBOT_BACKEND=claude-code to run via the claude
CLI’s subscription auth; intent then falls back to the run <workflow> grammar.
Talk to it
Mention the bot with a request, or use a control command. Every mention roots (or continues) a thread; the thread is the run’s identity.
| Say this | What happens |
|---|---|
@trackerbot make me a CLI that greets people | Natural-language intent picks a workflow and starts a run. |
@trackerbot run build_product | Explicit grammar — runs a named workflow. Add k=v params: run build_product spec=SPEC.md. |
@trackerbot retry | Re-run this thread’s last workflow (also again / rerun). |
@trackerbot bump <dollars> | Re-run the last workflow with a raised cost ceiling — offered after a run hits its budget. |
@trackerbot steer <guidance> | Nudge the running workflow with a note — surfaces at the next step (workflows that read steer.guidance act on it). |
@trackerbot status | This thread’s run state, with a live 5/9 steps · $1.12 · <node> progress digest. |
@trackerbot cancel | Stops this thread’s run (π cancelling this runβ¦). |
@trackerbot runs | Lists all active runs across threads. |
@trackerbot workflows | Lists the workflows you can run. |
@trackerbot help | The command menu. |
Choice / yes-no gates
Render as buttons. Click one; the run continues. A click for one thread’s gate can never resolve another’s.
Freeform gates
βοΈ <question> — just reply in the thread. Your next message in that thread is the answer.
Interview gates
A structured form asked one question at a time (buttons or reply), accumulated into a single result.
Beyond mentions: /tracker & the App Home tab
Two optional surfaces, same engine underneath. /tracker <what you want>
is a slash command that works anywhere without an @mention — the bot opens a thread and
runs there, so every in-thread command (retry, steer, gates) still applies. The
App Home tab is a standing dashboard: a how-to plus a live list of active runs.
Both need a little extra Slack app setup — register the /tracker command with the
commands scope, and enable the Home tab with the app_home_opened event. See the
trackerbot README.
Make a workflow steerable
steer injects a note under the context key steer.guidance, which lands
in the pipeline context at the next step boundary. A workflow acts on it by referencing that key
in an agent prompt — otherwise the note is a harmless unused value. For example:
Implement the requested change.
Extra guidance from the operator (may be empty): ${ctx.steer.guidance}Now @trackerbot steer prefer the smaller change mid-run reaches that agent on its
next turn. The steer.* namespace is never interpolated into shell/tool commands, so a
note can’t become code.
How it works
One process holds one outbound WebSocket and runs N concurrent pipelines, one per thread. The bot is a pure consumer of Tracker’s transport boundary — no engine changes — so it inherits panic containment, the one-terminal-event guarantee, per-run isolation, and durable resume from the core.
Two-level demux. Inbound events route by thread_ts (which run) and a
gate_id (which question — encoded in a button’s action_id or the thread’s
pending freeform gate). Outbound is automatic: each run owns a thread-bound UI, so its posts go to its own
thread with no shared state.
Configuration
Everything is an environment variable. Only the two Slack tokens are required.
| Variable | Purpose | Default |
|---|---|---|
SLACK_BOT_TOKEN | bot token (xoxb-) | required |
SLACK_APP_TOKEN | app-level token (xapp-) | required |
ANTHROPIC_API_KEY / etc. | provider keys the workflows use | — |
TRACKERBOT_WORKDIR | where run <name> finds local .dip files | . |
TRACKERBOT_RUNS | base dir for isolated per-run workdirs | $TMPDIR/trackerbot-runs |
TRACKERBOT_MAX_CONCURRENT | concurrent run cap | 8 |
TRACKERBOT_MODEL | model for natural-language intent | claude-haiku-4-5-20251001 |
TRACKERBOT_BACKEND | agent backend (native/claude-code/acp) | native |
TRACKERBOT_ALLOWED_USERS | comma-separated Slack user ids allowed to drive the bot | — (open) |
TRACKERBOT_MAX_COST_CENTS | fail-closed per-run cost ceiling; 0 disables | 500 ($5) |
TRACKERBOT_CONFIRM_OVER_CENTS | require a Run/Cancel click when the estimate is at/above this; 0 disables | 200 ($2) |
TRACKERBOT_KEEP_WORKDIRS | 1 retains finished-run workdirs (else reaped) | — (reap) |
Security & cost
The bot triggers paid, host-side execution from chat. Three controls make that safe; set the first two before you point it at a shared channel.
Authorization — who can run
Set TRACKERBOT_ALLOWED_USERS to a comma-separated list of Slack user ids. Unlisted users are refused (start and control commands both). Empty means open to everyone in the bot’s channels — the bot logs a loud warning at startup when unset.
Budget — how much it can spend
Every run carries a fail-closed cost ceiling (TRACKERBOT_MAX_COST_CENTS, default $5). The ceiling is shown in the ack; a breach halts the run. A chat-triggered run can never spend unbounded. A rough cost estimate is posted up front, and above TRACKERBOT_CONFIRM_OVER_CENTS (default $2) the bot asks for a Run / Cancel click before spending.
Source containment
Workflow names are validated before resolution, so a mention can never load an arbitrary .dip off the host (e.g. run ../../../etc/hosts is rejected).
Inherited hardening
From the core: a handler panic is contained (never crashes the process), tool subprocesses run with secrets stripped and an output cap, and the audit log is tamper-evident. See Architecture.
Durability & resume
Each thread gets a deterministic workdir + checkpoint. If the bot process restarts — a deploy, an OOM, a crash — it resumes every interrupted run from its checkpoint on startup, no run-id bookkeeping.
- Node-granular resume. A run resumes from its last completed node; a crash while a gate is waiting resumes at the gate without re-running the completed upstream work.
- Atomic writes. Checkpoints and the resume-state file are written temp-then-rename, so a crash mid-write can’t corrupt the one file whose job is recovery. A corrupt state file is preserved aside and logged — never silently dropped.
- Bounded disk. Finished-run workdirs are reaped by default (
TRACKERBOT_KEEP_WORKDIRS=1retains them for inspection), plus a startup sweep of orphans.
Troubleshooting
| Symptom | Likely cause & fix |
|---|---|
| Bot never responds to a mention | It isn’t in the channel (/invite @yourbot), or app_mention isn’t subscribed, or the socket didn’t connect (check the startup log line and the xapp- token’s connections:write scope). |
| “you’re not on the allowlist” | Your Slack user id isn’t in TRACKERBOT_ALLOWED_USERS. Find your id in Slack → profile → Copy member ID, or unset the var to open the bot. |
| Freeform reply is ignored | You must reply in the thread, not the channel; and channels:history/groups:history + message.* events must be enabled. |
| Buttons do nothing | Interactivity is off — enable Interactivity & Shortcuts. |
| “I’m at capacity right now” | The concurrent-run cap is hit. Raise TRACKERBOT_MAX_CONCURRENT or wait for a run to finish. |
| Runs fail with an auth / credit error | Provider key missing or exhausted. For subscription auth, use TRACKERBOT_BACKEND=claude-code and unset ANTHROPIC_API_KEY. |
| Diagnosing a failed run | The bot posts a Diagnose summary on failure. For depth, run tracker diagnose against the run’s workdir under TRACKERBOT_RUNS (keep it with TRACKERBOT_KEEP_WORKDIRS=1). |
Further reading
Transports
The boundary the bot plugs into, and how to build your own web/mobile transport with the conformance suite.
Workflows
The built-in pipeline catalog you can run by name from Slack.
trackerbot README
The in-repo reference: source layout, the two-level demux, and the full setup checklist.
Slack Socket Mode
Slack’s official docs for the connection model trackerbot uses.
Architecture
The engine, backends, budgets, and the audit trail behind every run.
CLI
tracker diagnose, audit, and the commands for inspecting a run.