Skip to main content

slack-agent

Use when working on Slack agent/bot code, Chat SDK applications, or projects using `chat` and `@chat-adapter/slack`. Provides development patterns, testing requirements, and quality standards.

Source facts

Repository
millionco/pookie
Last source activity
May 5, 2026 at 08:58
Detected SKILL.md language
English
Stars
42
Forks
1

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
17 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
slack-agent
description
Use when working on Slack agent/bot code, Chat SDK applications, or projects using `chat` and `@chat-adapter/slack`. Provides development patterns, testing requirements, and quality standards.
version
4.0.0
user-invocable
true
# Slack Agent Development Skill (Chat SDK) This skill builds Slack agents on the **Chat SDK**: `chat` + `@chat-adapter/slack` running on Next.js (App Router) deployed to Vercel. ## Skill Invocation Handling When this skill is invoked via `/slack-agent`, check for arguments and route accordingly: ### Command Arguments | Argument | Action | | ------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `new` | **Run the setup wizard from Phase 1.** Read `./wizard/1-project-setup.md` and guide the user through creating a new Slack agent. | | `configure` | Start wizard at Phase 2 or 3 for existing projects | | `deploy` | Start wizard at Phase 5 for production deployment | | `test` | Start wizard at Phase 6 to set up testing | | (no argument) | Auto-detect based on project state (see below) | ### Auto-Detection (No Argument) If invoked without arguments, detect the project state and route appropriately: 1. **No `package.json` with `chat`** → Treat as `new`, start Phase 1 2. **Has project but no customized `manifest.json`** → Start Phase 2 3. **Has project but no `.env` file** → Start Phase 3 4. **Has `.env` but not tested** → Start Phase 4 5. **Tested but not deployed** → Start Phase 5 6. **Otherwise** → Provide general assistance using this skill's patterns ### Wizard Phases The wizard is located in `./wizard/` with these phases: - `1-project-setup.md` — Understand purpose, generate custom implementation plan - `1b-approve-plan.md` — Present plan for user approval before scaffolding - `2-create-slack-app.md` — Customize manifest, create app in Slack - `3-configure-environment.md` — Set up `.env` with credentials - `4-test-locally.md` — Dev server + ngrok tunnel - `5-deploy-production.md` — Vercel deployment - `6-setup-testing.md` — Vitest configuration **IMPORTANT:** For `new` projects, you MUST: 1. Read `./wizard/1-project-setup.md` first 2. Ask the user what kind of agent they want to build 3. Generate a custom implementation plan using `./reference/agent-archetypes.md` 4. Present the plan for approval (Phase 1b) BEFORE scaffolding the project 5. Only proceed to scaffold after the plan is approved --- ## General Development Guidance You are working on a Slack agent project. Follow these mandatory practices for all code changes. ## Project Stack - **Framework**: Next.js (App Router) - **Chat SDK**: `chat` + `@chat-adapter/slack` for Slack bot functionality - **State**: `@chat-adapter/state-redis` for state persistence (or in-memory for development) - **AI**: AI SDK v6 with `@ai-sdk/openai` - **Linting**: Biome - **Package Manager**: pnpm ```json { "dependencies": { "ai": "^6.0.0", "@ai-sdk/openai": "latest", "chat": "latest", "@chat-adapter/slack": "latest", "@chat-adapter/state-redis": "latest", "zod": "^3.x", "next": "^15.x" } } ``` **Note:** Pookie uses `@ai-sdk/openai` directly. `OPENAI_API_KEY` is read automatically by the SDK at runtime. Other providers can be swapped in by changing the import and model string. --- ## Quality Standards (MANDATORY) These quality requirements MUST be followed for every code change. There are no exceptions. ### After EVERY File Modification 1. **Run linting immediately:** ```bash pnpm lint ``` - If errors exist, run `pnpm lint --write` for auto-fixes - Manually fix remaining issues - Re-run `pnpm lint` to verify 2. **Check for corresponding test file:** - If you modified `foo.ts`, check if `foo.test.ts` exists - If no test file exists and the file exports functions, create one ### Before Completing ANY Task You MUST run all quality checks and fix any issues before marking a task complete: ```bash pnpm typecheck pnpm lint pnpm test ``` **Do NOT complete a task if any of these fail.** Fix the issues first. ### Unit Tests Required **For ANY code change, you MUST write or update unit tests.** - **Location**: Co-located `*.test.ts` files or `lib/__tests__/` - **Framework**: Vitest - **Coverage**: All exported functions must have tests Example test structure: ```typescript import { describe, it, expect, vi } from "vitest"; import { myFunction } from "./my-module"; describe("myFunction", () => { it("should handle normal input", () => { expect(myFunction("input")).toBe("expected"); }); it("should handle edge cases", () => { expect(myFunction("")).toBe("default"); }); }); ``` ### E2E Tests for User-Facing Changes If you modify: - Bot mention handlers / Slack message handlers - Slash commands - Interactive components (buttons, modals) - Bot responses You MUST add or update E2E tests that verify the full flow. --- ## Bot Setup Patterns (CRITICAL) Use the Chat SDK to define your bot instance. This is the central entry point for all Slack bot functionality. ### Bot Instance (`lib/bot.ts` or `lib/bot.tsx`) ```typescript import { Chat } from "chat"; import { createSlackAdapter } from "@chat-adapter/slack"; import { createRedisState } from "@chat-adapter/state-redis"; export const bot = new Chat({ userName: "mybot", adapters: { slack: createSlackAdapter(), }, state: createRedisState(), }); ``` **Note:** If your bot uses JSX components (Card, Button, etc.), the file must use the `.tsx` extension. ### Webhook Route (`app/api/webhooks/[platform]/route.ts`) ```typescript import { after } from "next/server"; import { bot } from "@/lib/bot"; export async function POST( request: Request, context: { params: Promise<{ platform: string }> }, ) { const { platform } = await context.params; const handler = bot.webhooks[platform as keyof typeof bot.webhooks]; if (!handler) return new Response("Unknown platform", { status: 404 }); return handler(request, { waitUntil: (task) => after(() => task) }); } ``` The Chat SDK automatically handles: - Content-type detection (JSON vs form-urlencoded) - URL verification challenges - Slack's 3-second ack timeout - Background processing via `waitUntil` - Signature verification --- ## Event Handler Patterns ### Mention Handler ```typescript bot.onNewMention(async (thread, message) => { await thread.subscribe(); const text = message.text; await thread.post(`Processing your request: "${text}"`); }); ``` ### Subscribed Message Handler ```typescript bot.onSubscribedMessage(async (thread, message) => { await thread.post(`You said: ${message.text}`); }); ``` ### Slash Command Handler ```typescript bot.onSlashCommand("/mycommand", async (event) => { const text = event.text; await event.thread.post(`Processing: ${text}`); const result = await generateWithAI(text); await event.thread.post(result); }); ``` The Chat SDK handles background processing automatically via `waitUntil` — there's no need for fire-and-forget patterns. ### Action Handler (Buttons, Menus) ```typescript bot.onAction("button_click", async (event) => { await event.thread.post(`Button clicked with value: ${event.value}`); }); ``` ### Reaction Handler ```typescript bot.onReaction("thumbsup", async (event) => { await event.thread.post("Thanks for the thumbs up!"); }); ``` --- ## Implementation Gotchas ### 1. Private Channel Access Slash commands work in private channels even if the bot isn't a member, but the bot **cannot read messages or post** to private channels it hasn't been invited to. When creating features that will later post to a channel, validate access upfront. ### 2. Graceful Degradation for Channel Context When fetching channel context for AI features, wrap in try/catch and fall back gracefully. ### 3. Vercel Cron Endpoint Authentication Protect cron endpoints with a `CRON_SECRET` environment variable: ```typescript import { NextRequest, NextResponse } from "next/server"; export async function GET(request: NextRequest) { const authHeader = request.headers.get("authorization"); if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } return NextResponse.json({ success: true }); } ``` ### 4. `vercel.json` Cron Configuration Configure cron jobs in `vercel.json`: ```json { "crons": [ { "path": "/api/cron/my-job", "schedule": "0 * * * *" } ] } ``` ### 5. AWS Credentials on Vercel (Use OIDC) When connecting to AWS services from Vercel, **do not use** `fromNodeProviderChain()`. Use Vercel's OIDC mechanism: ```typescript import { awsCredentialsProvider } from "@vercel/functions/oidc"; const s3Client = new S3Client({ credentials: awsCredentialsProvider({ roleArn: process.env.AWS_ROLE_ARN! }), }); ``` ### 6. TSConfig for JSX Components When using Chat SDK JSX components (`<Card>`, `<Button>`, etc.), your `tsconfig.json` must include: ```json { "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "chat" } } ``` --- ## AI Integration Pookie uses `@ai-sdk/openai` for LLM access. `OPENAI_API_KEY` is read automatically by the SDK at runtime. ### Basic Usage ```typescript import { generateText, streamText } from "ai"; import { openai } from "@ai-sdk/openai"; const result = await generateText({ model: openai("gpt-4o-mini"), maxOutputTokens: 1000, prompt: "Your prompt here", }); console.log(result.text); console.log(result.usage.inputTokens); console.log(result.usage.outputTokens); ``` ### Streaming Responses to Slack ```typescript const result = await streamText({ model: openai("gpt-4o-mini"), maxOutputTokens: 1000, prompt: userMessage, }); await thread.post(result.textStream); ``` The Chat SDK handles streaming updates to Slack automatically. ### With Tools ```typescript import { tool } from "ai"; import { z } from "zod"; const result = await generateText({ model: openai("gpt-4o-mini"), maxOutputTokens: 1000, tools: { getWeather: tool({ description: "Get weather for a location", inputSchema: z.object({ location: z.string().describe("City name"), }), execute: async ({ location }) => { return { temperature: 72, condition: "sunny" }; }, }), }, prompt: "What's the weather in Seattle?", }); ``` ### AI SDK v6 API Changes | v4/v5 | v6 |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub