Skip to content

Commit 57f4f22

Browse files
chore: add an AGENTS.md (#2528)
Co-authored-by: Eden Zimbelman <eden.zimbelman@salesforce.com>
1 parent ba92b3d commit 57f4f22

File tree

4 files changed

+362
-0
lines changed

4 files changed

+362
-0
lines changed

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

AGENTS.md

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
# AGENTS.md — node-slack-sdk
2+
3+
Instructions for AI coding agents working on this repository.
4+
5+
## Project Overview
6+
7+
- **Repository**: https://github.com/slackapi/node-slack-sdk
8+
- **Documentation**: https://docs.slack.dev/tools/node-slack-sdk/
9+
- **Monorepo** managed with npm workspaces, TypeScript-first
10+
- Publishes multiple `@slack/*` packages to npm
11+
12+
## Package Architecture
13+
14+
| Package | Folder | Description |
15+
|---------|--------|-------------|
16+
| [`@slack/web-api`](https://www.npmjs.com/package/@slack/web-api) | `packages/web-api` | Core Web API client (most complex package) |
17+
| [`@slack/types`](https://www.npmjs.com/package/@slack/types) | `packages/types` | Shared Slack platform TypeScript types (Block Kit, events, etc.) |
18+
| [`@slack/logger`](https://www.npmjs.com/package/@slack/logger) | `packages/logger` | Logging utility used by other packages |
19+
| [`@slack/webhook`](https://www.npmjs.com/package/@slack/webhook) | `packages/webhook` | Incoming webhook client |
20+
| [`@slack/oauth`](https://www.npmjs.com/package/@slack/oauth) | `packages/oauth` | OAuth flow handling and token management |
21+
| [`@slack/socket-mode`](https://www.npmjs.com/package/@slack/socket-mode) | `packages/socket-mode` | WebSocket-based real-time event client |
22+
| [`@slack/cli-hooks`](https://www.npmjs.com/package/@slack/cli-hooks) | `packages/cli-hooks` | CLI integration hooks for Slack CLI |
23+
24+
Additional internal packages: `cli-test` (test utilities), `rtm-api` (legacy RTM client).
25+
26+
### Dependency Graph (Build Order)
27+
28+
```txt
29+
Independent (no internal deps): cli-hooks, cli-test
30+
Base: logger, types
31+
Depends on base: web-api, webhook
32+
Depends on web-api: oauth, rtm-api, socket-mode
33+
```
34+
35+
Build packages in this order — a package can only be built after its dependencies.
36+
37+
## Build System
38+
39+
```bash
40+
# Install all dependencies from the repo root
41+
npm install
42+
43+
# Lint all packages (Biome)
44+
npm run lint
45+
npm run lint:fix
46+
47+
# Build a specific package
48+
npm run build --workspace=packages/web-api
49+
50+
# Test a specific package
51+
npm test --workspace=packages/web-api
52+
```
53+
54+
### Full Build Order (from CI)
55+
56+
```bash
57+
# 1. No internal dependencies
58+
npm run build --workspace=@slack/cli-hooks
59+
npm run build --workspace=@slack/cli-test
60+
61+
# 2. Base dependencies
62+
npm run build --workspace=@slack/logger
63+
npm run build --workspace=@slack/types
64+
65+
# 3. Packages requiring base dependencies
66+
npm run build --workspace=@slack/web-api
67+
npm run build --workspace=@slack/webhook
68+
69+
# 4. Packages depending on web-api
70+
npm run build --workspace=@slack/oauth
71+
npm run build --workspace=@slack/rtm-api
72+
npm run build --workspace=@slack/socket-mode
73+
```
74+
75+
## Critical Rules
76+
77+
1. **Never manually edit `packages/web-api/src/types/response/*.ts`** — these files are auto-generated by `scripts/generate-web-api-types.sh`. They contain a "DO NOT EDIT" banner.
78+
2. **Request types ARE manually maintained**`packages/web-api/src/types/request/` is hand-written code; edit these responsibly.
79+
3. **Build packages in dependency order** — see the dependency graph above.
80+
4. **Use Biome**, not ESLint or Prettier — config is in `biome.json` at repo root.
81+
5. **TypeScript 5.9.3**, Node 18+.
82+
83+
## Code Conventions
84+
85+
- **Formatting**: configured in `biome.json`
86+
- **Test files**: `*.spec.ts` using Mocha + chai + sinon; coverage via c8
87+
- **Type tests**: `*.test-d.ts` using tsd
88+
- **Naming conventions for request/response types**:
89+
- Request: `{Namespace}{Action}Arguments` (e.g., `ChatPostMessageArguments`)
90+
- Response: `{Namespace}{Action}Response` (e.g., `ChatPostMessageResponse`)
91+
- **Method names**: camelCase matching the Slack API method (e.g., `chat.postMessage``postMessage`)
92+
93+
## Adding a New Slack API Method
94+
95+
This is the most common contribution. Follow these steps in order.
96+
97+
### Step 1: Look Up the API Method Documentation
98+
99+
Reference: `https://docs.slack.dev/reference/methods/{method.name}`
100+
101+
For example, for `chat.appendStream`: https://docs.slack.dev/reference/methods/chat.appendStream
102+
103+
### Step 2: Generate Response Types
104+
105+
Run the generation script from the repo root:
106+
107+
```bash
108+
bash scripts/generate-web-api-types.sh
109+
```
110+
111+
This script:
112+
113+
1. Clones/updates `slackapi/java-slack-sdk` into `tmp/java-slack-sdk`
114+
2. Reads JSON response samples from `tmp/java-slack-sdk/json-logs/samples/api/`
115+
3. Runs `scripts/code_generator.rb` which uses quicktype to generate TypeScript types
116+
4. Outputs `*Response.ts` files to `packages/web-api/src/types/response/`
117+
5. Regenerates `packages/web-api/src/types/response/index.ts`
118+
6. Runs `npm run lint:fix` on the generated files
119+
120+
**Prerequisites**: Ruby and npm must be installed.
121+
122+
Generated response types look like this (example: `ChatAppendStreamResponse.ts`):
123+
124+
```typescript
125+
import type { WebAPICallResult } from '../../WebClient';
126+
export type ChatAppendStreamResponse = WebAPICallResult & {
127+
channel?: string;
128+
error?: string;
129+
needed?: string;
130+
ok?: boolean;
131+
provided?: string;
132+
ts?: string;
133+
};
134+
```
135+
136+
All generated files extend `WebAPICallResult` and have all properties optional.
137+
138+
**Note**: If the JSON sample doesn't exist yet in `java-slack-sdk`, the API method has not been added to that project yet. The maintainers need to add it there first before it can be added here.
139+
140+
### Step 3: Add Request Argument Types
141+
142+
File: `packages/web-api/src/types/request/<namespace>.ts`
143+
144+
Create an interface/type for the method's arguments. Reuse mixins from `packages/web-api/src/types/request/common.ts`:
145+
146+
| Mixin | Purpose |
147+
|-------|---------|
148+
| `TokenOverridable` | Optional `token` override |
149+
| `CursorPaginationEnabled` | `cursor` + `limit` pagination |
150+
| `TimelinePaginationEnabled` | `oldest` + `latest` + `inclusive` pagination |
151+
| `TraditionalPagingEnabled` | `count` + `page` pagination |
152+
| `OptionalTeamAssignable` | Optional `team_id` |
153+
| `LocaleAware` | Optional `include_locale` |
154+
155+
Also reuse namespace-specific mixins from the same file (e.g., `Channel`, `ChannelAndTS`, `AsUser` in `chat.ts`).
156+
157+
**Example**`ChatAppendStreamArguments` from `packages/web-api/src/types/request/chat.ts`:
158+
159+
```typescript
160+
export interface ChatAppendStreamArguments extends TokenOverridable, ChannelAndTS, Partial<MarkdownText> {
161+
/**
162+
* @description An array of chunk objects to append to the stream.
163+
* Either `markdown_text` or `chunks` is required.
164+
*/
165+
chunks?: AnyChunk[];
166+
}
167+
```
168+
169+
### Step 4: Export Request Types
170+
171+
File: `packages/web-api/src/types/request/index.ts`
172+
173+
Add the new type to the appropriate export block:
174+
175+
```typescript
176+
export type {
177+
ChatAppendStreamArguments,
178+
ChatStartStreamArguments,
179+
ChatStopStreamArguments,
180+
// ... existing exports
181+
} from './chat';
182+
```
183+
184+
### Step 5: Add Method Binding
185+
186+
File: `packages/web-api/src/methods.ts`
187+
188+
1. Import the argument and response types at the top of the file.
189+
2. Add a method binding in the appropriate namespace object of the `Methods` class.
190+
191+
**Import pattern**:
192+
193+
```typescript
194+
// Request types are imported from the request index barrel
195+
import type {
196+
ChatAppendStreamArguments,
197+
// ...
198+
} from './types/request';
199+
200+
// Response types are imported from individual files
201+
import type { ChatAppendStreamResponse } from './types/response/ChatAppendStreamResponse';
202+
```
203+
204+
**Note**: Request types are imported from the barrel `./types/request` (already grouped by namespace), but response types are imported from their individual files (e.g., `./types/response/ChatAppendStreamResponse`).
205+
206+
**Binding pattern** — within the appropriate namespace object in the `Methods` class:
207+
208+
```typescript
209+
public readonly chat = {
210+
/**
211+
* @description Appends text to an existing streaming conversation.
212+
* @see {@link https://docs.slack.dev/reference/methods/chat.appendStream `chat.appendStream` API reference}.
213+
*/
214+
appendStream: bindApiCall<ChatAppendStreamArguments, ChatAppendStreamResponse>(this, 'chat.appendStream'),
215+
// ...
216+
};
217+
```
218+
219+
**`bindApiCall` vs `bindApiCallWithOptionalArgument`**:
220+
221+
- `bindApiCall` — for methods with **required** arguments (most methods)
222+
- `bindApiCallWithOptionalArgument` — for methods where **all arguments are optional**
223+
224+
### Step 6: Add Type Tests
225+
226+
File: `packages/web-api/test/types/methods/<namespace>.test-d.ts`
227+
228+
Add both sad path (should error) and happy path (should compile) tests:
229+
230+
```typescript
231+
import { expectAssignable, expectError } from 'tsd';
232+
import { WebClient } from '../../../src/WebClient';
233+
234+
const web = new WebClient('TOKEN');
235+
236+
// chat.appendStream
237+
// -- sad path
238+
expectError(web.chat.appendStream()); // lacking argument
239+
expectError(web.chat.appendStream({})); // empty argument
240+
expectError(
241+
web.chat.appendStream({
242+
channel: 'C1234', // missing ts and markdown_text
243+
}),
244+
);
245+
246+
// -- happy path
247+
expectAssignable<Parameters<typeof web.chat.appendStream>>([
248+
{
249+
channel: 'C1234',
250+
ts: '1234.56',
251+
markdown_text: 'hello',
252+
},
253+
]);
254+
```
255+
256+
### Summary Checklist
257+
258+
- [ ] Looked up method docs at `https://docs.slack.dev/reference/methods/{method.name}`
259+
- [ ] Generated response types via `scripts/generate-web-api-types.sh` (or created manually if JSON sample unavailable)
260+
- [ ] Added request argument type in `packages/web-api/src/types/request/<namespace>.ts`
261+
- [ ] Exported new request type from `packages/web-api/src/types/request/index.ts`
262+
- [ ] Imported argument + response types in `packages/web-api/src/methods.ts`
263+
- [ ] Added method binding with `bindApiCall` in appropriate namespace in `packages/web-api/src/methods.ts`
264+
- [ ] Added sad/happy path type tests in `packages/web-api/test/types/methods/<namespace>.test-d.ts`
265+
- [ ] Verified: `npm test --workspace=packages/web-api`
266+
267+
## Code Generation Details
268+
269+
### `scripts/generate-web-api-types.sh`
270+
271+
Entry point for response type generation. It:
272+
273+
1. Clones or pulls `slackapi/java-slack-sdk` into `tmp/`
274+
2. Runs `npm install` in `scripts/` to install quicktype
275+
3. Executes `scripts/code_generator.rb`
276+
4. Runs `npm run lint:fix` on `packages/web-api`
277+
278+
## Testing
279+
280+
- **Unit tests**: Mocha + chai + sinon (`*.spec.ts` files), coverage via c8
281+
- **Type tests**: tsd (`*.test-d.ts` files in `packages/web-api/test/types/`)
282+
- **Integration tests**: CommonJS, ESM, and TypeScript compatibility checks
283+
- **CI matrix**: Node 18.x, 20.x, 22.x on Ubuntu + Windows
284+
285+
Per-package test commands:
286+
287+
```bash
288+
npm test --workspace=packages/web-api # all tests (types + integration + unit)
289+
npm run test:unit --workspace=packages/web-api
290+
npm run test:types --workspace=packages/web-api
291+
```
292+
293+
## Web API Client Architecture
294+
295+
`packages/web-api/src/WebClient.ts`:
296+
297+
- Extends the `Methods` class (which defines all API method bindings in `methods.ts`)
298+
- Uses Axios for HTTP requests
299+
- `p-queue` for request concurrency control
300+
- `p-retry` for automatic retries with backoff
301+
- Built-in cursor pagination via `paginate()`
302+
- Streaming support via `chatStream()` using `ChatStreamer`
303+
- Rate limiting with emitted events
304+
305+
## Common Pitfalls
306+
307+
- **Don't edit generated response types** — use `scripts/generate-web-api-types.sh` instead. Look for the "DO NOT EDIT" banner.
308+
- **Build in dependency order** — building `web-api` before `logger` and `types` will fail.
309+
- **Use Biome, not ESLint/Prettier** — this repo uses Biome exclusively (`biome.json`).
310+
- **Biome overrides exist for generated code**`packages/web-api/src/types/response/**/*.ts` has relaxed rules (`noBannedTypes: off`, `noExplicitAny: off`).
311+
- **Import organization is disabled** for `packages/web-api/src/index.ts` in Biome config.
312+
- **Response type imports use individual files**, not the barrel — e.g., `import type { ChatPostMessageResponse } from './types/response/ChatPostMessageResponse'`.
313+
314+
## Development Philosophy
315+
316+
- **Follow existing patterns exactly** — when adding a new method, match the style of adjacent methods.
317+
- **Reuse mixins** from `common.ts` and namespace-specific files rather than duplicating field definitions.
318+
- **Every API method needs four things**: request type, response type, method binding, and type tests.
319+
- **Naming conventions**: PascalCase for types (`ChatPostMessageArguments`), camelCase for methods (`postMessage`).
320+
- **JSDoc on method bindings**: Always include `@description` and `@see` with a link to the API reference.

0 commit comments

Comments
 (0)