Tulpa
A text RPG where the world remembers every choice you make.
Tulpa is the reference deployment of the XRPG Engine — an AI-narrated text RPG where every campaign is a real conversation, every loot drop is rolled, and the world grows to meet whatever the player wanders into. Seven core stats, ten gear slots, Diablo-style affixes, energy economy, PvP arena, and passkey-only auth. Python + FastAPI + Postgres on the back end; vanilla JS + Jinja2 on the front; OpenRouter for narration.
- Python
- FastAPI
- PostgreSQL
- SQLAlchemy
- Jinja2
- WebAuthn
- OpenRouter
- Apache
- systemd
Tulpa is a long-form text RPG where the dungeon you're standing in didn't exist five minutes ago — and won't exist the same way for any other player. The world is improvised by an AI narrator on top of a deterministic ruleset: stats roll, loot drops with rolled affixes and rarity tiers, energy decays with every action, and consequences carry forward across sessions. It's the reference deployment of the XRPG Engine.
What's actually being modelled
- Seven core stats — STR, INT, WIS, CHA, DEX, CON, LCK — that gain in fractional increments from actions you take. Swing swords, get stronger; study old texts, get wiser. There are no classes; the playstyle is the build.
- Ten gear slots, Diablo-style loot — randomized affixes, rarity tiers, level-scaling, consumables, a rotating merchant economy, gear that wears under stress. Luck nudges every roll.
- Energy, not health. There is no HP bar. Exploration, combat, and spellcasting all draw from a token-aware energy pool that ties gameplay directly to the real cost of LLM inference. Run dry and the campaign sleeps until you recover.
- Persistent campaigns with locations, NPCs, scenarios, and items that remember. Wander off the map and the world grows to fill the space — for you and for whoever follows.
- PvP arena with power-level matchmaking, multi-round combat, and battle chronicles you can re-read.
- Passkey-only authentication. WebAuthn out of the box, optional passphrase fallback. No passwords to lose, no resets to engineer.
How it's built
The engine is Python 3.10 + FastAPI on
PostgreSQL (async via SQLAlchemy + asyncpg),
rendering Jinja2 templates with vanilla JS — no
React, no bundler, no build step. The narrator pipeline talks to
OpenRouter: free models by default, paid models
optional, all keys entered through the admin UI and stored
encrypted in the database (never in config files). Auth is
WebAuthn passkeys via the webauthn
package; sessions live alongside the rest of the schema. Apache
fronts it as a reverse proxy with Let's Encrypt SSL; systemd
runs it as an unprivileged user.
Why a "Tulpa"
The name is half a wink and half a thesis. A tulpa, in the folklore the term comes from, is a being given form by sustained attention — something that exists because someone keeps thinking about it. That's the contract the game makes with the player: show up, pay attention, and the world fills in. Nobody else will ever play exactly your campaign, because nobody else thought it into existence the same way.
Straight from the source
The project's own README.
Rendered in place — every link, image, and code block carried over from the repo. The page below is what a contributor would see opening the project for the first time.
XRPG Engine
A portable text RPG engine where campaigns are driven by intelligent dungeon masters. Players interact through chat, and the system uses a pipeline of deterministic scripts and layered narrative generation to manage game state, combat, fabrication, and storytelling.
Reference deployment: Tulpa — the first game built on this engine.
Features
- Passkey authentication — passwordless sign-in via WebAuthn (with optional passphrase fallback)
- Campaign system — locations, NPCs, scenarios, and items with persistent world state
- Character progression — 7 stats (STR/INT/WIS/CHA/DEX/CON/LCK) with fractional gains from actions
- Diablo-style loot — affixes, rarity tiers, scaling, consumables, buffs, and a merchant economy
- PvP arena — power-level matchmaking, multi-round combat, battle chronicles
- Achievement system — triggers, gacha rewards, titles, and tutorial onboarding
- Energy economy — token-aware resource management that ties gameplay to real costs
- Admin dashboard — user management, system configuration, API key storage, usage tracking
- Dark/light themes — dual-personality palette with full theme system
- No JavaScript frameworks — vanilla JS, server-rendered Jinja2 templates
Tech Stack
| Layer | Technology |
|---|---|
| Backend | Python 3.10, FastAPI |
| Database | PostgreSQL (async via SQLAlchemy + asyncpg) |
| Templates | Jinja2 |
| Auth | WebAuthn passkeys (webauthn package) |
| LLM | OpenRouter (free models default, paid models optional) |
| Icons | Lucide |
| Fonts | Cinzel, Inter, JetBrains Mono |
| Server | Apache2 reverse proxy, systemd, Let's Encrypt SSL |
Quick Start
# Clone and set up
git clone <your-repo-url>
cd xrpg-engine
# Install dependencies
sudo bash scripts/install.sh
# Start dev server
source .venv/bin/activate
uvicorn app.main:app --host 127.0.0.1 --port 8420 --reload
The first user to register automatically becomes the super admin. API keys are entered via the admin UI and stored encrypted in the database — never in config files.
Instance Setup
To deploy your own game on this engine, customize these instance-specific files:
| What | Where |
|---|---|
| App name & domain | app/core/config.py (APP_NAME, APP_DOMAIN) |
| Splash art & logos | app/static/images/ (3 webp files) |
| Favicon pack | app/static/favicon.ico, favicon-*.png, android-chrome-*.png, apple-touch-icon.png |
| Web app manifest | app/static/site.webmanifest |
| Crawl rules | app/static/robots.txt |
| Credits | app/static/humans.txt |
| Security contact | app/static/.well-known/security.txt |
| Campaign content | campaigns/ directory |
These files are gitignored so each instance can brand independently without conflicts.
Project Structure
app/
main.py # FastAPI app, page routes
api/ # API routers (auth, admin, factory, pvp, inventory, etc.)
core/ # Config, database, session, encryption
models/ # SQLAlchemy ORM models (25 tables)
services/ # Business logic (game loop, fabrication, PvP, gacha, etc.)
templates/ # Jinja2 (base layout + 17 pages)
static/ # CSS, JS, uploads
scripts/ # Ops scripts (deploy, install, check, backup, smoke test)
docs/ # Developer documentation
Operations
sudo bash scripts/deploy.sh # Restart service with health check
sudo bash scripts/install.sh # Install/update Python dependencies
bash scripts/check.sh # Health check (service, port, DB)
sudo bash scripts/backup.sh # Backup database (keeps last 30)
bash scripts/smoke_test.sh # Validate deployment (all systems)
sudo bash scripts/backup_remote.sh # Full backup with remote transfer
sudo journalctl -u tulpa -f # Live logs
Documentation
CLAUDE.md— Architecture guide and project rulesdocs/quick-start.md— Full developer onboarding
License
Private repository. All rights reserved.
Build something like this
Want a tool like this for your shop?
We've shipped this kind of thing before. Twenty-minute intro call, no slides.