Metadata-Version: 2.4
Name: specshift
Version: 1.0.0
Summary: Detects, classifies, and optionally summarizes breaking changes in OpenAPI/Swagger contracts using AI
Author: Lethe044
License: MIT
Project-URL: Homepage, https://github.com/Lethe044/specshift
Project-URL: Repository, https://github.com/Lethe044/specshift
Project-URL: Issues, https://github.com/Lethe044/specshift/issues
Project-URL: Changelog, https://github.com/Lethe044/specshift/blob/main/CHANGELOG.md
Keywords: openapi,swagger,api,breaking-changes,contract-testing,api-diff,devtools,cli,ci-cd
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyyaml>=6.0
Requires-Dist: requests>=2.28
Provides-Extra: pretty
Requires-Dist: rich>=13.0; extra == "pretty"
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: responses>=0.23; extra == "dev"
Requires-Dist: rich>=13.0; extra == "dev"
Dynamic: license-file

# SpecShift

[![CI](https://github.com/Lethe044/specshift/actions/workflows/ci.yml/badge.svg)](https://github.com/Lethe044/specshift/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/specshift.svg)](https://pypi.org/project/specshift/)
[![Python versions](https://img.shields.io/pypi/pyversions/specshift.svg)](https://pypi.org/project/specshift/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

SpecShift detects changes in OpenAPI and Swagger contracts, classifies each
one as breaking, warning, or info, and can optionally summarize them in
plain language.

When an API changes from one version to the next, the real question isn't
"what changed" but "will this break me". SpecShift is built to answer
exactly that: it takes two specifications, evaluates every difference
between them individually, and tells you which ones actually matter.

```
$ specshift diff examples/old_api.yaml examples/new_api.yaml

Bookstore API : 1.0.0 -> 2.0.0
13 breaking, 2 warning, 3 info changes found.

[BREAKING] DELETE /books/{bookId} :: HTTP method removed
[BREAKING] GET /books > parameter 'category' :: Parameter 'category' is now required
[BREAKING] GET /books > response 200 > field 'author' :: field removed from response
...

Result: 13 breaking change(s) make this update risky.
```

## Why SpecShift

Every team that keeps evolving its API eventually hits the same problem:
a field gets removed, a parameter becomes required, an enum value
disappears, and nobody notices until a client breaks in production.
Most existing diff tools just show you a raw JSON diff and leave it up to
you to figure out what actually matters.

SpecShift doesn't do that. It evaluates every change based on its context:

- Removing a field from a **response** is **breaking**, because clients
  may depend on it being there.
- Removing the same field from a **request body** is usually just a
  **warning**, because clients that send it are simply ignored, not broken.
- Adding a new required field to a request is **breaking**, but adding a
  new field to a response is just **informational**.

These context-aware rules are the core of SpecShift, and they work
completely free, with no API key required. The optional AI-powered
natural-language summary is an additional layer on top, never a
requirement.

## Features

- **Comprehensive structural diff**: deep comparison at the path, HTTP
  method, parameter, request body, response, and schema level.
- **Context-aware classification**: the same change is weighted
  differently depending on whether it occurs in a request or a response.
- **`$ref` resolution and `allOf` merging**: correctly follows the
  reference and composition patterns common in real-world specifications.
- **Detects enum, format, nullable, and security scheme changes**.
- **Works entirely for free**: no API key or paid service is required.
- **Optional AI summary**: can generate a natural-language summary using
  Groq, the Gemini free tier, or any OpenAI-compatible endpoint. If no key
  is set, it automatically falls back to a rule-based summary and never
  stops working.
- **CI/CD integration**: the `specshift check` command compares the
  current specification against a branch and fails the build if a
  breaking change is found.
- **Live monitoring**: the `specshift watch` command periodically checks
  a remote API's specification and sends a Slack or Discord notification
  when it changes.
- **Three output formats**: a colored console table, a Markdown report
  (ideal for PR comments), and JSON (for integrating with other tools).

## Installation

```bash
pip install specshift
```

For colored console output (optional, works fine without it too):

```bash
pip install "specshift[pretty]"
```

Installing from source:

```bash
git clone https://github.com/Lethe044/specshift.git
cd specshift
pip install -e .
```

## Quick start

Compare two specifications directly:

```bash
specshift diff old_openapi.yaml new_openapi.yaml
```

You can also compare specifications from URLs:

```bash
specshift diff https://api.example.com/v1/openapi.json https://api.example.com/v2/openapi.json
```

To use it in CI, create a configuration file in your repo:

```bash
specshift init
```

This produces a `.specshift.yml` file similar to:

```yaml
spec_path: openapi.yaml
base_ref: main
fail_on: breaking
```

Then, in your CI pipeline:

```bash
specshift check
```

This command compares the current `openapi.yaml` file against its version
on the `main` branch and returns exit code 1 if a breaking change is found.

## AI summary (optional)

SpecShift can use free-tier AI services to generate a natural-language
summary of the changes. This never requires any payment:

```bash
export GROQ_API_KEY="your-groq-api-key"
specshift diff old.yaml new.yaml --ai
```

You can also use Google Gemini's free tier instead of Groq:

```bash
export GEMINI_API_KEY="your-gemini-api-key"
specshift diff old.yaml new.yaml --ai --ai-provider gemini
```

If you want to use a more powerful (paid) model, you can connect any
OpenAI-compatible endpoint:

```bash
export SPECSHIFT_API_KEY="your-api-key"
export SPECSHIFT_OPENAI_BASE_URL="https://api.openai.com/v1"
specshift diff old.yaml new.yaml --ai --ai-provider openai_compatible --ai-model gpt-4o-mini
```

If no key is configured, the `--ai` flag still works, it simply produces a
rule-based summary instead of waiting on a network call. AI support is an
optional enhancement, never a requirement.

## Commands

### `specshift diff <old> <new>`

Compares two specifications. `<old>` and `<new>` can be a file path, an
http(s) URL, or raw JSON/YAML text.

Useful options:

| Option | Description |
|---|---|
| `--format console\|markdown\|json` | Output format (default: console) |
| `--output <file>` | Writes the output to a file |
| `--ai` | Adds a natural-language summary |
| `--ai-provider groq\|gemini\|openai_compatible` | Chooses the AI provider |
| `--fail-on breaking\|warning\|none` | Determines at which level exit code 1 is returned |
| `--quiet` | Only prints the summary line |

### `specshift check`

Designed for CI/CD. Compares the current specification file against a git
reference (branch, tag, or commit) defined in `.specshift.yml`.

```bash
specshift check --spec openapi.yaml --base-ref origin/main
```

### `specshift watch <url>`

Periodically checks a remote specification, compares it against the
previous snapshot, and sends a notification if a difference is found.

```bash
specshift watch https://api.example.com/openapi.json \
  --interval 600 \
  --slack-webhook "$SLACK_WEBHOOK_URL"
```

### `specshift init`

Creates a sample `.specshift.yml` file.

## Using it with GitHub Actions

The workflow below checks your API contract against the `main` branch on
every pull request and fails the build if a breaking change is found:

```yaml
name: API Contract Check

on:
  pull_request:
    paths:
      - "openapi.yaml"

jobs:
  contract-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - run: pip install specshift

      - run: specshift check --base-ref origin/${{ github.base_ref }}
```

If you want to add AI-powered PR comments, you can generate a Markdown
report with `specshift check --ai --format markdown --output report.md`
and post it as a PR comment using an action like
`peter-evans/create-or-update-comment`.

## Configuration file (`.specshift.yml`)

```yaml
spec_path: openapi.yaml
base_ref: main
fail_on: breaking

# optional
ai_provider: groq
ai_model: llama-3.3-70b-versatile
slack_webhook: https://hooks.slack.com/services/...
discord_webhook: https://discord.com/api/webhooks/...
ignore_paths: []
```

## When SpecShift calls something breaking

The table below summarizes which severity level applies in the most
common scenarios:

| Change | In a request | In a response |
|---|---|---|
| Field removed | Warning | Breaking |
| New required field added | Breaking | Info |
| New optional field added | Info | Info |
| Field no longer required | Info | Breaking |
| Field became required | Breaking | Info |
| Data type changed | Breaking | Breaking |
| Enum value removed | Breaking | Breaking |
| Endpoint or method removed | Breaking | Breaking |

## Comparison with other tools

| | SpecShift | Raw JSON/YAML diff | oasdiff / openapi-diff style tools |
|---|---|---|---|
| Context-aware classification | Yes | No | Partially |
| Natural-language summary | Yes (optional) | No | No |
| Free to use | Fully free | Free | Usually free |
| CI integration | Built-in (`check`) | Manual | Varies |
| Live URL monitoring | Built-in (`watch`) | No | Rarely |

## Roadmap

This project is under active development. Some planned areas:

- Support for gRPC/Protobuf contracts
- GraphQL schema diffing
- An official GitHub Action for posting automatic PR comments
- A web-based result viewer
- More semantic rules (path parameter pattern changes, content-type
  changes, etc.)

Feel free to open an issue if you have a feature request.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for the contribution guide. Bug
reports, feature requests, and pull requests are always welcome.

## License

This project is licensed under the [MIT License](LICENSE).
