compact | Master: enabled, cacheTtlSecs (default 300, max 900). Trim ratios: softTrimRatio (default 0.50), hardClearRatio (default 0.70). Reactive microcompact: reactiveMicrocompactEnabled (default true), reactiveTriggerRatio (default 0.75, range 0.50–0.95). Tool-result trimming: toolPolicies (HashMap mapping tool name → eager/protect), maxToolResultContextShare (default 0.3, range 0.1–0.6), minPrunableToolChars (default 20000), softTrimMaxChars / softTrimHeadChars / softTrimTailChars (default 6000/2000/2000), hardClearEnabled, hardClearPlaceholder. Recent boundary: preserveRecentRounds (default 4, range 1–12; protects recent message rounds, expands to the owning user turn only when that does not swallow prior execution rounds). Tier 3 summary: summarizationModel (provider:model override), summarizationThreshold (default 0.85), summarizationTimeoutSecs (default 60), summaryMaxTokens (default 4096), maxHistoryShare (default 0.5), maxCompactionSummaryChars (default 16000, range 4000–64000), maxCompactionInjectedContextShare (default 0.5, clamped to maxHistoryShare; combined budget for summary + ledger + recovery), identifierPolicy (strict/off/custom), identifierInstructions, customInstructions. Recovery: recoveryEnabled, recoveryMaxFiles (default 5), recoveryMaxFileBytes (default 16384). |
session_title | enabled, providerId, modelId (null provider/model = use the chat model). When enabled, new sessions keep the first-message fallback title immediately, then run one LLM call after the first assistant reply to generate a concise title. Manual renames are never overwritten. |
memory_extract | autoExtract, extractProviderId, extractModelId, flushBeforeCompact, extractTokenThreshold (default 8000), extractTimeThresholdSecs (default 300), extractMessageThreshold (default 10), extractIdleTimeoutSecs (default 1800), enableReflection, extractClaims (default true; next-gen Dreaming structured claim dual-write (beta) — also gates the Dashboard Claims view) |
memory_selection | enabled, threshold (min candidates before LLM picks, default 8), maxSelected (default 5) |
memory_budget | totalChars (int, default 10000), coreMemoryFileChars (int, default 8000 — cap per memory.md file), sqliteEntryMaxChars (int, default 500 — cap per rendered SQLite bullet), sqliteSections.{userProfile,aboutUser,preferences,projectContext,references} (defaults 1500/2000/2000/3000/1500; userProfile was renamed from aboutYou and the system-prompt heading from ## About You to ## User Profile — the old aboutYou key is still accepted for back-compat). Priority order: Guidelines > Agent memory.md > Global memory.md > SQLite. Reducing totalChars may hide parts of memory.md from the system prompt; full content is still retrievable via recall_memory / memory_get. |
embedding_cache | enabled, maxEntries |
dedup | thresholdHigh (default 0.02), thresholdMerge (default 0.012) |
hybrid_search | vectorWeight (default 0.6), textWeight (default 0.4), rrfK (default 60.0) |
temporal_decay | enabled (default false), halfLifeDays (default 30.0) |
mmr | enabled (default true), lambda (default 0.7) |
multimodal | enabled (default false), modalities (array of image/audio, defaults to both), maxFileBytes (default 10485760 / 10MB). Requires a multimodal-capable embedding provider — enabling without one produces empty vectors silently. |
dreaming | Master: enabled (default true). Triggers: idleTrigger.{enabled,idleMinutes} (default true / 30 min), cronTrigger.{enabled,cronExpr} (default false / 0 3 * * *), manualEnabled (Dashboard "Run now" button). Promotion: promotion.{minScore,maxPromote} (default 0.75 / 5). Window: scopeDays (default 1), candidateLimit (default 50). Narrative: narrativeMaxTokens (default 2048), narrativeTimeoutSecs (default 60), narrativeModel (provider:model override; null = active chat agent). Profile: profileSynthesis.{enabled (default true), maxLinesPerScope (default 12)} (per-scope user-profile aggregation; manual runs an LLM rewrite). |
recap | analysisAgent, language (output language for AI-generated sections/titles; null/empty = follow interface language), defaultRangeDays, facetConcurrency, maxSessionsPerReport, cacheRetentionDays |
awareness | Master: enabled (default false), mode (off/structured/llm_digest, default structured). Window: maxSessions (default 6), maxChars (default 4000), lookbackHours (default 72), activeWindowSecs (default 120), previewChars (default 200). Filters: sameAgentOnly, excludeCron, excludeChannel, excludeSubagents. Refresh control: dynamicEnabled (default true), minRefreshSecs (default 20), semanticHintRegex, refreshOnCompaction. LLM digest mode (mode: "llm_digest"): llmExtraction.{extractionAgent, extractionModel, minIntervalSecs (300), maxCandidates (5), digestMaxChars (1200), concurrency (2), perSessionInputChars (2000), inputLookbackHours (4), fallbackOnError, reuseSideQueryCache}. |
knowledge_passive_recall | enabled (default true), topN (default 5, 1–20), maxChars (default 800, 100–4000), cacheTtlSecs (default 120), showSnippet (default false). Read bridge ③: each user turn injects the top accessible-KB note titles as an untrusted reference block (retrieval-only, no LLM). On by default so attached knowledge spaces feel alive immediately; incognito sessions and KBs the session isn't attached to never surface. |
knowledge_search | textWeight (default 0.4), vectorWeight (default 0.6), rrfK (default 60, 1–1000), mmrLambda (default 0.7, 0–1), candidateMultiplier (default 3, 1–10). Hybrid note_search ranking: keyword (BM25) + semantic (vector) over note chunks → RRF fusion → MMR diversity re-rank. Pure query-time, no reindex. Weights' ratio sets keyword↔semantic balance; rrfK smooths fusion; mmrLambda trades relevance vs. variety; candidateMultiplier sizes the pre-MMR pool. Defaults suit most libraries; send the defaults above to restore them. |
web_fetch | enabled, maxBytes |
web_search | providers (per-provider entries — id ∈ DuckDuckGo / Searxng / Brave / Perplexity / Google / Grok / Kimi / Tavily, enabled, apiKey, apiKey2 (Google CX), baseUrl (Searxng instance)), searxngDockerManaged, searxngDockerUseProxy, defaultResultCount (default 5), timeoutSeconds (30), cacheTtlMinutes (15), defaultCountry, defaultLanguage, defaultFreshness. Read responses redact providers[*].apiKey and providers[*].apiKey2 to "[REDACTED]", so the model can describe what's configured without seeing existing keys. Writes still flow through so the skill can help the user provision a new key, but the value won't be echoed on subsequent reads. |
issue_reporting | enabled, owner, repo, apiBaseUrl, labelsByKind.{bug,feature,improvement}, maxEvidenceChars, duplicateCheckEnabled. GitHub token is optional and stored separately in ~/.hope-agent/credentials/github-issue.json; do not ask update_settings to write it. If no token is configured, issue_report falls back to the user's authenticated gh CLI. Use Settings UI token controls or the dedicated Tauri/HTTP commands for token save/clear/test. |
deferred_tools | enabled |
async_tools | enabled, autoBackgroundSecs, maxJobSecs, maxConcurrentJobs (default: hardware-derived clamp(logical_cores − 2, 4, 16), 0 = unlimited; global cap on concurrent run_in_background jobs — each holds an OS thread; at the cap a new background request QUEUES, R7.1), maxConcurrentJobsPerSession (usize, default: hardware-derived ≈ 3/4 of the global cap, band [3,12], always below it; 0 = no per-session limit; R7.1 fairness tier — per-session share of the pool: extra jobs from the same session queue even when the global pool has room, so one session/IM chat can't monopolize every slot; auto-backgrounded jobs are counted but not refused), retryEnabled (bool, default false — opt-in; R7.4 — auto-retry a backgrounded job that fails, with exponential backoff. Only idempotent re-runnable tools (web_search / web_fetch) are ever retried — exec / image_generate and any side-effecting tool are NEVER auto-retried regardless of this switch (eligibility is a code-level allowlist); user cancels / policy denials / timeouts are never retried. Off by default because an eligible tool re-RUNS and web_search is often a paid provider, so retrying a deterministic failure would re-bill — the user opts into that), maxRetryAttempts (u32, default 3, hard-capped at 10; total attempts incl. the first run, 1 = no retry), completionMergeWindowSecs (u64, default 3, 0 = disabled; R4: when several background jobs in the same session finish within this window, their completion notifications merge into ONE injected turn instead of N billed turns — Group is the pre-merged special case), maxQueuedJobs (usize, default 256, R9; bounded wait-queue length once all concurrency slots are full — beyond it a new background request hard-rejects. NOT an "unlimited" knob: each queued job pins a live context in RAM, so it's clamped at read to [1, 4096], 0 is floored not unbounded), outputTailBytes (usize, default 8192, R9; bytes of a running background exec job's latest stdout/stderr kept for live job_status inspection — clamped at read to [256, 1048576]), wakeupMaxDelaySecs (u64, default 86400, R9; upper bound on a schedule_wakeup self-scheduled delay — the 10s lower floor is fixed/non-configurable; clamped at read to [10, 604800] (10s–7d)), wakeupMaxPendingPerSession (usize, default 5, R9; per-session cap on pending schedule_wakeup wakeups — a structural reject, not a queue; clamped at read to [1, 100]), inlineResultBytes, retentionSecs, orphanGraceSecs, jobStatusMaxWaitSecs |
timeout_policy | modelRuntimeOverrides (allow / warn / ignore_when_user_unlimited, default warn). Governs model-supplied runtime timeout arguments that can shorten or kill long-running work (exec.timeout, async job_timeout_secs, sub-agent / ACP timeout_secs, cron per-job job_timeout_secs). It does not affect short polling waits or network/connect timeouts. allow honors silently; warn honors but logs/emits metadata; ignore_when_user_unlimited ignores a positive model timeout only when the corresponding user/system runtime budget is 0 (unlimited). Positive user budgets still cap execution and model values may only tighten them. |
cron | maxConcurrent (u32, default 5, 0 = unlimited) — global cap on how many scheduled tasks (cron jobs) may execute at once. Each cron run is a full agent turn (it can spawn sub-agents / tools), so a herd of jobs all due at the same instant could otherwise spawn dozens of simultaneous LLM turns and trip provider rate limits. The scheduler acquires a slot before claiming a due job (slot-before-claim), so a job beyond the cap keeps its schedule and runs on the next 15s tick instead of skipping the occurrence. Manual run now bypasses the cap but its running marker still counts toward occupancy. jobTimeoutSecs (u64, default 0 = unlimited; positive values are clamped at read to [30, 7200]) — global per-run wall-clock budget; on expiry the run is abandoned (logged as a timeout failure) and its slot freed. A per-job override (CronJob.job_timeout_secs, set via the cron job form / manage_cron, not this settings category) takes precedence for a single long-running task; under timeout_policy.modelRuntimeOverrides = "ignore_when_user_unlimited", a positive model-supplied per-job override is ignored when the effective user/system cron timeout is unlimited. atGraceSecs (u64, default 300 = 5min; capped at read to 7 days; 0 preserved = strict, no late-fire) — late-fire grace window for one-shot at jobs: on startup an at job that came due while the app was down still fires if it's past-due by no more than this many seconds; beyond that it's marked missed. Unlike the other knobs 0 is NOT floored (it means strict miss). |
approval | approvalTimeoutEnabled (bool, default false; when false, approval waits forever and approvalTimeoutSecs is only a saved duration), approvalTimeoutSecs (seconds, default 300; used only when approvalTimeoutEnabled=true), approvalTimeoutAction (deny/proceed) |
tool_result_disk_threshold | toolResultDiskThreshold (bytes, null = default 50KB, 0 = disable) |
ask_user_question_timeout | askUserQuestionTimeoutEnabled (bool, default false; when false, ask-user questions wait forever and model-provided timeout_secs is ignored), askUserQuestionTimeoutSecs (seconds, default 1800; used only when askUserQuestionTimeoutEnabled=true; 0 also waits forever) |
plan | planSubagent (bool), plansDirectory (string or null) |
skills_auto_review | Five-gate auto-review pipeline. Trigger / quality-floor fields (enabled, promotion (draft/auto — HIGH-equivalent), cooldownSecs, tokenThreshold, messageThreshold, toolUseThreshold, correctionSignalEnabled, requireToolUse, minMessageCount, discardBlacklistDays, topKForDedup, minReuseProbability, sessionRecapThreshold, minSteps/maxSteps, candidateLimit, timeoutSecs, retentionDays, autoCuratorEnabled, autoCuratorIntervalDays) are safe to tune. ⚠️ reviewSystemOverride replaces the built-in review prompt verbatim, and extraRejectCategories appends free-form reject categories — backend gates 2/4/5 still apply but the prompt-level safety net narrows. reviewModel ("provider:model") pins a dedicated review LLM. Confirm with the user before touching the three advanced fields. |
recall_summary | enabled, minHits, contextCharBudget, timeoutSecs, maxTokens, includeHistory (Phase B'3 — opt-in LLM summarization on recall_memory output; adds one side_query per call, degrades silently on failure) |
tool_call_narration | toolCallNarrationEnabled (bool, default false). When true, the system prompt tells the model to preface every tool call with a one-sentence announcement (Claude Code style). Some models (e.g. GPT-5.4 via Codex) over-apply this and restate identical intent across consecutive tool calls, causing visible duplication — default is off so users opt in explicitly. |
teams | Special: DB rows, not AppConfig fields. read returns an array of all user-configured team templates. update uses CRUD-style values — { "action": "save", "template": {...} } or { "action": "delete", "templateId": "..." }. Saved templates become discoverable by the model via team(action="list_templates"). See "Special: teams semantics" below. |
im_auto_transcribe | Aggregate view + writer for IM-channel voice auto-transcribe. Read returns { imFallbackModel, accounts: [{ id, label, channelId, autoTranscribeVoice }] }. Write accepts { imFallbackModel?: { providerId, modelId } | null, accounts?: [{ id, autoTranscribeVoice }] } — both keys are independently optional. Enabling auto-transcribe consumes STT API quota per inbound voice message; without imFallbackModel (or stt.activeModel as fallback), the dispatcher logs a warning and forwards the original audio unchanged. Transcripts are prepended to the engine message as [Voice transcript] …\n\n (localised to cfg.language); the original audio always stays as an attachment alongside. |