> ## Documentation Index
> Fetch the complete documentation index at: https://docs.langchain.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> Configure Deep Agents Code with config.toml, hooks, and MCP servers

Deep Agents Code stores its configuration in the `~/.deepagents/` directory. The main config files are:

| File          | Format | Purpose                                                                                           |
| ------------- | ------ | ------------------------------------------------------------------------------------------------- |
| `config.toml` | TOML   | Model defaults, provider settings, constructor params, profile overrides, themes, update settings |
| `.env`        | Dotenv | Global API keys, secrets, and other environment variables                                         |
| `hooks.json`  | JSON   | External tool subscriptions to Deep Agents Code lifecycle events                                  |
| `.mcp.json`   | JSON   | Global MCP server definitions                                                                     |

<Note>
  Files under `~/.deepagents/.state/` hold per-machine Deep Agents Code state and are managed automatically.
</Note>

***

## Provider credentials

Deep Agents Code needs an API key for each model provider you use. The recommended way to add one is the [`/auth`](#use-%2Fauth-recommended) credential manager. For non-interactive runs, set [environment variables](#environment-variables-ci-and-headless) instead.

If the same key is set in more than one place, see [Key resolution order](#key-resolution-order) for which one wins.

### Use `/auth` (recommended)

Open the credential manager from any session:

```txt theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
/auth
```

The manager lists the LLM providers available in your installation and marks the ones that already have a key set. Select a provider to add or replace its key, or remove one you have already stored. Keys you save here persist across sessions.

<Accordion title="Provider row labels" icon="list-check">
  Each row shows the provider name followed by where its key comes from:

  | Label            | Meaning                                                                                                                             |
  | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
  | `[stored]`       | A key saved in this manager via `/auth`                                                                                             |
  | `[env: VARNAME]` | The key comes from environment variable `VARNAME` (the resolved name, such as `DEEPAGENTS_CODE_OPENAI_API_KEY` or `OPENAI_API_KEY`) |
  | `[missing]`      | No key is stored and the env var is unset; select the row to paste one                                                              |
</Accordion>

The `/auth` prompt also has an optional **base URL** field. Leave it blank to use the provider's default endpoint, or set a custom one to use with this key. The base URL is saved alongside the key. See [Endpoints, keys, and gateways](#endpoints-keys-and-gateways) for how endpoints resolve, including with gateways.

<Warning>
  A stored base URL is not a secret and may be logged; the key paired with it is never logged.
</Warning>

<Note>
  Keys are scoped to your user account on this machine — Deep Agents Code never transmits them anywhere except to the configured provider's API.
</Note>

`/auth` only manages **LLM provider** credentials. Tool credentials such as `TAVILY_API_KEY` (web search) and `LANGSMITH_API_KEY` (tracing) are read from the environment instead — [set them in `~/.deepagents/.env` or your shell](#environment-variables).

### Environment variables (CI and headless)

For non-interactive runs, CI/CD pipelines, or anywhere a TUI isn't available, export the provider's env var in your shell:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
export ANTHROPIC_API_KEY="sk-ant-..."
export OPENAI_API_KEY="sk-..."

# Prefix with DEEPAGENTS_CODE_ to scope a key to Deep Agents Code only,
# leaving a shared key used by other CI steps untouched
export DEEPAGENTS_CODE_OPENAI_API_KEY="sk-..."
```

To keep keys in a file instead, define them in a [`.env` file](#environment-variables).

### Key resolution order

When a provider's key is set in more than one place, Deep Agents Code uses the first of these that is set:

1. **`DEEPAGENTS_CODE_`-prefixed env var** — for example `DEEPAGENTS_CODE_OPENAI_API_KEY` as an inline shell export. The [`DEEPAGENTS_CODE_` prefix](#deepagents_code_-prefix) is the explicit "use this key in Deep Agents Code" override.
2. **App-stored key** — entered in the `/auth` credential manager.
3. **Plain provider env var** — for example `OPENAI_API_KEY`, from your shell or `.env` files.

An app-stored key wins over a plain env-var key for the same provider, but a `DEEPAGENTS_CODE_`-prefixed key wins over an app-stored key. The prefix is the way to override an already-stored key for a single run, without clearing it:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
# With a key already stored via /auth, a plain env var does not override it.
# dcode still uses the app-stored key for this run:
OPENAI_API_KEY=sk-xxxx dcode -n "..."

# The DEEPAGENTS_CODE_ prefix does override it, for this run only:
DEEPAGENTS_CODE_OPENAI_API_KEY=sk-xxxx dcode -n "..."
```

This layering exists for the common case where your machine already exports a plain provider variable for some other purpose — a shared `OPENAI_API_KEY` used by other tools, scripts, or CI — that you do not want Deep Agents Code to reuse. An app-stored key or a `DEEPAGENTS_CODE_`-prefixed variable gives Deep Agents Code its own value while leaving the unprefixed one untouched for everything else, so the two never mix.

Each provider's API key and its endpoint (`base_url`) resolve as a pair from the same source. See [Endpoints, keys, and gateways](#endpoints-keys-and-gateways).

### Enable web search with Tavily

The built-in `web_search` tool uses [Tavily](https://tavily.com). Deep Agents Code shows a "Web search disabled — `TAVILY_API_KEY` is not set" notification on startup until you provide a key. Unlike model provider keys, Tavily is **not** managed by `/auth`; it is read directly from the environment.

<Steps>
  <Step title="Get a key">
    Sign up at [tavily.com](https://tavily.com) and copy the key (it starts with `tvly-`). The free tier is sufficient for most Deep Agents Code usage.
  </Step>

  <Step title="Add it to your environment">
    Add the key to `~/.deepagents/.env` so every session picks it up:

    ```bash title="~/.deepagents/.env" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    TAVILY_API_KEY=tvly-...
    ```

    Or export it in your shell for a one-off session:

    ```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    export TAVILY_API_KEY=tvly-...
    ```

    Shell exports take precedence over `.env` values (see [Loading order and precedence](#loading-order-and-precedence)). To scope a key to Deep Agents Code only without affecting other tools that read `TAVILY_API_KEY`, use the [`DEEPAGENTS_CODE_` prefix](#deepagents_code_-prefix): `DEEPAGENTS_CODE_TAVILY_API_KEY=tvly-...`.
  </Step>

  <Step title="Reload or restart">
    In an existing session, run `/reload` to re-read `.env` files. On the next launch, the "Web search disabled" notification goes away and the agent can call `web_search`.
  </Step>
</Steps>

***

## Environment variables

In addition to shell exports, Deep Agents Code reads environment variables from dotenv files, so you can keep API keys out of your shell profile and avoid duplicating `.env` files across projects.

```bash title="~/.deepagents/.env" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
```

### Loading order and precedence

At startup, Deep Agents Code reads the nearest project `.env`, found by searching the directory you launch from and walking up through its parents (the first `.env` found wins), then `~/.deepagents/.env` as a global fallback for all projects. A project `.env` wins over the global one, and neither overrides a value already set in your shell. Running `/reload` re-reads both `.env` files so you can change keys without restarting, with shell values still taking precedence. This applies to every variable Deep Agents Code reads (for example, `TAVILY_API_KEY` or the `DEEPAGENTS_CODE_*` settings). Provider API keys have additional resolution rules; see [Provider credentials](#provider-credentials).

### `DEEPAGENTS_CODE_` prefix

All Deep Agents Code-specific environment variables use a `DEEPAGENTS_CODE_` prefix (e.g., `DEEPAGENTS_CODE_AUTO_UPDATE`, `DEEPAGENTS_CODE_DEBUG`). See the [environment variable reference](#environment-variable-reference) for the full list.

The prefix also works as an override mechanism for any environment variable Deep Agents Code reads, including third-party credentials. Deep Agents Code checks `DEEPAGENTS_CODE_{NAME}` first, then falls back to `{NAME}`:

```bash title="~/.deepagents/.env" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
# Give Deep Agents Code its own value, without affecting other tools
DEEPAGENTS_CODE_OPENAI_API_KEY=sk-cli-only

# Or set it empty so Deep Agents Code ignores a key exported in your shell
DEEPAGENTS_CODE_ANTHROPIC_API_KEY=
```

***

## Config file

`~/.deepagents/config.toml` lets you customize model providers, set defaults, and pass extra parameters to model constructors. This section covers:

* **Defaults**: pin a [default model](#default-and-recent-model) or [agent](#default-and-recent-agent).
* **Provider setup**: the [`[models.providers.<name>]` table](#provider-configuration), [constructor params](#model-constructor-params), [profile overrides](#profile-overrides-advanced), and [adding models to the `/model` switcher](#adding-models-to-the-interactive-switcher).
* **Custom endpoints and providers**: [custom base URLs](#custom-base-url), [OpenAI- or Anthropic-compatible APIs](#compatible-apis), and [arbitrary providers](#arbitrary-providers).
* **Endpoints and gateways**: how [API keys and base URLs resolve together](#endpoints-keys-and-gateways), including through a managed gateway.

### Default and recent model

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models]
default = "ollama:qwen3:4b"             # your intentional long-term preference
recent = "google_genai:gemini-3.5-flash"   # last /model switch (written automatically)
```

`[models].default` always takes priority over `[models].recent`. The `/model` command only writes to `[models].recent`, so your configured default is never overwritten by mid-session switches. To remove the default, use `/model --default --clear` or delete the `default` key from the config file.

### Default and recent agent

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[agents]
default = "backend-dev"  # your intentional long-term preference (Ctrl+S in /agents picker)
recent = "frontend-dev"  # last /agents switch (written automatically)
```

`[agents].default` always takes priority over `[agents].recent`. Selecting an agent in the `/agents` picker with `Enter` writes to `recent`; pressing `Ctrl+S` on the highlighted row pins it as `default`. Pressing `Ctrl+S` again on the same row clears the default.

Explicit `-a`/`--agent` always overrides both, and `-r`/`--resume` bypasses both so the thread's original agent is restored. See [Command reference](/oss/python/deepagents/code/overview#command-reference) for related flags.

### Provider configuration

Each provider is a TOML table under `[models.providers]`:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.<name>]
models = ["gpt-4o"]
api_key_env = "OPENAI_API_KEY"
base_url = "https://api.openai.com/v1"
class_path = "my_package.models:MyChatModel"
enabled = true

[models.providers.<name>.params]
temperature = 0
max_tokens = 4096

[models.providers.<name>.params."gpt-4o"]
temperature = 0.7
```

Providers have the following configuration options:

<ResponseField name="models" type="string[]" post={["optional"]}>
  A list of model names to show in the interactive `/model` switcher for the provider defined as `<name>`. For providers that already ship with model profiles, any names you add here appear in addition to bundled ones (useful for newly released models that haven't been added to the package yet). For [arbitrary providers](#arbitrary-providers), this list is the only source of models in the switcher.

  Models listed here **bypass** any applied profile-based [filtering criteria](/oss/python/deepagents/code/providers#which-models-appear-in-the-switcher), always appearing in the switcher. This makes it the recommended way to surface models that are excluded because their profile lacks `tool_calling` support or doesn't exist yet.

  This key is optional. You can always pass any model name directly to `/model` or `--model` regardless of whether it appears in the switcher; the provider validates the name at request time.
</ResponseField>

<ResponseField name="api_key_env" type="string" post={["optional"]}>
  The **name** of the environment variable that holds the API key (e.g., `"OPENAI_API_KEY"`). Deep Agents Code reads the credential from this env var at startup to verify access before creating the model.

  Most chat model packages read from a default env var automatically. See the [Provider reference](/oss/python/deepagents/code/providers#provider-reference) table for which variable name each built-in provider checks. For a provider not in that table, set `api_key_env` to its variable name (see [Arbitrary providers](#arbitrary-providers)).
</ResponseField>

<ResponseField name="base_url" type="string" post={["optional"]}>
  Override the base URL used by the provider, if supported. Refer to your provider packages' [reference docs](https://reference.langchain.com/python/integrations/) for more info.

  See [Compatible APIs](#compatible-apis) for pointing a built-in provider at a wire-compatible endpoint, or [Arbitrary providers](#arbitrary-providers) for one configured via `class_path`.
</ResponseField>

<ResponseField name="base_url_env" type="string" post={["optional"]}>
  Name of the environment variable that holds this provider's base URL, parallel to `api_key_env`. Reach for this instead of `base_url` when the endpoint comes from the environment rather than a fixed value — for example a gateway URL that differs by machine or CI job — so it can change without editing `config.toml` and can take part in endpoint resolution and key/endpoint pairing (see [Endpoints, keys, and gateways](#endpoints-keys-and-gateways)). It also extends those to providers outside the [built-in set](/oss/python/deepagents/code/providers#provider-reference); see [Arbitrary providers](#arbitrary-providers).

  If both are set, the static `base_url` wins:

  ```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  [models.providers.example]
  base_url = "https://fixed.example/v1"   # used
  base_url_env = "EXAMPLE_BASE_URL"        # ignored while base_url is set
  ```
</ResponseField>

<ResponseField name="params" type="object" post={["optional"]}>
  Extra keyword arguments forwarded to the model constructor. Flat keys (e.g., `temperature = 0`) apply to every model from this provider. Model-keyed sub-tables (e.g., `[params."gpt-4o"]`) override individual values for that model only; the merge is shallow (model wins on conflict).

  Do not put credentials (e.g., `api_key`) in `params`. Use [`api_key_env`](#provider-configuration) to point at an environment variable instead.
</ResponseField>

<ResponseField name="profile" type="object" post={["optional"]}>
  (Advanced) Override fields in the model's runtime [profile](/oss/python/langchain/models#model-profiles) (e.g., `max_input_tokens`). Flat keys apply to every model from this provider. Model-keyed sub-tables (e.g., `[profile."claude-sonnet-4-5"]`) override individual values for that model only; the merge is shallow (model wins on conflict). These overrides are applied after the model is created, so they take effect for context-limit display, auto-summarization, and any other feature that reads the profile. See [Profile overrides](#profile-overrides-advanced) for examples and the `--profile-override` flag.
</ResponseField>

<ResponseField name="class_path" type="string" post={["optional"]}>
  Used for [arbitrary model](#arbitrary-providers) providers. Fully-qualified Python class in `module.path:ClassName` format. When set, Deep Agents Code imports and instantiates this class directly for provider `<name>`. The class must be a `BaseChatModel` subclass.
</ResponseField>

<ResponseField name="enabled" type="boolean" default="true" post={["optional"]}>
  Whether this provider appears in the `/model` selector. Set to `false` to hide a provider that was auto-discovered from an installed package (e.g., a transitive dependency you don't want cluttering the model switcher). You can still use a disabled provider directly via `/model provider:model` or `--model`.
</ResponseField>

### Model constructor params

The [`params` field](#provider-configuration) forwards extra arguments to the model constructor. To give one model different values, add a model-keyed sub-table so you do not have to duplicate the whole provider config:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.ollama]
models = ["qwen3:4b", "llama3"]

[models.providers.ollama.params]
temperature = 0
num_ctx = 8192

[models.providers.ollama.params."qwen3:4b"]
temperature = 0.5
num_ctx = 4000
```

With this configuration:

* `ollama:qwen3:4b` gets `{temperature: 0.5, num_ctx: 4000}` — model overrides win.
* `ollama:llama3` gets `{temperature: 0, num_ctx: 8192}` — no override, provider-level params only.

The merge is shallow: any key present in the model sub-table replaces the same key from the provider-level params, while keys only at the provider level are preserved.

<Tip>
  For one-off adjustments without editing `config.toml`, pass a JSON object via `--model-params` at launch or mid-session with `/model`. CLI flags take highest priority over the config file. See [Model parameters](/oss/python/deepagents/code/providers#model-parameters) on the providers page for syntax and provider-specific examples.
</Tip>

### Profile overrides (Advanced)

Override fields in the model's runtime profile to change how Deep Agents Code interprets model capabilities. See [`ModelProfile`](https://reference.langchain.com/python/langchain-core/language_models/model_profile/ModelProfile) for the full list of overridable fields. The most common use case is lowering `max_input_tokens` to trigger auto-summarization earlier — useful for testing or for constraining context usage:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
# Apply to all models from this provider
[models.providers.anthropic.profile]
max_input_tokens = 4096
```

Per-model sub-tables work the same way as `params` — the model-level value wins on conflict:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.anthropic.profile]
max_input_tokens = 4096

# This model gets a higher limit
[models.providers.anthropic.profile."claude-sonnet-4-5"]
max_input_tokens = 8192
```

Profile overrides are merged into the model's profile after creation. Any feature that reads the profile — context-limit display in the status bar, auto-summarization thresholds, capability checks — will see the overridden values.

<Accordion title="CLI profile overrides with --profile-override" icon="terminal">
  To override model profile fields at runtime without editing the config file, pass a JSON object via `--profile-override`:

  ```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  dcode --profile-override '{"max_input_tokens": 4096}'

  # Combine with --model
  dcode --model google_genai:gemini-3.5-flash --profile-override '{"max_input_tokens": 4096}'

  # In non-interactive mode
  dcode -n "Summarize this repo" --profile-override '{"max_input_tokens": 4096}'
  ```

  These are merged on top of config file profile overrides (CLI wins). The priority chain is: model default \< config.toml profile \< CLI `--profile-override`.

  `--profile-override` values persist across mid-session `/model` hot-swaps — switching models re-applies the override to the new model.
</Accordion>

### Adding models to the interactive switcher

Some providers (e.g. `langchain-ollama`) don't bundle model profile data (see [Provider reference](/oss/python/deepagents/code/providers#provider-reference) for full listing). When this is the case, the interactive `/model` switcher won't list models for that provider. You can fill in the gap by defining a `models` list in your config file for the provider:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.ollama]
models = ["gemma4", "qwen3.6", "granite4.1:3b"]
```

The `/model` switcher will now include an Ollama section with these models listed.

This is entirely optional. You can always switch to any model by specifying its full name directly:

```txt theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
/model ollama:qwen3.6:27b
```

<Note>
  When `langchain-ollama` is installed and the daemon is reachable, Deep Agents Code auto-discovers locally pulled models and merges them into the switcher—no `models` list required. Run `/reload` to refresh after pulling new models, or set `DEEPAGENTS_CODE_OLLAMA_DISCOVERY=0` to opt out.
</Note>

### Custom base URL

Some provider packages accept a `base_url` to override the default endpoint. For example, `langchain-ollama` defaults to `http://localhost:11434` via the underlying `ollama` client. To point it elsewhere, set `base_url` in your configuration:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.ollama]
base_url = "http://your-host-here:port"
```

Refer to your provider's reference documentation for compatibility information and additional considerations.

### Compatible APIs

For providers that expose APIs that are wire-compatible with OpenAI or Anthropic, you can use the existing `langchain-openai` or `langchain-anthropic` packages by pointing `base_url` at the provider's endpoint:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.openai]
base_url = "https://api.example.com/v1"
api_key_env = "EXAMPLE_API_KEY"
models = ["my-model"]
```

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.anthropic]
base_url = "https://api.example.com"
api_key_env = "EXAMPLE_API_KEY"
models = ["my-model"]
```

<Note>
  Any features added on top of the official spec by the provider will not be captured. If the provider offers a dedicated LangChain integration package, prefer that instead.
</Note>

<Warning>
  The OpenAI provider defaults to the [Responses API](https://platform.openai.com/docs/api-reference/responses), which most OpenAI-compatible gateways do not implement. If your provider only supports the Chat Completions API, invocation will likely fail. Disable the Responses API explicitly:

  ```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  [models.providers.openai.params]
  use_responses_api = false
  ```
</Warning>

### Arbitrary providers

Deep Agents Code works with any tool calling LLM available as a [LangChain `BaseChatModel`](https://reference.langchain.com/python/langchain_core/language_models/#langchain_core.language_models.BaseChatModel). The [built-in providers](/oss/python/deepagents/code/providers#provider-reference) work out of the box; a less common or in-house model takes a little more setup. Point `class_path` at its `BaseChatModel` subclass and Deep Agents Code imports and instantiates the class directly.

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.my_custom]
class_path = "my_package.models:MyChatModel"
api_key_env = "MY_API_KEY"
base_url = "https://my-endpoint.example.com"

[models.providers.my_custom.params]
temperature = 0
max_tokens = 4096
```

`api_key_env` and `base_url` are optional. To read the endpoint from an environment variable instead of hardcoding `base_url`, use [`base_url_env`](#provider-configuration); it then resolves and pairs with the key the same way as for the built-in providers (see [Endpoints, keys, and gateways](#endpoints-keys-and-gateways)).

`class_path` providers are expected to handle their own authentication internally — useful when your model uses custom auth (JWT tokens, proprietary headers, mTLS, etc.) rather than a standard API key:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.xyz]
class_path = "abc.integrations.deepagents:DeepAgentsXYZChat"
models = ["abc-xyz-1"]

[models.providers.xyz.params]
bypass_auth = true
temperature = 0
```

With this config, switch to the model with `/model xyz:abc-xyz-1` or `--model xyz:abc-xyz-1`.

<Note>
  Deep Agents Code requires **tool calling** support. If your custom model supports tool calling but Deep Agents Code doesn't know about it, declare it in the provider profile:

  ```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  [models.providers.xyz.profile]
  tool_calling = true
  max_input_tokens = 128000
  ```

  Although optional, setting `max_input_tokens` to your model's context window is strongly encouraged. Without it, Deep Agents Code cannot show how full the context is, and auto-summarization falls back to a fixed trigger (around 170,000 tokens) instead of a fraction of your model's window. For a model with a smaller window, summarization may not run before you reach the model's hard limit, so requests start failing once the conversation grows.
</Note>

Because Deep Agents Code imports the `class_path` class at startup, the package that defines it must be importable from the same environment that runs `dcode`. Built-in providers ship as [install extras](/oss/python/deepagents/code/providers#quickstart), but a custom or in-house package is not one. Install it into the `dcode` environment with the `--package` flag:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
dcode --install my_package --package
```

In a session, run `/install my_package --package --force`. Both install the package alongside `dcode`. If the package is missing or cannot be imported, Deep Agents Code skips the provider and its models do not appear in `/model`.

When you switch to `my_custom:my-model-v1` (via `/model` or `--model`), the model name (`my-model-v1`) is passed as the `model` kwarg:

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
MyChatModel(model="my-model-v1", base_url="...", api_key="...", temperature=0, max_tokens=4096)
```

<Warning>
  `class_path` executes arbitrary Python code from your config file. This has the same trust model as `pyproject.toml` build scripts — you control your own machine.
</Warning>

Your provider package may optionally provide model profiles at a `_PROFILES` dict in `<package>.data._profiles` in lieu of defining them under the `models` key. See LangChain [model profiles](https://github.com/langchain-ai/langchain/tree/master/libs/model-profiles) for more info.

### Endpoints, keys, and gateways

An API key and the endpoint it is sent to have to match: the endpoint has to accept that key, or the request will likely fail. Deep Agents Code resolves the key and endpoint together, so overriding one updates the other to match. For example, if you replace a gateway-provisioned key with your own, Deep Agents Code also drops the gateway endpoint, so your key goes to the provider directly instead of to a gateway that would reject it.

#### How `base_url` resolves

Deep Agents Code resolves a provider's endpoint in this order (first match wins):

1. **`base_url` in `config.toml`** for the provider.
2. **The `DEEPAGENTS_CODE_`-prefixed endpoint variable.**
3. **The plain endpoint variable** in the environment (for example, `OPENAI_BASE_URL`).
4. **The endpoint saved with a `/auth` credential.** This step applies the saved endpoint for a provider that has no endpoint variable—such as a provider you add without declaring [`base_url_env`](#provider-configuration). Steps 2-3 have no variable to read for these, so the saved endpoint is used directly here. For a provider that does have an endpoint variable, the saved endpoint already took effect at step 2 or 3 (it is written to that variable), so this step changes nothing. Either way, an endpoint entered in `/auth` applies.
5. **The provider SDK's own default endpoint**, when none of the above is set.

<Note>
  Resolved endpoints are delivered to the model as the `base_url` constructor argument.
</Note>

As with API keys, the [`DEEPAGENTS_CODE_` prefix](#deepagents_code_-prefix) scopes the endpoint to Deep Agents Code without affecting other tools. For any other provider, declare the name with [`base_url_env`](#provider-configuration) and the endpoint resolves and pairs the same way:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.myprovider]
api_key_env = "MYPROVIDER_API_KEY"
base_url_env = "MYPROVIDER_BASE_URL"
models = ["my-model"]
```

A literal `base_url` wins over `base_url_env`, so set only the one you need:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[models.providers.myprovider]
base_url = "https://fixed.example/v1"   # used
base_url_env = "MYPROVIDER_BASE_URL"    # ignored while base_url is set
```

#### Overrides keep the pair together

When you store a key with `/auth`, the endpoint you enter (or the provider's default, if left blank) is applied together with the key. Storing a key with a blank base URL also clears any endpoint already set in your environment (for example, a gateway `OPENAI_BASE_URL` your shell exports), so your key goes to the provider's default endpoint instead of to that gateway.

```bash title="Scope both the key and the endpoint to Deep Agents Code" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
DEEPAGENTS_CODE_OPENAI_API_KEY=sk-cli-only
DEEPAGENTS_CODE_OPENAI_BASE_URL=https://api.openai.com/v1
```

#### Managed gateways

On a machine provisioned with a model gateway (for example, the LangSmith gateway), the gateway typically exports a gateway key and the matching endpoint variable (`OPENAI_BASE_URL`, `ANTHROPIC_BASE_URL`, or `GOOGLE_GEMINI_BASE_URL`) together. Deep Agents Code uses that pair by default, so no configuration is needed.

To use your own key instead, store it with `/auth` (leave the base URL blank for the provider default, or set it explicitly), or set the `DEEPAGENTS_CODE_` prefixed key and endpoint. Both override the gateway pair without leaving a mismatched endpoint behind.

***

## Skill directory allowlist

By default, when Deep Agents Code loads skills it validates that a resolved skill file path stays inside one of the standard [skill directories](/oss/python/deepagents/code/data-locations#skills). This prevents symlinks inside skill directories from reading arbitrary files outside those roots.

If you store shared skill assets in a non-standard location and use symlinks from a standard skill directory to reference them, you can add that location to the containment allowlist. This does **not** add a new skill discovery location: skills are still only discovered from the standard directories.

<ResponseField name="extra_allowed_dirs" type="string[]" post={["optional"]}>
  Paths added to the skill containment allowlist. Supports `~` expansion.

  ```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  [skills]
  extra_allowed_dirs = [
      "~/shared-skills",
      "/opt/team-skills",
  ]
  ```
</ResponseField>

Alternatively, set the `DEEPAGENTS_CODE_EXTRA_SKILLS_DIRS` environment variable as a colon-separated list:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
export DEEPAGENTS_CODE_EXTRA_SKILLS_DIRS="~/shared-skills:/opt/team-skills"
```

When the environment variable is set, it takes precedence over the config file value. Changes take effect on `/reload`.

***

## Themes

Use `/theme` to open an interactive theme selector. Navigate the list to preview themes in real-time, press `Enter` to persist your choice to `config.toml`.

Deep Agents Code ships with many built-in themes. The default theme is `langchain`, a dark theme with LangChain-branded colors. The selected theme is persisted under `[ui]`:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[ui]
theme = "langchain-dark"
```

### User-defined themes

Define custom themes under `[themes.<name>]` sections in `config.toml`. Each section requires `label` (str). `dark` (bool) defaults to `false` if omitted — set to `true` for dark themes. All color fields are optional — omitted fields fall back to the built-in dark or light palette based on the `dark` flag.

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[themes.my-solarized]
label = "My Solarized"
dark = true
primary = "#268BD2"
warning = "#B58900"

# Theme names with spaces require TOML quoting
[themes."ocean breeze"]
label = "Ocean Breeze"
primary = "#0077B6"
background = "#CAF0F8"
```

User-defined themes appear alongside built-in themes in the `/theme` selector.

### Override built-in theme colors

To tweak a built-in theme's colors without creating a new theme, use a `[themes.<builtin-name>]` section. Only color fields are read — `label` and `dark` are inherited from the built-in:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[themes.langchain]
primary = "#FF5500"
```

Omitted color fields retain the existing built-in values.

Changes to `[themes.*]` sections take effect on `/reload`.

### Map themes to terminals

If you switch between terminals with different color schemes (for example, a dark iTerm and a light Apple Terminal), map each one to a theme under `[ui.terminal_themes]`. Deep Agents Code matches the shell's `TERM_PROGRAM` and applies the mapped theme automatically:

```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
[ui.terminal_themes]
"Apple_Terminal" = "langchain-light"
"iTerm.app" = "langchain"
```

Press `T` in the `/theme` picker to save the highlighted theme for the current terminal, or run `echo $TERM_PROGRAM` to find your terminal's identifier and add it by hand.

<Accordion title="Advanced: picker shortcuts, resolution order, terminal identifiers">
  #### Picker shortcuts

  In the `/theme` selector:

  * `N` toggles between display labels and canonical registry keys—the keys are what `[ui] theme` and `[ui.terminal_themes]` accept.
  * `T` saves the highlighted theme into `[ui.terminal_themes]` for the current `TERM_PROGRAM`. The mapped theme is badged `(default)` in the picker.

  #### Common `TERM_PROGRAM` values

  Keys are matched verbatim against the environment variable—quote them in TOML when they contain dots or special characters.

  | Terminal                    | `TERM_PROGRAM`   |
  | --------------------------- | ---------------- |
  | Apple Terminal              | `Apple_Terminal` |
  | iTerm2                      | `iTerm.app`      |
  | WezTerm                     | `WezTerm`        |
  | VS Code integrated terminal | `vscode`         |
  | Ghostty                     | `ghostty`        |

  #### Resolution order

  Deep Agents Code resolves a theme on every launch using this precedence:

  1. `DEEPAGENTS_CODE_THEME` environment variable (explicit override).
  2. `[ui.terminal_themes]` mapping for the current `TERM_PROGRAM`.
  3. `[ui] theme` saved preference (set by `/theme`).
  4. The built-in default (`langchain`).
</Accordion>

***

## Auto-update

Deep Agents Code can automatically check for and install updates.

<Tabs>
  <Tab title="Config file">
    ```toml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    [update]
    auto_update = true
    ```
  </Tab>

  <Tab title="Environment variable">
    ```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
    export DEEPAGENTS_CODE_AUTO_UPDATE=1
    ```
  </Tab>
</Tabs>

The environment variable takes precedence over the config file.

When enabled, Deep Agents Code checks PyPI for a newer version at session start and automatically upgrades using the detected install method (uv, Homebrew, or pip). When disabled (default), Deep Agents Code shows an update hint with the appropriate install command instead.

You can also check for and install updates manually at any time with the `/update` slash command, which bypasses the cache and reports success or failure inline.

After an upgrade, Deep Agents Code shows a "what's new" banner on the next launch with a link to the changelog.

At session exit, if a newer version was detected during the session, an update banner is displayed as a reminder.

***

## Uninstall

To remove the `dcode` and `deepagents-code` binaries and the isolated tool environment, run:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
uv tool uninstall deepagents-code
```

The uninstall command does not remove user configuration or session data. Deep Agents Code stores those files under `~/.deepagents/`, including `config.toml`, `hooks.json`, the global `.env`, and `.state/` contents such as saved sessions and credentials. To delete that data as well, run:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
rm -rf ~/.deepagents
```

***

## Managed deployments

The [install script](https://github.com/langchain-ai/deepagents/blob/main/libs/code/scripts/install.sh) supports running as root, targeting macOS MDM tools (Kandji, Jamf, etc.) that execute scripts in a minimal root environment.

When `id -u` is `0`, the script:

1. Resolves the real console user's `HOME` (via `/dev/console` or a `/Users` directory scan)
2. `chown`s all created files back to the target user after each install step

Non-root installs are unaffected: all root-specific code paths short-circuit when not running as root.

To pre-configure auto-update for managed installs, set `DEEPAGENTS_CODE_AUTO_UPDATE=1` in the user's shell profile or deploy a `config.toml` with `[update] auto_update = true` to `~/.deepagents/config.toml`. To suppress automatic updates and update checks entirely, set `DEEPAGENTS_CODE_NO_UPDATE_CHECK=1`.

To route every user's model traffic through a managed gateway (provisioning a gateway key and base URL fleet-wide), see [Managed gateways](#managed-gateways).

***

## Environment variable reference

All Deep Agents Code-specific environment variables use the `DEEPAGENTS_CODE_` prefix. See [`DEEPAGENTS_CODE_` prefix](#deepagents_code_-prefix) for how the prefix also works as an override for third-party credentials.

<ResponseField name="DEEPAGENTS_CODE_AUTO_UPDATE" type="string" post={["optional"]}>
  Enable automatic Deep Agents Code updates (`1`, `true`, or `yes`).
</ResponseField>

<ResponseField name="DEEPAGENTS_CODE_DEBUG" type="string" post={["optional"]}>
  Enable verbose debug logging to a file. Accepts `1`, `true`, `yes`, `on` (case-insensitive) as enabled; `0`, `false`, `no`, `off`, empty string, or unset disables it. When enabled, the per-session server log file is preserved on shutdown and its path is printed to stderr for triage.
</ResponseField>

<ResponseField name="DEEPAGENTS_CODE_DEBUG_FILE" type="string" default="/tmp/deepagents_debug.log" post={["optional"]}>
  Path for the debug log file.
</ResponseField>

<ResponseField name="DEEPAGENTS_CODE_EXTRA_SKILLS_DIRS" type="string" post={["optional"]}>
  Colon-separated paths added to the [skill containment allowlist](#skill-directory-allowlist).
</ResponseField>

<ResponseField name="DEEPAGENTS_CODE_LANGSMITH_PROJECT" type="string" post={["optional"]}>
  Override the LangSmith project name for agent traces. See [Trace with LangSmith](/oss/python/deepagents/code/overview#trace-with-langsmith).
</ResponseField>

<ResponseField name="DEEPAGENTS_CODE_NO_UPDATE_CHECK" type="string" post={["optional"]}>
  Disable automatic update checking when set.
</ResponseField>

<ResponseField name="DEEPAGENTS_CODE_SHELL_ALLOW_LIST" type="string" post={["optional"]}>
  Comma-separated shell commands to allow (or `recommended` / `all`).
</ResponseField>

<ResponseField name="DEEPAGENTS_CODE_USER_ID" type="string" post={["optional"]}>
  Attach a user identifier to LangSmith trace metadata.
</ResponseField>

***

## External editor

Press `Ctrl+X` or type `/editor` to compose prompts in an external editor. Deep Agents Code checks `$VISUAL`, then `$EDITOR`, then falls back to `vi` (macOS/Linux) or `notepad` (Windows). GUI editors (VS Code, Cursor, Zed, Sublime Text, Windsurf) automatically receive a `--wait` flag so Deep Agents Code blocks until you close the file.

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
# Set in your shell profile (~/.zshrc, ~/.bashrc, etc.)
export VISUAL="code"    # GUI editor (--wait auto-injected)
export EDITOR="nvim"    # Terminal fallback
```

***

## Hooks

Hooks let external programs react to Deep Agents Code lifecycle events. Configure commands in `~/.deepagents/hooks.json` and it pipes a JSON payload to each matching command's stdin whenever an event fires.

Hooks run fire-and-forget in a background thread — they never block Deep Agents Code and failures are logged without interrupting your session.

### Setup

Create `~/.deepagents/hooks.json`:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "hooks": [
    {
      "command": ["bash", "-c", "cat >> ~/deepagents-events.log"],
      "events": ["session.start", "session.end"]
    }
  ]
}
```

Now every time a session starts or ends, Deep Agents Code appends the event payload to `~/deepagents-events.log`.

### Hook configuration

The config file contains a single `hooks` array. Each entry has:

<ResponseField name="command" type="list[str]" required>
  Command and arguments to run. No shell expansion: use `["bash", "-c", "..."]` if needed.
</ResponseField>

<ResponseField name="events" type="list[str]" post={["optional"]}>
  Event names to subscribe to. Omit or leave empty to receive **all** events.
</ResponseField>

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "hooks": [
    {
      "command": ["python3", "my_handler.py"],
      "events": ["session.start", "task.complete"]
    },
    {
      "command": ["bash", "log_everything.sh"]
    }
  ]
}
```

The second hook above has no `events` filter, so it receives every event Deep Agents Code emits.

### Payload format

Each hook command receives a JSON object on stdin with an `"event"` key plus event-specific fields:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "event": "session.start",
  "thread_id": "abc123"
}
```

### Events reference

#### `session.start`

Fired when an agent session begins (both interactive and non-interactive modes).

<ResponseField name="thread_id" type="string" required>
  The session thread identifier.
</ResponseField>

#### `session.end`

Fired when a session exits.

<ResponseField name="thread_id" type="string" required>
  The session thread identifier.
</ResponseField>

#### `user.prompt`

Fired in interactive mode when the user submits a chat message.

No additional fields.

#### `input.required`

Fired when the agent requires human input (human-in-the-loop interrupt).

No additional fields.

#### `permission.request`

Fired before the approval dialog when one or more tool calls need user permission.

<ResponseField name="tool_names" type="list[str]" required>
  Names of the tools requesting approval.
</ResponseField>

#### `tool.error`

Fired when a tool call returns an error.

<ResponseField name="tool_names" type="list[str]" required>
  Names of the tool(s) that errored.
</ResponseField>

#### `task.complete`

Fired when the agent finishes its current task (the streaming loop ends without further interrupts).

<ResponseField name="thread_id" type="string" required>
  The session thread identifier.
</ResponseField>

#### `context.compact`

Fired before Deep Agents Code compacts (summarizes) the conversation context.

No additional fields.

### Execution model

* **Background thread**: Hook subprocesses run in a thread via `asyncio.to_thread` so the main event loop is never blocked.
* **Concurrent dispatch**: When multiple hooks match an event, they run concurrently in a thread pool.
* **5-second timeout**: Each command has a 5-second timeout. Commands that exceed this are killed.
* **Fire-and-forget**: Errors are caught per-hook and logged at debug/warning level. A failing hook never crashes or stalls Deep Agents Code.
* **Lazy loading**: The config file is read once on the first event dispatch and cached for the rest of the session.
* **No shell expansion**: Commands are executed directly (not through a shell). Wrap in `["bash", "-c", "..."]` if you need shell features like pipes or variable expansion.

### Hook examples

<Accordion title="Log all events to a file">
  ```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  {
    "hooks": [
      {
        "command": ["bash", "-c", "jq -c . >> ~/.deepagents/hook-events.jsonl"],
        "events": []
      }
    ]
  }
  ```
</Accordion>

<Accordion title="Desktop notification on task completion (macOS)">
  ```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  {
    "hooks": [
      {
        "command": [
          "bash", "-c",
          "osascript -e 'display notification \"Agent finished\" with title \"Deep Agents\"'"
        ],
        "events": ["task.complete"]
      }
    ]
  }
  ```
</Accordion>

<Accordion title="Python handler">
  Write a handler script that reads the JSON payload from stdin:

  ```python title="my_handler.py" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import json
  import sys

  payload = json.load(sys.stdin)
  event = payload["event"]

  if event == "session.start":
      print(f"Session started: {payload['thread_id']}", file=sys.stderr)
  elif event == "permission.request":
      print(f"Approval needed for: {payload['tool_names']}", file=sys.stderr)
  ```

  ```json title="~/.deepagents/hooks.json" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  {
    "hooks": [
      {
        "command": ["python3", "my_handler.py"],
        "events": ["session.start", "permission.request"]
      }
    ]
  }
  ```
</Accordion>

### Security considerations

Hooks follow the same trust model as Git hooks or shell aliases — any user who can write to `~/.deepagents/hooks.json` can execute arbitrary commands. This is by design:

* **No command injection**: Payload data flows only to stdin as JSON, never to command-line arguments. `json.dumps` handles escaping.
* **No shell by default**: Commands run with `shell=False`, preventing shell injection.
* **Malformed config**: Invalid JSON or unexpected types produce logged warnings, not security issues.

<Warning>
  Only add hooks from sources you trust. A hook has the same permissions as your user account.
</Warning>

***

<div className="source-links">
  <Callout icon="terminal-2">
    [Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
  </Callout>

  <Callout icon="edit">
    [Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/oss/deepagents/code/configuration.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
  </Callout>
</div>
