Metadata-Version: 2.4
Name: curatorkit
Version: 0.1.19
Summary: Data curation and synthetic data generation for LLM post-training — provenance-grounded quality gates, adaptive recovery, trainer-ready exports
Author: Soham Bhattacharjee, Karun Sharma, Vinay Kumar Sankarapu, Pratinav Seth
Author-email: Lexsi Labs <hello@lexsi.ai>
Maintainer-email: Pratinav Seth <pratinav.seth@lexsi.ai>, Soham Bhattacharjee <soham.bhattacharjee@lexsi.ai>
License-Expression: LicenseRef-LSAL-1.1
Project-URL: Homepage, https://lexsi.ai
Project-URL: Documentation, https://lexsi-labs.github.io/CuratorKIT/
Project-URL: Repository, https://github.com/Lexsi-Labs/CuratorKIT
Project-URL: Issues, https://github.com/Lexsi-Labs/CuratorKIT/issues
Project-URL: Changelog, https://github.com/Lexsi-Labs/CuratorKIT/blob/main/CHANGELOG.md
Keywords: llm,synthetic-data,data-curation,post-training,fine-tuning,sft,dpo,grpo,dataset-generation,hallucination-detection,data-quality
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: pydantic>=2.7
Requires-Dist: typer>=0.12
Requires-Dist: tqdm>=4.66
Requires-Dist: pyyaml>=6.0
Provides-Extra: tiktoken
Requires-Dist: tiktoken>=0.7; extra == "tiktoken"
Provides-Extra: pdf
Requires-Dist: mineru[pipeline]>=3.0; extra == "pdf"
Provides-Extra: parquet
Requires-Dist: pyarrow>=15.0; extra == "parquet"
Provides-Extra: hf
Requires-Dist: datasets>=3.0; extra == "hf"
Requires-Dist: huggingface_hub>=0.26; extra == "hf"
Provides-Extra: connectors
Requires-Dist: pyarrow>=15.0; extra == "connectors"
Requires-Dist: datasets>=3.0; extra == "connectors"
Requires-Dist: huggingface_hub>=0.26; extra == "connectors"
Provides-Extra: generation
Requires-Dist: litellm>=1.60; extra == "generation"
Requires-Dist: tenacity>=9.0; extra == "generation"
Requires-Dist: nest-asyncio>=1.6; extra == "generation"
Provides-Extra: embedding
Requires-Dist: sentence-transformers>=3.0; extra == "embedding"
Requires-Dist: numpy>=2.0; extra == "embedding"
Provides-Extra: embedding-faiss
Requires-Dist: sentence-transformers>=3.0; extra == "embedding-faiss"
Requires-Dist: numpy>=2.0; extra == "embedding-faiss"
Requires-Dist: faiss-cpu>=1.9; extra == "embedding-faiss"
Provides-Extra: generation-full
Requires-Dist: litellm>=1.60; extra == "generation-full"
Requires-Dist: tenacity>=9.0; extra == "generation-full"
Requires-Dist: nest-asyncio>=1.6; extra == "generation-full"
Requires-Dist: sentence-transformers>=3.0; extra == "generation-full"
Requires-Dist: numpy>=2.0; extra == "generation-full"
Requires-Dist: faiss-cpu>=1.9; extra == "generation-full"
Provides-Extra: hygiene
Requires-Dist: detoxify>=0.5; extra == "hygiene"
Requires-Dist: detect-secrets>=1.4; extra == "hygiene"
Requires-Dist: presidio-analyzer>=2.2; extra == "hygiene"
Requires-Dist: presidio-anonymizer>=2.2; extra == "hygiene"
Requires-Dist: spacy>=3.7; extra == "hygiene"
Requires-Dist: faker>=26.0; extra == "hygiene"
Provides-Extra: hygiene-transformers
Requires-Dist: presidio-analyzer[transformers]>=2.2; extra == "hygiene-transformers"
Provides-Extra: hygiene-stanza
Requires-Dist: presidio-analyzer[stanza]>=2.2; extra == "hygiene-stanza"
Provides-Extra: safety
Requires-Dist: transformers<6,>=5.15; extra == "safety"
Requires-Dist: torch>=2.3; extra == "safety"
Provides-Extra: review
Requires-Dist: argilla>=2.0; extra == "review"
Provides-Extra: all
Requires-Dist: pyarrow>=15.0; extra == "all"
Requires-Dist: datasets>=3.0; extra == "all"
Requires-Dist: huggingface_hub>=0.26; extra == "all"
Requires-Dist: tiktoken>=0.7; extra == "all"
Requires-Dist: litellm>=1.60; extra == "all"
Requires-Dist: tenacity>=9.0; extra == "all"
Requires-Dist: nest-asyncio>=1.6; extra == "all"
Requires-Dist: sentence-transformers>=3.0; extra == "all"
Requires-Dist: numpy>=2.0; extra == "all"
Requires-Dist: faiss-cpu>=1.9; extra == "all"
Requires-Dist: detoxify>=0.5; extra == "all"
Requires-Dist: detect-secrets>=1.4; extra == "all"
Requires-Dist: presidio-analyzer>=2.2; extra == "all"
Requires-Dist: presidio-anonymizer>=2.2; extra == "all"
Requires-Dist: spacy>=3.7; extra == "all"
Requires-Dist: faker>=26.0; extra == "all"
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
Requires-Dist: mkdocstrings[python]>=0.27; extra == "docs"
Requires-Dist: mike>=2.1; extra == "docs"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=6.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Requires-Dist: check-wheel-contents>=0.6; extra == "dev"
Requires-Dist: pre-commit>=3.7; extra == "dev"
Provides-Extra: trl
Requires-Dist: trl>=0.21; extra == "trl"
Requires-Dist: transformers<6,>=5.15; extra == "trl"
Requires-Dist: torch>=2.3; extra == "trl"
Requires-Dist: datasets>=3.0; extra == "trl"
Dynamic: license-file

<p align="center">
  <a href="https://github.com/Lexsi-Labs/CuratorKIT">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="docs/assets/logo-white.png">
      <img src="docs/assets/logo.png" alt="CuratorKIT" width="480">
    </picture>
  </a>
</p>

<p align="center">
  <b>Data curation and synthetic data generation for LLM post-training.</b><br>
  Ingest from any source, generate with any LLM, verify every sample against its origin,<br>
  recover what fails, and export trainer-ready datasets with full provenance.
</p>

<p align="center">
  <a href="https://pypi.org/project/curatorkit/"><img src="https://img.shields.io/pypi/v/curatorkit?color=0a8868" alt="PyPI version"></a>
  <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.11%2B-blue" alt="Python 3.11+"></a>
  <a href="https://github.com/Lexsi-Labs/CuratorKIT/blob/main/LICENSE.md"><img src="https://img.shields.io/badge/license-LSAL%20v1.1-orange" alt="License: LSAL v1.1 (source-available)"></a>
  <a href="https://lexsi-labs.github.io/CuratorKIT/"><img src="https://img.shields.io/badge/docs-available-brightgreen" alt="Documentation"></a>
</p>

<p align="center">
  <a href="https://lexsi-labs.github.io/CuratorKIT/">Documentation</a> ·
  <a href="#quickstart">Quickstart</a> ·
  <a href="#tutorials">Tutorials</a> ·
  <a href="#ecosystem">Ecosystem</a> ·
  <a href="CONTRIBUTING.md">Contributing</a>
</p>

---

## Why CuratorKIT

Synthetic data is the fastest way to build a post-training dataset. It is also the fastest way to poison a model: generated samples hallucinate beyond their source material, drift off-distribution, duplicate each other, and quietly carry secrets, PII, and toxicity into training runs. Most teams find out after fine-tuning.

CuratorKIT treats dataset construction as a pipeline with quality gates, not a script with a prompt. Every generated answer is checked for grounding against the exact source chunk it came from. Rejected samples get diagnosed rather than discarded, and the fixable ones are repaired. Every run emits a provenance manifest, a dataset card, and checksums, so any sample can be audited back to its source.

## Key features

- **Grounded hallucination gate.** Verifies each generated answer against the source passage it was generated from, not against the judge model's general knowledge.
- **Reward and diversity gates.** Multi-dimension LLM-judge scoring plus embedding-based filtering against low-quality and near-duplicate samples.
- **Adaptive recovery.** An inline diagnostic probe classifies each rejection into a failure-mode taxonomy and repairs the recoverable ones.
- **Data hygiene.** Secrets detection, PII pseudonymization (Presidio), and toxicity filtering as pipeline stages.
- **Any source.** JSONL, JSON, CSV, Parquet, HuggingFace datasets, and PDFs with layout-aware parsing. Multi-source runs with per-source field mapping.
- **Eight generation tasks.** QA, preference pairs, GRPO rollouts, multi-turn, Evol-Instruct, chain-of-thought, and adversarial variants, on any LiteLLM-compatible API or local Ollama/vLLM.
- **Trainer-ready exports.** Alpaca, ShareGPT, chat messages, DPO, GRPO, and PPO formats with train/val/test splits, consumed directly by TRL and [AlignTune](https://github.com/Lexsi-Labs/aligntune).
- **Provenance by default.** Every run writes `manifest.json`, `rejected.jsonl` with structured reasons, `dataset_card.md`, `lexsi_provenance.json`, and SHA-256 `checksums.txt`.

## How it works

```mermaid
flowchart LR
    A["Ingest<br/>PDF · JSONL · CSV<br/>Parquet · HF Hub"] --> B["Clean + dedup<br/>exact · minhash · embedding"]
    B --> C["Hygiene<br/>secrets · PII · toxicity"]
    C --> D["Generate<br/>QA · DPO · GRPO · CoT"]
    D --> E{"Quality gates<br/>hallucination · reward · diversity"}
    E -->|pass| F["Export<br/>Alpaca · ShareGPT · Messages · DPO · GRPO · PPO"]
    E -->|reject| G["Adaptive recovery<br/>diagnose · repair · re-gate"]
    G -->|recovered| E
    G -->|unrecoverable| H["rejected.jsonl<br/>+ diagnostics"]
    F --> I["manifest · dataset card · checksums"]
```

## Install

```bash
pip install "curatorkit[all]"        # connectors + generation + embedding + hygiene (recommended)
pip install curatorkit               # core only: cleaning and dedup
```

Requires Python 3.11+ on Linux, macOS, or Windows.

<details>
<summary>More install options</summary>

```bash
pip install "curatorkit[generation]"       # LLM generation only
pip install "curatorkit[generation-full]"  # generation + embedding + FAISS
pip install "curatorkit[connectors]"       # pyarrow + datasets (no LLM)
pip install "curatorkit[hygiene]"          # secrets / PII / toxicity gates
pip install "curatorkit[pdf]"              # layout-aware PDF parsing (MinerU)

# From source
pip install "curatorkit[all] @ git+https://github.com/Lexsi-Labs/CuratorKIT.git"
```

The [installation guide](https://lexsi-labs.github.io/CuratorKIT/getting-started/installation/) has the full extras table.

</details>

## Quickstart

**Clean and deduplicate an existing dataset (no LLM, no API key):**

```python
from curatorkit import Curator, CuratorConfig

result = Curator(CuratorConfig(
    dataset        = {"name": "tatsu-lab/alpaca", "max_samples": 2000},
    dedup          = "minhash",
    clean          = True,
    export_formats = ["alpaca", "sharegpt"],
    output_dir     = "output/clean",
)).run()

result.print_summary()
```

HF Hub sources need the `connectors` extra (included in `all`); local JSONL/CSV files run on the core install.

**Generate gated synthetic QA data from a document:**

```bash
export OPENAI_API_KEY=sk-...   # any LiteLLM backend works; local Ollama/vLLM too
```

```python
result = Curator(CuratorConfig(
    dataset                 = "handbook.pdf",          # needs the [pdf] extra
    llm_model               = "openai/gpt-4o-mini",
    generation_task         = "qa",
    num_questions           = 3,
    hallucination_threshold = 0.7,                     # grounding gate
    reward_threshold        = 0.7,                     # LLM-judge gate
    export_formats          = ["alpaca", "sharegpt"],
    output_dir              = "output/qa",
)).run()
```

**Or run a declarative YAML pipeline from the CLI:**

```bash
curatorkit run examples/quickstart/pipeline.yaml --output-dir output/
```

Every run writes `manifest.json`, `rejected.jsonl`, `dataset_card.md`, `lexsi_provenance.json`, and `checksums.txt` alongside the export files. The [quickstart example](examples/quickstart/) runs end to end without an API key.

The output folder is also a Hugging Face dataset: its `README.md` maps each export to a config (`sft_alpaca`, `sft_sharegpt`, `sft_messages`, `dpo`, `grpo`, `ppo`, `corpus`) with one split per `output_split` directory, or `train`:

```python
from datasets import load_dataset
chat = load_dataset("output/qa", "sft_messages")  # DatasetDict: train (+ validation, ... with output_split)
```

### Cohere Aya as generator or judge

Any LiteLLM model string works, so Aya can generate the data, judge it, or both. Three ways to reach it:

```python
from curatorkit import Curator, CuratorConfig

result = Curator(CuratorConfig(
    dataset                 = "handbook.pdf",
    # 1. Cohere API (export COHERE_API_KEY=...)
    llm_model               = "cohere_chat/c4ai-aya-expanse-32b",
    # 2. Ollama:  llm_model = "ollama/aya-expanse"
    # 3. A local vLLM / `transformers serve` endpoint (OpenAI-compatible):
    #    llm_model = "openai/CohereLabs/aya-expanse-8b", llm_api_base = "http://localhost:8000/v1"
    judge_llm_model         = "cohere_chat/c4ai-aya-expanse-8b",   # optional; defaults to llm_model
    generation_task         = "qa",
    hallucination_threshold = 0.7,
    reward_threshold        = 0.7,
    min_tokens              = 3,          # short multilingual rows; CJK/Thai count per character
    output_dir              = "output/",
)).run()

result.push_to_hub("your-org/aya-qa", export_file="sft_alpaca.jsonl")   # private by default; needs [hf]
```

- **Tiny Aya** (e.g. [`CohereLabs/tiny-aya-global`](https://huggingface.co/CohereLabs/tiny-aya-global)) is **gated** on the Hugging Face Hub: request access on the model page and log in with `hf auth login` before serving it with route 3. It is not in the Ollama library.
- Aya Vision served through route 3 needs a chat template that accepts list-type `content`; CuratorKIT sends text only.
- Small judges often fail to return JSON. A failed judge call or an unparseable score **rejects** the sample (`judge_error:<type>` in `rejected.jsonl`). Set `judge_on_error="pass"` to keep such samples instead.

## What it generates

| `generation_task` | Output task type | Use for |
|-------------------|-----------------|---------|
| `qa` | `instruction_following` | SFT on question-answering |
| `preference` | `preference` | DPO training |
| `grpo` | `grpo` | GRPO training |
| `multiturn` | `conversational` | Multi-turn SFT |
| `evol` | `instruction_following` | Harder instruction variants |
| `cot` | `instruction_following` | Chain-of-thought reasoning |
| `adversarial_preference` | `preference` | Robustness DPO |
| `adversarial_qa` | `instruction_following` | Hallucination stress-test data |

## Output files

| File | Always written | Contents |
|------|:-------------:|---------|
| `manifest.json` | ✓ | Config hash, per-stage counts, rejection breakdown |
| `rejected.jsonl` | ✓ | All rejected samples with structured reason strings |
| `dataset_card.md` | ✓ | Human-readable run summary |
| `README.md` | ✓* | The same card with `configs:` YAML, so `load_dataset(output_dir, "<config>")` works |
| `lexsi_provenance.json` | ✓ | Library, version, inputs, and generator/judge model ids (also `manifest["provenance"]`) |
| `checksums.txt` | ✓ | SHA-256 for all output files |
| `sft_alpaca.jsonl` | optional | Alpaca-format SFT data (`instruction`, `input`, `output`) |
| `sft_sharegpt.jsonl` | optional | ShareGPT `conversations` (from/value) |
| `sft_messages.jsonl` | optional | Chat `messages` (role/content), as TRL's `SFTTrainer` expects |
| `dpo.jsonl` | optional | DPO preference pairs |
| `grpo.jsonl` | optional | GRPO group rollouts |
| `ppo.jsonl` | optional | PPO prompt-only format |
| `diagnostic_summary.json` | optional | Failure mode counts, recovery rate (when probe active) |

\* An existing `README.md` that CuratorKIT did not write is left untouched (with a warning), and `write_hf_readme=False` skips it. Use a dedicated `output_dir` to get a loadable folder.

## Handing off to AlignTune / SafeTune / AuditKIT

Pass the output folder and a config name; no conversion step. Use `output_split={"train": 0.9, "validation": 0.1}` to get a validation split.

```python
# AlignTune (Track 1): SFT on the chat messages, or DPO on the preference pairs
from aligntune.core.backend_factory import create_sft_trainer
create_sft_trainer(model_name="CohereLabs/aya-expanse-8b", dataset_name="output/", config_name="sft_messages", backend="trl").train()
```

```python
# SafeTune (Track 2): the curated set is the fine-tuning data for a harden method
from datasets import load_dataset
from safetune.runner import harden
harden.SafeGradTrainer(model, tokenizer).train(load_dataset("output/", "sft_messages", split="train"), safety_dataset=safety_dataset)
```

```python
# AuditKIT: evaluate on the held-out split
from auditkit.loaders import load_hf
samples = load_hf("output/", name="sft_alpaca", split="validation", input_col="instruction", target_col="output")
```

Each library records `lexsi_provenance.json` from this folder in its own outputs, so the lineage follows the model through the track.

## Documentation

Full documentation lives at **[lexsi-labs.github.io/CuratorKIT](https://lexsi-labs.github.io/CuratorKIT/)**.

| Section | Contents |
|---------|----------|
| [Getting started](docs/getting-started/index.md) | Installation, quickstart, reading the output |
| [Guides](docs/guides/index.md) | Data sources, generation, quality gates, recovery, hygiene, exporters, customisation |
| [Configuration reference](docs/reference/configuration.md) | Every `CuratorConfig` parameter |
| [CLI & YAML](docs/reference/cli.md) | `curatorkit run`, all flags, the YAML pipeline schema |
| [API reference](https://lexsi-labs.github.io/CuratorKIT/reference/api/) | Generated from the source docstrings |
| [Architecture](docs/reference/architecture.md) | Base classes, contracts, provenance model |

## Tutorials

Nine runnable notebooks cover the feature set end-to-end. 

| # | Notebook | Links |
|---|----------|-------|
| 01 | Generate an SFT dataset from a PDF | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1GqY-OoCz9WdyyUD6Qt9bCFI84bAFb52T?usp=sharing) |
| 02 | Generate DPO preference pairs | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1stGK2iPHUn_MM8xPtA9IlMifENSotXwH?usp=sharing) |
| 03 | Generate GRPO rollouts | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1U0XcubWNl7397PYx3cFpGxd7NIg2Kioz?usp=sharing) |
| 04 | Ingest multiple sources | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1SPG3mGHRVME1TrXM3Y1As6y_Tj3VjQSX?usp=sharing) |
| 05 | Clean and deduplicate a dataset | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1JmF5MaE5cutvTB3LkwGlrr5nBc_c1dc3?usp=sharing) |
| 06 | Adaptive recovery | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1OYGOUUWqH_HzgimTHq9R11eg6pyNjWs_?usp=sharing) |
| 07 | Adversarial generation | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1DSWNeHPI3elIL9Ts9U8s7DfFffTrPhoo?usp=sharing) |
| 08 | Data hygiene pipeline | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1HSXAKGSdXTPSw4CNN269Qj5N6ca0H89R?usp=sharing) |
| 09 | Filtered vs unfiltered fine-tuning | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1sJ_LL-f4VbVGMol2F-Y3XppIvnU1JXUB?usp=sharing) |

Full descriptions and prerequisites are in the [tutorials index](https://lexsi-labs.github.io/CuratorKIT/tutorials/).

## Contributing

The connector, generator, gate, and exporter layers are designed as plugin points. Read the [contributing guide](CONTRIBUTING.md) and the [architecture reference](docs/reference/architecture.md), then open an issue or PR. Questions go to [GitHub Issues](https://github.com/Lexsi-Labs/CuratorKIT/issues).

## Support

- **Documentation**: [lexsi-labs.github.io/CuratorKIT](https://lexsi-labs.github.io/CuratorKIT/)
- **GitHub Issues**: [github.com/Lexsi-Labs/CuratorKIT/issues](https://github.com/Lexsi-Labs/CuratorKIT/issues)
- **Email**: [pratinav.seth@lexsi.ai](mailto:pratinav.seth@lexsi.ai)

## Citation

If you use CuratorKIT in your research, please cite it (see [`CITATION.cff`](CITATION.cff)):

```bibtex
@software{curatorkit2026,
  author    = {Bhattacharjee, Soham and Sharma, Karun and Sankarapu, Vinay Kumar and Seth, Pratinav},
  title     = {CuratorKIT: Data Curation and Synthetic Data Generation for LLM Post-Training},
  year      = {2026},
  publisher = {Lexsi Labs},
  url       = {https://github.com/Lexsi-Labs/CuratorKIT}
}

@misc{bhattacharjee2026curatorkitdatacuration,
      title={CuratorKIT : Data Curation and Synthetic Data Generation for LLM Post-Training}, 
      author={Soham Bhattacharjee and Karun Sharma and Vinay Kumar Sankarapu and Pratinav Seth},
      year={2026},
      eprint={2606.21631},
      archivePrefix={arXiv},
      primaryClass={cs.CL},
      url={https://arxiv.org/abs/2606.21631}, 
}

@misc{bhattacharjee2026provenancegroundedgatingadaptiverecovery,
      title={Provenance-Grounded Gating and Adaptive Recovery in Synthetic Post-Training Data Curation}, 
      author={Soham Bhattacharjee and Karun Sharma and Vinay Kumar Sankarapu and Pratinav Seth},
      year={2026},
      eprint={2606.11127},
      archivePrefix={arXiv},
      primaryClass={cs.CL},
      url={https://arxiv.org/abs/2606.11127}, 
}
```

## License

LSAL v1.1; see [LICENSE](LICENSE.md). Free for research, education, and non-commercial use. Commercial use requires a separate license — contact support@lexsi.ai. The optional `pdf` extra installs [MinerU](https://github.com/opendatalab/MinerU), which is licensed AGPL-3.0. Install it only if that suits your use.

---

## Contact

<div align="center">
  <a href="https://www.lexsi.ai">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="docs/assets/lexsi-logo-white.png">
      <img src="docs/assets/lexsi-logo-dark.png" width="300" alt="Lexsi Labs">
    </picture>
  </a>
  <p><a href="https://www.lexsi.ai">https://www.lexsi.ai</a></p>
  <p>Paris 🇫🇷 · Mumbai 🇮🇳 · London 🇬🇧</p>
</div>

## Ecosystem

CuratorKIT is part of the Lexsi Labs open-source stack:

- **[AlignTune](https://github.com/Lexsi-Labs/aligntune)** fine-tunes with the data you curate here. CuratorKIT's Alpaca, DPO, GRPO, and PPO exports are AlignTune's native input formats.
- **[TabTune](https://github.com/Lexsi-Labs/TabTune)** is a unified library for tabular foundation models.
- **[DLBacktrace](https://github.com/Lexsi-Labs/DLBacktrace)** and **[xai_evals](https://github.com/Lexsi-Labs/xai_evals)** cover model interpretability and explanation evaluation.

