ᗣᗣ Milo
August 4, 2026 · View on GitHub

One typed Python function becomes a human CLI command, an MCP tool, and an agent-readable discovery entry. (evidence: one-definition-three-surfaces)
Milo keeps the interfaces for people, Python, and AI agents tied to one command contract. Define the types, defaults, constraints, and docstring once; Milo derives argparse, JSON Schema, MCP dispatch, and llms.txt without a second adapter layer.
Get started · Read the docs · Compare with Typer + FastMCP
Prove It in 60 Seconds
With uv installed, paste this into a clean
directory. uv downloads Python 3.14 and Milo when needed:
uvx --python 3.14 --from milo-cli milo new hello_milo
uv run --python 3.14 --with milo-cli python hello_milo/app.py greet --name World
uv run --python 3.14 --with milo-cli milo verify hello_milo/app.py
The command prints Hello, World!. The ten-check verifier
(evidence: verify-ten-check-conformance) exercises
import, schema generation, MCP discovery, MCP Apps conformance, gateway
projection, and a real subprocess JSON-RPC handshake. Do not register a new
tool until it reports zero failures.
Give Claude Code the same file as a local stdio MCP server:
claude mcp add --transport stdio hello_milo -- \
uv run --python 3.14 --with milo-cli python "$PWD/hello_milo/app.py" --mcp
Now the terminal and the agent call the same function.
What is Milo?
Milo is a pure-Python framework for capabilities that must stay aligned across human and agent interfaces. One command definition owns CLI + MCP + llms.txt, including parsing, generated schema, validation, discovery, dispatch, and structured results.
from milo import CLI
cli = CLI(name="greet", description="Say hello", version="1.0")
@cli.command("greet", description="Return a greeting")
def greet(name: str, loud: bool = False) -> str:
"""Greet someone by name.
Args:
name: The person to greet.
loud: If true, SHOUT.
"""
message = f"Hello, {name}!"
return message.upper() if loud else message
if __name__ == "__main__":
cli.run()
That definition becomes:
| Surface | Milo derives |
|---|---|
| Human CLI | argparse command, help, flags, exit behavior, and terminal rendering |
| Python | direct typed dispatch through invoke(), call(), and call_raw() |
| MCP | truthful inputSchema, validation, tool metadata, and JSON-RPC dispatch |
| Discovery | llms.txt and MCP tools/list from the same registered command |
Why Milo
- One contract, not synchronized wrappers. A renamed option or tighter constraint cannot quietly update the CLI while leaving the MCP tool behind.
- Verification is part of the product.
milo verify app.pychecks the assembled application, not just an isolated schema. - Humans and agents get appropriate presentation. A person can receive a confirmation flow or terminal UI while an agent receives structured input, progress, errors, and results.
- Types stay auditable. Standard annotations,
Annotated[...]constraints, defaults, and docstrings are the schema source—without another model layer. - Terminal applications are first-class. Immutable state, pure reducers, Kida views, forms, flows, commands, and sagas support interactive tools when a single command needs a richer human experience.
- Free-threading ready. Milo is tested with
PYTHON_GIL=0on Python 3.14t. (evidence: free-threaded-runtime) - One runtime dependency. Milo depends only on
kida-templates; there is no Click, Rich, Pydantic, curses, or compiled runtime layer. (evidence: one-runtime-dependency)
Use Milo For
- Internal or developer CLIs that agents should discover and call safely.
- Dual-mode commands: interactive for people, structured over MCP for agents.
- Tool gateways that collect several local CLIs behind one agent connection.
- Wizards, installers, forms, and multi-screen terminal workflows.
- Commands that stream progress or expose resources and MCP Apps UI metadata.
- Refactorable command suites that need schema, direct-dispatch, and protocol parity tests.
If MCP itself is the product—including hosted transports, clients, auth, and deployment—start with FastMCP. If only the polished human CLI matters, Typer may be the stronger fit. Choose Milo when drift between the human and agent surfaces is the problem you want the framework to own.
Migrating an established framework or developer CLI? The mature-CLI adoption guide covers compatibility inventory, phased cutover, and exact-version downstream proof.
Interactive Terminal Apps
Milo also supplies an Elm-style runtime for commands that need more than line output:
from milo import Action, App
def reducer(state, action: Action):
if state is None:
return {"count": 0}
if action.type == "INCREMENT":
return {"count": state["count"] + 1}
return state
app = App(template="counter.kida", reducer=reducer, initial_state=None)
State remains explicit, reducers remain pure, effects move through Cmd or
sagas, and Kida templates own presentation. See
Build Apps for forms,
flows, input, live rendering, cleanup, and testing.
Examples
Start with examples/greet, then use the
examples/README.md map for run commands and copy paths.
| Example | What it demonstrates |
|---|---|
| greet | Smallest CLI + MCP + llms.txt definition |
| deploy | Flagship dual-mode command with progress and confirmation |
| mcp_app | MCP Apps UI resource with structured fallback |
| ctxdemo | Context injection, output, progress, and confirmation |
| groups | Nested command groups |
| lazyapp | Deferred imports for fast startup |
| devtool | Production CLI with before_command/after_command, completions, and doctor |
| taskman | @cli.command, @cli.resource, llms.txt, and MCP |
| outputgallery | Terminal reports and diagnostics |
| configapp | TOML configuration and profiles |
| pluggable | Hooks, listeners, and plugins |
| buildpipe | Dependency-aware pipelines and retries |
| counter | Smallest reducer-driven terminal app |
| todo | Modal input and derived filtering |
| stopwatch | Tick-driven animation |
| filepicker | Viewports and saga I/O |
| wizard | Forms and multi-screen flows |
| fetcher | Generator-based side effects |
| downloader | Parallel work, delays, and timeouts |
| spinner | Bubbletea-style Cmd thunks |
| liverender | Live rendering outside an App |
For a recording-ready demonstration of hooks, CLI, MCP, TUI, and MCP Apps in one scenario, run the Waypoint showcase.
Explore
- Agent quickstart: from typed function to verified Claude MCP tool.
- Testing guide: schema, direct dispatch, MCP dispatch, verifier, rendering, and free-threading proof.
- Build CLIs: commands, groups, context, output, MCP, gateway, help, and llms.txt.
- Build Apps: state, reducers, templates, forms, flows, effects, input, and live rendering.
- Quality: verification, testing, debugging, and pipelines.
- Reference: schema, dispatch, error codes, actions, and public types.
Status
Milo is pre-1.0. The core commitment is stable: one typed definition owns its
human CLI, Python dispatch, MCP tool, and agent discovery contract. Public
claims are classified in public-claims.json; pending
claims stay out of product copy until their evidence lands.
See the release notes for current changes and migration guidance.
Development
git clone https://github.com/lbliii/milo-cli.git
cd milo-cli
uv sync --group dev --python 3.14t
make ci
make docs-test
See CONTRIBUTING.md for repository setup, proof, changelog, and pull-request expectations. Report vulnerabilities through SECURITY.md, not a public issue.
Python Components Ecosystem
Milo is the terminal and agent-tooling layer in a personal, pure-Python stack built for Python 3.14t.
| Project | Role | |
|---|---|---|
| ⌁⌁ | Chirp | Web framework |
| =^..^= | Pounce | ASGI server |
| )彡 | Kida | Server-side component system |
| ∿∿ | Purr | Content runtime |
| ᓚᘏᗢ | Bengal | Static-site integration |
| ฅᨐฅ | Patitas | Markdown parser |
| ⌾⌾⌾ | Rosettes | Syntax highlighter |
| ᗣᗣ | Milo | CLI and agent-tooling framework ← You are here |
License
MIT License — see LICENSE.