Amadeus uses environment variables as startup input, not as a general runtime state store.
- The parent process environment has highest priority. Electron, CI, or a launcher can use it to define one locked process profile.
- Electron desktop settings supply user-managed connection values to the
Python child process. Secrets are encrypted through Electron
safeStorageand are never returned to the renderer. - The repository-root
.envsupplies local developer values only when the parent/desktop launch profile did not already define a key. config/settings.pyparses application startup values and remains the compatibility import surface for Python callers.- Function arguments or explicitly owned runtime objects carry values that
can change after startup. They must not be written back into
os.environ.
.env.example is the public, curated setup template. .env is local and must
not be committed. Defaults that ordinary users should not tune stay in
config/settings.py instead of making the template unreadable.
config/environment.py is the shared dotenv and type-parsing boundary. It
loads one reader per project root, preserves the existing process-over-dotenv
precedence, and records every setting declared through it. New startup
configuration should use this boundary rather than calling load_dotenv
again.
Development bootstrap is an explicit exception: AMADEUS_DEV_PORT is read by
electron/src/main/developmentServer.ts before Python exists. It reads only this
key from the repository-root .env, with process environment taking priority
and 5173 as the default. Supply a literal integer from 1 to 65535 (no variable
interpolation). Both development commands and Electron use that resolver;
Electron passes the resolved port to its Python child. Headless Python uses
config/development.py with the existing EnvironmentReader to accept the same
exact development origin for HTTP/WebSocket requests. This is a development
transport setting, not a desktop Settings field. Changing it requires restarting
the development launcher, not just the backend. Production frontend builds do
not read this setting, and packaged Electron never trusts a development URL.
Invalid input stops the development launcher. Python instead disables the
development browser origin and logs a warning, so this development-only setting
cannot prevent native/file-origin backend clients from starting.
The shared catalog covers the TTS selector, all four built-in TTS connection/model
groups, graphics, voice input/reference controls, model connections, model roles,
Provider connections, character, desktop and live presentation/vision settings.
Edit the owning JSON for defaults, types, options,
ranges, desktop editability, application policy, and English/Chinese labels. The
configuration keys retain their existing environment-variable names.
Run npm run generate:config from electron after editing a declaration.
Python reads the JSON through config/catalog/__init__.py and the existing
EnvironmentReader; settings.FISH_TTS_* callers keep working. The generator
maintains explicit, typed bindings in a marked block of settings.py, so Ruff
and editors can resolve the same public names without globals() injection.
Electron consumes
the generated src/shared/configCatalog.generated.ts, which is compiled into
both main and renderer bundles. Offline Settings never requires a running Python
process or access to the source checkout. The generator also maintains marked
sections of .env.example. Empty strings are quoted so option comments cannot
become values; secret examples stay commented out. Uncomment and fill only the
credentials you use. Commit generated output with its declaration;
npm test and npm run build reject stale output. Removed or renamed groups
lose their old managed env sections; duplicate declared keys outside those sections
are rejected. catalog_legacy.json bounds the remaining handwritten declarations:
new keys and migrated keys cannot be added to legacy desktop lists/forms or Python
parsing/status definitions. The desktop list now contains only structured ACP
records and removal of the retired route key. Internal Python tuning fields
outside Settings remain in the bounded legacy inventory.
Desktop snapshots distinguish stored overrides from known non-secret startup inputs. The form follows source precedence even when offline. Dotenv interpolation remains Python-owned: an unresolved offline value is shown as unknown, and a pending clear never reuses the running backend's superseded value. Secrets expose only configured state. Computed defaults for the next launch use the projected inputs, so changing a local model also changes an unset Hybrid model without being overwritten by the old running value.
desktop_default: { "value": true, "platforms": ["win32"] } declares a
desktop-only launch default; omit platforms to apply it on every desktop OS.
The launch environment and offline snapshot derive it from the same declaration,
after process, saved-user and dotenv overrides. Python's headless default stays
unchanged. Defaults equal to Python's must not be injected unnecessarily: AEC
delay key presence denotes an explicit override of device-class calibration.
Catalog JSON resources are packaged recursively; adding a new folder does not
require new package entries in pyproject.toml.
apply is frontend, host, backend_restart or desktop_restart, with a
field override when its group has mixed behavior. Desktop-only fields never
enter the backend environment. A one-to-one Host setting declares its
runtime_key; forms, persistence mapping and basic runtime validation derive
from that declaration. The implementation still owns applying the value.
Save failures never apply a change, and live application failures leave the
saved revision pending. Only the matching application acknowledgment clears it.
Supported field types are string, path, URL, enum, boolean, integer and number.
Move existing labels, explanations, icons and translations intact when migrating a
field. Option descriptions belong in their localized description; a renderer
that displays them must retain that content. An option marked hidden remains
an accepted configuration value but is not newly offered by the form. This
preserves the existing Vision and AUIP choice sets without rejecting saved or
environment inputs. Field icon preserves an existing control's icon instead of
replacing it with the group's default. Voice groups may use their existing group order for UI
placement independently of backend registration order. The local-engine owner
keeps the CLI executable label specific to the selected engine.
Where existing UI guidance differs from backend diagnostic copy, the group
retains both through ui_description and description, instead of replacing
one audience's explanation with the other's.
Fields use the same override; ui_description: null preserves an intentionally
absent form explanation while retaining an existing backend diagnostic.
computed_default: true omits the static default: its owner supplies a value
when resolving it. Texture sampling still defaults to whether the effective
frame rate is 60 FPS, with explicit choices taking precedence. Graphics presets,
TTS device selection and atomic checkpoint-pair resolution remain ordinary code.
The wallpaper caption default belongs to the presentation owner because the
legacy combined subtitle input may select source, bilingual or disabled captions.
An unresolved offline computed value stays unknown and editable.
An example may differ from the runtime default (for example the curated Kurisu
setup); example_active preserves whether that env example is enabled.
Boolean true_values is used only where an existing owner accepts additional
spellings such as on; other booleans retain the shared parser's contract.
Each TTS declaration has voice_backend metadata and a section (output or
remote). These drive the existing TTS registry, offline selector, Settings
placement and backend status projection. To add a built-in TTS backend, add its
declaration plus implementation: factory names its constructor, probe reports
readiness, and streaming is either a boolean or an implementation function.
Entry points are resolved lazily; listing backends never constructs a model.
The implementation owns protocol validation and optional dependency checks.
Add backend-specific tests, then regenerate; no central backend switch or
Settings allowlist needs editing. New env sections are appended automatically.
This is an internal catalog of packaged application data, not an extension manifest loader. Third-party code still needs the extension host's lifecycle and authorization boundary. ASR fields, shared reference/emotion controls and live runtime application retain their existing owners. TTS mode/language remain bounded composite conversions; window enumeration, character management and theme previews keep their dedicated UI behavior. ACP/MCP records keep their existing structured validation, encrypted storage and authorization boundaries.
The catalog describes fields; it does not store user values or prove that a
backend is available. DesktopSettingsStore still owns encryption, process
locks, clearing, durable saves and pending revisions. Runtime probes still own
availability; an incomplete unselected provider must not prevent startup.
Secret declarations have no default, and status responses expose only whether
a credential is configured. Protocol-specific validation stays in the backend.
server/handlers/voice.py owns construction and binding of TTS, ASR and Wake
handlers. The built-in composition table registers the domain's handlers before
starting the server; app.py supplies runtime dependencies later through
configure(). Add a handler
using existing voice dependencies inside this domain; app.py does not need a
new import, constructor, registration entry or configure call. New cross-domain
dependencies still belong at the application composition root.
The domain closes the current Wake and ASR instances before the shared microphone; shutdown never invokes lazy factories. Shared service creation and replacement remain with the existing scene/runtime owners. WebSocket registration rejects duplicate method ownership before inserting any methods from the new handler.
DeepSeek image input is available with DEEPSEEK_MODEL_NAME=deepseek-flash.
The documented deepseek-v4-flash and deepseek-v4-flash-vision-exp aliases
also accept images. DeepSeek Pro and legacy text models remain text-only.
See the DeepSeek vision guide.
Both direct DeepSeek Chat and the DeepSeek tail of hybrid2 send the image
using the existing OpenAI-compatible image_url format. The hybrid local
head receives only a text acknowledgement hint. Images are attached to the
current user turn, not stored in conversation history. The desktop image
button follows the backend's selected-model capability; changing the model
in startup settings requires restarting the backend.
GRAPHICS_PROFILE is the startup owner for the shared PixiJS render budget:
standardis the default and uses 60 FPS with the native device-pixel ratio.power_savinguses 30 FPS and caps resolution at 1.5.customusesRENDER_MAX_FPS(10–240) andRENDER_MAX_RESOLUTION(0.25–4.0).
The parsed effective values are propagated to chat, Electron, Lively, and
Wallpaper Engine render surfaces. A missing effective resolution limit means
native DPR; it must not be serialized as zero, NaN, or the string None.
Wallpaper Engine's valid general fps property is a runtime host constraint,
so the renderer uses the lower of it and the project profile. Unsupported host
values restore the project limit. This runtime constraint does not mutate the
startup environment.
RENDER_TEXTURE_SAMPLING defaults on when the effective startup limit is
60 FPS, and off at other rates. An explicit true/false choice overrides the
default. The 30 FPS fast-transition timing tradeoff remains opt-in. Changing
sampling requires a backend restart and reopening render surfaces.
Migration from an older .env.example: an existing
RENDER_TEXTURE_SAMPLING=false remains an explicit override, even if it was
copied from that template. Remove/comment that line to use the new startup
default, or set it to true to enable sampling explicitly. Updates do not
rewrite the user's .env or guess whether an old value was intentional.
Once sampling is enabled, a Wallpaper Engine host-cap change rebuilds the sampling plans at the new effective FPS on their next use. It preserves authored playback time, the logical position and exact held/required frames. For example, a 120-frame, 5 ms transition keeps its 600 ms duration when the host changes from 60 to 30 FPS; the unsampled legacy 30 FPS path can take 1 s. The host cap does not toggle the user's sampling choice. Sampling-disabled sessions stay disabled, and a 30 FPS startup default is still off.
RENDER_BC7_CACHE defaults true for the shared HTTP wallpaper asset server.
On GPUs exposing WebGL BPTC, displayed UASTC frames are saved as derived BC7
in the background, then reused on later loads and application launches. The
texture-store budget is unchanged by the cache (see
Animation frame source). Derived files target
4 GiB under %LOCALAPPDATA%/Amadeus/texture-cache/bc7-v1 on Windows,
~/Library/Caches/Amadeus/texture-cache/bc7-v1 on macOS, and
$XDG_CACHE_HOME/Amadeus/texture-cache/bc7-v1 (or ~/.cache/...) on Linux.
Only owned flat cache files are pruned; character packs are never modified.
Concurrent app instances reconcile the shared directory on writes every 30
seconds, so the disk target may be temporarily exceeded between scans.
New writes also preserve a 1 GiB free-space reserve, checked before allocating
the temporary file (including its size) and before publication. This is a
best-effort guard against concurrent external disk use, not a volume reservation.
Low space pauses derivation; existing cache reads and playback continue.
Cache identity includes source content and the bundled transcoder revision. Writes publish atomically. Corrupt entries fall back to the UASTC source and are rebuilt as their frames are displayed. Unsupported GPUs/layouts, file:// legacy rendering, and unavailable cache storage retain the source path. Startup derivation is bounded to one compression worker and two pending frames, using zstd level 3 to limit interactive CPU work. It does not prebuild an entire pack. Cache disk space, worker/transient buffers, and reclaimable OS file cache are separate from the texture-store residency budget.
Identical publications succeed without replacing an in-use file. Failed evictions remain indexed and charged. Temporary write failures (including 503 sharing/space errors) cool down for 30 seconds, then a later playback load can try again; no payloads or autonomous retries are queued during cooldown. 403 disables writes for that page's capability lifetime, without disabling reads. A stalled/crashed worker is retired with only its own pending jobs; later requests create a replacement. Three consecutive worker incidents in one channel pause that channel for 30 seconds. Decode and encode health are independent, and a worker interruption does not mark valid disk data corrupt. Temporary cache-directory initialization errors likewise retry on a later asset request after a 30-second cooldown, without changing the configured flag.
- Credentials, model paths, ports, startup feature flags:
.env->config/settings.py-> imported constant or injected constructor argument. - Electron launch-profile defaults: the field's
desktop_defaultin the catalog. These may be intentionally different from headless Python defaults. The current desktop profile enables realtime AEC/barge-in while headless Python does not. - Runtime choices changed by UI or request handling: a named runtime owner.
tts/pre_translation_runtime.pyis one example. - Test isolation and subprocess metadata: the test/launcher that creates the child process. These are not application settings.
- Script-local variables such as executable paths or encoding flags: the script, unless Python application code also consumes the same value.
system.get_config returns current values from their real owners and
system.set_config accepts an explicit runtime allowlist only. Unsupported
keys fail instead of being reported as updated. Model and Work Provider
connection cards use a separate Electron-owned desktop profile. Non-secret
values are persisted in the app user-data directory; secrets are stored only
as operating-system-encrypted ciphertext. Saving a startup value never mutates
the repository .env and requires a backend restart. An explicit parent
environment value remains authoritative and is shown as locked in the GUI.
Skills and MCP connections are Host-installed Work Provider capabilities. They are not a Main Chat tool surface: a Provider manifest must explicitly accept the capability projection before the Settings catalog shows it as a consumer.
TTS mode and language changes are accepted only while Chat and playback are
idle. TTS_BACKEND defaults to the embedded Amadeus GPT-SoVITS v3 rewrite,
which accepts v1, v2, v2Pro, v2ProPlus and v3 GPT/SoVITS checkpoint pairs. Selecting openai_compatible
avoids importing the local model stack and sends synthesis text to the
explicitly configured speech endpoint. Remote TTS defaults to broadly compatible
buffered WAV responses; TTS_API_STREAM_PROTOCOL=openai_sse explicitly enables
PCM first-packet playback for endpoints that implement OpenAI speech SSE events.
There is no automatic retry from a partial stream to a second billable request.
TTS_BACKEND=fish_audio selects Fish Audio's MessagePack WebSocket transport.
Set FISH_TTS_API_KEY, FISH_TTS_MODEL (for example s2.1-pro-free), and
FISH_TTS_REFERENCE_ID (the hosted voice ID, not the inference model).
The default reference is the public Japanese Makise Kurisu voice
b450b19370434173b121446057622e9b. FISH_TTS_LATENCY=balanced is the default;
FISH_TTS_WS_URL defaults to wss://api.fish.audio/v1/tts/live.
Install the voice extra for MessagePack support. Chat/VN keep their existing
sentence scheduling; audio streams into the existing playback pipeline.
The adapter also accepts asynchronously arriving text chunks for duplex
experiments. See Fish Audio setup and probe.
ASR_BACKEND selects only
the full Conversation recognizer and defaults to Qwen3-ASR, preserving context
prompting and speculative endpoint optimization. WAKE_ASR_BACKEND is an
independent always-on role and may keep SenseVoice loaded alongside Qwen. A
remote Conversation ASR intentionally disables partial speculative API calls
to avoid hidden duplicate network requests and metered usage.
The Electron Voice settings use the same precedence and encrypted-secret store
as model connections. ASR_API_KEY, TTS_API_KEY, and FISH_TTS_API_KEY are never returned to the
renderer. Remote voice backends are selected explicitly; local failures never
silently upload microphone audio or synthesis text.
The first-release Main Chat default is remote DeepSeek; local model settings
apply only when the user explicitly selects the pure-local profile.
LOCAL_LLM_TYPE is editable for the pure local provider and synchronizes
ChatRuntime with the synchronous fallback. LLM_PROVIDER is the only chat
router; the deprecated USE_LOCAL_LLM value no longer overrides it.
LOCAL_LLM_LAUNCH_MODE=external|managed controls only ownership of the
default llama.cpp server process. LM Studio, Ollama, and llama-cli remain
pure-local compatibility profiles with type-specific fields. The hybrid*
providers use the dedicated OpenAI-compatible HYBRID_LOCAL_LLM_URL and
HYBRID_LOCAL_LLM_MODEL; they never branch on LOCAL_LLM_TYPE.
Direct os.environ reads are still valid at genuine process boundaries (for
example an isolated legacy provider helper), but they should not duplicate an
already parsed startup setting. A direct write is reserved for child-process
construction or a documented third-party compatibility contract.
These are not pending mechanical migrations:
| Owner | Values | Why they remain late-bound |
|---|---|---|
tts/aec_realtime.py |
explicit AEC delay | Only presence is checked; the value comes from parsed settings. An explicit value disables device-class calibration. |
tts/pipeline.py |
ENABLE_CUDA_GRAPH |
The compatibility mode function and bundled inference code read the value at synthesis time. There is no active mainline UI caller today, so no replacement runtime contract is invented yet. |
| provider/session storage helpers | AMADEUS_*_PATH values |
Helpers accept explicit path injection and subprocess tests supply isolated stores at their process boundary. |
| wallpaper scenario helpers | wallpaper/scenario overrides | Both wallpaper hosts resolve component-local media overrides without importing the heavyweight application settings facade. |
vn_player/runtime.py |
VN_* values |
These describe one VN session, not the application startup snapshot. |
server/runtime_status.py |
build/workspace metadata | The launcher supplies diagnostic facts for the current process. |
asr/qwen3_asr_sidecar.py |
QWEN3_ASR_DEVICE, QWEN3_ASR_REQUIRE_CUDA |
The isolated interpreter reads the environment supplied by its parent. |
tts/gpt_sovits_sidecar.py |
TTS_REQUIRE_CUDA |
The isolated interpreter enforces the device requirement supplied by its parent. |
server/presentation_runtime.py |
AMADEUS_PRESENTATION_LOCALE, AMADEUS_WALLPAPER_CAPTION_MODE |
Presentation resolves its current, component-owned preferences. |
server/handlers/system_handler.py |
Browser/VN role provider and model overrides | Existing status projections distinguish explicit overrides from inherited values. Their empty-value semantics are retained; the ratchet does not mechanically replace these reads. |
server/app.py |
AMADEUS_ALLOW_MAIN_VOICE_DURING_VN |
The existing voice-route callback checks this override while deciding whether main voice may run during a VN session. |
server/vn_tts_bridge.py, tts/utterance_scheduler.py |
dispatch, queue and utterance limits | Existing bridge/scheduler owners resolve their timing and grouping controls. Changing when they are read requires a separate behavior review. |
server/wallpaper_subtitle_translator.py |
translation timeout and token budget | Each translator resolves its own request limits at construction. |
The inventory also retains startup reads in server/visual_runtime.py and
server/chat_translation_runtime.py. These initialize component-owned mutable
state using catalog defaults, then accept live changes through set_config.
They are legacy parsing sites, not justification for introducing new raw reads.
The helper-aware audit added 47 existing file/key pairs across eight files;
eight of these refer to declared catalog keys. No runtime reads were moved.
catalog_legacy.json.environment_reads records exact file/key pairs, including
process-boundary and remaining legacy reads. The AST scan recognizes literal
keys in direct reads and same-file parameter-forwarding helpers, including
nested helpers and positional/keyword calls. It does not resolve arbitrary
runtime expressions, callbacks, or helpers imported from other modules; this
is a bounded source guardrail, not a complete runtime inventory.
New product settings belong in the
catalog. A new intentional late read needs an explicit baseline review and an
explanation here; moving a read to another file is not automatically permitted.
python tools/maintainability_ratchet.py --update only tightens existing
baselines and refuses new entries. It also reports silent broad exceptions for
inspection; that observation is not a CI gate.
config/durable_io.py provides write_text and write_bytes without loading
application settings. Callers own serialization, parent-directory creation,
locking, validation, exclusive creation and recovery. The file is written and
synced in the destination directory before replacement. On Windows, known
sharing/access conflicts receive bounded retries on ordinary threads. A call
on a running asyncio event-loop thread propagates the first conflict without
sleeping, preserving synchronous caller ordering and avoiding retry backoff
that would stall unrelated events. Other errors propagate immediately. The
write and file sync themselves remain synchronous.
Replacement is the commit point. Pre-commit I/O errors preserve the previous file. A later directory-sync error logs a warning and returns normally: the new contents are visible but crash durability is unconfirmed. This does not promise multi-file transactions or coordinate concurrent writers. Text uses UTF-8 with no platform newline translation; existing Windows JSON saves may consequently change CRLF to LF without changing their parsed content or trailing-newline convention.
The VN context store is explicitly deferred (2026-10-11). Its non-atomic fallback
and recovery behavior are unchanged. Future work must distinguish a new session
from missing/corrupt state in an existing session, preserve corrupt evidence,
recover sequence ordering or refuse continuation on every subsequent startup,
and define policies for all JSON files that are read and later overwritten.
Permission failures must not be treated as malformed content. The R3 exception
is limited to VNContextStore.write_json, not a general exception for VN code.
The catalog is trusted, packaged application data. An external extension manifest is a separate validation and lifecycle boundary; this documentation does not enable extension discovery or runtime registration.
| Vocabulary | Built-in catalog | Extension design boundary |
|---|---|---|
type |
String, path, URL, enum, boolean, integer, number | No path type in the current draft; do not silently grant filesystem access. |
title, description |
English and Chinese localized maps | May be a string or language map; normalize representation and enforce manifest length limits. |
default |
Must match the declared field type | Must match the type and constraints; a secret cannot declare a default, including an empty one. |
secret |
Host-owned string credentials | Host-owned bindings; omit built-in empty defaults when constructing a manifest, rather than copying them. |
options |
Strings or objects with required label and optional description/hidden | Draft options permit optional labels and have a bounded count; adapt explicitly. |
min, max, max_length |
Validated field constraints | Common concepts, with manifest-specific bounds and applicability. |
apply |
frontend, host, backend_restart, desktop_restart |
live or reactivate; these describe extension generations and are not interchangeable with built-in restart policy. |
required |
Not a built-in field attribute | Missing required configuration keeps the extension in needs_config. |
extension_selection |
Identifies the supported contribution kind/role for an existing selector; currently TTS and interface theme only | Not a manifest field; the Host support profile owns selection and application policy. |
| Runtime and presentation wiring | runtime_key, scope, setting, computed/desktop defaults, visibility, factories and probes |
Host implementation details, not a public manifest surface. |
The generator already rejects unknown built-in attributes. Share only genuinely common value checks; keep manifest authority, secrets, application policy and lifecycle validation with their owners. A real out-of-tree adapter must exercise installation, configuration, enable/disable, failure and removal before fixing the registration API, followed by a second adapter to validate its generality.
TTS_DEVICE=autoresolves tompson Apple Silicon,cpuon Intel macOS, and the existingcuda:0default elsewhere. The resolved device is copied toos.environbecause the bundled BigVGAN loader directly consumes that variable. An explicit indexed CUDA device or explicitmps/cpuvalue is preserved.- Local GPT-SoVITS CPU synthesis automatically uses the existing persistent
TTS sidecar (the current Python interpreter unless
TTS_PYTHONis set). This isolates its PyTorch thread settings from ASR/VAD dependencies. CUDA and MPS keep their embedded default; explicit sidecar/interpreter settings still select a subprocess. The sidecar serializes synthesis and drains interrupted requests before accepting the next one; CPU compute is still shared with the host. All synthesis modes consume blocking model/IPC streams on the TTS executor, keeping the event loop available to ASR. AMADUES_PRE_TRANSLATION_ENABLEDremains accepted as a deprecated spelling ofAMADEUS_PRE_TRANSLATION_ENABLEDat the pre-translation boundary.- The legacy root GPT-SoVITS WebUI/API entry points and their conflicting
config.pywere removed. A future HTTP API should be designed around the currentserver.appcontracts instead of reviving that compatibility layer.
Model connection inheritance stays in the model owner. The catalog records legacy
names (aliases), facade attribute bindings (setting), and local engine field
visibility (visible_when). CLI numeric controls remain parsed strings;
control: "number" supplies UI hints without changing command argument types.
Bedrock bearer credentials now use the same surrounding-quote/whitespace
normalization as other API secrets. AWS credential discovery remains unchanged.
Role/session fields use scope: "session": their owner calls read_catalog_value
against its current environment, preserving per-session overrides without loading
all application settings. scope: "virtual" marks composite controls such as
Codex transport; the desktop owner translates these into the real launch keys.
They are not emitted as synthetic environment variables or Python settings.
visible_when permits only equality against declared selectors in the same group;
it contains no executable expressions. Provider availability and authorization
remain runtime facts. String selectors offer choices without turning a previously
open provider identifier into a new hard-coded enum. Structured ACP/MCP profiles
retain their existing dedicated storage, validation and authorization owners.
server/handlers/composition.py is the built-in factory table. It constructs all
request handlers against explicitly supplied startup services and registers every
result before the server accepts clients. Adding a handler changes its
implementation and this table, without editing server/app.py. Runtime owners
still bind their live services and callbacks; this table is not a plugin loader
and grants no new extension permissions. Duplicate request methods fail startup
instead of replacing the existing owner.
Run python tools/smoke_builtin_handler_catalog.py to start an isolated backend
with models and external agents disabled. The smoke adds a synthetic factory,
verifies an authenticated WebSocket round trip, reads the real configuration,
checks voice routes, and shuts the process down cleanly.
Graphics settings retain the existing profiles, FPS, density, sampling and BC7
cache controls. RENDER_FRAME_SOURCE=auto selects the optional matched video/
companion within the existing SpriteForge pack only after renderer capability
checks; static selects the established static path. RENDER_FRAME_BUDGET_MIB=auto
uses 384 MiB for video and 2048 MiB for static/fallback. Explicit 384/768/2048 values
apply to both paths. The GUI shows observed per-surface state separately from
saved choices. Restart the backend and reopen existing render windows after saving.
No launcher override or old-pack path migration is required. See
frame-source integration.
QWEN3_ASR_CUDA_GRAPH and QWEN3_ASR_FLASH_ATTN default to true and
are independently editable in Conversation recognition settings. Both apply
after a backend restart. Set the first to false for official decoding, and
the second to false for PyTorch SDPA on NVIDIA CUDA. Set both to false
to compare against the official SDPA path; TTS acceleration settings are
independent. CPU and ROCm keep their existing attention paths. FlashAttention 2
requires a supported installed package and an NVIDIA GPU with compute capability
8.0 or newer; older NVIDIA devices use SDPA regardless of the preference.
The explicit Python inference_engine constructor argument remains an offline
benchmark control; ordinary application callers use the parsed startup setting.