Skip to content

Getting Started

Welcome to your first steps with Sayer, the modern async CLI framework. This guide will walk you through installing Sayer, running your first command, and understanding the basics of how it works.


πŸ“¦ Installing Sayer

Sayer supports Python 3.10 and above.

Using pip:

pip install sayer
uv pip install sayer

Once installed, you’ll have everything you need to start building CLIs immediately.


πŸš€ Your First CLI

Here’s a simple Hello World app using Sayer:

# app.py
from sayer import Sayer, Option

app = Sayer()

@app.command()
def hello(name: str = Option(..., help="Your name")):
    """Says hello to the given name."""
    print(f"Hello, {name}!")

if __name__ == "__main__":
    app()

Run it like so:

python app.py hello --name Ada

πŸ” What just happened?

  • @app.command() turns a function into a CLI command.
  • Option(...) declares a named parameter.
  • app() runs the CLI parser.

This already provides help text, argument validation, and a beautifully formatted CLI!

Try:

python app.py --help
python app.py hello --help

🧠 Under the Hood

Sayer creates a full CLI parser under the hood, powered by click + async + a metadata-rich decorator system.

When you call app(), it:

  1. Parses the CLI args.
  2. Resolves the command.
  3. Maps inputs to the function signature.
  4. Runs any middleware.
  5. Executes the function (sync or async).

πŸ§ͺ Going Async

Want to use async def in your commands? No problem:

@app.command()
async def ping():
    """Asynchronous command"""
    print("Pong!")

It runs just like the sync version:

python app.py ping

You can even await async database calls, HTTP requests, etc.


πŸ—‚οΈ Project Layout Tips

You can put all commands in a single file or split them across modules. Example structure:

mycli/
β”œβ”€β”€ main.py
β”œβ”€β”€ commands/
β”‚   β”œβ”€β”€ greet.py
β”‚   └── utils.py

Then import them in your app:

# main.py
from sayer import Sayer
from commands import greet, utils

app = Sayer()

# commands auto-register from decorators

if __name__ == "__main__":
    app()

🧰 Recap

  • βœ… Install Sayer with pip or uv
  • βœ… Create a Sayer app with Sayer()
  • βœ… Use @app.command() to define CLI functions
  • βœ… Run via python app.py or sayer script
  • βœ… Add parameters using Option, Argument, or Env

Next, let’s build more complex commands!

πŸ‘‰ Defining Commands