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

# Language servers and formatters

> Give the model code navigation through language servers, and a tool to format files.

o4 can connect to language servers and code formatters you already have
installed. With a language server, the model can jump to definitions, find
references, and read type information instead of searching text. With a
formatter, the model can format a file after it edits it.

Both are tools the model calls when it decides to. o4 doesn't run them
automatically after each edit, and it doesn't feed language-server
diagnostics back to the model. Both are available in interactive sessions,
not in print mode (`o4 -p`) or evals.

## Language servers

Language servers work without setup for four languages, as long as the
server is installed and on your `PATH`:

| Server command | File extensions |
| - | - |
| `rust-analyzer` | `.rs` |
| `typescript-language-server --stdio` | `.ts`, `.tsx`, `.js`, `.jsx` |
| `pyright-langserver --stdio` | `.py` |
| `gopls` | `.go` |

o4 starts a server the first time the model asks about a file with one of its
extensions, and keeps it running for the rest of the session. It starts a
separate copy of the server for each extension, so `.ts` and `.tsx` files get
two `typescript-language-server` processes. The server runs in the directory
you started o4 in. If a server isn't installed, the model's request fails
with an error and the session carries on.

<Warning>
  In 0.2.74, o4 doesn't send language servers the `initialize` request that the
  language server protocol requires before anything else. Standard servers such
  as `rust-analyzer` and `clangd` answer every request with a "not initialized"
  error, so the `lsp` tool returns an `LSP error -32002` instead of a result.
  For code navigation that works today, use the code index. See
  [Code intelligence](/guides/code-intelligence).
</Warning>

### What the model can do

The model uses the `lsp` tool, which takes an operation, a file path
(`filePath`), and a 1-based `line` and `character` position:

| Operation | What it returns |
| - | - |
| `goToDefinition` | Where the symbol at the position is defined |
| `findReferences` | Every place the symbol is used |
| `hover` | Type and documentation for the symbol |
| `documentSymbol` | The symbols in the file |
| `workspaceSymbol` | Symbols across the workspace. The tool always sends an empty search query. |
| `goToImplementation` | Implementations of an interface or trait |
| `prepareCallHierarchy` | The call-hierarchy item at the position |
| `incomingCalls` | Callers of the function |
| `outgoingCalls` | Functions it calls |

`incomingCalls` and `outgoingCalls` send a file position, but the protocol
expects the item that `prepareCallHierarchy` returns, so servers can reject
them.

In the default `ask` permission mode, the first `lsp` call in a session asks
for your approval. After you approve, o4 doesn't ask again for the rest of the
session. See [Permissions](/safety/permissions).

For text and symbol search that doesn't need a language server, see
[Code intelligence](/guides/code-intelligence).

### Configure language servers

To use other servers, or change the command for a built-in one, add
`lsp_servers` to `~/.o4/settings.json`. Each entry has a name you choose, the
command, optional arguments, and the file extensions it handles (without the
dot):

```json theme={null}
{
  "lsp_servers": {
    "rust": {
      "command": "rust-analyzer",
      "extensions": ["rs"]
    },
    "clangd": {
      "command": "clangd",
      "args": ["--background-index"],
      "extensions": ["c", "h", "cpp", "hpp"]
    }
  }
}
```

<Warning>
  Once `lsp_servers` has at least one entry, it replaces the built-in list. List
  every server you want, including any of the four built-in ones.
</Warning>

An entry needs a non-empty `command` and at least one extension. o4 ignores
entries without them. Extensions match without regard to case, and an
extension written with a leading dot, such as `".rs"`, never matches. If two
entries claim the same extension, the entry whose name sorts first
alphabetically wins. If every entry is invalid, the model gets no working
servers; o4 doesn't fall back to the built-in list.

o4 reads these settings when it starts. Restart o4 after you change them.

## Formatters

o4 has no built-in formatters. When you configure at least one, the model gets
a `format` tool that formats one file at a time with the formatter set for
that file's extension.

Add `formatters` to `~/.o4/settings.json`:

```json theme={null}
{
  "formatters": {
    "rustfmt": {
      "command": "rustfmt",
      "args": ["--edition", "2021"],
      "extensions": ["rs"]
    },
    "prettier": {
      "command": "prettier",
      "args": ["--write"],
      "extensions": ["ts", "tsx", "js", "json", "md"]
    }
  }
}
```

o4 runs the command with your `args` and then the file path, so the
formatter must rewrite the file in place. That's why the `prettier` example
passes `--write`. Like language servers, an entry needs a non-empty `command`
and at least one extension, and when two entries claim the same extension,
the name that sorts first wins.

How a formatter runs:

* The file must already exist inside the folders o4 may access, and the tool
  formats one file per call.
* It runs through the same sandbox as the model's shell commands. See
  [Sandbox](/safety/sandbox).
* It has 2 minutes to finish unless the model sets a shorter or longer
  `timeout`, in milliseconds.
* If it exits with a non-zero code, the model gets the formatter's output as
  the error. On success the model gets `Formatted <file> with <name>`, not the
  formatter's output.
* In the default `ask` permission mode, the first `format` call in a session
  asks for your approval. After you approve, o4 doesn't ask again for the rest
  of the session.

o4 reads these settings when it starts. Restart o4 after you change them.

## Project settings

You can also put `lsp_servers` and `formatters` in `.o4/settings.json` in a
project, so everyone who works on it gets the same setup. o4 reads that file
from the directory you start o4 in. Project entries are added to your user
entries, and a project entry replaces a user entry with the same name. A
project `lsp_servers` entry also replaces the built-in list, as it does in
your own file.

Because these settings choose programs to run, o4 reads a project's
`.o4/settings.json` only after you trust the workspace. See
[Workspace trust](/safety/workspace-trust).

## See your setup

Run `/config tools` to open the **Tools** tab of the settings. It lists the
language servers and formatters o4 will use:

* **LSP servers** shows each configured server as `name: command args [extensions]`,
  or the four built-in server commands when you haven't configured any.
* **Formatters** shows each configured formatter the same way, or
  `not configured`.

Each row lists the first three entries by name, then `+N more`, and
`N invalid` for entries o4 ignores because they have no command or no
extensions. Press `Enter` on a row to see the full value.

The rows are read-only. Edit `settings.json` to change them. See
[Configuration files](/configuration/overview) for where settings live.
