Skip to content

docs: add Signal community adapter - #1118

Open
dVelopment wants to merge 1 commit into
vercel:mainfrom
dVelopment:docs/signal-community-adapter
Open

dVelopment wants to merge 1 commit into
vercel:mainfrom
dVelopment:docs/signal-community-adapter

Conversation

@dVelopment

Copy link
Copy Markdown

Summary

Adds the independently maintained @stibbons/chat-adapter-signal package to the community adapter catalog and chat-sdk.dev.

  • Registers signal in COMMUNITY_ADAPTERS with its npm package, source repository pinned to a commit, and platform feature matrix.
  • Adds a Signal docs page covering signal-cli setup and account provisioning, configuration, the four signal-cli transports, direct messages, groups and mentions, streaming, formatting and cards, attachments, message actions, message history, thread IDs, and limitations.
  • Adds the page to the community adapter navigation and includes a @chat-adapter/catalog changeset, as the add-adapter skill asks for community listings.

The adapter talks to signal-cli, which you install and run yourself, over its JSON-RPC interface: an HTTP daemon, a Unix socket, TCP, or a signal-cli process the adapter spawns. It receives messages over signal-cli's event stream instead of webhooks, so the bot runs as a long-running process. It supports 1:1 and group messages, mentions, attachments in both directions, edits and remote deletes of its own messages, reactions, typing indicators, and read receipts. Streaming is buffered: the adapter shows the typing indicator while the stream runs and posts the answer once. Cards render as formatted text without buttons or select menus, and message history is what Chat records in its state adapter.

#169 proposed a first-party Signal adapter and was closed until Signal offers official support. This PR adds no package to the monorepo. It lists an adapter maintained outside it in the community group, the way Baileys and Zaileys are listed for WhatsApp, and the page opens with a callout that the adapter depends on signal-cli rather than an official Signal API.

The Quick start is a standalone bot.ts without export const bot, because no webhook route imports it (as on the Zaileys page).

Test plan

  • pnpm validate: passes (knip, check, typecheck, all package tests, and build:validate including the docs next build).
  • pnpm --filter @chat-adapter/catalog build and pnpm --filter @chat-adapter/catalog test (53 passed).
  • pnpm --filter @chat-adapter/integration-tests exec vitest run src/docs-adapters.test.ts src/docs-llms.test.ts src/docs-skills.test.ts --coverage=false (662 passed).
  • pnpm --filter create-chat-sdk test (223 passed) and pnpm konsistent (no violations).
  • Opened /adapters/community/signal with pnpm --filter docs dev: the navigation entry, callout, configuration table, and feature matrix render, and /adapters lists Signal.
  • Type-checked the Quick start and openDM snippets with strict TypeScript against the adapter's build at the pinned commit (0.1.0) and chat 4.43.0.
  • Checked every feature value and every claim on the page against the adapter's README and source at the pinned commit.

Checklist

  • All commits are signed and verified
  • All commits are signed off for the DCO (git commit -s)
  • pnpm validate passes
  • Changeset added (or N/A — see CONTRIBUTING.md)
  • Documentation updated (or N/A)

Signed-off-by: Daniel Holzmann <daniel@danielholzmann.com>
@dVelopment
dVelopment requested a review from a team November 4, 2026 12:39
@vercel

vercel Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

@dVelopment is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@bensabic bensabic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thorough listing. I checked the catalog entry and page against the adapter source at the pinned commit (c85ae16) and the Chat core, and the claims I spot-checked hold up (Node >= 24, chat ^4.43, signal-cli 0.14.9 minimum, 64 KiB text limit, 150 MiB attachments, 2-minute typing timeout). The structure follows the add-adapter skill and the frontmatter description matches the catalog entry.

A few small, non-blocking suggestions inline:

  1. imagesInCards is "no", but the adapter renders card images as links, the same way it handles link buttons (which are partial, "Sent as URLs").
  2. The Docker Compose example links point at main while every other adapter-repo link is pinned to the commit.
  3. The chat.openDM() / chat.getUser() note could warn that an ACI matches the UUID format Chat routes to Linear, so it misroutes instead of throwing when Linear is also registered.

I didn't run the test suite locally, and CI on this fork PR hasn't run beyond the security and Socket checks.

tables: { status: "partial", label: "Monospace text" },
charts: { status: "partial", label: "Monospace text" },
fields: { status: "partial", label: "Formatted text" },
imagesInCards: "no",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The adapter does render card images, as links: cardToAst turns card.imageUrl and image children into link paragraphs (src/format.ts at the pinned commit), and the page itself says cards render "images, links, and link buttons as URLs". Matching linkButtons keeps the matrix consistent with the page:

Suggested change
imagesInCards: "no",
imagesInCards: { status: "partial", label: "Sent as URLs" },


## Platform setup

1. Install signal-cli 0.14.9 or newer and provision the bot's Signal account with signal-cli's own CLI, using the data directory the daemon will use. In the [Docker Compose example](https://github.com/stibbons-ai/chat-adapter-signal/tree/main/examples/echo-bot), that means a one-off container on the daemon's volume: `docker compose run --rm signal-cli <arguments>`. The daemon loads accounts only when it starts, so stop a running daemon first and start it again afterwards.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: pin the Docker Compose example to the same commit as the other adapter-repo links, so the setup steps can't drift from what this page describes:

Suggested change
1. Install signal-cli 0.14.9 or newer and provision the bot's Signal account with signal-cli's own CLI, using the data directory the daemon will use. In the [Docker Compose example](https://github.com/stibbons-ai/chat-adapter-signal/tree/main/examples/echo-bot), that means a one-off container on the daemon's volume: `docker compose run --rm signal-cli <arguments>`. The daemon loads accounts only when it starts, so stop a running daemon first and start it again afterwards.
1. Install signal-cli 0.14.9 or newer and provision the bot's Signal account with signal-cli's own CLI, using the data directory the daemon will use. In the [Docker Compose example](https://github.com/stibbons-ai/chat-adapter-signal/tree/c85ae16eb4392f4b0cac81ef04ca8a0c31a4ea2c/examples/echo-bot), that means a one-off container on the daemon's volume: `docker compose run --rm signal-cli <arguments>`. The daemon loads accounts only when it starts, so stop a running daemon first and start it again afterwards.


## Direct messages

`adapter.openDM()` takes an ACI, a phone number such as `+15550001111`, or `u:<username>`, and returns the 1:1 thread ID. signal-cli looks numbers and usernames up on the Signal server, and `openDM()` throws `ResourceNotFoundError` when it finds no ACI for the user. `chat.openDM()` and `chat.getUser()` can't route Signal user IDs to this adapter, so call the adapter directly and open the thread yourself:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth spelling out why, because there's a sharp edge: Chat.inferAdapterFromUserId matches any UUID to Linear (LINEAR_UUID_REGEX in packages/chat/src/chat.ts), and ACIs are UUIDs. Without Linear registered it throws; with Linear registered, chat.openDM(aci) silently goes to the Linear adapter.

Suggested change
`adapter.openDM()` takes an ACI, a phone number such as `+15550001111`, or `u:<username>`, and returns the 1:1 thread ID. signal-cli looks numbers and usernames up on the Signal server, and `openDM()` throws `ResourceNotFoundError` when it finds no ACI for the user. `chat.openDM()` and `chat.getUser()` can't route Signal user IDs to this adapter, so call the adapter directly and open the thread yourself:
`adapter.openDM()` takes an ACI, a phone number such as `+15550001111`, or `u:<username>`, and returns the 1:1 thread ID. signal-cli looks numbers and usernames up on the Signal server, and `openDM()` throws `ResourceNotFoundError` when it finds no ACI for the user. `chat.openDM()` and `chat.getUser()` can't route Signal user IDs to this adapter. Chat picks the adapter from the user ID's format, and an ACI has the UUID format Chat assigns to Linear, so with the Linear adapter also registered these calls go to Linear instead of failing. Call the adapter directly and open the thread yourself:

## Resources

- [Adapter source](https://github.com/stibbons-ai/chat-adapter-signal)
- [Docker Compose example](https://github.com/stibbons-ai/chat-adapter-signal/tree/main/examples/echo-bot)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same pin as above:

Suggested change
- [Docker Compose example](https://github.com/stibbons-ai/chat-adapter-signal/tree/main/examples/echo-bot)
- [Docker Compose example](https://github.com/stibbons-ai/chat-adapter-signal/tree/c85ae16eb4392f4b0cac81ef04ca8a0c31a4ea2c/examples/echo-bot)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants