Aposlop
Apos, the Slopbreaker
Slop always rolls downhill. Aposlop helps to push back.
Aposlop is a fast command-line tool. It finds duplicate code and calculates cyclomatic complexity.
Aposlop supports Go, Rust, Python, TypeScript, and TSX. Aposlop uses Tree-sitter to parse each supported language.
Documentation: https://aposlop.ezygang.digital/
Source Code: https://github.com/EzyGang/aposlop
Issues: https://github.com/EzyGang/aposlop/issues
Table of Contents
- Why Aposlop?
- Installation
- Quick Start
- Core Features
- Configuration
- CLI Quick Reference
- Contributing
- License
Why Aposlop?
Aposlop exists to find code slop from coding agents.
Coding agents can generate duplicate code and add complex control flow. These changes can enter a project faster than a reviewer can find them.
Text comparison does not find a duplicate after an agent renames identifiers or changes literals. A linter does not find repeated logic in different files or languages. A complexity limit does not identify repeated logic.
Aposlop uses exact, normalized, and verified near-miss duplicate detection. It also calculates cyclomatic complexity for each code block.
Aposlop is fast enough for an agent validation loop. You can configure thresholds for each language and file extension. You can also exclude paths or accept specific findings. These controls let a project accept known findings and continue development.
| Feature | Result |
|---|---|
| Type-1 detection | Finds exact duplicates |
| Type-2 detection | Finds duplicates after identifier or literal changes |
| Type-3 detection | Finds verified near-miss duplicates |
| Complexity analysis | Calculates complexity for each code block |
| Terminal code view | Shows every group instance with line numbers |
| JSON output | Provides stable data for other tools |
| CI command | Returns failure when findings remain |
| Local cache | Reuses analysis for unchanged files |
| Update check | Warns interactive users when a new release is available |
How Aposlop works
- Parse once. Tree-sitter providers extract blocks, identifiers, literals, comments, and complexity decisions.
- Type-1. XXH3 groups exact token streams before complete equality verification.
- Type-2. The same process compares streams with normalized identifiers and literals.
- Type-3. Five-token shingles feed a prefix-filtered similarity join. Length and position filters prune candidates before Jaccard verification.
- Grouping. Connected duplicate relations become one deterministic group with every source instance.
- Complexity. Each block starts at
1and adds unique language-specific decision captures. Nested blocks have independent scores. - Cache. Versioned bincode data reuses unchanged analysis. File metadata and schema versions invalidate stale entries before atomic replacement.
Installation
Install script on Linux or macOS
Install cosign. Then run the installer:
curl -fsSLo install.sh https://github.com/EzyGang/aposlop/releases/latest/download/install.sh
sh install.sh
Install script on Windows
Install cosign. Then run the installer:
Invoke-WebRequest https://github.com/EzyGang/aposlop/releases/latest/download/install.ps1 -OutFile install.ps1
powershell -ExecutionPolicy Bypass -File .\install.ps1
Both scripts verify the archive checksum and Sigstore signatures.
Cargo
Install Aposlop from crates.io:
cargo install aposlop --locked
PyPI with uv
Install Aposlop as a global tool:
uv tool install aposlop
Run Aposlop without installing it:
uvx aposlop --help
Homebrew
Install Aposlop from the EzyGang Homebrew tap:
brew install EzyGang/tap/aposlop
From source
Install Aposlop from source. A stable Rust toolchain must support edition 2024.
git clone https://github.com/EzyGang/aposlop.git
cd aposlop
cargo install --path . --locked
Verify the installation:
aposlop --version
aposlop --help
Agent skill
Install the Aposlop skill for supported coding agents:
npx skills@latest add EzyGang/aposlop --skill aposlop
The skill teaches agents how to configure Aposlop, inspect findings, and add Aposlop to validation workflows. The skill does not install the Aposlop binary.
Update checks
Aposlop checks for a new GitHub release during interactive runs. It performs a network request at most once every 24 hours. It stores the latest result in the user cache directory. Non-interactive commands do not perform this check.
Set this environment variable to disable the check:
APOSLOP_NO_UPDATE_CHECK=1 aposlop .
Quick Start
Analyze the current directory:
aposlop .
Show the source for each duplicate:
aposlop . --terminal-output code
Run CI validation:
aposlop ci .
The ci command returns exit code 1 when a finding remains.
Write the complete report as JSON:
aposlop . --format json > aposlop-report.json
Read the full quick-start guide.
Core Features
Duplicate Detection
A block enters analysis when it meets the line and named-node limits.
Aposlop classifies block relations in this order:
- Type-1 requires identical canonical syntax.
- Type-2 allows different identifiers and literals.
- Type-3 requires a Jaccard similarity at or above the configured threshold.
Aposlop reports each connected set of duplicate relations as one group. Two blocks do not match when either contains the other in the same file. A TypeScript block can match a TSX block.
Cyclomatic Complexity
Each valid block has an initial complexity score of 1.
Aposlop adds one for each language-specific decision.
Decisions include branches, loops, alternatives, exception paths, conditional expressions, and short-circuit operations.
A nested block has an independent score. Nested blocks include functions, closures, lambdas, field initializers, and static blocks.
A violation requires:
score > complexity_threshold
Language Support
| Language | Extensions |
|---|---|
| Go | .go |
| Rust | .rs |
| Python | .py |
| TypeScript | .ts |
| TSX | .tsx |
Aposlop ignores unsupported extensions.
Aposlop follows standard ignore files such as .gitignore.
Output Formats
The terminal report is the default. It contains duplicate groups, complexity findings, diagnostics, and a summary.
aposlop . --format terminal
The JSON report contains the complete report and its schema version.
aposlop . --format json
The ci command shows only the status and finding counts.
aposlop ci .
Manual Exclusions
Aposlop assigns a deterministic five-character ID to each duplicate group or complexity finding.
Add a finding to the manual exclusions:
aposlop allow aB7_x
The command writes the ID to .aposlopignore.
Delete the ID from that file to restore the finding.
Aposlop reports valid IDs that match no current finding as unused ignores at the end of each report.
Unused ignores do not change the process exit code.
Configuration
Aposlop reads <PATH>/.aposlop.toml.
Aposlop uses built-in values when this file does not exist.
[core]
min_lines = 5
min_nodes = 30
exclude = ["tests/", "vendor/", "node_modules/", "target/"]
use_cache = true
[duplicates_detection]
type_1 = true
type_2 = true
type_3 = true
type_3_threshold = 0.85
[metrics]
calculate_complexity = true
complexity_threshold = 15
Each exclude value uses the same pattern syntax as one .gitignore line.
A directory pattern such as tests/ matches that directory name at any depth.
Patterns can use / for root anchoring and ** for recursive directory matching.
Language and extension tables can override the core values. Command-line values override all configuration-file values.
CLI Quick Reference
| Command or option | Purpose |
|---|---|
aposlop ci [PATH] |
Print a concise finding summary and fail when findings exist |
aposlop allow <FINDING> [PATH] |
Add a finding to the target's manual exclusions |
--format <terminal|json> |
Select the report format |
--terminal-output <locations|code> |
Select terminal duplicate detail |
--min-lines <N> |
Override the minimum block line count |
--min-nodes <N> |
Override the minimum named-node count |
--exclude <GLOB> |
Replace configured gitignore-style exclusion patterns |
--use-cache <BOOL> |
Enable or disable the analysis cache |
--type-1 <BOOL> |
Enable or disable Type-1 findings |
--type-2 <BOOL> |
Enable or disable Type-2 findings |
--type-3 <BOOL> |
Enable or disable Type-3 findings |
--type-3-threshold <RATIO> |
Override the Type-3 threshold |
--calculate-complexity <BOOL> |
Enable or disable complexity findings |
--complexity-threshold <N> |
Override the complexity threshold |
Read the complete CLI reference.
Contributing
Open a GitHub issue to discuss a large change. Then open a pull request.
Run these checks before you submit the pull request:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features
cargo run -- --help
License
You can use Aposlop under either license:
Metadata
Release files for aposlop 1.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| aposlop-1.1.3-py3-none-win_arm64.whl | Python 3 | none | Windows ARM64 | Details |
| aposlop-1.1.3-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| aposlop-1.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details |
| aposlop-1.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | Python 3 | none | Linux glibc 2.17+ ARM64 | Details |
| aposlop-1.1.3-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| aposlop-1.1.3-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details |
Total release size: 21.0 MB
Release files / aposlop-1.1.3-py3-none-win_arm64.whl
| Download URL | aposlop-1.1.3-py3-none-win_arm64.whl |
|---|---|
| Size | 3.2 MB |
| Tags | Python 3 Windows ARM64 |
|
SHA-256 checksum How to use checksums |
aa061c395cb09c2db12f79161e5d86c6a93f8c8d0e172d301f3cbcc7ca897e57
|
|
BLAKE2b-256 checksum How to use checksums |
40c65a3c1e90351f0602ad605ab37a3d3542625addb42b389c0aa3914632ee07
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / aposlop-1.1.3-py3-none-win_amd64.whl
| Download URL | aposlop-1.1.3-py3-none-win_amd64.whl |
|---|---|
| Size | 3.3 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
9b91590c785791e7c50f90a9e34855c6f5c8643d3d238896e8a8279b4a086827
|
|
BLAKE2b-256 checksum How to use checksums |
3d45d096ec7064d4e26ace6a3b39816d51aac2f007966effb5f3e1fa996091bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / aposlop-1.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | aposlop-1.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 3.8 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
934f97ec9439060730f0f2db6a75d20db2e52ae72daf8352e6af9fcc00f61a5c
|
|
BLAKE2b-256 checksum How to use checksums |
3dbdb01e04b3bcb231c2f1e2fdec866cdc3d469dd1a37621d7c6c8bd9b6e8204
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / aposlop-1.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | aposlop-1.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 3.5 MB |
| Tags | Linux glibc 2.17+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
8d6fb17b7f523ed5e3cba9c1f85ade9b371441f32fcfe34ddc8fb55079318456
|
|
BLAKE2b-256 checksum How to use checksums |
b19c11a920a303ca4cb3ec69e7f48456a95d210b548be7632d7418a5e3c40377
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / aposlop-1.1.3-py3-none-macosx_11_0_arm64.whl
| Download URL | aposlop-1.1.3-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 3.5 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
30ff132c4291f7b7805619eb30a2a2ef1e34952f663e182c813ebb8f88c6c788
|
|
BLAKE2b-256 checksum How to use checksums |
353dcbb406206f3870d4fde6f70878a61e4a7e9e574cb13c2d6c14409ce4cae9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / aposlop-1.1.3-py3-none-macosx_10_12_x86_64.whl
| Download URL | aposlop-1.1.3-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
5cf3231f6d8b2d3d03b986b91209788ab27eb718a884ab0b03379729be2f4768
|
|
BLAKE2b-256 checksum How to use checksums |
446fdb8c1cd1d829ee3ce7dc8f55295405a3531b450c1d2b412a8974349a1c4a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency log