8000
Skip to content

Latest commit

Β 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ• Hound

Hound watches the third-party APIs your code depends on, and tells you exactly when β€” and where β€” a change will break you.

CI PyPI License: MIT Python 3.10+

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)

Table of contents


Why Hound

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.

How it works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Spec Fetcher    │────▢│   Diff Engine     │────▢│                   β”‚
β”‚ (OpenAPI/Swagger)β”‚     β”‚ (structural +     β”‚     β”‚                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚  semantic)        β”‚     β”‚    Correlator     │────▢ Report
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚ (blast-radius      β”‚    (GitHub Issue /
β”‚  Usage Scanner   │────────────────────────────▢│  matching)         β”‚     Slack / JSON)
β”‚ (AST over your   β”‚                              β”‚                   β”‚
β”‚  codebase)        β”‚                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. 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/.
  2. 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.
  3. 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.
  4. 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.
  5. Report β€” opens a GitHub Issue (or posts to Slack) with the exact change, severity, and the file:line that needs attention.

Install

pip install hound-watchdog

Or run without installing, via uvx:

uvx hound-watchdog check

Requires Python 3.10+.

Quick start

# 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-action

The first run establishes a baseline snapshot β€” no alerts fire. Every subsequent run diffs against that baseline and advances it once the diff is reported.

Configuration

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 only

Config 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.

GitHub Action

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 }}

CLI reference

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 model

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.

Supported languages & API types

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.

Architecture

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 check without 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.

Comparison with other tools

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

Roadmap

  • 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

Contributing

Issues and PRs welcome. Before opening a PR:

git clone https://github.com/8dazo/hound
cd hound
pip install -e ".[dev]"
pytest

See CONTRIBUTING.md for coding standards and how to add support for a new language scanner.

Security

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.

License

MIT β€” see LICENSE.

About

πŸ• Hound watches the third-party APIs your code depends on and tells you exactly when β€” and where β€” a change will break you.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0