ai-slop-gate β€” Contribution Guide

Thank you for your interest in ai-slop-gate πŸ™Œ

Goal: prevent β€œAI slop” β€” including inside ai-slop-gate itself.

All architectural decisions are defined in ai_slop_gate_snapshot.json (v7.5.0). If this document conflicts with the snapshot, the snapshot wins.


Project Philosophy

  • Advisory-first: By default, nothing is blocking. Results are recommendations, not verdicts.

  • Short > Clear > Readable: Output must be concise, signal-like, and actionable.

  • Policy is the source of truth: All enforcement flows from policy.yml.

  • No hidden logic: Every decision is traceable.


Architectural Principles (Non-Negotiable)

Component

Does

Does NOT

cli/

Parses args, wires components

Contains analysis logic

engine/

Orchestrates providers

Formats output

domain/policy_engine.py

Evaluates observations β†’ Decision

Knows about CI or reporters

providers/

Collect or analyze data

Make enforcement decisions

reporters/

Render and deliver output

Know about providers

cache/

Prevent duplicate LLM calls

Cache static providers

Zero dependency on CI platforms. CLI works locally and in any CI without GitHub/GitLab SDKs.

Provider-first design. Everything goes through providers via registry. CLI never imports concrete providers directly.


Canonical Contracts

BaseProvider

class BaseProvider(ABC):
    name: str
    kind: str  # "llm" | "static" | "infra"

    @abstractmethod
    def analyze(self, code: str, input_file: str = "") -> ProviderObservation:
        # LLM: analyze PR diff or snippet
        ...

    @abstractmethod
    def collect(self, base_path: str = ".") -> ProviderObservation:
        # Static/infra: scan a directory
        # LLM: delegates to chunked file scanning via LlmProvider
        ...

    def analyze_pr(self, repo: str, pr_id: int, token: str) -> ProviderObservation:
        # Optional: direct PR analysis (LLM providers only)
        # Default raises NotImplementedError
        ...

ProviderObservation

@dataclass(frozen=True)
class ProviderObservation:
    provider: str
    model: str
    observations: List[Any]
    raw_text: str

CachedProvider

Wraps any LLM provider. Caches collect() and analyze() results. Must not change provider behavior. CachedProvider is infrastructure, not logic.

class CacheBackend:
    def get(self, key): ...
    def set(self, key, value): ...

Adding a New Provider

LLM Provider

  1. Create ai_slop_gate/providers/llm/<n>.py extending LlmProvider with kind = "llm"

  2. Implement analyze(code, input_file) β†’ ProviderObservation

  3. Optionally implement analyze_pr(repo, pr_id, token)

  4. Add prompt file(s) to ai_slop_gate/providers/llm/prompts/<n>/

  5. Register in providers/registry.py

  6. Add --provider <n> to CLI

  7. Write tests in tests/unit/providers/

LLM JSON contract β€” prompt must instruct the model to return:

{
  "issues": [
    {
      "category": "security|quality|architecture|...",
      "signal": "snake_case_identifier",
      "message": "non-empty string",
      "severity": "low|medium|high|critical",
      "confidence": 0.85,
      "file": "path/to/file.py",
      "line": 42
    }
  ]
}

No markdown, no text outside JSON, no ranges for line numbers.

Static/Infra Provider

  1. Create ai_slop_gate/providers/static/<n>.py extending BaseProvider

  2. Set kind = "static" or "infra"

  3. Implement collect(base_path) β†’ ProviderObservation

  4. Register in providers/registry.py

  5. Write tests with positive (detects issues) and negative (clean code) examples


Testing Philosophy

Tests lock architectural contracts, not implementation.

Critical invariants:

  • LLM token is not spent twice for the same cache key

  • Cache key changes when input or policy changes

  • Static providers are never wrapped by CachedProvider

python -m pytest ai_slop_gate/tests -v
python -m pytest ai_slop_gate/tests --cov=ai_slop_gate --cov-report=term-missing

Snapshot Rule

Any architectural change must:

  1. Update ai_slop_gate_snapshot.json

  2. Bump the snapshot version (e.g. 7.4.0 β†’ 7.5.0)

  3. Be aligned with the roadmap

No snapshot update = not canonical.


Roadmap

βœ… Stage 5 β€” DONE

GitLab support, provider registry, cache contracts, CachedProvider, rate-limit guard, file cache backend.

βœ… Stage 6 β€” Runtime & UX (current)

  • init command (ai-slop-gate init)

  • Policy examples for static, plan.json, k8s

  • Kubernetes runtime: admission-style analysis, advisory-only

πŸ”œ Stage 7 β€” AI Quality Heuristics

LLM as advisor, short outputs, mandatory caching.

πŸ”œ Stage 8 β€” Terraform

Static terraform plan parsing. Advisory mode only.

πŸ”œ Stage 9 β€” Composition & Profiles

Profiles (ci, local, infra) and preset policies.


Working with AI Assistants

ai-slop-gate ships context files for AI-assisted development. Use them β€” they prevent the tool from generating β€œAI slop” in its own codebase.

GitHub Copilot (VS Code)

.github/copilot-instructions.md is loaded automatically by Copilot Chat when you open the repository in VS Code. It contains the full architectural context: BaseProvider contracts, provider inventory, cache rules, and strict β€œnever do” list.

No setup required. Open the repo, start Copilot Chat with @workspace.

Tessl / Agent Skills Registry

skills/ai-slop-gate/SKILL.md is published to the Tessl registry. It allows any AI agent that supports the Agent Skills spec to automatically load project context when working in this codebase.

Install locally:

npx tessl install ai-slop-gate

Evaluate or publish:

npx tessl skill review ./skills/ai-slop-gate
npx tessl skill publish ./skills/ai-slop-gate

Claude (claude.ai or API)

When starting a new conversation with Claude about this project, paste the contents of ai_slop_gate_snapshot.json. It is the single source of truth and gives Claude full architectural context without relying on README or stale memory.

Paste ai_slop_gate_snapshot.json β†’ then describe your task

For multi-session work, re-paste the snapshot at the start of each conversation. Claude has no persistent memory of previous sessions.

General Rules for AI-Assisted Contributions

  • Always provide the snapshot. Without it, any model will guess architecture and invent missing components.

  • Never accept invented file paths, method names, or SDK methods. Verify against the actual source before committing.

  • Snapshot update is mandatory. If an AI assistant suggests an architectural change, update ai_slop_gate_snapshot.json as part of the same PR.

  • AI-generated code goes through the gate. Run --provider static on your own diff before opening a PR. The project uses ai-slop-gate on itself via .github/workflows/analyze.yml.


Not Accepted

  • β€œSmart” decisions without policy

  • Auto-blocking by default

  • Tight coupling to a single CI platform

  • Long LLM essays instead of signals

  • Business logic inside CLI

  • Provider-specific cache logic