尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A chat assistant for two people playing Arkham Horror: The Card Game campaigns together. Ask it about a rule, a card or a deck, and it answers from the real sources: the full Rules Reference, ArkhamDB's card text with errata, official rulings and taboo changes, and any published ArkhamDB deck with its author's guide. It can also find decks, and partners for a deck, that the players can build from their own collection.
| Question | How it answers |
|---|---|
| Does doom on an enemy count toward the agenda? | From the complete Rules Reference, which is part of the system prompt |
| What does Ward of Protection do at each level? | cards tool: every level and printing together, with errata and rulings |
| How do I play Boom Chakra Lacka? | findDeck finds the deck by its name, then the deck tool reads the decoded list and the author's guide live from ArkhamDB |
| What could replace Archive of Conduits with something cheaper? | replaceCard tool: legal, owned substitutes, with how often each is played |
| Suggest a mystic cluever deck. | recommendDecks tool: searches an index of 660 of the most-liked published decks by class, role, archetype, XP, investigator or key card |
| I have 5 XP for my deck. What should I buy? | upgrades tool: every owned, legal upgrade, customization box and new card the XP buys, priced by the Rules Reference and the taboo setting, ranked by how often liked decks play them |
| How should we prepare for The Path to Carcosa? | campaignPrep tool: what the campaign's encounter cards ask of you, as counts only (skills tested, horror against damage, enemy toughness, keywords, frost), overall and by scenario pack, so it spoils nothing. Only when asked. |
| What should I play with my partner's deck? | recommendDecks with pairWith: decks whose role covers what the partner's deck lacks, never the same investigator |
Every card an answer names is a link. Tapping one opens the card in the app, laid out like the printed card with its game symbols, art, owned printings, other levels and official rulings; with the taboo list on, its taboo change too.
Decks are named the way players name them, never by number. A deck can be linked, named ("Boom Chakra Lacka", "the bless Mary deck", matched against the index; when the match is unsure the assistant asks, and when nothing fits it asks for the link), or saved once under Decks as yours or your partner's, so "my deck" is enough.
A few rules hold everywhere, enforced in code rather than left to the model:
lib/collection.json).flowchart LR
ui["Chat UI<br/>(assistant-ui)"] -- "POST /api/chat" --> loop["Agent loop<br/>lib/agent.ts"]
loop <--> llm["LLM<br/>(OpenAI or Anthropic)"]
loop --> tools["Tools<br/>cards · deck · findDeck<br/>recommendDecks · replaceCard<br/>upgrades · campaignPrep"]
tools --> adb[("ArkhamDB<br/>cards, taboos, decks")]
tools --> index[("Deck index<br/>lib/index/")]
pipeline["Offline pipeline<br/>pipeline/"] -. builds .-> index
The app is a Next.js chat page and a single API route. Each question runs an agent loop
(the AI SDK's streamText) with seven tools. The system prompt holds the
whole Rules Reference (about 39,500 words) and never changes between requests, so the provider
can cache it. Anything that changes from turn to turn, such as the date and the players'
settings, is added to the newest message instead. Steps, tool calls and wall time are capped in
code, and the last step is always kept for the answer.
Card data, taboo lists and decks are fetched from ArkhamDB when needed. The one thing the app builds ahead of time is its deck index: the ten most-liked published decks for each investigator the players own. Each deck is labeled with a role, archetypes and a one-line summary. Claude wrote the labels during development, one investigator at a time, and they were checked against each deck's card counts. The offline pipeline that builds the index uses the same card store, XP counting and legality check as the app, so the two can never disagree.
docs/ARCHITECTURE.md walks through a request end to end.
You need Node.js 22.12 or later and an OpenAI or Anthropic API key.
npm install
cp .env.example .env.local # then add your API key
npm run dev # http://localhost:3000
To try it without a key, run ARKHAM_MODEL=mock:local npm run dev. The mock model is a
scripted stand-in that sends each question to one tool, so the UI, the tools and the agent loop
can all be exercised for free. It doesn't write real answers.
The first request downloads ArkhamDB's card set (about 9 MB). The app keeps it for a day, in
memory and, in development, on disk under data/cache/.
All settings are environment variables, read from .env.local in development.
| Variable | Purpose |
|---|---|
OPENAI_API_KEY | Uses OpenAI. When both keys are set, OpenAI is used. |
ANTHROPIC_API_KEY | Uses Anthropic, when no OpenAI key is set. |
ARKHAM_MODEL | Optional. Overrides the model as provider:model. The defaults are openai:gpt-6-sol and anthropic:claude-opus-5-5; mock:local is the mock model. |
ARKHAM_EFFORT | Optional. Reasoning effort: low, medium, high, xhigh or max. Defaults to medium for OpenAI and high for Anthropic. |
DATABASE_URL | Optional locally. Postgres for accounts and chats; without it the app keeps them in PGlite under .data/. |
OWNER_EMAIL, BETTER_AUTH_SECRET | The account that can sign up without an invite, and the key that signs sessions. Sign-in also needs GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET, or RESEND_API_KEY for emailed links (without it the link is printed in the server log). See docs/deploying.md. |
For how the default model was chosen, see docs/evals.md. For hosting it privately on Vercel, see docs/deploying.md.
| Command | What it does |
|---|---|
npm run dev | Starts the dev server |
npm run check | Typecheck, Biome lint and format check, and the unit tests. CI runs this. |
npm run format | Applies Biome's fixes and formatting |
npm run build | Production build |
npm run e2e | Builds the app and runs the Playwright tests in desktop and mobile Chrome |
npm run eval | Runs the eval cases against a real model; this costs money |
npm run data:* | Refreshes the data the app ships with; see docs/data-pipeline.md |
The unit tests (Vitest) never touch the network. They read the same snapshots of the card set,
taboo lists and decklists that the index was built from (tests/fixtures/). They check
behavior against answers known in advance, for example:
deck tool's.The system prompt and every tool definition are pinned in tests/golden/, since any change to
them changes what the model reads. After a deliberate change, regenerate the pins with
UPDATE_GOLDEN=1 npx vitest run tests/golden.test.ts and review the diff.
The end-to-end tests (Playwright) run the production build against the mock model and the same
snapshots, so they need no API key either. CI runs both suites on every push to main and on
every pull request.
The evals (evals/cases.ts) are the product's use cases run against a real model, with a
spending cap. Each case writes a transcript to evals/results/ (git-ignored) for a person to
read. The evals don't grade answers, but they flag card codes that no tool returned, taboo
mentions while the list is off, a deck called by its number, and empty answers.
set -a && . ./.env.local && set +a # load the API keys into the shell
npm run eval -- --model openai:gpt-6-sol --max-usd 2 --cases rules-doom,partner
Omit --cases to run all of them. docs/evals.md has the results per model.
arkham-ai/
├── app/
│ ├── api/chat/route.ts # POST /api/chat: validates and runs the agent
│ └── assistant.tsx # the chat page
├── components/
│ ├── tools/ # how each tool's result renders in the chat
│ ├── settings/ # the taboo-list switch
│ ├── assistant-ui/ # thread and sidebar, adapted from assistant-ui
│ └── ui/ # shadcn/ui primitives (vendored)
├── hooks/ # client hooks: settings, chat title, media queries
├── lib/
│ ├── agent.ts # the agent loop and its budgets
│ ├── prompt.ts # system prompt, with the Rules Reference inlined
│ ├── model.ts # picks the provider and model from the environment
│ ├── tools/ # cards, deck, recommendDecks, replaceCard
│ ├── cards.ts # the card store, loaded from ArkhamDB
│ ├── legality.ts # ArkhamDB's deckbuilding rules
│ ├── collection.json # the packs the players own
│ └── index/ # the deck index and card play rates (generated)
├── pipeline/ # offline scripts that build the index and data
├── data/
│ ├── rules.md # the Rules Reference
│ ├── faq.json # official rulings
│ └── deck-labels/ # role, archetypes and summary of each indexed deck
├── tests/ # unit tests; fixtures/ holds the data snapshots
├── e2e/ # Playwright tests
├── evals/ # eval cases and their runner
└── docs/
| Document | Covers |
|---|---|
| ARCHITECTURE.md | How a request is answered, end to end |
| design-decisions.md | Why it is built this way, and the alternatives that were rejected |
| data-pipeline.md | How the deck index is built, and how to refresh any data |
| archetypes.md | What each deck archetype means |
| evals.md | How answers were checked, per model, and what that changed |
| deploying.md | Deploying to Vercel behind authentication |
| design-log.md | The project's history: each version, what was measured, what was dropped |
| AGENTS.md | The invariants to keep when changing the code |
This is an unofficial fan project. It is not affiliated with or endorsed by Fantasy Flight Games or ArkhamDB.
data/rules.md) and the
official FAQ rulings (data/faq.json) are © Fantasy Flight Games.app/fonts/arkham-icons.woff) and the card scans the card dialog shows
are ArkhamDB's.The code is released under the MIT License. The license does not cover the
third-party material listed above: data/rules.md, app/fonts/arkham-icons.woff, data/faq.json, the deck index in
lib/index/ (built from public decklists) and the ArkhamDB snapshots in tests/fixtures/.