Back to projects

Maneki

Live voice sales agent for any website

A business gives Maneki their site, and visitors can talk live with an AI voice agent embedded on that site who knows the business's content and can pitch or answer questions like a sales rep. Built as a workspace of five independent git repos, not a monorepo, each with its own CLAUDE.md.

LangGraphLiveKitWebRTCPythonTypeScriptPostgreSQLpgvectorRedisClerk
  1. 01

    widget/

    A tiny <maneki-widget> custom element embedded on the client's site. The visitor clicks it, which requests a token.

  2. 02

    api-gateway/ (:8080)

    Mints that token (checking Origin, published status, rate limits) and dispatches a LiveKit voice agent into a room. Also handles the business owner's auth (Clerk JWT) for managing their tenant config.

  3. 03

    LiveKit room

    The visitor's browser connects via WebRTC; the voice agent joins as a participant.

  4. 04

    voice runtime gateway/

    The actual AI brain — a LangGraph-based agent that reasons over the conversation, decides what to say, and sends navigate/interrupt events back to the widget over the data channel (e.g. to scroll the visitor to a pricing section). It never touches the ingestion DB directly, only HTTP calls.

  5. 05

    Firecrawl-scraper-ingestion/ (:8000)

    The knowledge base — crawls the tenant's site (via firecrawl-selfhost), chunks it, embeds locally (fastembed, no API cost), stores it in pgvector, and generates the approved "sales script" the voice agent follows.

  6. 06

    firecrawl-selfhost/

    Vendored upstream Firecrawl (Node/TS), the actual crawling engine, treated as third-party.

Three distinct secrets never share a code path: INTERNAL_SERVICE_TOKEN (gateway/voice → ingestion), GATEWAY_INTERNAL_TOKEN (voice → gateway's tenant-config endpoint), and Clerk JWTs (human dashboard owner only).

All three custom backends share one Postgres instance in dev but own separate schemas, with no cross-service table access — gateway is also the only service using Redis, for rate limiting.

  • The owner dashboard UI — the API exists, but there's no frontend for it yet.
  • Most of the widget's runtime behavior beyond the visual shell — LiveKit connection, navigation handling, and session resume.