尚未偵測到更新。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.