Skip to content

Repository files navigation

RespondKit

RespondKit is a small, multilingual support stack for indie products. Customers use a React or native chat widget, and each support thread appears in a Discord forum post in its original language. Optional Gemini translation is available through message actions, /translate, and /reply translate:…. Plain /reply sends as written.

The runtime is one Cloudflare Worker bundle with D1 and Cloudflare Workflows. It deliberately has no control-plane dashboard, Better Auth, Queue, Cron trigger, Durable Object, WebSocket, or Discord Gateway.

Native widgets

The repo includes a root Swift Package (RespondKitCore + RespondKitUI, iOS 18+) and Kotlin/Compose modules under native/android (API 26+). Apps provide custom triggers and unread indicators, then present the SDK conversation UI full screen. Visible iOS transcripts acknowledge each newly loaded reply cursor; closed chats remain unread. Unread state refreshes in the foreground; native push notifications are outside this version. SwiftUI supports an explicit foreground color for solid accent buttons, including dark icons on light brand colors.

See the native integration and demo guide for SPM setup, local Android builds, identity/persistence, and simulator tests. See the shared release process for versioned SwiftPM and Maven Central distribution.

Repository

apps/
  api/          Hono Worker, MessageWorkflow, D1 migrations, setup scripts
  widget/       Vite playground and Playwright browser host
packages/
  protocol/     public v1 DTOs, validation, and opaque IDs
  api-client/   retry-safe customer API client
  react/        embeddable Tailwind v4 + shadcn customer widget
  workspaces/   workspace/product/inbox/origin persistence
  conversations/ thread, message, translation, and cursor persistence
  translation/  Vercel AI SDK Gemini adapter and protected-text translation
  discord/      signed interactions, REST projection, commands, and mappings

Feature packages export TypeScript source directly. Only apps/api and apps/widget build production bundles.

The reviewed system design and message flows are in docs/architecture/base-v1.md.

Key-free development

Requirements: Node.js 22.18 or newer and pnpm 10.33.2.

pnpm install --frozen-lockfile
pnpm check
pnpm test:all
pnpm build:all
pnpm --dir apps/widget test:e2e

The API suite runs against Cloudflare's local Vitest pool with an isolated D1 database and local Workflow test helpers. Discord signature and REST behavior use fixtures/mocks; Gemini translation uses an injected fake model. These commands do not need external credentials.

Run the widget playground with:

pnpm dev:widget

Local Cloudflare topology

Copy the example and replace its placeholder IDs:

cp apps/api/config/workspaces.example.json apps/api/config/workspaces.local.json
pnpm config:apply --local
pnpm discord:commands:apply --dry-run

config:apply validates the complete workspace → product → inbox topology, applies the checked-in D1 migration, and idempotently seeds the local database. The Discord dry run prints the guild-scoped /reply, /status, /retry, /translate, and Translate to English registration requests without contacting Discord. See the optional translation setup and test guide for inbox enablement, permissions, and rollout.

Inbox origin allowlists accept exact production origins and loopback any-port patterns such as http://localhost:* or http://127.0.0.1:*. Wildcards are rejected for non-loopback hosts so a development convenience cannot expose an inbox to arbitrary websites.

Live local API development additionally needs an uncommitted apps/api/.dev.vars, based on .dev.vars.example. Do not commit it. Remote deployments should use wrangler secret put for secrets rather than plaintext configuration.

React integration

The host app needs React 18.2 or newer, Tailwind CSS v4, and @tailwindcss/vite. Import the widget and its stylesheet once at the application entry point:

import { RespondKitWidget } from "@respondkit/react";
import "@respondkit/react/styles.css";

export function Support() {
  return (
    <RespondKitWidget
      apiBaseUrl="https://support.example.com"
      title="Example Support"
      context={{
        inboxId: "inbox_example_public",
        userId: currentUser.id,
        email: currentUser.email,
        posthogDistinctId: posthog.get_distinct_id(),
        locale: navigator.language,
        timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
        path: window.location.pathname,
        metadata: { plan: currentUser.plan },
      }}
    />
  );
}

The widget preserves a browser visitor through anonymous use and login. Customer-supplied IDs remain advisory; pass getIdentityToken from an authenticated backend and identityPending from your auth state to link conversations to a verified account and restore history on another browser. Logout and account changes isolate subsequent history. See persistent visitors and verified customer history for signing, aliases, migration, and rollout instructions.

The package uses shadcn primitives with Tailwind v4 utilities namespaced as ac: and does not import Tailwind preflight, so it can coexist with the host product's Tailwind/shadcn theme.

This release is intended for a monitored, low-volume pilot. Discord ambiguity recovery currently inspects the newest 100 messages and at most 50 active plus 50 archived forum threads. A retry delayed until the original projection has moved beyond that window can duplicate a Discord projection; production-scale use needs paginated reconciliation to a persisted boundary and a canonical content digest.

Credential-backed validation still required

The implementation and automated tests are key-free. Before a real-world pilot, provision separate development credentials for:

  • Gemini (GEMINI_API_KEY)
  • a Discord application/bot (DISCORD_BOT_TOKEN, application ID, and Ed25519 public key)
  • a random customer-session signing secret (SESSION_SIGNING_KEY)

Then run one Thai and one Burmese customer message end to end, verify original-language Discord delivery, use Translate to English, and invoke /reply translate:customer to validate localized customer delivery. Also verify plain /reply works with translation disabled. Follow the translation test checklist.

About

Cloudflare-native multilingual customer support with a React widget and Discord inbox

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages