Mimir Architecture
Architecture documentation following the C4 model: Context → Containers → Components → Code.
Level 1: System Context
Section titled “Level 1: System Context”Mimir is a local-first desktop application for D&D 5e campaign management. It has no cloud dependencies — all data stays on the user’s machine.
┌─────────────────────┐ │ Dungeon Master │ │ (User) │ └──────────┬──────────┘ │ ┌────────────────────┼────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Mimir │ │ Claude Code │ │ Dungeondraft│ │ Desktop App │ │ (via MCP) │ │ (Map Tool) │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ SQLite │ │ MCP Sidecar │ │ .dd2vtt / │ │ Database │◀────│ Server │ │ .uvtt files │ └─────────────┘ └─────────────┘ └─────────────┘Users: Dungeon Masters preparing and running D&D 5e campaigns.
External systems:
- Claude Code — AI assistant that manages campaigns via the MCP sidecar server
- Dungeondraft — Map authoring tool; Mimir imports UVTT maps and generates
.dungeondraft_mapfiles - 5etools — Source of D&D 5e catalog data (monsters, spells, items, etc.), imported into the database at runtime by the user from the Sources UI (
crates/mimir-core/src/import/)
Level 2: Container Diagram
Section titled “Level 2: Container Diagram”The system is a Cargo workspace with 5 crates, a Vue 3 frontend, and a SQLite database.
┌──────────────────────────────────────────────────────────┐│ Mimir Desktop App ││ ┌────────────────────────┐ ┌────────────────────────┐ ││ │ Vue 3 Frontend │ │ Tauri Shell (mimir) │ ││ │ TypeScript + Pinia │──│ Rust command handlers │ ││ │ │ │ │ ││ │ 4 feature modules: │ │ 16 command modules │ ││ │ campaigns, modules, │ │ AppState management │ ││ │ characters, sources │ │ │ ││ └────────────────────────┘ └───────────┬────────────┘ ││ │ ││ ┌───────────────────────────┼───────────┐ ││ │ │ │ ││ ▼ ▼ │ ││ ┌────────────────────────┐ ┌──────────────────┐ │ ││ │ mimir-core │ │ mimir-print │ │ ││ │ Domain logic, DAL, │ │ Typst-based │ │ ││ │ services, migrations │ │ PDF generation │ │ ││ └───────────┬────────────┘ └──────────────────┘ │ ││ │ │ ││ ▼ │ ││ ┌────────────────────────┐ │ ││ │ SQLite Database │ │ ││ │ 56 tables + FTS5, │ │ ││ │ WAL mode │ │ ││ └────────────────────────┘ │ │└──────────────────────────────────────────────────────┘ │ │┌──────────────────────────────────────────────────────┐ ││ MCP Sidecar (mimir-mcp) │ ││ Separate binary, launched by Tauri externalBin │◀──┘│ 54 tools across 8 categories ││ Depends on: mimir-core, mimir-mapgen │└──────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────┐│ Map Generator CLI (mimir-mapgen) ││ Standalone binary + library ││ Procedural terrain, rooms, polygons → Dungeondraft ││ No database dependency │└──────────────────────────────────────────────────────┘Container responsibilities
Section titled “Container responsibilities”| Container | Technology | Purpose |
|---|---|---|
| Vue 3 Frontend | TypeScript, Pinia, Tiptap, Tailwind | UI: campaign dashboard, character sheets, play mode, player display |
| Tauri Shell (mimir) | Rust, Tauri 2 | IPC command handlers, AppState, window management |
| mimir-core | Rust, Diesel ORM | Domain models, services, data access layer, migrations |
| mimir-print | Rust, Typst | PDF generation: character sheets, spell cards, map prints |
| mimir-mcp | Rust, rust-mcp-sdk | MCP server exposing campaign management to AI assistants |
| mimir-mapgen | Rust, noise-rs, clap | Procedural map generation with YAML config or biome presets |
| SQLite Database | SQLite 3, WAL mode | 56 schema tables plus FTS5 indexes: campaigns, characters, maps, D&D 5e catalog |
Crate dependency graph
Section titled “Crate dependency graph”mimir ──────► mimir-core │ └─────────► mimir-print
mimir-mcp ──► mimir-core │ └─────────► mimir-mapgen
(mimir-core, mimir-print, mimir-mapgen have no internal crate dependencies)Level 3: Component Diagrams
Section titled “Level 3: Component Diagrams”mimir-core — Domain Logic
Section titled “mimir-core — Domain Logic”The shared library containing all business logic and data access.
┌─────────────────────────────────────────────────────────┐│ mimir-core ││ ││ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││ │ Models │ │ Services │ │ DAL │ ││ │ │ │ │ │ │ ││ │ campaign/ │ │ Campaign │ │ Repository │ ││ │ catalog/ │◀─│ Character │──│ traits │ ││ │ character/ │ │ Module │ │ │ ││ │ │ │ Document │ │ Diesel │ ││ │ Domain │ │ Map, Token │ │ queries │ ││ │ types and │ │ Archive │ │ │ ││ │ enums │ │ Asset │ └──────────────┘ ││ │ │ │ Homebrew │ ││ └──────────────┘ │ │ ┌──────────────┐ ││ │ 24 catalog │ │ Migrations │ ││ │ services │ │ 29 migrations│ ││ └──────────────┘ └──────────────┘ │└─────────────────────────────────────────────────────────┘Service layer pattern (per ADR-0005):
Services are stateful structs that borrow a database connection:
pub struct CampaignService<'a> { pub conn: &'a mut SqliteConnection,}
impl<'a> CampaignService<'a> { pub fn new(conn: &'a mut SqliteConnection) -> Self { Self { conn } }
pub fn create(&mut self, input: CreateCampaignInput) -> ServiceResult<Campaign> { // Business logic + database access }}Service inventory:
| Category | Services |
|---|---|
| Campaign | CampaignService, ModuleService, DocumentService, ArchiveService, AssetService |
| Character | CharacterService, HomebrewService |
| Map | MapService, TokenService |
| Catalog (24) | SpellService, MonsterService, ItemService, ClassService, RaceService, BackgroundService, FeatService, ConditionService, SubclassService, and 15 more |
Tauri Shell — Command Layer
Section titled “Tauri Shell — Command Layer”The mimir crate bridges the Vue frontend to core services via Tauri IPC commands.
┌──────────────────────────────────────────────────────────┐│ mimir (Tauri) ││ ││ ┌─────────────┐ ┌──────────────────────────────────┐ ││ │ AppState │ │ Commands (16 modules) │ ││ │ │ │ │ ││ │ AppPaths │ │ campaign character map │ ││ │ (data_dir, │◀───│ module document print │ ││ │ db_path, │ │ archive homebrew*3 token │ ││ │ is_dev) │ │ asset source dev │ ││ │ │ │ dm_map player_display │ ││ └─────────────┘ │ catalog/ (8 sub-modules) │ ││ └──────────────────────────────────┘ ││ ││ ┌──────────────────────────────────────────────────────┐ ││ │ Sidecar Management │ ││ │ Launches mimir-mcp as externalBin process │ ││ │ Configured in tauri.conf.json │ ││ └──────────────────────────────────────────────────────┘ │└──────────────────────────────────────────────────────────┘Request flow:
Vue Component │ invoke('get_campaign', { id: 42 }) ▼Tauri IPC │ Deserialize params, inject State<AppState> ▼Command Handler (commands/campaign.rs) │ let mut conn = state.get_connection()?; │ let mut svc = CampaignService::new(&mut conn); ▼CampaignService (mimir-core) │ svc.get_by_id(42)? ▼Diesel Query → SQLite │ ▼Result<ApiResponse<Campaign>, ApiError> → JSON → FrontendVue 3 Frontend
Section titled “Vue 3 Frontend”Feature-based organization with 4 domain modules.
frontend/src/├── app/ # App bootstrap, router, root layout├── features/│ ├── campaigns/ # Dashboard, module listing, homebrew tab│ │ ├── views/ # CampaignDashboardView, etc.│ │ ├── components/ # WorldTab, ModulesTab, PCsTab, NPCsTab, HomebrewTab│ │ └── composables/ # useDashboardState│ ├── characters/ # Creation wizard, character sheet, level-up│ │ ├── views/ # CharacterListView, CharacterSheetView│ │ └── components/ # CharacterCreationWizard, LevelUpDialog│ ├── modules/ # Module prep, player display│ │ ├── views/ # ModulePrepView│ │ └── components/ # ModuleMonsters, ModuleNPCs, ModuleMaps│ └── sources/ # D&D 5e catalog browser│ └── composables/ # useCatalogSearch (instantiated 22×)├── components/ # Shared: TokenPalette, DmMapViewer, print dialogs├── stores/ # Pinia: campaigns, characters, theme├── services/ # Tauri command wrappers└── types/ # TypeScript interfaces (generated from Rust)Key architectural patterns:
- Composition API with
<script setup>exclusively - Pinia setup stores (function-based, not options-based)
- Tauri
invoke()for all backend communication ApiResponse<T>wrapper for consistent error handling- 3 themes: light, dark, hyper (CSS variables + Pinia persistence)
mimir-mcp — MCP Sidecar Server
Section titled “mimir-mcp — MCP Sidecar Server”Runs as a separate process, sharing the same SQLite database.
┌──────────────────────────────────────────────────────────┐│ mimir-mcp ││ ││ ┌──────────────┐ ┌──────────────────────────────────┐ ││ │ MCP Server │ │ Tools (54 total) │ ││ │ │ │ │ ││ │ rust-mcp- │ │ character (13) campaign (10) │ ││ │ sdk 0.8 │ │ module (8) map (8) │ ││ │ │ │ document (6) homebrew (5) │ ││ │ stdio + │◀───│ mapgen (3) catalog (1) │ ││ │ streamable │ │ │ ││ │ HTTP │ │ │ ││ └──────────────┘ └──────────────────────────────────┘ ││ ││ ┌──────────────┐ ┌──────────────────────────────────┐ ││ │ Database │ │ Claude Code Plugin │ ││ │ Context │ │ plugin/ directory with: │ ││ │ │ │ - plugin.json (manifest) │ ││ │ Shares same │ │ - skills/ (mapgen, mimir-dm) │ ││ │ SQLite DB │ │ - agents/ (campaign authoring) │ ││ │ as Tauri app │ │ - hooks/ (event handlers) │ ││ └──────────────┘ └──────────────────────────────────┘ │└──────────────────────────────────────────────────────────┘Sidecar lifecycle:
- Tauri launches
mimir-mcpbinary viaexternalBinconfiguration - Binary built to
crates/mimir/binaries/mimir-mcp-{target-triple} - Build scripts:
scripts/build-sidecar.{sh,ps1,mjs} - Must be built before
cargo build -p mimir(Tauri requirement)
mimir-mapgen — Procedural Map Generator
Section titled “mimir-mapgen — Procedural Map Generator”Standalone library + CLI for generating Dungeondraft-compatible maps.
┌──────────────────────────────────────────────────────────┐│ mimir-mapgen ││ ││ CLI Interface (clap) Pipeline ││ ┌──────────────────┐ ┌──────────────────────┐ ││ │ generate │ │ YAML Config │ ││ │ --config / --preset │ │ │ ││ │ --output │────────│ ▼ │ ││ │ --seed │ │ Noise Generation │ ││ │ validate │ │ │ │ ││ │ list-presets │ │ ▼ │ ││ └──────────────────┘ │ Terrain Blending │ ││ │ │ │ ││ Core Modules (15) │ ▼ │ ││ ┌──────────────────┐ │ Object Placement │ ││ │ noise_gen │ │ (trees, clutter) │ ││ │ terrain │ │ │ │ ││ │ objects │ │ ▼ │ ││ │ paths (roads, │ │ Paths & Water │ ││ │ rivers, meander) │ │ (exclusion zones) │ ││ │ water │ │ │ │ ││ │ rooms │ │ ▼ │ ││ │ polygons │ │ Rooms / Polygons │ ││ │ elevation │ │ │ │ ││ │ contour │ │ ▼ │ ││ │ biomes (12 │ │ Dungeondraft │ ││ │ presets) │ │ Format Output │ ││ │ format │ │ (.dungeondraft_map) │ ││ │ pipeline │ └──────────────────────┘ ││ │ distribution │ ││ │ curves │ ││ │ assets │ ││ └──────────────────┘ │└──────────────────────────────────────────────────────────┘No database dependency. Operates entirely on YAML config input → file output.
mimir-print — PDF Generation
Section titled “mimir-print — PDF Generation”Typst-based document builder with pluggable sections.
┌──────────────────────────────────────────────────────────┐│ mimir-print ││ ││ ┌──────────────┐ ┌──────────────────────────────────┐ ││ │ PrintService │ │ Renderable Sections │ ││ │ │ │ │ ││ │ Template │ │ CharacterSection (2-page sheet) │ ││ │ resolution + │ │ CharacterBattleCardSection │ ││ │ PDF compile │ │ SpellCardsSection (3×3 grid) │ ││ │ │ │ EquipmentCardsSection │ ││ └──────────────┘ │ MonsterCardSection │ ││ │ TrapCardSection │ ││ ┌──────────────┐ │ TiledMapSection + MapPreview │ ││ │ DocumentBuilder │ TokenCutoutSection │ ││ │ │ │ MarkdownSection │ ││ │ Assembles │ └──────────────────────────────────┘ ││ │ sections into│ ││ │ multi-part │ ┌──────────────────────────────────┐ ││ │ documents │ │ Support Modules │ ││ └──────────────┘ │ markdown → Typst converter │ ││ │ map_renderer (grid, LOS, tokens) │ ││ │ Typst World (font/file resolver) │ ││ └──────────────────────────────────┘ │└──────────────────────────────────────────────────────────┘Level 4: Key Design Decisions
Section titled “Level 4: Key Design Decisions”Detailed rationale lives in ADRs. Summary:
| Decision | ADR | Rationale |
|---|---|---|
| Denormalized catalog data | ADR-0001 | Child entities (subclasses, subraces) embed full parent data to avoid joins on read |
| Multi-ruleset content | ADR-0002 | Content organized by rule system and source for future expansion |
| JSON columns | ADR-0003 | Variable/complex fields (spell components, monster traits) stored as JSON |
| Stateful services | ADR-0005 | Services borrow &mut SqliteConnection for lifetime-scoped transactions |
Database Schema (56 schema tables plus FTS5 indexes)
Section titled “Database Schema (56 schema tables plus FTS5 indexes)”| Category | Tables | Examples |
|---|---|---|
| Campaign (7) | campaigns, modules, documents, campaign_sources, campaign_assets, campaign_homebrew_* | Core user data |
| Character (8) | characters, character_classes, character_spells, character_inventory, character_feats, character_features, character_proficiencies, character_sources | PC/NPC data |
| Map & Tokens (8) | maps, token_placements, light_sources, fog_revealed_areas, map_pois, map_traps, module_monsters, module_npcs | Spatial data |
| D&D Catalog (28) | spells, monsters, items, classes, races, backgrounds, feats, conditions, subclasses, etc. | Immutable 5etools data |
| Management (5) | catalog_sources, books, spell_classes, spell_subclasses, item_attunement_classes | Relationships & metadata |
Data Paths
Section titled “Data Paths”| Environment | Database | Assets |
|---|---|---|
| Production | ~/Library/Application Support/com.mimir.app/data/mimir.db |
~/Library/Application Support/com.mimir.app/assets/ |
| Development | ~/Library/Application Support/com.mimir.app/dev/data/mimir.db |
~/Library/Application Support/com.mimir.app/dev/assets/ |
Dev mode activated by debug assertions or MIMIR_DEV environment variable. Paths shown are macOS; Linux uses ~/.local/share/, Windows uses %APPDATA%.
Directory Structure
Section titled “Directory Structure”mimir/├── Cargo.toml # Workspace manifest (5 crates)├── crates/│ ├── mimir/ # Tauri desktop application│ │ ├── src/│ │ │ ├── main.rs # Entry point, plugin registration│ │ │ ├── state.rs # AppState, AppPaths, dev/prod separation│ │ │ └── commands/ # 16 Tauri command modules│ │ │ └── catalog/ # 8 sub-modules for D&D catalog queries│ │ ├── frontend/ # Vue 3 + TypeScript application│ │ │ └── src/│ │ │ ├── features/ # campaigns/, characters/, modules/, sources/│ │ │ ├── components/ # Shared: TokenPalette, DmMapViewer, print dialogs│ │ │ └── stores/ # Pinia: campaigns, characters, theme│ │ ├── binaries/ # Sidecar output (mimir-mcp-{target})│ │ └── tauri.conf.json # Tauri config with externalBin sidecar│ ││ ├── mimir-core/ # Domain logic library│ │ └── src/│ │ ├── models/ # Domain types (catalog/, campaign/)│ │ ├── services/ # 9 core + 24 catalog services│ │ │ └── catalog/ # Spell, Monster, Item, Class, Race, etc.│ │ ├── dal/ # Data access layer│ │ └── migrations/ # 29 Diesel migrations│ ││ ├── mimir-mcp/ # MCP sidecar server│ │ ├── src/│ │ │ ├── main.rs # Server bootstrap (stdio + HTTP)│ │ │ └── tools/ # 8 tool modules (54 tools total)│ │ └── plugin/ # Claude Code plugin definition│ │ ├── plugin.json # Manifest│ │ ├── skills/ # mapgen, mimir-dm, mimir-campaign│ │ └── agents/ # Campaign authoring agent│ ││ ├── mimir-print/ # PDF generation library│ │ └── src/│ │ ├── service.rs # PrintService│ │ ├── builder.rs # DocumentBuilder│ │ ├── sections/ # 9 renderable section types│ │ └── map_renderer.rs # Map image rendering│ ││ └── mimir-mapgen/ # Map generation library + CLI│ ├── src/│ │ ├── main.rs # CLI (generate, validate, list-presets)│ │ ├── pipeline.rs # MapConfig, generation orchestration│ │ ├── biomes.rs # 12 biome presets│ │ └── (13 more modules) # noise, terrain, paths, water, rooms, etc.│ └── examples/ # YAML configs + generated maps│├── docs/ # Documentation (Astro Starlight)├── scripts/ # Build scripts (sidecar, CI)└── .metis/ # Project management (ADRs, initiatives)