CoOp:Anything
Search any game and see how much of it you can play with friends: every co-op mod, its stage, quality and community rating.
Arkham Horror LCG rules, cards and decks
Translation pending
GamesTypeScript · CSSGitHub @alon-pilosophOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full 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/.