# 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). Any recent 0.12.x works; you don't need the exact version the repo pins. - [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 --all-packages # 2. Install the pinned Node.js and pnpm versions nvm install npm i -g pnpm@12.0.0 # 3. Install dekit, the process manager that `pnpm dev` uses to run the API and UI together curl -fsSL https://dekit.run/install.sh | sh # 4. Install the JavaScript workspace and build the web app cd js pnpm install pnpm build cp app/.env.example app/.env # Set PHOENIX_ENABLE_AUTH=False in app/.env to disable authentication locally # 5. Start the dev server (Python API + frontend with hot reload) cd app pnpm dev ``` `pnpm dev` starts the API, the Vite dev server, and a trace generator as dekit tasks and attaches a console to them. The tasks run in a detached runner, so they survive closing the terminal: press `q` to detach and leave them running, `Q` to stop everything, or run `dekit down` from a shell. `dekit help` documents the rest of the CLI. Open [http://localhost:6006](http://localhost:6006). If authentication is enabled, log in with **`admin@localhost`** / **`admin`**, or set `PHOENIX_ENABLE_AUTH=False` in `js/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. Your system `uv` only needs to satisfy the range in `pyproject.toml` under `tool.uv.required-version`. The range's lower bound is the exact version CI uses, and `uv.lock` should be written by that version: different `uv` versions can serialize the same lockfile differently. You don't have to install it. `scripts/uv.sh` runs the pinned `uv` through `uv tool run` (cached, nothing installed globally), and `make`, the `js/app` pnpm scripts and the Playwright test server all go through it. When you change dependencies, use the wrapper instead of a bare `uv`: ```bash scripts/uv.sh add # or: scripts/uv.sh lock pnpm --dir js/app uv lock # the same wrapper, from pnpm ``` The following command installs the main `arize-phoenix` package and all sub-packages in editable mode with development dependencies. It uses the default development Python version. CI still tests the lowest supported version. ```bash uv sync --python 3.11 --all-packages ``` 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 JavaScript workspace 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 # install pnpm globally npm i -g pnpm@12.0.0 ``` Then install the JavaScript workspace from its root and build the web app: ```bash cd js pnpm install pnpm build cp app/.env.example app/.env ``` Check out the `README.md` file in the `js/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 `uv` to manage the development environment and run linters, formatters, type-checks, and tests. `uv.lock` pins every dependency, so a fresh `uv sync` reproduces the environment CI tests against. ```bash uv sync --all-packages ``` Unit tests run with `pytest` from the `tests` directory: ```bash cd tests && uv run pytest unit/ ``` By default, database tests run against `sqlite`. To run them against `postgresql` instead, pass `--db postgresql`; pytest-postgresql finds `pg_ctl` through `pg_config`, or takes `--postgresql-exec /path/to/pg_ctl`. ```bash cd tests && uv run pytest unit/ --db postgresql ``` To run unit tests faster using parallel execution: ```bash cd tests && uv run pytest unit/ -n auto ``` To run type checking: ```bash make typecheck-python ``` Run `make help` 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. - `make format-python`: Runs formatters - `make clean-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 `js/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": [".venv,js/app"], "javascript.preferences.importModuleSpecifier": "shortest", "typescript.preferences.importModuleSpecifier": "non-relative", "oxc.fmt.configPath": ".oxfmtrc.jsonc", "oxc.path.oxfmt": "js/app/node_modules/oxfmt/bin/oxfmt", "oxc.path.oxlint": "js/app/node_modules/oxlint/bin/oxlint", "editor.defaultFormatter": "oxc.oxc-vscode", "editor.formatOnSave": true, "relay.rootDirectory": "js/app", "relay.pathToConfig": "js/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 `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 `js/app` directory: ```bash pnpm dev ``` This launches both the Python server and the frontend UI simultaneously using [dekit](https://dekit.run) (see `js/app/dekit.yaml`). 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 > ``` > > Environment variables apply when the dekit runner starts. If a runner is already up, run `dekit down` first so the new values take effect. > > Or add to `js/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