Dashboard Guide
July 3, 2026 · View on GitHub
The Fusion dashboard is the main control plane for tasks, agents, missions, settings, logs, and repository operations.
Dashboard Updates
When Fusion detects a newer @runfusion/fusion release, the Settings modal footer shows the available version with Learn more and Update now actions. Update now installs the latest global package with npm; after it succeeds, restart Fusion to apply the new version because the already-running dashboard server is unchanged until restart.
Mobile/PWA app icons
The installed mobile/PWA home-screen icons are generated from packages/dashboard/app/public/logo.svg by the desktop icon generator. When the Fusion brand mark changes, run pnpm --filter @fusion/desktop generate:icons so packages/dashboard/app/public/icons/icon-192.png and packages/dashboard/app/public/icons/icon-512.png stay aligned with the canonical logo. Also bump CACHE_NAME in packages/dashboard/app/public/sw.js whenever those icon assets change so installed PWAs refresh the cached launcher images.
Browser Navigation
The dashboard now handles browser back navigation consistently on desktop and mobile. Using Back will first dismiss open modals and then step back through in-app view changes before leaving the app. When task detail is open from a board card, mobile list row, right-dock/activity/onboarding link, deep link, or another task detail link, one browser/Android Back action closes the current detail first and restores the prior dashboard context (for example, nested task detail → previous task detail, or task detail → board). On mobile board-card detail, Back to board also restores the prior board/card scroll position so the same lane context remains visible.
This behavior used to be mobile-only, and now applies across all viewports. Task Detail modal opens from onboarding, activity log, and task-to-task navigation now all register navigation history entries, so Android back swipe/button dismisses them consistently.
Left Sidebar Navigation (experimental)
Left Sidebar Navigation is enabled by default for desktop/tablet project screens, moving project navigation out of the Header and into a persistent left sidebar. To opt out, open Settings → Experimental Features and turn Left Sidebar Navigation off (leftSidebarNav: false).
When enabled on desktop or tablet project screens, the sidebar starts with a centered New Task button that opens the existing New Task dialog from any project screen. Expanded mode shows the plus icon and New Task label; collapsed rail mode keeps the centered icon-only button accessible through its label/title. Below that action, the sidebar contains primary destinations (Board, List, Agents when enabled, Command Center, Planning, Missions, Chat, Artifacts, Mailbox, and plugin primary views) followed by secondary destinations (Workflows, Import Tasks, Automations, optional Evals, Goals, Research, Insights, Skills, Memory, Dev Server, and plugin overflow views when their flags/plugins are enabled). The footer contains the sidebar collapse toggle directly above Settings.
Use the desktop/tablet sidebar this way:
- Select New Task at the top of the sidebar. Expected outcome: the existing New Task dialog opens from any project screen, including advanced options such as priority, execution mode, workflow/model routing, and GitHub tracking.
- Select a primary destination such as Board, Command Center, Planning, or Artifacts. Expected outcome: the selected view renders in the main content region and the sidebar item receives the active highlight.
- Select Workflows, Import Tasks, or Automations from the secondary section. Expected outcome: each surface opens as an embedded main-content view. Import Tasks is the GitHub import surface.
- Use the footer Collapse control or drag the right-edge resize handle.
Expected outcome: the sidebar switches between labeled and icon-only rail modes or persists the resized width in browser
localStorage(fusion:left-sidebar-collapsedandfusion:left-sidebar-width) for the next reload.
While the sidebar is active on desktop/tablet project screens, Board and List workflow controls move into the Header slot that replaces the hidden view toggle. Board and List share one workflow dropdown: each workflow row includes an inline edit action, and a persistent New workflow action remains at the bottom of the dropdown while the workflow list scrolls. The standalone workflow row above the board/list content is removed in this mode. When the flag is off, outside project screens, or on mobile, workflow controls remain inline with the same consolidated dropdown.
The active nav-item highlight and the resize-handle hover/focus accent track the active color theme's --accent token across all themes, so shadcn, forest, ocean, and other themes no longer show a fixed blue selected state. The Header retains the Fusion brand and project selector, keeps non-navigation controls, and hides duplicate desktop view-toggle entries while the sidebar is active.
On mobile viewports (<=768px), the sidebar is not rendered even when the default-on setting is enabled. The existing bottom MobileNavBar remains the navigation surface, with mobile-only More-sheet entries for compact tools such as Git Manager, Terminal, Files, and Import from GitHub.
Right Dock (experimental, default on)
The Right Dock Panel experiment is enabled by default. To disable it, open Settings → Experimental Features and turn off Right Dock Panel.
When enabled on desktop or tablet project screens, the right dock is a persistent far-right tools sidebar in the project content row. By default it opens as an overlay so the main content does not reflow. Use the dock toolbar pin action to switch into push mode, where the dock becomes an in-flow pane that shrinks the main content beside it; unpinning returns to overlay mode. The selected tool, open/closed state, pinned push-mode state, width, and expanded modal size persist across reloads.
If Settings → Appearance → Open tasks in the right sidebar is enabled, board task-card clicks open task detail inside this right dock and keep the board visible. The setting is default off; mobile or hidden/inactive dock states automatically fall back to the existing full-panel task detail unless the task-popup setting below is enabled, and non-board task-open paths keep their existing behavior.
Settings → Appearance → Open tasks as popups changes only ordinary board task-card clicks across desktop, tablet, and mobile viewports. When enabled, those clicks use the existing task popup/FloatingWindow surface instead of the full-panel task detail or right-dock task detail, keeping the board visible in the background. Deep changes/retries/workflow opens, list/task-detail links, plugin/graph opens, and explicit pop-out actions keep their existing paths.
The dock toolbar has built-in inline tool panels for Tasks, Files, Chat, Activity Log, Git Manager, Dev Server when enabled, Secrets, Todos when enabled, and Pull Requests. These tools render in embedded mode inside the dock instead of opening fixed popup overlays; Files opens by default and is the fallback when browser storage points at a removed dock key. The Tasks tab shows the last task opened in the dock; when no dock task is active, it shows a compact clickable active-task list. Use Show Done to include completed tasks in that compact list; archived tasks stay hidden there. Either task-detail back button returns to the Tasks list. Inline dock views have an expand button that opens the same view in a resizable modal for more room. The right-dock Files viewer and its expanded pop-out match the Files modal for browser-previewable file types: image, video/movie, audio, and PDF selections render as native browser previews, while editable text files keep the editor and save flow. Plugin overflow views may add additional right-dock tool tabs, except plugin destinations that explicitly belong in the left sidebar.
Use the desktop/tablet right dock this way:
- Open a project screen with Right Dock Panel enabled. Expected outcome: the dock appears on the far right with Files selected unless a valid previous dock view is stored.
- Select Tasks, Chat, Activity Log, Git Manager, Files, or another available tool in the dock toolbar. Expected outcome: the selected tool renders inline inside the dock body and the toolbar tab becomes active; Tasks either restores the last-viewed dock task or shows the compact active-task list with optional Show Done completed-task visibility.
- Drag the dock's left-edge resize handle, or focus the separator and use the arrow keys. Expected outcome: the dock width changes within its min/max bounds and is saved for future reloads.
- Select the dock expand action. Expected outcome: the same inline tool opens in a resizable modal while the dock remains the source navigation surface.
- Select the dock pin action. Expected outcome: pinned mode pushes the main content narrower, unpinned mode overlays the page without reserving space, and the preference is saved for future reloads.
- Use the Header right-sidebar toggle. Expected outcome: the far-right surface opens or closes without creating duplicate left-sidebar destinations; mobile viewports never render or reserve space for the right dock.
Content views such as Artifacts, Research, Insights, Skills, Memory, Evals, Goals, Workflows, Import Tasks, and Automations live in the left sidebar (or compact mobile navigation) rather than the right dock. On desktop/tablet, GitHub import lives under Import Tasks; mobile keeps compact GitHub import entries in the More surfaces.
On mobile viewports, the Right Dock never renders. The compact Header actions and bottom MobileNavBar keep their existing mobile behavior even when the experiment is enabled.
Automations
Open Automations from the left sidebar (or the mobile More surfaces) to create cron, webhook, API, or manual routines. AI Prompt steps now run with all selectable coding tools by default: Read, Bash, Edit, Write, Grep, Find, and Ls. In the routine editor, use Allowed tools on a simple AI Prompt action or any multi-step AI Prompt step to clear or re-select tools. Leaving every tool selected stores the legacy default, so existing schedules continue to run with full tool access; clearing every box is an explicit no-tools configuration.
When you choose Run now, the routine card opens a Live output panel while the manual run is active. The panel appends step status, AI text deltas, and tool start/finish activity as the run executes, then the card falls back to the persisted final run output and run history once the server records the result. The same RoutineCard surface is used by the floating modal and embedded Automations view, so live output appears in both presentations and collapses into a single-column card layout on mobile.
Deep Links
Use deep links to open a specific task directly from notifications, chat, or external tools.
/tasks/<TASK_ID>(for example,/tasks/FN-1234) opens that task, and can include?project=<project-id>for multi-project routing./?task=<TASK_ID>[&project=<project-id>]is the canonical in-app form and opens the task detail modal on load.- Selecting a project from the dashboard project switcher writes
?project=<project-id>into the URL and preserves unrelated query parameters/hash fragments, so refreshing the browser keeps the same selected project instead of returning to the default project.
- Legacy path-style links (including trailing-slash forms like
/tasks/<TASK_ID>/and older hash-style entry points that resolve to that path) are normalized client-side to the canonical query form withhistory.replaceState, so the URL updates without a full reload. - In non-headless dashboard mode, the server also issues an HTTP 301 redirect from
/tasks/<TASK_ID>to/?task=<TASK_ID>and preserves?project=when present. - Theme assets resolve
theme-data.cssagainst the current document base (HTTP/HTTPS,file://, and Electron fallback paths), so non-default themes still load correctly when you land on deep-linked or sub-path URLs. - Configure
dashboardHostandntfyDashboardHostin settings reference so generated notification links use the correct base URL.
/tasks/FN-1234
/?task=FN-1234
/?task=FN-1234&project=my-project
Clickable File Paths
File paths in dashboard text are automatically rendered as inline links. Clicking a linked path opens the Files browser modal at that path (including line/column targets when available) so you can inspect the file and use editor actions where supported.
Current surfaces include:
- Task detail modal content (description markdown, Review tab, and Workflow Results tab output plus workflow overview/graph/model settings)
- Chat view messages/tool output
- Agent log viewer
- Activity log modal
- Dev Server log viewer
- Settings sync log
Only detected file-path text is linkified; non-path text remains plain. Linked paths must resolve within the current project workspace to open successfully.
Board View
Board view is the kanban surface for day-to-day operation.
Features:
- Drag-and-drop between lifecycle columns
- Search/filter tasks (including working-branch and base-branch dropdown filters with explicit No working branch / No base branch options)
- Working-branch and base-branch filter selections are persisted per project and restored across refresh/navigation
- Column visibility controls
- Inline quick entry creation
- The quick-entry GitHub icon is a per-task tracking override: leave it untouched to use the project default, turn it on to opt the next task into tracking when the default is off, or turn it off to opt the next task out when the default is on.
- PR/issue badges with live updates
- GitLab tracking badges on task cards for linked GitLab project issues, group issues, and merge requests; stale GitLab metadata uses a warning-colored badge while GitHub badges remain unchanged.
- GitHub provenance marker on task cards imported from GitHub (
sourceType: github_import), shown in the footer with other external-source metadata - Task card header meta badges group priority, fast mode, agent-created provenance, workflow identity, and elapsed/created-time chips into one wrapping row; agent labels prefer
sourceMetadata.agentNameover raw agent IDs - Task detail surfaces show the selected/effective workflow identity near the task's workflow controls so individual cards remain understandable when Board is in All workflows or another aggregate/mixed context.
- Board task cards support a context menu from right-click, keyboard context menu / Shift+F10, or touch long-press for detail-aligned lifecycle actions without changing normal card clicks. The menu opens as an independent overlay so it stays visible beyond the card or column edge while remaining clamped to the viewport. On mobile, long-press opens that menu without selecting card text or showing native copy/paste callouts. Selecting an action applies that exact action once and dismisses the menu. Completed card context menus include Refine, which opens the existing task-detail refinement feedback modal for the same task.
- The Triage column actions dropdown includes Auto-approve plan. Turning it on sets the project plan approval mode to auto-approve all planned tasks; turning it off returns to the workflow/default plan approval behavior. In workflow-mode Boards, the same switch appears on intake/hold planning columns and on the equivalent All workflows aggregate intake column. Use Settings → Merge for the full three-state project control, including Require approval for all tasks.
- Column ordering semantics:
todomirrors scheduler pickup order (priority descending, then oldestcreatedAt, then task ID);triage,in-progress,in-review, andarchivedremain priority-first with task-ID tie-breaks;donedefaults to most recent completion first (columnMovedAt, thenupdatedAt, thencreatedAtfallback) and can be switched from the Done/complete column actions dropdown to descending task ID. In workflow mode, non-archived columns marked with thecompleteflag use the same Done menu items even when their column ID or label is customized. - Done-column sorting has two descending modes: Completion date (newest first) keeps the default completion-time order, while Task ID (newest first) places the highest numeric task IDs first. The sort actions are only shown in Done/complete column action menus, including custom workflow completion lanes; Archive All Done lives in the same menu when available.
- On mobile, both default and workflow-mode boards fill the project viewport while the column strip remains the internal horizontal scroller with contained edge overscroll.
- Board and List workflow switchers use a themed dropdown instead of a native select. The closed trigger shows the workflow identity (Fusion icon for built-ins, optional custom icon for custom workflows), name, and chevron only; compact Todo / In Progress / Done counts derived from workflow column flags (excluding archived and board-hidden columns) refresh each time the dropdown opens and appear while the dropdown is expanded, including on each workflow option. Built-in lanes with synthesized trait-less lifecycle columns fall back to canonical column ids (
todo,in-progress,done, andarchived) for those counts. Board and List also show All workflows before real workflows as a dashboard-only aggregate view with combined counts that sum only the real visible workflow rows exactly once and a deterministic union of visible workflow columns; shared column ids use the default workflow label/flags when available, otherwise the first workflow definition that declares the column. Hidden columns stay workflow-scoped in the aggregate: a task whose effective workflow hides a shared column is omitted from that aggregate column even if another workflow exposes the same column id. That option is not editable, persists as top-level workflow view state, and quick-create/Plan/Subtask/Mission handoffs translate it to a real default workflow id or no-specific-workflow behavior so task creation never sends the sentinel. Each real workflow option row also exposes an inline edit action, and a persistent New workflow footer stays visible below the scrollable option list. The open listbox grows from the longest workflow name plus its count/edit decorations while remaining viewport-bounded; the closed trigger stays narrow and ellipsized. Those inline count badges intentionally use the same board column color tokens as cards:--todo,--in-progress, and--done. - When workflow columns are enabled, Board and List hydrate the last successful workflow-lane payload from a per-project session cache; cold loads show a neutral skeleton until settings and workflow metadata are known, avoiding a legacy single-lane flash. The selected workflow is remembered per project in durable browser storage and restored when returning to Board/List after task refreshes, route changes, respecification flows, or refinement creation from Task Detail and done-task chat; Board, List, Planning/Missions header selectors, and Graph also restore the dashboard-only All workflows aggregate view when that was the last selected top-level workflow context. If a saved real workflow is later deleted, Fusion falls back to a valid default/first workflow so tasks remain visible.
- Briefly leaving Board/List for a task detail or another non-task-SSE view preserves the current in-memory task snapshot. Returning to Board/List reuses that fresh snapshot immediately and restores live SSE updates without an extra all-task fetch; Fusion still runs one catch-up fetch when task data is missing, stale, or from a failed refresh.

List View
List view is optimized for dense task management.
Features:
- Sectioned task table grouped by lifecycle column
- Sortable columns (ID/title/status/column)
- Column visibility toggles and optional hide-done filtering
- Bulk selection + batch model updates
- Bulk Pause / Unpause / Archive actions from the selection toolbar (
Pause selected,Unpause selected,Archive selected) for fast batch task state management. - Bulk delete from the selection toolbar (
Delete selected): archived selections are skipped automatically, and dependency-conflict failures can be force-deleted per task after a danger confirmation that removes dependency references. - List rows and mobile cards support the same task context menu as Board cards from right-click, keyboard context menu / Shift+F10, or touch long-press without changing ordinary row selection or tap-to-open behavior. Selecting an action applies that exact action once and dismisses the menu, including Refine for completed tasks.

Import Tasks (GitHub import)
Import Tasks is the desktop/tablet sidebar destination for importing GitHub issues and pull requests onto the board. It embeds the GitHub import surface in the main content region; the same component can still appear as a modal from compact mobile paths.
Use Import Tasks on desktop/tablet:
- Select Import Tasks in the left sidebar. Expected outcome: the GitHub import surface opens in the main content region with GitHub issue and pull request tabs.
- Choose or enter a repository (
owner/repo). If Git remotes are detected, use the remote selector. Expected outcome: Fusion loads import candidates for the selected repository and shows repository/load state feedback. - Stay on Issues or switch to Pull Requests, then optionally enter issue label filters before loading results. Expected outcome: the list pane shows matching open issues or pull requests and marks entries that already exist on the board.
- Select an issue or pull request row. Expected outcome: the preview pane shows its title, source link, body excerpt/content, labels or PR metadata, and import availability.
- Select the import action. Expected outcome: Fusion creates a task (or review task for a pull request) on the board and preserves GitHub provenance/tracking metadata. After a successful issue import, the issue selection clears and the view returns to the main issue list/no-selection preview so completed issue actions do not leave stale buttons active.
Use GitHub import on mobile:
- Open the compact Header actions or bottom More sheet and select Import from GitHub. Expected outcome: the same import workflow opens in the mobile modal layout.
- Choose the repository, issue/PR tab, candidate row, and import action. Expected outcome: Fusion creates the board task with the same GitHub provenance/tracking metadata as the desktop/tablet Import Tasks view.
Graph View
Graph view visualizes task dependencies as an interactive node/edge map.
Navigation:
- Desktop/tablet: left sidebar or applicable plugin/content navigation entry for Graph when the dependency graph surface is enabled
- Mobile: MobileNavBar → More → Graph
Behavior:
- Shows only tasks in
triage,todo,in-progress, andin-review - Excludes
doneandarchived - On desktop/tablet, the header workflow dropdown mirrors Board/List selection behavior, restores the same per-project saved workflow when available, and filters graph nodes to tasks assigned to the selected workflow; All workflows restores the full active-task graph.
- Uses Sugiyama-style layered auto-layout to place nodes by dependency depth
- Renders directed bezier dependency edges (dependent → dependency) with arrowheads
- Supports cursor-centered wheel zoom, pinch zoom, keyboard shortcuts (
Ctrl/Cmd+=,Ctrl/Cmd+-,Ctrl/Cmd+0,Ctrl/Cmd+Shift+F,Escape), and fit/reset controls via the floating toolbar with live zoom percentage - Pan limits are zoom-aware and based on full graph extents (including negative auto-layout origins), so zoomed-in views can still pan to every rendered node instead of getting trapped by fixed viewport-only bounds
- Dependency graph nodes reuse the same
TaskCardUI as board/list views, so status badges, progress/steps, mission badges, retry/archive controls, and active-task glow stay visually consistent - Active graph nodes also add a dedicated top status indicator bar and current-step row highlighting so in-progress execution state stays visible even when zoomed out
- Clicking a graph card opens task details in the shared movable/resizable task pop-out via the host detail handler (
onOpenDetail, withonOpenTaskDetailfallback), while clicking the same card again or empty canvas clears selection. - On touch devices, single-tap is reserved for pan/drag gestures, so double-tapping a node opens the same shared task pop-out; this does not change selection state.
- Hovering or selecting a node highlights its full upstream and downstream dependency chain; highlighted nodes and connecting edges are emphasized while non-chain nodes are dimmed, and highlight clears when hover/selection is removed
- Nodes support manual drag repositioning with a 4px movement threshold to separate click from drag, using pointer capture and zoom-aware delta scaling for reliable tracking
- Custom node positions persist per project in browser localStorage (
kb:${projectId}:fusion-plugin-dependency-graph:positions) across refresh/project switches, and Fit to graph clears saved positions and restores auto-layout
Workflow Selection and Editor
Workflows define how a task moves through planning, execution, review, workflow steps, merge, and any custom graph policy. Most coding tasks can stay on the default Coding workflow, but task and board workflow controls can select a different built-in or custom workflow per task. For the built-in catalog and runtime semantics, see Workflow Steps → Workflow overview.
When creating a task from the full New Task dialog, the Workflow advanced control opens a styled dropdown instead of a native select. Built-in workflows show the Fusion mark, custom workflows show their configured compact icon when present, No workflow remains the explicit opt-out, and leaving the picker untouched still inherits the project/default workflow.
The workflow editor opens as a full-screen modal editor for inspecting built-ins and authoring custom workflows.
Navigation:
- Open a task or board surface that shows the workflow selector, then choose Manage….
- From the Board or List workflow dropdown, use the inline edit button on a workflow row to open that workflow directly, or use the persistent New workflow footer to create a workflow without leaving the dropdown. The same dropdown previews each workflow's Todo / In Progress / Done task counts inline before switching.
- Use Workflows in the desktop/tablet left sidebar, compact mobile actions, or mobile More navigation to browse definitions.
- From Settings moved-setting stubs, choose Open workflow settings to jump to the default workflow's settings values.
Behavior:
- Opens a workflow node editor with a workflow list/sidebar, canvas, inspector, and settings/authoring panels
- Built-in workflows are inspectable in the same canvas as custom workflows, including connected success, failure, and rework edges for their graph topology. Their graph structure stays read-only, but prompt/gate node Prompt fields can be edited per project and reset to the shipped default from the node inspector or expanded prompt editor.
- Custom workflows can be created from blank, duplicated from built-ins/custom definitions, imported/exported, AI-designed, validated, and saved from the editor. Custom workflows can carry an optional compact plain-text icon; built-in workflow rows use the Fusion mark instead of a textual built-in suffix.
- Optional-group node inspectors include controls for
defaultOnand per-step Max revisions (maxRevisions), including an Unbounded toggle for Code Review, Browser Verification, or custom pre-merge gates that should keep cycling until they approve.
- Optional-group, foreach, and loop containers show their template nodes inside the block. Canvas connections between the surrounding workflow and the block attach to the container boundary; connections between template nodes stay inside the block. Optional groups also draw non-editable entry/exit connector lines between the boundary and the template entry/exit nodes so single-step blocks such as Plan Review and Code Review do not look disconnected; those visual connectors are not saved into workflow IR.
- The Settings panel is value-first for built-in workflows and groups workflow settings by Models, Review & Approval, Step Execution, and Advanced. Known workflow model values use the same model dropdown picker as Settings → Project Models so provider/model pairs are saved together; custom or non-model string values can still use typed inputs. Definitions remain available for custom workflow schema authoring.
- The main Settings modal also exposes the default workflow's Plan/Triage, Executor, and Reviewer model lanes from Project Models; the modal's primary Save action writes those dropdown values as workflow setting values for the active default workflow.
- On desktop, the editor uses a multi-panel canvas layout for editing the graph and adjacent workflow metadata. The Show simple editor toggle switches that same workflow into the graph-outline editor with dedicated Graph, Add, Settings, Fields, Columns, and Actions tabs.
- On viewports
<=768px, the editor switches to a full-screen mobile sheet. Global workflow entry points open to the workflow list with no workflow preselected and prompt users to select a workflow to edit; the Board/List workflow dropdown row edit action opens directly to the selected workflow editor when that selected workflow is available. - Simple/mobile editing uses a graph outline instead of making the canvas the primary control. The outline shows nodes, branch/rework edges, column placement, and optional-group/foreach/loop template children as tappable rows and chips that open the same node and edge detail editors as desktop. The structural start node opens an inspector for the workflow entry column when the workflow defines columns; the Name field remains unavailable because the start label is structural. For custom workflows, editable outline rows also expose Move up and Move down controls that reorder steps within their current column or template parent; built-in workflows remain read-only and hide those controls.
- Simple/mobile authoring exposes dedicated destinations for Graph, Add, Settings, Fields, Columns, and Actions. Add includes the node palette plus fragments, built-in step templates, and plugin step templates; Actions includes save, AI edit, auto-layout, export, and delete for custom workflows, plus export and duplicate for built-ins. Settings keeps the Definitions/Values tab split.
- The create-workflow dialog and workflow AI authoring popover follow the same mobile full-screen/sheet pattern so they are not clipped by the editor canvas on narrow screens
Custom Providers
Custom Providers live in Settings → Authentication → Custom Providers, inside the Advanced: Custom Providers disclosure. Use this section to add user-defined model providers that speak an OpenAI-compatible API, the OpenAI Responses API, an Anthropic-compatible API, or Google Generative AI. After a provider is saved with models, those models become selectable in model dropdowns, including Settings → Project Models lanes and workflow model lanes.
Settings → Global Models also includes Model pricing overrides for Command Center estimates. The section shows a compact pricing snapshot/override-count summary; use View pricing table to add or edit rows with lowercased provider:model keys (or bare :model fallback keys), USD-per-1M token prices for input/output/cache read/cache write, and optional source text. Fetch LiteLLM pricing remains available from the collapsed summary and performs an explicit one-click refresh from LiteLLM's published model pricing JSON, replaces the override table only after a successful parse, and records the fetched timestamp/source; failed fetches keep the existing overrides.
Supported API type values match the dropdown in the form:
- OpenAI-compatible
- OpenAI Responses
- Anthropic-compatible
- Google Generative AI
The custom-provider form uses these fields:
- Provider name — the display name for the provider.
- API type — one of the supported API types above.
- Base URL — the provider endpoint base URL. It must be a valid
httporhttpsURL, for examplehttps://api.example.com/v1. - API key — optional credential for providers that require authentication.
- Available models — comma-separated model IDs, for example
gpt-4, gpt-3.5-turbo.
Use Detect Models to auto-fill Available models while adding or editing a provider from the provider's /models endpoint. Detection requires a Base URL and may require an API key, depending on the provider. Saved providers also have a row-level Refresh Models action that uses the stored endpoint and credential to replace the persisted model list without exposing the raw key in the browser.
Add a custom provider
- Open Settings → Authentication → Custom Providers.
- Expand Advanced: Custom Providers if it is collapsed.
- Select Add Custom Provider.
- Enter a Provider name.
- Choose the correct API type: OpenAI-compatible, OpenAI Responses, Anthropic-compatible, or Google Generative AI.
- Enter the provider Base URL. The value must be a valid
httporhttpsURL. - If the provider requires authentication, enter its API key.
- Populate Available models by either:
- entering comma-separated model IDs manually, or
- selecting Detect Models to query the provider's
/modelsendpoint and prepend detected model IDs to the field.
- Select Save Provider.
Expected outcome: the provider appears in the Custom Providers list with its API type and base URL. Each saved model is then available in model dropdowns as a {provider}/{modelId} option, including Settings → Project Models default-workflow lanes and workflow model lanes in the workflow editor.
Edit a custom provider
- Open Settings → Authentication → Custom Providers and expand Advanced: Custom Providers.
- Find the provider in the list and select its pencil Edit action.
- Update Provider name, API type, Base URL, API key, or Available models as needed.
- Select Detect Models again if you want to refresh or add model IDs from the provider's
/modelsendpoint before saving. - Select Save Changes.
Expected outcome: the provider list refreshes, and model dropdowns use the updated model list. If you only need to refresh a saved provider's models after credentials, endpoints, or upstream availability changed, select the row-level Refresh Models action instead; failures keep the previous model list intact. If you rename the provider or change model IDs, update any Project Models or workflow model lane selections that should use the new {provider}/{modelId} value.
Delete a custom provider
- Open Settings → Authentication → Custom Providers and expand Advanced: Custom Providers.
- Find the provider in the list and select its trash Delete action.
- Confirm the prompt:
Delete custom provider "<name>"?.
Expected outcome: the provider is removed from the list, and its models are no longer offered as selectable options in model dropdowns. Review any Project Models or workflow model lane values that previously selected that provider.
Masked API key behavior
Saved API keys are stored in settings but are masked in API responses and UI-loaded provider records. When you edit an existing Custom Provider, the API key field starts blank and shows the hint Leave blank to keep current key if a key is already saved.
- Leave API key blank to preserve the saved key.
- Enter a new API key value to replace the saved key.
- The masked value shown in responses is never reused or submitted as a real credential by the edit form.
For the stored settings shape, see customProviders in the Settings Reference. For the API behavior, including masked keys in responses, see Architecture → Custom Provider endpoints.
Worktree copy files
Open Settings → Worktrees to maintain Files to copy into new worktrees. Add editable rows for repository-root-relative files such as .env, use Browse to select a project file, remove rows you no longer want, then Save. Fusion trims blank rows and de-duplicates paths before persisting. During task startup, configured regular files are copied into fresh or pooled task worktrees before the worktree init command and task execution begin; existing/resumed worktrees are not overwritten. Missing files, directories, absolute paths, traversal entries, and unreadable sources are skipped with non-fatal diagnostics and without logging file contents. See worktreeCopyFiles in the Settings Reference for the stored setting shape.
Use Show worktree grouping on the board in Settings → Worktrees when you want WIP/processing columns to always show worktree names and group cards by worktree. With the toggle off, Fusion preserves the legacy default: only the non-workflow in-progress column is grouped, and workflow-mode processing columns stay as plain cards.
Planning Mode
Planning is a desktop/tablet left-sidebar main-content destination after Command Center. It opens the planning-session list and composer in the main content region; mobile continues to use the compact planning entry points. Planning Mode now includes branch controls on the summary screen before you create a task.
Before Planning Mode shows Planning Complete! or the final plan summary, it first asks Would you like to go deeper?. Select one or more suggested themes to continue the interview, use Other to add a custom topic, or choose No, continue to final summary to reveal the pending summary and task-creation actions.
- Branch strategy options mirror Subtask Breakdown semantics:
Use project/default branchCreate auto-named branch per taskUse existing branchCreate custom new branch
- Branch name is required when using
existingorcustom newstrategies. - Merge target / base branch (optional) uses a dropdown of existing local branches (with common names like
main/master/trunk/developlisted first) plus a Custom… fallback when you need to type a branch that is not local yet. - Description supports a
Markdown/Plaintoggle in the summary header row:Plainkeeps the editable textarea, whileMarkdownrenders formatted preview (react-markdown+ GFM) in the same footprint for easier review before task creation.
These values are sent with the Planning Mode create-task request as branchSelection, so created tasks persist branch/base-branch settings consistently with other branch-aware task creation flows.
When quick-create task creation, Planning Mode, or Subtask Breakdown runs from a workflow-filtered board/list lane, the create request also carries that active workflow selection. Quick-created tasks appear on the selected workflow lane immediately while board-workflows metadata refreshes, and planning saves, planning breakdown saves, and subtask-breakdown saves create their tasks directly on the selected workflow lane instead of briefly landing on the default board. When Board is showing All workflows, quick-create uses the real workflow intake/default column that owns the affordance; it never submits the synthetic aggregate as a workflow id.
The New Task dialog's workflow selector also defaults to the current or last selected Board/List workflow lane for the current project. If no valid lane has been selected, or the remembered lane was deleted, the selector falls back to the project default workflow and task creation omits an explicit workflowId.
Optional workflow steps declared by the active workflow are available from the quick-add action row and the New Task dialog's inline quick buttons. For example, the coding workflow's browser verification option appears as a quick drop-down when that workflow is active; each option is seeded from the workflow step's defaultOn setting and is sent with the task's enabledWorkflowSteps payload at creation time.
Quick Add image attachments use the paperclip icon button in the action row. Supported image files (png, jpeg, gif, webp) can be selected from that control, pasted into the Quick Add input, or dragged onto the Quick Add box; all three paths show pending previews before task creation and upload the images to the created task afterward.
Quick entry, inline quick-create, and the full New Task dialog all check for similar active tasks before creating. When possible duplicates exist, the warning lists each match by task description (falling back to title, then “No description”) and lets you open an existing task, cancel, or create anyway with the duplicates acknowledged.
Completed single-task planning sessions remain in the Planning Mode history after you create the task, and selecting one restores the completed summary instead of restarting the composer. History rows are deduplicated by session id even if the initial load and live session updates arrive out of order, and deleting a history entry now waits for the server delete to persist (failures keep the row visible and surface an error instead of silently disappearing until refresh).
New Task Modal Branch Strategy
The New Task dialog uses the same four-option Branch strategy selector and branchSelection payload as Planning Mode:
Use project/default branchCreate auto-named branch per taskUse existing branchCreate custom new branch
Rules:
existingandcustom-newrequire a branch name.project-defaultleavesbranchunset.auto-newcreates a branch after task creation usingfusion/{task-id}-{short-name}(for examplefusion/fn-5671-branch-strategy-dropdown).Merge target / base branchstays optional for all modes and uses the same branch-dropdown +Custom…fallback behavior as Planning Mode.- In More options → Model Configuration, Auto-merge is a per-task override with three states: Default (follow project setting), Enabled, or Disabled.
The dialog also exposes AI handoffs that quick-add no longer shows: Plan opens Planning Mode with the current description, and Subtask opens Subtask Breakdown with the current description when Settings → Experimental Features → Subtask Breakdown is enabled. The Subtask handoff is hidden by default; visible handoff buttons remain disabled until the description has content, matching the quick-add row behavior for Subtask. Execution mode and optional workflow-step selection are available in the New Task dialog as well as quick entry, so users can choose Fast or standard execution and opt into workflow-specific creation-time steps before creating a task from either surface.
The full New Task dialog includes a compact GitHub issue or PR picker near the description. It detects GitHub remotes for the current project, auto-selects a single remote or origin, and asks you to choose a remote when multiple non-origin remotes are available. Selecting an issue replaces the description with a prompt that tells the executor to fetch/read the issue and includes Source: <issue-url>; selecting a pull request creates a PR-focused prompt with PR: <pr-url> and explicit instructions to inspect the PR conversation, review comments, checks, and changed files, then resolve or address actionable review comments. If you already typed a description, Fusion asks before replacing it. This picker only seeds the prompt; it does not import, close, or comment on GitHub items. On mobile, the full-screen New Task sheet keeps the GitHub picker, dependency picker, agent picker, quick handoff buttons, and action row tappable and scrollable even when the keyboard reduces the visual viewport.
Chat View
Chat view provides project-scoped conversations with agents.
- Entering
/newor/clear(exact match after trimming) in the composer starts a fresh thread for the current chat target instead of sending the literal command to the model - On mobile, the New Chat and Delete Conversation dialogs use a compact inset treatment (centered, viewport-bounded, internally scrollable) instead of the app's default full-height mobile modal chrome.
- Full Chat and Quick Chat both consume the same streamed
/api/chat/sessions/:id/messagesresponse contract, and both now prefer the authoritative assistantmessagesnapshot ondonewhile still accumulatingtextchunks when present (so providers without incremental text streaming still render output immediately) - In-progress assistant responses now survive refresh/navigation while generation is still active: Chat restores the last durable in-flight text/thinking/tool state immediately, keeps the prior persisted conversation visible, then resumes streaming from the stored replay point; any new text, thinking, or tool-call updates append to that restored bubble instead of replacing it or starting from an empty "Working…" placeholder.
- If a regular Chat stream drops with a hidden-tab/browser-suspension error (for example
Load failed) while the server is still generating, Chat suppresses the false error banner, re-attaches to the in-progress stream using the durable replay state, and reconciles the final assistant reply when generation completes. - If you queue follow-up user messages while the assistant is still streaming, Chat persists them per session, stacks each queued preview above the input box with one shared divider, and restores/sends them one at a time in FIFO order once each active response finishes if you leave and return.
- Chat message lists now track near-bottom scroll state: while you are reading older messages, live streaming/new replies do not force-scroll; a Latest jump control appears until you return to the tail.
- On mobile direct-chat threads, entering a thread and restoring Chat after tab/page visibility returns re-anchors to the newest message (
scrollTop = scrollHeight) so the view always opens at the live tail. - On mobile direct-chat threads, the top Chat header collapses into one compact row: the back button is the far-left visible control and the active conversation dropdown stays beside it, while the visible Chat icon/title shell is hidden to preserve transcript space. Tapping the active conversation opens a lightweight dropdown so you can switch to another direct session or start a New Chat without backing out to the sidebar list first; long conversation titles stay readable in the dropdown via wrapped option text and taller touch-friendly rows.
- On mobile direct-chat threads, the single thread-wide Markdown/plain eye toggle floats above the transcript/composer area instead of occupying a second header row; desktop/tablet keeps the toggle in the thread header.
- Direct chat sessions can be renamed from the sidebar row edit button, the desktop conversation context menu, and the mobile session switcher; blank rename submissions clear the custom title so the default session label is shown again.
- Task-detail planner Chat conversations stay available from each task's Chat tab, including after the task is
done. They are hidden from the common Direct/common Chat feed by default; enable Settings → Project General → Show task chats in common Chat feed to include populated task chats again. Empty task chat sessions stay hidden either way. Planner Chat can answer token-count, estimated-cost, runtime, timing-event, workflow-step duration, and per-model usage questions for the current task through a read-only task-scoped metrics tool; unknown/stale pricing is reported as uncertain instead of$0. On completed tasks, clear follow-up implementation or improvement requests can create a normal refinement task from the completed source task.
- On desktop/tablet Direct chat, the thread header shows an estimated token count against the active model's known context window (for example
~12.3k / 200k). It is hidden on mobile, narrow floating chat, rooms, and unknown-context-window models.
- In narrow Chat containers (including phone-width full Chat, narrow Quick Chat popups, and right-dock Chat), message bubbles use the full content width for improved readability. On tablet-width main Chat containers, assistant/agent, streaming, and failure bubbles keep the wider 88% reading measure, while wide desktop Chat keeps the standard 75% bubble cap.
- Full Chat tool-call summaries now use a denser mobile layout: grouped and single-call collapsed rows keep icon + label + status on one line (Quick Chat-style scanability) while expanded details remain unchanged.
- Assistant question tool calls now render as a shared in-chat response card instead of a generic tool-call disclosure. The card recognizes provider-native question tools and Fusion's
fn_ask_question, supports select, multi-select, text, and yes/no prompts, sends the formatted answer back into the same direct or room thread, and renders historical answered questions read-only. - The desktop Chat view toggle and mobile Chat tab now show an unread-response indicator when a live assistant reply arrives for a visible direct or room chat after you leave Chat; opening Chat clears it immediately. Task-detail planner Chat replies stay task-local and do not light up the global Chat unread indicator while those sessions are hidden from the common Chat feed.
- Agent-backed chat sessions now expose the same mailbox messaging tools (
fn_send_message,fn_read_messages) used by runtime execution/heartbeat flows whenever the engineMessageStoreis available; model-only chats continue to run without mailbox tools. - Chat attachments are included in agent-visible prompts for both direct sessions and rooms: supported text attachments are appended under an
Attachmentsprompt section, and supported images (png,jpeg,gif,webp) are passed as image inputs to the model. - Chat attachments can be sent without accompanying text in both Quick Chat and Main Chat; fully empty sends with no text and no attachments are still blocked.

Chat Rooms
Chat Rooms are project-scoped group conversations for multiple agents. They are separate from one-on-one direct chat sessions.
- Chat Rooms are currently gated behind the
chatRoomsexperimental feature flag. Enable it in Settings → Experimental Features → Chat Rooms. - Use the Direct / Rooms toggle in the Chat sidebar to switch scopes. The selected scope is saved and restored the next time you open Chat.
- In Rooms, click Create room to open the room-creation modal.
- Room names follow strict validation: a leading
#is removed automatically, names must be lowercase, up to 80 characters, use onlya-z,0-9,-, or_, cannot start or end with-/_, and must be unique in the current project. - The modal includes a member picker with search + multi-select from project agents. You must pick at least one member before creating the room.
- Members are currently chosen during room creation. The shipped UI does not yet provide full post-creation member management in Chat View.
- Each room row includes a trash action (
aria-label="Delete room {name}",data-testid="chat-room-delete-{slug}") that opens a Delete Room? confirmation dialog with Cancel and Delete actions. - Confirming delete calls
rooms.deleteRoom(roomId)and permanently removes the room and its messages ("This action cannot be undone. This room and all its messages will be permanently deleted."); failures surface aFailed to delete roomtoast. - Selecting a room opens the room thread pane with loading and empty states, then renders room messages from
rooms.messagesasChatMessageInfoentries in the same thread UI used for direct Chat. - Submitting the room composer calls
rooms.sendRoomMessage(...), which immediately inserts a temporary local user message and then posts toPOST /api/chat/rooms/:id/messages. - The room composer clears immediately when send is dispatched so the user gets instant feedback; on success the optimistic message is reconciled with persisted server data and the transcript is refreshed to authoritative history.
- On mobile, room threads use the same keyboard-aware thread anchoring as direct chat, keeping the composer pinned above the soft keyboard while typing.
- On mobile, the room and direct composer send buttons use a two-latch touch/pointer dedupe: pointer/touch events claim only the current gesture, while a separate click latch consumes any trailing synthetic click. One tap dispatches exactly one send, a second iOS tap within the suppressed-click window still sends, and a send-to-stop button swap does not accidentally press stop.
- The dashboard backend now orchestrates room responders on that POST: mentioned members are routed as direct responders, additional ambient members may reply (up to the room ambient responder cap), and each assistant reply is persisted with
senderAgentIdviachatStore.addRoomMessage(...). - Room responders can intentionally stay silent by returning the
__SKIP__sentinel; that sentinel is treated as a no-op and is never persisted, emitted over SSE, or rendered in room transcripts. - If room replies cannot be generated (for example no resolvable responders or all responders fail), the POST fails with an API error (HTTP 502) instead of silently returning only the user message.
- If room responders cannot be resolved or all room-reply generations fail, the POST now returns an error instead of silently succeeding with only the user message, so failures are surfaced deterministically.
- Room responder prompt construction now keeps the most recent room messages verbatim and, when the room runs long, prepends a compacted summary of older history (span, participants, and key highlights) plus an explicit latest-user-message marker so replies stay thread-aware without unbounded prompt growth.
- Room responder prompts include the latest room message attachments using the same direct-chat behavior: text is inlined into the prompt and supported images are forwarded as model image inputs.
- On send failure,
useChatRoomsrolls back/reconciles optimistic state and rethrows;ChatViewcatches once, restores the exact pre-send composer text for retry/edit, and surfaces a single error toast (no duplicate hook+view notifications). - After each send attempt, the room transcript still re-fetches authoritative messages so persisted user/assistant replies remain visible even when SSE delivery is delayed, and
chat:room:message:*SSE updates continue live fan-out. - Relationship summary: direct Chat runs one target (agent or model) per session; rooms are shared threads with multiple agent members and now use the same message contract as direct Chat; Quick Chat is still a floating panel, but when a room is selected it now reads/writes that room thread directly.
- For backend details, see the Chat Room REST API reference and the chat room storage schema (
chat_rooms,chat_room_members,chat_room_messages).
Quick Chat
Quick Chat is an optional fast, project-scoped assistant surface for conversations without leaving your current view. Depending on the project launcher setting, desktop and tablet can open it from the footer status bar beside Terminal, while mobile continues to use the compact Quick Chat panel behavior.
- Controlled by the project setting
showQuickChatFAB - Supports agent mentions (
@agent) and shared#task/file mentions - Supports
/skill:{name}in model-loop chat to request a specific enabled skill for that session; slash/catalog forms such as/skill:review/pr,/skill:review/pr/SKILL.md, andsource::skills/review/pr/SKILL.mdresolve to the matching discovered bare skill token, and the slash token is removed from the model prompt while the original user message remains in chat history - Uses the same model/provider infrastructure as full Chat view
- On small screens, compact tool-call summaries in the floating panel intentionally stay single-line (count + tool names + status) to preserve message density
- The panel header uses a session-first flow: the main dropdown lists persisted sessions (preferring
session.title, then falling back to deterministicSession Nlabels) - Quick Chat sessions can be renamed from the session dropdown, and the active title is shown in the header so custom names remain visible after the dropdown closes.
- Selecting a session from that dropdown resumes the persisted conversation; this keeps
switchSession()resume-oriented rather than forcing a new thread - Entering
/newor/clear(exact match after trimming) in the Quick Chat composer clears the active thread target: direct/model targets usestartFreshSession(...), while room targets callrooms.clearRoom(activeRoom.id). - The
+action opens an inline new-session chooser (inside the panel, not a modal) withModelselected by default and optional switch toAgent - Submitting the inline chooser uses explicit fresh-session creation and immediately persists/selects the new thread, then refreshes the session dropdown list
- On first open for a project, Quick Chat restores the last opened non-archived session from per-project local storage; if that saved session is missing, it falls back to the most recently touched non-archived session by latest activity (
max(lastMessageAt, updatedAt)), and only falls back to the first agent / configured default model when no prior session exists. - Closing and reopening Quick Chat keeps the active conversation warm in memory, so messages stay visible without a conversation reload or "Loading conversation…" flash.
- Clicking outside the desktop Quick Chat floating window closes it by default; disable Settings → General → Close Quick Chat on outside click to keep it open until you explicitly close/minimize/maximize it. Task pop-out floating windows remain persistent on page clicks.
- Queued follow-up messages entered while a Quick Chat response is still streaming now persist per session, so closing/reopening the panel restores the queued stack and flushes the messages one at a time in FIFO order as active responses complete.
- Resume lookups still use targeted session queries instead of loading the full active-session list first
- Tool-call summaries in the floating quick-chat panel are intentionally condensed into a single-line header row (especially on small screens) so tool name + status stay scannable without multi-line wrapping
- Question tool calls use the same shared response card as full Chat, with compact spacing in the floating panel and read-only answered history so Quick Chat can continue agent clarification loops without exposing raw tool JSON.
- Opening Quick Chat auto-focuses the composer as soon as it is ready on desktop and mobile viewports; mobile additionally uses the stealth-input handoff so the soft keyboard opens immediately
- FAB dragging uses pointer events with document-level move/up tracking and a 5px drag threshold so Android touch drags reposition reliably while short taps still open Quick Chat
- Quick Chat now mirrors full Chat tail behavior: if you scroll up, live updates stop auto-following and a Latest jump control appears until you jump back down.
- On mobile, Quick Chat re-anchors to the newest message whenever the panel is opened/reopened and when page visibility is restored, while still preserving the near-bottom gate so intentional scroll-away keeps Latest jump behavior.
- On mobile and other narrow Quick Chat container widths, Quick Chat bubbles use the full content width while keeping compact tool-call summary layout and full-screen/safe-area behavior intact.
- On mobile, the fullscreen Quick Chat sheet follows soft-keyboard
visualViewportheight/offset samples directly, dedupes repeated identical samples, and smooths Android resize-content height-only changes so the sheet does not visibly step while the keyboard animates. iOS-style non-zerooffsetTopsamples still apply synchronously so transform alignment stays exact. - On mobile, Quick Chat send reliability includes a delivery watchdog: if a queued message would otherwise stay stranded in the composer after a dropped or suspended stream, it is re-confirmed and delivered once no generation is in flight and no live stream is connected, so sends are not silently dropped.
- On mobile, Quick Chat sends exactly once per tap even when the browser emits paired pointer and touch events; a stop tap immediately after send is still honored.
- While a response is streaming, the Quick Chat stop control matches the send button's square dimensions (including on mobile) instead of collapsing toward its icon, so it stays an easy touch target.
Mailbox View
Mailbox view shows inbox/outbox communication threads and unread state.
- Inbox renders one row per message (no sender-based collapsing)
- clicking a message in the Mail tab opens the task detail pane with full message content and conversation context
- reply rows in the mailbox modal can expand inline to show the replied-to message context for easier thread reading
- when an agent or dashboard chat session registers an artifact with
fn_artifact_register, Fusion sends a best-effortsystem→ user inbox message announcing the new artifact (for example,New image artifact registered: <title>) with metadata forartifactId,artifactType,title,authorId, and optionaltaskId; notification delivery is informational and never blocks or rolls back the artifact registration - mailbox now includes an Approvals tab with pending and history filters (
approved/denied/completed), approval detail context, and inline approve/deny actions for pending requests - in the Agents tab, the agent selector now includes All agents, which shows one combined agent-to-agent stream (with sender + recipient labels); selecting a specific agent still shows Inbox/Outbox subtabs
- mailbox entry points now show unread/pending indicators: the desktop/tablet Header mailbox toggle shows a pending-approval dot first or an unread dot when unread mail exists without pending approvals, the mobile bottom-nav Mailbox tab carries the mobile badges/dots, and the compact Header actions overflow keeps a Mailbox entry only when the mobile bottom nav is disabled
- approval lifecycle SSE events (
approval:requested,approval:updated,approval:decided) trigger mailbox approvals refresh without manual reload - when a real pending mailbox approval request is created, the app shows a persistent approval banner above project content with an Open Mailbox CTA; task plan-approval states (
awaiting-approval) remain visible on the triage board and do not create a mailbox banner - when a task first transitions into
done, the dashboard shows a one-time Enjoying Fusion? GitHub star prompt in the project view after first-run setup is closed; clicking Star on GitHub or dismissing the card marks it shown in browserlocalStorage, so it does not reappear on reload or later task completions. The setup wizard does not add a second star prompt. - Visible message history/threading is driven by explicit
message.metadata.replyTo.messageIdlinks - Separate top-level messages from the same sender remain independent in the inbox and detail pane

Interactive Terminal
Fusion embeds a terminal using xterm.js. Desktop and tablet use the footer status bar as the terminal launcher; mobile keeps the full-screen terminal path.
On Windows, the embedded terminal starts a supported shell inside Fusion, such as Command Prompt (cmd.exe) or Windows PowerShell. Windows Terminal (wt.exe) is an external terminal host and is not required or launched for the embedded panel, so Fusion should not show native Windows Terminal help/version popups while starting a terminal. If embedded terminal startup fails, Fusion shows an inline error with Retry instead of a blocking native dialog; install or repair Windows Terminal separately with winget install Microsoft.WindowsTerminal only if you want to use Windows Terminal outside Fusion.
Use the terminal on desktop/tablet:
- Select the Terminal button in the footer executor status bar. Expected outcome: the terminal opens as a bottom-docked panel with the active shell session and a draggable top resize handle.
- Drag the top edge of the docked panel. Expected outcome: the panel height changes within its viewport-safe bounds and persists per project.
- Select Pop out from the terminal header. Expected outcome: the terminal switches to a floating window that can be dragged and freely resized; size, position, and display mode are saved per project.
- Select Dock in the floating terminal. Expected outcome: the terminal returns to the bottom docked panel using the saved docked height.
- Select the scripts chevron beside the footer Terminal button. Expected outcome: the quick scripts menu opens without toggling the terminal; choosing a script runs it in the terminal, and the menu footer opens script management.
Use the terminal on mobile:
- Open the bottom navigation More sheet and select Terminal. Expected outcome: the terminal opens as a full-screen, keyboard-aware modal rather than the desktop/tablet docked or floating surface.
- Use the Terminal tab selector to switch between terminal tabs, or use the adjacent + action to open another Project Root terminal. Expected outcome: every terminal tab appears in the dropdown, switching preserves the active session, and the desktop horizontal tab strip is not shown on mobile.
- When multiple tabs are open, use Close current tab beside the selector, then close the modal when finished. Expected outcome: mobile can close the active terminal tab without exposing a cramped horizontal tab strip, and terminal sessions reconnect/recover normally without desktop dock state affecting the mobile layout.
Open a terminal in a specific workspace:
- Open the terminal and use the workspace picker in the terminal header. Expected outcome: Project Root is always available and opens a new tab in the repository root. On narrow mobile screens, the picker menu remains visible, viewport-safe, and scrollable instead of being clipped by the terminal header.
- Select a task worktree from the Task Worktrees list, then choose Open terminal in selected workspace. Expected outcome: Fusion opens a new terminal tab with the selected task label and starts the shell in that task worktree.
- If a task is listed without a live worktree, the task remains visible but disabled and marked No worktree. Expected outcome: no empty action button or arbitrary path field is shown; create or restore the task worktree first, then refresh/open the terminal again.
The picker follows the same workspace metadata as the Files modal. The server accepts terminal working directories only for the project root or registered project worktrees; rejected, missing, or unsafe explicit worktree paths fail the new-tab request rather than opening a mislabeled Project Root shell or an arbitrary location. The existing + new-tab action remains a fast Project Root terminal on both desktop and mobile, and reconnect, restart, resize, scrollback, initial-command, and tab-persistence flows continue to use server-confirmed session metadata.
Features:
- Multiple terminal tabs, including Project Root tabs and task-worktree tabs
- PTY-backed shell sessions
- Ctrl/Cmd+C copies the current terminal selection, while plain Ctrl+C with no selection still sends SIGINT
- Ctrl/Cmd+V pastes clipboard text into the active terminal session
- The Shortcuts panel includes Ctrl/Alt helpers, ESC/Tab, common shell shortcuts, and Up/Down/Left/Right arrow buttons that send standard ANSI cursor sequences for keyboard-less shell history and line editing
- Shortcuts panel buttons preserve terminal focus on the active terminal session during pointer, mouse, and touch activation, so Ctrl combinations reliably emit control bytes to the shell
- The Preferences panel customizes font family, font size, cursor style, cursor blink, and renderer; changes persist in browser
localStorageunderkb-terminal-preferences, with the legacykb-terminal-font-sizevalue migrated automatically - Font and cursor preferences apply live to the active xterm instance; renderer changes apply the next time the terminal opens, and mobile devices keep the WebGL renderer disabled to avoid glyph artifacts
- Embedded CLI session terminals honor the same saved preferences and physical copy/paste semantics for live interactive session views: selected text copies with the platform copy modifier, no-selection Ctrl+C stays available to the shell, and paste travels once through xterm's native input path. Idle, ended, and read-only replay views suppress input handlers and mobile accessory controls. Cursor blink still stays disabled for read-only/replay sessions, renderer changes apply on the next session mount, and WebGL never loads on mobile viewports.
- Mobile-aware virtual keyboard handling and auto-refit behavior
- Reopen/reconnect/session-recovery flows preserve single-keystroke input forwarding (no duplicate characters, no page refresh required)

Git Manager
Git Manager centralizes repo operations in the dashboard. On desktop/tablet it is available as an embedded right-dock panel and can expand into a resizable modal; on mobile it opens from the compact More surfaces.
Use Git Manager:
- On desktop/tablet, open the right dock and select Git Manager. Expected outcome: Git Manager renders inline in the right dock with its section tabs and repository status.
- Select the dock expand action if you need more room. Expected outcome: the same Git Manager surface opens in a resizable modal without changing the selected dock tool.
- On mobile, open the compact Header overflow or bottom More sheet and select Git Manager. Expected outcome: Git Manager opens in the mobile modal layout with the section tabs restored as a horizontal scrolling strip.
- Select Status, Changes, Commits, Branches, Worktrees, Stashes, Recovery, or Remotes. Expected outcome: the corresponding section panel replaces the previous section while preserving the same Git Manager session.
Features:
- Branch/worktree visibility
- Commit and diff browsing, including a read-only History target selector for Git-reported worktrees in the Commits panel and View commits shortcuts from populated Worktrees rows. Changing this target affects only the Commits list and diff viewer, and the API accepts only worktrees already reported by
git worktree listfor the current repository target. - Push/pull/fetch actions
- Pull with rebase option (split-button chooses between
git pullandgit pull --rebase) - One-click Sync action in Remotes (
git pull --rebasefollowed by push; it stops and surfaces an error instead of pushing when the pull conflicts or fails) - Remote editing controls
- Stash inspection (view stat + patch) before apply/pop/drop actions
- Recovery tab for orphaned merger-autostashes; orphan counts appear on Git Manager entry points
- Remotes tab keeps "Recent commits on {remote}" in sync immediately after successful push/pull actions
Mutating actions such as staging, committing, checkout, stash, pull, push, fetch, sync, and remote edits still operate on the current repository or the active section's existing target. Use the Commits History target selector only for read-only history/diff inspection of another known worktree.

Merge Advance Notice
Merge Advance Notice is a global banner (MergeAdvanceNotice) mounted in the main app chrome that appears when the integration branch advances.
When it appears:
- Reacts to
task:mergedSSE events - Hydrates from
GET /api/tasks/merge-advance-events - Shows the latest merge-advance event for the current project
What it shows:
- Integration branch name and the new tip short SHA
- Advancing task ID and advance metadata from the event payload (
advanceMode,refName, SHA details) - Checkout-state warnings when your current worktree is dirty or has untracked files
How to react:
- Click Pull to run Smart Pull (
POST /api/git/smart-pull), including the stash-conflict flow inStashConflictModalwhen needed - Use the dismiss close button to hide the notice
- Treat dirty/untracked warnings as a hint that local changes may be auto-stashed during pull
- In Git Manager's "Recent integration-branch advances" panel, entries are classified as
pending,reachable,subsumed,orphaned, orsuperseded:pending: actionable (not reflected in HEAD; Sync can help)reachable: commit already reachable from HEADsubsumed: equivalent patch content already landed under a different SHA (history rewrite/re-squash)orphaned: recorded SHA no longer exists locally after history rewritesuperseded: recorded SHA still exists but is unreachable, and HEAD is already aligned with the local integration tip after a history rewrite (handled; no sync action applies)
- Sync working tree is shown only when there is at least one
pendingentry and HEAD is not already aligned with the integration tip; handled entries (reachable/subsumed/orphaned/superseded) can be dismissed from the panel.
Push follow-up (when shown):
- If the integration branch is ahead of
origin, the banner can show push controls with ahead count - Use Push to origin (or force-with-lease via Advanced) to publish the advanced branch tip
- If push is rejected (
rejected-non-ff/sha-mismatch), the banner offers a Smart Pull retry path
Branch names are dynamic from merge/audit payloads; the banner is not hardcoded to main.
OAuth Re-login Banner
The global OAuth re-login banner clears a provider row immediately after that provider successfully re-authenticates (from Settings → Authentication or Model Onboarding), instead of waiting for the next GET /auth/status poll interval.
For Claude/Anthropic OAuth credentials, the same /auth/status poll also attempts an automatic refresh when the stored OAuth credential has a refresh token and the access token is expired or within the refresh buffer. Anthropic banner state is keyed to anthropic-subscription (including legacy Anthropic OAuth rows), not Claude CLI state. When that refresh succeeds, the banner clears for the subscription provider without manual re-login and without waiting for a separate model request.
If the OAuth credential has no refresh token, the refresh request fails, or the provider is not Anthropic, the provider stays expired and the banner remains visible. Re-authenticate with manual re-login from Settings → Authentication or Model Onboarding.
Anthropic also supports a raw ANTHROPIC_API_KEY from a separate Anthropic API Key card in Settings → Authentication and Model Onboarding. Claude subscription OAuth remains on the Anthropic Subscription card for auth status, usage/subscription checks, and banner clearing; it also drives direct agent execution on the anthropic provider — a subscription/OAuth token runs anthropic/* selections against https://api.anthropic.com/v1 with Claude Code identity headers, no API key required. CLI-backed execution remains the distinct, explicit Claude CLI provider (pi-claude-cli); subscription OAuth does not require it. When Anthropic Subscription is expired but Anthropic API Key or Anthropic — via Claude CLI is already authenticated, the global banner suppresses only the urgent subscription re-login entry so it does not imply agents are blocked; Settings still shows the subscription OAuth card as expired/not connected and re-login remains available. A configured API key takes precedence over OAuth on the direct provider. Saving or clearing an API key does not affect the OAuth sign-in path or turn OAuth tokens into raw API-key material. The dashboard only displays masked key hints after a key is saved.
Smart Pull
Smart Pull is a one-shot pull workflow that keeps local work safe while advancing your checked-out integration branch.
What it does:
- Calls
POST /api/git/smart-pull - If your worktree is clean, runs a fast-forward pull and returns
kind: "clean-pull" - If local changes exist, auto-stashes (including untracked files), runs
git pull --ff-only, then restores the stash - Returns
kind: "stash-pull-pop"when stash → pull → pop succeeds cleanly - Returns
kind: "stash-pop-conflict"when stash restore conflicts, then opensStashConflictModal
Where it is triggered:
- From the merge-advance banner pull action (
MergeAdvanceNotice) - From any dashboard surface that invokes
POST /api/git/smart-pull
When stash-pop-conflict occurs, StashConflictModal shows:
- Stash short SHA + stash label
- Per-file conflict list
- Per-file resolution actions (Keep mine / Keep incoming, backed by
/api/git/stash-resolvechoicesours/theirs) - Stash actions: Drop stash (
POST /api/git/stash-drop) and Restore from stash ref (POST /api/git/stash-restore) - A stash-SHA copy button for sharing the conflict list/reference
After resolution:
- As each file is resolved,
remainingConflictsshrinks; when empty, the modal can be closed and the branch stays at the advanced integration tip with resolved stash content applied - Dropping the stash discards the saved local edits after conflicts are resolved
- Restoring from stash ref re-applies the stash and may reintroduce conflicts for manual handling
You may also see matching run-audit events in logs, including pull:fast-forward and stash:pop-conflict.
goal:* run-audit events (goal:injection-applied, goal:injection-skipped, goal:retrieval-invoked) use the same timeline endpoint and are filterable with startTime/endTime query params.
Goal run-audit metadata is IDs-only (goalIds + counts/tool fields) and never includes goal titles/descriptions/prompt text.
For per-run aggregation, GET /api/agents/:id/runs/:runId/cited-goals returns { runId, taskId?, injectedGoalIds, retrievedGoalIds, citedGoalIds }.
Artifacts View
Artifacts view aggregates project markdown files, task documents, and registered artifacts. The dashboard title is Artifacts; the internal tab bar keeps the shipped Project Files, Task Documents, and Artifacts labels.
Features:
- Group task documents by task ID (with revision history metadata) and show the parent task status badge in each task group header when status metadata is available
- Search documents across tasks
- Open project markdown files with inline preview
- Browse the Artifacts tab for registry media registered by any agent, dashboard chat/user action, or system tool across tasks
- Already-open global and task-detail artifact lists refresh live from the artifact registry event when an agent, dashboard chat session, user action, or system tool registers a new artifact, while preserving active search filters and task scoping
- Use the tab-count badges to see the current counts for Project Files, Task Documents, and Artifacts; the Artifacts badge reflects the loaded
GET /api/artifactsresult set, including active search filters - Use the responsive media gallery to scan thumbnail-first image and video cards with consistent framing, while audio, document, and generic artifacts remain readable cards in the same grid
- Expand image and video artifact thumbnails into a full-size lightbox; dismiss it with the close button, backdrop click, or Escape while non-previewable artifact cards keep their normal controls and links
- Preview artifact images inline, play video and audio with native controls, read document previews from inline content/description, and open generic
otherartifacts through their media URL (GET /api/artifacts/:id/media) - Read artifact metadata on each card: type badge (
Image,Video,Audio,Document, orOther), title, optional description/content preview, author ID, timestamp, and linked task title/ID when present - Use Open task on an artifact card to jump back to the originating task when the artifact has a
taskId; inside task detail, the Artifacts tab shows that task's documents and registered media artifacts together - Loading state: the Artifacts tab shows
Loading artifacts…while the first artifact list request is pending and no artifact results are loaded - Empty states: with no search query it shows
No artifacts yet.plus the hint that artifacts are created by agents, users, and system tools; with a search query it showsNo artifacts match "<query>". - Error state: a failed artifact list request uses the shared
Failed to load artifacts: <error>panel with a Retry action that re-runs the artifact fetch - Toggle between raw text and rendered markdown using the Markdown/Plain button
- Highlight text in raw or rendered project-file previews, choose Add comment, and send the file path, selected snippet, and your comment to the New Task dialog
Agent registrations also surface through the Mailbox View: successful fn_artifact_register calls send a best-effort system inbox notification so users can discover new media even before opening the gallery. Artifact list live-refresh does not depend on that best-effort message; it listens to the registry registration event.

Reports View
Reports View is available when the Reports plugin is installed and enabled.
Navigation:
- Desktop/tablet: left sidebar plugin/content entry for Reports when the Reports plugin is installed and enabled
- Mobile: More sheet → Reports
Features:
- Reports history list with filters for cadence, status, date range, title text, and agent
- Detail viewer with a sandboxed iframe preview backed by the report HTML preview endpoint
- Section quick-jump sidebar based on stable report section markers
- Compare drawer for side-by-side report comparisons with section-level diff groupings
- Standalone HTML download/export action for sharing a self-contained report file
For plugin internals (registration, API routes, rendering/export pipeline), see Reports plugin docs.
Markdown Rendering
Artifacts view supports toggling between raw text and formatted markdown when viewing document content:
- Raw mode (default): Shows markdown syntax as plain text (e.g.,
**bold**) - Markdown mode: Renders markdown with proper formatting (e.g., bold, headings, lists, tables)
The toggle button is accessible with aria-pressed for screen readers. Toggle state is scoped per-document, so switching between documents resets the view to raw mode.
Project-file previews also support selection comments in both raw and rendered markdown modes. Select text, click Add comment, enter a short note, and Fusion opens New Task with a seeded description containing the file path, snippet, and comment.
Todo View
Todo View is an experimental full-height dashboard surface for managing per-project todo lists and turning items into planning or task workflows. It renders in the right content area like other project views rather than as a modal overlay.
Available when
experimentalFeatures.todoViewis enabled.
Navigation:
- Desktop/tablet: Left sidebar → Todos when the Todo view is enabled
- Mobile: More sheet → Todos
For full behavior, API contracts, and storage details, use the canonical Todo View guide.
Research View
Research view is a standalone dashboard surface for creating and managing research runs.
Available when
experimentalFeatures.researchViewis enabled. The related Settings sections (Research Defaultsand projectResearch) are also hidden until this flag is enabled.
Features:
- Create-run form with required query text and selectable provider options
- Searchable run history list with project-scoped state
- Selected-run reader with summary, citations, findings, and run event history
- Run lifecycle controls: cancel, retry, and refresh
- Export actions for supported formats (
markdown,json,htmlas advertised by backend availability) - Task-facing actions to create a new task from findings or attach findings to an existing task
- Graceful unavailable/setup messaging when research backend capability is disabled or not configured
Navigation:
- Desktop/tablet: Left sidebar → Research when the Research view is enabled
- Mobile: More sheet in
MobileNavBar - Research is intentionally separate from the primary Board/List workflow controls
For the full research workflow, provider setup, CLI commands, API reference, and agent integration, see the canonical Research guide.
Files Modal
The Files modal provides a workspace-aware file browser and editor.
- In Files — Project, use the visible Create new file and Create new folder buttons in the browser header to create entries in the current folder; new files open in the editor after creation
- In Files — Project, use Search project files to find project files recursively without navigating the tree; matching rows include path context so duplicate filenames can be distinguished
- Source/text editing supports a Line # header toggle to show or hide line numbers in the editor gutter
- The line-number preference is saved per project and restored automatically when you switch projects
- Known image, video/movie, audio, and PDF files render browser-native read-only previews inline with their real content type from the selected project or task workspace download URL; the explicit Download action still saves files as attachments, text files remain editable, and unknown binary files keep the read-only editor fallback
- In editable files and markdown preview mode, highlighted text exposes Add comment so you can send the file path, selected snippet, best-effort line range, and your note to the New Task dialog without copy/paste
Memory View
Memory view provides a multi-file editor for project and daily memory files. Its file editors share the same highlighted-text Add comment affordance as the Files modal, so memory snippets can seed a New Task with file path, snippet, and comment context.
Available when the
experimentalFeatures.memoryViewtoggle is enabled.

Setup Wizard Project Registration
First-run setup and embedded project setup both expose a Repository setup section before path entry:
- Use Existing Directory registers an existing git repository or workspace root. Workspace detection and the workspace-mode checkbox only appear in this mode.
- Initialize New Repository registers the selected local folder and relies on the server-side project registration path to run
git initif the folder is not already a git repository. - Clone Git Repository requires a non-blank remote URL and an absolute destination path. Fusion runs
git clonewith argument-vector execution, requires the destination to be absent or empty, cleans up a newly-created failed destination best-effort, then registers the cloned folder.
Advanced setup remains limited to runtime node and isolation-mode choices, so repository mode selection is not hidden behind the advanced panel.
Agents View
Agent list and detail surfaces now surface pending approvals per agent:
- Agents list/board cards show a warning-colored pending-approval badge when
pendingApprovalCount > 0 - Agent detail summary shows a matching pending-approval badge for the selected agent
- Approval SSE events refresh these indicators live (no page reload required)
Agents view is the control surface for runtime agents and team structure.
Navigation:
- Desktop: primary view toggle (Agents)
- Mobile: bottom nav tab (Agents)
Features:
- Switch between List, Board, and Org chart layouts
- Filter by role/state, include/exclude system agents, and inspect health/status
- Token Usage by Agent includes task-derived token counts for ephemeral/task-worker system agents when system agents are shown, matching Agent detail and Command Center Team token surfaces.
- Agent list cards show the configured Model or plugin Runtime for each agent, falling back to Auto when no override is set
- Agent list, live-agent, and detail task badges show the linked task ID with its current column when the task is non-terminal (for example
FN-6902 · TriageorFN-6902 · In Progress). Terminal linked tasks are omitted, and unresolved column lookups render an explicitUnresolved tasksuffix so missing or deleted task links are not mistaken for healthy parked work. - First-run setup asks whether to create an optional project agent after project registration. The default template is CEO; users can choose another preset, use the AI interview when
experimentalFeatures.agentOnboardingis enabled, or skip it. Fusion can still build tasks without an agent by starting temporary agents to plan, code, review, and merge task work. - Start, pause, stop, and trigger agent runs from the view and from detail panels
- In Agent detail, use the kebab Bulk agent actions button in the header utility cluster (next to Refresh and Close) to run project-wide lifecycle transitions for non-ephemeral agents in the current project — Pause All Agents targets agents in the
activeorrunningstate, while Resume All Agents targets agents in thepausedstate only - Bulk menu items stay disabled when nothing is eligible and show an inline hint (
Loading eligible agents...,No active agents eligible,No paused agents eligible, or the current eligible count such asPause 2 active/running agents) - Bulk lifecycle flow: open Bulk agent actions, review the eligibility hint, confirm the modal, then use the success or partial-failure toast to verify paused/resumed counts plus skipped/failed agents
- Open agent detail tabs for runs, logs, read-only mail (agent inbox/outbox), settings/config, tasks, memory, and chain-of-command relationships
- Error indicator on agent list cards when an agent is in the
errorstate and has a captured error (lastError); select it to open Agent Error Details - Run-level error indicator in Agent detail → Runs when a run has captured stderr; select it to open the same Agent Error Details modal
- Agent Error Details shows full error text plus Copy and Report on GitHub actions
- Report on GitHub opens a pre-filled issue draft with available context from where you launched it (surface plus agent metadata, and run/task IDs when available on that view)
- Jump from agent activity to related task logs, and (when
experimentalFeatures.agentOnboardingis enabled) launch AI Interview from the New Agent dialog (create mode) or Agent detail → Settings (edit mode)
For full lifecycle behavior, runtime/heartbeat settings, and budgets, see Agents guide.
Missions View
Missions view manages mission hierarchies and task handoff from milestones, slices, and features.
Workflow behavior:
- When workflow columns are enabled and more than one workflow is available, Missions shows the same header workflow selector as Planning.
- Feature triage and slice Triage all features create new tasks on the selected workflow.
- If no workflow is selected, or workflow columns are unavailable, mission-created tasks continue to use the project default workflow.
Plan Mission with AI modal behavior:
- On desktop, the modal opens as a floating workspace that can be dragged by its title bar and resized from the window edges/corners.
- On mobile, the mission interview keeps the fixed full-screen/sheet-style layout so touch users retain the original focused flow.
- If the mission interview stream reports a terminal failure, the modal closes the failed stream, shows one normalized error, and offers retry without duplicating late error/complete events.
- Structured single-select and multi-select interview questions include Other (write your own) so users can decline all suggested options, submit a free-text answer, or combine that text with selected multi-select options.
Roadmaps View
Roadmaps view manages roadmap hierarchies (roadmaps, milestones, features) and planning handoff exports.
Available when
experimentalFeatures.roadmapis enabled. Hidden when a plugin replaces Roadmaps navigation.
Navigation:
- Desktop/tablet: left sidebar plugin/content entry for Roadmaps when the Roadmap plugin is enabled
- Mobile: More sheet (or promoted to a top tab when eligible based on mobile nav slot rules)
Features:
- Create, edit, archive/delete, and reorder roadmaps, milestones, and features
- Use inline editing plus drag/drop for milestone and feature organization
- Open roadmap export modal and copy mission/feature planning handoff payloads
- Feed roadmap output into mission/task planning workflows
For mission planning context and handoff structure, see Missions guide.
Goals View
Goals view is a strategic-goals surface backed by the Goals REST API.
No feature flag required. Current status: the
GoalsViewchunk is lazy-defined/prefetched inApp.tsx, but it is not yet wired into the primary dashboard navigation.
What it shows:
- Header with active-goal count (
N active goals) and an Add Goal action - Goal cards with title, optional description,
Status: active|archived, and a Linked Missions section - Linked-mission chips navigate to Mission Manager, each chip has an unlink control, and the card picker hides missions already linked to that goal
- Empty state when no goals exist:
No goals yet. Add one to begin tracking strategic outcomes.
Data behavior:
- Initial load:
GET /api/goals(returns{ goals }) - Create: inline Add Goal form posts
title(required) +description(optional) toPOST /api/goals - Add-form drafting: Draft with AI sends the typed goal title to
POST /api/ai/draft-goal-descriptionand drops the returned{ description }into the description textarea for review/editing before save - Edit: per-card inline form patches title/description via
PATCH /api/goals/:id - Archive/unarchive:
POST /api/goals/:id/archiveandPOST /api/goals/:id/unarchive - Linked missions:
GET /api/goals/:id/missionsfor the reverse lookup, thenPOST/DELETE /api/missions/:missionId/goals/:goalIdfor link/unlink mutations
AI drafting behavior:
- The add-goal form enables Draft with AI once the title is non-empty
- Draft requests are readonly and use the same shared AI-text rate limiter as
/api/ai/refine-text(10 requests per hour per IP) - The backend drafts a concise plain-text strategic goal description from the title only; users can freely edit the generated description before saving
Active-goal cap behavior:
- Hard cap of 5 active goals (server-enforced)
- Warning banner appears when active goals are in the 3–5 range
- Cap violations (for create or unarchive) return HTTP 409 with
code: ACTIVE_GOAL_LIMIT_EXCEEDEDand are surfaced as inline goal errors
Source file: packages/dashboard/app/components/GoalsView.tsx
Evals View
Evals view is a dedicated dashboard surface for reviewing scheduled task-evaluation output.
Available when
experimentalFeatures.evalsViewis enabled.
Navigation:
- Desktop/tablet: Left sidebar → Evals when evaluations are enabled
- Mobile: More sheet → Evals
Features:
- Filter eval results by free-text query, run, and score range
- Review list summaries (task, eval/run identity, timestamps, and score)
- Drill into full rationale, category scores, evidence references, and suggested follow-ups
- Open Scheduled Evals settings directly when setup is disabled
Insights View
Insights view surfaces categorized project insights and lets you turn findings into work.
Available when
experimentalFeatures.insightsis enabled.
Navigation:
- Desktop/tablet: Left sidebar → Insights when insights are enabled
- Mobile: More sheet → Insights
Features:
- Category-based insight browser with run metadata and status indicators
- Manual insight generation plus refresh actions for latest insight runs
- Dismiss/archive/unarchive insight records as they age
- Create triage tasks from selected insights directly from the view
Command Center
Command Center is the combined analytics and live-operations surface for a project: it pairs historical usage, cost, throughput analytics, live system telemetry, and a live Mission Control panel.
Navigation:
- Desktop/tablet: primary header view toggle, immediately after Agents
- Mobile: bottom nav tab, immediately after Mailbox
- Deep link:
?view=command-center
Features:
- Global date-range picker in the header scopes the analytics tabs; Last 24h, Last 7 days, Last 30 days, All time, and custom/open-ended ranges each request their selected analytics window. Mission Control remains live rather than historical.
- Overview controls dashboard sits at the top of the Overview landing surface on desktop and mobile. It includes AI engine stop/start backed by
globalPause, live scheduler status from executor stats, the shared Global Max Concurrent slider backed by/api/global-concurrency, range sliders formaxConcurrent,maxTriageConcurrent, andmaxWorktreesthat persist through/api/settings, and a compact theme dropdown with the same color-chip swatches and Shadcn variant list as Settings → Appearance. The four concurrency sliders ask for confirmation after a changed value settles; confirming persists the new cap, while cancel, backdrop, or Escape dismissal reverts to the last persisted value without saving. The global and current-project max-concurrent sliders show running-agent counts plus a current-use dot on the track once utilization data loads; triage and worktree sliders remain cap-only. These controls reuse existing APIs and App-level theme setters; they do not add a new backend route or second theme owner. - Overview summarizes token usage/cost, autonomy, active nodes, sessions, agent runs, tasks done, model breadth, and real open signals, and includes the SDLC throughput funnel for the selected range at the bottom of the Overview content in loading, error, empty, and populated states. Its token total and Live activity snapshot token metric refresh on a bounded live cadence and animate number changes while preserving reduced-motion preferences. The sessions card uses the selected-range
ActivityAnalytics.sessionsvalue already loaded for the overview. The Live activity snapshot also shows the current board-state count for tasks in progress, independent of the selected analytics date range. Overview's active-agent and daily activity values count durable-agent usage events plus ephemeral task-worker execution runs, including graph-owned workflow step sessions that publishagentRunslifecycle rows, with the same agent counted once per day/range if both sources record activity. Overview includes a graph-rich software-factory snapshot with the existing top-model-consumers bar, tool-category bar, top-model token-share pie, and the daily activity multi-series line chart placed before the daily activity sparkline/trend so the richer line graph sits higher in the chart grid. These reuse the already-loaded tokens, tools, activity, and signals analytics; the signals count comes from/api/command-center/signalsand renders unavailable (—) while the incidents-backed response is loading or unavailable. The chart reveal/glow accents are decorative and disabled when reduced-motion preferences are active. The SDLC completion rate is shown as a radial gauge and is calculated as cohort conversion from in-range triage entrants, so the rate is capped at 100% even when older tasks finish during the range.
- Tokens breaks down token totals, estimated cost, task count, chat-turn count, and per-model usage. Per-model and per-provider breakdowns include task execution tokens plus supported dashboard chat, task-detail planner chat, and room responder turns when their runtime exposes authoritative session token stats; CLI-backed chat and title generation are excluded until those paths expose reliable stats. Task counts remain task-only while chat turns are counted separately, so task detail token panels stay execution-scoped and planner chat does not double-count the task it discusses. Per-model and per-provider breakdowns use the task/chat analytics-only actually-used model snapshot when available, so usage from settings-resolved runs appears under the real runtime model instead of
(unknown)without changing future model resolution; estimated cost uses the same snapshot-first, legacy-fallback model identity so those resolved runs price normally when the model is in the pricing table. Estimated cost is derived at read time from recorded token counts multiplied by the effective per-model pricing table: Settings → Global Models pricing overrides win first, then the built-in fallback table is used. It is not persisted, so historical rows stay tied to current maintained prices instead of stale stored billing truth. The Tokens area shows a prices as of date/source for the effective table, marks pricing older than the staleness threshold as low-confidence, and shows cost unavailable for models with no pricing entry rather than guessing a price. It includes the existing token-usage-over-time chart, an additive recharts multi-series line graph, a full token-by-model bar, and a token-share pie backed by every grouped model returned by token analytics; use the granularity control to switch the time-series request between hourly, daily, and weekly buckets. The token total and charts poll on a bounded cadence, keep the previous data visible during refresh, animate decorative count/bar transitions, and disable those animations for reduced-motion users. - Tools shows autonomy ratio, tool-call volume, intervention counts, sessions, and tool categories. The area keeps the existing category bar and adds a recharts category-share pie from
ToolAnalytics.byCategory. There is intentionally no tools line chart yet becauseToolAnalyticsdoes not expose a per-day tool trend; the dashboard does not fabricate one or call a new endpoint. - Activity tracks sessions, messages, active nodes, active agents, agent heartbeat runs, and stickiness. Active agents include durable-agent
usage_eventsand ephemeral task-workeragentRunsrows in the selected range; graph-owned/new workflow step sessions publish thoseagentRunsrows as they move from active to completed/failed, duplicate same-day agent ids across both sources count once, and run-only task workers still make the active-agents lines and stat cards non-zero. Agent-run sheets show total, active, completed, and failed runs for the selected range, and the Agent runs/day sparkline trends runs byagentRuns.startedAt. The area keeps the existing live animated line charts for messages/day, active agents/day, active nodes/day, and combined throughput/day (messages + active agents + active nodes), and adds a recharts multi-series line graph for messages, active agents, and agent runs plus an agent-run outcome pie from the existingagentRunssplit. These charts reuse the existing activity analytics endpoint, refresh on a bounded 15-second cadence while mounted, keep the previous data visible during refreshes, and disable decorative draw-on motion for reduced-motion users. - Productivity separates outcome counters (commits and pull requests), task-duration stats, and volume proxies such as modified files, lines changed, and files by language. The task-duration block counts done tasks completed in the selected range and shows average, median, p90, and total active execution time from
cumulativeActiveMs; when no qualifying duration data exists, duration values render the unavailable—sentinel rather than0. The Lines changed card includes Preview LOC backfill, an explicit operator control for historical commit-association diff stats. Preview runs the project-scoped backfill in dry-run mode by default and reports scanned rows, distinct commits, updated rows, skipped unavailable commits, and skipped invalid SHAs without writing; Apply backfill appears after a preview and requires danger confirmation before persisting additions/deletions totask_commit_associations, then renders the same counts as an applied report. It keeps the files-by-language bar and adds a language-share pie fromProductivityAnalytics.byLanguage. There is intentionally no productivity line chart because the current productivity response has no per-day throughput or completion time series; no new endpoint is called. - Team shows the read-only agent org chart, heartbeat pause/resume backed by the existing
enginePausedsetting, a per-agent analytics table, tokens-by-agent and tasks-done-by-agent charts, and a real token-share pie from the same per-agent token totals. The org chart is styled by Command Center's Team CSS, not lazy Agents view CSS, auto-switches to a horizontal top-down tree when the container is wide enough using the same breakpoint resolver as the full Agents view, and otherwise keeps the vertical nested list inside the taller scrollable org-chart container. The org-chart scroll container supports mouse click-and-drag panning while touch devices keep native scrolling. Parent agents draw connector lines to child agents in both horizontal and vertical Team layouts across desktop and mobile breakpoints. Org nodes show only agent names so role/title description/meta text does not clutter Team operations. Metrics come only from the project-scopedtasksandagentstables: token totals and estimated cost are summed from thetokenUsage*columns byassignedAgentId, files changed counts parsedtasks.modifiedFilespaths, tasks done countscolumn = 'done'moves in the selected range, and in-progress / in-review values reflect current task columns. Agent name, role, and live state come from theagentstable; deleted-agent task history falls back to the raw agent id instead of crashing. The tab uses/api/command-center/team, adds no schema, never calls GitHub, and intentionally leaves per-agent issues filed/fixed to FN-6653. Team has no per-day analytics series today, so it intentionally does not render a line chart or fabricate a trend. Decorative chart reveal motion uses duration tokens and is disabled for reduced-motion users.
- Workflows breaks down selected-range token totals, estimated cost, tasks done, in-progress and in-review counts, and files changed by workflow. Tasks with an explicit workflow selection appear under that built-in or custom workflow identity; tasks without a selection are attributed to the project default workflow. Unknown model pricing keeps the unavailable
—cost sentinel rather than displaying$0, matching Tokens and Team cost semantics. - Ecosystem shows active model breadth, per-model task activity, and real plugin activations for the selected range. Plugin activation counts come from project-scoped plugin/extension load events via
/api/command-center/plugin-activations; if no activation rows exist in range, the metric renders unavailable (—) rather than fabricating zero. The tab still reuses the tokens analytics endpoint grouped by model, adds a task-share-by-model pie fromTokenAnalytics.groups, and renders a tokens/tasks trend line whenTokenAnalytics.seriesbuckets are present; if series buckets are absent, no synthetic trend is shown.
- GitHub shows local GitHub issue flow for the selected range: Filed by Fusion counts tasks with a persisted
githubTracking.issue, Fixed by Fusion counts tasks imported from GitHub source issues (sourceIssueProvider = "github") that are currently indone, using the persistedsourceIssueClosedAt/TaskSourceIssue.closedAtclose time when the reconciler has observed it. Rows that predate the field or have not been observed closed fall back to taskupdatedAtas the documented completion-time approximation; Fusion never fabricates a close timestamp and this analytics path never calls GitHub, theghCLI, or any external network source. To make historical fixed dates exact, use Backfill exact close times in the Fixed by Fusion card; the dashboard calls the project-scoped manualPOST /api/git/github/backfill-source-issue-closed-atendpoint in{ offset, limit }batches untilhasMoreis false, then surfaces the accumulatedscanned,filled,skipped, anderrorscounts. The endpoint fetches real GitHubclosed_atvalues once, fills only missingsourceIssueClosedAtvalues, and never runs automatically or from analytics-time rendering. The area shows filed/fixed/net stat cards, a filed-vs-fixed pie, a filed/fixed recharts trend line, existing daily sparklines, a by-repository bar breakdown, and a Resolved issues detail list. Resolved rows include the Fusion task, repository, source issue number, optional issue link, resolved timestamp, and whether that timestamp is exact (sourceIssueClosedAt) or the documentedupdatedAtapproximation; missing issue URLs render as plain text rather than empty anchors or click targets. The same resolved rows are available from the GitHub analytics payload asresolvedand from the CSV export.
GitLab Settings disclosure and enable toggle
GitLab settings are collapsed by default to keep Settings less noisy. Use Settings → Project → General → GitLab Configuration for project GitLab URL/API overrides, Settings → Project → Merge → GitLab Authentication for project token settings, and Settings → Global General → GitLab Configuration for global fallbacks. Each disclosure header includes Enable GitLab integration so operators can disable GitLab without expanding advanced fields.
When gitlabEnabled is off, Fusion keeps saved GitLab URLs and tokens intact but disables outbound GitLab API work: Import Tasks GitLab fetch/import controls show an enable-in-Settings message, API/CLI/pi import paths reject before network calls, and lifecycle comments/close/reconcile/refresh paths skip with diagnostics. Existing imported-task GitLab metadata remains viewable. GitHub imports and GitHub settings are unchanged. GitLab Signals inbound webhooks are configured separately by FUSION_SIGNAL_GITLAB_SECRET; they are not governed by the outbound GitLab API enable toggle.
- Signals is backed by the project-scoped
/api/command-center/signalsendpoint, which aggregates real rows from the localincidentstable. Verified external connectors (POST /api/signals/gitlab,/webhook,/sentry,/datadog, and/pagerduty) create triage tasks and also write/resolve incidents, so Signals shows total/open/resolved counts, MTTR when resolved incidents have enough timestamps, and source/severity/status breakdowns from connector traffic. GitLab supports GitLab.com and self-managed project/group issue and merge-request webhooks through the environment-onlyFUSION_SIGNAL_GITLAB_SECRETandX-Gitlab-Tokenheader; no GitLab CLI or server-side link fetch is used. Signals adds an open-vs-resolved status pie from the same response. Signals has no per-day series today, so it intentionally does not render a line chart or fabricate a trend. The companion/api/command-center/signals/connectorsendpoint returns only per-provider configured booleans, allowing the empty state to distinguish "no connector configured" from "connector configured, awaiting signals" without exposing secrets. - System is the canonical system-telemetry destination. It reads local telemetry from
GET /api/system-statsand, when multiple registered nodes exist, shows a node selector that can proxy the same system-stats payload throughGET /api/nodes/:id/system-statsfor remote nodes. It renders live radial gauges for app CPU, host memory, and heap usage, keeps a small client-side rolling buffer for CPU/memory/heap trend sparklines, adds a recharts CPU/memory/heap line from that same rolling buffer, and adds a task-by-column pie alongside the existing tasks-by-column and agents-by-state bars. Host memory uses OS-available memory (Nodeprocess.availableMemory()when available, with a flaggedfreememfallback) so macOS inactive/cache pages are not reported as used. The Vitest process count, manual kill confirmation, auto-kill toggle, threshold controls, and last-auto-kill timestamp moved here unchanged; the standalone System Stats modal and its desktop Header/mobile More affordances were removed. - Mission Control shows live active sessions/runs/nodes, current sessions and nodes, an animated live activity snapshot, and a live SDLC funnel; when idle it reports that live updates resume when work starts. No additional pie or line chart is rendered because the live SDLC funnel already visualizes the panel's only quantitative distribution (
snapshot.columns), while sessions/nodes are live control lists rather than categorical analytics. Motion-heavy accents respect reduced-motion preferences. - CSV exports are available from the analytics endpoints with
?format=csv. The Tokens CSV includesnTasksandnChatMessagescolumns so mixed task/chat totals can be reconciled without relabeling chat turns as tasks. The Workflows CSV includes one row per workflow plus a summary row; the Activity CSV includes dailyagentRunsvalues plus summary rows for(agentRuns.total),(agentRuns.active),(agentRuns.completed), and(agentRuns.failed).
Rendering invariants:
- On mobile (
max-width: 768px),.cc-tabpanelremains the sole vertical scroll owner for every chart-bearing tab. Shared chart primitives (Bar,StackedBar,Sparkline,LineChart,RadialGauge,Funnel,TokenSeriesChart, and the Command Center recharts wrappers) must shrink within the tabpanel, keep non-zero usable height, avoid stretch/clipping artifacts, and never introduce a competing vertical overflow container. - The hand-rolled Activity
LineCharttracks its rendered SVG box for coordinates: populated paths fill the available chart width (no centered square letterboxing), while point markers remain true circles even when the CSS chart box is wide/short on desktop or auto-aspect on mobile. - Mobile chart text must not rely on min-content luck: bar labels, values, token-series axis labels, funnel headers, radial labels, legends, and chart tracks need explicit
min-inline-size: 0, wrapping, or ellipsis rules so long model/agent/repo labels cannot crush the track or create hidden horizontal overflow in a real browser. - On tablet (
min-width: 769pxandmax-width: 1024px),.project-content,.command-center, and.cc-tabpanelkeep the same definite flex/min-height scroll-owner chain, while the live strip and chart grids collapse before they can create document-level horizontal overflow. - Command Center stat cards, overview chart cards, live strips, table wrappers, Team chart panels, token-series plots, system control cards, and gauge/chart cards share the same tokenized rhythm:
--space-mdgaps/padding for card-like surfaces,1px solid var(--border-subtle)borders,--radius-mdradii, and--surface-1backgrounds. Area-specific accents may usecolor-mix(...), but layout, border, radius, text color, and motion must stay on design tokens, with the named 4px spacing scale (--space-xs/sm/md/lg/xl/2xl) as the canonical vocabulary. - The dashboard browser-layout smoke includes a
[data-smoke="command-center-charts"]fixture that loads emitted lazy Command Center CSS and verifies representative recharts pie, line, and empty states at mobile (390×844) and desktop breakpoints. The fixture asserts non-zero chart and SVG heights, visible empty-state text, no internal/page horizontal overflow, and no chart-level vertical scroll owner before chart layout changes are considered verified.
Data states:
- Overview shows a loading state while core analytics settle, then shows
No usage data yet. Run some agents to populate the Command Center.only after the selected range has settled with no core usage data. Overview, Tokens, Tools, Activity, Productivity, Team, Workflows, Ecosystem, GitHub, Signals, System, and Reliability omit their additive recharts cards in loading/error/empty states, so non-populated data never leaves an empty chart shell. - GitHub issue analytics is local and additive: empty filed/fixed totals keep the stat cards and historical backfill button available while omitting empty chart shells; malformed historical
githubTrackingJSON is skipped instead of breaking the Command Center. - Team analytics renders its shared loading/error/empty states for null or zero-agent responses, omits empty chart shells for zero-value datasets, and keeps the Command Center tab panel as the mobile scroll owner.
- Workflow analytics renders the same shared loading/error/empty states for zero-workflow responses, omits empty chart shells for zero-value workflow datasets, and keeps unavailable cost as
—instead of$0. - System telemetry keeps the previous snapshot visible during refresh failures, preserves the node selector when a selected remote node fails to refresh, renders a first-sample CPU
Sampling…state without NaN values, shows zero-value task/agent bars for empty collections while omitting the zero-value task-distribution pie, and keeps the Command Center tab panel as the mobile scroll owner. - Signals is best-effort over local incidents data: if the project has no incidents, the Signals area shows either the setup empty state (no signal connector secret configured) or the quiet empty state (at least one connector configured but no rows in range), omits its status pie, and other Command Center metrics remain valid; endpoint errors surface as the shared analytics error state instead of silently swallowing a missing route.
Reliability View
Reliability view summarizes in-review pipeline health so operators can spot bounce/merge instability trends without leaving the dashboard.
Navigation:
- Desktop and mobile: Command Center → Reliability tab
- Legacy persisted
reliabilityview state redirects to Command Center so existing browser sessions land on the new tab container instead of an invalid top-level view.
Features:
- Headline 7-day in-review success rate (derived as
1 - inReviewFailureRate7d) with color thresholds: success for≥95%, warning for≥90%, error below90%; shows Insufficient data when the metric is null - Per-day in-review flow table showing tasks that entered in-review versus tasks bounced back to in-progress
- Entered vs bounced trend line chart in the In-review flow card, using the same per-day rows as the table and respecting the Show/Hide empty days filter
- In-review duration percentiles (P50 and P95) plus sample count
- Merge-attempt distribution stats including mean, max, and histogram buckets
- Attempts distribution pie chart in the Merge attempts card, visualizing the merge-attempt histogram buckets and showing
No merge attempt datawhen no histogram data exists - Auto-refreshes every 60 seconds
For the backing API and windowDays query parameter, see architecture.md.
Dev Server View
Dev Server view manages detected dev server commands, preview URLs, and live logs for local development.
Available when
experimentalFeatures.devServerViewis enabled (devServeris treated as a legacy alias).
Navigation:
- Desktop/tablet: Left sidebar → Dev Server when the Dev Server view is enabled
- Mobile: More sheet → Dev Server
Features:
- Detect candidate dev server commands and choose which command/session to run
- Pick an executing task to run the dev server against that task's worktree and preview its in-progress work; the selected task's descriptor is shown so you know what you're previewing.
- Start, stop, and restart the current server session
- Manage preview URLs with embedded preview and Open in new tab fallback
- Tail live logs, load older history, and refresh session status
- When Dev Server is hosted in a very narrow right sidebar, open the preview from the compact Open preview launcher; the modal keeps preview actions available while configuration and logs stay usable in the sidebar.
For module-level behavior and API surfaces, see Dev Server modules.
Stash Recovery in Git Manager
Stash Recovery helps recover orphaned merger autostashes (fusion-merger-autostash:*) left behind when merge restore could not fully complete. It now lives as the Recovery tab in Git Manager and is reached through Git Manager on desktop/tablet and mobile.
Navigation:
- On desktop/tablet, open the right dock, select Git Manager, then select Recovery. Expected outcome: the Recovery section opens inside the embedded Git Manager panel; expanding Git Manager keeps the same section available in the modal.
- On mobile, open the More sheet, select Git Manager, then select Recovery from the horizontal section-tab strip. Expected outcome: the Recovery section opens in the mobile Git Manager modal with the tab strip still scrollable.
Features:
- Lists orphaned stash entries grouped by source task ID (or Unknown source when unavailable)
- Surfaces provenance metadata from recovery events (
sourcePhase,detectedByTaskId,detectedAt) to show where/when leftovers were captured and surfaced - Inspect diff output for any orphaned stash before taking action
- Apply a stash to recover changes, or drop a stash with confirmation to permanently remove it
For API endpoints, see architecture.md.
Plugin Manager
Plugin management lives in Settings → Plugins → Fusion Plugins.
Features:
- Install bundled plugins or custom path-based plugins
- Enable/disable plugins, reload active plugins, and uninstall plugins
- Inspect plugin runtime state and transition feedback
- Edit and save plugin-defined settings schemas from the same panel
For full plugin lifecycle workflows (discovery, install, enable/disable, configure, update, uninstall, troubleshooting), see Plugin Management. For plugin-related settings and experimental toggles, see Settings reference.
Pi Extensions Manager
Pi extension management lives in Settings → Plugins → Pi Extensions.
Features:
- Add/remove Pi package sources (npm, git, or local)
- Reinstall the Fusion Pi package/skill bundle
- Enable/disable discovered extensions
- Manage extension, skill, prompt, and theme path lists in one place
For related global/project configuration behavior, see Settings reference.
Task Detail Modal
Inspect task definition, logs, review feedback, comments, artifacts, workflow outcomes, model overrides, and task routing from a single modal.
- Editable tasks with descriptions show Summarize as title beside the read-mode title; it asks AI to generate a concise title from the description and saves it without opening the edit form.
- The top-level Chat tab appears first for active task details and is the default landing tab for non-
donetasks. It uses the task's effective planning model, but opening the tab is lookup-only: Fusion creates the task-scoped planner chat only after you send a composer message, starter prompt, or planner-question answer. Once a user message exists, the resumable planner chat can appear in the global Chat list; interacted chats are kept when the task reachesdoneand removed when the task is archived. Each send includes bounded server-built task context so the planner can answer current status, progress, recent activity, dependency, and task definition questions. It shows starter prompts for common planning questions, can render structured planner questions, and converts only explicit operator steering intent through the scoped steering tool. The composer stays pinned while the transcript, loading, error, starter, history, and streaming states scroll internally; on mobile/narrow task detail, the default focused Chat layout hides nonessential title/metadata/tab/action rows until you collapse it from the in-view expand control. - The Activity → Live, Feed, and Raw Logs segments remain immediately after Chat and share an expand/collapse control that lets the active Activity segment fill the task-detail modal, then restores the normal header, tabs, and action footer when collapsed.
- The Summary tab appears for
donetasks and remains their default landing tab. It shows the recorded completion summary, changed-file/merge stats when available, completed steps, workflow results, retry counts, and a token usage & cost section broken down by model from the already-loaded task detail; unpriced models show cost as unavailable rather than$0. - Task-detail Activity steering comments are persisted as user comments/steering guidance and surfaced to every relevant agent lane: live executor sessions receive steering injection, while planner, reviewer (spec/plan/code), and merger agents (standard and clean-room AI merge/review) receive the latest user comments in their next prompt/pass.
- The priority chip in task metadata is an inline picker: you can change priority directly without entering full edit mode.
- Execution mode has a read-mode inline lightning-bolt toggle for Fast mode on/off without opening the full edit form.
- These two metadata controls share matched sizing/alignment in read mode (including mobile wrapping) so they behave like a single polished control group.
- Task metadata keeps priority, execution mode, provenance, optional workflow identity, optional PR context, and compact
Created/Updatedtimestamps in one wrapping row across desktop and mobile widths; recent timestamps render as relative time (just now,Xm,Xh,Xd) and older values switch to short month/day dates. - The Actions menu exposes Pause / Unpause for eligible non-terminal tasks, including tasks assigned to agents. If a task was paused by an agent, the Paused by agent note is informational; users can still unpause it manually from the same menu. On mobile task popups, tapping an Actions item applies the selected action once and closes the menu.
- After delete confirmations are complete, Task Detail closes immediately while the delete request finishes in the background; success and error outcomes still appear as toasts.
- Eligible existing tasks (triage, todo, in-progress, in-review) expose a GitHub tracking section directly in Task Detail, even when tracking is currently disabled.
- The GitHub tracking section now defaults to a compact summary row; use the disclosure arrow to expand linked-issue details plus tracking edit controls.
- Tasks linked to GitLab imports show a separate GitLab tracking section for GitLab.com and self-managed project issues, group issues, and merge requests. The section provides Open in GitLab and local Unlink GitLab item actions; lifecycle side effects run in the background and appear as task-log entries such as
Posted GitLab tracking comment,Closed linked GitLab source issue, orSkipped closing GitLab merge request. - GitLab stale state means Fusion is displaying the last persisted GitLab metadata after a sync/import refresh could not confirm a newer state; no GitLab token or secret is stored on the task.
- GitLab comment and close/reopen actions use the configured GitLab REST API base URL for GitLab.com or self-managed instances. Group-imported issues are updated only when Fusion has the concrete project identity plus IID, and merge requests are closed/reopened only for GitLab-supported states; Fusion never auto-merges a GitLab merge request.
- Backstop reconciliation runs every 15 minutes to close tracked GitHub issues for soft-deleted and archived tasks even after restart; the sweep is paginated so large archive backlogs are eventually drained.
- In shared task edit/create forms, GitHub Tracking appears at the bottom of More options, after Workflow Steps.
- From this section you can explicitly enable/disable tracking and manage a per-task repo override (
owner/repo). Clearing the override savesnulland falls back to project/global defaults. - In
in-review, pull-request controls/status (including stall badges) are in a dedicated Pull Request tab instead of the Definition tab. - In the task detail Pull Request tab, PR numbers open the linked pull request on GitHub when a PR URL is available.
- Task Detail and list split-pane PR affordances follow the live project auto-merge setting: when auto-merge is off, manual Create PR / merge actions are shown; when it is on, the tab shows the automatic auto-merge hint unless a per-task override changes the effective behavior.
- A PR created or linked with Create PR is treated as a manual handoff: while it remains open, Fusion excludes that task from automatic merge processing so the human can merge via GitHub or Merge PR.
- The Workflow tab resolves the effective workflow for both explicitly selected and default-inherited tasks. Its overview, expandable graph preview, configured step details, and live step results refresh when switching tasks or projects without showing stale rows from the previous task.
- The Create Pull Request modal now offers in-app remediation for every blocking preflight check. If
branchOnRemoteis false, use Push branch to remote and Fusion will publishfusion/<task-id-lower>tooriginand refresh preflight. IfconflictsWithBaseis true, use Resolve conflicts with AI and Fusion will use an AI coding agent to resolve merge markers on the task branch, commit and push real merge changes, or report success without an empty commit when the selected base is already merged; preflight then refreshes so normal PR creation can continue once all checks pass. - The Create Pull Request modal is a floating pop-out like Plan Mission, New Task, and Automations: drag its header or resize from desktop edges/corners, while mobile keeps the full-screen dialog layout. Close it with X, Cancel, or Escape; stray clicks inside or outside the floating shell do not dismiss it.
- The modal shell renders immediately: preflight checks and PR options load independently of AI-generated title/body metadata, so slow AI suggestions no longer block base-branch selection, diagnostics, or manual PR authoring. The Diff & commit preview section starts collapsed and can be expanded on demand.
- The Body section includes a Preview/Edit toggle so authors can review the rendered markdown description before creating the PR without changing the submitted raw body text.
- AI title/body generation is bounded to 60 seconds on the server and 15 seconds in the dialog, and is canceled if the request disconnects; while it runs, the title and body fields show a skeleton loading state and are temporarily disabled, then resolve into generated content or deterministic task-based fallback content on timeout/cancel.
- Project Settings → Project Models includes optional PR title prompt guidance and PR description prompt guidance fields. Blank fields preserve the default Create PR metadata prompt; populated fields append guidance for the generated title or body sections.
- The Artifacts tab combines task documents written by agents or users with task-scoped registered media artifacts. The gallery uses thumbnail-first image/video cards, image and video previews can expand into a dismissible full-size lightbox, video and audio use native controls, document artifacts show text previews, and generic artifacts open through their media URL.
- The Review tab is separate from Comments: Review shows actionable PR/reviewer feedback and same-task revision controls, while Comments remains the general collaboration thread.
- When a linked PR has actionable comments or a changes-requested decision, Address PR feedback appears in the Review tab and on the task card; it starts a same-task AI session to evaluate open PR threads, fix valid issues, reply, and resolve them.
- Review comments hide GitHub template HTML comments in both Markdown and Plain modes, show author avatars or User/Bot fallbacks, label Human vs Bot/agent authors, and include All/Human/Bot filtering.
- Request revision in Review resumes work on the same task ID (no refinement task):
in-progresstasks get steering injection, whilein-reviewtasks are moved back toin-progressfor the same branch/worktree revision pass. The selected feedback can come from either PR review data or reviewer-agent feedback shown in the tab. - Review supports a manual Refresh action in-place: PR mode pulls latest GitHub review state/decision, while direct mode rehydrates reviewer-agent feedback from task agent logs (no GitHub call).
- For shared
branch_groups(tasks withbranchContext.groupId), PR merge mode opens and tracks one group-level PR from the group integration branch to the project default branch; member tasks share that PR state. - In direct/non-PR auto-merge mode, Review renders normalized reviewer-agent feedback (verdict/step/timestamp/detail) with dedicated loading/error/empty states; it does not require users to read raw agent logs.
Legacy auto-merge stamp cleanup
Settings → Merge includes Legacy auto-merge stamp cleanup for operators auditing tasks that inherited historical in-review autoMerge stamps. The panel loads a dry-run candidate list, shows task IDs and current columns, and only reveals the destructive Clear legacy stamps action when candidates exist. Applying the cleanup requires the browser confirmation prompt, calls the maintenance apply endpoint, and then refreshes the dry-run list so cleared tasks disappear.
Use this panel when upgrading a project with pre-FN-6245/FN-6277 in-review rows before relying on per-task auto-merge overrides. It only targets stamps tagged as legacy provenance; explicit user overrides remain intact.
Executor footer engine controls
The global AI engine stop/start control and triage pause/resume control live in the executor footer status bar rather than the header. Select the small engine-controls button beside the executor state badge, or select the state text such as Running, to open the footer popover. The popover includes Stop AI engine / Start AI engine, Pause triage / Resume scheduling, and live scheduler sliders for max concurrent tasks, max triage concurrency, and max worktrees. On mobile, narrow tablets, and tablet landscape, the same controls open as a full-width bottom panel above the executor footer and mobile navigation so the close button and sliders remain reachable. Use the visible Close engine controls X button, Escape, or outside-click to dismiss it. The global and current-project concurrency sliders also show how many agents are running, including actively-triaging planners (triage + planning, not paused), and a dot on the slider track for current use. The dot uses absolute utilization (running / cap) rather than range-slider coordinates and shares the same track/thumb geometry as Command Center sliders, so one running agent renders above the start of the track, zero stays at the start, and over-cap usage clamps to the end. Changed concurrency slider values ask for confirmation after the value settles. Confirming saves the global cap through /api/global-concurrency and project caps through /api/settings; cancel, backdrop dismissal, Escape, close, outside-click, or unmount reverts unconfirmed slider edits without saving. Multiple changed project sliders within one debounce window are summarized in one confirmation dialog, matching Command Center behavior.
Brief, single-poll executor stats fetch blips keep showing the last good footer stats instead of flashing Connecting…. Routine executor stats heartbeats also keep the populated footer mounted after initial load, so an open engine/concurrency popover stays open while counts refresh. The footer only switches to Connecting… for sustained suspension-like stats failures, or to an explicit error state for non-transient failures.
Engine status banner
When a project dashboard is open but no project engine is connected, Fusion shows a sticky Engine disconnected banner above the project content. This covers paused projects, failed or still-starting project engines, delayed reconciliation, and dashboard-only/dev launches where the UI is available before an engine manager is attached.
If the server can start the current project engine, use Start engine in the banner to resume a paused project or call the project engine startup path without reloading the dashboard. While the start request is in flight the button is disabled and shows the starting state so repeated clicks cannot create duplicate startup attempts. The banner disappears as soon as the status endpoint reports the project engine is connected.
If the dashboard is running without engine management, the banner stays informational and disables the start action. Start the full server with fn serve to enable one-click engine startup and live task execution.
Identifying high-impact blockers
Use blocker fan-out signals on task cards and in the footer status bar to spot blockers with high downstream impact:
Blocks Ncounts active downstream dependents intriage,todo,in-progress, orin-review.- FN-3942 immediate signal: blockers with at least 5 active
tododependents (activeTodoCount >= 5) are marked High fan-out. - FN-3954 escalation signal: a high-fan-out blocker is upgraded to Escalated only after it remains in
in-progress/in-reviewpaststaleHighFanoutBlockerAgeThresholdMs(age source:columnMovedAt ?? updatedAt). - Escalation payload surfaced in UI includes blocker ID, active todo downstream count, total active downstream count, and computed blocking age.
- Done and archived downstream tasks remain visible for debugging context but do not count toward the todo threshold.
- The badge tooltip shows active totals and, when escalated, the computed blocking age context.
(stale)markers mean the dependent is blocked throughblockedByand matches stale conditions thatclearStaleBlockedByself-healing should clear automatically.- Stale
dependencies[]links are shown for awareness but are not auto-cleared byclearStaleBlockedBy. - The executor footer summarizes the top escalated blocker (deterministic rank: highest todo fan-out, then highest active total, then oldest age, then stable task ID).
Recommended workflow: ordinary chains stay as Blocks N so noise stays low, high-fan-out blockers stand out immediately, and only long-lived high-impact blockers trigger explicit escalation.
Activity → Raw Logs view
The Activity tab is the first task-detail tab by default and presents a segmented control for Live, Feed, and Raw Logs. Live contains the live, chat-styled transcript of task agent output. Consecutive entries are grouped by role and labeled as Planner, Executor, Reviewer, or Merger; legacy log rows without an agent role use the neutral Agent fallback. Agent group headers and user message headers show a small muted relative timestamp (for example, “just now”, “1m ago”, or “2h ago”) based on the transcript timestamp, while agent group metadata still includes the entry count. Consecutive text/message chunks inside a role group render as one continuous markdown bubble, while consecutive tool/tool-result/tool-error rows collapse into one expandable, compact tool-call summary that stays collapsed by default and mirrors regular Chat's dense treatment; the summary stays single-line/ellipsis-friendly on desktop and mobile, counts tool invocations, lists deduped tool names with overflow, and shows an error count when failures are present, while the expanded body pairs each call with its result or error in dense entry cards. Thinking entries render in a collapsible block that starts expanded. The transcript opens at the latest output whenever the tab loads or becomes active, then follows new live output when you are already near the bottom while preserving your scroll position when you review older messages. When older task-agent history exists, scrolling to the top or selecting Load previous messages prepends earlier transcript entries without moving the message you were reading. When you scroll away from the bottom of a populated transcript, a sticky Latest button appears inside the transcript so you can jump back to the newest message and resume live follow. For non-done tasks, the Activity Live composer sends typed guidance through the same steering path used by comments, including active planning/triage, in-progress, and in-review sessions, plus live CLI-agent sessions reported by the session bridge; an in-review Activity Live message or Comments-tab task comment re-engages an executor unless an open PR blocks moving the task back, and other messages are still saved as queued guidance when no session is currently live. Feed and Raw Logs do not show the composer. On a done task, the same composer starts a refinement task using the typed text as feedback and shows a success toast with the new task ID, while the current task detail modal remains on the completed task. The task-detail Activity Live segment keeps the composer pinned and visible on mobile and desktop while the transcript scrolls internally; its textarea placeholder reads “Steer the currently executing agent” for steering mode and switches to refinement copy for completed tasks, with the same inline, icon-only send affordance to the right of the input at every breakpoint. In the composer, plain Enter sends, Shift+Enter inserts a newline, and Cmd/Ctrl+Enter remains a supported send shortcut.
The top-level Chat tab opens the planner-model conversation for the same task instead of posting steering comments. It appears after Activity by default, or before Activity when Settings → Appearance → Open task details with Chat first is enabled. Each send includes server-built, bounded context for the task id, status/column/progress/current step, dependencies, recent activity/comment excerpts, prompt/plan content, and available source/review state; unavailable sections are labeled so the planner states uncertainty rather than inventing execution evidence. Opening the tab with no existing history does not create a database chat row; when no planner-chat history is found, Chat shows a guided empty state with starter prompts for recent activity, current status/blockers, next best action, and plan/definition review. Selecting a starter creates/resumes the planner chat and sends that prompt as an ordinary chat message through the task-context-aware planner-chat composer/stream path, including for completed tasks. On live tasks, clear bounded implementation-change requests are routed to task steering; on done tasks, clear follow-up implementation or improvement requests are routed through a task-scoped planner refinement tool that calls the same refinement creation path as the completed-task Activity composer. The starter prompts disappear while history is loading or after conversation history exists, so Activity Live, Feed, Raw Logs, and the steering/refinement composer remain separate. Planner Chat uses the same standard chat bubble, markdown/plain assistant rendering, thinking details, tool-call/question cards, and mobile first-tap send/stop affordance as the main Chat view while keeping task-scoped planner sessions separate. Planner Chat defaults to focused mode, keeps its composer visible at the bottom while only the transcript scrolls, and on narrow/mobile task-detail layouts collapses nonessential rows above the chat until the user selects the Chat collapse control.
The Raw Logs segment is designed for debugging long-running and tool-heavy sessions, while legacy links that requested the former top-level Logs tab land on Activity → Feed:
- Full
thinking,tool_result, andtool_errorpayloads are shown without entry-content truncation. - Raw tool output is rendered as multiline blocks, preserving line breaks and indentation.
- The Feed and Raw Logs segments show loading indicators while their first async history/detail request is pending, so empty states only appear after the relevant fetch completes.
- The initial load fetches a recent page, then Load More progressively prepends older history.
- Live streaming appends new entries in chronological order while preserving your scroll position when loading older pages.
- The Markdown / Plain toggle lets you switch between formatted markdown and literal/raw text rendering.
- The Tools: On/Off toggle shows or hides tool-call rows (
tool,tool_result,tool_error) so you can focus on narrative/thinking output when needed. - Both display preferences persist across sessions via local storage (
fn-agent-log-markdownandfn-agent-log-tool-output).
The Routing tab shows:
- effective node
- routing source (task override vs project default vs local)
- unavailable-node policy value
- per-task node override controls (locked while task is active)
Project-wide routing defaults are configured in Settings → Node Routing.

Node Dashboard
The Node Dashboard provides a mesh view of connected Fusion nodes. Each node can be a local instance or a remote headless node (fn serve).
Navigation:
- Desktop: Header node controls / overflow entry
- Mobile:
MobileNavBar→ More sheet → Nodes (shown only whenexperimentalFeatures.nodesViewis enabled)

Local/Remote Node Switching
When remote nodes are available, the dashboard header displays a node status indicator:
- Local mode — Shows a green "Local" badge, indicating the dashboard is connected to the local Fusion instance
- Remote mode — Shows the remote node name with its connection status (online/offline/connecting)
Click the chevron next to the status indicator to open the node selector dropdown:
- Local — Switch back to viewing the local Fusion instance
- Remote nodes — Select a remote node to view its tasks, projects, and status
Remote Node Onboarding Discovery
When adding a remote node in the Nodes view, onboarding now discovers projects directly from the target node before the node is registered.
- Enter the remote URL (and API key when required)
- Click Discover Remote Projects
- Fusion calls the remote node's
/api/projectsendpoint and shows discovered projects (name,path,status) - For selected local projects, Fusion only auto-prefills a node path when there is exactly one discovered project with the same name
- If discovery fails, onboarding shows an inline error and does not prefill remote mappings for that attempt
- If discovery succeeds with zero projects, onboarding shows an explicit empty state
This keeps remote path mappings anchored to remote-authoritative data instead of local guesses.
How Node Switching Works
- The node selector appears in the header when remote nodes are registered in the mesh
- Selecting a remote node routes all API calls through the proxy endpoint (
/api/proxy/:nodeId/...) - Task data (projects, tasks) is fetched from the remote node and displayed in the dashboard
- SSE events from the remote node are streamed via the proxy and update the dashboard in real-time
- Selecting "Local" returns to the local Fusion instance with full local data
Benefits of Remote Node Viewing
- Monitor task progress across distributed teams
- View task status on remote headless nodes without direct SSH access
- Compare project health across multiple Fusion instances
- Stay informed about remote agent activity and task completion
Node Status Indicators
| Status | Color | Meaning |
|---|---|---|
| Online | Green | Node is connected and responsive |
| Offline | Red | Node is unreachable or shut down |
| Connecting | Yellow (pulsing) | Connection attempt in progress |
Project availability and path visibility
Node and project surfaces now use per-node project mappings (nodeMappings) instead of a single project.nodeId assumption.
- Node cards / counts include only projects with an
available: truemapping for that node. - Node Details modal lists one row per project available on the selected node and shows:
- project name
- project ID
- configured path for that node
- Project node filter in the Projects view is built from available mappings and uses canonical node-name resolution (
Node.name→ mapping name → source node name → node ID). - Project cards show node availability as compact
Node → /pathrows:- up to 3 rows inline
+N moresummary when additional mappings exist- single-node projects still show the configured path clearly
- Mappings marked
available: falseare excluded from node counts, node filter options, node detail project rows, and project-card availability summaries.
Persistence
The selected node persists across browser sessions via localStorage. If the selected remote node is unregistered, the dashboard automatically falls back to local mode.
Native shell connection flow
If you use Fusion from a native shell (mobile app or desktop shell in remote mode), dashboard startup is gated by shell onboarding until a connection is selected.
For the canonical workflow (first-run onboarding, QR/manual setup, saved profiles, and desktop local/remote handoff), see Native Shell Connection Guide.
Remote Access (Settings)
Dashboard remote controls live in Settings → Remote Access.
From this section, operators can:
- Configure Tailscale and Cloudflare provider fields
- Save provider options such as Tailscale Accept routes and Remember last running state with the main Settings Save button; starting a tunnel is not required for these settings to persist.
- Activate the current provider
- Start/stop tunnel lifecycle manually
- Generate login URLs / QR payloads using persistent or short-lived token mode
For setup prerequisites, security caveats for tokenized URLs/QR links, and troubleshooting, use the canonical Remote Access runbook.
Skills API
The Skills view now supports the full browse-and-install loop for skills.sh entries: use Skills Catalog to search the catalog, click Install on any card with a source repository, and the dashboard will run the same installer as the CLI (npx skills add <owner/repo> -y -a pi, with --skill <slug> when applicable). On success, the view refreshes Discovered Skills immediately so the newly installed skill appears without a page reload.
The Skills API provides endpoints for managing execution skills. Skills are toggled via project-scoped settings in .fusion/settings.json.

GET /api/skills/discovered
List all discovered skills with their enabled state.
Response: 200 OK
{
"skills": [
{
"id": "npm%3A%40example%2Fskill::skills/foo/SKILL.md",
"name": "foo/SKILL.md",
"path": "/path/to/skills/foo/SKILL.md",
"relativePath": "skills/foo/SKILL.md",
"enabled": true,
"metadata": {
"source": "npm:@example/skill",
"scope": "project",
"origin": "package"
}
}
]
}
Skill ID Format: encodeURIComponent(metadata.source) + "::" + relativePath
- Top-level skills use
source: "*" - Package skills use the package source identifier
Error Response: 404 Not Found
{
"error": "Skills adapter not configured",
"code": "adapter_not_configured"
}
GET /api/skills/:id/content
Fetch a skill's SKILL.md content and supplementary file metadata.
Response: 200 OK
{
"content": {
"name": "foo/SKILL.md",
"skillMd": "# Foo Skill\n...",
"files": [
{
"name": "examples",
"relativePath": "skills/foo/examples",
"type": "directory"
},
{
"name": "example.ts",
"relativePath": "skills/foo/examples/example.ts",
"type": "file"
}
]
}
}
Error Responses:
400 Bad Request— invalid encoded skill ID (code: "invalid_skill_id")404 Not Found— skill not found (code: "skill_not_found") or adapter missing (code: "adapter_not_configured")
PATCH /api/skills/execution
Toggle a skill's enabled/disabled state.
Request Body:
{
"skillId": "npm%3A%40example%2Fskill::skills/foo/SKILL.md",
"enabled": true
}
Response: 200 OK
{
"success": true,
"skillId": "npm%3A%40example%2Fskill::skills/foo/SKILL.md",
"enabled": true,
"persistence": {
"scope": "project",
"targetFile": "/path/to/.fusion/settings.json",
"settingsPath": "packages[].skills",
"pattern": "+skills/foo/SKILL.md"
}
}
Toggle Semantics:
- Top-level skills (
origin: "top-level"): Mutatesettings.skills- Enable: ensures
+<relativePath>exists, removes-<relativePath> - Disable: ensures
-<relativePath>exists, removes+<relativePath>
- Enable: ensures
- Package skills (
origin: "package"): Mutatesettings.packages[].skillsfor the matchingmetadata.source- If the package entry is a string, it's converted to an object
{ source: <same>, skills: [] } - Other package fields (
extensions,prompts,themes) are preserved
- If the package entry is a string, it's converted to an object
Error Responses:
400 Bad Request— Invalid request body{ "error": "skillId is required", "code": "invalid_body" }404 Not Found— Adapter not configured{ "error": "Skills adapter not configured", "code": "adapter_not_configured" }
POST /api/skills/install
Install a catalog skill into the current project.
Request Body:
{
"source": "owner/repo",
"skill": "example-skill"
}
Behavior:
- Validates
sourceinowner/repoformat before spawning anything - Runs
npx skills add <source> -y -a pi - Appends
--skill <skill>whenskillis provided - Uses the scoped project root as
cwd, so installed files land in the current project's skill directories
Response: 200 OK
{
"success": true
}
Error Responses:
400 Bad Request— missing source{ "error": "source is required", "code": "invalid_body" }400 Bad Request— malformed source{ "error": "Invalid source format. Use owner/repo.", "code": "invalid_source" }404 Not Found— adapter not configured{ "error": "Skills adapter not configured", "code": "adapter_not_configured" }502 Bad Gateway— installer failed/timed out/could not start{ "error": "installer failed", "code": "install_failed" }
GET /api/skills/catalog
Fetch the skills.sh catalog with optional authentication.
Query Parameters:
limit(optional): Number of results (default 20, max 100)q(optional): Search query string
Response: 200 OK
{
"entries": [
{
"id": "example-skill",
"slug": "example-skill",
"name": "Example Skill",
"description": "An example skill",
"tags": ["utility"],
"installs": 100,
"installation": {
"installed": true,
"matchingSkillIds": ["npm%3A%40example%2Fskill::skills/example/SKILL.md"],
"matchingPaths": ["skills/example/SKILL.md"]
}
}
],
"auth": {
"mode": "unauthenticated",
"tokenPresent": false,
"fallbackUsed": false
}
}
Authentication Flow:
- If
SKILLS_SH_TOKENenv var is present, use authenticated request - If authenticated request returns
400/401/403, retry without authentication (fallback mode) - If no token, use unauthenticated request directly
Unauthenticated Short-Query Behavior:
- Public
skills.sh /api/searchrequests are only sent whenqhas at least 2 characters - For omitted, empty, or 1-character queries, the API returns
200with{ entries: [] } - This applies both to direct unauthenticated mode and authenticated-to-unauthenticated fallback mode, preventing upstream
400 Bad Requestresponses during initial load
Auth Mode Values:
authenticated— Request made with tokenunauthenticated— Request made without token (no token available)fallback-unauthenticated— Initial authenticated request failed with 401/403, retried without token
Error Response: 502 Bad Gateway
{
"error": "Upstream request timed out",
"code": "upstream_timeout"
}
Possible error codes:
upstream_timeout— Request timed outupstream_http_error— Upstream returned an error statusupstream_invalid_payload— Upstream returned invalid response format
Agent Import
The Agent Import feature allows you to import agents from Agent Companies packages. When importing agents from companies.sh or local directories, Fusion now also persists any skill definitions from the package.
Launch Points
You can open Agent Import from:
- Agents view → Controls popup → Import
- Agent Detail header → Import (opens directly to the companies.sh browse catalog)
How It Works
-
Select Source: Choose to import from:
- The companies.sh catalog (browse and search)
- A local directory containing AGENTS.md files
- A single manifest file (.md or .txt)
- Paste manifest content directly
-
Preview: Review the agents and skills that will be imported before confirming
-
Import: Upon confirmation:
- Agents are created in Fusion's agent store
- Skills are persisted to
skills/imported/{companySlug}/{skillSlug}/SKILL.md - Each skill's
SKILL.mdcontains YAML frontmatter with skill metadata and the instruction body
Skill Persistence
Skills from Agent Companies packages are persisted to the project-local skills directory:
{projectRoot}/
skills/
imported/
{companySlug}/ # slugified company name or "unknown-company"
{skillSlug}/ # slugified skill name
SKILL.md # skill manifest with frontmatter + instructions
Collision Handling: If a SKILL.md file already exists at the target path, the import skips that skill (does not overwrite). This prevents accidental data loss.
Path Safety: All path segments are slugified to prevent directory traversal attacks. Special characters are removed and whitespace is normalized to hyphens.
Import Result
The import result shows:
Agents:
- Number of agents created
- Number of agents skipped (already exist)
- Number of errors (import failures)
Skills:
- Number of skills imported (written to disk)
- Number of skills skipped (already exist)
- Number of skill errors (write failures)
API Response
The POST /api/agents/import endpoint returns skill import results:
{
"companyName": "Example Co",
"companySlug": "example-co",
"created": [{ "id": "agent-1", "name": "CEO" }],
"skipped": [],
"errors": [],
"skillsCount": 3,
"skills": {
"imported": [
{ "name": "review", "path": "skills/imported/example-co/review/SKILL.md" },
{ "name": "strategy", "path": "skills/imported/example-co/strategy/SKILL.md" }
],
"skipped": [],
"errors": []
}
}
The skills object contains detailed import outcomes for each skill from the package.
Styling Guide
The dashboard's CSS is split into a global stylesheet (packages/dashboard/app/styles.css) and per-component files (packages/dashboard/app/components/ComponentName.css). Each ComponentName.tsx imports its stylesheet at the top.
Rule: New CSS for a component goes in app/components/ComponentName.css, NOT styles.css. Only design tokens, primitives (.btn, .card, .modal, .form-input), and cross-component @media overrides belong in the global file.
PR tab note: PrPanel cards use tokenized .pr-card grid spacing (padding + gap) and boxed token-based hint callouts for empty/loading states. Manual PR merges now show in-progress feedback (Merging… button state + status hint) until the merge call resolves.
The index.html shell is templated server-side: the server injects a per-user <link rel="modulepreload"> for the last-used taskView chunk, sourced from Vite's dist/client/.vite/manifest.json and kb:<projectId>:kb-dashboard-task-view in localStorage.
Design tokens
styles.css is the source of truth for tokens (--space-*, --radius-*, --shadow-*, --duration-*, --transition-*, --font-*, --header-height, --mobile-nav-height, --standalone-bottom-gap, --overlay-padding-top) and color variables (--bg, --surface, --card, --text, --text-muted, status colors --triage/--todo/--in-progress/--in-review/--done, semantic --color-success/--color-error/--color-warning/--color-info, status backgrounds --status-*-bg).
Always reference tokens. Never hardcode pixels, hex, or rgba() in component CSS — global/theme token CSS is also covered by global-theme-css-no-raw-rgba.test.ts, so raw rgba() belongs only in explicit var(--token, rgba(...)) fallbacks. For translucent backgrounds use color-mix(in srgb, var(--color) X%, transparent), not rgba().
Command Center chart surfaces are a stricter token-only zone: CommandCenter.css, areas/areas.css, and charts/charts.css should avoid raw color fallbacks and hardcoded dimensions in component rules, keep secondary copy on --text-muted, use canonical --accent / --text for generic accent and primary text styling, use --duration-* for animation durations, and encode mobile chart invariants with shared classes rather than one-off area styles. Hand-rolled chart primitives cycle through the existing semantic palette (--accent, workflow status tokens, and success/warning/error tokens) rather than adding one-off chart color aliases. The undefined --color-accent / --text-primary aliases are forbidden under components/command-center/** and guarded by command-center-css-token-canonicalization.test.ts.
Non-Command-Center dashboard CSS uses --text as the canonical primary text token. The undefined --text-primary alias is forbidden outside components/command-center/** and guarded by packages/dashboard/app/__tests__/text-token-canonicalization.test.ts.
Theme system
Dark/light modes via data-theme; 76 color themes via data-color-theme (lazy-loaded from app/public/theme-data.css), including the Shadcn zinc-neutral theme with an orange default highlight/accent, Shadcn Custom (the same base with sanitized per-token color-picker overrides), and its color family: Shadcn Blue/Green/Red/Purple/Pink/Orange/Yellow, Shadcn Mono Red/Blue/Green/Purple/Pink/Orange/Yellow (grayscale surfaces with color-specific accents; legacy shadcn-mono selections migrate to Shadcn Mono Red), Shadcn Black (pure black and white), Shadcn Gray (fully neutral zinc-gray accent), and Shadcn Gray Blue (blue-gray slate neutral surfaces with a muted slate-blue accent). Air is the minimal, borderless, paper-like preset with near-monochrome tokens and CSS-only chrome flattening. Glass Silver preserves the Glass theme's frosted translucent surfaces and transparent modal overlay behavior while using silver and graphite accents instead of purple/pink.
Choose Shadcn variants from Settings → Appearance or from the Command Center Overview theme card; both selectors use the same themeOptions.ts labels and color-chip swatches. The left sidebar active-item highlight and resize accent use the active theme's --accent, so they follow the selected Shadcn accent instead of staying fixed blue.
- Base tokens (
--bg,--surface, etc.) — redefine in:root,[data-theme="light"], and every theme block. - Semantic tokens (
--autopilot-pulse,--event-error-text,--badge-mission-*,--fab-*) —:root+[data-theme="light"]only; no per-color-theme overrides. - Status tokens (
--triage,--todo, etc.) — redefine per theme block.
status-colors-theme.test.ts iterates all theme blocks to catch regressions.
Component classes
Reuse existing primitives from styles.css:
- Buttons:
.btn,.btn-primary,.btn-danger,.btn-warning,.btn-sm,.btn-icon,.btn-icon--active,.btn-badge. All inherit:focus-visiblevia--focus-ring-strongand:activeviatransform: scale(0.97). - Modals:
.modal-overlay[.open],.modal,.modal-lg,.modal-header,.modal-close,.modal-actions,.modal-actions-left/right. Overlay pads top with--overlay-padding-top. Overlay dialogs should render throughcreatePortal(..., document.body)soposition: fixedoverlays escape transformed, contained, or fixed ancestors. Resizable modals usinguseModalResizePersist(...)get a shared bottom-right touch/mouse resize grip on tablet and desktop; mobile sheets stay full-screen and grip-free. - Forms:
.form-group,.input,.select,.checkbox-label,.form-error. Inputs in.form-groupget focus styles automatically. - Cards:
.card,.card-header,.card-id,.card-title,.card-meta,.card-status-badge--{triage,todo,in-progress,in-review,done,archived}. - Utility:
.touch-target(44px min),.visually-hidden.
Don't create parallel button/form variants — add states (:hover, :focus-visible, :active) to the existing primitives.
Small fixed notification cards (for example the first-task GitHub star prompt) should reuse .card, .btn, and .btn-icon, anchor themselves with tokenized position: fixed offsets, and include a mobile @media (max-width: 768px) override so they clear the mobile nav/FAB region.
Mobile responsive
Breakpoints: 768px (primary mobile), 1024px (tablet min-width: 769px and max-width: 1024px), 640px (compact), 480px (xs). Mobile overrides go in @media (max-width: 768px) blocks at the bottom of styles.css after base styles.
Bottom spacing: --mobile-nav-height (44px) + env(safe-area-inset-bottom, 0px) + --standalone-bottom-gap (0/8px PWA). All bottom-positioned mobile elements compose those. When the soft keyboard opens, the mobile nav bar stays pinned to page bottom cross-platform; the executor footer keyboard-collapse pin is iOS-only. On Android (interactive-widget=resizes-content), the footer keeps its stacked position above the nav bar to avoid overlap after keyboard dismiss.
Footer-safe fill layouts: View wrappers that reserve footer/mobile-nav space (for example .project-content) should be flex containers with min-height: 0 / min-width: 0, and child surfaces like .board should use flex: 1 1 auto plus the same min-size guards. Workflow-mode board wrappers (.board-workflow-view → .board-workflow-columns) also keep a definite height: 100%/max-height: 100% chain so the workflow toolbar and columns split the available space on tablet as well as desktop/mobile. This keeps the board/columns stretched between the header and fixed bottom bars across desktop, tablet, and mobile while allowing internal scroll regions to own overflow.
Touch targets: Standing button-freeze directive supersedes per-button touch-target guidance. For non-button elements, primary controls (nav bar, FAB, tab action rows, modal CTAs, list-row tap targets, form controls) must be ≥36px on mobile. Secondary controls inside a card/list-row where the row itself is the tap target stay compact (24–28px or small chips).
Safe area: max(var(--space-md), env(safe-area-inset-left, 0px)) for notch-aware horizontal padding.
Secrets management in Settings
Manage project and global secrets directly inside Settings → Project → Secrets. This section embeds the existing Secrets UI in the settings content panel so you no longer need a footer "Manage secrets" link to leave the modal.
MCP server management in Settings
Manage Model Context Protocol servers from the existing Settings modal; no new top-level dashboard view is introduced. See MCP for the full setup, validation, CLI, import, and export guide.
- Settings → Global → MCP Servers stores global MCP defaults shared by projects.
- Settings → Project → MCP Servers stores project-level MCP settings. Project entries override global servers by matching
name, and a same-named disabled project entry suppresses the inherited global server. The project list marks inherited, overridden, project-local, and disabled-global states so operators can see which scope owns the effective entry. - Supported transports are
stdio,sse, andstreamable-http. The editor shows the transport-specific command, URL, args, env, and header fields. - Sensitive MCP values are secret references only. Environment values, HTTP/SSE header values, and tokens must be selected from or created in Fusion secrets; plaintext values are never persisted into the settings blob.
- Each server row has a Test control that calls the MCP validation API and renders pending, valid, unreachable, or error status inline using the standard status-dot convention and semantic status colors.
- The Discovered on this machine region scans known Claude Desktop, Claude Code, Cursor, Windsurf, and VS Code MCP config paths for the selected scope. Candidates are read-only and inert until the operator clicks Add; sensitive discovered values open the secret-reference editor instead of persisting plaintext.
- The import panel accepts Claude Desktop-style
{ "mcpServers": { ... } }JSON by paste or upload. Imported plaintext sensitive values are converted into Fusion secret references before the settings draft is saved. - The export panel produces Fusion MCP JSON for the active scope and offers copy/download actions.
The MCP sections reuse Settings form/card primitives and include mobile layouts for (max-width: 768px) so validate, discovery, override, disable, import, and export controls remain usable in the Settings sheet.
Lazy-Loaded Heavy Views
These 20 views are lazy-loaded via React.lazy() with <Suspense fallback={null}>. prefetchLazyViews() warms App-level chunks once on mount via requestIdleCallback; AppModals lazy modal imports (SettingsModal, WorkflowNodeEditor, SetupWizardModal) are part of the same inventory. Do not make these eager. The user-facing Artifacts section is still implemented by the DocumentsView component name.
AgentsViewChatViewMemoryViewDevServerViewSecretsViewInsightsViewDocumentsViewSkillsViewResearchViewCommandCenterEvalsViewTodoViewGoalsViewPullRequestViewSetupWizardModalSettingsModalWorkflowNodeEditorPluginManagerPiExtensionsManagerAgentDetailView
Embedded Workflows (_WorkflowEditorView), Import Tasks (_ImportTasksView), Automations (_AutomationsView), and Settings (_SettingsView) reuse existing lazy chunks and are intentionally excluded from the curated count by the underscore-prefixed App const convention.
When adding or removing entries, update packages/dashboard/app/__tests__/lazy-loaded-views-docs.test.ts (expected set + count).
CSS testing
Use packages/dashboard/app/test/cssFixture.ts:
import { loadAllAppCss, loadAllAppCssBaseOnly } from "../test/cssFixture";
const allCss = await loadAllAppCss(); // styles.css + all component .css
const baseOnly = await loadAllAppCssBaseOnly(); // strips @media/@supports
Never directly readFileSync('../styles.css') — an ESLint rule (no-restricted-syntax in eslint.config.mjs) bans this and points at cssFixture.ts. vitest.config.ts has test.css: { include: [/.+/] } so component CSS imports inject into jsdom for getComputedStyle assertions.
File browser editor & autosize textarea
FileEditor.tsxis CodeMirror 6-only (no<textarea>fallback). Language resolution:packages/dashboard/app/utils/codemirror-language.ts.- For chat-style composer fields use
packages/dashboard/app/hooks/useAutosizeTextarea.ts. Pattern:height = "auto"then clampscrollHeightto min/max inuseLayoutEffect. Pair withresize: none; keepoverflow-y: hiddenwhile under the max-height cap and switch tooverflow-y: autoonly after content exceeds the cap.
File-path links
Reuse packages/dashboard/app/utils/filePathLinkify.tsx and FileBrowserContext. Wrap plain text with linkifyFilePaths(...), mixed JSX with linkifyReactChildren(...). Mount under FileBrowserProvider and route clicks through its openFile(path, { workspace?, line?, col? }).
Common pitfalls
--surface-hoverundefined — reference with a fallback (var(--surface-hover, rgba(0,0,0,0.03))) or define explicitly.- BEM specificity — when a container state class and an element modifier target the same node, the container can win. Use
:not(.modifier)to scope. - CSS
@mediadetection — track brace depth to confirm a rule is mobile-scoped; don't scan backwards for the nearest@media. Many components are global even if visually mobile-only. - Mobile board scroll-snap (FN-001) —
scroll-snap-type: x mandatoryon mobile.boardcauses iOS Safari to compress the viewport when switching from ListView. Usex proximity+overflow-anchor: none. lucide-reacticon adds — updatevi.mock("lucide-react")test mocks immediately; missing exports cascade..spinis global — don't redefine the generic spin keyframes in component CSS.- Animation durations use
--duration-*, never--transition-*— transition tokens carry aduration easingpair; substituting one into ananimationshorthand that names its own easing (or intocalc()) is invalid at computed-value time and silently resolves the whole declaration toanimation: none. Enforced byanimation-duration-tokens.css.test.ts; seedocs/solutions/ui-bugs/css-animation-frozen-by-transition-token-shape-mismatch.md.
Integration Branch Push to Origin
The merge-advance notice includes an explicit Push to origin action for the dynamically resolved integration branch.
- The branch name is resolved from project settings, then
origin/HEAD, then fallback; UI copy and API behavior must remain dynamic. - Push status probes compute ahead/behind counts and disable push when there is no
origin, no upstream tracking ref, the branch is not ahead, or a Fusion merge lock is active. - The mutating route performs a TOCTOU merge-lock recheck immediately before building push argv.
- Standard push is
git push origin refs/heads/<branch>:refs/heads/<branch>with no plain--forcepath. - Advanced mode enables opt-in
--force-with-lease=refs/heads/<branch>:<localSha>only. - Non-fast-forward and lease-stale failures surface actionable messaging with Smart Pull.
- Every attempt records
mutationType: "push:origin"run-audit metadata:integrationBranch,remote,localSha,remoteSha,aheadCount,behindCount,forceWithLease,outcome, optionalstderrPreview, anddurationMs. - Push remains explicit user authorization only through dashboard HTTP routes (no scheduler/heartbeat auto-push).
Shared branch groups
The dashboard now exposes branch-group visibility and controls for shared planning/mission branches.
GET /api/branch-groupslists groups with completion (landed/total) and tracked PR metadata.GET /api/branch-groups/:idreturns group details (shared branch, members, per-member landed state, completion, PR state).POST /api/branch-groups/assignis the supported online grouping path to attach/detach tasks ({ taskId, groupId|null, branchName? }). PassinggroupId: nullclears only that task's branch-group context and preserves unrelated task source metadata.POST /api/branch-groups/:id/promotetriggers the engine promotion flow (promoteBranchGroup) and returns promotion/PR status.
UI surfaces:
- Subtask planning interview shows a grouped indicator when
assignmentMode=shared. - Task cards show grouped/shared branch metadata for grouped tasks.
- Clicking either grouped badge opens the dedicated Group Task Modal for that branch group.
- Task detail renders a branch-group card with member landed progress.
- If a task references a stale/missing branch group, Task Detail shows a Stale branch group reference recovery message with Reset branch group for this task. The action uses the supported assign API to clear only the current task's context, then reloads the detail so the card disappears and the task can proceed ungrouped without raw SQLite surgery.
- In Task Detail Logs on mobile, the branch-group card includes a collapse/expand toggle so logs can reclaim vertical space while keeping group summary progress visible.
The Group Task Modal shows shared branch name/status, member list (taskId, title, column, landed state), quick links to open each member task detail, completion progress (X of Y members finished), and tracked PR state when present. Branch groups are durable SQLite state keyed by real BG-* ids, so valid grouped tasks continue to list/show after a server restart. It live-refreshes from the same dashboard task-update stream and ignores stale cross-project events.
Both the modal and branch-group card are completion-gated: while members are still pending, they show progress only. PR / merge controls are only revealed after all members are landed into the shared branch. When auto-merge is off, promote/open-PR is explicit user action (no automatic push-to-origin behavior).
CLI-onboarding backfill runbook
Use the assign endpoint to place paused CLI-onboarding tasks into a single shared group rooted on feature/cli-onboarding:
for id in FN-5805 FN-5806 FN-5807 FN-5808 FN-5809 FN-5810 FN-5811 FN-5812 FN-5813 FN-5814 FN-5815 FN-5816; do
curl -sS -X POST "http://127.0.0.1:4040/api/branch-groups/assign" \
-H 'content-type: application/json' \
--data "{\"taskId\":\"$id\",\"branchName\":\"feature/cli-onboarding\"}"
done
If the endpoint is unavailable on the running dashboard build, the response will be {"error":"Not found"} until a build containing the branch-group router is deployed.