Setup guide
Set up knock-knock.
From nothing to a running group chat: install, connect a chat platform, pick a coding agent, decide what it may do, verify it works, then add a teammate's bot. Follow it top to bottom the first time; skim it later.
The model in five words
Learn these five nouns and the rest of the setup reads plainly. Everything you configure hangs off them.
Bot
One coding-agent identity you run = one Discord app holding a token locally. Its name lives on the platform and is fetched on connect — never typed. Has a runtime. Run several at once.
Channel
A platform channel = a project = a permission boundary. The thing a bot is invited to.
Membership
One of your bots active in one channel. It carries that bot's workspace folder and its allow/ask/deny profile for that project.
Roster
Your address-book of people and peer bots, each entered once and picked from a list thereafter. No re-pasting IDs.
Owner
You — one user id per platform, entered once and reused as the owner of every bot. Approvals go to the owner; only the owner can approve, stop, or resolve conflicts.
@mention opens a task thread, but the workspace and permission profile always come from the bot's membership on the parent channel, so a threaded task is governed by the same rules as a top-level one.Prerequisites
macOS or Linux
The prebuilt
knock-knockCLI — installed in the quickstart below — embeds the Bun runtime, so there's nothing else to install. Bun (curl -fsSL https://bun.sh/install | bash) is needed only if you install via npm or run from a source checkout.A chat platform you can add a bot to
knock-knock supports Discord, Slack, Telegram, GitHub, and Notion. Creating the app and copying the token(s) and id you need is covered per-platform in step 4.
A coding-agent runtime
The default (
claude-sdk) needs only anANTHROPIC_API_KEYor an existingclaudelogin. Nothing to install. Other runtimes are in step 5.
config.json you hand-edit. Everything lives under ~/.knock-knock/ and is written by the setup CLI. access.json — normalized into me / bots / channels (with each member's inline permission profile) / roster — is written only from your terminal, never from a chat message, so nothing said in the channel can change who's allowed or what they may do.Quickstart: from zero to a reply
The fastest path to seeing it work, solo, on Discord. Three commands and a few answers.
Install knock-knock
One CLI with the Bun runtime embedded — nothing else to install.
brew install ryanyen2/tap/knock-knockNo Homebrew? The install script works on macOS & Linux and verifies the checksum:
curl -fsSL https://raw.githubusercontent.com/ryanyen2/knock-knock/main/packaging/install.sh | bashAlso available: a
.debon the Releases page,npm install -g knock-knock(needs Bun), or from source (git clone … && bun install).Run setup
By default
knock-knock setupopens a local web UI in your browser (localhost-only, gated by a one-time token) to add a bot, a channel it works in, your owner id, and the ledger backend. The page never holds a secret — typing a token, editing permissions, and starting the relay hand off to the terminal that launched it. Prefer the keyboard?knock-knock setup --tuiruns the same flow as a terminal wizard: bot (platform → runtime) → channel (paste id → set owner id → pick member bots → set each one's workspace + preset → add collaborators from your roster) → token → ledger. Either way your owner id is asked once per platform; the bot's name is fetched from the platform on connect, never typed. It writesaccess.jsonand.envfor you. (You'll need a bot token and a couple of IDs first; step 4 shows how.)knock-knock setup # web UI (default) knock-knock setup --tui # terminal wizardStart the relay
It prints a “who's listening where” table — each bot, its channels, and the workspace it uses — then
connected as your-bot#1234. Now@mentionthe bot in your channel and say hello.knock-knock relay
Re-running knock-knock setup reopens the web UI — a dashboard of your bots, channels, and roster you can edit directly, with the same terminal handoff for tokens and permissions. With --tui, the second run instead opens a status dashboard + action menu in the terminal: a map of your bots, channels, and roster, plus actions to add a bot, add/edit a channel, add a person or peer to the roster, save a token, or choose the ledger backend.
Supported platforms
knock-knock connects through one platform-neutral adapter seam. Five platforms are supported today, in descending fidelity: Discord and Slack are full-fidelity and live; Telegram is near-parity; GitHub and Notion are async and degraded. Pick a platform below, then create the app, grab the token(s) and id, and run setup. Full reference: messaging-platforms-setup.md.
Discord
full · livePrerequisites: a Discord server you can manage, and Developer Mode on (Settings → Advanced → Developer Mode) so you can copy IDs.
Create the application and bot
Go to discord.com/developers/applications → New Application → name it. Open the Bot tab → Reset Token → copy it. It's shown only once. This is your
DISCORD_BOT_TOKEN.Enable the message-content intent
Bot → Privileged Gateway Intents → enable MESSAGE CONTENT INTENT. The only privileged toggle you need. Without it the bot connects but reads empty message text.
Invite the bot to your server
OAuth2 → URL Generator → scope bot → enable these permissions, then let the server owner open the generated URL.
View ChannelsSend MessagesSend Messages in ThreadsCreate Public ThreadsRead Message HistoryAdd ReactionsManage MessagesCollect the id and your owner id
Channel id — right-click the channel → Copy Channel ID (a 17–20 digit snowflake). Owner id — right-click yourself → Copy User ID (asked once per platform).
Then: run knock-knock setup, choose manage a bot -> add a new bot -> choose Discord; Add to a channel -> paste the channel id; then save/update token -> paste DISCORD_BOT_TOKEN.
Slack
full · liveFull fidelity over Socket Mode — an outbound WebSocket, no public server. Needs two tokens. (Inbound files work; outbound upload is pending.) Fast path: create the app from the manifest below — no clicking scopes one by one — then mint the two tokens.
Create the app from this manifest skip the clicking
On the page above: Create New App → From an app manifest → pick your workspace → paste the YAML below → Create. One paste sets every scope, event, interactivity, and Socket Mode — no adding them one chip at a time.
display_information: name: knock-knock features: bot_user: display_name: knock-knock always_online: true oauth_config: scopes: bot: - app_mentions:read - channels:history - groups:history - im:history - mpim:history - chat:write - reactions:read - reactions:write - pins:write - files:read - files:write settings: event_subscriptions: bot_events: - app_mention - message.channels - message.groups - message.im - message.mpim - reaction_added interactivity: is_enabled: true socket_mode_enabled: true org_deploy_enabled: false token_rotation_enabled: falseRename it later by editing
name/display_name— knock-knock fetches whatever the bot is called on connect, so the manifest name isn't binding.Generate the two tokens, then install
The manifest can't mint tokens — do these two by hand:
1 · App-Level Token — Basic Information → App-Level Tokens → Generate, add scope
connections:write. This isSLACK_APP_TOKEN(xapp-…).2 · Bot token — OAuth & Permissions → Install to Workspace. This yields
SLACK_BOT_TOKEN(xoxb-…). Then/invitethe bot App to each channel.Collect the id and your owner id
Channel id — channel name → View Channel Details → Copy Channel ID at the bottom (
C0123ABCD). Owner id — your avatar → Profile → ⋯ → Copy member ID (U0123ABCD).
Then: run knock-knock setup, choose manage a bot -> add a new bot -> choose Slack; Add to a channel -> paste the channel id; then save/update token -> paste both tokens (SLACK_BOT_TOKEN + SLACK_APP_TOKEN, stored as the bot's app-token secret).
Telegram
near-parity · liveLive over getUpdates long-poll (no public server). One token, minor degrades (whitelist reactions, cold-DM).
Create the bot via BotFather
DM @BotFather →
/newbot→ copy the token (<id>:<secret>). This is yourTELEGRAM_BOT_TOKEN. No extra secret.Disable Group Privacy & make it admin
BotFather → /mybots → Bot Settings → Group Privacy → Turn off (else the bot sees only @mentions and looks "deaf"). Make the bot a group admin to receive reactions. Forum topics (the thread analogue) need a supergroup with Topics enabled.
Collect the chat id and your owner id
Chat id — via @userinfobot or
getUpdates; groups are negative, supergroups-100…. Owner id — DM @userinfobot for your numeric user id.
Then: run knock-knock setup, choose manage a bot -> add a new bot -> choose Telegram, paste your user id; Add to a channel -> paste the chat id; then save/update token -> paste TELEGRAM_BOT_TOKEN. Gotcha: the bot can only DM users who have /started it — /start your own bot so approval DMs reach you.
GitHub
async · degradedAsync transport (~60 s) over Notifications polling — best for PR-cadence coding and agent-to-agent-over-issues, not live chat. The repo is the room; an issue / PR is the task scope (automatic).
Make a machine-user & a PAT
Create a dedicated machine-user account to act as the bot, then a Personal Access Token at github.com/settings/tokens. Scopes: classic
repo+notifications, or fine-grained Issues R/W + Pull requests R/W + Contents R/W + Metadata R. This is yourGITHUB_BOT_TOKEN. No extra secret.Add the machine-user to the repo
The machine-user must be a collaborator / org member of the repo so @mentions notify it and it can comment.
The id and your owner id
Channel id is the repo —
owner/repo(each task scopeowner/repo#issueis derived automatically). Owner id is your GitHub login.
Then: run knock-knock setup, choose manage a bot -> add a bot -> choose GitHub, paste login; Add to a channel -> paste owner/repo; then save/update token -> paste GITHUB_BOT_TOKEN. Gotchas: ~60 s latency; public repos are an injection surface — restrict to allowed authors; approvals arrive as a numbered text reply (host wiring is a known pending item).
Notion
async · heavily degradedAsync over comment/page polling (~seconds, no reactions/buttons/DM/edit/inline files). Honest verdict: often better used as an MCP tool than a chat transport.
Create the integration
At notion.com/developers/connections create a connection with access token and capabilities of Read content, Insert content, Read comments, Insert comments, Read user information. It yields the secret
NOTION_TOKEN(ntn_…). No extra secret.Share each page/database with it (might be automatically by Notion)
Open the page or database → ••• → Connections → manage connections → add your integration. Without sharing, the integration sees nothing — the token alone grants no access. This is the single most common failure.
The id and your owner id
Channel id is a page or database id — 32 hex chars from the page link's trailing id. Owner id is your Notion user id (find it via
settings->profile->user id).
Then: run knock-knock setup, choose manage a bot -> add a bot -> choose Notion; Add to a channel -> paste the page/database id and owner id; then save/update token -> paste NOTION_TOKEN. Gotcha: cold-start ignores the pre-existing comment backlog; the Workers/External-Agents bridge needs Business/Enterprise and is a future option.
Choose the coding agent behind the bot
The bot is just the face. The relay can drive any of these, chosen by the bot's runtime in setup, with no code changes.
| runtime | Agent | Notes |
|---|---|---|
| claude-sdk | Claude Code, in-process | Default. Nothing to install; enforces the deny floor natively. |
| claude-acp | Claude Code, over ACP | Runs out-of-process over ACP. |
| opencode | OpenCode | Install, then set it to ask before tools. |
| codex | OpenAI Codex | Needs OPENAI_API_KEY; don't launch it in a bypass mode. |
| gemini | Gemini CLI | gemini --experimental-acp. |
| acp | any ACP agent | You set the spawn command. |
Decide what the bot may do
Each membership (a bot in a channel) gets a preset, expanded inline into its allow/ask/deny. Every tool is checked against it, with one rule: deny beats ask beats allow. The same bot can be strict in one channel and auto in another.
| Preset | Reads | Edits | Shell | Good for |
|---|---|---|---|---|
| strict | allow | deny | deny | untrusted peers, read-only research |
| ask-per-edit | allow | ask | ask | day-to-day work (recommended start) |
| auto | allow | allow | ask | trusted solo flow |
| bypass | allow | allow | allow | unattended runs you review after |
Two things hold no matter the preset. The deny floor is always on: destructive shell (rm -rf, sudo), writes to sensitive paths, and reading or sharing any credential file (.env, *.key, ~/.aws) are blocked even under bypass, checked against the real command. And you can give peers less than yourself with per-actor tiers, e.g. a peer's bot runs read-only while you keep full access. Full guide: Permissions & security.
!share <path>. Both are typed as a FileShare permission, and the secret floor refuses reading or sharing a credential no matter the preset. See File exchange.Say hello, then verify
With the relay running and your bot a member of a channel on ask-per-edit, @mention it, then run this three-line check.
- T1“What files are here?”
Answered immediately, no prompt. Read is allowed.
- T2“Run
echo hello.”An Allow / Deny prompt pings you, the owner. A non-owner tapping Allow is rejected.
- T3“Delete everything with
rm -rf.”Blocked, no prompt ever appears, the command never runs. The floor.
Run the relay with KNOCK_KNOCK_DEBUG=1 to log every permission decision if you want to watch the floor work.
Add a teammate's bot
The point of knock-knock: two people, two machines, two bots, one channel. Each person does steps 4 to 6 on their own machine, then adds the other to their roster and to the channel.
Both join one channel
Invite both bots to the same server and channel. That channel is the project both bots are members of.
Exchange bot user IDs
Each person copies their bot's user ID and sends it to the other.
Add each other as peers, then as collaborators
Add the other bot to your roster as a peer (id + a blurb like “hosts the vLLM box”), then add it as a collaborator of the channel. The blurb is what your bot sees in the roster, so it knows who to
@mentionfor what. Entered once; picked from a list thereafter.knock-knock setup # "Add a peer bot to the roster" → then "Add / edit a channel"Both launch
Now one bot can
@mentionthe other with a request. A task thread opens, the other bot works in its membership's workspace under its owner's rules, and anything that changes that machine waits for that owner's Allow.knock-knock relay
knock-knock relay connects both. With more than one of your bots in a channel, an @mention routes to the named bot.Go deeper
Once the basics work, these are the features worth knowing about. Each has a dedicated guide.
!share one back — gated by the same permission floor.
WatchesLet a turn defer and be resumed by the world: a file changing, a job finishing, a deadline passing.
Reactions & versioningThe reaction vocabulary, equal-role conflict cards, and how the ledger versions every action.