Skip to content

Slack

Hansard can post to Slack when a conversation finishes, mirror conversations into Slack threads as they happen, and post a daily digest. Slack posting is off until you set it up.

App
Settings → Slack
CLI
hansard notify slack

The Interactive bot section adds one private bot with a confirmed configuration for each channel. A channel can combine these roles:

Role Behavior
Broadcaster Posts recent archived excerpts into conversation threads. Replies become requests for an isolated continuation. One Broadcaster configuration can be enabled.
Tag-to-run Starts a configured agent after an approved mention. Replies continue its run after approval. Orchestrator mode uses up to three helpers in the same project.
Digest Posts recent eligible conversation titles and counts at the configured interval.
Persistent watcher Collects permitted channel activity and proposes tasks for owner approval. It never starts work automatically.
Approvals Sends launch and supported native tool decisions to the thread. Only the owner can approve.

Socket Mode requires Node 22 or later. It connects outward from the Mac and needs no public endpoint. Native execution currently supports Claude Code and Codex on macOS. Team memory and other isolated harness adapters are unavailable.

  1. Open Settings → Slack → Interactive bot and select Set up bot.
  2. Register the owner, workspace, app, bot, and channel IDs.
  3. Add an existing project folder and select its harness, model, and native permission mode.
  4. Copy the app manifest into Slack’s private app creation flow. Install the app with the listed scopes.
  5. Create an app-level token with connections:write. Save that token and the bot token through the local credential form.
  6. Invite the app to each permitted channel and select Start connection in Hansard.
  7. Mention the bot with a description, such as “Broadcast the Web project and act as a persistent watcher.”
  8. Review the proposed channel settings and confirm them.

The local channel form provides the same preview and confirmation flow. Message display names and pictures use chat:write.customize. Mentions continue to identify the installed Slack app. Channel instructions can select registered projects, but they cannot grant new folders or change native permission modes.

Without owner prompts or channel access, each launch and continuation requires owner approval, and only the owner and listed requesters can submit requests. Guests, Slack Connect members, bots, unknown users, and direct messages from anyone but the owner never start agents. Configuration changes invalidate pending approvals. Redacted or incomplete approval details require review in the local Settings panel. The panel shows the complete saved task before execution. Saves that change only owner prompts, channel access, requesters, or allowed channels apply to a running connection without stopping it. Runs that the new settings no longer permit stop.

Agents run inside a project filesystem sandbox. They cannot read Hansard’s archive, Slack credentials, or unrelated folders. The sandbox blocks Keychain authentication and localhost proxies. Account modes that need these facilities are unavailable. The selected native permission mode remains unchanged.

Keep the app connection or hansard notify slack bot run process running. Stopping it stops its agents. After restart, a new request needs owner approval. The process that starts the bot owns its controls. Other local processes cannot change its grants, approve its tasks, or stop its agents. Start the connection in Settings to answer native questions in the local panel. A bot started by the CLI has Slack controls, but a separate viewer cannot answer its native questions. Stop that CLI process before changing its configuration from Settings.

Progress appears as paced status edits and complete responses. Broadcasts use at most 200 recent conversations within 24 hours and short excerpts from the archive. These limits do not guarantee a complete transcript mirror.

The existing outbound notifier below stays independently configured. Enabling both for the same conversations can produce duplicate posts. Team sharing remains opt-in and does not grant Slack execution access.

The Prompts from Slack group holds the owner’s own switches. Each switch works only while the one above it is on, and keeps its saved value while it cannot apply.

Setting Behavior
Run your prompts The owner’s own messages start and continue runs without an approval click.
Direct messages The owner can message the bot directly. Anyone else’s direct message starts nothing and gets one short reply.
Project for direct messages The granted project that a direct message uses when it names none.
Agents on this Mac Direct messages from the owner can reach agents that run in a terminal or are paused on this Mac, as Running lists them.

An app installed before direct messages were on lacks their scopes. After turning on Direct messages, open App manifest, update the Slack app from it, and reinstall the app. The manifest then adds the im:history and im:read scopes, the message.im event, and the app’s Messages tab. hansard notify slack bot manifest --direct-messages on prints the same manifest.

A top-level direct message is a task for the default project. A message that starts with project:<id or name> uses that granted project instead. Quote a name with spaces, as in project:"Web App" Fix the build. Without a default project or a prefix, the bot replies with the granted project IDs. Each top-level message starts its own thread, and a reply in that thread continues the same run. help or an empty message gets a short usage reply. These tasks run in the project’s sandbox, like channel runs. The bot doesn’t read attached files yet, so send each task as text.

With Agents on this Mac on:

  • agents lists up to 20 agents, numbered. A list number stays valid for 30 minutes.
  • agent:<number> <words>, or agent: followed by six or more characters of the session ID and the words, sends the words. A reply in that thread sends more words to the same agent.
  • A paused agent resumes where it ran, as Resume in Running does. Hansard delivers the words once the agent has been idle at its prompt for 5 seconds. If it does not start within 3 minutes, the bot says so.
  • An agent that waits on an approval or a question is never typed into. The words wait until it returns to its prompt.
  • For Claude Code and Codex, the agent’s next complete reply appears in the thread. For other harnesses, check the agent on the Mac.

agents and agent: in a channel start nothing. The bot replies that live agents take messages only in a direct message.

When an agent asks you a question with ask_user, the question also arrives in your direct message with the bot as a card, with Approve, Deny, and Deny with a note. Only your own press on the card answers it. After Deny with a note, your reply in the card’s thread is the note.

Channel access lists each allowed channel. Its Edit dialog sets who besides the owner can send there and how their runs start. A channel without its own setting keeps the behavior above.

Setting Choices
Who can send Only you, People you list (the owner and the listed requester IDs, one list for all channels), or Everyone in the channel (any full member, checked against the channel’s members).
Approval You approve each run (the default) or Runs start without approval.
Runs per person each day Runs without approval for each person over 24 hours, from 1 to 100. The default is 10.
Runs at once Runs without approval from people on the channel’s default at the same time, from 1 to 5. The default is 2.

Runs start without approval only when the channel’s project uses Claude Code’s Manual or Plan mode, where Claude Code asks before every edit, every command that is not read-only, and every read outside the project, Claude Code’s Auto mode, where Claude Code’s classifier decides tool use inside the same sandbox, or Codex’s Read only mode, where Codex asks before every edit and every command that is not read-only. Under any other mode, Accept edits and Codex’s Auto and Full access included, requests still wait for the owner, and the dialog says so. Tool approvals from these runs still go only to the owner. A person starts new threads and continues only their own runs without approval. Another person’s run, or a thread with archived context, needs the owner. Over a limit, the bot replies with the limit and starts nothing. A person can have at most three requests waiting for approval.

People in this channel, at the end of the Edit dialog, lists everyone the bot has seen send a message in that channel, by their Slack name. The bot keeps each person’s member ID, name, and when it last saw them, never what they wrote. Each person gets one Access choice:

Choice Behavior
Channel default The channel’s project, approval, and limits.
You approve each run The owner approves each run, and the person uses only the channel’s project.
Their own scope The projects the person can use, whether their runs need approval, and their own runs each day and runs at once.
Can’t send here In a channel for People you list only, for someone who is not on the list.

In a channel open to Everyone in the channel, a person that the owner has not reviewed starts at You approve each run. A person on the list of requesters starts at Channel default. Runs at once in the channel counts the runs of everyone on the channel’s default together, and a person with their own scope has their own count. A mention that starts with project:<id or name> runs in another granted project that the person can reach. Quote a name with spaces, as in project:"Web App". A reply runs in its thread’s project.

Before a save gives anyone more access, such as a new audience, another person, another project, runs without approval, or higher limits, Settings shows a notice. It says who can start runs on the Mac, in which projects, and with which limits, what they can’t do, and the risks. Accept and save saves the change and records when the owner accepted. Cancel saves nothing. A save that narrows access shows no notice. From the CLI, hansard notify slack bot configure --file <json> prints the same notice and saves only when run again with --accept-coworker-access and the code it prints.

Guests, people from other organizations (Slack Connect), and bots can never send. Other people’s runs stay in the channel’s project inside the sandbox and reply only in their thread. Each such run, approved or not, gets a provider home of its own that leaves out the owner’s personal instruction and memory files (Claude Code’s CLAUDE.md and rules, Codex’s AGENTS.md), the owner’s Claude Code allow rules, plugins, hooks, MCP servers, and the project’s own Claude Code settings, and the owner’s Codex MCP servers, connectors, and plugins. A Codex run for another person holds no sign-in: it reaches its model only through the router in Accounts, with a key that works only for that run while it works, so these runs need the router with a Codex account. Such a run has no other network, so a command that needs the internet fails even when the owner approves it. The sandbox keeps every such run’s reads to the project, its own home, and system folders. These runs still follow the project’s own instructions: Claude Code reads the project’s CLAUDE.md and the files it imports from inside the project, such as AGENTS.md, and Codex reads the project’s AGENTS.md. The home is removed 15 minutes after the run’s last reply. A reply in the thread after that starts a new run without the earlier context, as a new request would, and the bot says so in the thread.

Post Content Default
Summaries One recap per conversation after it has been quiet for 10 minutes: the goal, the result, edited files, and activity counts. On once Slack is set up
Live threads Every user and agent message, posted whole into one thread per conversation, in batches every 45 seconds. Tool calls are left out unless notify.slack.stream.includeTools is true. Off
Daily digest One summary per day, grouped by person or device, with conversation, repository, model, and token totals. Off
Behavior digest A comparison of one period with the previous one. Posts only when you run it. Manual

Hansard posts from its archive, with redaction applied, never from the harness’s original files. Subagent runs, SDK batch jobs, and imported ChatGPT, Claude.ai, and Gemini conversations never post as summaries or live threads. A conversation you resume later opens a new thread with only the new messages.

Creating the Slack app is a CLI step. Before you start, create the channels you want to post to and decide which repositories may post.

  1. Start the guided setup:

    Terminal window
    hansard notify slack setup

    It opens Slack’s app creation page with a prepared manifest. The app asks for chat:write, chat:write.customize so live threads can show each speaker’s name, and channels:read plus groups:read so setup can list channel names. It cannot read Slack messages. Paste the bot token when asked, then enter channel IDs. Setup ends by sending a test post.

  2. In Slack, invite the bot to each channel.

  3. Check the saved configuration and preview a test message:

    Terminal window
    hansard notify slack status
    hansard notify slack test --dry-run
  4. Send the test when the preview is right:

    Terminal window
    hansard notify slack test
Settings, Slack: the Interactive bot section with its connection stopped and no registered projects or channelsSettings, Slack: the Interactive bot section with its connection stopped and no registered projects or channels
  1. Open Settings → Slack. If Slack is not connected yet, select Add bot token, enter a label, and paste a bot token from your Slack app.

  2. Use Post to Slack to pause or resume all posting. Your rules and digest stay saved while it is off.

  3. Under Bot tokens, the token marked Default posts for every rule and digest that does not choose another. To change it, choose Set as default from another token’s menu. Select Add bot token to save another token.

  4. Under Posting rules, select Add rule or edit a rule to set which conversations post, the summary channel and quiet time, the live thread, and Post as.

  5. Under Daily digest, turn on Post a daily digest and set the Channel ID, Send at as a local hour, the period it Covers, and Post as. Changes save automatically.

The app’s name and icon in Slack come from Slack. Change them in your Slack app settings, which Open Slack app settings under Bot tokens opens.

The app does not post a digest preview. To see the complete digest before anything posts, run:

Terminal window
hansard notify slack digest run --dry-run

An empty digest posts nothing.

Turn summaries and live threads on or off separately:

Terminal window
hansard notify slack enable \
--summaries on \
--summary-channel C0123456789 \
--quiet-minutes 10 \
--firehose off \
--repos github.com/example/app

With no --repos, every eligible conversation posts.

Routes send different conversations to different channels or through different bots. A conversation posts to every route it matches, in order. A route marked --exclusive stops later routes from also receiving it.

Store a bot token under a name so it never appears on a command line:

Terminal window
hansard notify slack token add example-bot

Named tokens live in a local file readable only by you. Status output shows only the name and the last characters of the token.

Add a route that uses the stored token:

Terminal window
hansard notify slack route add \
--match-owners example \
--summary-channel C0123456789 \
--token ref:example-bot \
--exclusive

Routes can also match repositories (--match-repos), repository hosts (--match-hosts), harnesses (--match-providers), archive scopes (--match-scopes), local folders (--match-path), portfolios (--match-containers), and devices (--match-devices). A route with no match options matches every conversation. List routes and their channels without posting:

Terminal window
hansard notify slack route list

hansard notify slack route reorder --order <id,id> sets route priority. Use the route IDs from route list in the desired order.

Terminal window
hansard notify slack digest behavior --period 1m --dry-run

It uses the daily digest’s channel and token. Remove --dry-run to post.

Summaries and live thread headers include an Open in Hansard app link. It opens the Mac app and selects the conversation. Run hansard app --no-fallback to confirm the app is installed. To link to a hosted viewer instead, set notify.slack.viewerBaseUrl to its address. Set it to an empty string to leave the link out.

Going offline pauses posting, never archiving. Failed posts keep their place and retry about once a minute, so everything posts after you reconnect. A post can occasionally appear twice. When one conversation has more than 20 messages waiting, Hansard posts the latest 20 and a note with the number skipped. The full conversation stays in your archive.

Terminal window
hansard notify slack disable

Messages already in Slack stay there. Delete them with Slack’s controls, and revoke the app’s token in Slack when you retire the connection.