Skip to content

Commit a8b7880

Browse files
chore: add AGENTS.md (#2826)
Co-authored-by: Eden Zimbelman <eden.zimbelman@salesforce.com>
1 parent 983bcdf commit a8b7880

4 files changed

Lines changed: 239 additions & 0 deletions

File tree

.claude/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CLAUDE.local.md
2+
settings.local.json
3+
worktrees/
4+
plans/

.claude/CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@../AGENTS.md

.claude/settings.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(cat:*)",
5+
"Bash(echo:*)",
6+
"Bash(gh issue view:*)",
7+
"Bash(gh label list:*)",
8+
"Bash(gh pr checks:*)",
9+
"Bash(gh pr diff:*)",
10+
"Bash(gh pr list:*)",
11+
"Bash(gh pr status:*)",
12+
"Bash(gh pr update-branch:*)",
13+
"Bash(gh pr view:*)",
14+
"Bash(gh search code:*)",
15+
"Bash(git diff:*)",
16+
"Bash(git grep:*)",
17+
"Bash(git log:*)",
18+
"Bash(git ls-tree:*)",
19+
"Bash(git show:*)",
20+
"Bash(git status:*)",
21+
"Bash(grep:*)",
22+
"Bash(head:*)",
23+
"Bash(jq:*)",
24+
"Bash(ls:*)",
25+
"Bash(node --test:*)",
26+
"Bash(node --version:*)",
27+
"Bash(npm --version:*)",
28+
"Bash(npm config:*)",
29+
"Bash(npm install)",
30+
"Bash(npm install:*)",
31+
"Bash(npm run build:*)",
32+
"Bash(npm run lint:*)",
33+
"Bash(npm run test:*)",
34+
"Bash(npm show:*)",
35+
"Bash(npm test:*)",
36+
"Bash(npm version:*)",
37+
"Bash(nvm use:*)",
38+
"Bash(tail:*)",
39+
"Bash(tree:*)",
40+
"WebFetch(domain:docs.slack.dev)",
41+
"WebFetch(domain:github.com)",
42+
"WebFetch(domain:npmjs.com)",
43+
"WebFetch(domain:raw.githubusercontent.com)"
44+
]
45+
}
46+
}

AGENTS.md

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# AGENTS.md - bolt-js
2+
3+
Instructions for AI coding agents working on this repository.
4+
5+
## Project Overview
6+
7+
Slack Bolt for JavaScript -- a framework for building Slack apps, fast.
8+
9+
- **Foundation:** Built on top of `@slack/web-api`, `@slack/oauth`, `@slack/socket-mode`, and other `@slack/*` packages (see `package.json` for the full list and versions).
10+
- **Language:** TypeScript-first, compiled to CommonJS.
11+
- **Node version:** See `engines` in `package.json` for minimum Node.js and npm versions.
12+
- **Repository**: <https://github.com/slackapi/bolt-js>
13+
- **Documentation**: <https://docs.slack.dev/tools/bolt-js/>
14+
- **npm**: <https://www.npmjs.com/package/@slack/bolt>
15+
- **Current version**: defined in `package.json`
16+
- **Examples**: Sample apps in `examples/` (Socket Mode, OAuth, Lambda, custom receivers, etc.)
17+
18+
## Environment Setup
19+
20+
```bash
21+
# Install all dependencies
22+
npm install
23+
```
24+
25+
## Common Commands
26+
27+
Before considering any work complete, you MUST run `npm test` and confirm it passes.
28+
29+
```bash
30+
npm test # Full pipeline: build -> lint -> type tests -> unit test coverage
31+
npm run build # Clean build (rm dist/ + tsc compilation)
32+
npm run lint # Biome check (formatting + linting)
33+
npm run lint:fix # Biome auto-fix
34+
npm run test:unit # Unit tests only (mocha)
35+
npm run test:coverage # Unit tests with coverage (c8)
36+
npm run test:types # Type definition tests (tsd)
37+
npm run watch # Watch mode for development (rebuilds on src/ changes)
38+
```
39+
40+
## Architecture
41+
42+
### Event Flow
43+
44+
Incoming events flow through a middleware chain before reaching listeners:
45+
46+
1. **Receiver** ingests event from Slack (HTTP, Socket Mode, or Lambda)
47+
2. Receiver calls `App.processEvent(ReceiverEvent)`
48+
3. **Global middleware** chain executes (authorization, self-event ignoring, custom middleware)
49+
4. App determines event type and matches relevant **listeners** based on constraints
50+
5. **Listener-specific middleware** chains execute
51+
6. **Listener handler** runs with full context
52+
53+
For FaaS environments (`processBeforeResponse: true`), acknowledgment happens after the handler executes.
54+
55+
### Core Classes
56+
57+
- **`App`** (`src/App.ts`) -- Central orchestrator. Registers listeners via methods (`app.event()`, `app.action()`, `app.command()`, etc.). Dispatches incoming events through middleware to matching listeners. Manages the Web API client pool, authorization, and error handling.
58+
- **`Receiver`** interface (`src/types/receiver.ts`) -- Pluggable transport layer abstraction. Methods: `init(app)`, `start()`, `stop()`.
59+
- `HTTPReceiver` (`src/receivers/HTTPReceiver.ts`) -- Express v5 HTTP server, default receiver
60+
- `SocketModeReceiver` (`src/receivers/SocketModeReceiver.ts`) -- WebSocket-based, no public URL needed
61+
- `ExpressReceiver` (`src/receivers/ExpressReceiver.ts`) -- Integrates with an existing Express v5 app
62+
- `AwsLambdaReceiver` (`src/receivers/AwsLambdaReceiver.ts`) -- AWS Lambda handler
63+
- **`Assistant`** (`src/Assistant.ts`) -- AI assistant thread handling middleware. Intercepts assistant thread events (`assistant_thread_started`, `assistant_thread_context_changed`, `message` in assistant threads) and dispatches them to registered sub-handlers. Provides utilities: `say`, `setStatus`, `setSuggestedPrompts`, `setTitle`, `getThreadContext`, `saveThreadContext`. Uses `AssistantThreadContextStore` (`src/AssistantThreadContextStore.ts`) for thread context persistence.
64+
- **`CustomFunction`** (`src/CustomFunction.ts`) -- Workflow custom function handler. Provides `complete()` and `fail()` utilities for function execution lifecycle.
65+
- **`WorkflowStep`** (`src/WorkflowStep.ts`) -- **Deprecated.** Use `CustomFunction` and `app.function()` instead.
66+
67+
### Middleware System
68+
69+
Middleware uses a chain-of-responsibility pattern. Each middleware receives args and calls `next()` to continue the chain.
70+
71+
**Type:** `Middleware<Args> = (args: Args & AllMiddlewareArgs) => Promise<void>`
72+
73+
**AllMiddlewareArgs** (always available):
74+
75+
- `context` -- Event metadata (botToken, userToken, botId, botUserId, teamId, enterpriseId, etc.)
76+
- `logger` -- Logger instance
77+
- `client` -- Web API client (pre-authorized)
78+
- `next` -- Call to continue the middleware chain
79+
80+
**Built-in middleware** in `src/middleware/builtin.ts` includes constraint matchers (event type, command name, message pattern, action/shortcut/view constraints), type guards (`onlyActions`, `onlyCommands`, etc.), `ignoreSelf`, and `autoAcknowledge`.
81+
82+
### Listener Methods
83+
84+
| Method | Description | Must `ack()`? |
85+
|--------|-------------|---------------|
86+
| `app.event(type, fn)` | Events API events | No |
87+
| `app.message([pattern,] fn)` | Message events (optional string/RegExp filter) | No |
88+
| `app.action(constraints, fn)` | Block Kit interactive actions (buttons, selects, etc.) | Yes |
89+
| `app.command(name, fn)` | Slash commands | Yes |
90+
| `app.shortcut(constraints, fn)` | Global and message shortcuts | Yes |
91+
| `app.view(constraints, fn)` | Modal view_submission / view_closed | Yes |
92+
| `app.options(constraints, fn)` | External data source requests | Yes |
93+
| `app.function(callbackId, fn)` | Custom workflow function executions | Auto-acknowledged |
94+
95+
### Listener Arguments
96+
97+
Listeners receive a single object with these properties (availability depends on event type):
98+
99+
- `payload` / type-specific alias (`event`, `action`, `command`, `shortcut`, `view`, `options`, `message`) -- The incoming event data
100+
- `say` -- Send a message to the associated channel
101+
- `ack` -- Acknowledge receipt of the event (required for interactive events within 3 seconds)
102+
- `respond` -- Respond via `response_url`
103+
- `client` -- Pre-authorized Web API client
104+
- `context` -- Event metadata and authorization info
105+
- `body` -- Full request body from Slack
106+
- `complete` / `fail` -- Workflow function completion (for `app.function()`)
107+
108+
### Authorization
109+
110+
- **Single workspace:** Provide `token` in `AppOptions` -- used for all events.
111+
- **Multi-workspace:** Provide an `authorize` function that receives `AuthorizeSourceData` (teamId, enterpriseId, userId, conversationId, isEnterpriseInstall) and returns `AuthorizeResult` (botToken, userToken, botId, botUserId, etc.).
112+
- OAuth support via `@slack/oauth` -- configure `clientId`, `clientSecret`, `stateSecret`, `scopes`, `installationStore` in `AppOptions`.
113+
114+
## Code Conventions
115+
116+
- **TypeScript** throughout. Compiler options in `tsconfig.json` (extends `@tsconfig/node18`, CommonJS output).
117+
- **Biome** for formatting and linting. Configuration in `biome.json`.
118+
- **Testing:** See the Testing section below for test frameworks and conventions.
119+
120+
## Critical Rules
121+
122+
1. **Use Biome exclusively** -- never ESLint or Prettier. Config is in `biome.json`.
123+
2. **Run `npm test` before submitting** -- this runs the full pipeline (build + lint + types + coverage).
124+
3. **Follow existing patterns** -- when adding new listener types, middleware, or receivers, match the structure and style of existing implementations.
125+
4. **Don't duplicate `package.json` values** -- reference it for versions, engines, and dependency lists.
126+
5. **Don't add `WorkflowStep` code** -- it is deprecated. Use `CustomFunction` and `app.function()` instead.
127+
6. **Build before running unit tests directly** -- `npm test` handles this automatically, but `npm run test:unit` requires a build to exist first.
128+
7. **Keep the Receiver abstraction clean** -- receivers should only handle transport concerns (ingesting events, sending ack responses). Business logic belongs in middleware and listeners.
129+
8. **Prefer middleware for cross-cutting concerns** -- authorization, logging, validation, and feature-level request handling (like `Assistant`) all use the middleware pattern.
130+
9. **TypeScript types are part of the API** -- changes to exported types are breaking changes. Add type tests for new public types.
131+
10. **Every listener type needs four things:** type definitions, built-in middleware matchers, an App method, and tests.
132+
133+
## Adding a New Listener Type
134+
135+
This is one of the more complex contribution patterns. Follow these steps:
136+
137+
1. **Define types** in `src/types/` -- create the event-specific middleware args interface (see existing patterns in `src/types/actions/`, `src/types/events/`, etc.).
138+
2. **Add built-in middleware matchers** in `src/middleware/builtin.ts` -- create a constraint-matching function and a type guard (e.g., `onlyMyType`).
139+
3. **Add the listener method** in `src/App.ts` -- follow the pattern of existing methods like `action()`, `command()`, etc. Wire up the middleware matchers and register listeners.
140+
4. **Export types** from `src/types/index.ts` and `src/index.ts`.
141+
5. **Add unit tests** in `test/unit/` mirroring the source structure.
142+
6. **Add type tests** in `test/types/` using tsd.
143+
144+
## Adding Middleware
145+
146+
1. Implement the middleware function with signature `(args: MiddlewareArgs & AllMiddlewareArgs) => Promise<void>`. Call `await next()` to continue the chain.
147+
2. For built-in middleware, add to `src/middleware/builtin.ts` and export from `src/middleware/`.
148+
3. For complex middleware (like `Assistant`), create a dedicated file in `src/` with a class that provides a `getMiddleware()` method returning the middleware function.
149+
4. Register in the App's middleware chain in `src/App.ts` where the default middleware is assembled.
150+
5. Add tests in `test/unit/middleware/`.
151+
152+
## Testing
153+
154+
### Test Structure
155+
156+
Tests mirror the source directory structure:
157+
158+
```text
159+
test/unit/
160+
App/ # App class tests
161+
middleware/ # Middleware tests
162+
receivers/ # Receiver tests
163+
helpers/ # Helper function tests
164+
Assistant.spec.ts
165+
CustomFunction.spec.ts
166+
conversation-store.spec.ts
167+
...
168+
test/types/ # tsd type tests
169+
```
170+
171+
### Test Conventions
172+
173+
- **Test files** use `*.spec.ts` suffix
174+
- **Assertions** use chai (`expect`, `assert`)
175+
- **Mocking** uses sinon (`stub`, `spy`, `fake`) and proxyquire for module-level dependency replacement
176+
- **Test config** in `test/unit/.mocharc.json`
177+
- **Where to put new tests:** Mirror the source structure. For `src/Foo.ts`, add `test/unit/Foo.spec.ts`. For `src/receivers/Bar.ts`, add `test/unit/receivers/Bar.spec.ts`.
178+
179+
### CI
180+
181+
CI configuration is in `.github/workflows/ci-build.yml`. Tests run across multiple Node.js versions on every push to `main` and every PR. Coverage is uploaded to Codecov.
182+
183+
## Security Considerations
184+
185+
- **Request signature verification:** The built-in receivers validate `x-slack-signature` and `x-slack-request-timestamp` on every incoming HTTP request using `tsscmp` for timing-safe comparison. Never disable `signatureVerification` in production.
186+
- **Tokens and secrets:** `SLACK_SIGNING_SECRET`, `SLACK_BOT_TOKEN`, and `SLACK_APP_TOKEN` must come from environment variables. Never hardcode or commit secrets.
187+
- **Authorization middleware:** Verifies tokens and injects an authorized `WebClient` into the listener context. Do not bypass authorization.
188+
- **Tests:** Always use mock/stub values for tokens and secrets. Never use real credentials in tests.

0 commit comments

Comments
 (0)