Serein
Rust로 만든 가볍고 성능 좋은 Discord 전용 네이티브 클라이언트
Dejavue는 중복 질문을 포착해 해결된 스레드의 답변을 제공하고, 검색 가능한 지식베이스를 구축해 관리자의 시간을 절약합니다
Dejavue is a Discord bot that catches duplicate questions, answers them from solved threads to save moderator hours, and builds a searchable knowledge base.
소셜TypeScript · AstroGitHub @lkaesberg온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Discord bot for help and Q&A channels: it catches duplicate questions as they are posted, runs a mark-solved workflow and turns solved threads into a public, searchable website, plus an MCP server for AI tools.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Dejavue is a Discord bot for help and Q&A channels. It catches duplicate questions the moment they're posted, drives a clean mark-solved workflow, and turns every solved thread into a searchable archive — inside Discord, on a public SEO-friendly website, and (on the top tier) as an MCP server your AI tools can query.
It's useful for any server where the same questions keep coming back:
unsolved → solved tag, stores the accepted answer plus the
full transcript, embeds it for semantic search, writes an AI summary (Pro/Max), and — if the
server opted in — publishes it to the public website./dejavue search, on the website, or through the MCP server./dejavue search over the solved-answer archive — private to the searcher, with broad /
balanced / exact match presets or a custom match thresholdsolved / unsolved tag automation (created automatically on setup){slug}.dejavue.app) or your own custom domainQAPage / FAQPage JSON-LD, DB-driven sitemap, near-zero-JS pages for SEO{slug}.dejavue.app/mcp/dejavue setup channel:#help — this also creates the solved /
unsolved tags for forum channels/dejavue rescan channel:#help indexes past threads so duplicate
detection works from day one/dejavue dashboard — your home screen: every indexed channel, how fresh it is, and buttons
through to everything below/dejavue settings — duplicate sensitivity, stale-question nudges, the off-topic guard and
cleanup, one page each with a plain-English explanation/dejavue website — set up your public site: name, address, theme, privacy and imprint/dejavue insights — stats, analytics, recurring-question clusters and the auto-FAQEverything lives under one /dejavue command, plus a Mark as Answer message context menu.
Every admin screen links to every other one, so /dejavue dashboard is enough to find the rest.
| Command | Description | Who |
|---|---|---|
/dejavue dashboard | See what Dejavue is watching — channels, index size, sync status and your plan | admin |
/dejavue setup <channel> [mode] | Start indexing a channel — forum, text or announcement | admin |
/dejavue search <query> [match] [threshold] | Search every answer Dejavue has archived (results only you can see) | anyone |
/dejavue insights | Stats, resolution rate, top helpers, most-asked topics and the auto-FAQ | anyone |
/dejavue settings | Duplicate detection, stale-question nudges, the off-topic guard and cleanup | admin |
/dejavue website | Your public knowledge-base site — name, address, theme, privacy and imprint | admin |
/dejavue rescan [channel] | Re-read a channel's full history and drop posts that were deleted | admin |
/dejavue privacy | Opt out of having your messages archived, in every server | anyone |
/dejavue help | What Dejavue does, and every command explained | anyone |
| Mark as Answer (right-click a message → Apps) | Mark that reply as the accepted answer | OP/mod/admin |
/dejavue customizewas renamed to/dejavue website. The old name still works for now and points you at the new one.
/dejavue settings opens one page per feature. None of them are locked behind a paid plan.
| Page | What it controls |
|---|---|
| 🔁 Duplicate detection | How closely a new question must match an archived one before I suggest it. Presets, or an exact minimum match % |
| ⏰ Stale-question nudges | Whether to chase up unanswered questions, after how long, and which role to ping |
| 🧭 Channel routing & off-topic guard | Gentle "might fit better in #other" suggestions, and the stricter guard that warns on — and optionally closes — clearly off-topic posts |
| 🧹 Cleanup & branding | Whether my "Got your answer?" prompt is deleted when a post is solved, and whether the "Powered by Dejavue" footer is shown (always on for Free) |
| Option | Values | Description |
|---|---|---|
mode | question, knowledge | Forums only. question runs the Q&A loop (duplicates + mark-answer); knowledge archives everything with no prompts. Default: question |
match | broad, balanced, exact | How closely search results must match. Default: balanced |
threshold | 0–100 | Custom minimum match percentage — overrides the match preset |
⚠️ The search
thresholdand the duplicate-detection sensitivity in/dejavue settingsare both percentages, but they are not on the same scale — search compares a question against retrieval chunks, duplicate detection compares two questions, and the same genuine match scores much higher in the second. Tune each against its own results, not against the other's number.
Dejavue needs View Channels, Manage Channels, Send Messages, Embed Links, Read Message History,
Manage Threads and Send Messages in Threads. Manage Channels is what lets it create and swap
the solved / unsolved forum tags — without it, tag automation fails.
View Audit Log is optional. It is used once, to work out who added the bot so the setup walkthrough can be sent to them by DM; without it, that DM goes to the server owner instead.
The Message Content privileged intent must be enabled, since Dejavue reads question text to detect duplicates.
The hosted bot records aggregate, per-server operational metrics (threads indexed, AI
credits used, embedding tokens spent, subscription events) so the service can be run and
billed. The allowlist in packages/analytics makes it structurally impossible to emit
message content, thread titles, search queries, or Discord user ids. distinct_id is the
guild id.
Published knowledge bases additionally count page traffic in the visitor's browser
(components/KbAnalytics.astro), in PostHog's cookieless mode: no cookie, no local
storage, no persistent visitor id, no person profile, autocapture and session replay both
off. Visitors are counted by a hash PostHog computes server-side that rotates daily. The
apex marketing site is not instrumented at all. Because this runs client-side,
POSTHOG_API_KEY is rendered into the page — correct for a PostHog project key
(phc_…), which is public by design; never put a personal key (phx_…) there.
Free-plan knowledge bases also show one ad (ADS_PROVIDER=ethicalads). It is
cookieless and non-behavioural, and because loading it discloses the reader's IP to a
third party it is gated behind an explicit opt-in — nothing is requested until the visitor
agrees, and declining falls back to an in-house promo.
Both are disclosed in the privacy policy. Self-hosting sends nothing: leave
POSTHOG_API_KEY unset and no client is created, and leave ADS_PROVIDER at none.
The hosted bot is billed per server through Discord Premium Apps. AI usage is metered in AI credits (1 credit = 1,000 model tokens, input + output): a drafted answer costs ≈ 0.8 credits and a thread summary ≈ 3.
Only two things actually cost us money per server: indexing (embedding your messages) and AI generation. So those are the only two things the tiers meter. Semantic search, analytics, nudges and theming cost nothing to serve, so every server gets them.
| Free | Plus €4.99 | Pro €9.99 | Max €24.99 | |
|---|---|---|---|---|
| Forum channels | 3 | 15 | 50 | unlimited |
| Tracked (non-forum) channels | 3 | 15 | 50 | unlimited |
| Indexed messages | 2,500 | 25,000 | 250,000 | unlimited |
| Duplicate detection / search | semantic | semantic | semantic | semantic |
| Stale-question nudges | ✓ | ✓ | ✓ | ✓ |
| Analytics | full | full | full | full |
| Knowledge-base theming | ✓ | ✓ | ✓ | ✓ |
| AI-drafted answers | — | ✓ | ✓ | ✓ |
| AI summary / clustering / auto-FAQ | — | ✓ | ✓ | ✓ |
| AI credits / mo | — | 250 | 2,500 | 12,000 |
| Website page rendering | raw | AI-summarized | AI-summarized | AI-summarized |
| MCP server | — | — | ✓ (30 req/min) | ✓ (30 req/min) |
| Ads on the public site | shown | none | none | none |
| "Powered by Dejavue" branding | shown | removed | removed | removed |
One-time purchases (any tier): Custom domain — €29.99 · AI top-up packs of 500 / 1,000 / 2,000 / 5,000 credits (consumable, stacks, never expires). Importing your existing history is free, up to each tier's indexed-message limit.
💡 Self-hosting has no tiers. Set
DEV_FORCE_TIER=maxand every feature is unlocked — you just pay your own OpenRouter bill for the AI parts, or run embeddings on CPU for free.
bge-small-en-v1.5)Dejavue is fully self-hostable — no license key, no phone-home, no feature gating. You have two options: Docker (recommended) or Manual Installation.
Requirements: Docker, or Node.js 22+ with a Postgres 16 database that has the pgvector
extension available.
The whole stack — Postgres, migrations, bot, worker and web — comes up with one command.
git clone https://github.com/lkaesberg/Dejavue.git
cd Dejavue
cp .env.example .env
nano .env
Fill in at minimum:
DISCORD_TOKEN=<Discord Bot Token>
DISCORD_CLIENT_ID=<Discord Bot Client ID>
OPENROUTER_API_KEY=<OpenRouter API Key> # optional: only needed for AI features
DEV_FORCE_TIER=max # unlock every feature when self-hosting
docker compose up -d --build
DATABASE_URL is auto-pointed at the bundled postgres service, migrations run on start, and the
CPU embedding model is cached in a named volume. The web app listens on port 4321.
docker compose exec bot pnpm --filter @dejavue/bot register
Postgres has no built-in encryption, so scripts/encrypt-db-volume.sh encrypts the storage under it,
the way managed database providers do. It moves the Postgres volume into a LUKS2 container
mounted at the volume's own folder, so Docker, Coolify and the compose files keep using the same
volume and the official pgvector image is unchanged. It works for this compose file and for
Coolify alike (run it in Coolify's server terminal).
sudo bash scripts/encrypt-db-volume.sh setup # asks for a passphrase, then encrypts
sudo bash scripts/encrypt-db-volume.sh status
sudo bash scripts/encrypt-db-volume.sh cleanup # once verified: delete the unencrypted copies
Setup asks for a passphrase. Paste one from your password manager, or let the script generate
one and save it there; it asks you to paste it back before changing anything. The same
passphrase is stored in a key file on the server so the volume unlocks by itself at boot. Your
password-manager copy is the way back in if that file is ever lost. Dejavue is offline for the
copy, usually under a minute. Setup checks that every table has the same row count afterwards,
and rollback undoes it until you run cleanup. Needs root, systemd and a Linux host.
Requirements: Node.js v22 or higher
git clone https://github.com/lkaesberg/Dejavue.git
cd Dejavue
corepack enable # provides pnpm (version pinned in package.json)
pnpm install
cp .env.example .env
nano .env
pnpm db:up # Postgres (pinned pgvector/pgvector:pg16) in Docker
pnpm db:migrate # extension + tables + HNSW index
pnpm db:verify # proves pgvector cosine search works
Point DATABASE_URL at your own Postgres instead if you already run one — it needs the pgvector
extension.
pnpm dev # Postgres + migrations + bot + worker + web, with live reload
Or run the services individually: pnpm dev:bot / pnpm dev:worker / pnpm dev:web.
💡
make setupdoes steps 1–3 in one go, andmake helplists every available task.
Dev container: open the repo in VS Code / Cursor and "Reopen in Container" — the .devcontainer starts Postgres alongside a Node 22 workspace, installs dependencies, and runs migrations automatically (ports 4321/5432/8090 forwarded).
bot + applications.commands; permissions: View Channels,
Manage Channels, Send Messages, Embed Links, Read Message History, Manage Threads, Send Messages
in Threads. Open the generated URL to add your bot.pnpm --filter @dejavue/bot register — uses DISCORD_DEV_GUILD_ID for
instant guild-scoped commands, or registers globally if unset.*.yourdomain.tld (wildcard DNS + TLS) at the web app and
set KB_BASE_DOMAIN. Custom domains CNAME to the same host..env. Self-hosters should just set DEV_FORCE_TIER=max instead.| Option | Description |
|---|---|
DATABASE_URL | Postgres connection string (needs the pgvector extension) |
DISCORD_TOKEN | Your Discord bot token |
DISCORD_CLIENT_ID | Your Discord application's client ID |
DISCORD_DEV_GUILD_ID | (Optional) Register commands to one guild for instant updates |
OPENROUTER_API_KEY | (Optional) Enables AI drafts, summaries, clustering and the auto-FAQ |
OPENROUTER_MODEL | Model for generative features (default deepseek/deepseek-v4-pro) |
KB_BASE_DOMAIN | Base domain for public knowledge bases (default dejavue.app) |
KB_PUBLIC_URL | Public URL of the marketing/website root |
KB_REVALIDATE_SECRET | Signs the private-KB gate cookie. Required in production — the app refuses to boot without it rather than fall back to a constant published in this repo. openssl rand -hex 32 |
TRUSTED_PROXY_HOPS | How many reverse proxies sit in front, each appending to X-Forwarded-For. Decides which entry is trustworthy for rate-limit keys. 0 (default) ignores the header and uses the socket peer — correct for a directly exposed app. Traefik alone = 1; Cloudflare + Traefik = 2. Setting it too high is the dangerous direction |
EMBEDDING_PROVIDER | local (default, free CPU) or openrouter |
EMBEDDING_MODEL | Embedding model id — see the table below |
EMBEDDING_SERVICE_URL | (Local provider) Set on bot and web only, to http://worker:8090: they ask the worker to embed instead of each loading the ~1.6 GB model. Both compose files set it |
QUOTA_CREDITS_PLUS / _PRO / _MAX | Monthly AI credits per tier (250 / 2,500 / 12,000) |
QUOTA_EMBED_TOKENS_FREE / / / |
Embeddings are pluggable via EMBEDDING_PROVIDER:
| Provider | EMBEDDING_MODEL | Cost | Notes |
|---|---|---|---|
local (default) | bge-small-en-v1.5 / multilingual-e5-small | free, on-CPU | downloads a small ONNX model |
openrouter | openai/text-embedding-3-large | per-token API | reuses OPENROUTER_API_KEY |
Both produce 384-dim vectors (EMBEDDING_DIM) so they share one vector(384) column — switching
is a config change. On startup the bot re-embeds threads with the new model, and search is scoped to
the active model id so stale vectors are never mixed in. Point EMBEDDING_BASE_URL /
EMBEDDING_API_KEY at https://api.openai.com/v1 to call OpenAI directly instead of OpenRouter.
💡 Fully offline AI: with
EMBEDDING_PROVIDER=localand noOPENROUTER_API_KEY, Dejavue runs duplicate detection, semantic search and the whole archive without sending anything to a third party. Only the generative features (drafts, summaries, FAQ) need an LLM.
packages/core shared types, env, tier/entitlement logic, clustering
packages/db Drizzle schema + migrations (pgvector) + repositories
packages/ai embeddings (Transformers.js) + OpenRouter LLM client
packages/queue pg-boss queues + job definitions
apps/bot discord.js gateway client (commands, events, interactions)
apps/worker pg-boss jobs (embed, summarize, cluster, FAQ, nudge, backfill, reconcile)
apps/web Astro SSR — public website (subdomain/custom-domain) + /mcp endpoint
The bot handles live query-embedding and interactions; the worker does the heavy and scheduled work. They coordinate only through pg-boss and Postgres, so you can scale or restart either independently. Tier is derived purely from Discord entitlements (hourly LIST reconcile + per-process cache) and gates every feature in one place.
See docs/PLAN.md for the full design rationale and milestone history.
Once a Max server has set a website slug and opted in, its published answers are queryable at
https://{slug}.dejavue.app/mcp. Add it to any AI client as a Streamable HTTP MCP server. It
exposes one tool:
search_knowledge_base(query: string, limit?: number) → relevant solved Q&As with source links
Dejavue is open source so you don't have to take our word for any of this — read the code, or host it yourself.
/dejavue privacy stops Dejavue from storing anything they post, in
every server, and deletes what it already had of theirs.data_collection: deny).Full details: Privacy Policy · Terms
Contributions are welcome. See CONTRIBUTING.md for the workflow, and SECURITY.md for reporting vulnerabilities.
Before pushing:
make check # typecheck + tests
Distributed under the GNU Affero General Public License v3.0. See LICENSE for the full text.
In short: you're free to use, modify and self-host Dejavue, including commercially. If you run a modified version as a network service, you must make your source available to its users under the same license.
_PLUS_PRO_MAX| Monthly embedding-token ceiling per tier. A runaway guard, not the product limit (indexed messages is) — fail-closed on Free, alert-only on paid |
EMBED_MAX_CHUNKS_PER_THREAD | Max chunks a single thread is split into. 0 (default) = unlimited, i.e. every message is embedded |
EMBED_BATCH_SIZE | Chunks sent per embedding request (default 64) |
MCP_RATE_PER_MIN | MCP endpoint rate limit (default 30) |
POSTHOG_API_KEY | (Optional) Product analytics. Unset = nothing is sent at all — the expected setup when self-hosting |
POSTHOG_HOST | PostHog host (default https://eu.posthog.com) |
ADS_PROVIDER | none (default, and the right setting when self-hosting) or ethicalads. Free-tier knowledge bases only, behind a visitor opt-in |
ADS_PUBLISHER_ID | Publisher id from the ad network. Without it ethicalads stays off — a provider with no id would render a permanently empty slot |
CHANNEL_JOB_CONCURRENCY | Parallel channel history jobs (default 2). Keep at 1 on a memory-constrained host |
SKU_* | Discord SKU ids — only needed if you monetize your own instance |
DEV_FORCE_TIER | Force a tier (free/plus/pro/max). Set max when self-hosting |