1
0
Fork 0
mirror of https://github.com/ananthb/concierge.git synced 2026-09-20 16:27:06 +00:00
Automated customer engagement for small businesses
  • Rust 84.9%
  • CSS 5.5%
  • TypeScript 4.5%
  • Fluent 4%
  • JavaScript 0.5%
  • Other 0.5%
Find a file
Ananth 08a2eddd66
demo: wrap long business card text inside the phone frame (#40)
Two card cells could push past the phone frame when tenant copy ran
long:

- `.chat-business-card .biz-meta span` matched the nested
  `<span x-text="…goal">` inside `.biz-goal`, re-imposing `nowrap` over
  the goal cell's `white-space:normal`. Long goal sentences then
  rendered as one infinite line. Scope the nowrap rule to direct
  children so the inner goal span keeps its parent's wrapping.
- `.chat-business-card .roleplay` had no `overflow-wrap`, so an
  unbreakable business name in `<strong>` (or e.g. a pasted URL)
  would push the line past the frame. Set `overflow-wrap:anywhere`.

Verified by stubbing `demo-personas-data` with a long-name + long-goal +
100-char-URL persona and an unbreakable 50-char-word name at both
1280×800 and 375×812 — every probe element reports
`scrollWidth - clientWidth == 0` after the fix.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-09 19:17:06 +05:30
.github chore(ci)(deps): bump actions/upload-pages-artifact from 3 to 5 (#25) 2026-06-09 13:58:35 +05:30
assets demo: the phone IS the live demo, modal becomes the reference layer (#37) 2026-06-08 14:17:42 +00:00
doc demo: real-phone status bars, live clock, slower wipe, depth on flip (#38) 2026-06-09 08:29:19 +00:00
migrations lead-forms: remove the feature; rework is coming 2026-06-07 14:23:09 +05:30
public/css demo: wrap long business card text inside the phone frame (#40) 2026-06-09 19:17:06 +05:30
scripts ci: dependabot, flake-update, security audit, test.yml hardening (#20) 2026-06-07 10:57:03 +00:00
src demo: use business name in chat composer placeholder (#39) 2026-06-09 12:54:39 +00:00
tests demo: real-phone status bars, live clock, slower wipe, depth on flip (#38) 2026-06-09 08:29:19 +00:00
.envrc concierge-worker - a calendar and form concierge app 2026-02-10 15:16:22 +05:30
.gitignore chore: drop garnix config, untrack .claude state, doc dev-only migration 2026-05-02 16:26:51 +05:30
build.rs templates: split CSS into 7 modules with build.rs SRI codegen (#19) 2026-06-07 15:52:08 +05:30
Cargo.lock chore(deps)(deps): bump the cargo-minor-patch group with 3 updates (#27) 2026-06-09 08:43:36 +00:00
Cargo.toml chore(deps)(deps): bump fluent-syntax from 0.11.1 to 0.12.0 (#29) 2026-06-09 08:36:14 +00:00
flake.lock Add git-hooks.nix pre-commit hooks 2026-04-04 20:09:26 +05:30
flake.nix fix: nix run .#dev now anchors writable paths at CWD, not the Nix store 2026-05-05 19:23:43 +05:30
LICENSE Initial commit 2026-02-10 03:12:30 +05:30
package-lock.json ci: dependabot, flake-update, security audit, test.yml hardening (#20) 2026-06-07 10:57:03 +00:00
package.json ci: dependabot, flake-update, security audit, test.yml hardening (#20) 2026-06-07 10:57:03 +00:00
playwright.config.ts tests: extend layout sweep to /manage; add mobile-density spec 2026-05-07 16:18:05 +05:30
README.md style: drop em-dashes, tired clichés, and stray compliance claims (#14) 2026-05-04 02:22:46 +05:30
rust-toolchain.toml migrate deploy to Cloudflare Builds 2026-04-29 11:13:03 +05:30
worker-shim.mjs style: remove emdashes and simplify formal phrasing 2026-04-26 01:54:20 +05:30
wrangler.toml ci: dependabot, flake-update, security audit, test.yml hardening (#20) 2026-06-07 10:57:03 +00:00

Concierge logo

Concierge

Automated customer messaging for small businesses. Auto-replies across WhatsApp, Instagram DMs, and email. Managed email subdomains on cncg.email. Unified Discord inbox for everything that needs a human.

Deploy to Cloudflare

Hosted Service · Documentation

Hosted Service

Don't want to self-host? concierge.calculon.tech runs this exact stack as a managed service. Sign up, connect your channels, and start auto-replying in minutes. 100 free replies every month.

Features

  • WhatsApp Auto-Reply: rule-routed canned or AI replies via Meta Business API
  • Instagram DM Auto-Reply: connect your business account, reply automatically
  • Reply Rules: per-channel ordered rules (keyword matchers and embedding-based intent matchers), each routing to canned text or an AI prompt; mandatory default fallback per channel
  • Persona Builder: tenant-wide AI persona via guided builder (voice archetype, business name + type, goal, catch-phrases, off-topic boundaries, handoff conditions), curated archetype copied from a platform-managed D1 catalog, or raw prompt. Every change is run past a safety classifier asynchronously via Cloudflare Queues; AI replies stay blocked tenant-wide until the new prompt is approved
  • Prompt Envelope: every AI reply is wrapped by a fixed preamble + postamble (defined in src/prompt.rs) that establishes the operating manual, jailbreak rails, and the universal handoff sentinel. Tenant content lives in the editable middle and never reaches the model alone
  • Conversation Sessions: per-customer threads carry a stable conversation_id, recent message history, and any active handoff state. A configurable idle gap (default 6 h) wipes history and starts a fresh conversation; a configurable max-history-messages cap (default 20) bounds the multi-turn context fed to the AI
  • Human Handoff: the model can flag a turn with [[HANDOFF]] (universal triggers in the postamble + tenant-specific conditions in the persona). The pipeline strips the token, switches to a holding-pattern voice for follow-ups within the cooldown (default 60 min), then goes silent. The tenant is paged once via the existing approval-notification channels (Discord embed and/or immediate email)
  • Live Demo Chat: the public welcome page hosts an interactive demo where visitors roleplay as a customer of a sample business and see the AI reply in real time. Persona picker pulls from the safety-approved D1 archetype catalog; a "View prompt" panel reveals the exact envelope being sent to the model. Real customer messages still arrive on WhatsApp / IG / email / Discord — never on this chat box
  • Managed Email Subdomains: each tenant gets *.cncg.email addresses with smart routing rules (glob patterns). Forward, drop, AI-draft, or relay to Discord. MX records provisioned automatically via Cloudflare API
  • Discord Relay: unified inbox. Messages from any channel land in Discord with Reply/Approve/Drop buttons. Reply in Discord and it flows back to the customer
  • Lead Capture Forms: embeddable phone number forms that trigger WhatsApp messages
  • Onboarding Wizard: guided setup (business info, channels, notifications, persona archetype, billing)
  • Notification Preferences: configurable approval + digest delivery via Discord and/or Email with batching frequency
  • Localized: per-tenant BCP-47 locale (en-IN and en-US shipped) drives Indian-vs-Western number grouping (₹1,00,000 vs $100,000) via icu4x; translation backbone uses fluent-rs FTL files for drop-in new languages. AI-generated reply content stays English regardless of UI locale
  • Management Panel: Cloudflare Access-protected admin for tenant management, billing, audit log
  • Billing: flat prepaid credits (₹0.10 / $0.001 per AI reply, 100 included every month). Static auto-replies don't consume credits. Buy any quantity (slider, no tiers, no packs). Reply-email subscription: 5 addresses per ₹99 / $1 per month. All prices live in global_settings and are editable from the management panel
  • Metadata-only logging: message bodies pass through the Worker but are never written to durable storage. Only channel, direction, sender, recipient, and timestamp are persisted. A /data-deletion endpoint wipes the metadata that is stored.

Deploy

See the Deploy guide for step-by-step instructions on forking and deploying your own instance to Cloudflare.

CI/CD is handled by Cloudflare Builds (Workers CI), which builds and deploys directly from this repo without needing GitHub Actions or Nix.

To wire up your fork:

  1. In the Cloudflare dashboard, create a Worker named (e.g.) concierge and connect this repo under Settings → Builds.
    • Build command: leave default (CF Builds runs npm install from package.json)
    • Deploy command: npm run deploy (defined in package.json; installs worker-build then runs wrangler deploy)
  2. Bind a D1 database (DB), KV namespace (KV), Workers AI (AI), Email Routing send-binding (EMAIL), Durable Objects (REPLY_BUFFERReplyBufferDO, APPROVALS_DOApprovalsDO), and Queues (SAFETY_QUEUE producer + concierge-safety / concierge-safety-dlq consumers) under Settings → Bindings. Names must match the binding values in wrangler.toml.
  3. Set runtime variables and secrets under Settings → Variables and Secrets. The full list is documented at the bottom of wrangler.toml.
  4. Push to main. Cloudflare Builds runs the build command, then wrangler deploy, which picks up [build] command = "worker-build --release" from wrangler.toml to compile the Rust crate to WASM.

Architecture

Development

nix develop        # enter dev shell with all tools (Nix-only; CI does not use Nix)
cargo test         # run tests
wrangler dev       # local dev server
wrangler deploy    # deploy to Cloudflare

Nix is for local convenience only. Cloudflare Builds installs the same toolchain via rustup, which reads the channel from rust-toolchain.toml.

License

AGPL-3.0