Skip to main content

triplet-miner

Mine (anchor, positive, negative) triplets from git history for contrastive learning.

Given a git repo, it extracts commit messages as anchors, diffs as positives, and selects negatives from other commits/file contents using configurable strategies.

Quick Start

from triplet_miner import TripletMiner, MiningStrategy

miner = TripletMiner(
    default_strategy=MiningStrategy.HARD_NEGATIVE,
    max_commits=500,
    negatives_per_anchor=1,
)

triplets = miner.mine_from_repo("/path/to/repo")
print(f"Mined {len(triplets)} triplets")

# Export
miner.export(triplets, "output.json")

Command Line

# Install
pip install -e .

# Run from Python
python -c "
from triplet_miner import TripletMiner
miner = TripletMiner()
triplets = miner.mine_from_repo('.')
for t in triplets[:3]:
    print(f'anchor: {t.anchor[:80]}...')
    print(f'positive length: {len(t.positive)} chars')
    print(f'negative length: {len(t.negative)} chars')
    print(f'similarity: {t.similarity:.3f}')
    print()
"

What Gets Mined

For each non-merge commit in the repo:

Field Source
anchor Commit message
positive Full diff of the commit (capped at 5000 chars)
negative Selected from other commits' diffs or current file contents

Commits with messages <10 chars or empty diffs are skipped.

Mining Strategies

from triplet_miner import MiningStrategy
Strategy How it picks negatives
RANDOM Random selection from candidate pool
HARD_NEGATIVE Picks candidates most similar to anchor (hardest to distinguish)
SEMI_HARD Picks candidates with similarity between 0 and anchor-positive similarity
DOMAIN_AWARE Picks negatives from different repos (cross-repo mining only)

Similarity is computed using 3-shingle Jaccard (min-hash style) with word-level Jaccard fallback.

Strategy Examples

# Hard negatives: best for training discriminative models
miner = TripletMiner(strategy=MiningStrategy.HARD_NEGATIVE)

# Semi-hard: balanced between easy and hard
miner = TripletMiner(strategy=MiningStrategy.SEMI_HARD)

# Multi-repo with cross-domain negatives
triplets = miner.mine_from_repos(
    ["/path/to/repo-a", "/path/to/repo-b", "/path/to/repo-c"],
    strategy=MiningStrategy.DOMAIN_AWARE,
)

With DOMAIN_AWARE, negatives come from different repos than the anchor, and a deterministic hash ensures consistency.

Output Format

JSON

[
  {
    "anchor": "fix: handle empty diff in triplet mining",
    "positive": "diff --git a/triplet_miner/git_miner.py ...\n-index abc1234..def5678 100644\n...",
    "negative": "diff --git a/README.md ...\n Completely unrelated change...",
    "similarity": 0.23,
    "source": "triplet-miner",
    "metadata": {
      "sha": "abc1234def567",
      "author": "developer",
      "timestamp": 1700000000.0,
      "files_changed": 3,
      "files": ["triplet_miner/git_miner.py", "tests/test_git_miner.py"],
      "negative_similarity": 0.15
    }
  }
]

CSV

anchor,positive,negative,similarity,source,metadata
"fix: handle...","diff --git...","diff --git...",0.23,"triplet-miner","{...}"

Quality Filtering

from triplet_miner import QualityFilter, Triplet

qf = QualityFilter(
    min_length=10,        # minimum chars for anchor/positive/negative
    max_length=50000,     # maximum chars
    deduplicate=True,     # remove near-duplicate triplets
    languages={"python", "rust"},  # only keep these languages
    min_quality=0.3,      # minimum quality score
)

filtered = qf.filter(triplets)

Quality score factors (0.0–1.0):

  • Base: 0.5
  • Length sweet spot (50–2000 chars): +0.1 per field
  • Moderate length (20–5000): +0.05 per field
  • Anchor-positive similarity: +0 to +0.2
  • Metadata present: +0.05
  • SHA in metadata: +0.05

Language detection uses file extensions mapped to 20+ languages.

Multi-Repo Mining

from triplet_miner import TripletMiner, MiningStrategy, QualityFilter

miner = TripletMiner(
    default_strategy=MiningStrategy.DOMAIN_AWARE,
    max_commits=200,
    negatives_per_anchor=2,
)

triplets = miner.mine_from_repos(
    ["/repos/plato-core", "/repos/fleet-router", "/repos/constraint-substrate"],
    min_quality=0.3,
)

miner.export(triplets, "training-data.json")

mine_from_repos mines each repo independently, then applies quality filtering. With DOMAIN_AWARE, cross-repo negatives replace same-repo ones.

PyTorch / HuggingFace Integration

from triplet_miner import TripletMiner

miner = TripletMiner()
triplets = miner.mine_from_repo(".")

# PyTorch Dataset (requires pip install triplet-miner[torch])
dataset = miner.to_dataset(triplets)
# TripletDataset(len=150)

# HuggingFace Dataset (requires pip install datasets)
hf_dataset = miner.to_hf_dataset(triplets)

Install

pip install -e .

# With PyTorch support
pip install -e ".[torch]"

# With HuggingFace
pip install -e ".[torch]" datasets

TypeScript / npm

An npm package is available at npm/:

cd npm
npm install
npm run build

Tests

pytest tests/

License

MIT

Metadata

Release files for triplet-miner 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for triplet-miner 0.1.0
File Size Uploaded Provenance Actions
triplet_miner-0.1.0.tar.gz 17.8 kB Without provenance Details for triplet_miner-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for triplet-miner 0.1.0
File Interpreter ABI Platform Actions
triplet_miner-0.1.0-py3-none-any.whl Python 3 none any Details for triplet_miner-0.1.0-py3-none-any.whl

Total release size: 32.2 kB

Release files / triplet_miner-0.1.0.tar.gz

Download URL triplet_miner-0.1.0.tar.gz
Size 17.8 kB
Tags Source
SHA-256 checksum
How to use checksums
41a39a495280a70488ae9a99aee3af56d754958e562698dea2d2a6d2e27f914f
BLAKE2b-256 checksum
How to use checksums
a8c85faa0bb7aa7d1723ab5b145f3d6929f6a1890a91cecccfec866e328ff661
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12

Release files / triplet_miner-0.1.0-py3-none-any.whl

Download URL triplet_miner-0.1.0-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b7147811542cf07cb56ae4170f52a11c284f65e6db6b7b4c862774cad52d9b6f
BLAKE2b-256 checksum
How to use checksums
7b5a13f28e62a1abdf11440b609d734fd40f9af6a06bba3a4719bc12b77c605d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12

Security for triplet-miner 0.1.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page