Avoiding Hyperparameter Hell 🔥
params-proto v3 is a declarative hyperparameter management library for machine learning. Write your parameters once with type hints and inline comments to get automatic CLI parsing, help generation, and declarative parameter sweeps with explicit error messages.
- Automatically parse type hints and inline comments into a CLI program
- Your IDE will provide autocompletion and type checking for your parameters
- As simple as a class namespace or a function, progressively build up to more complex programs.
- Multiple override patterns: CLI, direct assignment, context managers, and yaml config files.
Here is a quick example: first install params-proto using uv or pip
Using with Claude Code? Install the params-proto plugin for better AI assistance:
Now you can convert this function into a CLI program:
Running python train_mnist.py --help gives you colorized output in the terminal:
What is Parameter Hell 🔥? (and Other Anti-Patterns)
When is the last time you spent hours tracking down a config variable, jumping through layers of class inheritance and runtime values? Only to find out that the value you were looking for was never set?
Good code should be self-explanatory and statically resolvable. You should be able
to take a look at the code and understand what value the parameter will take.
A common anti-pattern that appears everywhere is to nest config classes, and pass
a single config object to the constructure of the top-level class. This makes it
difficult to connect config flags with where and how it is used. Take a look
at the example below:
-
Nested Config Classes Without Type Hint: A common anti-pattern is to nest config classes, and pass a single
configobject to the constructor of the top-level class.This tends to make it impossible to understand what parameter is used where.
Single-Source-Of-Truth HyperParameter Management with params-proto
For a simple MNIST example we can define the training parameters by the
function signature of def train(lr: float...):, and def eval(batch_size: int...):.
And for the overall training run parameters, we can have those defined by the entrypoint
function def main(seed: int...):
This way, your IDE can provide definition/usage intellisense, and you can easily see what parameters are used where. The idea is to co-locate parameters with their usages throughout the codebase.
When is Centralized Configuration Useful?
It is helpful when we only need to look at one place to override default values, for
example at the beginning of your training run. params-proto does so by keeping track
of all configuration parameters in a single place. So to automatically override
parameters, you can simply run
- Track what parameters exist
- Get IDE autocompletion and type checking
- Change parameters from the command line
- Maintain parameter documentation
params-proto solves this by providing a declarative way to define parameters that integrates seamlessly with Python IDEs and command-line interfaces.
Override parameters from the command line:
Composing Configs from Multiple Locations
Use @proto.prefix to organize configuration across multiple namespaces:
Running python train_rl.py --help shows grouped options:
Override any parameter:
Environment Variables
Read configuration from environment variables with type-safe defaults:
The pipe operator (|) provides clean syntax for fallback values:
Environment variables are resolved at decoration time and automatically converted to the annotated type (int, float, bool, str).
See Environment Variables Guide for comprehensive documentation including template expansion, security considerations, and common patterns.
Learn More
The Quick Start covers the basics. For deeper understanding, see:
- Core Concepts - The three main decorators (@proto, @proto.cli, @proto.prefix)
- Configuration Patterns - Functions vs classes, when to use each
Building CLIs (related guides for creating command-line interfaces):
-
CLI Fundamentals - Basic CLI features and type display
-
CLI Patterns - Advanced patterns like grouped options and custom program names
-
Naming Conventions - How Python names convert to CLI arguments
-
Help Generation - Automatic help text from comments and docstrings
-
Type System - Complete type hints reference and type validation
-
Union Types: Subcommands - Union types as subcommands, optional parameters, and multi-way dispatching
-
Environment Variables - Configuration from environment with EnvVar
-
Parameter Overrides - CLI, context managers, and other override methods
-
Advanced Patterns: Prefixes & Composition - Global singleton configs with @proto.prefix, namespaced parameters, and complex composition
-
Hyperparameter Sweeps - Declarative parameter sweeps with Sweep
-
Parameter Iteration - Lightweight, composable sweeps with
piter @ {...}syntax -
ANSI Formatting - Terminal colors and formatting
Documentation Contents
- Quick Start
- Migration
- Release Notes
- Welcome
- Core Concepts
- Configuration Patterns
- CLI Fundamentals
- CLI Patterns
- Naming Conventions
- Help Generation
- Type System
- Union Types: Subcommands
- Environment Variables
- Parameter Overrides
- Advanced Patterns: Prefixes & Composition
- Hyperparameter Sweeps
- Parameter Iteration
- ANSI Formatting
- Basic Usage
- Ml Training
- Rl Agent
- Cli Applications
- Proto
Why v3?
params-proto v3 is a complete redesign focused on simplicity, that maximally takes
advantage of Python's new type hint system. This new API is in fact quite similar to
params-proto v1, but at that time when I developed v1 (back in 2018), the python
type hint system was still in its infancy. v2 was a rewrite from v1 that introduced
the params_proto.hyper module, that allowed us to create and load hyperparameter
sweeps.
v2 simply returns us to that, but with a modern, polished, and unified API for both decorator-based cli programs and the same powerful parameter sweeps.
| Feature | v1 | v2 | v3 |
|---|---|---|---|
| API Style | Decorators | Class inheritance | Decorators |
| Type Hints | Not available | Optional | Required |
| Inline Docs | Manual | Manual | Automatic |
| Functions | Full support | Not supported | Full support |
| Union Types | Not supported | Limited | Full support |
| IDE Support | Basic | Basic | Excellent |
See the Migration Guide for upgrading from v2.
GitHub Repository
The source code is available on GitHub.