On this page

Choose the right place

LocationPurpose
~/.haskell-agent/config.jsonMachine-wide harness configuration: theme, MCP, web fetching, LSP, worktrees, and agent concurrency
~/.haskell-agent/models.jsonAdditional model definitions and endpoint connections
<checkout>/.haskell-agent/settings.jsonRemembered checkout choices and approval policy; see persisted settings
~/.haskell-agent/settings.jsonUser model, title-model and terminal preferences
Process environmentCredentials and explicit transport/helper overrides; see environment variables
AGENTS.mdRepository instructions for the model, not a JSON settings file
Launch argumentsExplicit choices for this invocation, such as model, working directory, and interface

version must be the integer 1. Boolean settings take JSON true or false, not quoted strings. Both inactivityDays and an explicitly configured maxConcurrentAgents must be integers of at least one. Omitting the concurrency limit leaves it unspecified at machine scope; it does not override a project or launch setting.

Configuration boundaries and precedence

Do not treat every configuration source as one merged JSON tree. config.json configures the harness, models.json defines model connections, and AGENTS.md supplies model instructions. Putting a JSON option in AGENTS.md does not configure the runtime.

For concurrent agents, the explicit CLI limit wins over the project limit, which wins over the machine limit. For model selection and connection definitions, use the model guide. For instruction discovery, use project instructions.

Web-fetch settings

These settings control the harness's client-side web-fetch capability. They are not a general firewall for shell commands, MCP servers, or provider-hosted browsing.

Field under webFetchType / defaultConstraints
enabledBoolean / falseMust be enabled before requests can run
allowedDomainsString array / emptyAn empty list denies all requests; entries must not be blank
timeoutSecondsInteger / 601–300 seconds
maxContentBytesInteger / 104857601–52428800 bytes; maximum fetched content
maxInlineBytesInteger / 1000001–1048576 bytes and no greater than maxContentBytes; inline result limit

Merge this section into your existing configuration to permit a specific documentation host:

{
  "version": 1,
  "webFetch": {
    "enabled": true,
    "allowedDomains": ["haskell.org"],
    "timeoutSeconds": 30,
    "maxContentBytes": 1048576,
    "maxInlineBytes": 50000
  }
}

Restart the session after a manual edit and request an actual fetch of a page at https://haskell.org/. Inspect the tool result rather than accepting a response generated from model knowledge. A different host is not authorized merely because it belongs to the same organization. Keep the allowed host list narrow.

Language-server settings

lsp.enabled defaults to false and lsp.servers defaults to an empty object. Each key under servers names one local language-server process. Install the executable through your project's Nix development environment before enabling it.

Server fieldType / defaultPurpose
commandRequired stringExecutable to launch; must not be blank
argsString array / emptySeparate arguments; not a shell command string
envString-to-string object / emptyEnvironment overrides; values are redacted from diagnostics
extensionToLanguageRequired nonempty string-to-string objectMap filename extensions to language identifiers; neither keys nor values may be blank
initializationOptionsOptional JSONServer-specific initialization payload
settingsOptional JSONServer-specific workspace settings
workspaceFolderOptional stringExplicit workspace folder
startupTimeoutMillisecondsInteger / 15000Startup deadline; 1–120000 milliseconds
shutdownTimeoutMillisecondsInteger / 5000Shutdown deadline; 1–120000 milliseconds

Only stdio transport is supported. Do not copy configurations that require restartOnCrash: true or maxRestarts: the loader rejects them. Server settings depend on the language server, not the agent.

Language server workspace folder

Omitted workspaceFolder uses the active workspace. A relative value such as packages/api is resolved beneath that workspace, not beneath ~/.haskell-agent. The folder must already exist. Both paths are canonicalized, and a folder outside the active workspace is rejected, including a symlink that escapes it.

Each configured server receives one resolved root URI and a one-element workspace-folder list. This field is a string, not a multi-root array. Configure separate named server entries when different contained subdirectories need separate roots. An invalid workspaceFolder error means check existence/path permissions; an “inside the active workspace” error means choose a contained directory rather than relaxing unrelated tool approvals.

MCP settings

mcpServers maps names to local commands or remote URLs. Each entry must configure exactly one of those transports. The MCP field reference covers timeouts, OAuth, environment values, protocol selection, and optional capabilities.

For guided changes, use /meta. The Meta Console validates and previews supported configuration changes before applying them. Preserve unrelated settings when editing files manually.

MCP identity, credentials and lifecycle

Remote connectionId values must be nonempty, at most 128 characters and contain only lowercase ASCII letters, digits and hyphens. They identify connections, not display labels. Preserve generated identities; do not copy an identity from another connection to reuse its credentials.

If connectionCredentials is absent, it defaults to whether connectionId is present. Explicit false retains CLI-configured credentials; true selects managed connection credentials. Automatic migration of a legacy remote entry generates an identity and generation, sets this flag to false and fills a missing display name from its catalog label. Migration therefore does not silently move legacy authorization into the protected store.

connectionGeneration distinguishes lifecycle revisions. Managed authorization and enable/disable operations replace it; callbacks for an older generation must not restore a replaced or disabled connection. Use the management interface to authorize, disable or remove connections, rather than manually restoring an old generation. A failed migration requires repairing private configuration write access and retrying, not deleting all credentials. Refresh a stale management preview before saving.

For local servers, omitted cwd uses the workspace passed to MCP startup. An explicit value is passed to the process launcher unchanged; a relative value is relative to the agent process working directory, not the directory containing config.json. Prefer an absolute path when a server must start in a fixed directory.

MCP sampling limits

Enabling sampling allows a server to request an isolated one-shot completion using the active model/backend. Requests need at least one message and support only user/assistant roles with text strings, text-content objects or arrays of text content. Images and other content types are rejected. The system prompt and optional temperature are forwarded; the requested maximum output token count is clamped to at least one and remains subject to provider limits.

The main conversation is not shared: previous response state is cleared, tools and parallel tool calls are disabled, and provider storage is requested off where supported. A generated tool call, empty response or provider error rejects the request. Context/model preference hints do not switch the active model or import workspace context. Usage belongs to the active model's configured credential/billing route, not a free allowance supplied by the MCP server. Leave sampling disabled for untrusted servers.

Machine settings

The file is JSON, with quoted keys and no comments. Missing fields use the defaults below. A missing or blank file uses the default configuration. A malformed or semantically invalid file produces an error; do not assume that an invalid value silently falls back to its default.

FieldDefaultMeaning
version1Configuration schema version
theme"midnight"String: auto, midnight, daylight, tokyonight, rosepine-moon, or oscura-midnight
mcpInitStrategy"auto"MCP initialization strategy; also accepts "progressive" and "blocking"
mcpServersEmpty objectNamed local or remote MCP server configurations
webFetch.enabledfalseEnable client-side URL fetching; the domain allowlist still applies
webFetch.allowedDomainsEmpty listAllowed domains; an empty list denies requests
lsp.enabledfalseEnable configured language-server support
worktree.fetchLatestUpstreamtrueFetch upstream when preparing managed worktrees
worktree.inactivityDays1Inactivity threshold used by worktree management
maxConcurrentAgentsUnsetMachine-level concurrent-agent limit

Worktree policy, offline operation, and inactivity

The machine-wide worktree object contains two fields. fetchLatestUpstream is a boolean, defaulting to true; inactivityDays is a positive integer, defaulting to 1. For offline creation and a seven-day inactivity threshold, merge this into ~/.haskell-agent/config.json, preserving unrelated fields:

{
  "version": 1,
  "worktree": {
    "fetchLatestUpstream": false,
    "inactivityDays": 7
  }
}

With fetching disabled, new managed worktrees start from local HEAD. With fetching enabled, the current branch's configured remote wins, followed by upstream, origin, then a sole remaining remote. If no remote is selected, creation uses local HEAD. Otherwise it fetches the remote default branch into an isolated temporary ref: it does not merge into your checkout or update normal remote-tracking refs.

A cached remote default branch is reused. If that branch no longer exists, the agent discovers the remote default again; authentication, connectivity, or other fetch errors stop creation rather than silently using stale commits. For deliberately offline work, set fetching to false; do not interpret a failed fetch as a successful refresh. If a remote changes its default but keeps the old branch, explicitly fetch the new remote-tracking branch and update Git's remote HEAD with git remote set-head REMOTE --auto.

Interactive and subagent worktree creation reload the current machine policy for each creation. Initial CLI creation and background cleanup use the validated startup snapshot; restart the CLI to apply manual changes to that snapshot. Changes do not rewrite existing worktree branches.

Inactivity means elapsed 24-hour days since the later of the worktree's recorded activity and saved-session activity, not its creation age. Lease acquisition/release and explicit enrollment or recovery update recorded activity. The threshold never authorizes deletion on its own: active leases, protected/recovery-state checkouts, uncertain ownership, dirty files, and work not proven incorporated prevent collection.

Background maintenance runs asynchronously during session resource setup, not as an exact expiry timer. Each pass has bounded time and removal-attempt budgets, so an eligible checkout may survive until a later pass. A failure to establish activity evidence retains work rather than assuming inactivity. Use the worktree lifecycle guide to inspect eligibility, preview manual cleanup, and protect or recover work before changing retention settings.

Example: limit concurrent agents

/meta set the concurrent agent limit to 3

Inspect the proposed scope and value before confirming. An explicit launch limit takes precedence over project settings, which take precedence over the machine setting:

agent-cli --max-concurrent-agents 2

For a new configuration file, this minimal example sets only the machine limit. Do not replace an existing file with it; merge the field instead.

{
  "version": 1,
  "maxConcurrentAgents": 3
}

Verify a change

Harness-managed machine updates use a process-shared lock and atomic replacement. The configuration directory and file are written with private permissions. Preserve config.lock and config.revision-key alongside the file; the revision key supports detecting changes to the saved configuration.

Loading an older remote MCP entry can assign and persist a missing connection identity. A read can therefore require write access during migration. If it fails, check ownership and permissions rather than inventing IDs. A stale configuration preview should be refreshed and reviewed again, not forced over another process's edit.

  1. Save a private backup of the existing file. Configuration can contain credentials; do not paste it into issue reports or commit it to a repository.
  2. Change one section, preserving unrelated keys. Prefer /meta for a validated preview instead of editing a large file blindly.
  3. Restart after manually changing startup settings. For an external MCP catalog edit, /mcp followed by r reloads the runtime without discarding the session.
  4. Exercise the capability you changed: a fetch, a language-server operation, an MCP read, or a small delegated task. A file that parses is not proof that its external service works.

Use /session-info to inspect the active session and /model to check model selection. Restart the CLI when testing manually edited startup settings. If a configuration fails to load, restore your saved copy rather than deleting credentials or widening permissions.

Configuration errors

Error or symptomCorrection
Unsupported harness config versionUse version 1; do not copy another product's schema
must configure exactly one of url or commandKeep only the HTTP URL or local executable for that MCP entry
maxInlineBytes must not exceed maxContentBytesReduce the inline limit or increase the content limit within its documented bounds
LSP transport is unsupportedConfigure a stdio language server, not an HTTP endpoint
Change appears to have no effectCheck the file location, restart the affected runtime, and inspect project/launch overrides before changing more values

Continue with custom model configuration, MCP integrations, or project instructions.