Skip to content
← Public packages

@kody/slack

Read Slack conversations and safely send messages as the authorizing user through the saved slack OAuth integration.

AGENTS.md

103 lines · 3.3 KB · Markdown

@kody/slack — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke/dryRun snippets, and edge cases. Auth is a saved OAuth integration (default slack, user token). Do not paste tokens. Do not disable live webhooks or jobs.

Auth

  • Integration id: slack (override with integration)
  • Must be a Slack user token — never a bot token (xoxb-)
  • API origin: https://slack.com
  • No /account/secrets/new token path for this package

Import paths

ExportImport
overviewkody:@kody/slack
smoke-testkody:@kody/slack/smoke-test
list-conversationskody:@kody/slack/list-conversations
list-userskody:@kody/slack/list-users
get-historykody:@kody/slack/get-history
get-replieskody:@kody/slack/get-replies
send-messagekody:@kody/slack/send-message

Prefer static kody:@kody/slack/... imports from execute.

Smoke test (read-only)

Run on the forked package after connect:

import smokeTest from 'kody:@kody/slack/smoke-test'

export default async function main() {
	return await smokeTest()
	// or: smokeTest({ integration: 'slack-work' })
	// => { ok: true, integration: 'slack', userIdentity: true, botIdentity: false, teamIdentity: true }
}

If smoke-test says bot token: stop. Connect a user-token app (oauth/v2_user

  • oauth.v2.user.access). Do not keep calling helpers.

dryRun / confirm (send)

import sendMessage from 'kody:@kody/slack/send-message'

export default async function main() {
	return sendMessage({
		channel: 'C0123456789',
		text: 'Hello from Kody',
		dryRun: true,
	})
}

Live send requires explicit user approval of destination + content, then confirm: true (not only dryRun: false). Optional fields: threadTs, blocks, unfurlLinks, unfurlMedia.

Read helpers

import listConversations from 'kody:@kody/slack/list-conversations'

export default async function main() {
	return listConversations({
		types: ['public_channel', 'private_channel'],
		// integration: 'slack-work',
	})
}

types may include only: public_channel, private_channel, im, mpim.

Edge cases

  • Private channels / DMs only if the authorizing user can already see them.
  • On missing_scope / HTTP 403, helpers throw SlackApiError naming the missing user-token scope (needed) and the reconnect URL.
  • invalid_auth / token_revoked: reconnect at /connect/oauth?provider=<integration>.
  • redirect_uri mismatch: Slack app redirect must be exactly https://kody.codes/connect/oauth.
  • invalid_scope / "incorrect scope" on authorize: the connect URL's scopes= includes a name Slack does not recognize (e.g. projects:read is not a Slack OAuth scope). Use only the scopes in README; keep scopes= identical to User Token Scopes on the Slack app.
  • Name multi-account connections <provider>-<purpose> (slack, slack-work, slack-community). Do not hard-code personal workspace aliases.
  • Never treat smoke success as permission to post.

Fork / adapt

  1. Fork this listing (kody id stays slack).
  2. Connect the caller's user-token Slack app; do not reuse the platform listing's live integration as theirs.
  3. Run ./smoke-test on the fork before list/read/send.
  4. Keep LICENSE, ## Intent, and community-icon.svg intact for community listing.