npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@arthurcarlson/evalgate

v1.0.0

Published

LLM prompt eval gate for CI: run YAML-defined eval cases against your prompts on every PR, post a pass/fail report, and fail the build when outputs regress.

Readme

evalgate

Unit tests exist for code; prompts get vibes. evalgate runs YAML-defined eval cases against your LLM prompts on every pull request, posts a pass/fail report as a sticky PR comment, and fails the build when outputs regress. A one-word prompt change that breaks tone, format, or a JSON contract becomes a red X on the PR.

[GitHub Marketplace badge — pending listing]

60-second quickstart

1. Copy the workflow:

# .github/workflows/evals.yml
name: Prompt evals
on: pull_request
permissions:
  contents: read
  pull-requests: write
jobs:
  evalgate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: arthurcarlsonn/evalgate@v1
        with:
          config: evals/**/*.eval.yaml
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

2. Add one eval file:

# evals/support.eval.yaml
defaults:
  provider: anthropic
  model: claude-haiku-4-5
  temperature: 0

cases:
  - id: refund-policy-tone
    prompt: |
      You are the support agent for {{brand}}.
      Customer asks: "{{question}}"
      Reply in under 120 words.
    vars:
      brand: GlowLab
      question: What is your refund policy?
    assert:
      - type: contains
        value: "30 days"
      - type: not_contains
        value: lifetime guarantee
      - type: llm_judge
        rubric: Reply is polite, mentions the refund window, and does not invent policies.

3. Add ANTHROPIC_API_KEY to your repo secrets. Open a PR — evalgate comments with the table and gates the merge.

Try it locally, free

npx @arthurcarlson/evalgate run --dry-run --config "evals/**/*.eval.yaml"

--dry-run uses the mock provider: zero API calls, zero cost. Canned outputs are read from mocks/<case-id>.txt next to your eval file, so you can develop assertions offline. The examples/ folder in this repo runs green out of the box:

npx @arthurcarlson/evalgate run --dry-run --config "examples/evals/*.eval.yaml"

Config reference

defaults:            # optional, applies to every case
  provider: anthropic   # anthropic | openai | openrouter | mock
  model: claude-haiku-4-5
  temperature: 0        # 0-2, default 0
  max_tokens: 1024

cases:
  - id: my-case            # required, unique, [a-zA-Z0-9._-]
    prompt: "inline {{var}}"   # OR prompt_file: path/relative/to/this/file
    vars: { var: value }       # {{var}} is literal string replacement;
                               # unknown variables fail before any API call
    provider: openai           # per-case overrides of any default
    model: gpt-4o-mini
    temperature: 0.2
    max_tokens: 512
    assert:                    # at least one; case passes only if all pass
      - type: contains
        value: "..."

Assertions

| Type | Passes when | |------|-------------| | contains | Output includes the value (case-sensitive) | | not_contains | Output does not include the value | | icontains | Case-insensitive contains | | regex | JS regex (as string) matches | | json_valid | Output parses as JSON (one surrounding code fence is stripped) | | json_schema | Parsed JSON validates against schema_file (ajv, draft 2020-12) | | max_chars | Output length ≤ value | | llm_judge | Judge model (temperature 0, fixed template) answers PASS; anything else fails with the returned reason |

Action inputs and outputs

| Input | Default | | |---|---|---| | config | evals/**/*.eval.yaml | Eval file glob | | min_pass_rate | 100 | Gate: fail the run below this pass rate (%) | | comment | true | Post/update the sticky PR comment | | max_cases | 50 | Cost guard: hard cap on cases per run | | fail_on_missing_key | true | Fail fast when a needed provider key is missing |

Outputs: pass_rate, passed, failed, total. The report also lands in the job summary.

Providers

Keys are read from env only — never from inputs or flags — and masked with core.setSecret:

| Provider | Env var | |---|---| | anthropic | ANTHROPIC_API_KEY | | openai | OPENAI_API_KEY | | openrouter | OPENROUTER_API_KEY | | mock | none |

Cost notes

Defaults are chosen to keep runs cheap: temperature 0, haiku-class model, max_cases cap at 50, concurrency 4, retries only on 429/5xx. A 20-case suite on a haiku-class model typically completes in well under 90 seconds for pennies.

Troubleshooting

  • "Missing provider key(s)" — add the secret to the workflow env: block. Set fail_on_missing_key: false to run anyway (those cases will fail at runtime).
  • No PR comment — the job needs permissions: pull-requests: write and GITHUB_TOKEN in env:; on non-PR events the comment is skipped with a notice.
  • Gate failed but you disagree — lower min_pass_rate, or fix the prompt. That's the point.

CLI

evalgate run [--config <glob>] [--dry-run] [--min-pass-rate <n>] [--max-cases <n>] [--json]

Exit codes: 0 gate passed · 1 runtime/config error · 2 gate failed.

License

MIT © Arthur Carlson