Plugin System (v0.45.0)
5 parts, +169 tests. Public plugin / hook surface.
BasePlugin Protocol
from soup_cli.plugins import register_plugin
# The four hook names are fixed: pre_train, post_train, pre_step, post_step.
# Each takes one context dict and returns None. A plugin carries any
# subset of them; hooks are discovered by name, so a misspelled one is
# silently never called.
class MyTrainerPlugin:
def pre_train(self, context): ...
def post_step(self, context): ...
# Registration is what puts a plugin in the registry. Nothing is
# auto-discovered by subclassing: BasePlugin is a runtime-checkable
# Protocol, not a base class you inherit registration from.
register_plugin(
name="my-trainer", # kebab-case
version="0.1.0", # semver
plugin=MyTrainerPlugin(),
description="Example",
)soup plugins list
soup plugins enable my-trainer
soup plugins disable my-trainerRegistered plugins really run. Every transformers-backend trainer attaches them as a genuine Hugging Face TrainerCallback, so pre_train / post_train / pre_step / post_step fire against the live training loop rather than being a surface waiting to be wired. Two deliberate properties: a hook that raises is swallowed at WARNING, so one misbehaving plugin cannot kill a multi-hour run, and the hook set is snapshotted when the callback is constructed, so registering a plugin mid-run does not retroactively receive events.
One thing that is not automatic: nothing under soup_cli/plugins/ is auto-discovered at startup. A plugin exists once register_plugin(...) has been called in the process.
OpenAI ↔ Anthropic Messages converter
anthropic_messages.py converts between OpenAI and Anthropic Messages schemas — useful for trace-to-preference + serve.
Server-side tools allowlist
server_tools.py ships a server-side tools allowlist + WebSearchConfig for the inference server.
N-gram speculative decoding
ngram_spec.py schema for n-gram speculative decoding; the serve path consumes it live.
External integrations catalog
15-entry registry of known deployment and serving targets a trained model can be handed to, each with the artifact format it expects: LM Studio, ComfyUI, stable-diffusion.cpp, Open WebUI, Ollama, TEI, pgvector, FAISS, Weaviate and the rest. Not experiment trackers: W&B, MLflow, ClearML, Comet and Neptune are a separate allowlist, wired through soup train --tracker.
Advanced trainer-plugin allowlist
Closed allowlist for advanced trainer plugins.
Data Recipe DAG
recipe_dag.py parses a YAML DAG describing data preprocessing steps + dependencies. Topological sort guarantees deterministic execution order.
soup data recipe recipe.yamlValidation is the default: the path is a positional argument and there is no validate subcommand. The live per-node runner shipped in v0.53.7 behind --execute.
Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.