Skip to content

JohnODowdAI/scopefence

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ScopeFence

Repo fences for coding agents and PRs.

ScopeFence turns prose boundaries — "only touch the payments service", "don't edit infra", "keep it under 200 lines" — into executable diff checks.

Why

Coding agents and hurried developers make changes that wander outside the intended area of a repo. They touch the wrong files, broaden refactors, violate path boundaries, introduce forbidden imports, or blow past reviewable diff size.

Today, these boundaries mostly live in review comments and Slack messages. That is too loose.

ScopeFence makes them executable:

  1. Define repo boundaries in a small YAML policy file.
  2. Run scopefence check against any git diff.
  3. Get a precise verdict with offending files and reasons.

Quick Start

# Install from git tag (or use pip install -e ".[dev]" for local development)
pip install git+https://github.com/JohnODowdAI/scopefence.git@v0.1.0-beta.1

# Scaffold a policy
scopefence init --id payments-agent --title "Keep changes inside payments" -o fences/payments.yaml

# Validate the policy
scopefence lint fences/payments.yaml

# Check a diff against the policy
scopefence check fences/payments.yaml --base-ref main --head-ref HEAD

Example Fence Policy

version: "0.1"
id: payments-agent
title: Keep changes inside payments service

diff:
  include:
    - "services/payments/**"
    - "tests/payments/**"
  exclude:
    - "docs/**"
  forbid:
    - "infra/**"
    - ".github/**"

budgets:
  max_files_changed: 6
  max_added_lines: 200
  max_deleted_lines: 100

content:
  forbid_patterns:
    - name: no-debug-print
      files:
        - "services/payments/**/*.py"
      regex: "\\bprint\\s*\\("

imports:
  python:
    - name: payments-cannot-import-admin
      files:
        - "services/payments/**/*.py"
      forbid_modules:
        - services.admin
        - infra

Example Output

Pass

╭──────────────────────╮
│ ScopeFence: PASS     │
╰──────────────────────╯
  Policy: payments-agent (v0.1)
  Diff: 2 files, +15 / -3 lines

  Passed: allowed_scope, forbidden_paths, file_count_budget,
          added_line_budget, deleted_line_budget, no-debug-print,
          payments-cannot-import-admin

Fail

╭──────────────────────╮
│ ScopeFence: FAIL     │
╰──────────────────────╯
  Policy: payments-agent (v0.1)
  Diff: 4 files, +45 / -10 lines

┌─────────────────────┬────────────────────────────────────┬──────────────────┐
│ Rule                │ Reason                             │ Files            │
├─────────────────────┼────────────────────────────────────┼──────────────────┤
│ allowed_scope       │ 2 file(s) changed outside allowed  │ shared/utils.py  │
│                     │ scope                              │ infra/deploy.py  │
├─────────────────────┼────────────────────────────────────┼──────────────────┤
│ forbidden_paths     │ 1 forbidden file(s) touched        │ infra/deploy.py  │
├─────────────────────┼────────────────────────────────────┼──────────────────┤
│ payments-cannot-    │ Newly introduced forbidden          │ services/        │
│ import-admin        │ import(s)                          │ payments/        │
│                     │ `services.admin` (matches           │ service.py       │
│                     │ `services.admin`)                  │                  │
└─────────────────────┴────────────────────────────────────┴──────────────────┘

How It Works

Path Fences

  • include: Changed files must fall inside these globs. Files outside are violations.
  • exclude: Changed files matching these are ignored for scope purposes (e.g., docs).
  • forbid: Changed files matching these always fail, regardless of include rules.

Budget Fences

  • max_files_changed: Maximum number of files allowed in the diff.
  • max_added_lines: Maximum total added lines.
  • max_deleted_lines: Maximum total deleted lines.

Added-Line Regex Fences

Inspect only added lines in matching changed files. This avoids blocking on legacy bad patterns already present in the file — only new violations are caught.

content:
  forbid_patterns:
    - name: no-debug-print
      files: ["services/**/*.py"]
      regex: "\\bprint\\s*\\("

Python Import Fences

Detect newly introduced forbidden imports by comparing the base and head versions of changed Python files.

If a file already had import services.admin before this diff, it won't fail. Only new introductions are flagged. This is critical for incremental adoption — you can fence new drift without blocking on legacy code.

imports:
  python:
    - name: payments-cannot-import-admin
      files: ["services/payments/**/*.py"]
      forbid_modules:
        - services.admin
        - infra

A forbidden module matches exact names and prefixes:

  • services.admin matches services.admin and services.admin.foo
  • infra matches infra and infra.deploy

Note on TYPE_CHECKING imports: Imports guarded by if TYPE_CHECKING: are currently treated the same as runtime imports. This is intentional — they still represent architectural drift even if they don't execute at runtime. If this becomes a friction point, it may become a policy option in a future release.

CLI Commands

Command Description
scopefence init Scaffold a starter fence policy
scopefence lint <policy> Validate a policy file
scopefence check <policy> Check a diff against a policy
scopefence render <verdict.json> Re-render a saved verdict

Check Options

scopefence check policy.yaml \
  --base-ref main \
  --head-ref HEAD \
  --github       # emit GitHub step summary + annotations
  --json         # output verdict as JSON

When no refs are provided, ScopeFence compares HEAD against the working tree. In GitHub Actions, it auto-detects GITHUB_BASE_REF and GITHUB_SHA.

Run Artifacts

Each scopefence check saves a run to .scopefence/runs/<timestamp>-<policy-id>/:

  • policy.snapshot.yaml — the policy as evaluated
  • diff.json — the normalized diff snapshot
  • verdict.json — the machine-readable verdict
  • summary.md — the markdown summary

GitHub Actions

Copy examples/workflows/scopefence.yml to .github/workflows/scopefence.yml in your repo and update the policy path and install URL.

- name: ScopeFence
  run: |
    pip install git+https://github.com/JohnODowdAI/scopefence.git@v0.1.0-beta.1
    scopefence check fences/payments-agent.yaml \
      --base-ref ${{ github.event.pull_request.base.sha }} \
      --head-ref ${{ github.sha }} \
      --github

The --github flag writes a job summary and emits file-level annotations for violations.

What Is Intentionally Not Built

  • Hosted service or dashboard
  • GitHub App or check-run API integration
  • LLM-based policy interpretation or semantic review
  • Non-git SCM support
  • Multi-language import analysis (only Python in v0.1)
  • Automatic code remediation
  • Plugin system

Future Directions

  • JS/TS import fences
  • CODEOWNERS-aware policies
  • Richer PR comment integrations
  • Severity levels per rule
  • Policy packs for common repo layouts
  • Agent wrapper integrations

Development

git clone <repo>
cd scopefence
pip install -e ".[dev]"
pytest -v

License

MIT

Packages

 
 
 

Contributors

Languages