# Developer's Guide

- [Developer's Guide](#developers-guide)
  - [Quickstart](#quickstart)
  - [Setting Up Your macOS Development Environment](#setting-up-your-macos-development-environment)
  - [Testing and Linting](#testing-and-linting)
  - [Installing Pre-Commit Hooks](#installing-pre-commit-hooks)
  - [Contributing Notebooks](#contributing-notebooks)
  - [Contributing Documentation](#contributing-documentation)
    - [Getting Started](#getting-started)
    - [Making Changes](#making-changes)
  - [Building the Package](#building-the-package)
  - [Installing a Phoenix Build](#installing-a-phoenix-build)
  - [Installing a `git` Branch on Colab](#installing-a-git-branch-on-colab)
  - [Best Practices](#best-practices)
    - [REST API](#rest-api)
      - [HTTP Methods](#http-methods)
      - [Status Codes](#status-codes)
      - [Path Structure](#path-structure)
      - [Query Parameters](#query-parameters)
      - [Pagination](#pagination)
      - [Response Format](#response-format)
  - [Cursor / VS Code](#cursor--vs-code)
    - [Debugging the Python Server](#debugging-the-python-server)

## Quickstart

The fastest path from a fresh clone to a running Phoenix dev server. See the sections below for details on any step.

**Prerequisites**

- [uv](https://docs.astral.sh/uv/getting-started/installation/) (Python environment management)
- [nvm](https://github.com/nvm-sh/nvm) (Node version management)

```bash
# 1. Install Python dependencies (installs Phoenix and all sub-packages in editable mode)
uv sync --all-extras

# 2. Install the pinned Node.js version (reads .nvmrc) and pnpm
nvm install
npm i -g pnpm@11.11.0

# 3. Install and build the web app
cd app
cp .env.example .env
# edit .env and change PHOENIX_AUTH to `false` if you do not want to manage API keys during development
pnpm install
pnpm run build

# 4. Start the dev server (Python API + frontend with hot reload)
pnpm dev
```

Open [http://localhost:6006](http://localhost:6006). If authentication is enabled, log in with **`admin@localhost`** / **`admin`**, or set `PHOENIX_ENABLE_AUTH=False` in `app/.env` to bypass it.

> **💡 Tip:** Optionally use an in-memory database for a fresh Phoenix on every restart:
>
> ```bash
> PHOENIX_SQL_DATABASE_URL=sqlite:///:memory: pnpm dev
> ```

To send traces to your dev server, point any OpenInference/OpenTelemetry instrumented app at `http://localhost:6006` (for example, `PHOENIX_COLLECTOR_ENDPOINT=http://localhost:6006`). See the [Vercel AI SDK tracing guide](https://arize.com/docs/phoenix/integrations/typescript/vercel/vercel-ai-sdk-tracing-js) or the runnable [AI SDK agent example](./js/examples/apps/ai-sdk-agent) for a minimal traced agent.

If a step fails, consult the detailed setup instructions below.

## Setting Up Your macOS Development Environment

We recommend using a virtual environment to isolate your Python dependencies. This guide will use `uv`, but you can use a different virtual environment management tool such as `conda` if you want.

We recommend installing the project version of `uv` (found in `pyproject.toml` under `tool.uv.required-version`) by using the [standalone installer](https://docs.astral.sh/uv/getting-started/installation/#standalone-installer). This will enable you to upgrade `uv` using the `uv self update` command when the project `uv` version is updated.

The following command installs the main `arize-phoenix` package and all sub-packages in editable mode with development dependencies. It uses the lowest currently supported Python version to ensure compatibility with all supported Python versions.

```bash
uv sync --python 3.10
```

The sub-packages (`phoenix.evals`, `phoenix.otel`, and `phoenix.client`) located under the packages/ directory are automatically installed in editable mode via the `uv` workspace configuration.

**Next**, install the web build dependencies.

We recommend installing [nodejs via nvm](https://github.com/nvm-sh/nvm) and then
installing `pnpm` globally to manage the web frontend dependencies.

```bash
# install nvm
# https://github.com/nvm-sh/nvm
# install node via nvm, our .nvmrc file will automatically instruct nvm to install
# the version specified in the file
nvm install
# set it as default (optional)
nvm alias default <version-that-was-installed>
# install pnpm globally for v22
npm i -g pnpm@9.15.5
```

Then we will build the web app.

Change directory to `app`:

```bash
cd app
```

and run:

```bash
pnpm install
pnpm run build
```

Check out the `README.md` file in the `app` directory for more information on developing the web application.

## Testing and Linting

Phoenix is backed with either a `sqlite` or `postgresql` database. By default, tests that involve
persistence in some way run against both backends. Ensure that `postgresql` is installed on your
system.

```bash
brew install postgresql
```

Ensure your environment is set up so that `pg_config` points to the correct binary.

```bash
pg_config --bindir
```

This command should point to the `homebrew` install of `postgresql`, if it doesn't, try creating
a fresh Python environment or modifying your `PATH`.

Phoenix uses `tox` to run linters, formatters, type-checks, tests, and more.

`tox` manages isolated virtual environments, each with a corresponding set of commands. These environments are defined inside of `tox.ini` and can be enumerated by running

```bash
tox list
```

Commands corresponding to an environment can be executed by running `tox run -e <env-name>`. For example, you can execute unit tests by running

```bash
tox run -e unit_tests
```

By default, database tests only run against `sqlite`, in order to run database tests against
a `postgresql` database as well, use the `--run-postgres` flag

```bash
tox run -e unit_tests -- --run-postgres
```

To run unit tests faster using parallel execution:

```bash
tox r -e unit_tests -- -n auto
```

To run type checking:

```bash
make typecheck-python
```

Check the output of `tox list` to find commands for linters, formatters, and other tools.

## Installing Pre-Commit Hooks

First, install `pre-commit` globally. It is recommended to accomplish this using `uv`.

```bash
uv tool install pre-commit --with pre-commit-uv
```

Then install the project pre-commit hooks with

```bash
pre-commit install
```

Once installed, the pre-commit hooks configured in `.pre-commit-config.yaml` will automatically run prior to each `git commit`. Pre-commit hooks can be skipped by passing the `-n`/ `--no-verify` flag to the `git commit` command.

## Contributing Notebooks

To add or modify a Jupyter notebook, the following commands are needed to pass CI.

- `tox run -e ruff`: Runs formatters
- `tox run -e clean_jupyter_notebooks`: Removes cell output and notebook metadata to keep the diff as small as possible

## Contributing Documentation

Phoenix documentation is built using [Mintlify](https://mintlify.com/). The documentation source files are located in the `docs/` directory.

### Getting Started

1. Install the Mintlify CLI:

```sh
npm i -g mint
```

2. Run the local development server:

```bash
mint dev
```

3. Open your browser to `http://localhost:3000` to preview your changes.

### Making Changes

- Documentation pages are written in MDX (Markdown with JSX support).
- The `docs.json` file controls navigation and site-wide settings.
- Images and other assets should be placed in the appropriate subdirectories.

For more details on Mintlify's features, including formatting, components, and deployment, see the [Mintlify Quickstart Guide](https://www.mintlify.com/docs/quickstart).

## Building the Package

To build Phoenix, you must build the `app` and the python package.

To build the `app`, navigate to the `app` directory and run

```bash
pnpm run build
```

Then, from the root directory of the repo, run

```bash
make build-python
```

If successful, a source distribution (a tarball) and a Python `wheel` will appear in the `dist` folder at the repo base directory.

## Installing a Phoenix Build

We recommend using a separate virtual environment (e.g., `phoenixtest`) for installing and testing the builds created above.

To install Phoenix from the source distribution (i.e., tarball), run

```bash
pip install /path/to/source/distribution/tarball.tar.gz
```

To install Phoenix from the Python `wheel`, you must first install `wheel` with

```bash
pip install wheel
```

Then run

```bash
pip install /path/to/wheel.whl
```

(You should only install one of the source distribution or the `wheel` at a time.)

To make sure everything works, install `jupyter` with

```bash
pip install jupyter
```

and run the notebooks in the `tutorials` directory.

## Installing a `git` Branch on Colab

The code below installs the `main` branch in [Colab](https://colab.research.google.com/notebooks/empty.ipynb) and takes roughly 3 minutes to run.

```jupyterpython
!npm install -g -s n
!n latest
!npm install -g -s npm@latest
%pip install git+https://github.com/Arize-ai/phoenix.git@main
```

## Best Practices

### REST API

- The API should communicate over JSON unless otherwise specified by the URL.
- The API should be versioned. If a backwards incompatible change is made, the new route should be nested under a new version.

#### HTTP Methods

- **GET** Used to retrieve a representation of a resource.
- **POST** Used to create new resources and sub-resources.
- **PUT** Used to update existing resources. Use PUT when you want to replace a resource.
- **PATCH** Used to update existing resources. Use PATCH when you want to apply a partial update to the resource.
- **DELETE** Used to delete existing resources.

#### Status Codes

- **4xx** The client application behaved erroneously - client error
- **5xx** The API behaved erroneously - server error
- **2xx** The client and API worked

#### Path Structure

- Use nouns for resources and sub-resources.
- Avoid using verbs in the path.
- Nouns should be pluralized and followed by a globally unique identifier for specific resources (e.g., `/datasets/:dataset_id` where the dataset ID is the globally unique identifier consistent with the GraphQL API).

#### Query Parameters

Use query parameters for filtering, sorting, and pagination. Query parameters should use `_` as a separator.

#### Pagination

Use cursor-based pagination. Each request gives a cursor to the next page of results.

#### Response Format

- The response should be a JSON object with a `data` key.
- Payload content should use snake case to make it easier to work with when translating to objects.

## Cursor / VS Code

A recommended list of extensions for Cursor/VSCode is located in the `.vscode/extensions.json` file.
When opening Phoenix in Cursor, you will automatically be prompted to install the recommended extensions.
After doing so, consider pasting the following settings into your workspace settings at `.vscode/settings.json` to make sure the extensions work when Phoenix is opened at the root of the monorepo.

```json
{
  "python.languageServer": "Default",
  "mypy-type-checker.importStrategy": "fromEnvironment",
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.fixAll.ruff": "always"
    }
  },
  "[typescript, typescriptreact]": {
    "editor.defaultFormatter": "oxc.oxc-vscode",
    "editor.codeActionsOnSave": {
      "source.fixAll.oxlint": "always"
    }
  },
  "mypy-type-checker.ignorePatterns": [".tox,.venv,app"],
  "javascript.preferences.importModuleSpecifier": "shortest",
  "typescript.preferences.importModuleSpecifier": "non-relative",
  "oxc.fmt.configPath": ".oxfmtrc.jsonc",
  "oxc.path.oxfmt": "app/node_modules/oxfmt/bin/oxfmt",
  "oxc.path.oxlint": "app/node_modules/oxlint/bin/oxlint",
  "editor.defaultFormatter": "oxc.oxc-vscode",
  "editor.formatOnSave": true,
  "relay.rootDirectory": "app",
  "relay.pathToConfig": "app/relay.config.js",
  "relay.autoStartCompiler": true
}
```

> [!NOTE]
> The repo compiles with TypeScript 7 (the native compiler), which no longer ships
> `tsserver`, so do not set `typescript.tsdk`. For IntelliSense that matches the
> compiler, install the [TypeScript (Native Preview)](https://marketplace.visualstudio.com/items?itemName=TypeScriptTeam.native-preview)
> extension; otherwise VS Code's built-in TypeScript language service works fine for
> editing. Tools that still need the JS compiler API (openapi-typescript, typedoc,
> Storybook docgen) resolve the `@typescript/typescript6` bridge via `.pnpmfile.cjs`
> in `app/` and `js/`.

### Debugging the Python Server

The dev server runs with `debugpy` enabled, allowing you to attach a debugger from VS Code or Cursor.

1. **Create a launch configuration** at `.vscode/launch.json`:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Attach to Phoenix Dev Server",
      "type": "debugpy",
      "request": "attach",
      "connect": {
        "host": "localhost",
        "port": 5678
      },
      "justMyCode": false
    }
  ]
}
```

> **Note:** The default debugpy port is 5678. If you customize it via the `DEBUGPY_PORT` environment variable, update the `port` value in the launch configuration to match.

2. **Start the dev environment** from the `app` directory:

```bash
 pnpm dev
```

This launches both the Python server and the frontend UI simultaneously using `mprocs`. The server will start with debugpy listening on port 5678.

> **💡 Tip:** Use in-memory SQLite for a fresh database without affecting your existing on-disk data:
>
> ```bash
> PHOENIX_SQL_DATABASE_URL=sqlite:///:memory: pnpm dev
> ```
>
> **💡 Tip:** Customize ports via environment variables:
>
> ```bash
> VITE_PORT=3000 DEBUGPY_PORT=5679 pnpm dev
> ```
>
> Or add to `app/.env`:
>
> ```
> VITE_PORT=3000
> DEBUGPY_PORT=5679
> ```

3. **Set breakpoints** by clicking in the gutter (left of line numbers) in any Python file.
4. **Attach the debugger**:

- Press `⇧⌘D` (macOS) or `Ctrl+Shift+D` (Windows/Linux) to open the Run and Debug panel
- Select **"Attach to Phoenix Dev Server"** from the dropdown
- Press `F5` or click the green play button

5. **Trigger your code** by making a request to the server via the UI or API.
6. **Debug**: When a breakpoint is hit, use the debug toolbar to step through code:

- `F10` — Step over
- `F11` — Step into
- `F5` — Continue
- Inspect variables in the left panel or evaluate expressions in the Debug Console
