-
Notifications
You must be signed in to change notification settings - Fork 675
chore: add an AGENTS.md #2528
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: add an AGENTS.md #2528
Changes from all commits
1fa07cd
3d96cc7
968fa49
5745f14
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| CLAUDE.local.md | ||
| settings.local.json | ||
| worktrees/ | ||
| plans/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| @../AGENTS.md |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| { | ||
| "permissions": { | ||
| "allow": [ | ||
| "Bash(echo:*)", | ||
| "Bash(gh issue view:*)", | ||
| "Bash(gh label list:*)", | ||
| "Bash(gh pr checks:*)", | ||
| "Bash(gh pr diff:*)", | ||
| "Bash(gh pr list:*)", | ||
| "Bash(gh pr status:*)", | ||
| "Bash(gh pr update-branch:*)", | ||
| "Bash(gh pr view:*)", | ||
| "Bash(gh search code:*)", | ||
| "Bash(git diff:*)", | ||
| "Bash(git grep:*)", | ||
| "Bash(git log:*)", | ||
| "Bash(git show:*)", | ||
| "Bash(git status:*)", | ||
| "Bash(grep:*)", | ||
| "Bash(ls:*)", | ||
| "Bash(node --version:*)", | ||
| "Bash(npm --version:*)", | ||
| "Bash(npm config:*)", | ||
| "Bash(npm install)", | ||
| "Bash(npm install:*)", | ||
| "Bash(npm run build:*)", | ||
| "Bash(npm run lint:*)", | ||
| "Bash(npm run lint:fix:*)", | ||
| "Bash(npm test:*)", | ||
| "Bash(tree:*)", | ||
| "WebFetch(domain:docs.slack.dev)", | ||
| "WebFetch(domain:github.com)", | ||
| "WebFetch(domain:npmjs.com)", | ||
| "WebFetch(domain:raw.githubusercontent.com)" | ||
| ] | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,320 @@ | ||
| # AGENTS.md — node-slack-sdk | ||
|
|
||
| Instructions for AI coding agents working on this repository. | ||
|
|
||
| ## Project Overview | ||
|
|
||
| - **Repository**: https://github.com/slackapi/node-slack-sdk | ||
| - **Documentation**: https://docs.slack.dev/tools/node-slack-sdk/ | ||
| - **Monorepo** managed with npm workspaces, TypeScript-first | ||
| - Publishes multiple `@slack/*` packages to npm | ||
|
|
||
| ## Package Architecture | ||
|
|
||
| | Package | Folder | Description | | ||
| |---------|--------|-------------| | ||
| | [`@slack/web-api`](https://www.npmjs.com/package/@slack/web-api) | `packages/web-api` | Core Web API client (most complex package) | | ||
| | [`@slack/types`](https://www.npmjs.com/package/@slack/types) | `packages/types` | Shared Slack platform TypeScript types (Block Kit, events, etc.) | | ||
| | [`@slack/logger`](https://www.npmjs.com/package/@slack/logger) | `packages/logger` | Logging utility used by other packages | | ||
| | [`@slack/webhook`](https://www.npmjs.com/package/@slack/webhook) | `packages/webhook` | Incoming webhook client | | ||
| | [`@slack/oauth`](https://www.npmjs.com/package/@slack/oauth) | `packages/oauth` | OAuth flow handling and token management | | ||
| | [`@slack/socket-mode`](https://www.npmjs.com/package/@slack/socket-mode) | `packages/socket-mode` | WebSocket-based real-time event client | | ||
| | [`@slack/cli-hooks`](https://www.npmjs.com/package/@slack/cli-hooks) | `packages/cli-hooks` | CLI integration hooks for Slack CLI | | ||
|
|
||
| Additional internal packages: `cli-test` (test utilities), `rtm-api` (legacy RTM client). | ||
|
|
||
| ### Dependency Graph (Build Order) | ||
|
|
||
| ```txt | ||
| Independent (no internal deps): cli-hooks, cli-test | ||
| Base: logger, types | ||
| Depends on base: web-api, webhook | ||
| Depends on web-api: oauth, rtm-api, socket-mode | ||
| ``` | ||
|
|
||
| Build packages in this order — a package can only be built after its dependencies. | ||
|
|
||
| ## Build System | ||
|
|
||
| ```bash | ||
| # Install all dependencies from the repo root | ||
| npm install | ||
|
|
||
| # Lint all packages (Biome) | ||
| npm run lint | ||
| npm run lint:fix | ||
|
|
||
| # Build a specific package | ||
| npm run build --workspace=packages/web-api | ||
|
|
||
| # Test a specific package | ||
| npm test --workspace=packages/web-api | ||
| ``` | ||
|
|
||
| ### Full Build Order (from CI) | ||
|
|
||
| ```bash | ||
| # 1. No internal dependencies | ||
| npm run build --workspace=@slack/cli-hooks | ||
| npm run build --workspace=@slack/cli-test | ||
|
|
||
| # 2. Base dependencies | ||
| npm run build --workspace=@slack/logger | ||
| npm run build --workspace=@slack/types | ||
|
|
||
| # 3. Packages requiring base dependencies | ||
| npm run build --workspace=@slack/web-api | ||
| npm run build --workspace=@slack/webhook | ||
|
|
||
| # 4. Packages depending on web-api | ||
| npm run build --workspace=@slack/oauth | ||
| npm run build --workspace=@slack/rtm-api | ||
| npm run build --workspace=@slack/socket-mode | ||
| ``` | ||
|
|
||
| ## Critical Rules | ||
|
|
||
| 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. | ||
| 2. **Request types ARE manually maintained** — `packages/web-api/src/types/request/` is hand-written code; edit these responsibly. | ||
| 3. **Build packages in dependency order** — see the dependency graph above. | ||
| 4. **Use Biome**, not ESLint or Prettier — config is in `biome.json` at repo root. | ||
| 5. **TypeScript 5.9.3**, Node 18+. | ||
|
|
||
| ## Code Conventions | ||
|
|
||
| - **Formatting**: configured in `biome.json` | ||
| - **Test files**: `*.spec.ts` using Mocha + chai + sinon; coverage via c8 | ||
| - **Type tests**: `*.test-d.ts` using tsd | ||
| - **Naming conventions for request/response types**: | ||
| - Request: `{Namespace}{Action}Arguments` (e.g., `ChatPostMessageArguments`) | ||
| - Response: `{Namespace}{Action}Response` (e.g., `ChatPostMessageResponse`) | ||
| - **Method names**: camelCase matching the Slack API method (e.g., `chat.postMessage` → `postMessage`) | ||
|
|
||
| ## Adding a New Slack API Method | ||
|
|
||
| This is the most common contribution. Follow these steps in order. | ||
|
|
||
| ### Step 1: Look Up the API Method Documentation | ||
|
|
||
| Reference: `https://docs.slack.dev/reference/methods/{method.name}` | ||
|
|
||
| For example, for `chat.appendStream`: https://docs.slack.dev/reference/methods/chat.appendStream | ||
|
|
||
| ### Step 2: Generate Response Types | ||
|
|
||
| Run the generation script from the repo root: | ||
|
|
||
| ```bash | ||
| bash scripts/generate-web-api-types.sh | ||
| ``` | ||
|
|
||
| This script: | ||
|
|
||
| 1. Clones/updates `slackapi/java-slack-sdk` into `tmp/java-slack-sdk` | ||
| 2. Reads JSON response samples from `tmp/java-slack-sdk/json-logs/samples/api/` | ||
| 3. Runs `scripts/code_generator.rb` which uses quicktype to generate TypeScript types | ||
| 4. Outputs `*Response.ts` files to `packages/web-api/src/types/response/` | ||
| 5. Regenerates `packages/web-api/src/types/response/index.ts` | ||
| 6. Runs `npm run lint:fix` on the generated files | ||
|
|
||
| **Prerequisites**: Ruby and npm must be installed. | ||
|
|
||
| Generated response types look like this (example: `ChatAppendStreamResponse.ts`): | ||
|
|
||
| ```typescript | ||
| import type { WebAPICallResult } from '../../WebClient'; | ||
| export type ChatAppendStreamResponse = WebAPICallResult & { | ||
| channel?: string; | ||
| error?: string; | ||
| needed?: string; | ||
| ok?: boolean; | ||
| provided?: string; | ||
| ts?: string; | ||
| }; | ||
| ``` | ||
|
|
||
| All generated files extend `WebAPICallResult` and have all properties optional. | ||
|
|
||
| **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. | ||
|
|
||
| ### Step 3: Add Request Argument Types | ||
|
|
||
| File: `packages/web-api/src/types/request/<namespace>.ts` | ||
|
|
||
| Create an interface/type for the method's arguments. Reuse mixins from `packages/web-api/src/types/request/common.ts`: | ||
|
|
||
| | Mixin | Purpose | | ||
| |-------|---------| | ||
| | `TokenOverridable` | Optional `token` override | | ||
| | `CursorPaginationEnabled` | `cursor` + `limit` pagination | | ||
| | `TimelinePaginationEnabled` | `oldest` + `latest` + `inclusive` pagination | | ||
| | `TraditionalPagingEnabled` | `count` + `page` pagination | | ||
| | `OptionalTeamAssignable` | Optional `team_id` | | ||
| | `LocaleAware` | Optional `include_locale` | | ||
|
|
||
| Also reuse namespace-specific mixins from the same file (e.g., `Channel`, `ChannelAndTS`, `AsUser` in `chat.ts`). | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📣 note: This is a good practice to continue for now, but I'd be so curious in "flattening" these arguments for each method... |
||
|
|
||
| **Example** — `ChatAppendStreamArguments` from `packages/web-api/src/types/request/chat.ts`: | ||
|
|
||
| ```typescript | ||
| export interface ChatAppendStreamArguments extends TokenOverridable, ChannelAndTS, Partial<MarkdownText> { | ||
| /** | ||
| * @description An array of chunk objects to append to the stream. | ||
| * Either `markdown_text` or `chunks` is required. | ||
| */ | ||
| chunks?: AnyChunk[]; | ||
| } | ||
| ``` | ||
|
|
||
| ### Step 4: Export Request Types | ||
|
|
||
| File: `packages/web-api/src/types/request/index.ts` | ||
|
|
||
| Add the new type to the appropriate export block: | ||
|
|
||
| ```typescript | ||
| export type { | ||
| ChatAppendStreamArguments, | ||
| ChatStartStreamArguments, | ||
| ChatStopStreamArguments, | ||
| // ... existing exports | ||
| } from './chat'; | ||
| ``` | ||
|
|
||
| ### Step 5: Add Method Binding | ||
|
|
||
| File: `packages/web-api/src/methods.ts` | ||
|
|
||
| 1. Import the argument and response types at the top of the file. | ||
| 2. Add a method binding in the appropriate namespace object of the `Methods` class. | ||
|
|
||
| **Import pattern**: | ||
|
|
||
| ```typescript | ||
| // Request types are imported from the request index barrel | ||
| import type { | ||
| ChatAppendStreamArguments, | ||
| // ... | ||
| } from './types/request'; | ||
|
|
||
| // Response types are imported from individual files | ||
| import type { ChatAppendStreamResponse } from './types/response/ChatAppendStreamResponse'; | ||
| ``` | ||
|
|
||
| **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`). | ||
|
|
||
| **Binding pattern** — within the appropriate namespace object in the `Methods` class: | ||
|
|
||
| ```typescript | ||
| public readonly chat = { | ||
| /** | ||
| * @description Appends text to an existing streaming conversation. | ||
| * @see {@link https://docs.slack.dev/reference/methods/chat.appendStream `chat.appendStream` API reference}. | ||
| */ | ||
| appendStream: bindApiCall<ChatAppendStreamArguments, ChatAppendStreamResponse>(this, 'chat.appendStream'), | ||
| // ... | ||
| }; | ||
| ``` | ||
|
|
||
| **`bindApiCall` vs `bindApiCallWithOptionalArgument`**: | ||
|
|
||
| - `bindApiCall` — for methods with **required** arguments (most methods) | ||
| - `bindApiCallWithOptionalArgument` — for methods where **all arguments are optional** | ||
|
|
||
| ### Step 6: Add Type Tests | ||
|
|
||
| File: `packages/web-api/test/types/methods/<namespace>.test-d.ts` | ||
|
|
||
| Add both sad path (should error) and happy path (should compile) tests: | ||
|
|
||
| ```typescript | ||
| import { expectAssignable, expectError } from 'tsd'; | ||
| import { WebClient } from '../../../src/WebClient'; | ||
|
|
||
| const web = new WebClient('TOKEN'); | ||
|
|
||
| // chat.appendStream | ||
| // -- sad path | ||
| expectError(web.chat.appendStream()); // lacking argument | ||
| expectError(web.chat.appendStream({})); // empty argument | ||
| expectError( | ||
| web.chat.appendStream({ | ||
| channel: 'C1234', // missing ts and markdown_text | ||
| }), | ||
| ); | ||
|
|
||
| // -- happy path | ||
| expectAssignable<Parameters<typeof web.chat.appendStream>>([ | ||
| { | ||
| channel: 'C1234', | ||
| ts: '1234.56', | ||
| markdown_text: 'hello', | ||
| }, | ||
| ]); | ||
| ``` | ||
|
|
||
| ### Summary Checklist | ||
|
|
||
| - [ ] Looked up method docs at `https://docs.slack.dev/reference/methods/{method.name}` | ||
| - [ ] Generated response types via `scripts/generate-web-api-types.sh` (or created manually if JSON sample unavailable) | ||
| - [ ] Added request argument type in `packages/web-api/src/types/request/<namespace>.ts` | ||
| - [ ] Exported new request type from `packages/web-api/src/types/request/index.ts` | ||
| - [ ] Imported argument + response types in `packages/web-api/src/methods.ts` | ||
| - [ ] Added method binding with `bindApiCall` in appropriate namespace in `packages/web-api/src/methods.ts` | ||
| - [ ] Added sad/happy path type tests in `packages/web-api/test/types/methods/<namespace>.test-d.ts` | ||
| - [ ] Verified: `npm test --workspace=packages/web-api` | ||
|
|
||
| ## Code Generation Details | ||
|
|
||
| ### `scripts/generate-web-api-types.sh` | ||
|
|
||
| Entry point for response type generation. It: | ||
|
|
||
| 1. Clones or pulls `slackapi/java-slack-sdk` into `tmp/` | ||
| 2. Runs `npm install` in `scripts/` to install quicktype | ||
| 3. Executes `scripts/code_generator.rb` | ||
| 4. Runs `npm run lint:fix` on `packages/web-api` | ||
|
|
||
| ## Testing | ||
|
|
||
| - **Unit tests**: Mocha + chai + sinon (`*.spec.ts` files), coverage via c8 | ||
| - **Type tests**: tsd (`*.test-d.ts` files in `packages/web-api/test/types/`) | ||
| - **Integration tests**: CommonJS, ESM, and TypeScript compatibility checks | ||
| - **CI matrix**: Node 18.x, 20.x, 22.x on Ubuntu + Windows | ||
|
|
||
| Per-package test commands: | ||
|
|
||
| ```bash | ||
| npm test --workspace=packages/web-api # all tests (types + integration + unit) | ||
| npm run test:unit --workspace=packages/web-api | ||
| npm run test:types --workspace=packages/web-api | ||
| ``` | ||
|
|
||
| ## Web API Client Architecture | ||
|
|
||
| `packages/web-api/src/WebClient.ts`: | ||
|
|
||
| - Extends the `Methods` class (which defines all API method bindings in `methods.ts`) | ||
| - Uses Axios for HTTP requests | ||
| - `p-queue` for request concurrency control | ||
| - `p-retry` for automatic retries with backoff | ||
| - Built-in cursor pagination via `paginate()` | ||
| - Streaming support via `chatStream()` using `ChatStreamer` | ||
| - Rate limiting with emitted events | ||
|
|
||
| ## Common Pitfalls | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🌟 praise: These are nice callouts! I might have need this sometimes before... |
||
|
|
||
| - **Don't edit generated response types** — use `scripts/generate-web-api-types.sh` instead. Look for the "DO NOT EDIT" banner. | ||
| - **Build in dependency order** — building `web-api` before `logger` and `types` will fail. | ||
| - **Use Biome, not ESLint/Prettier** — this repo uses Biome exclusively (`biome.json`). | ||
| - **Biome overrides exist for generated code** — `packages/web-api/src/types/response/**/*.ts` has relaxed rules (`noBannedTypes: off`, `noExplicitAny: off`). | ||
| - **Import organization is disabled** for `packages/web-api/src/index.ts` in Biome config. | ||
| - **Response type imports use individual files**, not the barrel — e.g., `import type { ChatPostMessageResponse } from './types/response/ChatPostMessageResponse'`. | ||
|
|
||
| ## Development Philosophy | ||
|
|
||
| - **Follow existing patterns exactly** — when adding a new method, match the style of adjacent methods. | ||
| - **Reuse mixins** from `common.ts` and namespace-specific files rather than duplicating field definitions. | ||
| - **Every API method needs four things**: request type, response type, method binding, and type tests. | ||
| - **Naming conventions**: PascalCase for types (`ChatPostMessageArguments`), camelCase for methods (`postMessage`). | ||
| - **JSDoc on method bindings**: Always include `@description` and `@see` with a link to the API reference. | ||
Uh oh!
There was an error while loading. Please reload this page.