Slack Is Where You Spend the Time You Don't Have

You're deep in code. A teammate asks a question in #engineering. You alt-tab to Slack, type a response, get distracted by three other channels, and five minutes later you're still in Slack.

Or: you're leaving a meeting and need to update your team. You open Slack, find the channel, type the update. 60 seconds for a message you could have spoken in 10.

Every context switch to Slack costs 20–30 seconds of recovery time to get back into flow. Multiply by 30 messages a day. That's 15 minutes of lost flow state — just from switching apps.

⌘2

"Found the WebSocket memory leak. Fix incoming in about 20 minutes. No need to restart prod, the leak is slow enough. ENG-847 has the details."

Release. Your message arrives in #engineering via webhook. Properly punctuated, natural tone. You never left your editor.

One hotkey per channel. Three channels, three tones, three hotkeys. 15 seconds total. Zero context switching.

How It Works: Voice → Transform → Slack Webhook

Your voice ──▶ SpeechButton STT ──▶ Transform script ──▶ Slack Webhook
  (7ms)         (Parakeet V3,        (adjusts tone,         (posts to
                 100% offline)         fixes grammar)          channel)
  1. SpeechButton captures your voice and transcribes it locally (Apple Neural Engine, 100% offline)
  2. Transform script cleans up the text — removes filler words, adjusts tone for the channel context
  3. Slack Incoming Webhook receives the formatted message and posts it to the channel

The connection between SpeechButton and Slack is a Python script that calls the Slack Incoming Webhook API. No custom app, no OAuth dance, no middleware. Just a webhook URL and a script.

Setup: 3 Steps, 5 Minutes

A Slack webhook, a config file, and prompt files for each channel tone. That's the entire integration.

Step 1: Create a Slack Incoming Webhook

Each webhook is tied to one channel. Create one per channel you want to post to.

  1. Go to https://api.slack.com/appsCreate New AppFrom scratch
  2. Name it "Voice Messages", select your workspace
  3. Click Features → Incoming Webhooks → toggle Activate Incoming Webhooks to On
  4. Click Add New Webhook to Workspace → select the channel → Allow
  5. Copy the webhook URL: https://hooks.slack.com/services/T.../B.../xxx

The webhook URL is the only credential you need. Pass it as SLACK_WEBHOOK_URL inline in the exec line — no API key required.

Step 2: Add integrations/send_slack.py

A small Python script that reads the transformed text from stdin and posts it to Slack via webhook. No external dependencies — stdlib only.

python — ~/.config/speechbutton/integrations/send_slack.py
#!/usr/bin/env python3
"""Send a message to Slack via Incoming Webhook."""
import json, os, sys, urllib.request

def main():
    text = sys.stdin.read().strip()
    if not text:
        sys.exit(0)

    url = os.environ.get("SLACK_WEBHOOK_URL")
    if not url:
        print("SLACK_WEBHOOK_URL not set", file=sys.stderr)
        sys.exit(1)

    req = urllib.request.Request(url,
        json.dumps({"text": text}).encode(),
        {"Content-Type": "application/json"})
    resp = urllib.request.urlopen(req, timeout=10)
    print(f"Slack ({resp.status}): {text[:60]}...")

if __name__ == "__main__":
    main()

Step 3: SpeechButton config.toml

One hotkey per channel. The transform field points to a prompt file — SpeechButton runs the local AI model against it. The exec field sends the result to Slack.

toml — ~/.config/speechbutton/config.toml
# ~/.config/speechbutton/config.toml

[global]
model = "parakeet-tdt-0.6b-v3-int8"

[parakeet-tdt-0.6b-v3-int8]
language = "en"

# Slack — local AI transform (recommended)
[[hotkey]]
key = "RightCommand"
channel = "5"
name = "slack"
transform = "prompts/slack_message.md"
exec = "SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../xxx integrations/send_slack.py"

Two options for the transform field

Option A — Recommended Local AI
transform = "prompts/slack_message.md"

Uses SpeechButton's built-in local model to rewrite your transcript using the prompt in the file. Free, 100% offline. Nothing leaves your Mac except the final message to Slack.

Option B Claude API
transform = "transforms/transform_claude.py prompts/slack_message.md"

Sends the transcript to Claude API for higher-quality rewrites. Requires ANTHROPIC_API_KEY. Costs ~$0.001 per message.

Start with Option A — it's free and works offline. Switch to Option B only if you need higher quality.

Step 4: Prompt files — tone per channel

Each channel gets its own prompt file in the prompts/ folder. Same voice, different audience, different output.

Casual For #engineering — concise, dev-friendly

You say:

"hey so I basically found the um the memory leak it's in the websocket handler the connection pool uh doesn't clean up on disconnect I've got a fix coming in about twenty minutes"

markdown — ~/.config/speechbutton/prompts/slack_casual.md
Clean up this spoken message for a Slack dev channel.
Keep it casual and concise. Fix grammar, remove filler
words (um, uh, like, basically), keep technical terms.
Output ONLY the cleaned message, no quotes.

Slack receives:

Found the memory leak — it's in the WebSocket handler. Connection pool doesn't clean up on disconnect. Fix coming in ~20 min.

Professional For #general — clear, structured, polished

You say:

"Quick update the launch is moving to April 15th because the onboarding isn't ready yet the pricing stays the same and Maria is running an AB test on the student discount"

markdown — ~/.config/speechbutton/prompts/slack_professional.md
Rewrite this spoken message for a professional Slack
channel. Make it clear, well-structured, and polished.
Use bullet points if there are multiple items.
Output ONLY the message.

Slack receives:

Quick update on the launch:

  • Launch date moved to April 15 (onboarding flow not ready)
  • Pricing unchanged at $7.99/mo
  • Maria is running an A/B test on the student discount
Standup For #standup — Yesterday / Today / Blockers format

You say:

"Yesterday I fixed the CSV export bug and submitted the PR. Today I'm picking up the auth middleware rewrite. No blockers so far but I might need help with the token refresh logic later."

markdown — ~/.config/speechbutton/prompts/slack_standup.md
Format this spoken standup update into three sections:
*Yesterday*, *Today*, *Blockers*. Use bullet points.
If no blockers mentioned, write "None".
Output ONLY the formatted standup.

Slack receives:

*Yesterday*

• Fixed CSV export bug, PR submitted

*Today*

• Auth middleware rewrite

*Blockers*

• None (may need help with token refresh logic later)

Real Workflows

Incident response — update without leaving the terminal

You're debugging a production incident. Every minute counts. Your team needs updates.

RCmd

"Update: identified the cause. The Redis connection pool is exhausted because the new batch job isn't releasing connections. Temporary fix: increase pool size from 50 to 200. Permanent fix: add connection timeout, PR in progress."

Your team gets a clear, structured update. You didn't leave the terminal. The debugger is still open.

Quick answers — respond without context-switching

Someone asks a question in #engineering. You know the answer.

RCmd

"The config file is at slash etc slash app slash config dot toml. The retry count is on line 42, change max retries from 3 to 5. Don't forget to restart the service after."

Slack receives: "The config file is at /etc/app/config.toml. The retry count is on line 42 — change max_retries from 3 to 5. Don't forget to restart the service after." The transform converted spoken paths and code to proper formatting. You answered in 8 seconds.

Multi-channel — same info, different audience, different prompt

Assign different channels to different hotkeys with different prompt files.

toml — multi-channel config
# Casual dev channel
[[hotkey]]
key = "RightCommand"
channel = "5"
name = "slack-eng"
transform = "prompts/slack_casual.md"
exec = "SLACK_WEBHOOK_URL=https://hooks.slack.com/...engineering integrations/send_slack.py"

# Professional general channel
[[hotkey]]
key = "RightCommand"
channel = "6"
name = "slack-general"
transform = "prompts/slack_professional.md"
exec = "SLACK_WEBHOOK_URL=https://hooks.slack.com/...general integrations/send_slack.py"
RCmd 5

"WebSocket fix deployed to staging. Running load tests now. If they pass, production deploy at 4pm."

RCmd 6

"Heads up: we're deploying a fix for the connection stability issue at 4pm today. No downtime expected. Will update in this channel when done."

Same information, different tone, different audience. 15 seconds total.

Without Transform: Raw Voice to Slack

Don't need AI cleanup? Omit the transform field entirely:

toml — raw voice, no transform
[[hotkey]]
key = "RightCommand"
channel = "5"
name = "slack-raw"
exec = "SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../xxx integrations/send_slack.py"

Your speech goes directly to Slack — punctuated by SpeechButton's STT engine but otherwise unmodified. Useful for quick casual messages where tone doesn't matter.

Privacy

Here's exactly what stays on your Mac and what goes to the cloud:

Component Where it runs Data sent externally
Voice capture Your Mac Nothing
Speech-to-text (Parakeet V3 int8) Apple Neural Engine Nothing
Local AI transform (Option A) Your Mac Nothing
Claude API transform (Option B) Your Mac Message text → Claude API
send_slack.py Your Mac Message text → Slack (where it needs to go anyway)

With Local AI (Option A), everything stays on your Mac except the final webhook POST to Slack. Voice capture, transcription, and the AI rewrite all run locally. Only the finished message leaves your machine — directly to the Slack channel it was meant for.

Get Started

Prerequisites

  • macOS 15+ (Sequoia), Apple Silicon
  • A Slack workspace where you can create apps
  • Python 3 (pre-installed on macOS)

Quick Start

  1. 1 Download SpeechButton — free 15 minutes/day, no account needed
  2. 2 Create a Slack webhook at api.slack.com/apps — Features → Incoming Webhooks → Add New Webhook to Workspace
  3. 3 Save send_slack.py to ~/.config/speechbutton/integrations/
  4. 4 Write a prompt file in ~/.config/speechbutton/prompts/slack_message.md with the tone instructions for your channel
  5. 5 Add a [[hotkey]] block to config.toml with your webhook URL in the exec line
  6. 6 Hold RightCommand, speak, release. Your first voice message arrives in Slack in under 5 minutes.

Start sending Slack messages by voice today

Free 15 min/day · No account needed · macOS 15+ · Apple Silicon

 Download for macOS — Free

Pro ($7.99/mo) removes the daily limit. Requires macOS 15+ and Apple Silicon.