Operations and verification guide for the three OpenKOTOR Discord bots plus the Trask Holocron web UI.
| Component | Status | Evidence |
|---|---|---|
Trask HTTP server (/api/trask/*) |
✅ | pnpm holocron:e2e — 5 live research queries via Playwright on :4010 |
Holocron web UI (apps/holocron-web) |
✅ | Same functional e2e (apps/holocron-web/e2e/holocron-research.spec.ts) |
| Research Python venv auto-discovery | ✅ | .venv-trask-research when present |
| Garbage content filtering | ✅ | Cloudflare/JS-challenge blocks stripped from scraped pages |
| Seeded KOTOR lore (15 entries) | ✅ | Revan/Bastila/HK-47/Exile/Nihilus/Pazaak-rules/etc. answer without LLM key |
| Local knowledge fallback | ✅ | localKnowledgeFallbackAnswer used when synthesis fails |
| Unit test suite | ✅ | 453/453 passing — persistence, retrieval, config, core, platform (utils+oauth+cors+browser), policy (merge+public+file-loader), pazaak-engine (rules+opponents), discord-ui, personas, bots, Trask (reply-format+research-wizard), and tournament |
| Bot cold-start (no tokens) | ✅ | All 3 bots start → only fail at Discord token step |
| Discord bot code + command registration | ✅ | pnpm discord:smoke-bots once tokens provided |
| Live Discord bot interaction | ⏳ | Keep pnpm dev:trask (or container) running; verify channels — see below |
pnpm install
pnpm rebuild esbuild # must run once after clean install
pnpm buildnode scripts/trask_ops.mjs setup-venvThis creates .venv-trask-research/ at the repo root (scripts/bootstrap_trask_research.sh).
The venv path is auto-discovered by loadResearchWizardRuntimeConfig — no path configuration needed when bootstrap ran.
Versioned Trask policy lives under data/trask/ and loads via @openkotor/trask-config:
| Path | Purpose |
|---|---|
data/trask/eval/golden-queries.json |
Canonical five eval questions (e2e, CLI, smoke fixtures, faithfulness) |
data/trask/eval/verification-queries.json |
Expert phrasing for Holocron/Discord/browser gates; each row links to golden via goldenQueryId |
data/trask/profiles/surfaces.json |
Holocron / Discord / CLI compose profiles |
data/trask/policy.json |
Min citations, Discord line caps, degraded-answer patterns |
data/trask/linguistics.json |
Intent terms + anchor tokens (wizard + retrieval) |
data/trask/retrieval.defaults.json |
Shared retrieve limits (Node + trask_web_research.py) |
data/trask/prompts/*.md |
Compose / grounded LLM templates |
After editing golden questions or fixtures, run pnpm trask:config-drift. Env overrides: docs/knowledgebase/50-execution/trask-configuration-env-map.md.
Discord /ask research logging
| Variable | Purpose |
|---|---|
TRASK_RESEARCH_LOG_LEVEL |
Python trask.research logger level (INFO default, DEBUG for full retrieve/verify trail) |
TRASK_RESEARCH_LOG_VERBOSE=1 |
Node forwards DEBUG stderr lines into trask-bot logs |
TRASK_RESEARCH_TRACE_LOG=0 |
Disable Node JSON trask_research_trace lines on stderr (enabled by default; mirrors Holocron liveTrace) |
TRASK_DISCORD_SYNC_INTERVAL_MS |
When > 0, trask-bot runs scripts/trask_discord_sync.py on startup and on interval (recommended 15–60 min in production) |
Classify failures from server logs (AE3): each line is JSON with "type":"trask_research_trace". Grep examples:
# Retrieve / index miss
grep trask_research_trace trask-http.log | grep '"index_miss":true'
# URL verify rejects
grep trask_research_trace trask-http.log | grep '"rejected_urls":[1-9]'
# Gather or compose budget exceeded
grep trask_research_trace trask-http.log | grep '"timeout_phase":"gather"\|"timeout_phase":"compose"'pnpm trask:smoke-imports:ci asserts these diag keys stay present (see scripts/lib/trask_research_trace_assert.mjs).
Citation offline gates
| Command | When |
|---|---|
pnpm trask:optimize-measure |
Local preflight: faithfulness + discord stress + all citation unit suites + pnpm check (composite_score floor 165) |
pnpm trask:optimize-measure:ci |
CI-equivalent: faithfulness + discord stress + floor 165 (after pnpm build) |
pnpm trask:faithfulness-eval |
Fixtures-only replay (no discord stress) |
Module map: trask-citation-module-architecture-2026-05-24.md.
Gate: pnpm verify:trask-discord runs pnpm trask:gate first, then live expert queries (auto-bootstraps indexer+Worker; token only for --post). CI uses pnpm verify:trask-discord:ci (static embed smoke, no LLM/token).
Run the interactive wizard (opens discord.com/developers/applications in your browser):
pnpm discord:setupThe wizard will:
- Open https://discord.com/developers/applications in your browser
- Prompt you to paste App ID, Public Key, and Bot Token for each bot
- Write validated credentials to
.envat the repo root
Where to find each value in the Developer Portal:
- App ID and Public Key — "General Information" tab
- Bot Token — "Bot" tab → "Reset Token" → confirm → copy
Without a hosted provider, Trask may return extractive cited fallback only. Primary path (see docs/trask-research-backends.md):
# Primary: Hugging Face (replacement-first stack)
HF_TOKEN=hf_...
# HA fallback (optional)
TRASK_CLOUDFLARE_AI_BASE_URL=https://gateway.ai.cloudflare.com/...
TRASK_CLOUDFLARE_AI_TOKEN=...Legacy optional paths:
# Option A: OpenAI (paid profile)
OPENAI_API_KEY=sk-...
# Option B: OpenRouter (free/paid tier)
OPENROUTER_API_KEY=sk-or-...
OPENAI_BASE_URL=https://openrouter.ai/api/v1
OPENROUTER_HTTP_REFERER=https://github.com/openkotor/community-bots
OPENROUTER_APP_TITLE=OpenKotor Trask
TRASK_REWRITE_MODEL_FALLBACKS=meta-llama/llama-3.2-3b-instruct:free,openrouter/auto
# Option C: Tavily (improves search quality — legacy gather path only)
TAVILY_API_KEY=tvly-...# Start Trask web Q&A server (port 4010)
pnpm dev:trask-http
# Start Trask Discord bot (must stay running — Discord shows
# "The application did not respond" if no process is connected)
pnpm dev:trask
# Verify TRASK_APPROVED_CHANNEL_IDS matches real channel snowflakes
node scripts/trask_discord_channel_verify.mjs
# Start HK-86 Discord bot (react-for-role)
pnpm dev:hk
# Start Pazaak Discord bot
pnpm dev:pazaakBots automatically load credentials from root .env (dotenv walks up from cwd).
After the bot is running you need to configure which message(s) act as reaction panels.
Post a message in any channel (e.g. #roles). Users will react to that message to get roles.
In Discord: User Settings → Advanced → Developer Mode to enable copying IDs.
- Right-click the channel → "Copy Channel ID"
- Right-click the message → "Copy Message ID"
The file is auto-created from the template when you run pnpm discord:setup. Edit it:
{
"version": 1,
"defaultAnnounceMode": "reply",
"replyCooldownMs": 3000,
"panels": [
{
"channelId": "123456789012345678",
"messageId": "234567890123456789",
"mappings": [
{ "emoji": "🎮", "roleNameHint": "PC Gamer" },
{ "emoji": "📚", "roleNameHint": "Lore Enthusiast" }
]
}
]
}Use roleNameHint to bind by role name (auto-looked-up), or roleId for a stable snowflake ID.
The bot hot-reloads the file — no restart needed after saving changes.
The /designations reactions help command (ephemeral) outputs a pre-filled invite link.
Required permissions: Manage Roles (must be positioned above any role it assigns), Send Messages, Embed, Read History, Add Reactions.
# In Discord, as a guild manager:
/designations reactions statusShows loaded panels and mapping counts. Then react on the panel message with a test account — HK-86 should reply and apply the role.
pnpm exec playwright install chromium --with-deps # once per machine
pnpm holocron:e2eBuilds workspace + Holocron, starts trask-http-server on http://127.0.0.1:4010, and runs five live research queries in Chromium (no API mocks). Each test must finish with a substantive answer and Sources / https:// citations.
pnpm discord:smoke-botsCalls the Discord REST API to confirm all slash commands are registered for each bot.
| Bot | Command to test |
|---|---|
| Trask | /ask query:<your question> — compact Trask Ulgo Briefing (≤5 lines, inline linked [1]/[2] on the numbers; no separate Sources embed field). Deep page URLs preferred over bare forum homepages. |
| HK-86 | /designations reactions status — check reaction-role panel |
| HK-86 | Click a reaction emoji → role should be added/removed |
| Pazaak | /pazaak rules then /pazaak lobby action:create |
# Pull latest + rebuild
git pull
node scripts/trask_ops.mjs update
# Refresh research venv if requirements changed
node scripts/trask_ops.mjs setup-venvnode scripts/trask_ops.mjs --help
# Commands:
# setup Install deps, init submodules, build
# setup-venv Create/update .venv-trask-research Python venv
# update git pull + rebuild
# build-web Build holocron-web static assets
# dev-http Start trask-http-server (port 4010)
# verify-web Playwright browser verification (5 queries)
# smoke-discord Discord REST command registration smoke test