Connect Slack
The Slack source needs a Slack app of your own and the macOS login Keychain. Each person creates their own app: Slack hands each Socket Mode event to any one of an app’s open connections, so two people sharing an app would receive each other’s messages and miss their own.
wloop init walks you through these steps. To do them by hand:
1. Create the app
Section titled “1. Create the app”- Open api.slack.com/apps, choose Create New App, then From a manifest, and pick your workspace.
- Paste the manifest below, replacing
Your Nameindisplay_information.nameso the workspace admin can tell the apps apart. Slack labels your posts “Sent using” this name. - Create the app. On OAuth & Permissions, turn on PKCE. It cannot be turned off later, and the login has no client secret without it.
- On Basic Information, under App-Level Tokens, choose Generate Token and Scopes, add the scope
connections:writeand generate it. Copy thexapp-...token. - Copy the Client ID from App Credentials on the same page.
A workspace that requires admin approval shows a request form on the first login instead of the consent page. Send the request, wait for the approval, then log in again. Adding a scope to the app later asks for a new approval.
The manifest, also at slack-app-manifest.yaml:
display_information: name: wloop (Your Name) description: Brings the Slack threads and DMs that ask something of you into your wloop Inbox, and posts as you only after your approval.oauth_config: redirect_urls: - http://127.0.0.1:53682/slack/callback scopes: user: - search:read - channels:history - groups:history - im:history - mpim:history - channels:read - groups:read - im:read - mpim:read - users:read - users:read.email - chat:write - im:write - reactions:read - reactions:write - files:readsettings: event_subscriptions: user_events: - message.channels - message.groups - message.im - message.mpim - reaction_added - reaction_removed org_deploy_enabled: false socket_mode_enabled: true token_rotation_enabled: true2. Log in
Section titled “2. Log in”In config.toml:
[plugins.slack]client_id = "000000000000.000000000000"Then:
wloop slack login # opens the browser; --no-browser prints the URL insteadwloop slack login --app-token # paste the xapp-... token; hidden at a terminal, or piped on standard inputwloop slack status # team, user, token expiry, whether the app token is storedslack login runs Slack’s OAuth flow for a user token, with PKCE, and waits up to 5 minutes for the callback on http://127.0.0.1:53682/slack/callback (plugins.slack.redirect_port). The app’s redirect URL must name that address; the manifest already does. --app-token reads the token only from standard input and refuses a value on the command line.
Restart the daemon so it connects (on macOS, launchctl kickstart -k gui/$(id -u)/io.github.wloophq.wloop). wloop doctor then reports the socket and the login.
3. Choose what comes in
Section titled “3. Choose what comes in”By default, a message comes in when it mentions you, replies to you, sits in a thread you wrote in, or is in a DM. To widen it:
[plugins.slack]client_id = "000000000000.000000000000"post_allowlist = ["C000", "U000"] # channel ids, or user ids for their DMs
[plugins.slack.ingest]terms = ["api-outage", "billing"]allow_apps = ["B000"]ingest.termsadmits messages with any of these words.ingest.allow_appsadmits the messages of these bots or apps.post_allowlist, when not empty, is the only set of channels or users any post may reach.
Follow a whole thread, so every message of it comes in:
wloop slack follow https://acme.slack.com/archives/C000/p1700000000000000wloop slack unfollow https://acme.slack.com/archives/C000/p17000000000000004. Work with it
Section titled “4. Work with it”Slack threads and DM topics now give tasks in your Inbox. Their rows offer the intents that serve Slack: the bundled act, and any intent of yours with provider = "slack" or "any".
Delegate. d on a Slack task (a thread’s task, whether it waits on you or on someone else, or a capture on a thread) runs act, or your own Slack intent of the same verb, which outranks it. It asks for optional guidance first. By default act runs headless: one read-only agent call that resolves what it can and proposes the replies as drafts for that task. In the cockpit, Delegate on the task’s page asks for the guidance and lets the action pick its mode; the page’s composer writes to the task’s agent instead, which starts a turn when no session of the task is live. A thread or a DM with no placement runs its session in a neutral directory under the state directory, an empty repository with no project checked out; add a placement for a channel to work its threads in that repository instead. When no session can run at all, such as with no workspace manager enabled, the terminal’s guidance prompt says why. Tab in the guidance prompt switches to a session. The Inbox notification of a Slack task has a Draft for me button. A session started this way knows the task and its items, so what it drafts with slack_draft lands in the task’s detail like a headless draft.
From a terminal, an intent that serves Slack takes a message ref (<conversation>/<ts>), a permalink or slack:<key> in place of a pull request URL. The daemon resolves a ref or a permalink to the unit the message is in, as slack_draft does: the tracked direct message segment or thread, else its thread:
wloop act https://acme.slack.com/archives/C000/p1700000000000100 'say we ship Friday'The drafts made for a task are its draft gates, listed in its detail, where you approve, edit or discard them. In the terminal, a digit picks one (when the task asks no question), then a, i or Backspace acts on it.
Reply yourself. r on the task, Save as draft in the task page’s composer, the Reply composer in the thread detail, or the Reply field of its notification writes a reply in the thread (or, in the cockpit, a reaction such as eyes). Save to Outbox keeps it there for your approval; Send now (Tab in the terminal prompt, then y; Send reply in the notification) approves it at once. The task page’s composer also shows Also send to the conversation, checked as drafts.toml places a reply you write, and both buttons honor it. Either way it goes out through the Outbox like any draft, and counts as your reply for the thread’s items. Ctrl+E in the terminal prompt writes it in $EDITOR.
Write one, approve one with a, or from a terminal:
wloop outbox new https://acme.slack.com/archives/C000/p1700000000000100 'Friday, after the freeze.'wloop outbox new https://acme.slack.com/archives/C000/p1700000000000100 --react eyes --sendwloop outboxwloop outbox approve <id>slack send posts as you after a confirmation, through the running daemon. To a message ref or permalink it replies in the thread through the Outbox, as a draft of yours approved once you say yes (or at once with --yes), so the reply counts for the thread’s items and shows in the Logbook; --broadcast asks that draft to also post to the conversation. To a channel, a person, or with --thread=false, it posts directly:
wloop slack send https://acme.slack.com/archives/C000/p1700000000000100 'On it.'wloop slack send '#team-api' 'Deploy is done.'Log out
Section titled “Log out”wloop slack logoutIt revokes the user token at Slack and deletes both Keychain entries, even when the revoke fails. To keep Slack configured but stop the source, set plugins.slack.enabled = false and restart the daemon.
See Slack as a source for how messages are admitted and turned into items, and the configuration reference for every key.