Skip to content
Configuration

Configuration

Configuration

The .agents/ directory

core-agent walks up from the working directory looking for a folder named .agents/, analogous to how git looks for .git. The first match wins. Everything core-agent reads or writes lives there:

.agents/
├── config.json          # this file — provider, model, permissions, scope, telemetry, etc.
├── mcp.json             # MCP server declarations (see MCP page)
├── skills/              # SKILL.md bundles (see Skills page)
└── sessions/            # one-shot transcripts; auto-written, safe to .gitignore

You don’t have to create .agents/ — without it, core-agent runs with built-in defaults and skips the project-specific bits (no transcripts, no MCP, no skills). It’s required only when you want to customize.


config.json schema

Top-level shape, with all fields optional except version and model.name:

{
  "version": 1,
  "model": { ... },
  "permissions": { ... },
  "path_scope": { ... },
  "agent": { ... },
  "tool_output": { ... },
  "otel": { ... }
}

version must be 1. Other versions are rejected with a clear upgrade message — the schema is bumped only on breaking changes.

A minimal viable config:

{
  "version": 1,
  "model": {
    "provider": "anthropic",
    "name": "claude-opus-4-7"
  }
}

model

Selects the LLM backend.

FieldTypeDefaultNotes
providerstring"" (auto-detect)One of gemini, vertex, anthropic, anthropic-vertex. Empty = auto-detect from env.
namestringgemini-3.1-pro-previewModel ID. Required.
api_keystring""Inline key for provider: gemini. Usually unset; read from GOOGLE_API_KEY / GEMINI_API_KEY at runtime.
vertexobjectnullGCP project + region. Required when provider: vertex.
vertex.projectstringGCP project ID.
vertex.locationstringGCP region (e.g. us-central1).
anthropicobjectnullClaude-specific settings.
anthropic.api_keystring""Inline Anthropic key. Usually read from ANTHROPIC_API_KEY.
anthropic.vertexobjectnullWhen provider: anthropic-vertex, holds project + region.
anthropic.vertex.projectstringGCP project ID for Vertex Anthropic. Falls back to ANTHROPIC_VERTEX_PROJECT_ID then GOOGLE_CLOUD_PROJECT.
anthropic.vertex.locationstringRegion (e.g. us-east5). Falls back to CLOUD_ML_REGION then GOOGLE_CLOUD_LOCATION.
pricingobjectnullPer-model price override for usage.Tracker.
pricing.input_per_mtokfloatUSD per 1M input tokens.
pricing.output_per_mtokfloatUSD per 1M output tokens.

See Providers for full details on each backend.


permissions

Configures the permission gate that consults every tool call. See Permissions for the full pattern grammar.

FieldTypeDefaultNotes
modestringaskOne of ask, allow, yolo.
allowstring[][]Allowlist patterns. Format: <tool>:<glob> or <glob>.
denystring[][]Denylist patterns. Always wins over allow.

Example:

{
  "permissions": {
    "mode": "ask",
    "allow": ["bash:git status", "bash:git log*", "read_file:internal/**"],
    "deny":  ["bash:sudo *"]
  }
}

path_scope

Extra paths file tools may touch outside the default project root + user home.

FieldTypeDefaultNotes
allowstring[][]Patterns. Exact paths, directory trees ending in /..., or path/filepath.Match globs.

Example:

{
  "path_scope": {
    "allow": [
      "/etc/myapp/...",
      "/var/log/myapp.log",
      "~/scratch/*.json"
    ]
  }
}

agent

Runtime tuning for the agent loop.

FieldTypeDefaultNotes
max_stepsint50Max tool-call cycles within a single turn before the agent gives up.

tool_output

Caps tool result size before it enters model context. Prevents a runaway cat /huge.log from blowing through your token budget. The built-in tools (read_file, write_file, edit_file, list_dir, bash, todo) honor these caps; consumer-provided tools should call tools.Truncate(...) to do the same.

FieldTypeDefaultNotes
max_bytesint32768Per-tool-result byte cap.
max_linesint500Per-tool-result line cap.
per_toolobjectsee belowPer-tool overrides keyed by tool name.

Default per_tool overrides (apply to the built-in tools that ship with core-agent):

{
  "tool_output": {
    "per_tool": {
      "bash":      { "max_bytes": 65536,  "max_lines": 2000 },
      "read_file": { "max_bytes": 262144, "max_lines": 5000 },
      "list_dir":  { "max_bytes": 32768,  "max_lines": 500 }
    }
  }
}

core-agent ships these tools by default in the bundled CLI; library callers opt in with tools.Build(cfg, gate, tools.Default()). Override per-tool caps with the per-tool block above; add an entry under per_tool for any consumer-provided tool that should follow a non-default cap.


tools

Controls which built-in tools are wired into the bundled CLI. Defaults to the full set; list entries here to turn specific tools off without disabling the whole suite.

FieldTypeDefaultNotes
disablestring[][]Built-in tool names to turn off. Valid: bash, read_file, write_file, edit_file, list_dir, todo. Unknown names cause a startup error.

Example — keep everything except shell access:

{
  "tools": {
    "disable": ["bash"]
  }
}

The --disable-tools=bash,write_file CLI flag composes with this list by union — anything disabled in either path is off. To turn the entire suite off, use --no-builtin-tools (which makes tools.disable and --disable-tools moot).


mock

Configures the echo and scripted mock providers, plus the orthogonal recording wrapper. See Providers → Echo and Providers → Scripted for the full story; this section is the schema.

FieldTypeDefaultNotes
scriptstring""Path to a JSONL transcript. Required when model.provider: scripted.
strictboolfalseScripted: assert each incoming request’s Contents JSON-equal the recorded request. Catches prompt-construction regressions.
recordstring""Write a JSONL recording of every LLM turn to this path. Works with any provider, not just the mocks.

Example — record a real Gemini session for later replay:

{
  "model": { "provider": "gemini" },
  "mock":  { "record": "fixtures/last-session.jsonl" }
}

Example — replay it under tests:

{
  "model": { "provider": "scripted" },
  "mock":  { "script": "fixtures/last-session.jsonl", "strict": true }
}

CLI flags --script, --script-strict, and --record-to override the corresponding fields. --record-to is the orthogonal one — it’s safe to combine with any provider.


otel

OpenTelemetry exporter config. Off by default — a fresh invocation makes zero outbound spans.

FieldTypeDefaultNotes
exporterstringnoneOne of none, console, otlp.
endpointstring""OTLP endpoint when exporter: otlp (or set via standard OTEL_EXPORTER_OTLP_ENDPOINT env).

Console mode prints span JSON to stderr — useful for local debugging. OTLP mode honors all the standard OTEL_* env vars.


Discovery and merge

core-agent finds your config like this:

  1. Walk up from the current working directory looking for a folder named .agents/. First match wins.
  2. Read <found>/config.json if present. Missing file → use built-in defaults.
  3. Merge the loaded JSON over config.DefaultConfig() — unspecified fields keep their defaults. Unknown fields are tolerated for forward compatibility.
  4. Validate the merged result. Bad provider name, missing required field, or wrong schema version → fail fast at startup.

Override discovery with the CLI’s -c <path> flag, which reads the file directly and treats its parent directory as the agentsDir for MCP / skills resolution.


Atomic writes

config.Save(path, cfg) writes via temp file + rename so a partial write can never leave a corrupt config.json on disk. Use it when you build tooling that mutates config (e.g. an init-style command, or a /permissions slash command in a downstream consumer).