← Knowledge base
ModForge UI Conventions
modforge-ui-conventionsv1updated 5h ago
ModForge UI Conventions
Shared conventions for the ModForge desktop app UI.
Dialog scale
- Standard compact dialogs should match the app's small operational UI: about
w-[460px] max-w-[92vw],rounded-lg,p-5,text-smbody copy, andtext-xltitles. - Avoid oversized modal styling such as
text-3xltitles,text-lgform text, very large radii, or wide shells unless the dialog is intentionally a large workspace.
Prompt queue
- Prompts submitted while an agent is thinking belong only in the prompt queue UI above the prompt bar. Do not emit them into the agent feed until they actually dequeue and send.
UI performance
- Avoid high-frequency
git_diff_summary(..., include_diff=true)calls from visible React components. On 2026-07-14, brief UI lockups during typing were traced to repeated git diff work in Source Control and Codex live edit summaries. Keep Source Control refreshes serialized and slow (currently every 5 minutes), and useincludeDiff=falsefor periodic/background Codex diff snapshots unless exact patch text is needed for a one-shot action. - Renderer stall profiling lives behind Settings -> Performance -> "Enable renderer performance monitor" (added 2026-07-15). It persists
performance_monitor_enabled,performance_monitor_threshold_ms, andperformance_monitor_console_logging, mountsPerformanceMonitor, and records long tasks, event-loop drift, frame gaps, prompt input event delay, and prompt input-to-next-frame latency. Samples stay in renderer memory; optional console warnings use the[modforge:perf]prefix. - Tauri v2 runs plain
fncommands on the main thread — the same thread that pumps the window event loop and dispatches every WebView2 IPC message. Any slow sync command (process spawn, network, busy-wait, big file read) therefore freezes typing, dialogs, and all otherinvoke()round-trips until it returns. On 2026-07-23, intermittent multi-second dialog freezes were traced to this:claude_account_usage(spawnsclaude /usage, up to 8 s, polled every 60 s),game_shutdown_client/server(30 s process-exit busy-waits, invoked from the deploy modal),git_install_status(winget --versioncold start),game_processes(sysinfo sweep polled every 2 s), and others. Convention: every ModForge command that spawns a process, touches the network, sleeps, or reads/writes more than trivial bytes must be declared#[tauri::command(async)](orasync fn+spawn_blocking); only microsecond DB/stdin-write commands may stay plain sync. Themodforge-assetURI scheme handler must likewise stay onregister_asynchronous_uri_scheme_protocol— the synchronous variant read whole AssetBundles on the main thread.
Deploy queue marker
- Codex deploy requests use a root-level
.modforge-deploytrigger file in the mod folder. ModForge consumes and deletes this marker immediately after the non-recursive per-mod watcher sees it, so the file often will not remain visible in Explorer; judge success by the deploy queue/badge/modal, not by marker persistence. - The
.modforge-deploywatcher is the agent deploy-request channel and should stay enabled for open mods even when recursive workspace/source file watching is disabled.
Codex launch compatibility
- Agent binary settings should keep the editable text field visible and place discovery actions beside it. Claude Code uses
settings_discover_claude_binaryto search PATH/Get-Command forclaude; Codex usessettings_discover_codex_binaryplus its Windows app-package fallbacks. - Codex config
service_tier = "priority"is obsolete for current Codex builds; startup fails withunknown variant 'priority', expected 'fast' or 'flex'. Useservice_tier = "fast"as the direct replacement, and have ModForge sanitize that line when it edits~/.codex/config.tomlfor project trust. - ModForge's Codex model picker maps UI labels to Codex config overrides:
GPT-5.5->model = "gpt-5.5",Extra Highreasoning ->model_reasoning_effort = "xhigh", and speed choices ->service_tier = "fast"or"flex". Apply these ascodex exec -c ...overrides instead of relying on the user's global config file.
Knowledge Base panel
- The Knowledge Base settings must distinguish the repository URL from the local checkout folder.
kb_repo_pathis the local checkout folder used for indexing/syncing; the GitHub URL is only an input to clone. - The Knowledge Base panel has separate local refresh and git sync actions. Refresh only re-indexes configured KB files; Sync runs
git pull --rebase --autostashthengit pushagainst the configuredkb_repo_pathand should show an in-flight status plus the git result text. - Put Clone/Explorer/Sync next to the local
Knowledge Base Checkout Folderpath in Settings, not in the reader panel, so users can create, inspect, or fix the actual checkout before reading notes. - Agent sessions must get the KB checkout from ModForge settings, never by guessing
../7KB. Add configuredkb_repo_pathto Codex workspace-write roots, include it in Codex per-turn prompts, and stamp it into managed per-modCLAUDE.md/AGENTS.mdblocks. - Do not update a mod's
CLAUDE.mdorAGENTS.mdunless that mod is currently opened in ModForge. This prevents background or unrelated mod folders from receiving managed-agent-file edits. - The Knowledge Base opens as a full-window top-right toolbar section (
section="kb"), like Settings/Game/Mod Manager. Do not expose it as a left activity-rail side panel. - Dirty Knowledge Base git status is surfaced globally: poll
kb_status, show an amber count badge on the top-right KB toolbar icon, and show the changed-file list plus aCommit & Pushbutton in the KB reader. The commit action stages all KB changes and uses the generic messagemore knowledgebefore pushing. - KB
Commit & Pushmust pull before committing to avoid non-fast-forward push rejections: usegit pull --rebase --autostash, thengit add -A,git commit -m "more knowledge", thengit push. Settings expose a KB auto-pull timer (kb_auto_pull_enabled,kb_auto_pull_interval_minutes,kb_auto_pull_pause_unfocused) that runs the same pull command periodically. If a KB pull/commit hits conflicts, the KB reader should offer to queue a repair prompt to the currently selected mod agent, asking it to resolve conflicts in the configured KB checkout and then commit/push the KB. - The right dock cluster (Run panel, Terminal panel, Action Log panel, and right activity rail) is only visible in the main Mods workspace. Hide it in top-right full-window sections such as Knowledge Base, Settings, Game, and Mod Manager.
Right activity bar panels
- The right activity rail (
RightActivityBar.tsx) has two groups separated by aflex-1spacer (WebStorm tool-window stripe layout): a top group of right-docked side panels — Run (useRuns), Action Log (useActionLog), and Game Log (useGameLog) — and a bottom group of full-width bottom-docked tool windows — Terminal (useTerminal). Each panel has its own Zustand store withpanelOpen/setPanelOpen/togglePanel. - Right-dock mutual exclusion: Run, Action Log, and Game Log share the right dock, so opening one closes the others (enforced at the rail click AND in
RunPanel'spanelOpeneffect becausestartRunopens it without going through the rail). The Terminal is on a separate bottom dock and is independent — it can be open alongside a right-docked panel; do NOT couple it into the right-dock exclusion. - Game Log panel (
GameLogPanel.tsx,gameLogStore.ts): streams the in-game console live from 7debug'sGET /api/console/streamSSE endpoint while the panel is open (oneEventSource, no polling; auto-reconnects when the game is down). Rows click-to-copy; header has copy-all and clear. Clear sets a seq watermark so replayed backlog stays hidden; a changed per-processrunid in the events resets the watermarks (game restarted). Requires 7debug ≥ 1.2.0. - Layout (
App.tsx): everything left of the rail is a verticalflex flex-colstack — the section content row (with the right-docked Run/Action Log panels) on top, and<TerminalPanel />docked along the bottom.<RightActivityBar />stays full-height as a sibling on the far right. Opening the Terminal pushes the content above it up rather than stealing horizontal space. - Right-docked panels:
shrink-0 flex ... border-l border-zinc-800aside, 1px left drag handle resizing leftward (window.innerWidth - clientX - 48), width persisted tolocalStorageundermodman.<panel>PanelWidth. Bottom-docked Terminal:shrink-0 flex flex-col ... border-t border-zinc-800, 1px top drag handle resizing upward (window.innerHeight - clientY - 24), height persisted undermodman.terminalPanelHeight. - The Terminal embeds a plain interactive PowerShell (xterm) cwd'd to the active mod's root. The backend (
shell_term.rs,ShellRegistry) keeps one persistent shell per mod id, keyed bymod_id:shell_openis reattach-aware (returns existing scrollback, spawns fresh only when none), and events stream overshell:data:{modId}/shell:exit:{modId}. This mirrorspty.rs(agent PTY) but launchespwsh/powershell -NoLogoinstead of Claude/Codex. The panel follows the active mod tab viamodIdFromTab(activeTab)(falling back tomods[0]), same as the Run panel'sdefaultModId.
Git commit author identity
- ModForge stores a suggested git identity in Settings (
git_user_name/git_user_email, Git tab). When both are set,git_commitalso applies them inline viagit -c user.name=… -c user.email=… commit(seecommit_changesingit_status.rs). - When a mod becomes active,
App.tsxcallsgit_local_identityto inspect that repo's local (not inherited global/system)user.nameanduser.email. If either is absent,GitIdentityDialogopens, preserves any existing local field, and autocompletes missing fields from the saved ModForge identity. Confirming writes both fields locally throughgit_set_local_identityand saves the pair as the suggestion for other repos, making later prompts one-click confirms. A commit-time identity-error fallback remains and retries the pending commit after confirmation.
Adding a global setting (end-to-end)
A new global setting touches, in order: Settings struct in src-tauri/src/settings.rs → read it in BOTH settings_get_raw and settings_get → write it in settings_save (stored as a string KV row in the settings table) → Settings interface in src/types.ts (camelCase) → a control in the relevant SettingsPanel.tsx tab using draft.<field> / update("<field>", …). The Zustand store passes the whole Settings object through saveSettings, so no store change is needed for a plain field.
Beta feature toggles
- The Settings Beta tab holds per-feature on/off switches that hide experimental UI surfaces. Each toggle is a default-true bool (
bool_default_trueinsettings.rs, read assettings?.<field> !== falsein the renderer so it stays visible while settings load). Current toggles:feature_source_control,feature_unity_assets,feature_sketchfab_assets. - Gating is done at every entry point for the surface, not just one: Source Control and Unity Assets are left activity-rail panels, so gate BOTH the
ActivityBar.tsxbutton ANDSidePanel.tsx(return null when the opensidePanelkind is disabled, since it can be restored from persisted UI state). Sketchfab Assets is a top-right toolbar section, so gate theToolbar.tsxSectionIconButtonAND add anApp.tsxeffect that redirectssectionback to"mods"if the feature is switched off while that section is open. - Toggles hide surfaces only; they never delete data or force-close already-open tabs (e.g. an open Unity prefab tab survives disabling Unity Assets). Re-enabling restores the button immediately.
Installed mod manager
- The Mod Manager section should list installed client mods from
<7DTD client>/Mods, not just registered ModForge source mods. Match installed folders back to registered mods byModInfo.xml<Name value="...">first, then by source/folder name. - Installed freshness should reuse ModForge deploy status semantics: green is synced, yellow is marker mismatch, red is missing/never-deployed marker, and unknown is unmanaged/unmatched.
- Per-row deploy actions in the Mod Manager are exact-mod actions: run
deploy_runfor only the matched registered source mod, do not use the shared deploy queue/batch, then refresh that installed row afterdeploy:exit:{modId}. Unmanaged installed folders belong in a separate lower "Other Client Mods" list with no deploy action. - Disable moves the installed folder to
<7DTD client>/mods_disabled; delete permanently removes the installed folder with no trash/recycle step. - The Mod Manager also lists disabled mods (from
<7DTD client>/mods_disabled) in a separate lower "Disabled Mods" table, each row with an Enable and a Delete action. Enable moves the folder back to<7DTD client>/Mods(viaunique_destso it never clobbers an existing folder); Delete permanently removes the disabled folder with no trash step. Backed bymod_manager_list_disabled/mod_manager_enable_disabled/mod_manager_delete_disabledinmod_manager.rs, using adisabled_mod_pathpath-safety guard that mirrorsinstalled_mod_path. The disabled list only shows folder name + version (no deploy-status/source matching).