Skip to main content

NoEllipsis

CI Latest release Python 3.11+ PyPI MIT

A fast, local CLI that detects incomplete or dangerously truncated LLM-generated code before you paste, commit, or deploy it.

NoEllipsis is a deterministic static checker. It does not call a model, does not need an API key, and never uploads your source. It never executes the files it scans and never changes Git state.

It is not an AI-content detector, a full compiler, a vulnerability scanner, a rewriter, or a hosted service.

Terminal demo

2-minute landing

pipx install noellipsis
# or: python -m pip install noellipsis
noellipsis --version
noellipsis check examples/ok_examples.py --format text
noellipsis check examples/incomplete.py --format text
noellipsis compare examples/generated_snippet.py --against examples/original_module.py --format text

A clean file prints No issues found. An unfinished function reports NE002 and a one-line count such as 1 finding: 1 error. Compare reports shrink / removed-symbol rules (NE101NE104) plus any placeholders in the candidate.

The image above is a static terminal snapshot generated from real CLI output (see docs/demo.tape). It is not an animated GIF.

Install

Requires Python 3.11+.

pipx install noellipsis
python -m pip install noellipsis

From the git tag (same version):

python -m pip install "noellipsis @ git+https://github.com/hoodbroskillson/NoEllipsis.git@v1.1.2"

Then:

noellipsis --help
python -m noellipsis --help

Local development:

python -m pip install -e ".[dev]"
ruff check .
pytest -q

The dev extra includes pytest, pytest-cov, ruff, build, twine, Hypothesis, and pre-commit. Runtime dependencies remain empty.

Commands

Shared options may appear before or after the subcommand:

noellipsis --format json check src/
noellipsis check src/ --format json
noellipsis --fail-on warning compare candidate.py --against original.py
noellipsis compare candidate.py --against original.py --fail-on warning
noellipsis --format github git-diff --staged
noellipsis git-diff --staged --format github

noellipsis check FILE_OR_DIRECTORY

Scan a file or a tree. Default excludes include .git, virtualenvs, node_modules, vendor, dist, build, coverage output, __pycache__, minified JS, and common binaries.

noellipsis check src/
noellipsis check examples/incomplete.py --format text

noellipsis compare GENERATED --against ORIGINAL

Compare a model’s candidate against the file it was supposed to edit. Reports percent size reduction, removed top-level functions/classes/methods, removed imports, snippet-as-replacement, and any placeholders the candidate introduced.

noellipsis compare examples/generated_snippet.py --against examples/original_module.py

noellipsis git-diff / noellipsis git-diff --staged

Inspect added lines in the working-tree (or staged) diff. Requires a Git repository. Uses subprocess.run with an argument list and shell=False. Does not stage, commit, reset, restore, or checkout anything.

noellipsis git-diff
noellipsis git-diff --staged --format github

Outside a repository the command exits 2 with a clear error.

noellipsis rules

Print the built-in catalog (deterministic order). --format json or text.

noellipsis rules
noellipsis rules --format json

Options

Option Meaning
--format text|json|github|sarif Human text, stable JSON, GitHub Actions annotations, or SARIF 2.1.0
--fail-on error|warning Minimum severity that yields exit code 1
--exclude PATTERN Extra glob (repeatable)
--disable RULE_ID Turn off a rule (repeatable)
--shrink-threshold 40 Percent shrinkage that triggers NE101 (integer 0–100)
--verbose Progress on stderr
--config PATH TOML file with [tool.noellipsis] (overrides auto-discovered pyproject.toml)

Invalid CLI flags or invalid [tool.noellipsis] values print a clear error and exit 2. An explicit --config that is missing, unreadable, malformed, or invalid also exits 2 (no silent fallback).

Exit codes

Code Meaning
0 Nothing at or above --fail-on
1 One or more findings at or above the threshold
2 Invalid arguments, invalid config, unreadable path, not a git repo, or internal error

Rules

ID Default What it catches
NE001 error Placeholder phrases in real comments (Rest of code unchanged, Insert your code here, stub-like TODO/FIXME)
NE002 error Bare ellipsis / incomplete body. A Python function whose entire body is ... is an error
NE003 warning pass-only (or raise NotImplementedError-only) function, unless abstract or clearly intentional
NE004 error Unclosed Markdown code fence
NE005 error Unbalanced (), [], {} via a state machine that skips strings and comments
NE006 error Python syntax error / truncated statement (ast.parse)
NE007 error Unresolved merge-conflict markers
NE101 error Candidate dramatically shorter than the original (default 40% smaller)
NE102 error Top-level function, class, or method removed
NE103 warning Imports unexpectedly removed
NE104 error Probable full-file replacement with a partial snippet

Each finding includes: rule id, severity, file, line (when known), a short explanation, and a suggested next action.

What NoEllipsis deliberately does not flag

These are regression-tested:

  • print("...")
  • const copy = [...items]; and function collect(...args) {}
  • Prose such as Wait... what happened?
  • URLs and quoted documentation
  • Placeholder-looking text inside docstrings, JS/TS templates, Go raw strings, Rust raw strings, and shell heredocs
  • Intentional Python @abstractmethod / Protocol stubs
  • .pyi stub files
  • Empty constructors (def __init__(self): pass)
  • JavaScript spread / rest (...args)

Language support: strong AST for Python. Conservative heuristics for JS/TS/JSX/TSX, Java, Go, Rust, C/C++, C#, Ruby, PHP, Shell, and Markdown. Prefer a miss over a false positive.

A shared lexer classifies code / string / comment regions. Suppression phrases and placeholder detection look at comments only. The tool never executes scanned code.

Configuration

pyproject.toml:

[tool.noellipsis]
shrink-threshold = 40
fail-on = "error"
exclude = ["vendor/**", "generated/**"]
disable = ["NE103"]

See noellipsis.example.toml. An explicit --config PATH wins over pyproject.toml. CLI flags override both.

noellipsis --config noellipsis.example.toml check src
noellipsis check src --config noellipsis.example.toml

Suppressions

Works in real comments (#, //, /* */, <!-- -->). Phrases inside strings or docstrings never suppress.

def experimental():
    ...  # noellipsis: ignore[NE002]
# noellipsis: ignore-file

Multiple ids: noellipsis: ignore[NE002,NE003].

pre-commit

repos:
  - repo: https://github.com/hoodbroskillson/NoEllipsis
    rev: v1.1.2
    hooks:
      - id: noellipsis

The hook runs noellipsis git-diff --staged with no filename arguments and does not mutate Git. Exit codes match the table above.

GitHub Actions

- uses: actions/checkout@v7
- uses: actions/setup-python@v7
  with:
    python-version: "3.12"
- run: python -m pip install "noellipsis @ git+https://github.com/hoodbroskillson/NoEllipsis.git@v1.1.2"
- run: noellipsis git-diff --format github

Reusable action (exact tag, never a floating v1):

- uses: hoodbroskillson/NoEllipsis@v1.1.2
  with:
    path: .
    command: check
    format: github
    fail-on: error

SARIF upload (file is written even when the scanner exits 1; fail after upload):

- uses: actions/checkout@v7
- uses: hoodbroskillson/NoEllipsis@v1.1.2
  id: scan
  continue-on-error: true
  with:
    command: check
    path: src
    format: sarif
- uses: github/codeql-action/upload-sarif@v4
  if: always()
  with:
    sarif_file: ${{ steps.scan.outputs.sarif-file }}
- name: Fail if findings
  run: test "${{ steps.scan.outputs.exit-code }}" = "0"

See action/README.md. Also .github/workflows/noellipsis-sarif.yml (contents: read, security-events: write).

This repository’s own CI is .github/workflows/ci.yml. The release.yml workflow builds once, checksums and attests artifacts, attaches the same bytes to the GitHub Release, and is prepared to publish to PyPI via Trusted Publisher (environment: pypi). Do not publish from a laptop.

Output

Text:

src/example.py:84:5 ERROR NE002 Bare ellipsis used as function body
  Replace the placeholder with an implementation or suppress NE002 if intentional.
1 finding: 1 error

A clean scan prints No issues found.

GitHub Actions (special characters in paths and messages are escaped):

::error file=src/example.py,line=84,col=5::NE002 Bare ellipsis used as function body

JSON is deterministic (sorted keys, findings ordered by file / line / rule). SARIF is a standalone JSON document on stdout (see docs/sarif.md).

Limitations (honest)

  • Not a type checker, compiler, formatter, or security scanner.
  • Not an AI-content detector and will not tell you whether a human wrote a file.
  • Heuristics for non-Python languages miss some syntax and ignore some comments inside unusual constructs.
  • --shrink-threshold compare is byte-size based; a shorter-but-complete rewrite can still trip NE101.
  • False positives should be reported as issues with a minimal file. Prefer a suppression over loosening a rule globally.

Safety / privacy

  • No network requests at runtime
  • No evaluation or exec of scanned files
  • Scanned files are never modified
  • Git is read-only (git rev-parse, git diff)
  • Runs entirely on the machine you invoke it on

License

MIT © 2026 hoodbroskillson

Download files

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

Source Distribution

noellipsis-1.1.2.tar.gz (52.1 kB view details)

Uploaded Source

Built Distribution

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

noellipsis-1.1.2-py3-none-any.whl (34.6 kB view details)

Uploaded Python 3

File details

Details for the file noellipsis-1.1.2.tar.gz.

File metadata

  • Download URL: noellipsis-1.1.2.tar.gz
  • Upload date:
  • Size: 52.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for noellipsis-1.1.2.tar.gz
Algorithm Hash digest
SHA256 9a24bbdc99d1a6fc76e7a5310117eee1ef9e2229b5c2e7d906dd6222552b44a6
MD5 93866e975a66f5f57dfb7633c3f72509
BLAKE2b-256 628c4039bb80d6e9cfbf103d3bc592e8e47747026ca0f2b0b4a1b498634af3d0

See more details on using hashes here.

Provenance

The following attestation bundles were made for noellipsis-1.1.2.tar.gz:

Publisher: release.yml on hoodbroskillson/NoEllipsis

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file noellipsis-1.1.2-py3-none-any.whl.

File metadata

  • Download URL: noellipsis-1.1.2-py3-none-any.whl
  • Upload date:
  • Size: 34.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for noellipsis-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 afb9375b286e2d3b050bc293b7cf8a0ee02679537664293d1d02f2779c226a4f
MD5 a0307af3e0ab70f683c3f4220179f042
BLAKE2b-256 3a1e57d5b23d43d64c9d29ce705ac758fe7699f7a06167700e311948b6051588

See more details on using hashes here.

Provenance

The following attestation bundles were made for noellipsis-1.1.2-py3-none-any.whl:

Publisher: release.yml on hoodbroskillson/NoEllipsis

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.1.2 This release

2 files

1.1.0

2 files

Supported by

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