- 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 |
عرض على GitHub