Contributing to promptfoo
We welcome contributions from the community to help make promptfoo better. This guide will help you get started. If you have any questions, please reach out to us on Discord or through a GitHub issue.
Project Overview
promptfoo is an MIT licensed tool for testing and evaluating LLM apps.
We particularly welcome contributions in the following areas:
- Bug fixes
- Documentation updates, including examples and guides
- Updates to providers including new models, new capabilities (tool use, function calling, JSON mode, file uploads, etc.)
- Features that improve the user experience of promptfoo, especially relating to RAGs, Agents, and synthetic data generation.
Getting Started
-
Fork the repository on GitHub.
-
Clone your fork locally:
git clone https://github.com/[your-username]/promptfoo.git
cd promptfoo -
Set up your development environment:
3.1. Setup locally
# We recommend using the Node.js version specified in the .nvmrc file (ensure node >= 18)
nvm use
npm install3.2 Setup using
devcontainer
(requires Docker and VSCode)Open the repository in VSCode and click on the "Reopen in Container" button. This will build a Docker container with all the necessary dependencies.
Now install node based dependencies:
npm install
-
Run the tests to make sure everything is working:
npm test
-
Build the project:
npm run build
-
Run the project:
npm run dev
This will run the express server on port 15500 and the web UI on port 3000. Both the API and UI will be automatically reloaded when you make changes.
Note: The developement experience is a little bit different than how it runs in production. In development, the web UI is served using a Vite server. In all other environments, the front end is built and served as a static site via the Express server.
If you're not sure where to start, check out our good first issues or join our Discord community for guidance.
Development Workflow
-
Create a new branch for your feature or bug fix:
git checkout -b feature/your-feature-name
-
We try to follow the Conventional Commits specification. This is not required for feature branches. We merge all PRs into
main
with a squash merge and a conventional commit message. -
Push your branch to your fork:
git push origin your-branch-name
-
Open a pull request against the
main
branch of the promptfoo repository.
When opening a pull request:
- Keep changes small and focused. Avoid mixing refactors with new features.
- Ensure test coverage for new code or bug fixes.
- Provide clear instructions on how to reproduce the problem or test the new feature.
- Be responsive to feedback and be prepared to make changes if requested.
- Ensure your tests are passing and your code is properly linted.
Don't hesitate to ask for help. We're here to support you. If you're worried about whether your PR will be accepted, please talk to us first (see Getting Help).
Tests
Running Tests
We use Jest for testing. To run the test suite:
npm test
To run tests in watch mode:
npm run test:watch
You can also run specific tests with:
npx jest [pattern]
Writing Tests
When writing tests, please:
- Run them with the
--randomize
flag to ensure your mocks setup and teardown are not affecting other tests. - Check the coverage report to ensure your changes are covered.
- Avoid adding additional logs to the console.
Linting and Formatting
We use ESLint and Prettier for code linting and formatting. Before submitting a pull request, please run:
npm run format
npm run lint
It's a good idea to run the lint command as npm run lint -- --fix
to automatically fix some linting errors.
Building the Project
To build the project:
npm run build
For continuous building of the api during development:
npm run build:watch
Contributing to the CLI
Running the CLI During Development
We recommend using npm link
to link your local promptfoo
package to the global promptfoo
package:
npm link
promptfoo --help
We recommend running npm run build:watch
in a separate terminal while you are working on the CLI. This will automatically build the CLI when you make changes.
Alternatively, you can run the CLI directly:
npm run local -- eval --config examples/cloudflare-ai/chat_config.yaml
When working on a new feature, we recommend setting up a local promptfooconfig.yaml
that tests your feature. Think of this as an end-to-end test for your feature.
Here's a simple example:
providers:
- id: openai:chat:gpt-4o
prompts:
- Translate "{{input}}" to {{language}}
tests:
- vars:
input: 'Hello, world!'
language: 'English'
assert:
- type: new-assertion-type
Adding a New Provider
Providers are defined in TypeScript. We also provide language bindings for Python and Go. To contribute a new provider:
-
Ensure your provider doesn't already exist in promptfoo and fits its scope. For OpenAI-compatible providers, you may be able to re-use the openai provider and override the base URL and other settings. If your provider is OpenAI compatible, feel free to skip to step 4.
-
Implement the provider in
src/providers/yourProviderName.ts
following our Custom API Provider Docs. Please use our cachesrc/cache.ts
to store responses. If your provider requires a new dependency, please add it as a peer dependency withnpm install --save-peer
. -
Write unit tests in
test/providers.yourProviderName.test.ts
and create an example in theexamples/
directory. -
Document your provider in
site/docs/providers/yourProviderName.md
, including a description, setup instructions, configuration options, and usage examples. You can also add examples to theexamples/
directory. Consider writing a guide comparing your provider to others or highlighting unique features or benefits. -
Update
src/providers/index.ts
andsite/docs/providers/index.md
to include your new provider. Updatesrc/envars.ts
to include any new environment variables your provider may need. -
Ensure all tests pass (
npm test
) and fix any linting issues (npm run lint
).
Contributing to the Web UI
The web UI is written as a React app. It is exported as a static site and hosted by a local express server when bundled.
To run the web UI in dev mode:
npm run dev
This will host the web UI at http://localhost:3000. This allows you to hack on the React app quickly (with fast refresh). If you want to run the web UI without the express server, you can run:
npm run dev:web
To test the entire thing end-to-end, we recommend building the entire project and linking it to promptfoo:
npm run build
promptfoo view
Note that this will not update the web UI if you make further changes to the code. You have to run npm run build
again.
Python Contributions
While promptfoo is primarily written in TypeScript, we support custom Python prompts, providers, asserts, and many examples in Python. We strive to keep our Python codebase simple and minimal, without external dependencies. Please adhere to these guidelines:
- Use Python 3.9 or later
- For linting and formatting, use
ruff
. Runruff check --fix
andruff format
before submitting changes - Follow the Google Python Style Guide
- Use type hints to improve code readability and catch potential errors
- Write unit tests for new Python functions using the built-in
unittest
module - When adding new Python dependencies to an example, update the relevant
requirements.txt
file
Documentation
If you're adding new features or changing existing ones, please update the relevant documentation. We use Docusaurus for our documentation. We strongly encourage examples and guides as well.
Database
promptfoo uses SQLite as its default database, managed through the Drizzle ORM. By default, the database is stored in /.promptfoo/
. You can override this location by setting PROMPTFOO_CONFIG_DIR
. The database schema is defined in src/database.ts
and migrations are stored in drizzle
. Note that the migrations are all generated and you should not access these files directly.
Main Tables
evals
: Stores evaluation details including results and configuration.prompts
: Stores information about different prompts.datasets
: Stores dataset information and test configurations.evalsToPrompts
: Manages the relationship between evaluations and prompts.evalsToDatasets
: Manages the relationship between evaluations and datasets.
You can view the contents of each of these tables by running npx drizzle-kit studio
, which will start a web server.
Adding a Migration
-
Modify Schema: Make changes to your schema in
src/database.ts
. -
Generate Migration: Run the command to create a new migration:
npm run db:generate
This command will create a new SQL file in the
drizzle
directory. -
Review Migration: Inspect the generated migration file to ensure it captures your intended changes.
-
Apply Migration: Apply the migration with:
npm run db:migrate
Release Steps
Note: releases are only issued by maintainers. If you need to to release a new version quickly please send a message on Discord.
As a maintainer, when you are ready to release a new version:
-
Update the version in
package.json
. -
Run
npm install
. -
Add the updated files to Git:
git add package.json package-lock.json
-
Commit the changes:
git commit -m "chore: Bump version to 0.X.Y"
-
Push the changes to the main branch:
git push origin main
-
A version tag will be created automatically by a GitHub Action. After the version tag has been created, generate a new release based on the tagged version.
-
A GitHub Action should automatically publish the package to npm. If it does not, please publish manually.
Getting Help
If you need help or have questions, you can:
- Open an issue on GitHub.
- Join our Discord community.
Code of Conduct
We follow the Contributor Covenant Code of Conduct. Please read and adhere to it in all interactions within our community.