Are you sure you want to delete this access key?
title | sidebar_label | description |
---|---|---|
Contributing to promptfoo | Contributing | Contribute to promptfoo by submitting code, documentation, providers, and features following our development guidelines |
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.
promptfoo is an MIT licensed tool for testing and evaluating LLM apps.
There are several ways to contribute to promptfoo:
Submit Pull Requests: Anyone can contribute by forking the repository and submitting pull requests. You don't need to be a collaborator to contribute code or documentation changes.
Report Issues: Help us by reporting bugs or suggesting improvements through GitHub issues or Discord.
Improve Documentation: Documentation improvements are always welcome, including fixing typos, adding examples, or writing guides.
We particularly welcome contributions in the following areas:
Fork the repository on GitHub by clicking the "Fork" button at the top right of the promptfoo repository.
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 install
3.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.
:::info
The development 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.
Create a new branch for your feature or bug fix:
git checkout -b feature/your-feature-name
Make your changes and commit them. We follow the Conventional Commits specification for PR titles when merging into main
. Individual commits can use any format, since we squash merge all PRs with a conventional commit message.
:::note
All pull requests are squash-merged with a conventional commit message.
:::
Push your branch to your fork:
git push origin your-branch-name
Open a pull request (PR) against the main
branch of the promptfoo repository.
When opening a pull request:
npm run lint -- --fix
and npm run format
respectively.:::tip
If you're unsure about how to implement something, feel free to open a draft PR to get early feedback.
:::
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).
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 (see jest documentation):
npx jest [pattern]
# Example:
# Runs all provider tests
npx jest providers
When writing tests, please:
Run the test suite you modified with the --randomize
flag to ensure your mocks setup and teardown are not affecting other tests.
# Run specific test file with randomization
npx jest path/to/your/test.test.ts --randomize
# Run all tests in a directory with randomization
npm run test -- --testPathPattern="test/providers" --randomize
Ensure proper test isolation by:
beforeEach
and afterEach
to set up and clean up mocksjest.clearAllMocks()
or jest.restoreAllMocks()
as appropriateCheck the coverage report to ensure your changes are covered.
Avoid adding additional logs to the console.
We use Biome for JavaScript/TypeScript linting and formatting, and Prettier for CSS/HTML/Markdown. 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.
To build the project:
npm run build
For continuous building of the api during development:
npm run build:watch
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:
# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
providers:
- id: openai:chat:gpt-4.1
prompts:
- Translate "{{input}}" to {{language}}
tests:
- vars:
input: 'Hello, world!'
language: 'English'
assert:
- type: new-assertion-type
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 cache src/cache.ts
to store responses. If your provider requires a new dependency, please add it as a peer dependency with npm install --save-peer
.
Write unit tests in test/providers/yourProviderName.test.ts
and create an example in the examples/
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 the examples/
directory. Consider writing a guide comparing your provider to others or highlighting unique features or benefits.
Update src/providers/index.ts
and site/docs/providers/index.md
to include your new provider. Update src/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
).
Assertions define different ways to compare and validate the output of an LLM against expected results. To contribute a new assertion:
Define the Assertion Type:
BaseAssertionTypesSchema
enum in src/types/index.ts
.npm run jsonSchema:generate
to update the JSON schema located at site/static/config-schema.json
Implement the Assertion Handler:
src/assertions/
for your assertion logic.AssertionParams
and returns a GradingResult
.Basic handler structure:
import type { AssertionParams, GradingResult } from '../types';
import invariant from '../util/invariant';
export function handleYourAssertion({
assertion,
inverse,
outputString,
renderedValue,
provider, // Use if your assertion needs provider-specific logic
test, // Access to test case data
}: AssertionParams): GradingResult {
// Validate inputs
invariant(
typeof renderedValue === 'string' || Array.isArray(renderedValue),
'"your-assertion" assertion must have a string or array value'
);
// Implementation logic
const threshold = assertion.threshold ?? 0.5; // Set a sensible default
// Calculate the score
const score = /* your scoring logic */;
// Determine if test passes
const pass = (score >= threshold) !== inverse;
return {
pass,
score: inverse ? 1 - score : score,
reason: pass
? 'Assertion passed'
: `Your assertion scored ${score.toFixed(2)} vs threshold ${threshold}`,
assertion,
};
}
Register the Assertion Handler:
src/assertions/index.ts
, import your handler function and add it to the handlers mapping.import { handleYourAssertion } from './yourAssertion';
// In the handlers mapping
'your-assertion': handleYourAssertion,
Document Your Assertion:
Update the appropriate documentation files:
site/docs/configuration/expected-outputs/deterministic.md
site/docs/configuration/expected-outputs/index.md
For model-graded assertions:
site/docs/configuration/expected-outputs/model-graded/index.md
site/docs/configuration/expected-outputs/model-graded/your-assertion.md
Write Tests:
test/assertions/yourAssertion.test.ts
.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
This will not update the web UI if you make further changes to the code. You have to run npm run build
again.
:::
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:
ruff
. Run ruff check --fix
and ruff format
before submitting changesunittest
modulerequirements.txt
fileIf 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.
Our documentation follows several standards to ensure accessibility:
To run the documentation in development mode:
cd site
npm start
This will start the Docusaurus development server on port 3100 by default (or a custom port if you set the PORT
environment variable). You can then view the documentation at http://localhost:3100.
To build the documentation for production:
cd site
npm run build
This will generate static content in the build
directory that can be served using any static content hosting service. Building the documentation may occasionally catch errors that do not surface when running npm start
.
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.
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.
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
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:
From main, run npm version <minor|patch>
. We do not increment the major version per our adoption of 0ver. This will automatically:
package.json
, package-lock.json
and CITATION.cff
with the new versionchore/bump-version-<new-version>
"chore: bump version <new-version>"
When creating a new release version, please follow these guidelines:
0.0.1
and is used for bug fixes and minor features0.1.0
and is used for major features and breaking changesTo determine the appropriate release type, review the changes between the latest release and main branch by visiting (example):
https://github.com/promptfoo/promptfoo/compare/[latest-version]...main
Once your PR is approved and landed, 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.
Cleanup the release notes. You can look at this release as an example
A GitHub Action should automatically publish the package to npm. If it does not, please publish manually.
If you need help or have questions, you can:
We follow the Contributor Covenant Code of Conduct. Please read and adhere to it in all interactions within our community.
Press p or to see the previous file or, n or to see the next file
Are you sure you want to delete this access key?
Are you sure you want to delete this access key?
Are you sure you want to delete this access key?
Are you sure you want to delete this access key?