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

# Add the Peeps workflow

> The workflow file that lets your CI report runs to Peeps and run what Peeps asks for: TypeScript and Python versions for GitHub Actions, the job for GitLab CI/CD, and the action's inputs and modes.

Peeps runs your tests through one workflow in your repository. Once it's committed, the workflow:

* reports every run of your suite on a push to the headline branch and on pull requests
* runs the tests Peeps asks for when you start a run from Peeps
* hosts the job Peeps works in when it fixes a test or writes a new one

You add it yourself. Peeps never edits workflow files.

## Copy it from Peeps

The project's **Repository** settings page shows the workflow already filled in for your project: your headline branch, test root and Playwright config. Use that copy rather than the examples below.

<Tabs>
  <Tab title="GitHub">
    Under **Workflow to install**, click **Copy workflow** and commit it as `.github/workflows/peeps.yml`. If you changed **Workflow file** in the project's settings, use that name instead.
  </Tab>

  <Tab title="GitLab">
    Under **CI job to add**, click **Copy job** and add the job to your `.gitlab-ci.yml`, or to the file you set as **CI configuration**.
  </Tab>
</Tabs>

Peeps offers the Python version when your tests are Python, and the TypeScript version otherwise.

## TypeScript Playwright on GitHub Actions

This is the workflow for a suite at the repository root, with `main` as the headline branch:

```yaml .github/workflows/peeps.yml theme={null}
name: Peeps
on:
  workflow_dispatch:
    inputs:
      mode:      { type: string, required: true }   # inventory | run | agent
      sessionId: { type: string, required: false }
      ref:       { type: string, required: false }
  push:
    branches: [main]   # the headline branch is what Peeps mirrors
  pull_request:
permissions:
  contents: read
  id-token: write        # OIDC → Peeps; no Peeps secret needed
jobs:
  peeps:
    name: "peeps ${{ inputs.mode || 'report' }} ${{ inputs.sessionId || '' }}"
    runs-on: ubuntu-latest
    container: mcr.microsoft.com/playwright:v1.59.1-jammy
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v7
        with: { ref: "${{ inputs.ref || github.ref }}" }
      - run: npm ci
      - uses: Peeps-Labs/peeps-action@v1
        with:
          mode: ${{ inputs.mode }}
          session-id: ${{ inputs.sessionId }}
```

The parts that matter:

* **`workflow_dispatch` with `mode`, `sessionId` and `ref`** is how Peeps starts a run, a fix or a new test. Keep the three inputs as they are.
* **`push` and `pull_request`** make your own pushes and pull requests report their runs. The `push` branch is your headline branch.
* **`id-token: write`** lets the job ask GitHub for the identity token it shows Peeps. No Peeps secret is needed. `contents: read` is all the job itself needs: when Peeps pushes a fix, it uses its own token for that one push.
* **The job's `name`** includes the mode and session, so Peeps can find the job it started. Keep it as it is.
* **`actions/checkout` at `inputs.ref || github.ref`** checks out the branch Peeps asked for.

## Python (pytest-playwright) on GitHub Actions

For a pytest-playwright suite at the repository root:

```yaml .github/workflows/peeps.yml theme={null}
name: Peeps
on:
  workflow_dispatch:
    inputs:
      mode:      { type: string, required: true }   # inventory | run | agent
      sessionId: { type: string, required: false }
      ref:       { type: string, required: false }
  push:
    branches: [main]   # the headline branch is what Peeps mirrors
  pull_request:
permissions:
  contents: read
  id-token: write        # OIDC → Peeps; no Peeps secret needed
jobs:
  peeps:
    name: "peeps ${{ inputs.mode || 'report' }} ${{ inputs.sessionId || '' }}"
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v7
        with: { ref: "${{ inputs.ref || github.ref }}" }
      - uses: actions/setup-python@v6
        with: { python-version: "3.12" }
      - name: Install the suite's dependencies
        run: |
          if [ -f 'requirements.txt' ]; then python -m pip install -r 'requirements.txt'
          else python -m pip install './'
          fi
      - run: python -m playwright install --with-deps
      - uses: Peeps-Labs/peeps-action@v1
        with:
          framework: pytest
          mode: ${{ inputs.mode }}
          session-id: ${{ inputs.sessionId }}
```

The action runs your tests with pytest and streams each result to Peeps. With pytest-playwright installed, its output directory (traces, screenshots and videos) is uploaded in place of Playwright's HTML report. Your own `--tracing`, `--screenshot` and `--video` options decide what's in it.

A project runs one workflow, in one language. If your repository has both TypeScript and Python tests, the page offers the TypeScript workflow and says that it runs the TypeScript tests only. To run both, connect each suite to its own project, with its own test root and its own **Workflow file**.

## GitLab CI/CD

GitLab has no `uses:`, so the job fetches the action and runs it with Node:

```yaml .gitlab-ci.yml theme={null}
peeps:
  image: mcr.microsoft.com/playwright:v1.59.1-jammy
  timeout: 60m
  id_tokens:
    PEEPS_ID_TOKEN:
      aud: https://peepsai.com   # GitLab ID token → Peeps; no Peeps secret needed
  rules:
    - if: $PEEPS_MODE                                   # started by Peeps: inventory | run | agent
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"  # reports the merge request's run
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH       # the headline branch is what Peeps mirrors
  script:
    - npm ci
    - git clone --depth 1 --branch v1 https://github.com/Peeps-Labs/peeps-action.git /tmp/peeps-action
    - node /tmp/peeps-action/dist/index.js
```

Peeps starts each pipeline with pipeline variables, so the GitLab project must let the token's role set them. See [Connect GitLab](/integrations/gitlab#add-the-peeps-job-to-your-ci-configuration). The copy on the **Repository** page adds a `variables:` block when your project needs one, such as for a test root or a Playwright config. For a Python suite it's a different job, with a Python image and pip.

## Common setups

**Tests in a subdirectory.** Set the project's test root and the copied workflow points the action at it. By hand, add `working-directory` under the action's `with:`. `config` is relative to it:

```yaml theme={null}
      - uses: Peeps-Labs/peeps-action@v1
        with:
          mode: ${{ inputs.mode }}
          session-id: ${{ inputs.sessionId }}
          working-directory: tools/e2e
          config: playwright.config.ts
```

**A headline branch that isn't `main`.** The copied workflow's `push` filter names your headline branch. If you change the headline branch later, change the filter to match. On GitLab, the job's last rule runs on your default branch; change it to `$CI_COMMIT_BRANCH == "develop"`, with your headline branch's name. A push to another branch still reports its run, but only the headline branch's tests become the project's test cases.

**Pull requests from forks.** GitHub never gives a workflow triggered by a fork's pull request an identity token, so the job can't authenticate to Peeps and fails. If you take contributions from forks, skip the job for them:

```yaml theme={null}
jobs:
  peeps:
    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
```

**Running it by hand.** `inventory` mode needs no session, so you can refresh the list of tests from the command line. Run it on your headline branch, adding `--ref <branch>` if that isn't your default branch:

```bash theme={null}
gh workflow run peeps.yml -f mode=inventory
```

## Action inputs

| Input | Default | What it is |
| - | - | - |
| `mode` | `ci` | `inventory`, `run`, `report`, `agent` or `ci`. See [modes](#modes). |
| `session-id` | | The session Peeps passes when it starts the workflow. Needed by `run` and `agent`. |
| `working-directory` | the repository root | Where to run Playwright or pytest, relative to the repository root. |
| `config` | | The Playwright config, relative to `working-directory`. For pytest, the ini file. |
| `framework` | `auto` | `playwright`, `pytest` or `auto`. `auto` picks pytest when the working directory has a `pytest.ini`, a `conftest.py` or a `pyproject.toml` that configures pytest, and no Playwright config. |

On GitLab the same settings are variables: `PEEPS_WORKING_DIRECTORY`, `PEEPS_PLAYWRIGHT_CONFIG` and `PEEPS_FRAMEWORK`. Peeps sets `PEEPS_MODE` and `PEEPS_SESSION_ID` itself when it starts a pipeline.

`PEEPS_API_URL` is the address of Peeps the job reports to, `https://app.peepsai.com` by default. Leave it unset unless Peeps support gives you another address; the copy on the **Repository** page includes it when it's needed.

## Modes

| Mode | What runs on your runner |
| - | - |
| `report` | Your suite, with each result reported to Peeps as it finishes. |
| `run` | The tests Peeps asked for, reported the same way. |
| `inventory` | A listing of your tests (`playwright test --list`, or `pytest --collect-only`), sent to Peeps with the test files. Nothing runs. |
| `agent` | A session Peeps works in to fix a test or write one. Every step is written to the job log. |

`ci` is the default and means `report`. Peeps names the mode on every run it starts.

A `report` run on your default branch also refreshes the list of tests, because it's the freshest list there is. That list becomes the project's tests when your default branch is also your headline branch.

## Check it works

Push to your headline branch, or start a run from Peeps (see [Run tests in your CI](/repository/run-in-your-ci)). The run appears in Peeps, and the **Repository** page shows **Last CI run** with how long ago it was.

If nothing shows up, see [the CI job never connected](/repository/faq#the-ci-job-never-connected).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.