# Configuration file

The Node host (the `ze-harness` CLI, the SDK, and the Node.js server) reads a global `config.json` and the nearest project `ze-harness.config.json`. Every file uses this format. Later sources override earlier ones; the server-node package README describes how agents, providers, and permissions merge.

The full JSON Schema is at [/ze-harness.config.schema.json](https://github.com/ze-harness.config.schema.json).

## `model`

The default model as `provider/model`, such as `openai/gpt-5-mini`.

```ts
string
```

## `agents`

Agents by ID. An entry defines a new agent or overrides fields of a built-in or plugin agent with the same ID.

```ts
Record<string, {
  displayName?: string; // The name clients show for the agent.
  description?: string; // What the agent is for. Models read it when choosing a sub-agent.
  system?: string; // The agent's system prompt. An empty string removes inherited instructions.
  model?: string; // The model this agent uses, as `provider/model`.
  // `primary` agents run Turns directly, `subagent` agents run only as sub-agents, and `all` agents
  // do both.
  mode?: "primary" | "subagent" | "all";
  // Permission rules appended after the server's and Session's rules for this agent.
  permissions?: {
    // The tool action to match, such as `read`, `edit`, or `shell`. `*` matches any.
    action: string;
    // A pattern over the resource, such as a path or shell command. `*` matches any characters and
    // `?` one.
    resource: string;
    // `allow` runs the operation, `ask` waits for the user, and `deny` refuses it.
    effect: "allow" | "ask" | "deny";
  }[];
  disabled?: boolean; // `true` hides the agent; a later `false` restores it.
}>
```

## `defaultAgent`

The agent new Turns use when they name none. It must support primary use.

```ts
string
```

## `mcp`

MCP servers the host connects to. IDs and names must be unique.

```ts
Array<
  | {
    kind: "local";
    id: string; // Stable server identity, unique across MCP servers. (max length 128)
    // Server name. The model sees each of the server's Tools as `<name>_<tool>`. (max length 128)
    name: string;
    enabled?: boolean; // `false` keeps the server listed but never connects it. Defaults to `true`.
    order?: number; // Sort key for the order of servers' Tools and instructions. Defaults to 0.
    // Also gives the model a `<name>_read-resource` Tool for reading the server's resources.
    // Defaults to `false`.
    resourceReadTool?: boolean;
    // MCP protocol versions to accept; the server must answer with one. Defaults to `2025-06-18`,
    // the only version Core supports. (at least 1)
    protocolVersions?: string[];
    clientCapabilities?: { roots: false; sampling: false; elicitation: false };
    // Time limits in milliseconds. Reaching one fails that operation. Defaults to unlimited.
    limits?: {
      // One connection attempt: starting the transport, initializing, and reading the catalog.
      startupMs: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
      // One catalog read.
      catalogMs: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
      // One Tool call, resource read, or prompt resolution.
      executionMs: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
    };
    // `manual` never retries; `retry` retries a retryable connection failure every `delayMs`, up to
    // `maxAttempts` counting the first attempt. Defaults to retrying every 1,000 ms without limit.
    reconnect?:
      | { kind: "manual" }
      | {
        kind: "retry";
        delayMs: number; // min 1
        maxAttempts: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
      };
    // A server the host starts as a child process and talks to over stdio.
    transport: {
      kind: "stdio";
      command: string; // The executable the host starts.
      arguments?: string[]; // Command-line arguments.
      // Environment variables for the server process. The Node host passes only these, plus `PATH`
      // and temporary-directory variables.
      environment?: Record<string,
        | { kind: "environment"; reference: string /* max length 256 */ }
        | { kind: "secret"; reference: string /* max length 256 */ }
        | { kind: "oauth"; reference: string /* max length 256 */ }
      >;
    };
  }
  | {
    kind: "remote";
    id: string; // Stable server identity, unique across MCP servers. (max length 128)
    // Server name. The model sees each of the server's Tools as `<name>_<tool>`. (max length 128)
    name: string;
    enabled?: boolean; // `false` keeps the server listed but never connects it. Defaults to `true`.
    order?: number; // Sort key for the order of servers' Tools and instructions. Defaults to 0.
    // Also gives the model a `<name>_read-resource` Tool for reading the server's resources.
    // Defaults to `false`.
    resourceReadTool?: boolean;
    // MCP protocol versions to accept; the server must answer with one. Defaults to `2025-06-18`,
    // the only version Core supports. (at least 1)
    protocolVersions?: string[];
    clientCapabilities?: { roots: false; sampling: false; elicitation: false };
    // Time limits in milliseconds. Reaching one fails that operation. Defaults to unlimited.
    limits?: {
      // One connection attempt: starting the transport, initializing, and reading the catalog.
      startupMs: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
      // One catalog read.
      catalogMs: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
      // One Tool call, resource read, or prompt resolution.
      executionMs: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
    };
    // `manual` never retries; `retry` retries a retryable connection failure every `delayMs`, up to
    // `maxAttempts` counting the first attempt. Defaults to retrying every 1,000 ms without limit.
    reconnect?:
      | { kind: "manual" }
      | {
        kind: "retry";
        delayMs: number; // min 1
        maxAttempts: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
      };
    // A server the host reaches over MCP streamable HTTP.
    transport: {
      kind: "streamable-http";
      endpoint: string; // An `http://` or `https://` URL with no credentials in it. (uri)
      // Request headers, resolved from credential references.
      headers?: Record<string,
        | { kind: "environment"; reference: string /* max length 256 */ }
        | { kind: "secret"; reference: string /* max length 256 */ }
        | { kind: "oauth"; reference: string /* max length 256 */ }
      >;
      // An OAuth credential that authorizes requests. The host then owns `Authorization`.
      oauth?: { kind: "oauth"; reference: string /* max length 256 */ };
    };
  }
>
```

## `plugins`

Trusted plugins to load: a source string, or an object with options. Plugins run unsandboxed with full process authority.

```ts
Array<
  | string
  | {
    // An exact npm package name, or a local path starting with `./`, `../`, or `/`. Local paths
    // resolve from the config file that declares them.
    source: string;
    // JSON passed to the plugin as `context.options` in `setup`. Defaults to `{}`.
    options?: Record<string, JsonValue>;
    // `false` removes the same source declared by an earlier config layer. Defaults to `true`.
    enabled?: boolean;
  }
>
```

## `skills`

Extra local directories to search for `SKILL.md` files, besides the standard locations. Relative paths resolve from the working directory.

```ts
string[]
```

## `providers`

Model providers by ID. `true` enables a catalog provider with defaults. Without this map, OpenAI, OpenCode Go, and OpenRouter are enabled; with it, only listed providers are.

```ts
Record<string,
  | boolean
  | {
    // Overrides for `baseURL`, headers, the request timeout, and `apiKey`.
    options?: Record<string, JsonValue>;
    enabled?: boolean; // `false` disables a provider. Defaults to `true`.
    // A built-in provider whose transport and model list this entry inherits, so one provider can
    // have several entries with separate credentials. It cannot name this entry or another entry
    // with a `base`. (max length 128)
    base?: string;
    // A provider that holds this provider's key, such as `tap`. Requests then authenticate with
    // that provider's credential instead of a local key. (max length 128)
    via?: string;
    // Provider definition fields: routes, authentication, headers, credential environment names,
    // and models. A provider the models.dev catalog does not know needs a full definition.
    definition?: unknown;
  }
>
```

## `observerBufferSize`

Capacity of each Turn's in-memory event queue for in-process observers. When it is full the oldest events are dropped; durable Turn state is unaffected. Defaults to 128.

```ts
number
```

## `contentFlushMillis`

Longest time, in milliseconds, streamed model content waits before it is committed and published. Block boundaries and the end of a response commit immediately; 0 commits every provider chunk. Defaults to 100.

```ts
number
```

## `codemode`

CodeMode, which lets the model combine tool calls in one script.

```ts
{ enabled?: boolean /* `false` turns CodeMode off. Defaults to `true`. */ }
```

## `steering`

```ts
{
  // How many batches of steering input one Turn may take in. Defaults to unlimited.
  maxBatches?: { kind: "unlimited" } | { kind: "finite"; value: number };
}
```

## `subagents`

```ts
{
  // How many levels of sub-agents may nest. The default, 1, lets a Turn start sub-agents that
  // cannot start their own.
  maxDepth?: { kind: "unlimited" } | { kind: "finite"; value: number };
}
```

## `permissions`

Ordered permission rules, appended after Ze's defaults and earlier config layers. The last matching rule wins. The defaults allow everything inside the Session workdir and ask for paths outside it and for `.env` reads.

```ts
{
  action: string; // The tool action to match, such as `read`, `edit`, or `shell`. `*` matches any.
  // A pattern over the resource, such as a path or shell command. `*` matches any characters and
  // `?` one.
  resource: string;
  // `allow` runs the operation, `ask` waits for the user, and `deny` refuses it.
  effect: "allow" | "ask" | "deny";
}[]
```

## `permissionMatching`

```ts
{
  // Whether rule patterns match case-sensitively. Defaults to `true`, or `false` on Windows.
  caseSensitive?: boolean;
}
```

## `approval`

```ts
{
  // How long a permission request may wait for an answer. Defaults to unlimited.
  timeoutMs?: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
}
```

## `timeouts`

```ts
{
  // The longest a Turn may run. Defaults to unlimited.
  turnMs?: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
}
```

## `provider`

Model request retries. Core retries only attempts the provider rejected before emitting output.

```ts
{
  // Attempts per model request, including retries. Defaults to unlimited.
  maxAttempts?: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
  // The longest one model request attempt may run. Defaults to unlimited.
  attemptTimeoutMs?: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
  // The longest one model request may take across all its attempts. Defaults to unlimited.
  elapsedMs?: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
  // The delay between retries. Defaults to none.
  pacing?:
    | { kind: "none" }
    | { kind: "fixed"; delayMs: number }
    | {
      kind: "exponential";
      initialDelayMs: number; // min 1
      maximumDelayMs: number; // min 1
      jitter: boolean;
    };
}
```

## `context`

```ts
{
  // Context units each model request reserves beyond the model's output limit. Defaults to 1024.
  safetyReserveUnits?: number;
}
```

## `images`

```ts
{
  // The largest base64 payload, in bytes, of one attached image. URL images are not measured.
  // Defaults to unlimited.
  maxBase64Bytes?: { kind: "unlimited" } | { kind: "finite"; value: number /* min 1 */ };
}
```

## `JsonValue`

```ts
string | number | boolean | null | JsonValue[] | Record<string, JsonValue>
```

---

Generated from [`packages/server-node/src/bootstrap/config/schema.ts`](https://github.com/ZephyrCloudIO/ze-harness/blob/main/packages/server-node/src/bootstrap/config/schema.ts).
