5.0 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build & Development Commands
# Install in dev mode (editable + test deps)
pip install -e ".[dev]"
# Run all tests
pytest tests/ -v --tb=short
# Run a single test file
pytest tests/test_config.py -v
# Run a single test
pytest tests/test_data.py::test_detect_alpaca_format -v
# Lint
ruff check soup_cli/ tests/
# Lint with auto-fix
ruff check --fix soup_cli/ tests/
Architecture
Soup is a CLI-first tool for LLM fine-tuning. The core flow:
soup train --config soup.yaml
→ config/loader.py (YAML → Pydantic SoupConfig)
→ utils/gpu.py (detect CUDA/MPS/CPU, estimate batch size)
→ data/loader.py (load file or HF dataset → normalize format)
→ trainer/sft.py (load model → quantize → apply LoRA → train)
→ monitoring/callback.py + display.py (live Rich dashboard)
→ experiment/tracker.py (log run + metrics to SQLite)
→ save LoRA adapter to output/
Config system: config/schema.py is the single source of truth. All YAML fields are validated by Pydantic models (SoupConfig → TrainingConfig → LoraConfig, DataConfig). Templates (chat/code/medical) live as YAML strings in this file.
Data pipeline: data/loader.py handles local files (JSONL/JSON/CSV/Parquet) and HuggingFace datasets. data/formats.py auto-detects and normalizes alpaca/sharegpt/chatml formats into a unified {"messages": [...]} structure. Also supports reverse conversion via messages_to_format().
Trainer: trainer/sft.py (SFTTrainerWrapper) and trainer/dpo.py (DPOTrainerWrapper) wrap HuggingFace's SFTTrainer/DPOTrainer with auto quantization (BitsAndBytes), LoRA (PEFT), and batch size estimation. Heavy ML imports are lazy (inside methods) so CLI stays fast for non-training commands.
Monitoring: monitoring/callback.py is a HuggingFace TrainerCallback that streams metrics to monitoring/display.py (Rich Live panel at 2Hz) and optionally to the experiment tracker.
Experiment tracking: experiment/tracker.py (ExperimentTracker) stores runs, per-step metrics, and eval results in SQLite at ~/.soup/experiments.db. Automatically integrated into soup train. Commands: soup runs, soup runs show, soup runs compare, soup runs delete.
Data tools: commands/data.py provides inspect, validate, convert (between alpaca/sharegpt/chatml), merge, dedup (MinHash via datasketch), and stats (extended statistics with plotext histograms).
Eval: commands/eval.py wraps lm-evaluation-harness for model evaluation on standard benchmarks (mmlu, gsm8k, etc.) with results saved to the experiment tracker.
Code Conventions
- Line length: 100 chars (ruff enforced)
- Linter: ruff with E, F, I, N, W rules
- Config validation: Always Pydantic v2 (BaseModel + Field)
- CLI framework: Typer with
rich_markup_mode="rich" - Output: Use
rich.console.Console— never bareprint() - Lazy imports: Heavy deps (torch, transformers, peft, datasketch, lm_eval, plotext) are imported inside functions, not at module level
- Variable naming: Avoid single-letter names (ruff E741) — use
entry,part,lengthinstead ofl - Testing: Rich Panel objects must be rendered via
Console(file=StringIO())for string assertions, notstr(panel)
Git Workflow
- Repo: https://github.com/MakazhanAlpamys/Soup
- Branch:
main - CI: GitHub Actions runs ruff lint + pytest on Python 3.9/3.11/3.12
- Always run
ruff check soup_cli/ tests/before committing - Always run
pytest tests/ -vbefore committing
Publishing
- PyPI: https://pypi.org/project/soup-cli/ —
pip install soup-cli - Auto-publish:
.github/workflows/publish.ymltriggers ongit tag v* - How to release: bump version in
pyproject.toml, thengit tag v0.X.0 && git push --tags - Auth: PyPI Trusted Publisher (OIDC) — no tokens needed in GitHub secrets
Tests
Test suite (~147 tests) lives in tests/:
| File | Covers |
|---|---|
test_config.py |
Config loading, validation, defaults |
test_data.py |
Format detection, conversion, validation |
test_gpu.py |
GPU detection, batch size estimation |
test_cli.py |
CLI commands basic validation |
test_tracker.py |
SQLite experiment tracker |
test_runs.py |
soup runs CLI commands |
test_data_tools.py |
Data convert/merge/dedup/stats commands |
test_eval.py |
Eval command |
test_smoke_train.py |
Full pipeline smoke tests (GPU) |
test_chat.py |
Chat command, _detect_base_model |
test_push.py |
Push command, _format_size, _generate_model_card |
test_init.py |
Init command, templates, overwrite logic |
test_callback.py |
SoupTrainerCallback (mock-based) |
test_display.py |
TrainingDisplay rendering |
test_loader.py |
Data loading (JSONL/JSON/CSV, edge cases) |
test_validator.py |
validate_and_stats, extended_stats, _percentile |
test_formats.py |
Reverse conversion, round-trips, edge cases |