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

# Codex CLI and IDE

> Give Codex your cross-session Exo memory over hosted MCP, using a static key. One config covers both the CLI and the IDE extension.

The Codex CLI and the Codex IDE extension share `~/.codex/config.toml`, so a single setup covers both. They reach the same `https://api.get-exo.com/mcp/` endpoint Claude Code uses, authenticated with a static Exo API key.

<Note>
  This page covers the Codex CLI and the Codex IDE extension. Codex in the browser does not read `config.toml` and cannot be configured this way. For ChatGPT itself, see [ChatGPT connector](/integrations/chatgpt).
</Note>

## Before you start

* An Exo account allowlisted for the private preview.
* An Exo API key. Mint one in [the dashboard](https://get-exo.com) under **Import**, then **Codex**, or with `POST /v1/keys`. See [Authentication](/authentication).
* Node and the Codex CLI installed, or the Codex IDE extension.

## The short version

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
codex mcp add exo --url https://api.get-exo.com/mcp/ \
  --bearer-token-env-var EXO_API_KEY
```

With `EXO_API_KEY` stored in `${CODEX_HOME:-~/.codex}/.env`, not just exported in your shell. The next section explains why that distinction matters.

## Set it up

<Steps>
  <Step title="Mint a connection key">
    In the dashboard, open **Import**, then **Codex**, and click **Generate connection key**. Copy it. The plaintext is shown once.
  </Step>

  <Step title="Store the key where Codex will actually find it">
    Codex Desktop and IDE sessions do not reliably inherit environment variables from the shell that launched them, so an `export` in your profile is not enough. Write the key to Codex's durable environment file instead.

    <Tabs>
      <Tab title="Windows PowerShell">
        ```powershell theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
        $codexDir = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME '.codex' }
        New-Item -ItemType Directory -Force -Path $codexDir | Out-Null
        $envFile = Join-Path $codexDir '.env'
        $lines = if (Test-Path $envFile) {
          @([IO.File]::ReadAllLines($envFile, [Text.UTF8Encoding]::new($false)) | Where-Object { $_ -notmatch '^\s*(export\s+)?EXO_API_KEY\s*=' })
        } else { @() }
        [IO.File]::WriteAllLines($envFile, @($lines) + 'EXO_API_KEY=exo_prod_your_key_here', [Text.UTF8Encoding]::new($false))
        ```
      </Tab>

      <Tab title="bash and zsh">
        ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
        codex_dir="${CODEX_HOME:-$HOME/.codex}"
        mkdir -p "$codex_dir"
        env_file="$codex_dir/.env"
        tmp_file="$env_file.tmp"
        { grep -Ev '^[[:space:]]*(export[[:space:]]+)?EXO_API_KEY[[:space:]]*=' "$env_file" 2>/dev/null || true; \
          printf '%s\n' 'EXO_API_KEY=exo_prod_your_key_here'; } > "$tmp_file"
        mv "$tmp_file" "$env_file"
        chmod 600 "$env_file"
        ```
      </Tab>
    </Tabs>

    Both snippets remove any previous `EXO_API_KEY` line before appending, so re-running them rotates the key rather than stacking duplicates.
  </Step>

  <Step title="Register the server">
    The plugin path, which persists across Codex tasks:

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    codex plugin marketplace add With-Exo-AI/exo-plugin
    codex plugin add exo@exo
    ```

    Or register the endpoint directly:

    ```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    codex mcp add exo --url https://api.get-exo.com/mcp/ \
      --bearer-token-env-var EXO_API_KEY
    ```

    Only the credential needs to be stored durably. The registration itself persists on its own.
  </Step>

  <Step title="Restart Codex fully, then verify">
    Start a new task and run `/mcp`. Exo should be listed with its tools: `exo_context`, `exo_capture`, `search`, `fetch` and the rest.

    The dashboard's Codex card flips to **Connected** after the first authenticated request from that key, and the key list shows a last-used time. That is the check that cannot be faked by a config file.
  </Step>
</Steps>

## When it goes wrong

<AccordionGroup>
  <Accordion title="`missing field 'command'` when adding a url server" icon="circle-question">
    Your Codex build predates native Streamable HTTP support. Update Codex, or add this line at the top of `~/.codex/config.toml`:

    ```toml theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
    experimental_use_rmcp_client = true
    ```
  </Accordion>

  <Accordion title="401 right after a setup you are sure is correct" icon="circle-question">
    Two usual causes. First, the URL lost its trailing slash: a bare `/mcp` redirects, and the redirect drops the `Authorization` header behind a TLS-terminating proxy. Re-add with `/mcp/`.

    Second, the key is not actually reaching the process. Check the dashboard key list. A key that reads **Never used** was never sent, which almost always means it went into a shell profile instead of `${CODEX_HOME:-~/.codex}/.env`.
  </Accordion>

  <Accordion title="OAuth authenticates but no tools appear" icon="circle-question">
    Codex can speak OAuth against Exo's OAuth 2.1 server with `auth = "oauth"` and `codex mcp login`, and Exo accepts it. Codex's own OAuth client has known upstream issues though: a missing `User-Agent` breaks discovery behind some proxies, and the desktop app can authenticate and then import no tools. The static-key path on this page is the supported route.
  </Accordion>

  <Accordion title="It connects, but Exo knows nothing about you" icon="circle-question">
    Your organization has no content yet. Every recall surface returns empty collections until content lands and the background cognition cycle runs. See [How a memory is made](/concepts/memory-lifecycle), then [bring data in](/integrations/imports).
  </Accordion>
</AccordionGroup>

## Ingest your Codex history

Codex writes full session transcripts, called rollouts, to `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`. The `exo` CLI reads them and loads them into your graph:

```bash theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
exo backfill --source codex   # one-time import of past Codex sessions
exo daemon                    # tail new Claude Code and Codex sessions live
```

`--source all` covers Claude Code and Codex in one run. Re-runs are dedup safe, because each event carries a stable dedup key, so a second backfill over the same transcripts does not duplicate anything.

Requires an `exo` CLI release with Codex support. See [Coding session history](/integrations/sessions) for what the pipeline does with the transcripts once they land.

## Next

<Columns cols={2}>
  <Card title="Coding session history" icon="terminal" href="/integrations/sessions">
    What backfill sends, and how to watch the graph build.
  </Card>

  <Card title="Conditioning your own agent" icon="sliders" href="/guides/conditioning">
    Inject an identity-conditioned prompt into any model, not only Codex.
  </Card>
</Columns>
