---
name: Agency config file
description: A tour of the options you can set in an agency.json file to configure the Agency compiler and runtime.
---

# Agency config file

To set options, add an `agency.json` file to the directory you run Agency from.

I would suggest referring to this page as needed, instead of reading it all the way through.

## Local overrides

Put settings you don't want to commit in `agency.local.json`, next to `agency.json`. Agency merges the two files, and the local file wins. Add `agency.local.json` to your `.gitignore`.

```json
// agency.json
{ "log": { "host": "https://statelog.example.com", "projectId": "team" } }

// agency.local.json
{ "log": { "projectId": "my-project" } }
```

With these files, Agency logs to `https://statelog.example.com` under the project `my-project`. `agency deploy` reads the same settings, so it deploys to `my-project`.

Agency merges the files with these rules:

1. Objects merge key by key.
2. An array in the local file replaces the array in `agency.json`.
3. Any other value in the local file replaces the value in `agency.json`.

The fields in this table are exceptions. A value at one of these paths replaces the matching value in `agency.json` whole. `*` stands for any name.

| Path | Why |
| --- | --- |
| `mcpServers.*` | A server's fields depend on each other. Mixing two servers can change how Agency connects to it. |
| `client.modelAliases.*` | An alias's hash and companion models belong to its own model. |

For example, if both files define an MCP server named `search`, Agency uses the one in `agency.local.json`. Servers that only `agency.json` defines are still used.

To see the config Agency will use, run [`agency config show`](../cli/config.md).

If you pass `-c <file>`, Agency loads only that file and skips `agency.local.json`.

Don't put secrets in either file. Agency compiles config into the generated code, so these values can end up in build output. Keep secrets in `.env`.

## The basics

```json
{
  "verbose": false,
  "logLevel": "info",
  "outDir": "./dist"
}
```

- **`verbose`** — extra logging during compilation.
- **`logLevel`** — `"debug"`, `"info"`, `"warn"`, or `"error"`.
- **`outDir`** — where compiled code goes (next to Agency source by default).

## LLM client

This is where you set your default model, provider, and API keys.

```json
{
  "client": {
    "defaultModel": "claude-fable-5",
    "defaultProvider": "anthropic",
    "apiKey": {
      "openAi": "sk-...",
      "anthropic": "sk-ant-..."
    },
  }
}
```

| Option | Description |
| --- | --- |
| `defaultModel` / `defaultProvider` | Used when a `llm()` call doesn't specify its own. With neither set, calls use `gpt-5-mini` through `openai-responses`. Naming a model without a provider lets the provider be inferred from the model. |
| `apiKey` | Keys for `openAi`, `google`, `anthropic`, `ollama`, `openRouter`, `deepInfra`, `liteLlm`, and `openAiCompat`. |
| `baseUrl` | Needed if you're using a provider that provides an endpoint compatible with the OpenAI API, such as `openRouter`, `deepInfra`, `liteLlm` and others. |
| `maxToolResultChars` | Caps how much of a single tool result the model sees (the full value still reaches your code). Default `100000`; `0` disables it. Keeps a chatty tool from blowing the context window. |
| `maxToolSchemaChars` | Warns in the state log when one tool's JSON schema is longer than this. Default `2000`; `0` disables it. A tool's schema is re-sent on every request, so an oversized one quietly raises the cost of the whole run. |
| `providerModules` | Paths to custom smoltalk provider modules (e.g. a local model via `smoltalk-llama-cpp`). |
| `modelAliases` / `modelsDir` | Short-name aliases and the cache directory for local models. |
| `adaptersDir` | The folder LoRA adapters (`.safetensors` files) are in. A local image server loads one the first time a call names it: `generateImageLocal(..., lora: "sketch")` loads `sketch.safetensors` from this folder. A relative path is taken from the folder `agency.json` is in. |
| `controlnetsDir` | The folder ControlNets are in, one directory each. `agency local download controlnet-scribble-sdxl` puts one here, and `generateImageLocal(..., controlnet: "controlnet-scribble-sdxl", controlImage: "./pose.png")` loads it. A relative path is taken from the folder `agency.json` is in. |
| `llamaCpp.draftModel` | A smaller GGUF model of the same family that drafts tokens for the main one, which is speculative decoding. `agency run --local <model> --draft <model>` sets it for a run. |
| `llamaCpp.chatWrapper` | The chat wrapper node-llama-cpp formats the model's prompts with, by its name (`qwen`, `gemma4`, `harmony`, `chatML`), for a model whose template it does not recognise. |

Agency uses [Smoltalk](https://github.com/egonSchiele/smoltalk) for its LLM client.

## Type checking

The typechecker is on by default.

```json
{
  "typechecker": {
    "enabled": true,
    "strict": true,
    "strictTypes": true,
    "undefinedFunctions": "warn"
  }
}
```

| Option | Description |
| --- | --- |
| `enabled` | Run the type checker and print warnings. Defaults to `true`. |
| `strict` | Type errors become fatal. Defaults to `true`. |
| `strictTypes` | Untyped variables are errors. |
| `undefinedFunctions` / `undefinedVariables` |  `"silent"`, `"warn"`, or `"error"` for undefined functions or variables. Both default to `"warn"`. |
| `strictMemberAccess` | Guards against accessing a member that only exists on some branches of a union. For example, if you had a [Result](/guide/error-handling) type, and you tried to access `result.value` (which only exists on Success), that would be an error. Default `"error"`. |
| `matchExhaustiveness` | Flags a `match` over a closed type that doesn't cover every case. For example, if you were matching over a variable with a union type like "success" | "failure", but you didn't handle the failure case, that would be an error. Default `"error"`. |
| `definiteReturns` | Flags a function that has a return type set, but not all of its code paths return a value. Default `"error"`. |

## Observability and logging

Turns on logging. See [Observability](/guide/observability) for details.

```json
{
  "observability": true,
  "log": {
    "logFile": "log.jsonl"
  }
}
```

## Memory

Enable the memory layer so agents can store and recall facts across runs. Setting this makes `std::memory` usable and lets `llm({ memory: true })` inject relevant facts. See [Memory](/guide/memory) for details.

```json
{
  "memory": {
    "dir": "./.agency-memory",
    "autoExtract": { "interval": 5 },
    "compaction": { "trigger": "token", "threshold": 8000 }
  }
}
```

| Option | Description |
| --- | --- |
| `dir` | Where memory JSON files live (required if you use `memory`). |
| `model` | Model used for extraction, compaction, and recall. |
| `autoExtract.interval` | How many turns to wait before running an auto-extraction on message history. Default `5`. |
| `compaction` | Controls when a conversation gets compacted. When the thread crosses `threshold`, Agency extracts facts from the older messages in the conversation, summarizes them with an LLM, and replaces them with a single summary message. Roughly the older half of the conversation is compacted. Use `trigger` to pick the metric: either `"token"` (estimated at roughly 4 characters per token) or `"messages"` (raw message count). Defaults to `trigger: "token"` and `threshold: 50000`. |
| `embeddings.model` | Embedding model for semantic recall. |

## Debugging and tracing

```json
{
  "trace": true
}
```

| Option | Description |
| --- | --- |
| `instrument` | Emit per-step instrumentation (default `true`). Set `false` to shed the overhead when you don't need tracing. |
| `trace` / `traceFile` / `traceDir` | Write execution checkpoints to a `.trace` file. |
| `distDir` | Directory of pre-compiled JS the debugger imports instead of compiling on the fly. |

## Runtime limits

Safety guards that stop a program from running away.

```json
{
  "maxCallDepth": 2048,
  "maxToolCallRounds": 10,
  "checkpoints": { "maxRestores": 100 }
}
```

| Option | Description |
| --- | --- |
| `maxCallDepth` | The runaway-recursion guard. Default `2048`; raise it for legitimately deep recursion. |
| `maxToolCallRounds` | How many times the LLM can loop between calling tools and reacting to their output. Default `10`. At the cap, the pending tool calls are refused with a message telling the model to answer, and later requests offer no tools. A call's own `llm(..., { maxToolCallRounds })` and a `setLlmOptions` default from `std::llm` both override it; when both are set, the smaller wins. |
| `checkpoints.maxRestores` | Cap on how often one checkpoint can be restored before it errors out. Default `100`. |

## Testing and coverage

```json
{
  "test": { "parallel": 4 },
  "coverage": {
    "threshold": 80,
    "perFileThreshold": 60,
    "exclude": ["examples/**"]
  }
}
```

| Option | Description |
| --- | --- |
| `test.parallel` | Number of test files to run at once. Default `1`. |
| `coverage.threshold` / `coverage.perFileThreshold` | Minimum coverage percentages; `agency coverage report` fails below them. |
| `coverage.outDir` | Where coverage data lands. |
| `coverage.exclude` | Which files to skip, as glob patterns (e.g. `["examples/**"]`). |

## Eval and optimize

Configuration for the `agency eval` and `agency eval optimize` commands.

```json
{
  "eval": {
    "runsDir": "./eval-runs",
    "optimize": {
      "goal": "Maximize accuracy",
      "graders": "./graders.ts",
      "validation": { "split": 0.2 }
    }
  }
}
```

| Option | Description |
| --- | --- |
| `runsDir` | Where `agency eval` saves its run artifacts. Default `runs`. |
| `optimizeRunsDir` | Where `agency eval optimize` saves its artifacts. Defaults to an `optimize` subdirectory inside `runsDir`. |
| `optimize.goal` | The optimization objective. |
| `optimize.graders` | Path to a TS grading module. |
| `optimize.optimizer` | A built-in optimizer name or a path to your own module. |
| `optimize.validation` | A validation inputs file and/or a `split` fraction held out for validation. |

## Trusted modules

A workflow runs in Agency's sandbox, which refuses TypeScript imports. If the
functions you pass to a workflow call TypeScript, name their directories here,
with the directory your build writes their compiled JavaScript to.

```json
{
  "sandbox": {
    "trustedModules": [{ "source": "src/agent", "compiled": "dist/agent" }]
  }
}
```

| Option | Description |
| --- | --- |
| `sandbox.trustedModules` | Directories of `.agency` modules you vouch for, each with its compiled directory. Paths are relative to the working directory, so start the program from the project directory: a relative path resolves against wherever the process was started. If your compiled files sit beside the sources, name the same directory twice. |

The workflow's subprocess loads your compiled files instead of compiling the
source, so build your project before you run a workflow. Only workflows read
this list. `compile`, `run`, and `runCode` from `std::agency` still refuse a
trusted module.

## Docs, packing, and the log viewer

Odds and ends for other commands.

```json
{
  "doc": { "outDir": "docs", "baseUrl": "https://github.com/me/repo" },
  "pack": { "format": "esm", "target": "node20" },
  "viewer": { "slowMs": 5000, "expensiveUsd": 0.01 }
}
```

| Option | Description |
| --- | --- |
| `doc` | Output directory and source-link base URL for `agency doc`. |
| `pack` | Options for `agency pack`: output `format` (`"esm"` or `"cjs"`), esbuild `target` (e.g. `"node20"`), and `external`. `external` is an array of package names to exclude from the bundle and import at runtime instead (for packages that can't be bundled, like native addons). Anything marked external must already be installed wherever the bundle runs. |
| `viewer` | Color thresholds for `agency logs view`: `slowMs` and `fastMs` for durations, `expensiveUsd` for cost. |

## References
- [Full list of options](https://github.com/egonSchiele/agency-lang/blob/main/packages/agency-lang/lib/config/config.ts).
