fastapi/typer
Typer, build great CLIs. Easy to code. Based on Python type hints.
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1d ago
- ✓5 active contributors
- ✓Distributed ownership (top contributor 49% of recent commits)
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/fastapi/typer)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/fastapi/typer on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: fastapi/typer
Generated by RepoPilot · 2026-05-07 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/fastapi/typer shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 1d ago
- 5 active contributors
- Distributed ownership (top contributor 49% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live fastapi/typer
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/fastapi/typer.
What it runs against: a local clone of fastapi/typer — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in fastapi/typer | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of fastapi/typer. If you don't
# have one yet, run these first:
#
# git clone https://github.com/fastapi/typer.git
# cd typer
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of fastapi/typer and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "fastapi/typer(\\.git)?\\b" \\
&& ok "origin remote is fastapi/typer" \\
|| miss "origin remote is not fastapi/typer (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "typer/main.py" \\
&& ok "typer/main.py" \\
|| miss "missing critical file: typer/main.py"
test -f "typer/models.py" \\
&& ok "typer/models.py" \\
|| miss "missing critical file: typer/models.py"
test -f "typer/runner.py" \\
&& ok "typer/runner.py" \\
|| miss "missing critical file: typer/runner.py"
test -f "typer/utils.py" \\
&& ok "typer/utils.py" \\
|| miss "missing critical file: typer/utils.py"
test -f "pyproject.toml" \\
&& ok "pyproject.toml" \\
|| miss "missing critical file: pyproject.toml"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/fastapi/typer"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Typer is a Python library for building command-line interface (CLI) applications using Python type hints, automatically generating argument parsing, help text, and shell completion. It's the CLI equivalent of FastAPI—declarative, minimal boilerplate, and leveraging standard Python typing (via typing module) to define CLI arguments, options, and subcommands without manual argparse setup. Monorepo structure: main library code in typer/ (Python 675k LOC), docs in docs/ (Markdown with MkDocs), tests likely in tests/ (inferred), GitHub workflows in .github/workflows/, and shell scripts in root. Core abstraction: Typer wraps Click library, parsing Python function signatures via typing introspection.
👥Who it's for
Python developers building CLI tools who want intuitive syntax with IDE autocomplete support, and end-users of those CLIs who benefit from auto-generated help and shell completions. Also useful for DevOps/SRE engineers writing infrastructure scripts that need to feel polished without extra effort.
🌱Maturity & risk
Actively maintained and production-ready. The repo shows consistent CI/CD workflows (test.yml, publish.yml, deploy-docs.yml), comprehensive GitHub automation (labeler, dependabot), and documentation hosted at typer.tiangolo.com. Part of the fastapi org (high-quality standard), with regular releases via GitHub Actions publish workflow.
Low risk for active adoption. Single primary author (Sebastián Ramírez) implies potential single-point-of-failure for major decisions, but the org structure (fastapi/) and test infrastructure (test.yml workflow) suggest institutional support. Dependency footprint is minimal (mainly Click for underlying CLI parsing). Watch for breaking changes in major versions, but semver appears respected.
Active areas of work
Active development with automated workflows: pre-commit checks, nightly CPython tests, doc deployment on changes, and automated releases. Dependabot integration suggests continuous dependency updates. Issue/PR triage is automated via labeler.yml and issue-manager.yml workflows, indicating responsive maintainers.
🚀Get running
git clone https://github.com/fastapi/typer.git
cd typer
python -m venv venv
source venv/bin/activate
pip install -e .
pip install -r requirements.txt # if present, or check .github/workflows/test.yml for install steps
typer --help
Daily commands:
# Run CLI help
typer --help
# For development, use pre-commit hooks (defined in .pre-commit-config.yaml)
pre-commit run --all-files
# Run tests (inferred from test.yml workflow)
pytest
# Build docs locally (see build-docs.yml workflow)
cd docs && mkdocs serve
🗺️Map of the codebase
typer/main.py— Core Typer class that orchestrates CLI creation, command registration, and type hint processing—the primary entry point for all CLI applications.typer/models.py— Defines parameter models (Argument, Option) and their metadata that drive type inference and CLI behavior throughout the framework.typer/runner.py— Bridges Typer's type-driven model to Click's callback system, executing command functions with resolved parameters and error handling.typer/utils.py— Utility functions for type annotation parsing, Click group/command generation, and parameter introspection that power framework mechanics.pyproject.toml— Project metadata, dependencies (Click, typing-extensions), and build configuration that defines Typer's runtime environment.README.md— Entry point documenting Typer's value proposition, use cases, and links to comprehensive tutorial and API documentation.docs/tutorial/index.md— Master index to the tutorial hierarchy guiding developers through CLI fundamentals, commands, options, and advanced patterns.
🧩Components & responsibilities
- Typer (main.py) (Python, Click groups/commands) — Orchestrates app lifecycle: registers commands, stores callbacks, manages command groups, invokes Click CLI.
- Failure mode: Incorrect command routing, missing subcommands, or callback execution order errors break CLI structure.
- Parameter Models (models.py) (Python dataclasses, type hints) — Encapsulates metadata for CLI parameters: type, default, help, validation rules, environment variable bindings.
- Failure mode: Malformed parameter metadata (conflicting defaults, invalid types) causes Click to reject or misparse arguments.
- Type Inference (utils.py, types.py) (inspect module, typing, type guards) — Introspects function signatures and type hints to auto-generate Click parameters without explicit Click API calls.
- Failure mode: Unsupported type hints or complex generic types fall back to string input, breaking type safety.
- Runner (runner.py) (Click callbacks, Python introspection) — Bridges Typer's model layer and Click's callback system: resolves parameters, calls user functions, handles exceptions.
- Failure mode: Incorrect parameter resolution or exception handling leaks Click errors instead of user-friendly messages.
- Click Integration (Click library) — External framework providing argument parsing, group/command nesting, help generation, and shell completion infrastructure.
- Failure mode: Click upgrades or incompat
🛠️How to make changes
Add a new CLI command to an existing app
- Open your Typer app instance (e.g., app = typer.Typer()) (
docs/tutorial/commands/index.md) - Add a new function with @app.command() decorator and type-annotated parameters (
docs/tutorial/first-steps.md) - Use typer.Option() or typer.Argument() to customize parameter behavior (help text, prompts, validation) (
docs/tutorial/options/index.md) - Call app() at module level or use if name == 'main': app() to invoke (
docs/tutorial/first-steps.md)
Add multi-value options or arguments
- Define parameter with type hint: List[str] or tuple[str, ...] (
docs/tutorial/multiple-values/options-with-multiple-values.md) - Wrap with typer.Option() or typer.Argument() and set multiple=True if needed (
docs/tutorial/multiple-values/arguments-with-multiple-values.md) - Access the parameter as a sequence in your function body (
docs/tutorial/multiple-values/index.md)
Handle environment variables in CLI parameters
- Wrap parameter with typer.Option(envvar='ENV_VAR_NAME') (
docs/tutorial/arguments/envvar.md) - Typer/Click will automatically check environment before prompting or requiring the argument (
docs/environment-variables.md) - Set default or make required to control fallback behavior (
docs/tutorial/arguments/optional.md)
Create a callback or middleware for command chains
- Define a function and decorate with @app.callback() (
docs/tutorial/commands/callback.md) - Use typer.Context to pass state or config to subcommands (
docs/tutorial/commands/context.md) - Access context in subcommands via ctx: typer.Context parameter (
docs/reference/context.md)
🔧Why these technologies
- Click — Battle-tested CLI framework providing argument/option parsing, command groups, help generation, and cross-platform compatibility; Typer adds type-driven ergonomics on top.
- Python type hints (typing module, typing-extensions) — Core mechanism for inferring parameter types, validation rules, and help text without boilerplate; enables IDE autocompletion and static type checking.
- Pydantic (optional integration) — Used in advanced examples and extensions for complex type validation and serialization beyond standard Click converters.
⚖️Trade-offs already made
-
Typer wraps Click rather than reimplementing argument parsing
- Why: Reusing Click's maturity avoids reinventing cross-platform shell completion, help formatting, and argument parsing edge cases.
- Consequence: Typer exposes some Click internals (e.g., typer.Context wraps click.Context); tightly coupled to Click's versioning and API.
-
Type hints are the primary mechanism for parameter definition (no separate configuration DSL)
- Why: Single source of truth: type hints serve documentation, IDE completion, and parameter inference simultaneously.
- Consequence: Complex parameter logic (conditional defaults, dynamic help) requires custom typer.Option/typer.Argument calls; less declarative than YAML-based CLIs.
-
Callback-first command composition (vs. decorator nesting)
- Why: Matches Click's group/command model and allows middleware-like behaviors (e.g., setup/teardown in callbacks).
- Consequence: Callback order and context plumbing can be non-obvious for multi-level subcommand apps; state mutation risks.
🚫Non-goals (don't propose these)
- Does not handle distributed CLI orchestration or remote command execution.
- Does not provide built-in shell-native syntax (e.g., does not parse bash/zsh/fish syntax directly—only exec argument lists).
- Not a REPL or interactive shell framework; designed for one-shot command invocation.
- Does not manage secret/credential injection natively; relies on environment variables or OS-level secret stores.
🪤Traps & gotchas
No environment variables or services required for basic development. Watch for: (1) Click version compatibility—Typer wraps Click, so breaking Click updates may require Typer patches; (2) Python version coverage—test.yml shows specific supported versions, test locally on your target version; (3) Type-hint parsing edge cases—complex Union types or forward references may not infer correctly; (4) Shell completion scripts differ by shell (bash/zsh/fish)—test on your target shell.
🏗️Architecture
💡Concepts to learn
- Type-hint introspection — Core mechanism: Typer inspects Python function signatures via the
typingmodule to auto-generate CLI arguments, defaults, help text, and validation without manual argparse boilerplate - Decorator-based command registration — Typer's API uses decorators (@app.command(), @app.group()) to declaratively compose CLI structure, mirroring Flask/FastAPI patterns for familiarity
- Click command abstraction — Typer is a thin wrapper over Click; understanding Click's Command, Group, and Context objects helps when you need low-level control or debugging
- Shell completion generation — Typer auto-generates completion scripts for bash/zsh/fish; this requires understanding how shells parse completion metadata (e.g., compgen, _complete functions)
- Dependency injection in CLIs — Like FastAPI, Typer supports injecting dependencies (e.g., configuration, services) into command functions via Typer's dependency system, enabling testable, modular CLIs
- Subcommand hierarchies — Typer's group/command nesting allows arbitrarily deep CLI trees (e.g.,
tool db migrate up); understanding group composition is key for complex multi-tool CLIs - Annotated type metadata — Typer leverages Python's
Annotated[Type, metadata](PEP 593) to attach rich CLI hints (help text, validation constraints) directly to type hints, reducing boilerplate
🔗Related repos
fastapi/fastapi— Sibling project by same author; shares design philosophy (type-hint-driven, minimal boilerplate), Typer is FastAPI for CLIspallets/click— Underlying library Typer wraps; understanding Click's groups, callbacks, and context is essential for advanced Typer usagegoogle/python-fire— Alternative CLI-from-code library; simpler but less structured than Typer, good for comparison of design trade-offsencode/starlette— FastAPI's foundation; many patterns (dependency injection, middleware) inform Typer's architecturepydantic/pydantic— Data validation library likely used or compatible with Typer for argument/option validation and serialization
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive integration tests for file argument handling
The docs reference docs/reference/file_objects.md which suggests file handling is a documented feature, but there's no visible test suite specifically for file operations. This is critical for CLI tools since file I/O is a common use case. New contributors could add tests covering different file modes, error handling, and type validation.
- [ ] Review
docs/reference/file_objects.mdto understand documented file parameter behaviors - [ ] Check
tests/directory for existing file-related tests to avoid duplication - [ ] Create
tests/test_file_arguments.pywith test cases for: binary/text modes, file existence validation, permission errors, and type hints - [ ] Add parametrized tests for different file object types (Path, File, etc.)
- [ ] Run existing test suite to ensure no regressions
Complete missing documentation for context parameter patterns
docs/reference/context.md exists but the tutorial structure in docs/tutorial/arguments/ appears incomplete (only default.md is shown). Context handling is an advanced feature that needs practical examples. This PR would add tutorial pages showing real-world context usage patterns for new CLI developers.
- [ ] Review
docs/reference/context.mdcurrent content - [ ] Check existing
docs/tutorial/arguments/structure and naming conventions - [ ] Create
docs/tutorial/arguments/context.mdwith examples of: accessing context, nested command contexts, and passing state between commands - [ ] Add cross-references from
docs/tutorial/app-dir.mdto new context tutorial - [ ] Build docs locally with
mkdocs serveto verify rendering and links
Add type-checking validation tests for environment variables feature
docs/environment-variables.md is documented but corresponding test coverage is unclear. Type hints are central to Typer's value proposition, so validating that environment variable parameters maintain type safety is important. This PR would add tests ensuring type coercion and validation work correctly for env vars.
- [ ] Review
docs/environment-variables.mdto understand all supported env var patterns - [ ] Create
tests/test_environment_variables_typing.pywith tests for: type coercion (str→int, str→bool), optional env vars, env var with type hints validation, and error handling for invalid types - [ ] Add tests for edge cases: missing env vars with defaults, nested type hints (List, Dict), custom type validation
- [ ] Verify tests pass against Python versions listed in
.python-versionand CI workflows - [ ] Check for any related tests in existing test files to ensure no duplication
🌿Good first issues
- Add explicit type-hint validation tests for edge cases (Union types, Optional with defaults, Literal enums) in
tests/to improve robustness of signature introspection - Expand documentation under
docs/with a dedicated 'Type Hints Best Practices' guide, covering common patterns likeAnnotated[]for richer metadata and how Typer interprets them - Create a standalone example CLI app (e.g.,
examples/todo_app.py) with full test coverage to serve as a template for new users and CI reference
⭐Top contributors
Click to expand
- @github-actions[bot] — 49 commits
- @dependabot[bot] — 39 commits
- @YuriiMotov — 5 commits
- @tiangolo — 4 commits
- @svlandeg — 3 commits
📝Recent commits
Click to expand
250bd77— 📝 Update release notes (github-actions[bot])612a635— 👷 Add pre-commit for typos (#1730) (tiangolo)b21f9b4— 📝 Update release notes (github-actions[bot])a8a1d6c— ⬆ Bump ty from 0.0.33 to 0.0.34 (#1729) (dependabot[bot])da88cb5— 📝 Update release notes (github-actions[bot])3f7fb59— ⬆ Bump ty from 0.0.32 to 0.0.33 (#1724) (dependabot[bot])cfcc2ef— 🔖 Release version 0.25.1 (tiangolo)13846cc— 📝 Update release notes (github-actions[bot])a437469— 🔧 Add Typer Library Skill for Agents (#1620) (svlandeg)ba6cc2c— 📝 Update release notes (github-actions[bot])
🔒Security observations
Typer demonstrates a reasonable security posture with established security reporting procedures and automated CI/CD workflows. However, there are areas for improvement: (1) The security policy documentation is incomplete and should be finalized, (2) Dependency management should be actively monitored (dependabot is configured which is positive), (3) The .env file presence should be verified to not contain secrets. The project follows good practices with GitHub workflows for testing, but comprehensive analysis of actual source code and dependencies would be needed for a complete assessment. The presence of security.md and structured vulnerability reporting indicates security awareness by the maintainers.
- Medium · Incomplete Security Policy Documentation —
SECURITY.md. The SECURITY.md file appears to be incomplete - the last sentence regarding public discussions is cut off mid-sentence ('It's better to discuss privately and try to...'). This could lead to confusion about the security reporting process and may deter responsible disclosure. Fix: Complete the security policy documentation with clear, comprehensive guidance on vulnerability disclosure procedures. Ensure the policy is complete and well-formatted before publishing. - Low · Potential Sensitive File (.env) in Repository —
.env. A .env file is listed in the repository structure. If this file contains actual secrets, credentials, or sensitive configuration, it represents a security risk. The .env file should typically be in .gitignore to prevent accidental commits of sensitive data. Fix: Verify that .env is properly listed in .gitignore. Never commit actual secrets to the repository. Use environment variables for sensitive configuration in production. Document expected environment variables in a .env.example file instead. - Low · Dependency Visibility Limited —
pyproject.toml / setup.py / requirements.txt. The dependency/package file content was not provided in the analysis context. Without visibility into dependencies, it's impossible to identify outdated, vulnerable, or malicious packages that the project relies on. Fix: Implement automated dependency scanning using tools like dependabot (already present in workflows), pip-audit, or Safety. Regularly review and update dependencies. Pin versions appropriately in production. - Low · Security Email Exposure —
SECURITY.md. The security contact email (security@tiangolo.com) is publicly displayed in the SECURITY.md file. While this is intentional for reporting vulnerabilities, it could potentially be targeted for abuse or phishing. Fix: This is a necessary exposure for security reporting. Implement appropriate email filtering and monitoring on the security contact mailbox. Consider using a dedicated security response team or mailing list.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.