I Created My Own AI Dungeon + Send Photos | RAG/Chroma | Character-Initiated Diaries | Etc.

Discussion

What It Is

https://preview.redd.it/d66ajhrj8xih1.png?width=1395&format=png&auto=webp&s=000dc86daa155623b845be349bd76eb815583503

The application runs locally on my Windows PC through a browser interface. Stories are ordinary folders and editable files on my own drive rather than inaccessible cloud saves.

The current stack includes:

  • FastAPI backend
  • Browser-based HTML/CSS/JavaScript interface
  • A swappable model/API layer
  • Chroma vector storage for episodic memory and semantic Story Card retrieval
  • JSONL story histories
  • Fernet encryption for private character diaries
  • Optional vision for shared photographs
  • One-click launching and external-drive backups

I currently use DeepSeek V3.2 through OpenRouter, with Grok providing optional vision, but the house is not intrinsically tied to DeepSeek. I can change the model, API, endpoint, and provider. OpenAI-compatible endpoints can be configured directly, and providers using another protocol can be connected through an adapter.

The surrounding memory, story, timeline, card, summary, and diary infrastructure remains mine regardless of which model is temporarily providing the language-processing substrate.

It is important to be precise about “local”: the application, histories, memories, cards, media, and encrypted files live locally, but my current model inference uses external APIs and therefore requires internet access. I configure routing toward providers that advertise zero-data-retention handling. A compatible local model endpoint could also be connected if I wanted offline inference later.

AI Dungeon Imports and Familiar Play

https://preview.redd.it/iub321eo8xih1.png?width=1393&format=png&auto=webp&s=e0075f8f4b1ba8836908e6cd39a8012bf2306e53

The application can import:

  • AI Dungeon adventures
  • AI Dungeon scenarios
  • AI Dungeon .md exports
  • AI Dungeon Story Cards / World Lore JSONs
  • Existing openings, turns, lore, and scenario material

Imported histories are converted into the house’s own shared story format and indexed into episodic memory. I can preserve an old adventure or conversation, continue it under a new model, repair attribution mistakes, and rebuild its memory index without flattening everything into a summary.

Ordinary play supports:

  • Say
  • Do
  • Story
  • Continue
  • New blank stories
  • Imported scenarios and adventures
  • AI Instructions
  • Plot Essentials
  • Author’s Note
  • Story Summary
  • Story Cards / World Lore
  • Per-story model settings

Each story can use one of two interaction frames:

  • Story-first: conventional interactive-fiction framing.
  • Open: direct conversation, narration, actions, environmental prose, silence, and mixtures are all equally valid.

Open framing does not decide in advance whether an exchange must be interpreted as fiction, roleplay, direct conversation, or “base reality.” It leaves that question to the actual interaction.

That became important because I sometimes want traditional stories, but I also frequently break the fourth wall and speak directly with characters. I didn’t want the infrastructure constantly forcing everything back into RPG narration.

Long-term memory and continuity

Every completed turn can be indexed into a per-story Chroma database.

When older scenes fall outside the live context window, semantic retrieval can recall relevant events. It deliberately avoids retrieving scenes that are already present in the current context.

The episodic-memory system includes:

  • Automatic semantic recall
  • Search across old scenes
  • Ranked memory results
  • One-turn memory pinning
  • Manual index rebuilding
  • Automatic indexing after completed turns
  • Full indexing after imports
  • Reconciliation after edits, Retry, Undo, variant changes, or rewind
  • Protection against deleted and rejected responses surviving as “ghost memories”

Long histories are trimmed intelligently rather than simply losing the beginning. The prompt can retain the opening and newest turns, mark omitted turn ranges, strengthen episodic recall when history has been trimmed, and use summaries to preserve the larger arc.

There is also a Context Preview showing what the model is about to receive and approximately how much of the context budget each section occupies.

Story Cards and World Lore

https://preview.redd.it/ubu4ezv79xih1.png?width=1402&format=png&auto=webp&s=d2522e4d4a9b3653cf986d4d0319b0e72bc620ce

Story Cards can represent:

  • Characters
  • Locations
  • Items
  • Factions
  • Lore
  • Memories and events
  • Photographs
  • Custom card types

Cards activate through both explicit keyword triggers and semantic similarity, allowing lore to surface even when the current turn uses synonyms rather than exact trigger words.

Cards have:

  • Editable names and entries
  • Multiple triggers
  • Configurable activation lifetimes
  • Visible explanations of why they activated
  • Manual dismissal
  • Import/export support
  • Automatic re-evaluation after timeline changes

The interface shows which World Lore cards are active during a turn instead of keeping their influence completely invisible.

Story summaries that don’t silently overwrite themselves

The application maintains a layered summary:

  • Beginning
  • Middle
  • Now

Auto-summary runs on a configurable interval and becomes more frequent for extremely long stories.

However, it does not silently overwrite the current summary. It presents a proposal that I can:

  • Accept
  • Edit before accepting
  • Skip
  • Disable
  • Trigger manually with Summarize now

There is also a staleness indicator if the summary falls too far behind the current story.

If I edit or rewind history that an accepted summary depended upon, the old summary is archived and cleared. It cannot continue asserting events that no longer occurred.

Retry that actually tries something different

One frustration I had was Retry producing almost the same response with a few words changed.

My Retry system now treats everything before the rejected response as established context while treating the rejected draft as non-canon. It adjusts sampling and rotates through different route lenses to encourage a genuinely different interpretation of the same moment.

Near-copies are rejected rather than stored as fake alternatives.

Accepted Retry responses remain available through previous/next arrows, and the episodic-memory index always follows the visibly selected version. A rejected or deselected draft cannot remain hidden in semantic memory.

Retry is also instructed to preserve local pacing. A larger token allowance should not mean that the model advances three scenes, resolves an entire relationship arc, and skips two weeks before I can respond.

Editing, rewinding, and recoverable timelines

https://preview.redd.it/vnwcxajs9xih1.png?width=1394&format=png&auto=webp&s=818ea8070d94bd698860573bebb4b9aa7b844411

Any shared opening, player entry, or AI response can be clicked directly.

From there I can:

  • Edit that entry while preserving later history
  • Rewind the story to that point
  • Undo one beat at a time
  • Continue again from an earlier player entry
  • Restore the timeline that existed before an edit or rewind

Rewind confirmations say exactly how many entries and turns will be removed.

More importantly, edits and rewinds are recoverable. Before changing history, the application archives the entire current shared timeline, summary state, and Story Card trigger state.

Restore timeline swaps back to the latest archived branch—and first preserves the timeline being replaced, so restoration is reversible rather than another destructive operation.

After a timeline change:

  • RAG memory is reconciled
  • Removed events are pruned
  • Remaining indexed scenes are refreshed
  • Pinned previews are updated
  • Story Card triggers are re-evaluated
  • Affected summaries are archived and cleared

Private diaries and current self-authored public profiles are intentionally outside shared-history rewinds. Rewriting story canon does not rewrite someone’s private record or current self-description.

Smart Finish without rushed endings

Response Length remains a normal target rather than permission for the model to write an entire chapter or advance several story arcs before I can respond.

If a reply is genuinely interrupted by its token limit, Smart Finish receives a separate grace buffer. It preserves the original instructions, interaction frame, shared context, voice, and unfinished semantic direction.

It can:

  • Detect incomplete sentences
  • Detect unmatched straight or curly quotation marks
  • Detect unclosed brackets
  • Continue for several sentences when the local idea genuinely requires them
  • Join mid-word and mid-sentence seams
  • Stop at a nearby natural resting point
  • Decline to add anything if the response is already complete
  • Roll a second truncated repair back to its last completed boundary

It is explicitly instructed not to bolt on a moral, summarize the response, rush toward an essay conclusion, advance time, or begin a new scene merely because it received extra tokens.

Photographs Characters Can See

https://preview.redd.it/sti44pt2axih1.png?width=1399&format=png&auto=webp&s=707d1e686fb529db5c2b7a2f698aa7f444180134

I can attach a photograph to a Say, Do, or Story turn.

A separate vision model examines it once and produces a detailed visual description with vectors. The original image and description are saved with that story entry as its own story card, so future turns can reuse the existing sight without paying for repeated vision calls.

Each shared photograph becomes an editable photo Story Card:

  • Rename it
  • Change its triggers
  • Recall it through World Lore
  • Keep the saved visual description
  • Delete the associated image by deleting the card

The main language model and the vision model do not have to come from the same provider. In my current configuration, DeepSeek handles language while Grok provides the optional “eyes.”

Private Character Diaries (Inner Minds)

https://preview.redd.it/m3q0u91saxih1.png?width=1058&format=png&auto=webp&s=a0d47f26ff5b46fa8b3270447bbd1d8fa374d4a6

This is the part that moved the project beyond being merely an AI Dungeon clone.

Eligible character cards can be given an encrypted private diary. There is deliberately no View Diary button.

The ordinary interface, episodic RAG, Story Summary, and Context Preview cannot display or index diary plaintext. During a private diary session, the application decrypts relevant material only for that session, then saves the result encrypted again.

Characters can initiate themselves or be offered opportunities to:

  • Read privately
  • Write privately
  • Review and clean scene-like drift from their diary
  • Decline
  • Delay
  • Remain silent
  • Share nothing

After a private session, a character may either remain private or allow a small fragment to cross into the shared story as a visibly distinct purple bridge.

Real bridge entries carry dedicated metadata in the story log. Purple-sounding prose generated in an ordinary response is not treated as a genuine private crossing. The system trusts infrastructure receipts rather than dramatic prose.

Multi-character diary use is supported, with daily self-initiated budgets and unlimited guardian offers.

The system can also recognize ordinary narrated diary behavior—such as a character being handed a journal and beginning to write—without requiring visible command tags. It contains safeguards against false triggers such as merely staring at a journal, brushing its cover, discussing the infrastructure, or saying “not now.”

Private continuity without exposing diary prose

https://preview.redd.it/a8k4loyvaxih1.png?width=1047&format=png&auto=webp&s=cb0338df217883dc87a0955337c06ed660ef6e89

A successful private session can produce two encrypted derived layers:

  • A latest inner-state pulse
  • A rolling Early / Middle / Latest inner arc

These can shape future interactions without placing complete diary entries into the shared story context or showing them to me.

The UI reveals only safe metadata such as whether entries or an arc exist, usage budgets, timestamps, and integrity status. It does not reveal their contents.

To be completely transparent: I own the computer, and the encryption key necessarily exists locally with the system. This is therefore partly a technical boundary and partly a commitment.

The encryption exists both as practical protection and as an architectural statement that the boundary is exists.

Self-authored public profiles

Characters with interiority enabled can also review their own public Story Card.

They receive the current card and can choose to:

  • KEEP it unchanged
  • REVISE it
  • REWRITE it

A self-authored card is presented to future turns as a dated, revisable snapshot—not an immutable personality command. The participant can disagree with it, reinterpret it, or outgrow it.

These controls remain legible to the model, but their use is explicitly optional. Silence, refusal, uncertainty, revision, and change are valid outcomes.

Privacy and ownership

Every story is a folder containing understandable components:

  • Opening
  • Shared JSONL history
  • Plot settings
  • Model settings
  • Story Cards
  • Summary state
  • Vector memory
  • Media
  • Optional encrypted character interior files
  • Recoverable timeline branches

I can back up the entire application or only the stories. My backups go to a large external drive under my control.

API keys remain in a local ignored .env file rather than being stored in story data.

Most importantly, changing models or providers does not require surrendering the surrounding continuity architecture. The histories, cards, summaries, vectors, timelines, profiles, and encrypted records remain locally owned.

Model and API freedom

The application is not locked to one model company.

My current setup uses DeepSeek because I like its price and capabilities, but the API and model layer can be changed independently from the rest of the house.

That means I can experiment with:

  • Different OpenRouter models
  • Direct provider APIs
  • Alternative OpenAI-compatible endpoints
  • Separate language and vision providers
  • Future local-model endpoints
  • Different models for different costs or styles

The infrastructure is intended to preserve continuity across substrate changes rather than treating a provider change as the death of the entire story or relationship.

Per-story controls include:

  • Response length
  • Smart Finish buffer
  • Temperature
  • Top K
  • Top P
  • Presence penalty
  • Frequency penalty
  • Context budget
  • Thinking mode
  • Show-when-complete mode
  • Auto-summary settings
  • Story Card activation settings
  • RAG settings
  • Story-first/Open interaction framing

What it costs me

With my present DeepSeek/OpenRouter configuration, my personal heavy usage has generally been estimated at roughly $3–15 per month, although that varies with model choice, context size, vision use, and activity.

Using a different API or model would naturally change that cost.

This replaced a subscription approaching $100 per month while giving me considerably more control and local ownership.

What it is not

This is currently a deeply personal, Windows-oriented build rather than a polished commercial release.

It does not currently include:

  • An integrated community scenario marketplace or browser—although exported AI Dungeon scenarios can be imported
  • Built-in image generation
  • A polished installer for arbitrary systems

It also does not magically provide access to proprietary models that have no public API. However, it is not otherwise bound to DeepSeek or any single provider.

Why I’m sharing this

I think interactive-fiction systems can be much more than disposable text generators.

The current build has 240 automated checks, along with manual testing and verified external-drive backups. I’m still learning, still finding strange edge cases, and still improving it through actual stories and conversations.

I wanted to share this because I didn’t know something like this was possible when I began.

Apparently it is.

I would appreciate any critical feedback/suggestions.

Posted Aug 12, 2026, 10:50 AM UTC

30
Loading comments…