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

kolpo

v0.1.2

Published

AI code review CLI and GitHub Action for a local branch or pull request

Readme

Kolpo

AI code review CLI and GitHub Action. Point it at a local branch or a pull request: the diff plus the full contents of changed files go in; a structured review with inline comments comes out. Plain Node.js, no dependencies, no build.

By default the primary model reviews each change. Set model-1 and model-2 to review in parallel first; the primary then reviews independently and merges in only the secondary findings that are new and real. Leave a secondary empty to drop that slot.

Each slot is provider:id. Providers are anthropic, openai, gemini (Google AI Studio), openrouter, and zai (Z.AI). The primary model is required. Only the API keys for providers you actually use must be set. A failed secondary is dropped; a failed primary fails the run after one retry on that same model.

CLI

Needs Node 22+. Install once, then run kolpo in any repo. kolpo --help prints usage.

npm install -g kolpo
kolpo --help
kolpo config set anthropic-api-key sk-ant-...
kolpo config set openai-api-key sk-...
kolpo config set gemini-api-key AIza...
kolpo config set zai-api-key ...
kolpo config set model anthropic:claude-sonnet-4-6
kolpo config set model-1 openai:gpt-5.4
kolpo config set model-2 gemini:gemini-2.5-pro
kolpo config set timeout 180
kolpo config
kolpo

Or without a global install: npx kolpo. Persist flags from a review invocation with --save:

kolpo --anthropic-api-key sk-ant-... --model anthropic:claude-sonnet-4-6 --save
kolpo --gemini-api-key AIza... --model gemini:gemini-2.5-pro --save
kolpo --zai-api-key ... --model zai:glm-5.3 --save
kolpo --timeout 300 --save

Config lives at ~/.config/kolpo/config.json (override with KOLPO_CONFIG). API keys are stored with mode 600 and are masked in kolpo config output.

A positional argument is the base ref: kolpo main is the same as kolpo --base main. Plain kolpo uses the saved base, else origin/HEAD, then main, then master.

kolpo main
kolpo --base origin/dev
kolpo --model gemini:gemini-2.5-pro
kolpo --model anthropic:claude-sonnet-4-6 --model-1 openai:gpt-5.4 --model-2 gemini:gemini-2.5-pro
kolpo --model openai:gpt-5.4 --model-1 "" --model-2 ""
kolpo --timeout 60
TIMEOUT=300 kolpo
kolpo config unset model-2
kolpo config path

Flags (override saved config for this run):

  • --base <ref> — base branch or commit (or pass it as kolpo <ref>; default: saved, else origin/HEAD, then main, then master)
  • --model <provider:id> — primary model (required: flag or saved config)
  • --model-1 <provider:id> — first secondary, or empty to disable (default: saved, else disabled)
  • --model-2 <provider:id> — second secondary, or empty to disable (default: saved, else disabled)
  • --anthropic-api-key <key> — Anthropic key (overrides ANTHROPIC_API_KEY and saved config)
  • --openai-api-key <key> — OpenAI key (overrides OPENAI_API_KEY and saved config)
  • --gemini-api-key <key> — Google AI Studio key (overrides GEMINI_API_KEY and saved config)
  • --openrouter-api-key <key> — OpenRouter key (overrides OPENROUTER_API_KEY and saved config)
  • --zai-api-key <key> — Z.AI key (overrides ZAI_API_KEY and saved config)
  • --extra-instructions <text> — project-specific guidance appended to the system prompt
  • --timeout <seconds> — per-request HTTP timeout in seconds (default: 120; overrides TIMEOUT and saved config)
  • --save — write the flags you passed to the config file

A provider's key is required only when a slot uses that provider. Flag beats env beats saved config.

The CLI writes the review to REVIEW_<key>.md in the current directory and prints that filename. The file matches a GitHub PR review: the same summary body, then each inline comment under its file with the quoted line.

If stdin is a terminal, Kolpo then asks whether to post that review to the open GitHub PR (Post this review … as approve|comment|request changes? [y/N]). Default is no. Scripts and pipes skip the prompt.

Posting uses GITHUB_TOKEN or GH_TOKEN, or gh auth token after gh auth login. The review appears as the GitHub account that owns the token (usually you); the body still says Kolpo. You must have an open PR for the current branch, and local HEAD must match the PR head — push first if they differ. GitHub will not let you approve or request changes on your own PR; Kolpo falls back to a comment in that case.

Exit status is 1 when the verdict is request_changes or the run fails.

GitHub Action

Reviews when a PR is opened (unless it's a draft), a draft is marked ready for review, or someone comments /review or /kolpo as its own line (optional text after a space is fine). The sample workflow starts the job on a /review or /kolpo substring; the Action then requires the command on its own line, skips drafts, and no-ops on an empty PR diff. The sample also skips PRs labeled no-ai-review.

It does not re-review on every push — ask with /review when you want a fresh pass. The posted GitHub review uses the verdict: Approve, Comment, or Request changes. Approve requires the repo setting Allow GitHub Actions to create and approve pull requests (Settings → Actions → General). Without it, Kolpo falls back to a comment; the body still shows Kolpo — approve. Reviewer name is github-actions[bot].

Old Kolpo reviews are collapsed as outdated when a new one posts. Add the no-ai-review label to a PR to keep the bot out entirely.

Add .github/workflows/review.yml. Models can be a static provider:id or a repository variable so you can switch without editing the workflow. API keys always go in secrets. Unset model-1 / model-2 vars disable those slots. Only keys for providers you actually use must be set.

Variables: repo → Settings → Secrets and variables → Actions → Variables. Secrets: the Secrets tab on that same page.

name: kolpo
on:
  pull_request:
    types: [opened, ready_for_review]
  issue_comment:
    types: [created]
concurrency:
  group: kolpo-${{ github.event.pull_request.number || github.event.issue.number }}
  cancel-in-progress: true
permissions:
  contents: read
  pull-requests: write
  issues: write
jobs:
  review:
    if: >
      (github.event_name == 'pull_request' &&
       github.event.pull_request.draft == false &&
       !contains(github.event.pull_request.labels.*.name, 'no-ai-review')) ||
      (github.event_name == 'issue_comment' &&
       github.event.issue.pull_request &&
       !contains(github.event.issue.labels.*.name, 'no-ai-review') &&
       (contains(github.event.comment.body, '/review') ||
        contains(github.event.comment.body, '/kolpo')))
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          ref: ${{ github.event_name == 'issue_comment' && format('refs/pull/{0}/head', github.event.issue.number) || '' }}
      - uses: hasinoorit/kolpo@main
        with:
          model: ${{ vars.PRIMARY_MODEL }}
          model-1: ${{ vars.SECONDARY_MODEL }}
          model-2: ${{ vars.SECONDARY_MODEL_2 }}
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          openai-api-key: ${{ secrets.OPENAI_API_KEY }}
          gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
          openrouter-api-key: ${{ secrets.OPENROUTER_API_KEY }}
          zai-api-key: ${{ secrets.ZAI_API_KEY }}
          timeout: ${{ vars.TIMEOUT }}

Set PRIMARY_MODEL to a provider:id, for example anthropic:claude-sonnet-4-6. Optional: SECONDARY_MODEL, SECONDARY_MODEL_2, TIMEOUT (seconds; Action default is 120).

Static models, secrets for keys:

      - uses: hasinoorit/kolpo@main
        with:
          model: anthropic:claude-sonnet-4-6
          model-1: openai:gpt-5.4
          model-2: gemini:gemini-2.5-pro
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          openai-api-key: ${{ secrets.OPENAI_API_KEY }}
          gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
          timeout: 180
          extra-instructions: |
            This is a payments service; scrutinize idempotency and rounding.

Mix static and vars if you want a fixed primary and swappable secondaries:

      - uses: hasinoorit/kolpo@main
        with:
          model: anthropic:claude-sonnet-4-6
          model-1: ${{ vars.SECONDARY_MODEL }}
          model-2: ${{ vars.SECONDARY_MODEL_2 }}
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          openai-api-key: ${{ secrets.OPENAI_API_KEY }}
          gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
          openrouter-api-key: ${{ secrets.OPENROUTER_API_KEY }}
          zai-api-key: ${{ secrets.ZAI_API_KEY }}
          timeout: ${{ vars.TIMEOUT }}

Each provider as the primary reviewer:

      - uses: hasinoorit/kolpo@main
        with:
          model: anthropic:claude-sonnet-4-6
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
      - uses: hasinoorit/kolpo@main
        with:
          model: openai:gpt-5.4
          openai-api-key: ${{ secrets.OPENAI_API_KEY }}
      - uses: hasinoorit/kolpo@main
        with:
          model: gemini:gemini-2.5-pro
          gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
      - uses: hasinoorit/kolpo@main
        with:
          model: openrouter:openai/gpt-oss-120b:free
          openrouter-api-key: ${{ secrets.OPENROUTER_API_KEY }}
      - uses: hasinoorit/kolpo@main
        with:
          model: zai:glm-5.3
          zai-api-key: ${{ secrets.ZAI_API_KEY }}

Test

node --test test/*.test.js