Install & Compatibility
Where this runs
tested against v0.5.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.693s · 31.6MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 3.5s · import 0.632s · 31MB
30MB installed
● package 30MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
Application
✓ from app_model import Application
Command
✓ from app_model import Command
Menu
✓ from app_model import Menu
SubMenu
✓ from app_model import SubMenu
Action
✓ from app_model.types import Action
✗ from app_model import Action
Action is part of the `types` submodule, not directly under `app_model`.
This quickstart demonstrates how to set up a basic `Application`, define and register commands using `Command` objects, associate them with menus via `Menu` enumerations, and execute commands, retrieving their results. Note the use of `.result()` to unwrap the `Future` returned by `execute` for synchronous retrieval.
from app_model import Application, Command, Menu
def say_hello(name: str = "World") -> str:
"A command that greets the provided name."
return f"Hello, {name}!"
def say_goodbye() -> str:
"A simple command to say goodbye."
return "Goodbye!"
# 1. Initialize the application
app = Application("my-first-app")
# 2. Register commands
app.register_command(Command("my-app.hello", say_hello, title="Say Hello"))
app.register_command(Command("my-app.goodbye", say_goodbye, title="Say Goodbye"))
# 3. Register a menu item for the 'hello' command
app.register_menu_item(
Menu.APP, # or Menu.FILE, Menu.EDIT, etc.
Command("my-app.hello", title="Say Hello from Menu", menu_path="File > Hello"),
)
# 4. Execute a command and get its result
hello_result = app.commands.execute("my-app.hello", {"name": "Registry"}).result()
print(f"Hello Command Result: {hello_result}")
goodbye_result = app.commands.execute("my-app.goodbye").result()
print(f"Goodbye Command Result: {goodbye_result}")
Errors
Common errors & fixes
pydantic.v1.error_wrappers.ValidationError: ...
You are likely running `app-model` with Pydantic v1.x installed, which is incompatible with recent versions of `app-model` (v0.4.0+).
fixUpgrade Pydantic to version 2.0 or newer: `pip install 'pydantic>=2'`.
AttributeError: 'Future' object has no attribute 'my_expected_attribute'
You forgot to call `.result()` on the `Future` object returned by `app.commands.execute()`, attempting to access attributes directly on the Future itself.
fixModify your command execution to retrieve the actual result: `result = app.commands.execute('my-app.command_id').result()`. app_model.types.CommandNotFoundError: Command 'unknown_id' not found
The command ID provided to `app.commands.execute()` or `app.register_menu_item()` does not correspond to any command that has been registered with the `Application` instance.
fixEnsure the command ID matches exactly one of your registered commands. Verify the ID in `app.register_command(Command('YOUR_ID', ...))` and `app.commands.execute('YOUR_ID', ...)`. Upgrade
Version history
0.5.1latest on PyPI · released Nov 9, 2025
Audit
Dependencies
pydanticrequiredCore dependency for data modeling, validation, and serialization. Requires Pydantic v2.x.