Hound watches the third-party APIs your code depends on, and tells you exactly when β and where β a change will break you.
Most API changelogs are noise. A vendor renames a field, deprecates a param, or tightens a rate limit β and you find out in production, three weeks later, from a stack trace.
Hound doesn't just diff the spec. It cross-references every change against how your codebase actually calls that API, so you only get paged when something you use is actually affected β with the exact file and line to fix.
$ hound check
π Hound found 1 breaking change
stripe Β· /v1/charges
β BREAKING: field `source` is being removed (deprecated since 2026-05-01)
β used in src/services/payments/charge.py:42
1 non-breaking change suppressed (run with --verbose to see all)
- Why Hound
- How it works
- Install
- Quick start
- Configuration
- GitHub Action
- CLI reference
- Severity model
- Supported languages & API types
- Architecture
- Comparison with other tools
- Roadmap
- Contributing
- Security
- License
Every team that integrates a third-party API eventually gets burned by a silent change. The existing options are unsatisfying:
- Do nothing β find out in production.
- Watch the changelog manually β doesn't scale past 2β3 dependencies, and most changes don't matter to your usage.
- Generic OpenAPI diff tools β tell you the spec changed, not whether your code is affected. Every run is noisy, so teams mute the alerts within a month.
Hound's premise: a change only matters if your code touches it. So it builds a map of what your codebase actually reads and writes on each API, and only raises an alert when a real change intersects that map.
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββββ
β Spec Fetcher ββββββΆβ Diff Engine ββββββΆβ β
β (OpenAPI/Swagger)β β (structural + β β β
βββββββββββββββββββ β semantic) β β Correlator ββββββΆ Report
βββββββββββββββββββ ββββββββββββββββββββ β (blast-radius β (GitHub Issue /
β Usage Scanner ββββββββββββββββββββββββββββββΆβ matching) β Slack / JSON)
β (AST over your β β β
β codebase) β βββββββββββββββββββββ
βββββββββββββββββββ
- Fetch β pulls the current OpenAPI/Swagger spec (or scrapes changelog pages when no spec exists) and compares it against the last known-good snapshot stored in
.hound/snapshots/. - Diff β computes a structural diff (added/removed/renamed fields, changed required-ness, new deprecations, type changes) plus a semantic diff for prose-only changes (deprecation notices, rate-limit language) using sentence-embedding similarity.
- Scan β walks your codebase with AST parsing to build a usage table: every endpoint, field, and parameter your code actually touches, with file and line number.
- Correlate β intersects the diff against the usage table. Only intersecting changes are surfaced as actionable; everything else is available in verbose output but doesn't trigger a notification.
- Report β opens a GitHub Issue (or posts to Slack) with the exact change, severity, and the file:line that needs attention.
pip install hound-watchdogOr run without installing, via uvx:
uvx hound-watchdog checkRequires Python 3.10+.
# 1. Initialize config in your repo
hound init
# 2. Add an API to watch
hound add stripe \
--spec-url https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json \
--scan-path src/services/payments/
# 3. Run a check
hound check
# 4. (optional) Set up scheduled watching via GitHub Actions
hound init --with-actionThe first run establishes a baseline snapshot β no alerts fire. Every subsequent run diffs against that baseline and advances it once the diff is reported.
hound.yaml, created by hound init:
version: 1
watch:
- name: stripe
spec_url: https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json
scan_paths:
- src/services/payments/
language: python
- name: github-api
spec_url: https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json
scan_paths:
- src/integrations/github/
language: python
ignore_fields:
- "*.deprecated_beta_field" # explicitly acknowledged, don't re-alert
report:
github_issues:
enabled: true
labels: ["hound", "dependency-risk"]
assignees: []
slack:
enabled: false
webhook_url: ${SLACK_WEBHOOK_URL}
min_severity: breaking # breaking | deprecation | non_breaking
llm:
provider: openai # openai | azure_openai | huggingface_local | none
model: gpt-4o-mini
api_key: ${OPENAI_API_KEY}
# provider: none -> disables prose summarization; structural diffs onlyConfig is validated against a versioned JSON schema on every run (hound validate), so a bad config fails fast in CI rather than silently skipping a watch target.
Zero-infrastructure scheduled watching:
# .github/workflows/hound.yml
name: Hound API Watch
on:
schedule:
- cron: '0 9 * * 1' # every Monday, 9am UTC
workflow_dispatch: {}
jobs:
watch:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/checkout@v4
- uses: your-org/hound-action@v1
with:
config: hound.yaml
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}| Command | Description |
|---|---|
hound init |
Scaffold hound.yaml in the current repo |
hound add <name> --spec-url <url> --scan-path <path> |
Register a new API to watch |
hound check |
Run a full check: fetch, diff, scan, correlate, report |
hound check --dry-run |
Run without writing reports or advancing the snapshot |
hound check --verbose |
Show all changes, including non-breaking / unaffected ones |
hound validate |
Validate hound.yaml against the config schema |
hound baseline reset <name> |
Discard stored snapshot and re-baseline on next check |
hound diff <name> |
Show the raw structural diff without running the correlator |
Exit codes: 0 no breaking changes, 1 breaking change found, 2 config or fetch error β designed to gate CI pipelines.
| Severity | Meaning | Default action |
|---|---|---|
breaking |
A field/endpoint your code uses was removed, renamed, or made incompatible | Issue opened, CI can be gated to fail |
deprecation |
A field/endpoint your code uses is marked deprecated but still functional | Issue opened, non-blocking |
non_breaking |
Spec changed but doesn't intersect your usage table | Logged only, suppressed from notifications by default |
Severity classification for structural changes is deterministic (rule-based on the OpenAPI diff). Severity for prose-only changes (rate limits, policy notices) is LLM-assisted and always shown with the source excerpt it was derived from, so you can verify the classification rather than trust it blindly.
Languages:
- Python:
requests,httpx, HTTP clients, f-strings, variable URLs, and SDK calls (e.g.stripe-python,openai-python) - TypeScript & JavaScript:
fetch(),axios, and JS/TS SDK calls (e.g.stripe-node,@octokit/rest)
Spec & Documentation Formats:
- OpenAPI 3.x / Swagger 2.0: Full structural diffing across endpoints, methods, parameters, and request/response schemas.
- Vendor Changelogs & RSS/Atom Feeds: Unstructured documentation tracking via semantic chunk diffing and LLM severity classification.
If your API has no published spec, or your language isn't supported yet, Hound will tell you explicitly rather than silently skipping β check hound check --verbose output for unsupported_target warnings.
hound/
βββ hound/
β βββ fetchers/
β β βββ openapi_fetcher.py # spec retrieval + parsing + $ref resolution
β β βββ docs_fetcher.py # heading-based documentation chunker
β β βββ changelog_scraper.py # RSS/Atom and HTML changelog scraper
β βββ diffing/
β β βββ spec_diff.py # structural OpenAPI diff
β β βββ semantic_diff.py # text/semantic diff for prose
β βββ usage_scanner/
β β βββ ast_scanner.py # Python AST scanner for API call sites
β β βββ ts_scanner.py # TypeScript / JavaScript usage scanner
β β βββ field_extractor.py # endpoint & field usage dataflow table
β βββ correlator.py # blast-radius matching
β βββ reporter/
β β βββ github_issue.py # idempotent GitHub Issues publisher
β β βββ slack_notify.py # Slack webhook notifications
β βββ store/
β β βββ snapshot_store.py # baseline persistence (.hound/snapshots/)
β βββ llm/
β β βββ classify.py # prose severity classifier
β βββ agent.py # orchestration (fetch β diff β scan β correlate β report)
βββ cli.py
βββ configs/schema.json # versioned config schema
βββ tests/
Design principles:
- Deterministic core, LLM-assisted edges. Structural diffing and correlation never depend on an LLM call β they work with
llm.provider: none. The LLM only summarizes prose changes and drafts human-readable issue text. - Idempotent runs. Re-running
hound checkwithout a new spec change produces no duplicate issues; snapshot state is only advanced after a successful report. - Fails loud, not silent. Fetch failures, schema-validation failures, and unsupported targets all surface as explicit warnings/errors, never a quiet no-op.
- No required external infra. Local snapshot storage by default (
.hound/); S3/GCS backend is optional for teams running Hound centrally across many repos.
| Hound | Generic OpenAPI diff | Dependabot/Renovate | |
|---|---|---|---|
| Detects spec changes | β | β | β (version bumps only) |
| Tells you your blast radius | β | β | β |
| File:line of affected code | β | β | β |
| Works with no spec (docs-only APIs) | β | β | β |
| Noise level | Low (usage-filtered) | High (alerts on every change) | N/A |
- Python AST scanning
- TypeScript & JavaScript scanning
- Docs-only & RSS changelog tracking
- GraphQL schema diffing
- Hosted mode (multi-repo dashboard, no self-managed cron)
- VS Code extension surfacing warnings inline at the call site
Issues and PRs welcome. Before opening a PR:
git clone https://github.com/8dazo/hound
cd hound
pip install -e ".[dev]"
pytestSee CONTRIBUTING.md for coding standards and how to add support for a new language scanner.
Hound only reads public spec URLs and your local codebase β it never transmits your source code to an LLM provider; only extracted, minimal context (field names, endpoint paths) is sent when llm.provider is set to a hosted model. Set llm.provider: none or use huggingface_local for a fully offline run. Report vulnerabilities via SECURITY.md, not public issues.
MIT β see LICENSE.