尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证The CHOIR App using Slack Bolt
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
CHOIR is a Slack bot for organization knowledge workflows. It indexes markdown documents from GitHub, answers questions against that document set, and can turn Slack conversations into document update suggestions.
• Answer questions from GitHub-backed markdown documentation
• Suggest document updates from Slack conversations
• Refresh the document index automatically from GitHub webhook events
• Provide manager controls in Slack App Home
• Import Google Docs, PDFs, and public web pages into the repository as new markdown documents, with a preview before committing (see docs/pdf-web-import.md)查看完整 README ↗CHOIR is a Slack bot for organization knowledge workflows. It indexes markdown documents from GitHub, answers questions against that document set, and can turn Slack conversations into document update suggestions.
app.ts: app bootstrap and HTTP routeslisteners/: Slack event, action, and view handlersservices/: GitHub, Slack, retrieval, document, LLM, workspace, and persistence logicsrc/: shared config, constants, types, and utilitiespublic/: static web assetsscripts/: maintenance and migration scriptsdocs/: architecture and implementation notesdeployment/: container and nginx deployment filesSee docs/architecture.md for a fuller map of the codebase.
CHOIR supports two Slack runtime modes. Pick the one that matches your deployment intent before configuring .env.
SLACK_MODE=single — self-hosted, one Slack workspace. Uses a static SLACK_BOT_TOKEN issued when you install your own Slack app. This is the recommended path for teams that want to run CHOIR on their own infrastructure for their own workspace.SLACK_MODE=oauth — multi-workspace OAuth distribution. One HTTP server accepts OAuth installs from multiple Slack workspaces and stores per-workspace credentials. Use this only if you intend to distribute your CHOIR instance to other workspaces (mirrors the hosted choir.cs.vt.edu deployment).The rest of this README walks through the self-hosted single-workspace path. See Multi-workspace OAuth distribution at the bottom for the OAuth-mode specifics.
git clone https://github.com/wooogler/choir.git
cd choir
pnpm install
Copy the template and replace the domain placeholder with the public hostname you will deploy CHOIR at (e.g. choir.example.com). For local development with Socket Mode you can leave the URLs as-is — they will not be reached.
cp manifest.example.json manifest.local.json
# then edit manifest.local.json and replace your-domain.example with your domain
Open https://api.slack.com/apps/new, choose From an app manifest, and paste the contents of manifest.local.json.
For local Socket Mode development, set Socket Mode to on in the Slack app settings and generate an app-level token (xapp-...) with connections:write.
Install the app into your workspace and copy the Bot User OAuth Token (xoxb-...) and Signing Secret.
cp .env.example .env
For a self-hosted single workspace, set at minimum:
SLACK_MODE=single
SLACK_BOT_TOKEN=xoxb-...
SLACK_SIGNING_SECRET=...
OPENAI_API_KEY=sk-...
Add SLACK_APP_TOKEN=xapp-... when running locally in Socket Mode (pnpm dev:socket or pnpm dev). It is not needed in HTTP-mode production.
Optional but commonly used:
GITHUB_OAUTH_CLIENT_ID, GITHUB_OAUTH_CLIENT_SECRET — enables managers to connect a GitHub account via device flow. Required if you want CHOIR to read your docs repo. Create a GitHub OAuth App and enable the Device Flow option in its settings.GITHUB_WEBHOOK_SECRET — enables automatic re-indexing on push events (HTTP mode only).MANAGER_PROMOTION_PASSWORD — shared secret managers enter in App Home to gain manager-only controls.CHOIR_CONSENT_FORM_URL — link shown in onboarding flows.CHOIR_DB_ENCRYPTION_KEY — optional 32-byte hex key (openssl rand -hex 32) used to encrypt Slack installations and workspace config JSON in SQLite. If omitted, CHOIR creates data/.choir-db-key on first encrypted write; back that file up alongside data/..env.example documents the full set of supported variables. CHOIR does not use a server-wide GitHub PAT; managers authenticate their own GitHub account via OAuth device flow.
For local development, start the app and the docs viewer together:
pnpm dev:local
This runs the Slack app in Socket Mode on 127.0.0.1:3031 under nodemon, and the
React docs viewer on http://localhost:5173 under Vite with hot reload. It reads
.env.development, forces SLACK_MODE=single, and isolates state under data/dev/,
so it does not clash with a production deployment. Editing anything under web/
reloads in the browser without a rebuild; editing a .ts file restarts the app.
Slack does not accept http://localhost redirect URLs, so the viewer's normal sign-in
cannot complete locally. pnpm dev:local prints a /docs/auth/dev-login URL that mints
the session directly; pnpm dev:tunnel publishes the Vite server through the ngrok
domain in DOCS_BASE_URL instead, for rehearsing the real Slack flow.
To work on Google Docs sync without a Google account:
pnpm dev:local --fake-google
pnpm gdocs:seed && pnpm gdocs:edit
See docs/local-development.md for the full picture, including what each mode can and cannot exercise.
Notes:
pnpm dev:socket runs the app alone, without the viewer's dev server.pnpm dev also uses Socket Mode because NODE_ENV=development.pnpm dev:prod runs in HTTP mode locally (useful for testing webhook handlers).pnpm dev:oauth listens on port 3030 in OAuth mode for OAuth-flow debugging.For production, run CHOIR in HTTP mode behind a reverse proxy on a public hostname. The repository includes a Podman + systemd + nginx reference setup.
podman, pnpm, nginx, and a valid TLS certificate (e.g. Let's Encrypt) for your domainA/AAAA record pointing your domain at the hostCopy .env.example to .env on the server and fill in the values above with SLACK_MODE=single and NODE_ENV=production. Make sure the Slack app's event/interactivity request URLs in your manifest match https://your-domain/slack/events.
Adapt the nginx config. The shipped deployment/nginx.conf reflects the maintainer's multi-workspace production setup and is not suitable as-is. Start from the minimal example instead:
sudo cp deployment/nginx.example.conf /etc/nginx/sites-available/choir
sudo ln -s /etc/nginx/sites-available/choir /etc/nginx/sites-enabled/choir
# edit the file and replace your-domain.example with your hostname
sudo nginx -t && sudo systemctl reload nginx
Deploy with the helper script, passing your domain as the first argument:
./scripts/deploy-podman.sh your-domain.example
Once DOCS_BASE_URL is set in .env, later redeploys can omit the argument and the script reuses that domain.
The script builds choir:latest, installs a choir.service systemd unit, mounts ./data into the container, binds the app to 127.0.0.1:3000, and waits on /healthz. It refuses non-loopback HOST_BIND values by default so the app port is not exposed directly to the network.
sudo systemctl status choir
sudo journalctl -u choir -f
sudo systemctl restart choir
To auto-refresh documentation after repository changes:
push events.https://your-domain/webhook/github.GITHUB_WEBHOOK_SECRET in both .env and the GitHub webhook configuration.CHOIR will match the incoming repository against the workspace's saved repo configuration and rebuild the vector store when the configured branch changes.
CHOIR stores workspace configuration, repository mirrors, vector stores, and SQLite databases under data/ in the project directory (or CHOIR_DATA_DIR if set). That directory is runtime state and should not be committed.
Runtime state is stored in SQLite by default:
DATABASE_URL=file:data/choir.dbdata/*-config.json and data/slack-installations/ are migrated lazily on first read.pnpm dev:local: app + docs viewer with hot reload (the usual loop)pnpm dev:tunnel: the same, published through the ngrok domain in DOCS_BASE_URLpnpm dev: local development in Socket Modepnpm dev:socket: isolated Socket Mode development using .env.development and data/dev/choir-dev.dbpnpm dev:oauth: isolated OAuth/HTTP development on port 3030pnpm dev:watch: the app alone under nodemon, same isolated env as dev:socketpnpm dev:web:vite: the docs viewer's Vite dev server alonepnpm gdocs:seed / pnpm gdocs:edit / pnpm gdocs:reset: drive the Google Docs review flow against a fake Drivepnpm dev:prod: HTTP-mode runtimepnpm dev:web: development with web content enhancement enabledpnpm build: compile TypeScript into dist/pnpm test: run unit testspnpm test:coverage: run unit tests with coveragepnpm verify: build and run unit testspnpm lint / pnpm lint:fix: Biome on changed filespnpm lint:all / pnpm lint:all:fix: Biome across the broader codebase backlogBiome is in the repository but is intentionally not part of the default verification path while the backlog is still large.
pnpm verify for the default build-and-test path.pnpm lint or pnpm lint:fix during normal work; both target changed files only.pnpm lint:all only when intentionally paying down the backlog.RETRIEVAL_PROVIDER=faiss (default) — in-process FAISS index for question answering.RETRIEVAL_PROVIDER=qmd — local QMD retriever, useful when you want to avoid OpenAI embedding calls.UPDATE_RETRIEVAL_PROVIDER=qmd — also use QMD for document-update anchoring.QMD is configured to run CPU-only by default (QMD_FORCE_CPU_ONLY=true, NODE_LLAMA_CPP_GPU=off).
If you want one CHOIR instance to serve OAuth installs from multiple Slack workspaces (the hosted choir.cs.vt.edu model), set SLACK_MODE=oauth and additionally configure:
SLACK_CLIENT_IDSLACK_CLIENT_SECRETSLACK_STATE_SECRETSLACK_REDIRECT_URI=https://your-domain/slack/oauth_redirectSLACK_SCOPES (optional override; defaults match the manifest)Set INSTALL_PASSCODE to keep installation invite-only: /slack/install then asks for that shared passcode before it
redirects to Slack, and remembers a correct answer for 12 hours. Leave it unset and the install page is open to anyone who
reaches it.
In OAuth mode, Bolt exposes /slack/install and /slack/oauth_redirect. Each installing workspace stores its own bot token in the SQLite installation store. The GitHub webhook endpoint is reachable but auto-reload is not yet wired up for OAuth installs.
Slack manifest scopes are the same as for single mode; what changes is the install path and the per-workspace token storage.