Dictify models can describe validated command inputs for human users, scripts, and AI agents.

Model subclasses expose an inspectable keyword constructor signature, so tools that use inspect.signature() can discover model fields. This makes Dictify models work well with CLI libraries such as Cyclopts.

Why this matters

Modern AI agents often call tools through CLI commands. A Dictify model lets you keep one schema for:

  • validated Python construction
  • JSON-like mapping validation
  • CLI argument binding
  • AI-agent tool input validation
from typing import Annotated

from dictify import Field, Model


class CreateUser(Model):
    name: Annotated[str, Field(required=True)]
    email: Annotated[str, Field(required=True).match(r".+@.+")]

The same model accepts Python keyword input and mapping input:

CreateUser(name="Ada", email="ada@example.com")
CreateUser({"name": "Ada", "email": "ada@example.com"})

Inspectable signatures

Tools can inspect a model class and discover its fields.

import inspect

assert str(inspect.signature(CreateUser)) == "(*, name: str, email: str, _strict: bool = True)"

Required fields appear without defaults. Fields with Field(default=...) expose that default in the signature. _strict remains the Dictify constructor option for controlling unknown keys and attributes.

Cyclopts example

Use a Dictify model as a structured CLI parameter.

from typing import Annotated

from cyclopts import App
from dictify import Field, Model


class CreateUser(Model):
    name: Annotated[str, Field(required=True)]
    email: Annotated[str, Field(required=True).match(r".+@.+")]


app = App()


@app.default
def main(user: CreateUser):
    print(user.name)
    print(user.email)


app()

Run it with nested options:

python app.py --user.name Ada --user.email ada@example.com

Cyclopts constructs CreateUser(name="Ada", email="ada@example.com"), and Dictify validates assignments through the model fields.