* ci(release): pin changesets/action and enable npm provenance
Pin changesets/action to the v1.7.0 commit SHA, switch to GitHub-API
commit mode (signed commits via the API), set the version PR commit
and title to a conventional "chore(release): version packages", and
enable npm provenance attestations on publish via NPM_CONFIG_PROVENANCE.
* chore: add CODEOWNERS
Default ownership goes to @vercel/chat-sdk; release-plumbing paths
(release workflow, changeset config, CODEOWNERS itself) stay locked
to @cramforce since the publish workflow is bound to npm Trusted
Publisher by filename.
* docs: add SUPPORT.md and tidy issue contact links
Add a SUPPORT.md pointing users to docs, the issue chooser, and the
security advisory flow. Also update .github/config.yml: point the
Documentation contact link at chat-sdk.dev/docs (was a github.com
README anchor) and remove the GitHub Discussions entry, which 404s
because Discussions isn't enabled on the repo.
* chore: add docs issue and adapter request templates
Two new issue templates so reports come in pre-shaped:
- Documentation Issue — page/section, type (typo, outdated, missing,
broken link, etc.), description, suggested fix.
- Adapter Request — platform name, adapter type (platform/state), API
docs link, use case, existing community work, willingness to help
maintain.
* docs(contributing): point contributors at issue templates and SUPPORT.md
Add a "Reporting issues" section at the top of CONTRIBUTING.md that
links to the issue chooser (now covering bugs, features, docs issues,
and adapter requests) and to SUPPORT.md for general questions, with
the SECURITY.md private-disclosure path called out separately.
* chore: add pre-merge checklist to PR template
Adds four self-attestation boxes contributors can tick before
requesting review, surfacing requirements that already live in
CONTRIBUTING.md so they're not forgotten:
- Signed and verified commits (CONTRIBUTING explicitly bounces PRs
with unsigned commits).
- `pnpm validate` passes (lint, typecheck, tests, build in one go).
- Changeset added when a package's behavior changes.
- Docs updated for user-facing changes.
The "or N/A" wording on the last two avoids forcing a yes for
internal-only or docs-only PRs.
* chore: add Telegram and WhatsApp to bug report platform dropdown
The bug report platform dropdown was missing Telegram and WhatsApp,
which both have official adapters (@chat-adapter/telegram and
@chat-adapter/whatsapp). Reporters had to fall back to "Other" for
bugs in those adapters, losing the platform signal.
* docs(readme): fix CONTRIBUTING link path and add Support section
The Contributing section linked to ./CONTRIBUTING.md, but the file
actually lives at .github/CONTRIBUTING.md, so the link 404'd on
github.com. Repoint it.
Also add a Support section linking SUPPORT.md (general help) and
SECURITY.md (private vulnerability reporting) so those community
health files are reachable from the repo entry point instead of
only via GitHub's auto-surfacing.
* docs(contributing): add adapter authoring, commit conventions, and docs sections
Three additions to CONTRIBUTING.md to round out the file alongside
the recently added issue templates and PR checklist:
- "Building your own adapter" — points contributors who hit the
Adapter Request template at the existing community-adapter guide
on chat-sdk.dev rather than leaving them to discover it.
- "Commit messages" — codifies the Conventional Commits style the
repo already uses; the release workflow now relies on the
"chore(release): version packages" convention for its auto-PR,
so consistency in new commits keeps changelogs predictable.
- "Updating documentation" — names the apps/docs/content/docs/
source path, links the live site, and shows the local preview
command so the PR-template "Documentation updated" checkbox is
actionable.
* docs: trim agent docs, rename CLAUDE.md to AGENTS.md, add CLAUDE.md pointer
Move the agent guidance to AGENTS.md (the cross-tool convention) and
leave CLAUDE.md as a one-line "@AGENTS.md" pointer so Claude Code
keeps auto-loading the same content.
While renaming, trim and update the file:
- "packages/chat-sdk" was wrong — directory is "packages/chat", npm
name is "chat".
- Updated the package list to include adapter-{discord,telegram,
github,linear,zoom,shared}, state-{ioredis,pg}, integration-tests,
and the apps/docs and examples/nextjs-chat trees.
- Replaced the verbose recording-and-replay jq walkthrough with a
one-line pointer to the integration-tests README.
- Dropped the duplicated Changesets walkthrough — full guidance now
lives in CONTRIBUTING.md.
- Condensed ~120 lines of generic Ultracite/Biome rules to a short
list of non-obvious gotchas (Biome enforces the rest automatically).
- Added Conventional Commits (load-bearing for the release workflow's
auto-PR), the apps/docs/content/docs/ docs path with the "pnpm
--filter docs dev" preview command, a pointer to the community
health files, and POSTGRES_URL/DATABASE_URL for the new state-pg
adapter.
Net: 344 → ~125 lines.
* docs(nav): rename "Source" link to "GitHub"
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
6.4 KiB
CLAUDE.md
Guidance for Claude Code (claude.ai/code) when working in this repository.
Build commands
pnpm install
pnpm build # Build all packages (Turborepo)
pnpm typecheck # Type-check all packages
pnpm check # Lint and format check (ultracite/biome)
pnpm fix # Auto-fix lint/format issues
pnpm knip # Check for unused exports/dependencies
pnpm test # Run all tests
pnpm validate # knip + check + typecheck + test + build. ALWAYS run before declaring a task done.
pnpm dev # Watch mode
# Per-package
pnpm --filter chat test
pnpm --filter @chat-adapter/slack build
pnpm --filter docs dev # Preview the docs site (chat-sdk.dev) locally
Code style
- Install dependencies with
pnpm add, not by editingpackage.jsonby hand. sample-messages.mdfiles in adapter packages contain real-world webhook logs — useful when writing parsers or fixtures.- Commits must be signed and verified — see
.github/CONTRIBUTING.md. - We follow Conventional Commits (
feat:,fix:,docs:,chore:, optionally scoped). The release workflow's auto-PR useschore(release): version packages— don't reuse that exact subject for unrelated commits. - See the Ultracite section at the bottom for the in-code style rules Biome doesn't catch automatically.
Architecture
pnpm monorepo, Turborepo orchestrated. All packages are ESM ("type": "module"), TypeScript, bundled with tsup.
Packages
packages/chat— core SDK (chatnpm package):Chatclass, types, mdast-based markdown utilitiespackages/adapter-{slack,teams,gchat,discord,telegram,whatsapp,github,linear,zoom}— platform adapterspackages/adapter-shared— utilities shared across adapterspackages/state-{memory,redis,ioredis,pg}— state adapterspackages/integration-tests— integration tests against real platform APIsapps/docs— fumadocs-based docs site (chat-sdk.dev)examples/nextjs-chat— example Next.js app
Core concepts
- Chat (
packages/chat/src/chat.ts) — main entry point; coordinates adapters and handlers. - Adapter — platform-specific implementation: webhook verification + parsing, normalized format conversion,
FormatConverterfor markdown ↔ platform AST. - StateAdapter — persistence for subscriptions, distributed locks, key/value cache, lists, and queues.
- Thread — conversation thread with
post(),subscribe(),startTyping(),setState(), etc. - Message — normalized message:
text,formatted(mdast AST),raw(platform-specific).
Thread ID format
{adapter}:{channel}:{thread} — e.g. slack:C123ABC:1234567890.123456. Some adapters base64-encode IDs that contain delimiters (Teams, Google Chat).
Webhook flow
- Platform →
/api/webhooks/{platform} - Adapter verifies, parses, calls
chat.handleIncomingMessage() Chatacquires a thread lock, then routes toonSubscribedMessage,onNewMention, oronNewMessagehandlers depending on context.- Handler receives
ThreadandMessage.
Formatting
Messages use mdast as the canonical format. Each adapter's FormatConverter provides:
toAst(platformText)— platform → mdastfromAst(ast)— mdast → platformrenderPostable(message)—PostableMessage→ platform string
Testing
packages/chat/src/mock-adapter.ts exports test utilities:
createMockAdapter(name)—Adapterwithvi.fn()mockscreateMockState()— in-memory subscriptions/locks/cachecreateTestMessage(id, text, overrides?)mockLogger
For production-traffic-driven testing, see packages/integration-tests/fixtures/replay/README.md (recording / export / replay workflow). Recordings are tagged with the deployed git SHA and exported via pnpm recording:list / pnpm recording:export <session-id> from examples/nextjs-chat.
Documentation
User-facing docs live in apps/docs/content/docs/ (rendered at chat-sdk.dev/docs). When changing behavior, public APIs, or env vars, update the relevant page in the same PR. Preview locally with pnpm --filter docs dev.
Releases
Uses Changesets with fixed versioning (every package shares one version). Every PR that changes a package's behavior must include a changeset (pnpm changeset). Full rules in .github/CONTRIBUTING.md.
Environment variables
Key env vars (see turbo.json for the full list):
SLACK_BOT_TOKEN,SLACK_SIGNING_SECRETTEAMS_APP_ID,TEAMS_APP_PASSWORD,TEAMS_APP_TENANT_IDGOOGLE_CHAT_CREDENTIALSorGOOGLE_CHAT_USE_ADCWHATSAPP_ACCESS_TOKEN,WHATSAPP_APP_SECRET,WHATSAPP_PHONE_NUMBER_ID,WHATSAPP_VERIFY_TOKENREDIS_URL— Redis state adapterPOSTGRES_URL/DATABASE_URL— PostgreSQL state adapterBOT_USERNAME— default bot username
Community health files
.github/CONTRIBUTING.md— dev setup, signed commits, conventional commits, changesets, docs preview, building your own adapter.github/SUPPORT.md— where to send help/usage questions.github/SECURITY.md— private vulnerability reporting.github/ISSUE_TEMPLATE/— bug, feature, docs, and adapter-request templates.github/CODEOWNERS—@vercel/chat-sdkowns everything; release plumbing is locked to@cramforce
Ultracite code standards
This project uses Ultracite (Biome-based). pnpm check / pnpm fix run it across the monorepo. Most issues auto-fix.
Beyond what Biome enforces:
- Type safety — prefer
unknownoverany;as constfor literals; named constants over magic numbers. - Modern JS/TS —
for...ofover.forEach;?.and??;constby default; template literals; destructure. - Async — always
awaitreturned promises; no async Promise executors. - React — function components only; hooks at top level; stable
keys (prefer IDs over indices); no components defined inside other components; semantic HTML and ARIA;<Image>over<img>; ref-as-prop in React 19+. - Errors — throw
Errorobjects with descriptive messages; early returns over nested conditionals; noconsole.log/debugger/alertin shipped code. - Performance — top-level regex literals; no spread-in-accumulator loops; specific imports over barrel files.
- Security —
rel="noopener"ontarget="_blank"; avoiddangerouslySetInnerHTML; nevereval()or assign todocument.cookie.