Skip to content

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

BypasserAI

BypasserAI

Pre-commit humanizer for AI-shaped code.
Deterministic detection on every commit — API calls only when it matters.

CI License: MIT Node >= 18 Issues

Español · Quick start · How it works · Configuration · CLI · Development · AGENTS.md (for coding agents)


What is this?

BypasserAI is a Git pre-commit hook and CLI that:

  1. Scores staged source files for common AI-generated patterns (no API, deterministic).
  2. Rewrites files above your threshold through any OpenAI-compatible chat API, guided by the bundled humanizer skill (español).
  3. Re-stages successful rewrites so the commit uses the humanized version.

It is language-agnostic (JS/TS, Python, Go, Rust, Java, C#, PHP, Ruby, and more) and project-agnostic — install it once per repo, point it at your provider, and forget it until the toast says otherwise.

Scope: Natural Git authorship and code quality — not academic plagiarism evasion. See Limits.


Features

Free detection Heuristic scorer runs locally on every commit; no tokens burned on clean files.
Smart rewrite scope Small files → full file; large files → diff hunks or declaration chunks (rewriteScope: auto). Hunks closer than contextLines are merged into a single API call, so overlapping context windows never re-send already-rewritten lines.
Safety first Truncation, indent, structure, and syntax guards; semantic drift review (a second model pass rejects a rewrite that changed behavior); atomic restage with .bak rollback — originals win on doubt. Fragment rejections surface via sanitizerWarning so bypasser stats and --strict see them.
Parallel rewrites Configurable concurrency across staged files (rewriteConcurrency).
Optional notifications Native toast on Windows, shell notify on macOS/Linux; disable with notifications.
Any OpenAI-compatible API OpenAI, Groq, OpenRouter, Ollama, LM Studio, local proxies, etc.
Measured detector Annotated corpus + benchmark (npm run bench) reports precision/recall/F1 and locks scores with a golden snapshot.
String/comment masking Signals run on masked views, so a // in a string or a function inside a regex literal never inflates the score.
CI gate bypasser audit --strict fails the job when an AI-shaped file could not be humanized; reusable GitHub Action included.
Audit telemetry bypasser stats aggregates a structured .bypasser.log.jsonl — success rate by provider/model, rejection reasons, repeat offenders.
Live panel in OpenCode Optional TUI plugin shows the last run, per-family signals, trend and hotspots inside the OpenCode sidebar.
Agent-friendly AGENTS.md documents architecture and invariants for AI coding tools.

Quick start

npm install -g bypasser-ai

In your application repo (not inside BypasserAI):

cd /path/to/my-app
bypasser init
export BYPASSER_API_KEY=sk-...          # PowerShell: $env:BYPASSER_API_KEY = "sk-..."
bypasser install
git commit -m "test"                    # hook runs automatically

Set BYPASSER_VERBOSE=1 if you want per-signal detail in hook output.


How it works

git commit
    │
    ▼
pre-commit hook  →  bypasser audit --pre-commit
    │
    ▼
staged files (respecting ignore globs & min changed lines)
    │
    ▼
detector scores FULL file content (0–1, deterministic, no API)
    │
    ├─ score < threshold ──► pass through
    │
    └─ score ≥ threshold ──► OpenAI-compatible rewrite (humanizer skill)
              │
              ▼
          integrity guards + semantic review → restage on success; keep original on failure
    │
    ▼
commit proceeds (hook never blocks on tool/API errors)

Detection always uses the full staged file so a tiny edit in a large AI file still counts. The git diff drives rewrite strategy (full file vs hunks vs chunks), not the score.


Prerequisites

  • Node.js 18+
  • A Git repository
  • An API key for an OpenAI-compatible provider (env var recommended)

Installation

From npm (recommended)

npm install -g bypasser-ai
# or run without installing: npx bypasser-ai <command>

From source

git clone https://github.com/Pacoaldev/BypasserAI.git
cd BypasserAI
npm install
npm run build
npm link    # exposes the `bypasser` command globally

After changing src/ in this repo, run npm run build again. The hook everywhere executes dist/cli.js from your linked copy — stale dist/ = stale behavior.


Setup in your project

Run inside the repo you want to protect:

bypasser init
  • Creates .bypasser.json with sensible defaults.
  • Does not overwrite an existing config (protects apiKey and custom settings). Use bypasser init --force to regenerate.
  • Appends .bypasser.log, .bypasser.log.jsonl, .bypasser.state.json, *.bypasser.tmp, and *.bak to .gitignore.

Example config (omitted keys fall back to runtime defaults in loadConfig()):

{
  "baseURL": "https://api.openai.com/v1",
  "model": "gpt-4o-mini",
  "threshold": 0.65,
  "maxTokens": 16384,
  "temperature": 0.4,
  "ignore": [],
  "thresholds": [],
  "timeoutMs": 120000,
  "timeoutPer1kLinesMs": 30000,
  "maxTimeoutMs": 600000,
  "maxFileLines": 2000,
  "rewriteConcurrency": 3,
  "rewriteScope": "auto",
  "rewriteFullFileBelowLines": 400,
  "contextLines": 60,
  "maxChunkLines": 450,
  "structuralCheck": true,
  "semanticReview": true,
  "semanticReviewModel": "",
  "semanticReviewMaxLines": 1200,
  "notifications": "auto"
}
export BYPASSER_API_KEY=sk-...
bypasser install

Opt out of the hook (conflicting pre-commit)

If a repo already has its own pre-commit workflow, do not install BypasserAI there. Set excluded folder names (basename, lowercase) before install:

export BYPASSER_HOOK_EXCLUDED_REPOS="my-repo,legacy-monolith"
bypasser install   # throws inside those directories

If the repo uses husky, lefthook, pre-commit.com, or anything else that sets core.hooksPath to a directory other than .git/hooks, bypasser install refuses instead of silently writing a file git will never execute. Add a bypasser audit --pre-commit line to the existing pre-commit workflow, or unset core.hooksPath and re-run install. bypasser uninstall still cleans a legacy bypasser hook from .git/hooks even when core.hooksPath is set — it never touches the foreign hooks directory.

Details: AGENTS.md → Hook install exclusions. bypasser uninstall still removes our hook if it was installed by mistake.

Disable the audit for one repo (disable: true)

To keep the hook installed but make it a complete no-op in a specific repo — the tool's own source repo, or any repo that ships an equivalent workflow — set disable in that project's .bypasser.json:

{ "disable": true }

The audit then scans nothing, rewrites nothing and notifies nothing, and exits 0 so the commit is never blocked or slowed. It short-circuits before the API-key check, so a disabled repo needs no key. BYPASSER_DISABLE=1 forces it on regardless of the file. .bypasser.json is normally gitignored, so this is a per-machine, per-project switch that never leaks into the public source.


What happens on commit

Channel What you see
Hook stdout Compact per-file score + humanized / ok / skipped / failed
.bypasser.log Timestamped history with fired signals (great tab to leave open)
Desktop notification Clean / Humanized / Rewrite failed (optional; notifications: auto by default, important for humanized + failures only)

Example log excerpt:

── 2026-09-28 14:32:11 ─────────────────────────────────────
  src/utils.ts: 72% [███████░░░] ✓ humanized & re-staged
    ↳ [naming] Over-descriptive variable names
  src/index.ts: 31% [███░░░░░░░] ✓ ok
  → 1 file(s) humanized and re-staged

Manual audit with details:

bypasser audit --verbose
# or: BYPASSER_VERBOSE=1 git commit

OpenCode panel (optional)

If you use OpenCode, a bundled TUI plugin shows your BypasserAI data live in the right sidebar — last run (files, scores, per-family signals, delta vs previous run), project history (success rate, trend sparkline, hotspots) and the project config. It reads .bypasser.log.jsonl locally — no network, no API key.

BypasserAI panel inside the OpenCode sidebar

node integrations/opencode/install.mjs   # or: npm run install-panel

Then restart OpenCode. See integrations/opencode/README.md for details, manual install, and uninstall.


CLI reference

Command Description
bypasser init Create .bypasser.json (skip if exists)
bypasser init --force Regenerate config from defaults
bypasser install / uninstall Add or remove pre-commit hook
bypasser detect Score staged files
bypasser detect --all Score working tree without staging
bypasser detect --verbose Show fired signals
bypasser rewrite <file> Rewrite one file via API
bypasser audit Detect + rewrite + restage staged files
bypasser audit --dry-run Detect only, no API
bypasser audit --verbose Audit with signal details
bypasser audit --strict Exit non-zero if any AI-shaped file was not humanized (CI gate)
bypasser stats Summarize the structured audit log (.bypasser.log.jsonl)

Configuration

Field Default Description
baseURL https://api.openai.com/v1 OpenAI-compatible endpoint
model gpt-4o-mini Chat model name at that endpoint
threshold 0.65 Rewrite when AI score ≥ this (0–1)
maxTokens 16384 Max completion tokens per rewrite
temperature 0.4 Rewrite sampling temperature
ignore [] Extra globs to never rewrite
thresholds [] Per-glob overrides, e.g. [{ "pattern": "legacy/**", "value": 0.3 }]
timeoutMs 120000 Base rewrite timeout (ms)
timeoutPer1kLinesMs 30000 Added per 1000 lines over 1000
maxTimeoutMs 600000 Hard timeout cap
maxFileLines 2000 Skip full-file rewrite above this; diff/chunk still apply in auto
rewriteConcurrency 3 Parallel API calls per audit
rewriteScope auto file · diff · chunk · auto
rewriteFullFileBelowLines 400 Full-file cutoff in auto
contextLines 60 Context around diff hunks
maxChunkLines 450 Max lines per chunk
structuralCheck true Reject rewrites that drop too many top-level declarations
semanticReview true Second model pass that rejects a rewrite that changed behavior
semanticReviewModel "" Model for that second pass; empty → same model as the rewrite
semanticReviewMaxLines 1200 Skip the second pass above this file size (0 = no cap)
disable false Make the audit a complete no-op for this repo (hook stays installed)
notifications auto auto (notify every outcome) · important (only humanized + rewrite failures) · off (never)

Environment variables (override file config; preferred for secrets):

Variable Purpose
BYPASSER_API_KEY API key
BYPASSER_BASE_URL Base URL
BYPASSER_MODEL Model
OPENAI_API_KEY Fallback key
BYPASSER_VERBOSE 1 → verbose audit/hook output
BYPASSER_DISABLE 1 → force-disable the audit for this run
BYPASSER_HOOK_EXCLUDED_REPOS Comma-separated repo folder names to block install
BYPASSER_SKILL_LOCALE es → Spanish humanizer prompt (SKILL.es.md); default English
BYPASSER_NOTIFICATIONS auto | important | off → override the notification mode
BYPASSER_SEMANTIC_REVIEW 0 → turn off the semantic review pass for this run

Model choice (important)

The rewriter expects the same fragment back, humanized — not a compressed summary. Models that return ~10–35% of the input (dropping def, loops, types) are rejected by design; the file commits unchanged and it looks like “the hook did nothing.”

Before relying on a model for large files, sanity-check: output line count ≈ input, declarations intact. gpt-4o-mini is a reasonable default; for local or proxy setups, pick a model that round-trips full fragments.

Provider examples

Provider baseURL
OpenAI https://api.openai.com/v1
Groq https://api.groq.com/openai/v1
OpenRouter https://openrouter.ai/api/v1
Ollama http://localhost:11434/v1
LM Studio http://localhost:1234/v1
Local proxy (e.g. 9Router) http://localhost:20128/v1

Local proxies often accept any non-empty BYPASSER_API_KEY (e.g. local).

Full template for bulk sync across repos: scripts/canonical-bypasser.json.


Files always skipped

Built-in ignores include lockfiles, dist/**, build/**, .next/**, minified assets, most *.json / *.yaml / *.toml, and bypasser artifacts (*.bak, *.bypasser.tmp, .bypasser.log.jsonl). Extend with ignore in .bypasser.json.


Scoring (detector)

Six signal families (naming, structure, comments, error-handling, abstraction, uniformity) fire on language-aware profiles — not English-only heuristics. Fired weights combine through a saturating curve 1 - e^(-w/2.5) so realistic AI clusters land around 70–85% while typical human code stays below ~50% at the default threshold 0.65.

Informative docblocks (@param, multi-line rationale) are not penalized; only terse restating docblocks on nearly every function count as an AI tell.

Before scoring, code and comments are split into masked views (src/mask.ts), so a // inside a string, a function inside a regex literal, or a URL containing // never count as code. Detector behaviour is pinned by an annotated corpus + benchmark (npm run bench) — see CI gate & detector calibration.


Architecture

src/
  cli.ts              Command router
  config.ts           .bypasser.json + env + scope resolution
  detector.ts         Deterministic scorer (language profiles)
  mask.ts             Masked code/comments/documented views (strings & comments out of scoring)
  rewriter.ts         API client, humanizer prompt, sanitizers
  rewrite-validate.ts Indent / structure heuristics
  semantic-drift.ts   Second model pass: did the rewrite change behavior? (fail-open)
  rewrite-constants.ts Shared ratio thresholds
  syntax-guard.ts     Python / JSON parse backstop on assembled output
  diff-hunks.ts       Unified diff parse, slice, splice
  chunk-split.ts      Top-level declaration chunking
  concurrency.ts      Bounded parallel rewrite pool
  git.ts              Staged content, batch cached diff, restage, tracked files
  installer.ts        Hook install/remove + excluded repos
  audit.ts            detect → rewrite → restage → log → notify; selectUnresolvedFiles() for --strict
  logger.ts           .bypasser.log + structured .bypasser.log.jsonl (incl. per-file signals) + .bypasser.state.json cache (batch + prune)
  stats.ts            Aggregates the structured log for `bypasser stats`
  secrets.ts          Detects an inline apiKey at risk of being committed
  notifier.ts         Cross-platform notify (Windows toast + macOS/Linux shell)
  index.ts            Public library exports
docs/
  SKILL.en.md         Humanizer prompt (default at runtime)
  SKILL.es.md         Humanizer prompt (Spanish)
  SKILL.md            Bilingual index + locale notes
scripts/
  bench-detector.ts   Detector benchmark + golden snapshot (test/corpus/corpus.json)
  test.js             Cross-platform test runner
test/
  corpus/             Annotated AI/human samples + detector-snapshot.json
integrations/
  opencode/           Optional OpenCode TUI panel (install.mjs + bypasser-panel.tsx)

Integrity guards

On any doubt, the original file wins:

  • finish_reason: length → reject
  • Unbalanced brackets / suspicious line collapse → reject
  • Flattened indentation or dropped declarations → reject
  • checkSyntax() on assembled output (Python / JSON when available)
  • Semantic drift review: a second model pass compares the original against the rewrite and rejects it when observable behavior changed (a flipped comparison, a swapped return value). Fail-open: if the reviewer is unreachable, the rewrite is kept. Disable with semanticReview: false
  • restageFile(): no empty overwrite, severe-shrink guard, atomic write, .bak, rollback if git add fails

Failed rewrites do not block the commit; check .bypasser.log and hook output.


CI gate & detector calibration

Detector quality is measured, not assumed. test/corpus/corpus.json holds annotated AI/human samples across languages; npm run bench runs the detector over them and reports a confusion matrix, precision/recall/F1, and the threshold that maximises F1. test/bench-detector.test.ts asserts a quality floor and locks every sample's score against a golden snapshot — a weight tweak that moves a score by more than 0.02 fails CI until it is consciously re-recorded (BYPASSER_UPDATE_SNAPSHOT=1 npm test).

Strict gate for CI (not the hook — the hook never blocks a commit):

bypasser audit --strict   # exits 1 if an AI-shaped file was not humanized

A ready-made composite Action wraps this for any repo:

- uses: Pacoaldev/BypasserAI/.github/actions/bypasser-strict@main
  with:
    api-key: ${{ secrets.BYPASSER_API_KEY }}

Development

npm install
npm run build      # required after src/ changes
npm test           # node:test via scripts/test.js (Node >= 20.6 for tsx)
npm run bench      # detector precision/recall/F1 over the annotated corpus
npm run typecheck
npm run lint
npm run format

CI runs lint, typecheck, tests, and build on Node 18 / 20 / 22 (see .github/workflows/ci.yml).

Contributions welcome — open an issue or PR.


Limits

  • Skips config, locks, and generated artifacts by convention
  • Never weakens security or correctness to “look human”
  • Heuristic detector — tune threshold / thresholds if needed
  • Hook and CLI work on Windows/macOS/Linux; desktop notifications are optional (notifications: off disables them)

License

MIT — © Pacoaldev


Built with Gentle-AI

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages