Skip to main content

OpenPullRequest

logo

CLI tool that generates PR titles, descriptions, and post-review change summaries using a local or cloud LLM. Supports Ollama, OpenAI, Anthropic, Google Gemini, OpenRouter, DeepSeek, llama.cpp, and MLX.

CI License


Built primarily for local-first use — pair it with Ollama and Gemma or Ornith or any other model you like for a free, fully offline workflow. On Apple Silicon Macs, prefer the mlx tagged variant of your chosen model (e.g. gemma4:26b-mlx) — it runs on Apple's MLX framework instead of plain GGUF and is noticeably faster on that hardware. Don't want to run anything locally? Google's Gemini API has a generous free tier and is a great low-friction cloud option.

Installation

Recommended

uv tool install openpurr

Or

pipx install openpurr

On first run, the setup wizard creates ~/.openpurr automatically. You can also run it any time:

opo setup

Requirements

  • Python 3.11+
  • git on PATH
  • One of: Ollama running locally, or an API key for a cloud provider

Usage

# Generate a PR title + description from the diff against main
opo

# Diff against a different base branch
opo --base develop

# Summarise changes made since the last N commits (for reviewers)
opo review
opo review --commits 3

Example output

Running opo against a diff produces a title and description like this — generated with the default system prompt, no custom overrides. This is PR #11 from this very repo — in fact, every PR in openpurr's history was generated by openpurr itself:

feat(config): add support for custom system prompt overrides

📝 Summary

Introduced a mechanism to override default system prompts via the configuration file. Users can now define custom INIT PROMPT: and REVIEW PROMPT: sections to tailor LLM behavior for PR generation and reviews.

🛠 Type of Change

  • New feature

🔍 Key Changes

  • Implemented a new configuration parsing logic that uses a --- delimiter to separate key-value pairs from free-text prompt sections.
  • Added support for INIT PROMPT: and REVIEW PROMPT: headers to override default system prompts.
  • Updated Config class to load and expose custom prompt overrides.
  • Updated run_init and run_review to prioritize custom prompts over built-in defaults.
  • Enhanced config_describe to inform users of active prompt overrides.
  • Updated README.md with new installation instructions and documentation for custom prompts.

🧪 How Has This Been Tested?

  • Extensive unit tests in tests/test_config.py covering delimiter splitting, prompt parsing, and configuration preservation.
  • Functional tests in tests/test_pr.py verifying that custom prompts are correctly passed to the LLM provider.

Want a different tone or format? See Custom system prompts below.

Configuration

Settings are stored in ~/.openpurr as flat OPO_KEY=value lines — no sections, no quoting:

OPO_PROVIDER=ollama
OPO_MODEL=gemma4:26b
OPO_API_KEY=
OPO_HOST=http://localhost:11434
OPO_TEMPERATURE=0.0
OPO_KEEP_ALIVE=5m
OPO_BASE=main
OPO_LANGUAGE=en

Use the config subcommand to inspect and update values without editing the file directly.

# Show all keys with descriptions and current values
opo config describe

# Read a single value
opo config get model

# Update a value
opo config set provider ollama
opo config set model gemma4:26b
opo config set api_key sk-...
opo config set keep_alive 0s

Custom system prompts

The prompts opo sends to the LLM aren't fixed — everything after a lone --- line in ~/.openpurr is free text, not OPO_KEY=value config, so it can hold Markdown, headers, = signs, anything. Add an INIT PROMPT: section to override the prompt behind opo (title + description) and/or a REVIEW PROMPT: section to override the one behind opo review. Either section is optional; whichever is missing keeps the built-in default.

OPO_PROVIDER=ollama
OPO_MODEL=gemma4:26b
OPO_API_KEY=
OPO_HOST=http://localhost:11434
OPO_TEMPERATURE=0.0
OPO_KEEP_ALIVE=5m
OPO_BASE=main
OPO_LANGUAGE=en

---
INIT PROMPT:
You are a Senior Principal Engineer. Write a terse PR title and description in
Conventional Commits style. No emoji, no checklists.

REVIEW PROMPT:
Summarize what changed since the last review in one short paragraph.

opo config set/opo config describe only ever touch the OPO_KEY=value part above the --- line — the prompt section is left exactly as you wrote it, and opo config describe tells you which of init/review are currently overridden. Note that OPO_LANGUAGE (see below) only affects the built-in prompts — once you write your own INIT PROMPT:/REVIEW PROMPT:, you're in full control, so specify the language directly in the prompt text if you need one.

Configuration keys

Key Env var Default Description
provider OPO_PROVIDER ollama ollama · openai · anthropic · gemini · openrouter · deepseek · llamacpp · mlx
model OPO_MODEL (empty) Model name — set via opo setup or opo config set model <name>
api_key OPO_API_KEY (empty) API key for cloud providers
host OPO_HOST http://localhost:11434 Base URL — Ollama default; set to a custom endpoint when needed
temperature OPO_TEMPERATURE 0.0 Sampling temperature (0.0 = deterministic)
keep_alive OPO_KEEP_ALIVE 5m Ollama VRAM keep-alive (0s = unload immediately, 5m = keep warm)
base OPO_BASE main Default base branch to diff against
language OPO_LANGUAGE en Output language for generated PR text (ISO 639-1 code, e.g. es, fr, de, ja, zh)

There's no hardcoded default model: opo setup always has you pick one (from a live-fetched list, or typed manually), and opo/opo review will error out with a pointer back to opo setup if model is ever left blank (e.g. after hand-editing the file).

Example: switch to Google Gemini (free tier)

opo config set provider gemini
opo config set model <your-chosen-model>
opo config set api_key <your-gemini-api-key>

Model names aren't hardcoded anywhere in this README on purpose — providers retire and rename models constantly. Run opo setup or opo models --provider gemini to pick from what's actually available right now.

Example: unload Ollama from VRAM after each request

opo config set keep_alive 0s

Example: generate PR text in another language

opo config set language es

opo setup also asks for this up front, with arrow-key selection from common languages plus a custom-code fallback. This only affects the built-in prompts — see Custom system prompts above.

Models

List available models for the current or a specified provider:

opo models
opo models --provider anthropic

Model lists are always fetched live from the provider — Ollama's /api/tags, OpenAI/Anthropic/Gemini/OpenRouter/DeepSeek/llama.cpp/MLX's models.list() (or public models endpoint) — never a hardcoded/curated list baked into the tool. If the fetch fails (offline, bad key, local server not running) the command prints an empty result instead of erroring; check connectivity/credentials, or pull a model directly with ollama pull <model>.

Metadata

Release files for openpurr 0.8.11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openpurr 0.8.11
File Size Uploaded
openpurr-0.8.11.tar.gz 550.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openpurr 0.8.11
File Interpreter ABI Platform
openpurr-0.8.11-py3-none-any.whl Python 3 none any Details

Total release size: 580.3 kB

Release files / openpurr-0.8.11.tar.gz

Download URL openpurr-0.8.11.tar.gz
Size 550.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8e79c66659170b2224851b52502391d196518354691be23351481d863121465b
BLAKE2b-256 checksum
How to use checksums
f72a96ec393488f9129982f61af46f4fe8fe7beff0bf10ad77f35fab785a8a20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / openpurr-0.8.11-py3-none-any.whl

Download URL openpurr-0.8.11-py3-none-any.whl
Size 30.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
af53fbc1b35d486c3017fcd51f450f2a7ce8690dfe152158fe79a1e70a76acba
BLAKE2b-256 checksum
How to use checksums
c0037256525745cc5a6579df584f3529e257f9a40e5c313ed81827cf9614337a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

0.9.2

2 release files

0.9.1

2 release files

0.9.0

2 release files

This release

0.8.11 This release

2 release files

0.8.9

2 release files

0.8.8

2 release files

0.8.7

2 release files

0.8.6

2 release files

0.8.5

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page