Files
fusion/docs/settings-reference.md
Fusion 499417bc8e feat(FN-3321): add agent self-improvement service and heartbeat evaluation
This merge delivers agent self-improvement (FN-3321) — adding evaluation identity tools, wiring evaluation into the heartbeat loop, implementing a self-improvement service, and providing test coverage. It also expands the dashboard guide view with regression tests, adds org chart full-view mode with

Fusion-Task-Id: FN-3321
2026-05-05 06:32:33 -07:00

54 KiB
Raw Blame History

Settings Reference

← Docs index

This guide documents Fusion settings from packages/core/src/types.ts.

Settings Scopes

Fusion uses a two-tier settings system:

  • Global settings (~/.fusion/settings.json): user preferences shared across projects
  • Project settings (.fusion/config.json): execution/runtime behavior for one project

At runtime, settings are merged. Project settings override global settings when keys overlap.

Settings API Endpoints

Endpoint Purpose
GET /api/settings Get merged settings (global + project).
PUT /api/settings Update project settings only.
GET /api/settings/global Get global settings only.
PUT /api/settings/global Update global settings only.
GET /api/settings/scopes Get separated { global, project } view.

Global Settings

Defaults from DEFAULT_GLOBAL_SETTINGS; key scope from GLOBAL_SETTINGS_KEYS.

Setting Type Default Description
themeMode "dark" | "light" | "system" "dark" Dashboard theme mode.
colorTheme ColorTheme "default" Dashboard color theme preset.
dashboardFontScalePct number 100 Dashboard font scale percentage used by Appearance settings. Valid range: 85 to 125; applied pre-hydration via document root font-size so board typography (column headers/counts, task cards, and quick-entry text) scales with the setting from first paint.
defaultProvider string undefined Default AI provider.
defaultModelId string undefined Default AI model ID.
fallbackProvider string undefined Fallback provider when the primary default model hits transient provider failures.
fallbackModelId string undefined Fallback model ID (must pair with fallbackProvider).
defaultThinkingLevel "off" | "minimal" | "low" | "medium" | "high" undefined Default reasoning effort for AI sessions.
ntfyEnabled boolean false Enable ntfy push notifications.
ntfyTopic string undefined ntfy topic name.
ntfyBaseUrl string undefined Optional custom ntfy server base URL (must use http:// or https://). If blank/unset, Fusion uses https://ntfy.sh for both runtime and test notifications.
ntfyEvents ("in-review" | "merged" | "failed" | "awaiting-approval" | "awaiting-user-review" | "planning-awaiting-input" | "gridlock" | "fallback-used")[] ["in-review","merged","failed","awaiting-approval","awaiting-user-review","planning-awaiting-input","gridlock","fallback-used"] Event types that trigger ntfy notifications. planning-awaiting-input fires when planning mode is waiting on user input. gridlock fires when all schedulable todo tasks are blocked; delivery is cooldown-throttled (first alert immediately, then suppressed for 15 minutes until gridlock resolves). fallback-used fires when Fusion recovers from a retryable model failure by switching to a configured fallback model.
ntfyDashboardHost string undefined Dashboard host used to build deep links in notifications.
webhookEnabled boolean false Enable webhook notifications for task lifecycle events. Part of the legacy flat settings; prefer notificationProviders for new setups.
webhookUrl string undefined Webhook endpoint URL. Must be http:// or https://. Part of legacy flat settings.
webhookFormat "slack" | "discord" | "generic" "generic" Webhook payload format. Part of legacy flat settings.
webhookEvents string[] [] Event filter for webhook notifications. Empty/omitted means all events. Part of legacy flat settings.
notificationProviders NotificationProviderConfig[] [] Array of pluggable notification provider configurations. Each entry uses { id, name, enabled, config } and is dispatched by provider ID (for example ntfy or webhook).
customProviders CustomProvider[] [] User-defined OpenAI-compatible or Anthropic-compatible providers used by the custom-provider API (/api/custom-providers). Each entry uses { id, name, apiType, baseUrl, apiKey?, models? }; API keys are stored raw but masked in API responses.
defaultProjectId string undefined Default project for multi-project CLI operations when --project is omitted.
setupComplete boolean undefined Tracks completion of first-run setup.
favoriteProviders string[] undefined Pinned providers shown first in model selectors.
favoriteModels string[] undefined Pinned models in {provider}/{modelId} format.
openrouterModelSync boolean true Sync OpenRouter model catalog into model pickers at startup.
opencodeGoModelSync boolean true Sync opencode-go model catalog at startup via opencode models opencode --refresh, normalizing discovered opencode/... IDs into the opencode-go provider surface used by /api/models.
updateCheckEnabled boolean true When enabled, Fusion performs a daily npm registry check for new @runfusion/fusion versions and shows update notices in CLI/dashboard.
autoReloadOnVersionChange boolean true When enabled (default), the dashboard automatically reloads when a new build version is detected via /version.json polling or service worker activation. Set to false to suppress automatic reloads — the user must manually refresh to pick up updates.
modelOnboardingComplete boolean undefined Whether AI onboarding has been completed or dismissed.
executionGlobalProvider string undefined Global baseline provider for task execution. Project executionProvider overrides this.
executionGlobalModelId string undefined Global baseline model ID for task execution.
planningGlobalProvider string undefined Global baseline provider for planning. Project planningProvider overrides this.
planningGlobalModelId string undefined Global baseline model ID for planning.
validatorGlobalProvider string undefined Global baseline provider for validator/reviewer runs. Project validatorProvider overrides this.
validatorGlobalModelId string undefined Global baseline model ID for validator/reviewer runs.
titleSummarizerGlobalProvider string undefined Global baseline provider for title summarization. Project titleSummarizerProvider overrides this.
titleSummarizerGlobalModelId string undefined Global baseline model ID for title summarization.
daemonToken string undefined Daemon authentication token (fn_<32 hex chars>) used by CLI clients.
daemonPort number 4040 Port for daemon/serve mode binding.
daemonHost string "127.0.0.1" Host for daemon/serve mode binding. Defaults to localhost only; pass "0.0.0.0" to expose on all interfaces.
settingsSyncEnabled boolean false Enable automatic settings synchronization between nodes.
settingsSyncAuth boolean false Include model auth credentials in settings sync operations.
settingsSyncInterval number 900000 Automatic sync interval in ms. Valid values: 300000, 900000, 1800000, 3600000.
settingsSyncConflictResolution "last-write-wins" | "always-ask" | "keep-local" | "keep-remote" "last-write-wins" Conflict strategy for divergent synced settings.
dashboardCurrentNodeId string undefined Currently selected dashboard node ID. Restores the last-viewed node on fresh browser/PWA sessions. undefined means viewing the local node.

Mesh lifecycle note: settings sync is executed by the process-level PeerExchangeService started by fn serve/fn dashboard. InProcessRuntime does not instantiate settings-sync mesh services per project. | dashboardCurrentProjectIdByNode | Record<string, string> | undefined | Map of node ID to last-selected project ID. Use key "local" for the local node. Persists project context across browser restarts and PWA sessions. | | persistAgentToolOutput | boolean | true | Controls whether detailed detail payloads are persisted for tool, tool_result, and tool_error agent log entries. When disabled, tool timeline rows are still recorded, but verbose payloads are omitted. | | researchGlobalDefaults | ResearchGlobalDefaults | { searchProvider: undefined, synthesisProvider: undefined, synthesisModelId: undefined, enabledSources: { webSearch: true, pageFetch: true, github: false, localDocs: true, llmSynthesis: true }, maxSourcesPerRun: 20, defaultExportFormat: "markdown" } | Global Research defaults shared by all projects. Project overrides come from researchSettings. | | researchGlobalEnabled | boolean | true | Enable or disable the research subsystem globally. When false, dashboard/API/CLI/agent entrypoints reject new runs. | | researchGlobalMaxConcurrentRuns | number | 3 | Maximum concurrent research runs across all projects. | | researchGlobalDefaultTimeout | number | 300000 | Default timeout for end-to-end research runs in milliseconds (5 minutes). | | researchGlobalMaxSourcesPerRun | number | 20 | Maximum number of sources per research run. | | researchGlobalMaxSynthesisRounds | number | 2 | Maximum synthesis rounds per research run. | | researchGlobalWebSearchProvider | "searxng" \| "brave" \| "google" \| "tavily" \| "none" | "none" | Web search backend for research. Default: "none" (disabled). | | researchGlobalSearxngUrl | string | undefined | SearXNG instance URL (required when provider is "searxng"). | | researchGlobalBraveApiKey | string | undefined | Brave Search API key (required when provider is "brave"). | | researchGlobalGoogleSearchApiKey | string | undefined | Google Custom Search API key (required when provider is "google"). | | researchGlobalGoogleSearchCx | string | undefined | Google Custom Search engine ID (required when provider is "google"). | | researchGlobalTavilyApiKey | string | undefined | Tavily API key (required when provider is "tavily"). | | researchGlobalGitHubEnabled | boolean | undefined | Enable GitHub as a research source. | | researchGlobalLocalDocsEnabled | boolean | undefined | Enable local docs as a research source. | | researchGlobalMaxSearchResults | number | undefined | Maximum search results per provider query. | | researchGlobalFetchTimeoutMs | number | 30000 | Timeout for individual HTTP fetches in milliseconds. | | researchGlobalUserAgent | string | "FusionResearchBot/1.0" | User-Agent header for HTTP requests made by research providers. | | experimentalFeatures | Record<string, boolean> | {} | Global-scoped experimental feature flags. Includes experimentalFeatures.researchView for standalone Research route visibility. | | remoteAccess | RemoteAccessSettings | { activeProvider: null, providers: {...}, tokenStrategy: {...}, lifecycle: {...} } | Global-scoped remote access provider + token strategy configuration used by Remote Access routes and tunnel lifecycle controls. |

Notification providers (pluggable)

Fusion now supports a provider-list notification model via notificationProviders while keeping legacy flat ntfy/webhook settings intact.

  • Recommended for new setups: configure providers in notificationProviders.
  • Backward compatible: existing flat settings continue to work unchanged, including ntfyEnabled, ntfyTopic, ntfyBaseUrl, ntfyEvents, ntfyDashboardHost, webhookEnabled, webhookUrl, webhookFormat, and webhookEvents.
  • This is additive/non-breaking; no migration is required for existing ntfy users.

notificationProviders entry shape (NotificationProviderConfig):

{
  id: string;
  name: string;
  enabled: boolean;
  config: Record<string, unknown>;
}

Built-in provider IDs:

  • ntfy
  • webhook

Webhook provider config

When id is "webhook", the provider config supports:

Field Type Default Notes
webhookUrl string required Must be a valid http:// or https:// URL.
webhookFormat "slack" | "discord" | "generic" "generic" Invalid/omitted values fall back to "generic".
events string[] [] Event filter list. Empty/omitted means all events are sent.

ntfy provider config

When id is "ntfy" in notificationProviders, the provider config supports:

Field Type Default Notes
topic string required ntfy topic name (164 chars, alphanumeric + -_).
ntfyBaseUrl string "https://ntfy.sh" Optional custom ntfy server URL.
events ("in-review" | "merged" | "failed" | "awaiting-approval" | "awaiting-user-review" | "planning-awaiting-input" | "gridlock")[] DEFAULT_NTFY_EVENTS Event filter list used by the provider. For gridlock, enabled events are still cooldown-throttled at runtime (15-minute suppression window, reset on full resolution).
dashboardHost string undefined Dashboard host for deep links in notifications.

Disable daily update checks globally:

fn settings set updateCheckEnabled false

Project Settings

Defaults from DEFAULT_PROJECT_SETTINGS; key scope from PROJECT_SETTINGS_KEYS.

Setting Type Default Description
globalPause boolean false Hard stop: terminate active engine sessions and pause scheduling immediately.
globalPauseReason string undefined Optional reason for globalPause ("rate-limit" for automatic pauses, "manual" for user-triggered pauses). Cleared on unpause.
enginePaused boolean false Soft pause: stop dispatching new work while letting active sessions finish. Clearing enginePaused resumes runtime scheduling and, when autoMerge is enabled, immediately re-sweeps eligible in-review tasks back into the auto-merge queue (paused/blocked/failed review tasks remain skipped).
maxConcurrent number 2 Max concurrent task-lane AI agents (planning, executor, merge).
maxTriageConcurrent number 2 Max concurrent planning agents.
globalMaxConcurrent number 4 System-wide max concurrent agents across all projects.
maxWorktrees number 4 Max git worktrees.
pollIntervalMs number 15000 Scheduler poll interval (ms).
heartbeatMultiplier number 1 Global multiplier applied to all agent heartbeat intervals. Configured from the Agents screen (not Settings).
defaultNodeId string undefined Optional project default execution node for task dispatch. When set, tasks without a per-task nodeId override resolve to this node (routing source: project-default). See Task Management → Node Routing.
unavailableNodePolicy "block" | "fallback-local" "block" Project routing policy used during scheduler dispatch when a task resolves to a remote node and node health is known. "block" keeps the task in todo if the node is unhealthy; "fallback-local" reroutes dispatch to local execution. See Architecture → Task Routing Architecture.

| groupOverlappingFiles | boolean | true | Serialize execution when file scopes overlap. | | overlapIgnorePaths | string[] | [] | Optional project-relative file or directory paths to exclude from overlap blocking (for example docs or generated/openapi.json). Entries are trimmed, deduplicated, and must not be absolute or contain .. traversal. | | autoMerge | boolean | true | Auto-finalize tasks from in-review. | | mergeStrategy | "direct" \| "pull-request" | "direct" | Completion mode (local direct merge vs PR-first). | | pushAfterMerge | boolean | false | Auto-push to remote after successful direct merge. Includes pulling latest and AI conflict resolution. | | pushRemote | string | "origin" | Git remote (and optional branch) to push to after merge. | | worktreeInitCommand | string | undefined | Shell command run after worktree creation. For pnpm repos, prefer pnpm install --frozen-lockfile for deterministic bootstrap. | | testCommand | string | undefined | Merge-time test command (hard gate). When unset, Fusion auto-detects from lockfile. | | buildCommand | string | undefined | Merge-time build command (hard gate). | | recycleWorktrees | boolean | false | Reuse worktrees from a pool for faster startup. | | worktreeNaming | "random" \| "task-id" \| "task-title" | "random" | Naming mode for new worktree directories. | | taskPrefix | string | "FN" | Prefix used for newly generated task IDs. | | includeTaskIdInCommit | boolean | true | Include task ID as commit scope in generated commits. | | commitAuthorEnabled | boolean | true | Apply explicit --author attribution on Fusion commits. | | commitAuthorName | string | "Fusion" | Commit author name when commitAuthorEnabled is true. | | commitAuthorEmail | string | "noreply@runfusion.ai" | Commit author email when commitAuthorEnabled is true. | | planningProvider | string | undefined | Provider for planning agents. | | planningModelId | string | undefined | Model ID for planning agents. | | planningFallbackProvider | string | undefined | Fallback provider for planning. | | planningFallbackModelId | string | undefined | Fallback model ID for planning. | | defaultProviderOverride | string | undefined | Project-level override for global default provider baseline. | | defaultModelIdOverride | string | undefined | Project-level override for global default model baseline. | | executionProvider | string | undefined | Provider for task execution agents. | | executionModelId | string | undefined | Model ID for task execution agents. | | validatorProvider | string | undefined | Provider for plan/code reviewers. | | validatorModelId | string | undefined | Model ID for plan/code reviewers. | | validatorFallbackProvider | string | undefined | Fallback provider for reviewers. | | validatorFallbackModelId | string | undefined | Fallback model ID for reviewers. | | modelPresets | ModelPreset[] | [] | Reusable executor/reviewer model presets. | | autoSelectModelPreset | boolean | false | Auto-select presets by task size. | | defaultPresetBySize | { S?: string; M?: string; L?: string } | {} | Mapping for S/M/L → preset ID. | | autoResolveConflicts | boolean | true | Enable automatic merge conflict resolution. | | smartConflictResolution | boolean | true | Alias/preferred flag for smart conflict handling. | | strictScopeEnforcement | boolean | false | Block merges on out-of-scope file changes. | | buildRetryCount | number | 0 | Build retry attempts during merge. | | verificationFixRetries | number | 3 | Auto-fix retry attempts when verification fails during merge. | | buildTimeoutMs | number | 300000 | Build timeout in milliseconds (5 minutes). | | requirePlanApproval | boolean | false | Require manual approval before planning → todo. | | completionDocumentationMode | "off" \| "changeset" \| "changelog" | "off" | Controls triage prompt injection for release-note artifacts in future task specs. "changeset" requires .changeset/*.md workflow guidance; "changelog" requires updating an existing changelog file (without inventing a new one); "off" disables this automation. | | specStalenessEnabled | boolean | false | Enforce automatic re-planning for stale plans. | | specStalenessMaxAgeMs | number | 21600000 | Spec staleness threshold in ms (6 hours). | | taskStuckTimeoutMs | number | undefined | Inactivity timeout for stuck-task recovery. | | aiSessionTtlMs | number | 604800000 | TTL in ms for persisted planning/subtask/mission sessions (7 days). | | aiSessionCleanupIntervalMs | number | 3600000 | Interval in ms for AI session cleanup sweeps (1 hour). | | autoUnpauseEnabled | boolean | true | Auto-unpause after rate-limit-triggered pauses; manual pauses stay paused until explicitly unpaused by the user. | | autoUnpauseBaseDelayMs | number | 300000 | Base unpause delay in ms (5 min). | | autoUnpauseMaxDelayMs | number | 3600000 | Max auto-unpause delay in ms (1 hour). | | maxStuckKills | number | 6 | Max stuck-task terminations before permanent failure. | | maxPostReviewFixes | number | 1 | Max auto-revival attempts for in-review tasks failing pre-merge workflow steps. | | maxSpawnedAgentsPerParent | number | 5 | Max child agents per parent task. | | maxSpawnedAgentsGlobal | number | 20 | Max spawned agents across one executor instance. | | maintenanceIntervalMs | number | 300000 | Periodic maintenance interval in ms (5 min). | | autoArchiveDoneTasksEnabled | boolean | true | Enable periodic auto-archiving of done tasks. | | autoArchiveDoneAfterMs | number | 172800000 | Age in ms after entering done before auto-archive (48h). | | archiveAgentLogMode | "none" \| "compact" \| "full" | "compact" | Agent log retention strategy for cold archive snapshots. | | autoUpdatePrStatus | boolean | false | Auto-refresh PR status badges. | | githubCommentOnDone | boolean | false | When enabled, tasks imported from GitHub issues post a completion comment to the source issue when the task moves to done. | | githubCommentTemplate | string | undefined | Optional issue comment template used by githubCommentOnDone. Supports {taskId} and {taskTitle} placeholders. If unset, Fusion uses a default completion message. | | autoCreatePr | boolean | false | Auto-create PRs for completed tasks. | | autoBackupEnabled | boolean | false | Enable scheduled DB backups. | | autoBackupSchedule | string | "0 2 * * *" | Backup cron schedule. | | autoBackupRetention | number | 7 | Number of backups to retain. | | autoBackupDir | string | ".fusion/backups" | Relative backup directory path. | | autoSummarizeTitles | boolean | false | Auto-generate titles for long untitled descriptions across dashboard/API task creation and agent/tool-created tasks. | | useAiMergeCommitSummary | boolean | false | Use AI-generated merge commit summaries instead of raw step-commit subject lists. | | titleSummarizerProvider | string | undefined | Provider for title summarization. | | titleSummarizerModelId | string | undefined | Model ID for title summarization. | | titleSummarizerFallbackProvider | string | undefined | Fallback provider for title summarization. | | titleSummarizerFallbackModelId | string | undefined | Fallback model ID for title summarization. | | scripts | Record<string, string> | undefined | Named script map used by script-mode workflow steps and setup hooks. | | setupScript | string | undefined | Script key from scripts to run before task execution. | | insightExtractionEnabled | boolean | false | Enable scheduled memory insight extraction. | | insightExtractionSchedule | string | "0 2 * * *" | Insight extraction cron schedule. | | insightExtractionMinIntervalMs | number | 86400000 | Minimum interval between extractions (24h). | | memoryEnabled | boolean | true | Enable project memory integration. | | memoryBackendType | string | "qmd" | Memory backend type. Built-ins include qmd (Quantized Memory Distillation, default), file, and readonly; custom backends can also be registered. | | memoryAutoSummarizeEnabled | boolean | false | Enable automatic memory summarization when memory exceeds threshold. | | memoryAutoSummarizeThresholdChars | number | 50000 | Character threshold for auto-summarization. | | memoryAutoSummarizeSchedule | string | "0 3 * * *" | Cron schedule for auto-summarize checks. | | memoryDreamsEnabled | boolean | false | Enable dream processing that synthesizes daily notes and promotes durable lessons. | | memoryDreamsSchedule | string | "0 4 * * *" | Cron schedule for dream processing. | | tokenCap | number | undefined | Proactive token threshold for context compaction. | | runStepsInNewSessions | boolean | false | Run each task step in a fresh agent session. | | maxParallelSteps | number | 2 | Max concurrent step sessions when per-step sessions are enabled. | | missionStaleThresholdMs | number | 600000 | Mission stale threshold in ms while activating (10 min). | | missionMaxTaskRetries | number | 3 | Max automatic retries for failed mission-linked tasks. | | missionHealthCheckIntervalMs | number | 300000 | Mission health-check interval in ms (5 min). | | agentPrompts | AgentPromptsConfig | undefined | Custom role prompt templates and assignments. | | promptOverrides | Record<string, string \| null> | undefined | Segment-level prompt overrides (set a key to null to clear it). | | reflectionEnabled | boolean | false | Enable/disable agent self-reflection workflows. | | reflectionIntervalMs | number | 3600000 | Periodic reflection interval in ms. | | reflectionAfterTask | boolean | true | Trigger reflection after task completion. | | reviewHandoffPolicy | "disabled" \| "comment-triggered" \| "always" | "disabled" | Policy for agent-to-user review handoff detection. | | showQuickChatFAB | boolean | false | Show floating quick-chat button (chat remains available via More menu). | | researchSettings | ResearchProjectSettings | { enabled: true, searchProvider: undefined, synthesisProvider: undefined, synthesisModelId: undefined, enabledSources: { webSearch: true, pageFetch: true, github: false, localDocs: true, llmSynthesis: true }, limits: { maxConcurrentRuns: 3, maxSourcesPerRun: 20, maxDurationMs: 300000, requestTimeoutMs: 30000 } } | Project-specific Research enablement/overrides. Resolved together with researchGlobalDefaults via resolveResearchSettings(). | | researchEnabled | boolean | undefined | Enable or disable research for this project. Deprecated: prefer researchSettings.enabled. | | researchMaxConcurrentRuns | number | undefined | Project-level max concurrent research runs. | | researchDefaultTimeout | number | undefined | Project-level default run timeout in milliseconds. | | researchMaxSourcesPerRun | number | undefined | Project-level max sources per run. | | researchMaxSynthesisRounds | number | undefined | Project-level max synthesis rounds. |

Research settings hierarchy and credentials

Research configuration resolves through resolveResearchSettings(settings) in @fusion/core with this precedence:

  1. Project override (researchSettings.*)
  2. Global default (researchGlobalDefaults.*)
  3. Hardcoded fallback defaults

This applies to:

  • enabled
  • searchProvider
  • synthesisProvider + synthesisModelId
  • enabledSources (webSearch, pageFetch, github, localDocs, llmSynthesis)
  • run limits (maxConcurrentRuns, maxSourcesPerRun, maxDurationMs, requestTimeoutMs)
  • export default (defaultExportFormat)

The standalone Research route is feature-gated separately via experimentalFeatures.researchView. When that flag is disabled, the Settings modal also hides both Research sections (Research Defaults and project Research) and falls back to the first visible section if a hidden research section is requested directly.

Research failures are normalized to a shared error-code contract (FEATURE_DISABLED, MISSING_CREDENTIALS, PROVIDER_UNAVAILABLE, RATE_LIMITED, PROVIDER_TIMEOUT, RUN_CANCELLED, RETRY_EXHAUSTED, INVALID_TRANSITION, NON_RETRYABLE_PROVIDER_ERROR, INTERNAL_ERROR) with retryability metadata so dashboard, API, CLI, and agent tooling show consistent recovery guidance.

Recovery entrypoints in the dashboard:

  • Settings → Research Defaults: fix missing default provider configuration and provider-level readiness.
  • Settings → Authentication: repair missing provider credentials (MISSING_CREDENTIALS).
  • Settings → Research (project): re-enable project research or source toggles when runs are blocked by project settings.
  • Settings → Experimental Features: enable researchView when the standalone Research route/surfaces are hidden.

Credential storage rule: API keys for Research providers are not stored in settings JSON. They are managed through the existing auth storage pipeline (/api/auth/status, POST /api/auth/api-key, DELETE /api/auth/api-key) and persisted in auth credential storage with masked hints in API responses.

Node Routing settings (project scope)

Node routing controls in the project settings table are configured from Settings → Node Routing in the dashboard or via CLI:

  • fn settings set defaultNodeId <node-id>
  • fn settings set unavailableNodePolicy <block|fallback-local>

Routing precedence for task dispatch is:

  1. per-task override (Task.nodeId)
  2. project default (defaultNodeId)
  3. local execution

Project Default Node vs central project node assignment

Fusion also stores projects.nodeId in the central registry database (~/.fusion/fusion-central.db). That value is a multi-project runtime placement field used by ProjectManager (for selecting remote vs local project runtime), not the same setting as defaultNodeId task dispatch routing.

  • defaultNodeId (project settings): task-level dispatch default
  • projects.nodeId (central registry): which node hosts the project runtime in multi-project mode

See also:

Remote Access settings (global-scoped)

Remote access settings are global-only (stored in ~/.fusion/settings.json), not project-scoped. The canonical persisted shape is a nested remoteAccess object.

Use Remote Access runbook for setup prerequisites (Tailscale/Cloudflare), tokenized login-link security caveats, and operational troubleshooting. Keep this section as a schema reference.

When remoteAccess.activeProvider is cloudflare, the Settings UI fetches /api/remote/status and surfaces cloudflaredAvailable to show installed/missing state plus a one-click POST /api/remote/install-cloudflared action.

When remoteAccess.activeProvider is tailscale and the Fusion-managed tunnel is stopped, /api/remote/status also returns externalTunnel when a pre-existing funnel is detected. The UI exposes two actions: Use Existing (start Fusion tunnel lifecycle against the existing funnel) and Start Fresh (POST /api/remote/tunnel/kill-external then start).

Setting Type Default Description
remoteAccess.enabled boolean false Master toggle for remote access orchestration.
remoteAccess.activeProvider "tailscale" | "cloudflare" | null null Currently selected provider.
remoteAccess.providers.tailscale.enabled boolean false Enables Tailscale provider configuration.
remoteAccess.providers.tailscale.hostname string "" Optional serve hostname label for Tailscale.
remoteAccess.providers.tailscale.targetPort number 0 Local port exposed by Tailscale when configured.
remoteAccess.providers.tailscale.acceptRoutes boolean false Accept subnet routes when supported by local Tailscale config.
remoteAccess.providers.cloudflare.enabled boolean false Enables Cloudflare tunnel configuration.
remoteAccess.providers.cloudflare.quickTunnel boolean true Enables Cloudflare Quick Tunnel mode (cloudflared tunnel --url) with no account/token requirement; named tunnel fields are ignored while enabled.
remoteAccess.providers.cloudflare.tunnelName string "" Named tunnel identifier for cloudflared tunnel run when quickTunnel is false.
remoteAccess.providers.cloudflare.tunnelToken string | null null Tunnel token value (treat as secret; do not log raw values) for named tunnel mode.
remoteAccess.providers.cloudflare.ingressUrl string "" Preferred public ingress URL for named tunnel mode; in quick tunnel mode the live trycloudflare.com URL comes from runtime status.
remoteAccess.tokenStrategy.persistent.enabled boolean true Enables persistent remote-auth token mode.
remoteAccess.tokenStrategy.persistent.token string | null null Persistent remote-auth token.
remoteAccess.tokenStrategy.shortLived.enabled boolean false Enables short-lived token generation.
remoteAccess.tokenStrategy.shortLived.ttlMs number 900000 Default short-lived token TTL in milliseconds (15 minutes).
remoteAccess.tokenStrategy.shortLived.maxTtlMs number 86400000 Maximum allowed short-lived token TTL (24 hours).
remoteAccess.lifecycle.rememberLastRunning boolean false Enables safe startup restore attempts when prior-running markers + prerequisites are valid.
remoteAccess.lifecycle.wasRunningOnShutdown boolean false Internal marker written by runtime lifecycle management; explicit manual stop clears this to prevent unintended restart restore.
remoteAccess.lifecycle.lastRunningProvider "tailscale" | "cloudflare" | null null Internal provider marker used for startup restore gating; stale markers are cleared when restore is skipped/failed.

Patch semantics for global updates (PUT /api/settings/global and PUT /api/remote/settings):

  • remoteAccess patches are deep-merged so sibling branches are preserved.
  • remoteAccess: null clears the full global override (falls back to defaults).
  • Nested null clears only the targeted nested key/branch.

Examples:

{
  "remoteAccess": {
    "providers": {
      "tailscale": {
        "enabled": true,
        "hostname": "team.tail.ts.net",
        "targetPort": 5173,
        "acceptRoutes": true
      }
    }
  }
}

The payload above updates only providers.tailscale and keeps providers.cloudflare, tokenStrategy, and lifecycle unchanged.

{
  "remoteAccess": {
    "tokenStrategy": {
      "persistent": {
        "token": null
      }
    }
  }
}

The payload above clears only remoteAccess.tokenStrategy.persistent.token.

Runtime provider config/credential contract (engine remote-access manager):

  • The tunnel manager consumes resolved provider configs (TunnelProviderConfig) from callers; it does not read dashboard form state directly.
  • Provider config must include executable + args and may include credential references:
    • tokenEnvVar (env var name, value sourced from process/config env)
    • credentialsPath (Cloudflare credentials file path)
  • Missing/invalid credential references fail fast with invalid_config status/error behavior.
  • Secret-bearing values are redacted in command previews and emitted tunnel logs before they are published to subscribers.

Runtime lifecycle semantics:

  • Provider/settings edits remain manual-only and do not auto-start tunnel processes.
  • Startup restore is best-effort and non-fatal; failed/skipped restore attempts surface machine-readable diagnostics through /api/remote/status and do not loop indefinitely.
  • Tunnel status payloads redact secret values (persistent/short-lived tokens and tokenized URLs are never returned raw from status diagnostics).

Short-lived token bounds are enforced server-side:

  • Minimum TTL: 60_000 ms (60s)
  • Maximum TTL: 86_400_000 ms (24h)

Note: Agent metadata.skills is not a top-level project setting, but it is the primary mechanism for controlling execution-time skill selection. The engine's buildSessionSkillContext function reads this metadata from the assigned agent and uses it to resolve which skills are available in the agent session. If metadata.skills is absent or empty, the engine falls back to the built-in fusion skill.


Model Selection Hierarchy

Fusion uses a dual-scope model settings system with five lanes. Global settings provide baseline defaults, and project settings provide per-project overrides.

Planning model

  1. Per-task planningModelProvider + planningModelId
  2. Project planningProvider + planningModelId
  3. Global planningGlobalProvider + planningGlobalModelId
  4. Project defaultProviderOverride + defaultModelIdOverride
  5. Global defaultProvider + defaultModelId
  6. Automatic provider/model resolution

Executor model

  1. Per-task modelProvider + modelId
  2. Project executionProvider + executionModelId
  3. Global executionGlobalProvider + executionGlobalModelId
  4. Project defaultProviderOverride + defaultModelIdOverride
  5. Global defaultProvider + defaultModelId
  6. Automatic provider/model resolution

Reviewer model

  1. Per-task validatorModelProvider + validatorModelId
  2. Project validatorProvider + validatorModelId
  3. Global validatorGlobalProvider + validatorGlobalModelId
  4. Project defaultProviderOverride + defaultModelIdOverride
  5. Global defaultProvider + defaultModelId
  6. Automatic provider/model resolution

Merger model

  1. Project defaultProviderOverride + defaultModelIdOverride
  2. Global defaultProvider + defaultModelId
  3. Automatic provider/model resolution

Title summarization model

Used for task title auto-summarization and (when enabled) AI merge commit summaries.

  1. Project titleSummarizerProvider + titleSummarizerModelId
  2. Global titleSummarizerGlobalProvider + titleSummarizerGlobalModelId
  3. Project planningProvider + planningModelId
  4. Project defaultProviderOverride + defaultModelIdOverride
  5. Global defaultProvider + defaultModelId
  6. Automatic provider/model resolution

Note: Runtime fallback precedence logic is implemented in engine and dashboard routes. The hierarchies above reflect current runtime behavior.


Runtime Selection

Fusion supports multiple agent runtimes through a plugin-based runtime system. The default runtime is pi (the built-in runtime backed by the pi agent). Additional runtimes can be provided by plugins.

Available Runtimes

Runtime ID Name Description
pi Default PI Runtime Built-in runtime using the pi agent (default)
paperclip Paperclip Runtime Plugin-provided runtime (requires fusion-plugin-paperclip-runtime)
hermes Hermes Runtime (experimental) Plugin-provided experimental runtime hint (requires fusion-plugin-hermes-runtime)
openclaw OpenClaw Runtime (experimental) Plugin-provided experimental runtime hint (requires fusion-plugin-openclaw-runtime)

Runtime Resolution Order

When creating an agent session, Fusion resolves the runtime as follows:

  1. No runtimeHint configured → Use default pi runtime
  2. runtimeHint is "pi" or "default" → Use default pi runtime
  3. runtimeHint is a plugin runtime ID (e.g., "paperclip", "hermes", or "openclaw") → Look up and instantiate the plugin runtime
  4. Plugin runtime unavailable → Fall back to default pi runtime (with warning log)

Configuring Runtime Selection

Runtime selection is configured at the agent level via runtimeConfig.runtimeHint:

{
  "name": "Paperclip Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "paperclip"
  }
}
{
  "name": "Hermes Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "hermes"
  }
}
{
  "name": "OpenClaw Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "openclaw"
  }
}

runtimeHint: "hermes" and runtimeHint: "openclaw" are experimental runtime paths. Runtime resolution and execution are supported when the corresponding runtime plugin is installed and enabled.

Important: There is no task-level runtime configuration. Tasks inherit the runtime from their assigned agent's runtimeConfig.

Fallback Behavior

If a configured runtime is unavailable (plugin not installed, not enabled, or factory error), Fusion logs a warning and falls back to the default pi runtime:

[runtime-resolver] [executor] Runtime "hermes" unavailable (not_found), falling back to default pi runtime

The fallback ensures tasks continue executing even if the configured runtime plugin is unavailable.

Installing Plugin Runtimes

To use plugin-provided runtimes like Paperclip, Hermes, or OpenClaw:

  1. Install one or more runtime plugins:
fn plugin install ./plugins/fusion-plugin-paperclip-runtime
fn plugin install ./plugins/fusion-plugin-hermes-runtime
fn plugin install ./plugins/fusion-plugin-openclaw-runtime

💡 In the dashboard, go to Settings → Plugins → Fusion Plugins. The Bundled Plugins section surfaces Agent Browser, Hermes, Paperclip, OpenClaw, and Droid directly from shipped manifests, shows install status, and provides one-click install actions for plugins that are not yet installed.

  1. Create agents with the appropriate runtimeConfig:
{
  "name": "Paperclip Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "paperclip"
  }
}
{
  "name": "Hermes Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "hermes"
  }
}
{
  "name": "OpenClaw Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "openclaw"
  }
}
  1. Assign the agent to tasks that should use this runtime.

For more details, see the Paperclip Runtime Plugin documentation, Hermes Runtime Plugin documentation, and OpenClaw Runtime Plugin documentation.

OpenClaw Gateway Configuration

The OpenClaw runtime plugin connects to a running OpenClaw gateway instance through its OpenAI-compatible HTTP API. You can configure the gateway connection using plugin settings or environment variables.

Setting Type Default Description
gatewayUrl string http://127.0.0.1:18789 URL of the OpenClaw gateway instance
gatewayToken string (none) Authentication token for the gateway
agentId string "main" OpenClaw agent ID to use for sessions
Setting Environment Variable Default if Unset
gatewayUrl OPENCLAW_GATEWAY_URL http://127.0.0.1:18789
gatewayToken OPENCLAW_GATEWAY_TOKEN (none — unauthenticated)
agentId OPENCLAW_AGENT_ID main

Resolution priority is: plugin settings (PluginContext.settings) → environment variables → built-in defaults.

These are plugin-level settings configured when the OpenClaw runtime plugin is installed/enabled (for example in the dashboard Plugin Manager or plugin config). They are not agent-level runtimeConfig fields. Agents only need runtimeConfig.runtimeHint: "openclaw"; gateway connection details are handled by the plugin.

⚠️ gatewayToken is a secret. Never log it or commit it to version control. For production, prefer setting OPENCLAW_GATEWAY_TOKEN in the environment.

For additional gateway/runtime details, see the OpenClaw Runtime Plugin documentation.


Prompt Overrides

Fusion supports fine-grained customization of AI agent prompts through the promptOverrides setting. This enables surgical customization of specific prompt segments without replacing entire role prompts (which agentPrompts does).

Supported Prompt Keys

Key Agent Role Description
executor-welcome executor Introductory section for the executor agent
executor-guardrails executor Behavioral guardrails and constraints
executor-spawning executor Instructions for spawning child agents
executor-completion executor Completion criteria and signaling
triage-welcome planning Introductory section for the planning agent
triage-context planning Context-gathering instructions
reviewer-verdict reviewer Verdict criteria and format
merger-conflicts merger Merge conflict resolution instructions
agent-generation-system System prompt for AI-assisted agent plan generation
workflow-step-refine System prompt for refining workflow step descriptions into detailed agent prompts

How It Works

  1. Override Selection: When a prompt key is present with a non-empty value, that override replaces the default prompt segment.

  2. Fallback to Defaults: Missing or empty values fall back to the built-in default content.

  3. Cascade: agentPrompts provides full-role template customization, while promptOverrides provides segment-level customization. Both can be used together — promptOverrides applies to the segment even within a custom role template.

Clearing Overrides

To clear a specific override, set it to null:

{
  "promptOverrides": {
    "executor-welcome": null
  }
}

To clear all overrides, set promptOverrides to null:

{
  "promptOverrides": null
}

Configuration Example

{
  "settings": {
    "promptOverrides": {
      "executor-welcome": "Custom executor welcome message for this project...",
      "executor-guardrails": "## Custom Guardrails\n- Project-specific rules...",
      "triage-welcome": "Custom planning introduction..."
    }
  }
}

JSON Examples

1) Team baseline for reliable automation

{
  "settings": {
    "maxConcurrent": 3,
    "maxWorktrees": 6,
    "mergeStrategy": "direct",
    "autoResolveConflicts": true,
    "taskStuckTimeoutMs": 600000,
    "runStepsInNewSessions": true,
    "maxParallelSteps": 2
  }
}

2) Multi-model routing for plan/execute/review

{
  "settings": {
    "defaultProvider": "anthropic",
    "defaultModelId": "claude-sonnet-4-5",
    "planningProvider": "openai",
    "planningModelId": "gpt-4.1",
    "validatorProvider": "openai",
    "validatorModelId": "gpt-4o"
  }
}

3) Size-based preset auto-selection

{
  "settings": {
    "modelPresets": [
      {
        "id": "small-fast",
        "name": "Small / Fast",
        "executorProvider": "openai",
        "executorModelId": "gpt-4o-mini"
      },
      {
        "id": "large-deep",
        "name": "Large / Deep",
        "executorProvider": "anthropic",
        "executorModelId": "claude-sonnet-4-5",
        "validatorProvider": "openai",
        "validatorModelId": "gpt-4o"
      }
    ],
    "autoSelectModelPreset": true,
    "defaultPresetBySize": {
      "S": "small-fast",
      "L": "large-deep"
    }
  }
}

4) Agent runtime configuration (example agent config)

Runtime selection is configured at the agent level via runtimeConfig. These examples show agents configured to use Paperclip, Hermes, and OpenClaw runtime hints.

Common heartbeat/runtime keys on runtimeConfig include:

Field Type Description
heartbeatIntervalMs number Per-agent heartbeat interval
heartbeatTimeoutMs number Per-agent heartbeat timeout
maxConcurrentRuns number Per-agent concurrent heartbeat limit
messageResponseMode "immediate" | "on-heartbeat" Wake on message immediately or process during periodic heartbeat
selfImproveEnabled boolean Enables periodic self-improvement prompts
selfImproveIntervalMs number Delay between self-improvement cycles (default 4h, minimum 1h)
lastSelfImproveAt string Last self-improvement checkpoint timestamp (managed by heartbeat monitor)

These examples show agents configured to use Paperclip, Hermes, and OpenClaw runtime hints:

{
  "name": "Paperclip Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "paperclip"
  }
}
{
  "name": "Hermes Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "hermes"
  }
}
{
  "name": "OpenClaw Executor",
  "role": "executor",
  "runtimeConfig": {
    "runtimeHint": "openclaw"
  }
}

Hermes and OpenClaw remain experimental runtime options. Runtime hint selection and runtime execution are both available when their plugins are installed.

To create a Hermes-configured agent via the API:

curl -X POST http://localhost:4040/api/agents \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Hermes Executor",
    "role": "executor",
    "runtimeConfig": {
      "runtimeHint": "hermes"
    }
  }'

See also: Workflow Steps for how scripts and workflow model overrides are used.


Experimental Features

The experimentalFeatures setting provides a first-class mechanism for managing global-scoped experimental feature toggles. This allows users to explicitly mark capabilities as experimental and toggle them on/off from a dedicated section in the Settings dashboard.

How It Works

  1. Feature Registry: Features are stored as key-value pairs where keys are feature names and values indicate enabled/disabled state.

  2. Default Behavior: Features not present in the map are considered disabled (fallback to false).

  3. UI Integration: The Experimental Features section in Settings provides toggle controls for each configured feature.

  4. Consumption: Engine code can read experimentalFeatures[key] to check if a feature is enabled.

Example JSON Shape

{
  "settings": {
    "experimentalFeatures": {
      "my-new-feature": true,
      "another-experiment": false
    }
  }
}

Dashboard UI

The Experimental Features section in Settings shows:

  • Feature name and enabled/disabled toggle for each configured feature
  • Global scope indicator (features are shared across projects)
  • Description explaining the purpose of experimental features

Common built-in dashboard flags include:

  • insights
  • roadmap
  • memoryView
  • skillsView
  • nodesView
  • devServerView
  • todoView (enables dashboard Todo View; see Todo View)
  • researchView
  • remoteAccess
  • agentOnboarding (gates the planning-style New Agent onboarding flow in Agents view)

Background Memory Summarization & Audit

Fusion can automatically extract insights from project memory and prune transient content on a schedule. This feature is disabled by default and can be enabled via settings.

How It Works

  1. Scheduled Extraction: When insightExtractionEnabled is true, a background automation runs on the configured insightExtractionSchedule (default: daily at 2 AM).

  2. AI-Powered Analysis: The automation uses an AI agent to read canonical long-term memory (.fusion/memory/MEMORY.md) from the layered .fusion/memory/ workspace plus .fusion/memory/memory-insights.md, extract new insights, and produce a pruned working memory candidate.

  3. Insight Merging: New insights are automatically merged into .fusion/memory/memory-insights.md under the appropriate category (Patterns, Principles, Conventions, Pitfalls, Context). Duplicates are skipped.

  4. Memory Pruning: The AI agent also produces a pruned version of working memory containing only durable items:

    • Preserved: Architecture, Conventions, Pitfalls, Context sections with durable content
    • Pruned: Task-specific notes, one-time observations, outdated entries
  5. Audit Report: After each extraction run, a .fusion/memory/memory-audit.md file is generated with:

    • Working memory status (presence, size, sections)
    • Insights memory status (insight counts by category)
    • Last extraction results (success/failure, insight count, duplicates skipped)
    • Pruning outcome (applied/skipped, size delta, reason)
    • Health status (healthy/warning/issues)
    • Individual audit checks

Output Files

File Description
.fusion/memory/MEMORY.md Long-term memory (updated when pruning is applied and validated)
Legacy top-level memory file Deprecated migration fallback (compatibility only; not canonical storage)
.fusion/memory/memory-insights.md Long-term insights distilled from working memory
.fusion/memory/memory-audit.md Human-readable audit report after each extraction

Settings Interaction

Setting Effect
insightExtractionEnabled Enables/disables the automation
insightExtractionSchedule Cron expression for when extraction runs (default: "0 2 * * *" = daily at 2 AM)
insightExtractionMinIntervalMs Minimum time between extractions (default: 24 hours)

Safety Guarantees

  • Pruning validation: Before pruning is applied, the candidate is validated to ensure it preserves at least 2 of 3 required sections (Architecture, Conventions, Pitfalls). Invalid candidates are safely ignored.
  • Graceful failures: Malformed AI output does not destroy existing memory. Prior files are preserved.
  • Isolated processing: Post-run callback errors are logged but do not flip successful runs to failed.
  • Startup sync: Automation schedule is synchronized before the cron runner starts, preventing stale config races.
  • Non-destructive by default: If the AI produces no prune candidate or validation fails, working memory remains unchanged.

Configuration Example

{
  "settings": {
    "insightExtractionEnabled": true,
    "insightExtractionSchedule": "0 2 * * *",
    "insightExtractionMinIntervalMs": 86400000
  }
}

Cron Expression Format

Standard cron format: minute hour day-of-month month day-of-week

Expression Meaning
0 2 * * * Daily at 2:00 AM (default)
0 */6 * * * Every 6 hours
0 9 * * 1 Weekly on Monday at 9:00 AM

Scheduling Scope

Fusion supports scoped automations and routines:

  • Global scope (scope: "global") — Executes across all projects. Useful for backups, insight extraction, and cross-project maintenance.
  • Project scope (scope: "project") — Executes within a single project only. Useful for project-specific CI, tests, and deployments.

Defaults and resolution:

  • When scope is omitted, Fusion treats the entry as project scope with projectId: "default".
  • Global-scope entries ignore projectId.
  • Project-scope lookups require projectId; missing values fall back to "default".

Settings that interact with scheduling:

  • autoBackupEnabled / autoBackupSchedule — Backup automation respects scope like any other scheduled task.
  • insightExtractionEnabled / insightExtractionSchedule — Insight extraction can be configured as global or project-scoped.