Releases: kiselyovd/dungeon-master-ai
v0.12.0-real-engine - Make everything real (W1-W4)
[v0.12.0-real-engine] - 2026-06-16 - Make everything real (W1-W4)
The "make everything real" workstream: tool stubs are gone and the combat layer runs on real rules. Full design in the planning dir spec 2026-06-09-dmai-make-everything-real-design.md.
Added
- W1 combat engine: real initiative is rolled and sorted server-side; the frontend renders the backend initiative order.
- W1 turn-gating: token dragging is restricted to the active PC token, the movement budget is consumed on drag, and dead tokens (hp<=0) cannot be moved.
- W1 conditions gate movement and actions; the ActionBar is shown only on the player's turn; active-turn highlight plus token-move animation.
- W1 damage resistance/immunity/vulnerability applied in
apply_damage(migration0006_token_resistances). - W2
query_rulesperforms real SRD retrieval through embeddings (SrdRetriever). - W2
set_scenepersists to a newscenestable (migration0005_scenes) and the current scene is injected into model context. - W2
quick_save/load captures and restores real combat plus scene state end-to-end. - W2 real spell resolution: compendium lookup, damage, resistances, and saves.
- W3 end-to-end video generation: sidecar
/video/generateSSE,generate_videotool,VideoGeneratedevent, and<video>rendering in chat. generate_imagesplit intogenerate_map(top-down, routed to the VTT) andgenerate_illustration(cinematic, routed to a chat tool-call card).- VTT zoom/pan/fit-to-view and a layers popover (grid / scene image / tokens).
- Local text-only models Qwen3-0.6B and Qwen3-8B via ISQ.
- VRAM auto-swap around image generation: stops the local LLM, frees the card for SDXL, and restarts the LLM on the same port.
Changed
- W4 honest pending indicator replaces the fake cycling-digit progress.
- W4
agentTurnInFlightdisables the model switch while a turn is in flight. - W4 danger Button variant for destructive confirmations.
- W4 journal renders markdown as sanitized rich HTML.
- Migrated the local LLM sidecar from the deprecated
mistralrs-servertomistralrs-cli serve(clean structured tool_calls), with a parser fallback for tool-calls that leak intodelta.content.
Known limitations
- 7 biome warnings remain (non-null assertions in tests, exhaustive-deps, descending-specificity); they do not block the gates.
- GGUF loading crashes after load on non-TTY Windows (upstream mistralrs); the default Gemma/ISQ path works.
- Rendering a generated illustration directly onto the VTT map is deferred (the image is generated and delivered over SSE).
v0.11.0-m11
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-server,
plussrc-tauri/). - axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.
v0.10.0-m10
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-server,
plussrc-tauri/). - axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.
v0.9.0-m9
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-serversrc-tauri/).
- axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.
v0.8.0-m8
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-serversrc-tauri/).
- axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.
v0.7.2-m7
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-serversrc-tauri/).
- axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.
v0.7.1-m7-5: M7.5-DM real GPU loaders close
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-serversrc-tauri/).
- axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.
v0.7.0-m7
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-serversrc-tauri/).
- axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.
v0.6.0-m6
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-serversrc-tauri/).
- axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.
v0.6.0-m5: ci(release): drop darwin-x86_64 from first-GA matrix
Changelog
All notable changes to this project are tracked here. The format follows
Keep a Changelog and the project
uses Semantic Versioning.
Tags before v1.0.0 are pre-release milestones; the public surface and
on-disk schema may change between them. See docs/RELEASE.md for the
release pipeline and docs/RELEASE_CHECKLIST.md for the per-release
manual smoke list.
[Unreleased] - M5 polish
Added
- Persistent
SessionSlice(src/state/session.ts) with lazily-minted
(activeCampaignId, activeSessionId)UUID pair, persisted via the
split-storage adapter (settings.json). useSessionhook that ensures a session exists on app mount and
rehydrates the chat fromGET /sessions/{id}/messagesso reopening a
campaign restores chat history (incl. images sent in prior sessions).- Frontend Stronghold-encrypted secrets vault via
tauri-plugin-stronghold2.x and@tauri-apps/plugin-stronghold.
Provider configs and the Replicate API key now sit in
dmai-vault.holdunder the OS-native app data dir; argon2 salt at
app_local_data_dir()/salt.txtis lazily created. One-shot migration
drains the pre-M5 plaintextsecrets.jsoninto the vault on first
read (closes M4 carry-over E.2 frontend half). - Backend
StrongholdSecretsRepoviaiota_stronghold2.x (closes M4
carry-over E.2 backend half). dmai-server now opens an encrypted
Stronghold snapshot on startup (path:DMAI_VAULT_PATHenv override
or sibling to the SQLite db file) and uses it as the SecretsRepo.
Survives a sidecar restart without the frontend re-delivering keys
via/settingsPOST.
Changed
useAgentTurnanduseChatnow read campaign and session IDs from
the persistentSessionSliceinstead of hardcoded zero-UUID
placeholders.streamChatinvocations pass the activesessionIdso the backend
persists user and assistant rows across launches.
Tests
- 181 vitest (+5 from Stronghold + session work) and 210 cargo
(+4 stronghold round-trip tests).
[v0.5.5-m4.5] - 2026-05-09 - Vision input + chat persistence
Added
- Multimodal user messages:
MessagePartenum (Text/Image) on
both backend and frontend;LlmProvider::supports_vision()capability
flag (Anthropic / OpenAICompat / mistralrs reporttrue). - Composer attachments: paperclip button, paste-from-clipboard, and
drag-drop on the chat panel; PNG/JPEG/WebP, ≤ 5 MB, ≤ 4 images per
message; thumbnail strip andImageLightboxModalfor full-size view. - Backend chat persistence:
messagestable (migration
0003_m4_5_messages.sql),db::insert_message,
db::list_messages_by_session, andGET /sessions/{id}/messages
endpoint returningVec<ChatMessage>JSON. /chatand/agent/turnaccept an optionalsession_idand persist
user, assistant, and tool-result rows when present.- HF Hub real tree-API walker (
/api/models/{repo}/tree/{rev}) for the
diffusers folder downloader; injectableHfEndpointsfor testing. - E2E vision-flow Playwright spec + RELEASE_CHECKLIST M4.5 section.
Changed
ChatMessage::User { content: String }->ChatMessage::User { parts: Vec<MessagePart> };ChatMessage::user_text(impl Into<String>)
helper for the common text-only path.HttpMessageaccepts both legacy{role, content}and new{role, parts}shapes via custom dual-shapeDeserialize(size guards: 5 MB
per image, 4 images per message - return HTTP 413 on overrun).
Tests
- 206 cargo + 167 vitest (cargo per-crate to avoid Tauri-bin
PDB-overflow LNK1140 on Windows).
[v0.5.0-m4] - 2026-05-08 - Local Mode + cross-platform packaging
Added
- Local LLM via
mistralrs-serverTauri sidecar binary (pinned
MISTRALRS_VERSION=v0.8.0), ProviderConfig variantlocal-mistralrs
hot-swappable from Settings. - Local image generation via Python sidecar (FastAPI + diffusers
SDXL-Turbo), GPU coordination mutex (auto-swap LLM unload before
image-gen). - Model manifest (Qwen3.5 0.8B/2B/4B/9B + SDXL-Turbo), download
manager with resumable HTTP Range + sha256 verify, per-model state
machine with cancel. LocalRuntimestate machine, free-port discovery, health-probe with
exponential backoff retry,RuntimeRegistryaggregating two
runtimes.- Tauri updater plugin +
UpdateAvailableModal+useUpdaterhook
(pubkey placeholder until first release). SecretsRepotrait +InMemorySecretsRepo(Stronghold real impl
deferred to M5).- Local Mode UI:
LocalModeSlice,useModelDownloadSSE hook,
useLocalRuntimeStatus5 s poll,ModelDownloadCard,
RuntimeStatusPill,LocalModeModal. - Cargo features: default
with-local-runtime,cloud-onlygates
Local Mode routes off via cfg-attribute. - CI:
build-bundle.ymlmatrix (4 targets, no signing) +release.yml
with Win EV cert + macOS rcodesign + notarytool + Linux AppImage. RELEASE_CHECKLIST.mdfor manual smoke after each release.
Tests
- 179 cargo + 157 vitest.
[v0.4.0-m3] - 2026-05-08 - LLM agent loop + RAG + journal + NPC
Added
AgentOrchestratorN-round tool-call loop with a 15-tool surface
(combat:roll_dice,apply_damage,start_combat,end_combat,
add_token,update_token,remove_token; narrative:set_scene,
cast_spell,remember_npc,recall_npc,journal_append,
quick_save,generate_image,query_rules).- SRD content (20 spells / 15 monsters / 30 rules / 4 classes) +
fastembed BGE-small-en (default switched to MultilingualE5Small for
RU+EN coverage) + cosine retriever; RAG injection in
context_builder. - Journal:
journal_entriestable,JournalVieweroverlay (full-screen
modal, EN/RU, parchment polish deferred to M5). - NPC memory:
npc_memorytable,NpcMemoryGrid(responsive 320x420
dossier cards, name/role search, disposition chip filters). ImageProvidertrait +ReplicateProvider(90 s deadline + 10 s
per-request timeouts + status-checked polling) + cache-key
(FNV-1a 64-bit hex of scene_id + sorted(npc_ids) + style_preset);
LocalSdxlSidecarProviderstub for M4.POST /agent/turnSSE endpoint wrappingAgentOrchestrator.- DM system prompts (EN+RU reference templates).
- Frontend
ToolCallCardwith settle animation (cycle digits at 100 ms
while pending, snap to JSON + 600 ms gold flash on settle),
ToolLogSlice,streamAgentTurn+useAgentTurnhook,
ToolInspectorDrawer(480 px right slide-in, copy-as-cURL). - Settings Model tab (system prompt + temperature 0..2 step 0.1 +
Replicate API key).
Tests
- 37 cargo + 140 vitest.
[v0.3.0-m2] - 2026-04-30 - D&D 5e combat resolver + VTT overlay
Added
- 4-phase turn (initiative + action economy + conditions + damage +
healing + saves+checks + attack rolls) viaCombatResolver. ToolCallValidatordispatch table for the seven M2 combat tools.- sqlx 0.8 + uuid 1 + chrono 0.4 SQLite persistence:
campaigns,
sessions,snapshots(with v2 forward-compatparent_save_id/
branch_idcolumns),combat_encounters,combat_tokens. - Three combat HTTP endpoints (
/combat/start,/action,
/combat/end) streaming six SSE-event variants. - PixiJS
CombatTokenHTML overlay (HP-by-percent bar / AC chip /
status ring / active-turn pulse),AoeTemplatecone/sphere/line/cube
SVGs from school-of-magic palette,CombatOverlaycontainer (280 ms
cross-fade entry),InitiativeTrackerslide-in,ActionBar. - Chat refinements:
TypingIndicatorthree Cinzel diamonds 1.4 s loop,
useStickyScroll100 px threshold, drop-cap on finalised assistant
bubbles. - Global
prefers-reduced-motionoverride.
Tests
- 76 cargo + 116 vitest.
[v0.2.0-m1.5] - 2026-04-29 - Multi-provider settings + UI hardening
Added
OpenAICompatProviderfor BYO base_url + model + api_key (LM Studio,
Ollama/v1/, llama.cpp server, vLLM, mistral.rs, OpenRouter, Groq,
DeepSeek, Together, Fireworks).- Hot-swap atomic via
RwLock<Arc<dyn LlmProvider>>inAppState,
driven byPOST /settings. - Self-hosted Inter / Cinzel / JetBrains Mono in
public/fonts/. - C1-C6 design tokens folded into
src/styles/theme.css.
Changed
- Toolchain: npm + eslint + prettier +
@vitejs/plugin-react-swc->
bun+biome+@vitejs/plugin-reactv6. valibot(replaces zod) for runtime schemas.- Zustand
persistmiddleware with split-storage adapter
(secrets.jsonfor provider configs / API keys;settings.jsonfor
non-sensitive prefs). - All inline styles migrated to CSS Modules.
--color-accent-soft->--color-accent-tint(translucent rename),
freeing the canonical name for the hover-gold semantic.
[v0.1.0-m1] - 2026-04-28 - Tauri shell + chat skeleton
Added
- Tauri v2 shell (Rust workspace:
app-domain,app-llm,app-serversrc-tauri/).
- axum HTTP server as embedded backend, Tauri sidecar launch.
LlmProvidertrait +AnthropicProvider(genai 0.6.0-beta.18 with
native Anthropic prompt caching).- Streaming chat skeleton via SSE (
/chatendpoint). - React 19 + TypeScript + Vite + Zustand + react-i18next frontend
scaffolding.