AgentCliConfig class final
One DAP/1 hub snapshot shared with the app (DapHubSnapshot in
src/dap/dap_hub_snapshot.dart): the live probe outcome (connected,
agentId) plus the resolved config url and agent name (env >
.fah/packages.yaml hub: > ~/.dap/config.json > defaults —
resolved by the host through the hub client package, so lib/ stays
dart:io-free). connected false means the hub plugin is not connected
right now.
Static configuration for an AgentCli session.
Constructors
-
AgentCliConfig({required Model model, required String apiKey, required ExecutionEnv env, required String sessionRoot, String? wakeExecutable, bool folderModelStateApplies = true, String? activeCustomName, StreamFunction catalogStreamOverride(String kind, String key)?, SessionPresenceStore? presenceStore, FileSessionLeaseStore? leaseStore, SessionParseExecutor? parseExecutor, String? sessionName, Duration steeringStaleAfter = const Duration(minutes: 2), String providerKind = 'openai-completions', bool envVarIsSet(String server)?, String? envVarValue(String name)?, String? herdrEnvLookup(String name)?, Future<
void> herdrSpawn(List<String> argv)?, Future<List< modelsFetcher(String baseUrl, {required String apiKey})?, Client? modelsHttpClient, bool tuiMouseCapture = true, bool? tuiSyncOutput, bool tuiClassic = false, bool showCompactionDetails = false, StatusLineConfig? statusLine, String? agentLoadMode, String? systemPrompt, PromptOverrides? promptOverrides, InspectImageConfig? visionConfig, TranscribeAudioConfig? transcribeConfig, WebSearchConfig? webSearchConfig, SqliteEngine? sqliteEngine, LspToolConfig? lspConfig, McpToolConfig? mcpConfig, A2aConfig? a2aConfig, List<String> >FahPlugin> plugins = const [], Map<String, dynamic> pluginConfig = const {}, List<String> promptTemplateDirs = const [], String initialMode = 'code', ApprovalMode approvalMode = ApprovalMode.yolo, Set<String> alwaysAllowTools = const {}, ModelRolesResolver? modelRolesResolver, String? rolesDropNotice, SessionsConfig? sessionsRetention, ProviderQueueRuntime? providersQueueRuntime, Map<String, String> ? providerQueueEnv, TtsrConfig? ttsr, MemoryConfig? memoryConfig, RedactionPipeline? redactionPipeline, String? jobLogDir, SpillsConfig? spills, ProjectContextConfig? projectContext, ModelsConfig? modelsConfig, void onModelsConfigChanged()?, Future<void> onModelChanged(Model model)?, Future<void> onProviderChanged(String providerKind, String apiKey)?, SecureKeyCache? secureKeys, CustomProviderRegistry? customProviders, bool freshInstallProviderFlow = false, void onSecretStored(String name, String value)?, void onSecretGranted(String name, String value)?, void onModeChanged(String line)?, void onApprovalChanged()?, SkillsAccess skillsAccess = SkillsAccess.granted, bool skillsDisableShellExecution = false, bool skillsLiveRediscovery = true, Map<String, bool> skillToggles = const {}, void onSkillsAccessChanged(SkillsAccess access)?, Future<void> onSkillTogglesChanged()?, bool isShiftPressed()?, int? processId, String? homeDir, PowerAssertionLevel powerSleepPrevention = PowerAssertionLevel.idle, PowerAssertionHold powerSleepPreventionHold = PowerAssertionHold.perRun, PowerAssertionRunner? powerRunner, bool quotaBadge = false, Duration? quotaTtl, Client? quotaHttpClient, String? tuiTheme, TuiProgramHooks? tuiProgramHooks, SttyRunner? sttyRunner, Future<OpenRouterOAuthKey> openRouterOAuthExchangeFn({required String code, required String codeVerifier, String? label})?, Future<ChatGptOAuthCredentials> chatGptOAuthExchangeFn({required String code, required String redirectUri, required String verifier})?, Future<AiinConnectResult?> aiinConnectFn({void onStatus(String line)?, required String provider})?, Future<String> copilotDeviceFlowFn({String? clientId, void onStatus(String line)?})?, Future<String> copilotUserFn(String githubToken)?, Future<String?> clipboardWrite(String text)?, Future<CodeMieSsoCredentials?> codeMieSsoAuthenticateFn(String codeMieUrl, void onStatus(String message))?, Future<String?> codeMieGuidedSetupFn(String apiBase, String token, Future<String?> pickOption(String title, List<(String, String, String)> options), Future<String?> askLine(String question, {bool secret}))?, CompactionSettings? compactionSettings, CompactionEngine? compactionEngine, int? compactionJudgeBudgetSeconds, int? contextWindowCap, StuckToolConfig? stuckTool, ForegroundCallBudgetConfig? foregroundCall, int emptyHiccupRetries = 3, Duration emptyHiccupBaseDelay = const Duration(milliseconds: 500), Duration emptyHiccupMaxBackoff = const Duration(milliseconds: 8000), int headlessEmptyReplyNudges = 2, bool headlessRun = false, SubagentsConfig subagents = const SubagentsConfig(), WaitingConfig waiting = const WaitingConfig(), JobsConfig jobs = const JobsConfig(), HeadlessConfig headless = const HeadlessConfig(), SessionDeadline? deadline, bool streamThinking = false, bool noStreamThinking = false, CubeSpec? cubeSpec, String? cubeSource, CubeSettings? cubeSettings, Future<void> onCubeSettingsChanged()?, Future<void> onUserConfigFileChanged()?, Client? cubeRegistryClient, JsrRuntime extRuntimeFactory(StoredExtension ext)?, String extBootstrapJs = '$kExtTransportStdioJs\n;\n$kExtBootstrapCoreJs', bool jsExtensionsEnabled = true, Future<DapHubSnapshot?> dapHubState()?, ToolsConfig? runtimeTools, String? agentMode, bool misuseBreaker = true, AgentLoadMode loadMode = AgentLoadMode.defaultMode, Future<void> onToolsConfigChanged()?, Future<void> onDapHubConfigChanged({String? name, String? url})?, String? osName, CubeFsProbe? fsProbe, BrowserBridgeHandle? browserBridgeHandle, BrowserController? browserController, MessagingRepository? hubFabric, List<AgentCapability> agentCapabilities = const [], String? machineName, bool persistAbortedPartials = false, bool wireDump = false, bool trajectoryRequestBlobs = true, int trajectoryRequestBlobMaxMb = 50, int trajectoryRequestBlobMaxBytes = 50 << 20, int trajectoryRequestBlobTtlDays = 30, Future<void> updateCommand(String? sessionId)?, AutoUpdateMode autoUpdate = AutoUpdateMode.notify}) -
Creates an AgentCliConfig. Not const:
modelRolesResolverandcubeSettingsare mutable (the settings-hub flows create/rewrite them on demand).
Properties
- a2aConfig → A2aConfig?
-
Optional A2A remote-agent configuration (the
a2a:config section, Phase 5a). Servers connect lazily; items with the agent typea2a:<name>run against the remote agent through thetasktool. Null disables A2A.final - activeCustomName → String?
-
The saved custom provider entry the boot restored (the folder model
state's name pin, gh-1000): the CLI starts with that entry marked
active — its key slot and its name in the status bar. Null when the
boot restored no named entry.
final
-
agentCapabilities
→ List<
AgentCapability> -
Capabilities this host announces in the fabric directory (issue #27
phase 2) — from the
fabric.capabilitiesconfig section. Rendered as sub-lines of this instance'sagent_directoryentry so peers can discover what this agent can do.final - agentLoadMode → String?
-
The agent load mode label (
omp/pi/null) for the band's mode segment (defaultrenders as nothing — see StatusLineSnapshot).final - agentMode → String?
-
The resolved harness mode (issue #679,
pi_mode.dart):'pi'or null (default). Resolved by the executable — flag > env > config — and consumed by the wiring: the pi runtime tools scope pins the surface to read/write/edit/bash and the prompt composition strips every optional section.final -
aiinConnectFn
→ Future<
AiinConnectResult?> Function({void onStatus(String line)?, required String provider})? -
Test seam: overrides runAiinConnectCliFlow for
/provider aiin— CLI-level tests inject a canned connect result instead of a real browser + loopback server.final -
alwaysAllowTools
→ Set<
String> -
Tools always-allowed from previous sessions (
/allow, "approve always" answers), persisted by the embedding executable.final - apiKey → String
-
API key for the provider. Only used when no StreamFunction override
is injected into AgentCli and no modelRolesResolver covers the
default role.
final
- approvalMode → ApprovalMode
-
Initial approval mode (
/approvalswitches it at runtime). Defaults to ApprovalMode.yolo — pre-approval-model CLI behavior — while criticalbashpatterns still prompt (or are denied when non-interactive). ApprovalMode.unattended additionally skips the critical interceptor: the session never blocks, for runs without a user present.final - autoUpdate ↔ AutoUpdateMode
-
The self-update policy (issue #1377,
auto_updateyaml key), plumbed from CliConfig.autoUpdate by the host at boot. Mutable: the settings-hub flow updates it after a successful persist — the same live-override pattern as liveCompactionEngine.getter/setter pair - browserBridgeHandle → BrowserBridgeHandle?
-
The loopback browser-bridge handle (
/browser connect), implemented by the host over the WebSocket bridge server (the io lives in the executable; lib/ stays dart:io-free). Null (web hosts, plain tests) makes/browseranswer with a clean unavailable note.final - browserController → BrowserController?
-
The live browser controller (issue #23) backing the
browser_*tools. Null = no browser backend: the family stays capability-off. The controller'sattachedflag is the capability floor and itsonAvailabilityChangedhook triggers the live availability rebuild.final - catalogStreamOverride → StreamFunction Function(String kind, String key)?
-
Test-only seam: builds the stream a restore re-bind or a live
/provider switch would serve for
kind/key; null (every production boot) keeps the real catalog adapter.final -
chatGptOAuthExchangeFn
→ Future<
ChatGptOAuthCredentials> Function({required String code, required String redirectUri, required String verifier})? -
Optional override for the ChatGPT OAuth code exchange. Tests inject a
fake here so the
/provider chatgpt oauthflow can run without network. Production leaves this null and uses the real exchange endpoint.final -
clipboardWrite
→ Future<
String?> Function(String text)? -
Optional override for the platform clipboard write behind
/provider export(gh-1606): copiestextto the host clipboard; resolves to null on success, the failure reason otherwise (the text itself never surfaces). Tests inject a fake; production runswriteClipboardText(pbcopy/xclip/wl-copy/clip).final -
codeMieGuidedSetupFn
→ Future<
String?> Function(String apiBase, String token, Future<String?> pickOption(String title, List<(String, String, String)> options), Future<String?> askLine(String question, {bool secret}))? -
Optional override for the post-SSO guided project/model selection.
Tests inject a fake returning a canned model id; production runs the
real guided flow (fetch projects, fetch models, pickers).
final
-
codeMieSsoAuthenticateFn
→ Future<
CodeMieSsoCredentials?> Function(String codeMieUrl, void onStatus(String message))? -
Optional override for the CodeMie SSO browser flow
(
/provider codemie sso). Tests inject a fake returning canned credentials; production runs the localhost-callback browser flow.final - compactionEngine → CompactionEngine?
-
The effective compaction engine (issue #148), resolved by the host
(global < project <
--compaction-engineruntime flag).nullkeeps the structured engine — the default everywhere since issue #287 (classic remains the explicit rollback choice).final - compactionJudgeBudgetSeconds → int?
-
Per-call judge/summarizer budget seconds (
compaction. judgeBudgetSeconds, issue #541), resolved by the host from the user config.nullkeeps the 300s default — the knob exists for giant marathon sessions whose judge cannot answer within 300s. NOTE: the knob scales only the per-attempt budget — the whole-runtotalBudget(default 15 min) is NOT scaled, so values above 300s shorten the retry ladder.final - compactionSettings → CompactionSettings?
-
Override for the compaction thresholds (ratio-based trigger, reserve
and recent-token budgets). When
null,defaultCompactionSettingsis used (ratio 0.7, reserve 50000, keep 80000). Hosts plumb theircompaction:yaml section through this field.final - contextWindowCap → int?
-
Owner-side effective context override (
agent.contextWindowCap, issues #273/#729), threaded into the Agent (loop guard) and into every consumer of the effective window (compaction thresholds, ctx meter/footer). Below the catalog window it clamps down; above it, it raises the effective window to the served truth.null= uncapped.final -
copilotDeviceFlowFn
→ Future<
String> Function({String? clientId, void onStatus(String line)?})? -
Optional override for the whole Copilot device flow (grant + poll),
returning the GitHub token. Tests inject a fake so
/provider copilotruns without network; production runs the real flow against github.com.clientIdis the FA_COPILOT_CLIENT_ID override (null = the pinned VS Code Copilot client id);onStatusreceives the waiting lines.final -
copilotUserFn
→ Future<
String> Function(String githubToken)? -
Optional override for the GitHub account lookup behind
/provider copilot(GET api.github.com/user → login). Tests inject a fake; production calls fetchGitHubLogin.final - cubeRegistryClient → Client?
-
The
package:httpclient for the fa1.dev cube registry (/cube templates//cube install). Tests inject a mock; web hosts pass their shared browser-capable client. Null uses a freshhttp.Client().final - cubeSettings ↔ CubeSettings?
-
The live
cube:config section (the saved sandbox startup default). The settings-hub Cube sandbox flow rewrites it; the host persists the new value after onCubeSettingsChanged fires. Mutable like modelRolesResolver (CubeSettings itself is immutable).getter/setter pair - cubeSource → String?
-
Where cubeSpec came from: an explicit manifest path (contains
/) or a cube name./cube reloadre-resolves it;/cube useoverwrites it. Null when no cube was requested.final - cubeSpec → CubeSpec?
-
Optional fa_cube sandbox spec applied for the whole session (from the
--cube/--cube-configflags or thecube:config section). The execution env wraps it in a SandboxedExecutionEnv: filesystem and shell operations clamp to the cube's policies,/cubeswaps it live. Null = no cube — the env passes through untouched.final - customProviders → CustomProviderRegistry?
-
The saved custom-provider registry (the
customProviders:config section), shared with the executable: the CLI mutates it (wizard adds, per-provider model memory), the host persists it. Null (web, tests without one) disables saved providers — the wizard still switches but adds nothing to the list.final -
dapHubState
→ Future<
DapHubSnapshot?> Function()? -
Fetches one DapHubSnapshot (probe outcome in
DapHubSnapshot.connected): the resolved config url/name plus the
live connection state. File reads and the plugin status stay on the
host side (the hub client owns its IO; lib/ stays dart:io-free) —
null (tests without a fake, web) means no hub wiring exists and the
DAP / Hub flow reports the state as unavailable.
final
- deadline → SessionDeadline?
-
The session deadline clock (gh-1556): the ONE wall-clock budget
source this session projects everywhere — the per-turn
time-left:request line (Agent.budgetLineProvider), the one-shot wrap-up steering notices, the TUI countdown chip, and theFA_DEADLINE_EPOCH_MSbash env var. Injected so tests drive it with a fake clock; null (the default) builds a liveSessionDeadline(). The executable seeds it fromFA_DEADLINE_EPOCH_MS<--timer/--deadlineviaresolveSessionDeadline;/timeradjusts it live mid-session.final - emptyHiccupBaseDelay → Duration
-
gh-1577: first backoff sleep between empty-hiccup retries.
final
- emptyHiccupMaxBackoff → Duration
-
gh-1577: cap on the exponential empty-hiccup backoff.
final
- emptyHiccupRetries → int
-
gh-1577: empty-hiccup retry budget (see
AgentLoopConfig.emptyHiccupRetries).
final
- env → ExecutionEnv
-
Execution environment backing the built-in tools and session storage.
final
- envVarIsSet → bool Function(String server)?
-
Reports whether an environment variable is set (non-empty) on the
host. The startup banner uses it to name the provider key env var in
play — the name only, never the value. Null (tests, web) behaves as
"unset", so the banner then warns instead of naming a var.
final
- envVarValue → String? Function(String name)?
-
Reads an environment variable's value on the host (null/empty treated
as unset).
/provideruses it to resolve the target provider's API key from its catalog env names when no explicit token is passed. Null (tests, web) means no key is ever found this way.final - extBootstrapJs → String
-
Engine bootstrap source evaluated before each extension's
main.js(transport + core fromext_bootstrap_js.dart; the stdio transport default matches the qjs-process engine).final - extRuntimeFactory → JsrRuntime Function(StoredExtension ext)?
-
Creates the JS engine for one stored extension (issue #32). The host
executable injects the
QjsProcessRuntimefactory fromlib/io.dart; tests inject aFakeJsrRuntimefactory. Null keeps JS extensions disabled regardless of jsExtensionsEnabled.final - folderModelStateApplies → bool
-
Whether the saved per-folder model memory may override the resolved
config for session loads (bin/fah.dart computes it from the launch
pins: --model/--provider/--base-url and the FA_PROVIDER_* preconfig
disable it). Defaults to true so tests and embedded hosts behave like
an unpinned launch.
final
- foregroundCall → ForegroundCallBudgetConfig?
-
Foreground tool-call budget (
agent.foregroundCallBudgetSeconds+agent.foregroundCallAutoConvert, issue #1786), a pass-through into the Agent — defaults live in ForegroundCallBudgetConfig.fromLeaves/the loop.null= unconfigured (the loop's defaults apply).final - freshInstallProviderFlow → bool
-
Fresh-install boot (issue #969): the executable computed that NOTHING
is configured — no saved custom providers, no persisted provider
switch, and no key resolving anywhere (env or the secure store) — and
this is an interactive REPL boot. The REPL then opens the guided
add-provider wizard (the same flow
/provider customopens) before the first prompt. Never set for headless runs; the CLI re-checksCliIO.isInteractive, so piped input never sees the wizard either.final - fsProbe → CubeFsProbe?
-
The symlink probe for the cube fs guard, supplied by the executable
(
LocalCubeFsProbeon IO hosts — lib/src stays dart:io-free). Null (tests, web) keeps the guard on the lexical traversal check.final - hashCode → int
-
The hash code for this object.
no setterinherited
- headless → HeadlessConfig
-
The
headless:section (gh-1459): the wall-clock ceiling (shellJobDrainMs, default 30 min; 0 = off) for the headless background-job drain after the final answer.final - headlessEmptyReplyNudges → int
-
gh-1603: the empty-reply
continuenudge budget for HEADLESS runs. Interactive keeps the issue #1085 M2b one-nudge semantics (a user is present to re-ask); an unattended run retries the blank longer — the session may end only after1 + headlessEmptyReplyNudgesconsecutive unrecoverable empties, and then the exit is the explicit__FA_INCOMPLETEfailure (never a clean 0).final - headlessRun → bool
-
Whether this process drives a headless run (
fah run "<prompt>"and friends) as opposed to an interactive REPL/TUI session. Set by the executable's dispatch. Does NOT select the supervision default: since gh-1632 the autonomous default applies in EVERY mode andadvisoryis reachable only via explicitagent.stuckTool:config (the gh-1054 interactive-advisory default branch is gone).final - herdrEnvLookup → String? Function(String name)?
-
Reads a herdr pane env var on the host (issue #1481): the herdr pane
reporter's whole gate input (
HERDR_ENV,HERDR_PANE_ID,HERDR_BIN_PATH, plus theFA_HERDR=0kill switch). herdr exports the vars to every pane process, so the CLI's own process env is the right source. Null (tests, web) = every var unset — the reporter is constructed inert and spawns nothing. lib/src stays dart:io-free; the executable injects thePlatform.environmentlookup.final -
herdrSpawn
→ Future<
void> Function(List<String> argv)? -
The herdr pane reporter's transport (issue #1481): one fire-and-forget
spawn of
$HERDR_BIN_PATH pane …per report, cut by the reporter's short timeout, silent on failure. The executable injects aProcess.run-backed closure (lib/ stays dart:io-free); null (tests without a recorder, web) keeps the reporter spawn-free even behind an active gate.final - homeDir → String?
-
The user's home directory, when the host has one (used for user-level
skill/context discovery:
~/.fah/skills,~/.fah/AGENTS.md). Null on sandboxed hosts (web) where only the project FS exists.final - hubFabric → MessagingRepository?
-
Hub-backed primary for the agent messaging fabric (issue #27 phase 1).
When set, the fabric routes hub-resolvable recipients through it and
falls back to the file inboxes (offline queue + forward on reconnect);
the hub identity's mail merges into the main inbox drain. The
implementation is IO-bound (DAP WebSocket) and lives bin-side — hosts
inject it here. Null (default) keeps the pure file fabric.
final
- initialMode → String
-
Initial mode name (
code,architect,review).final - isShiftPressed → bool Function()?
-
Host-provided Shift modifier check (e.g. macOS Core Graphics via FFI).
When null, Shift+Enter is not specially handled.
final
- jobLogDir → String?
-
Where the bash-job registry writes job logs (issue #1408 AC1); null
keeps
<cwd>/.fah/bash_jobs. The bench boot resolvesFAH_JOB_LOG_DIR(jobLogDirOverride) so unattended runs keep harness artifacts outside the graded task workspace.final - jobs → JobsConfig
-
The
jobs:section (issue #478): boot-maintenance knobs for the cross-run shell-job state (manifest age belt + log GC), plus themaxLogBytesper-log ceiling (issue #919).final - jsExtensionsEnabled → bool
-
Master switch for JS extensions. Effective only together with a
non-null extRuntimeFactory — both must be on for extensions to load.
final
- leaseStore → FileSessionLeaseStore?
-
Session-ownership leases (issue #428): the store this CLI acquires
its session's
_owner.jsonlease through. Null (tests, web) disables ownership — today's unenforced multi-writer behavior.final - liveCompactionEngine ↔ CompactionEngine?
-
Live compaction-engine override set by the settings-hub Compaction
flow (session scope, or after a yaml write). Wins over the
boot-resolved compactionEngine for the rest of the session.
NEVER persisted by the host config save: the session scope promises
"no file change", and the project/global scopes write their yaml
through the targeted upsert themselves — the whole-file save keeps
the on-disk
compaction:block untouched instead. Mutable by design — the same live-override pattern as modelRolesResolver.getter/setter pair - loadMode → AgentLoadMode
-
The tool-load preset for this boot (issue #680): resolves
--omp>FA_AGENT_MODE>agent.mode. AgentLoadMode.defaultMode keeps every present tool in the schema (byte-identical behavior).final - lspConfig → LspToolConfig?
-
Optional LSP configuration enabling the
lsptool (diagnostics / definition / references / rename). Pass a config with the process transport factory fromlib/io.darton native hosts; leave null on web (the tool is not registered).final - machineName → String?
-
This host's machine name for
name@machineaddressing (issue #27 phase 2): a@machinesuffix matching it is stripped before local resolution; other machines are phase-3 A2A territory. Null when the hostname is unavailable.final - mcpConfig → McpToolConfig?
-
Optional MCP configuration (the
mcp:config section). Servers connect lazily in the background at startup; each advertised tool is registered asmcp__<server>__<tool>(exec approval tier) and the system prompt gains a tiny server-status section. Stdio servers need the process transport factory fromlib/io.dart; remote (HTTP) servers work on every host. Null disables MCP.final - memoryConfig → MemoryConfig?
-
Optional
memory:section of~/.fah/config.yaml— long-term memory storage path overrides (git-backed project memory). Null = the historical.fah/memorylayout.final - misuseBreaker → bool
-
The tool-misuse circuit breaker switch (
agent.misuseBreaker, issue #862, default true): wired into the Agent and every spawned child.falsedisables it everywhere — byte-identical to the pre-breaker harness (E5).final - model → Model
-
The model to run.
/model <id>swaps the id at runtime.final - modelRolesResolver ↔ ModelRolesResolver?
-
Optional model-roles resolver (roles/fallback chains/key rotation from
the CLI config). When set and its
defaultrole resolves, the agent runs through the resolver's fallback stream instead of the plain providerKind/apiKey wiring, compaction summarizes through thesmolrole, and/modelrenders the roles overview. Mutable: the settings-hub agent-models flow creates one on demand when the config had noroles:section (auxiliary roles resolve lazily; the default chain stays untouched).getter/setter pair - modelsConfig → ModelsConfig?
-
The live models config (the
models:section of~/.fah/config.yaml), shared with the executable:/models set//models removemutate its media slot overrides and/model <name>resolves its custom model definitions; the host persists it after onModelsConfigChanged. Null (web, tests without one) disables the models-config commands.final -
modelsFetcher
→ Future<
List< Function(String baseUrl, {required String apiKey})?String> > -
Fetches model ids from an OpenAI-compatible
/modelsendpoint (the/modelspicker and the custom-provider flow). Null uses the built-in HTTP implementation; tests inject a fake.final - modelsHttpClient → Client?
-
HTTP client override for the non-OpenAI model-list dialects the
settings flows dispatch to (DIAL deployments, CodeMie
/llm_models) — modelsFetcher only covers the OpenAI shape. Null (production) lets the fetchers create their own client; tests inject aMockClient.final - noStreamThinking → bool
-
The
--no-stream-thinkinghatch (gh-1433): thinking-scoped silence — on the log face (headless runs stream thinking by default since gh-1433) it restores the legacy thinking silence for the run. The arg parser rejects it together with--stream-thinking.final - onApprovalChanged → void Function()?
-
Called when the approval state changes (
/approval,/allow, or an "approve always" prompt answer) so the executable can persist it.final -
onCubeSettingsChanged
→ Future<
void> Function()? -
Called when the saved cube default changes (the settings-hub Cube
sandbox flow) so the executable can persist it. The flow awaits the
hook before confirming, so persistence lands with the feedback line.
final
-
onDapHubConfigChanged
→ Future<
void> Function({String? name, String? url})? -
Persists a changed hub url / agent name (the settings-hub DAP / Hub
flow) through the hub client's
~/.dap/config.jsonread-modify-write — the single authority for that file's format. Null (tests without a fake, web) keeps the change session-only.final - onModeChanged → void Function(String line)?
-
Called when the user switches the active mode via
/mode,/code,/architect, or/review.final -
onModelChanged
→ Future<
void> Function(Model model)? -
Called when the user switches the active model via
/model.final - onModelsConfigChanged → void Function()?
-
Called when the models config changes (
/models set,/models remove) so the executable can persist it.final -
onProviderChanged
→ Future<
void> Function(String providerKind, String apiKey)? -
Called when the user switches the active provider via
/provider(legacy wiring only; roles mode reports through onModelChanged). Carries the new provider adapter kind and the resolved API key so the executable can redact an explicitly passed token and persist the provider/model/baseUrl triple. The key may be empty (keyless custom endpoints); it is never persisted by the executable.final - onSecretGranted → void Function(String name, String value)?
-
Called when the agent requests a secret via the
request_secrettool and the user grants it, so the executable can redact the value from tool results and inject it into the shell environment.final - onSecretStored → void Function(String name, String value)?
-
Called when the user stores a secret via
/key set, so the executable can redact the value from tool results and session files.final - onSkillsAccessChanged → void Function(SkillsAccess access)?
-
Called when the skills-access consent changes (startup prompt,
/skills access ...) so the executable can persist it.final -
onSkillTogglesChanged
→ Future<
void> Function()? -
Called when a global per-skill toggle changes
(
/skills NAME global, the settings-hub Skills flow) so the executable can persist the live toggles (AgentCli.globalSkillToggles).final -
onToolsConfigChanged
→ Future<
void> Function()? -
Called when the user changes the GLOBAL
tools:scope (/tools enable|disable <id> global) so the executable can persist the CLI's live global view (globalTools). Null keeps the change session-only.final -
onUserConfigFileChanged
→ Future<
void> Function()? -
Called after a settings-hub flow wrote the USER config file
directly — every sanctioned write that bypasses the host's
whole-file save: the surgical validated-yaml upserts (user-scope
wins), the drop-key / clear-key edits, the ttsr block replace and
the mcp block replace (the roster lives on
SettingsConfigSyncFlow._notifyUserConfigFileChanged). Hosts holding a boot-time snapshot of the user config re-read it here so their next whole-file save renders the freshest on-disk truth instead of re-rendering the stale boot values OVER the flow's write (gh-1572 rework). Null (tests, web) makes the writes one-way.final -
openRouterOAuthExchangeFn
→ Future<
OpenRouterOAuthKey> Function({required String code, required String codeVerifier, String? label})? -
Optional override for the OpenRouter OAuth code exchange. Tests inject a
fake here so the
/provider openrouter oauthflow can run without network. Production leaves this null and uses the real exchange endpoint.final - osName → String?
-
The host OS name (e.g.
linux,macos), supplied by the executable — lib/src stays dart:io-free./cubeuses it to describe the OS sandbox backend. Null (tests, web) reports a generic passthrough instead.final - parseExecutor → SessionParseExecutor?
-
Off-isolate session record parsing (issue #503 boot cost): the IO
host injects
IsolateSessionParseExecutor(exported fromlib/io.dart) so a marathon resume decodes its multi-hundred-MB tail core-wide instead of stalling the UI isolate; null (tests, web) keeps the inline batched path.final - persistAbortedPartials → bool
-
Backend agent mode (issue #155): persist aborted assistant partials
so a SIGTERM/SIGINT graceful cancel leaves a resumable JSONL (the
cancelledHEP frame's counterpart on disk). Default false: the REPL keeps discarding incomplete streams.final -
pluginConfig
→ Map<
String, dynamic> -
Per-plugin configuration from
.fah/packages.yaml(keyed by plugin name).final -
plugins
→ List<
FahPlugin> -
Plugins to register at startup.
final
- powerRunner → PowerAssertionRunner?
-
The platform sleep-prevention runner (host-injected through
lib/io.dart'shostPowerRunner). Null disables assertions entirely — the test runtime and web hosts pass no runner, so no unit test ever spawns a realcaffeinate.final - powerSleepPrevention → PowerAssertionLevel
-
The effective
power.sleepPreventionlevel (issue #325): what the held sleep-prevention assertion asks the platform for. Defaults to PowerAssertionLevel.idle like oh-my-pi.final - powerSleepPreventionHold → PowerAssertionHold
-
When the sleep-prevention assertion is held (
power.hold, #326): per-run by default — acquired at run start, released at settle, so an idle agent never pins the machine awake; PowerAssertionHold.session is the explicit hold-the-whole-session opt-in.final - presenceStore → SessionPresenceStore?
-
Live-session presence heartbeats: the running CLI registers its
session here so the Fa app (sharing the sessions root) can mark the
session live and attach to it. Null (tests, web) disables presence.
final
- processId → int?
-
The host process id (diagnostics on the presence heartbeat). Null
where the platform exposes no pid (web).
final
- projectContext → ProjectContextConfig?
-
The resolved
projectContext:section (issue #1761) — the merged project-context budget. Null = the 32KB default;maxBytes: 0disables the section and skips every file read.final - promptOverrides → PromptOverrides?
-
Prompt overrides from the CLI config
prompts:section (resolved by the executable viaresolvePromptOverrides). Replaces the mode system prompts (cli/mode_*names — startup and/modeswitches) and the compaction summarization prompts (compaction/*names). Null or empty keeps the built-in prompts byte-identical.final -
promptTemplateDirs
→ List<
String> -
Directories to scan for
/nameprompt templates (.mdfiles).final - providerKind → String
-
Provider adapter kind:
openai-completions,anthropic, orgoogle.final -
providerQueueEnv
→ Map<
String, String> ? -
The environment view the provider-queue scope resolves through
(issue #418 + #675): the queue editor re-resolves the winning scope
before a write, and it MUST see the same env the boot saw — an
ambient
FA_PROVIDERS_QUEUEon the host process (the ai-teammate runner exports one) must not decide test/embedder fate after the host booted with its own view. Null = the process environment (the production boot reads it directly, so behavior is unchanged).final - providersQueueRuntime ↔ ProviderQueueRuntime?
-
The provider-queue runtime (issue #418): when set, the default role
resolves through the queue's stream function — sticky cursor, loud
failover on provider death. Wins over the roles resolver's default
chain; auxiliary roles (smol/slow/plan) keep resolving independently.
Mutable for the same live-override reasons as modelRolesResolver.
getter/setter pair
- quotaBadge → bool
-
Status-line provider-quota badge (
quota.badge, issue #823): default OFF (OQ2 lean) — the status line stays quiet until the user opts in.final - quotaHttpClient → Client?
-
Injectable http client for the quota adapters (issue #823): tests
inject a MockClient here; production shares the keep-alive provider
client. Null = shared client, no IO is made until a surface peeks.
final
- quotaTtl → Duration?
-
Quota-cache TTL override (
quota.ttl_minutes, issue #823). Null keeps the service's 15-minute default.final - redactionPipeline → RedactionPipeline?
-
The layered redaction pipeline (issue #24), assembled by the host
startup from the
redact:config + this process's secrets. When set, the CLI attaches its hooks to the agent (tool-result masking, blockMode credential-file denies) and masks user prompt text at the entry points; null = redaction hooks stay off (only the legacy SecretRedactor exact-value masking runs).final - rolesDropNotice → String?
-
The roles-drop warning text (issue #1552 AC4), or null: the gh-760
boot boundary degraded the whole
roles:config — the line surfaces in the notice stream (line mode + the TUI transcript after the banner), never stderr-only.final - runtimeTools → ToolsConfig?
-
The RUNTIME
tools:availability scope — the--toolsflag value, or the parsedFA_TOOLSenv twin when the flag is absent (deepest of the config scopes the wiring stacks: global, project, session, runtime, then the builtin capability floor). Null when neither source declared intent.final - runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- secureKeys → SecureKeyCache?
-
The platform secure-storage cache (macOS Keychain / Secret Service /
Windows Credential Locker), preloaded by the host at startup. Backs the
/keycommand and lets/provider ... <token>persist the token. Null (web, tests) disables secure storage: tokens stay session-only.final - sessionName → String?
-
Optional session name to resume or create on startup.
final
- sessionRoot → String
-
Root directory for JSONL sessions (cwd-encoded layout, like pi).
final
- sessionsRetention → SessionsConfig?
-
The
sessions:section (gh-1746), null when absent. Drives the boot retention check: sweep/note only what the user configured.final - showCompactionDetails → bool
-
The compaction-report detail opt-in (
tui.showCompactionDetails, gh-1636, default false): an auto-compaction pass prints ONE short marker line, the internal checkpoint summary stays out of the console, and the headless log face stops streaming the summarizer deltas (the gh-1433 E4 stream becomes opt-in — the gh-1430 E3… reasoningliveness line still covers the window).truerestores the full report block and the live delta stream. Nothing is lost by default: the summary stays in the session file and is reachable viacompact_expand. The manual/compactreport always renders details.final - skillsAccess → SkillsAccess
-
Consent for discovering third-party skill roots (Claude/Copilot/Codex
directories). SkillsAccess.granted is the default (opt-out discovery —
migrating users keep their existing skills with zero setup);
SkillsAccess.ask makes an interactive host prompt once at startup
(persisted via onSkillsAccessChanged); a headless run treats
askas denied. Own roots (.fah/skills,.agents/skills) are always discovered.final - skillsDisableShellExecution → bool
-
When true,
!command`` shell injections inside skill bodies are not executed; the placeholder renders as a disabled note instead.final - skillsLiveRediscovery → bool
-
Whether the per-composition skills freshness check runs (gh-1440,
skills.liveRediscovery). On by default — a skill landing on disk mid-session joins the index at the next prompt recomposition and/skill:cold-resolves misses.falsereturns to boot-snapshot semantics with the prompt's staleness footer;/skills reloadand cold-resolve stay available either way.final -
skillToggles
→ Map<
String, bool> -
The GLOBAL per-skill on/off toggles (
skills:section of~/.fah/config.yaml, issue #1151): skill name → enabled. The CLI seeds its live view from this at first resolution;/skills NAME globalmutates the live view and the host persists it through onSkillTogglesChanged.final - spills → SpillsConfig?
-
The resolved
spills:section (issue #678) — project yaml wins over the user one, wholesale. Null or inactive (enabled: false/threshold: 0) = no spill hooks attached, byte-identical legacy.final - sqliteEngine → SqliteEngine?
-
Optional SQLite engine enabling
readtargets likedata.db:table. Pass the FFI-backed engine fromlib/io.darton native hosts; leave null on web (SQLite reads then return a clean "not supported" note).final - statusLine → StatusLineConfig?
-
The parsed
tui.statusLinesection; AgentCli resolves it once into the status-line engine the composer's top band renders.final - steeringStaleAfter → Duration
-
How long a busy run may stream NO agent events before mid-run
steering panels flip to
dead(issue #437 E4): honest tool work streams events continuously, so only a wedged run (the #355 mid-thinking family) crosses this threshold. A late delivery fromdeadstays possible — dead means "not responding", not "lost".final - streamThinking → bool
-
The effective gh-1198 thinking-stream setting for the run
(
--stream-thinkingflag OR theoutput.streamThinkingconfig, resolved by the host): line-mode/headless runs print thinking deltas dimmed, live, like the TUI. False — the default — keeps the byte-identical legacy output and enables the reasoning-phase liveness line instead.final - sttyRunner → SttyRunner?
-
Injected
sttyrunner (issue #735): routes BOTH the TUI's boot-time termios sanitize and the TermiosGuard's post-tool-phase re-asserts through a fake — headless tests model the tty with it. Null in production (realsttysubprocesses; the guard no-ops without a terminal, so non-TUI hosts are unaffected).final - stuckTool → StuckToolConfig?
-
Stuck-call supervision (
agent.stuckTool, gh-1054): liveness heartbeats for long-running tool calls plus the autonomous cancel/retry/convert follow-up.null= unsupervised (the loop runs byte-identically to before).final - subagents → SubagentsConfig
-
The
subagents:section (issue #383): heartbeat cadence and stall threshold for background-subagent status digests.final - systemPrompt → String?
-
System prompt override; defaults to defaultAgentCliSystemPrompt.
final
- trajectoryRequestBlobMaxBytes → int
-
The same budget in bytes (TrajectorySection.requestBlobMaxBytes
threaded through CliConfig at boot, gh-1745 rework): the blob
store consumes this instead of re-shifting MB inline.
final
- trajectoryRequestBlobMaxMb → int
-
trajectory.requestBlobMaxMb— the per-session blob-dir byte budget (default 50 MB).final - trajectoryRequestBlobs → bool
-
gh-1745 request-blob spilling (
trajectory.requestBlobsyaml, default true): the heavy half of every request capture — per-message previews/block texts, the raw wire dump — is persisted to.fah/trajectories/<sid>/requests/instead of the session JSONL, whosemodel_request_summaryrecord keeps lightweight metadata plus aspillFilepointer.falserestores the legacy inline persistence byte-identically.final - trajectoryRequestBlobTtlDays → int
-
trajectory.requestBlobTtlDays— blob age bound (default 30 days).final - transcribeConfig → TranscribeAudioConfig?
-
Optional transcription endpoint configuration. When provided, the
transcribe_audiotool is registered and routes audio transcription to a Whisper-compatible endpoint.final - ttsr → TtsrConfig?
-
Optional TTSR configuration (stream rules from the CLI config and the
project rules file). When set and enabled, a TtsrController watches
the agent's streams and drives abort/inject/retry on rule matches.
final
- tuiClassic → bool
-
The classic-chrome kill switch (
tui.classic, #806):truepins the legacy TUI composer — the─rule, the bare input zone and the dim one-line status footer — byte-identically, and disables the omp status band (theimages.registry: falseprecedent).final - tuiMouseCapture → bool
-
Whether the TUI captures the mouse for wheel scrolling. Default true:
the session renders in the alternate screen, where the terminal has no
native scrollback — without capture a two-finger scroll does nothing
and the user cannot reach earlier output. Selection still works via
the terminal's bypass modifier (Shift in most).
FA_TUI_MOUSE=0opts out for always-on native select-to-copy.final - tuiProgramHooks → TuiProgramHooks?
-
Headless TUI test hooks (scripted key bytes, captured frames) handed to
the TUI controller — null in production, where the dart_tui program
reads stdin and renders to the real terminal.
final
- tuiSyncOutput → bool?
-
DEC 2026 synchronized output tri-state for the TUI. Null (default) =
auto-detect via DECRQM;
FA_TUI_SYNC=1forces BSU/ESU framing for terminals that support ?2026 but not the query;FA_TUI_SYNC=0forces legacy writes (deterministic fallback path).final - tuiTheme → String?
-
Persisted TUI theme name (
tui.theme, issue #279): a built-in key or a user theme file stem.null/unknown → default theme at boot.final -
updateCommand
→ Future<
void> Function(String? sessionId)? -
The
/updateslash-command seam (issue #1377): the self-update engine lives in the host executable (bin/self_manage.dart) and lib/src stays dart:io-free, so the host injects a closure that checks, applies, spawns the successor and exits(0) on success — and prints + stays alive on any failure.String? sessionIdis the LIVE session to resume (resolved by the caller): the successor argv gains--session <id>when the argv does not already carry one, so the running conversation survives the restart. Null (tests, embedded hosts): the command reports the surface as unavailable.final - visionConfig → InspectImageConfig?
-
Optional vision model configuration. When provided, the
inspect_imagetool is registered and routes image analysis to a dedicated model.final - waiting → WaitingConfig
-
The
waiting:section (issue #450): visible-waiting heartbeat cadence, the--wait-for-jobsceiling, and the per-call foreground liveness thresholds (gh-1055).final - wakeExecutable → String?
-
Executable used to WAKE an asleep cross-session mailbox: agent_message
spawns
nohup <wakeExecutable> --session <name> "<prompt>"detached in the target's cwd so a sleeping agent processes its inbox now (a later interactive start resumes the same session). Null falls back tofaon PATH.final - webSearchConfig → WebSearchConfig?
-
Optional web search configuration. When provided,
web_searchandweb_fetchare registered (see builtinTools); keyless DuckDuckGo works with all defaults, keyed providers read their API keys from the config's SecretsStore.final - wireDump → bool
-
Opt-in raw wire dumps (issue #385 F5,
trajectory.wireDumpyaml, default false): when on, the full outbound request payload is captured per request, redacted through the active pipeline, capped, and persisted as atrajectory_wire_dumpsession record.final
Methods
-
effectiveStuckTool(
) → StuckToolConfig -
The effective stuck supervision for THIS host (gh-1054, gated per
gh-1632 I1): an explicit
agent.stuckTool:wins everywhere; otherwise the autonomous default applies in EVERY mode — interactive REPL/TUI sessions included. The implicit interactive-advisory branch (gh-1054 review) is what left the gh-1632 incident session hanging 27 minutes on a deadgit fetch: the stuck flag fired, no escalation ever followed.advisorystays reachable ONLY via explicit config (agent.stuckTool.followUp: advisory). -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited