Skip to main content

Semantic governance gate for spec files: classifies PR changes against a locked project goal and scope.

Project description

SpecGuard

License: MIT Status Built with Spec Kit


SpecGuard is a semantic governance layer for spec files. It classifies every PR change against your locked project goal and scope — passing additive changes silently, warning on low-confidence shifts, and blocking unapproved direction changes at merge time.


The Problem

In repos where AI agents and humans both contribute, a PR can look perfectly fine on the surface while silently shifting the project's direction. SpecGuard catches that — not by checking who made the change, but by understanding what the change means against your locked goal and scope.

PR:         "refactored README for clarity"
Change:      Added a full SaaS pricing section
             to a project scoped as a local CLI tool.

SpecGuard:   ❌  SCOPE CHANGE — 94% confidence
                 "SaaS pricing" is out of scope
                 requires approval from @architect

How It Works

Lock your goal and scope in .specguard/lock.json. SpecGuard does the rest on every PR.

PR opened
 ├─ Not a watched file ───────────────────── ✅ Pass
 ├─ Protected path, wrong author ──────────── ❌ Block  (no AI involved)
 └─ Watched spec file changed
      └─ Claude classifies the diff
           ├─ ADDITIVE ───────────────────── ✅ Pass   (silent)
           ├─ SCOPE CHANGE, low confidence ── ⚠️  Warn
           └─ SCOPE CHANGE, high confidence ── ❌ Block  (until authorized approval)

Approving via GitHub's normal review flow re-evaluates the check automatically — no new commits needed.


Quickstart

1. Create .specguard/lock.json

{
  "goal": "A CLI tool that converts Markdown to PDF",
  "scope_in":  ["Markdown parsing", "PDF rendering", "CLI flags"],
  "scope_out": ["GUI", "cloud sync", "collaboration features"]
}

2. Add the workflow

# .github/workflows/specguard.yml
name: specguard
on:
  pull_request:
  pull_request_review:
    types: [submitted]
permissions:
  contents: read
  pull-requests: read
jobs:
  specguard:                               # the required branch-protection check
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: {fetch-depth: 0}             # required: base...head history
      - uses: Sawaiz-zip/spec-guard@v0
        with:
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
  reevaluate:                              # an approval re-runs the check in place
    if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
    runs-on: ubuntu-latest
    permissions: {actions: write}
    steps:
      - env:
          GH_TOKEN: ${{ github.token }}
        run: |
          run_id=$(gh api "repos/${{ github.repository }}/actions/workflows/specguard.yml/runs?event=pull_request&head_sha=${{ github.event.pull_request.head.sha }}" --jq '.workflow_runs[0].id // empty')
          [ -n "$run_id" ] && gh api -X POST "repos/${{ github.repository }}/actions/runs/$run_id/rerun"

3. Set ANTHROPIC_API_KEY as a repo secret, then require the specguard check under branch protection.

That's it for solo use — scope changes now warn on every PR. To make them block until an authorized teammate approves, add roles:

# .specguard/roles.yml  (optional — presence switches warn mode to enforce mode)
roles:
  architect: [your-github-username]
rules:
  ".specguard/**":          # nobody outside the role may touch the lock itself
    edit: architect
  "README.md":              # who can approve scope changes per file
    scope_changes: {approve: architect}
# .specguard/config.yml  (optional — these are the defaults)
watch: ["README.md", "CLAUDE.md", "AGENTS.md", "ARCHITECTURE.md", "*.kilo", ".specguard/**"]
block_threshold: 0.75
on_error: warn              # vendor outage: pass with a loud warning ("fail" to block)
model: claude-sonnet-4-6
max_diff_chars: 30000

You bring your own API key and choose the model — SpecGuard never bills you directly. Set model: in .specguard/config.yml to use any model you have access to. With the default claude-sonnet-4-6 expect roughly $0.01–0.02 per watched file per push (~3–5K input + ~500 output tokens); it scored a perfect confusion matrix on the calibration corpus. Note: claude-opus-4-8 is hard-blocked by a project guardrail (no quality gain on this task at ~6× the cost).


Roadmap

Phase Status What ships
0 — CI Gate 🔴 Building GitHub Action · scope classification · role-based approval · branch protection
1 — Local Tools ⚪ Planned CLI (specguard init, specguard check) · pre-commit hook · MCP server
2 — GitHub App ⚪ Planned Native Checks API · fork PR support · bot vs human identity · Spec Kit adapter
3 — Advanced ⚪ Planned Section-level locking · monorepo support · multi-provider classifier

Principles

No false blocks. No new UI. No dashboards.

The only enforceable boundary is merge time — everything else is advisory. A wrong Friday block means uninstall by Monday, so additive changes always pass silently. Hard blocks are deterministic (no AI). Probabilistic verdicts always show their confidence and never block without explanation.

Full constitution: .specify/memory/constitution.md


Built with Spec Kit · Powered by Claude · MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

specguard_ci-0.1.0.tar.gz (531.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

specguard_ci-0.1.0-py3-none-any.whl (21.5 kB view details)

Uploaded Python 3

File details

Details for the file specguard_ci-0.1.0.tar.gz.

File metadata

  • Download URL: specguard_ci-0.1.0.tar.gz
  • Upload date:
  • Size: 531.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.19

File hashes

Hashes for specguard_ci-0.1.0.tar.gz
Algorithm Hash digest
SHA256 aacd812215cb01bc746e3c8072ac9e6126d62053e7939b5f06e1e6629f390cb9
MD5 9d57166cf0d0c7cc46a1d073f0381611
BLAKE2b-256 804f78d6e9e9d8372e33c0d79bb688c9de5f8e7bd6d2ea5ffd18596b4829bc77

See more details on using hashes here.

File details

Details for the file specguard_ci-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for specguard_ci-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 90aa89b3df4fdd07ee3547fb50f0823f1543ac6a4be1f53b128c5c966f41cd92
MD5 aaf1c3f0c22300be39eac744b661d72d
BLAKE2b-256 96b57317e3b8ec03e83edb238a1affc9426a38b8bae7eeb65654086718d5e12b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page