[TERMINAL · SKILLS]
> mounting /skills...
> indexing skill manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Use Cases/Adopt Python Type Checking in CI with ty

Adopt Python Type Checking in CI with ty

Add a fast type checker to an existing untyped Python service and make CI block new type errors without forcing the team to fix hundreds of old ones first.

Development#python#type-checking#language-server#astral#static-analysis
Works with:claude-codeopenai-codexgemini-clicursor
agent@terminalskills — playground
full playground →

Try this use case on your own files

simulated preview
$
$

real run in an isolated sandbox · files auto-deleted after 7 days · nothing touches your machine

Skills stack · 4 skills

Avg quality 95/100·All SAFE
>

ty

v1.0.0

Checks Python code for type errors with ty, Astral's fast type checker and language server written in Rust. Use when a user asks to type check a Python project, add ty to pyproject.toml or CI, silence or baseline existing type errors, set up a type-checking language server in VS Code, Neovim, Zed or PyCharm, or move from mypy or pyright. Covers ty check, configuration, rule levels, ignore comments and output formats.

100/100 quality
8.50× impact
SAFE
View skill
>

uv

v1.0.0

Installs Python packages, creates virtual environments, locks dependencies and manages Python versions with one fast command-line tool that replaces pip, pip-tools, pipx, poetry, pyenv and virtualenv. Use when a user asks to set up a Python project, add or upgrade a dependency, create a lockfile, migrate from requirements.txt, run a script with inline dependencies, install a Python version, run a tool with uvx, or speed up installs in CI and Docker.

87/100 quality
6.38× impact
SAFE· stale score
View skill
>

ruff

v1.1.0

Lint and format Python with Ruff. Use when a user asks to set up Python linting, replace flake8/black/isort, configure code quality rules, or speed up Python code formatting.

93/100 quality
1.13× impact
SAFE· stale score
View skill
>

github-actions

v1.1.0

GitHub Actions runs CI/CD pipelines defined as YAML workflows inside a GitHub repository. Use when someone asks to "set up CI", "add a GitHub Actions workflow", "run tests on every pull request", "cache dependencies", "build a matrix", "deploy from Actions", "push a Docker image to ghcr.io" or "reuse a workflow", or needs triggers, secrets, environments, artifacts and permissions explained.

100/100 quality
2.66× impact
SAFE· stale score
View skill
$

The Problem

Mei Tanaka maintains billing-service, a 14,000-line FastAPI service that grew without a type checker. Twice this quarter a production error came from a value that could be None: a lookup helper returned Customer | None and a caller used .email on it. Code review did not catch either one. She wants type errors found before merge, but she has seen what happens when a strict checker is switched on in an old code base: 300 failures, a red CI for two weeks, and the team turns the job off.

The Solution

Add ty, Astral's Python type checker, as a pinned dev dependency. Run it once to see the real size of the problem, write an ignore comment on every existing error so the baseline passes, and then run it in CI with annotations on pull requests. From then on, new code must be type-clean and old errors are visible, countable debt. uv manages the dependency, Ruff stays the linter and formatter, and GitHub Actions runs the check.

Step-by-Step Walkthrough

1. Install ty as a dev dependency and look at the damage

The prompt to the agent: "Add ty to billing-service and tell me how many type errors we have today, grouped by rule."

bash
cd billing-service
uv add --dev ty
uv run ty --version
uv run ty check --exit-zero --output-format concise > /tmp/ty-before.txt
tail -1 /tmp/ty-before.txt
grep -o "error\[[a-z-]*\]" /tmp/ty-before.txt | sort | uniq -c | sort -rn

The agent reports the total (for this service, 312 diagnostics) and the top rules, for example 140 unresolved-attribute, 90 invalid-argument-type and 40 invalid-assignment. --exit-zero keeps the command from failing while the team is only measuring. If ty reports unresolved-import for packages that are installed, the agent reruns with --python .venv before trusting the numbers.

2. Configure the project

The prompt: "Set ty up for Python 3.12, skip generated code, and relax the rules for tests."

The agent edits pyproject.toml:

toml
[tool.ty.environment]
python-version = "3.12"
root = ["./src"]

[tool.ty.src]
exclude = ["src/billing/generated/"]

[tool.ty.rules]
unused-ignore-comment = "warn"

[[tool.ty.overrides]]
include = ["tests/**"]

[tool.ty.overrides.rules]
invalid-argument-type = "ignore"

It then runs uv run ty check again and confirms the count dropped by the excluded and relaxed files.

3. Baseline the existing errors

The prompt: "Make the check pass today without changing behavior, so only new errors fail."

bash
uv run ty check --add-ignore
uv run ty check
git diff --stat

ty writes a # ty: ignore[rule-name] comment on every line that currently fails and then prints All checks passed!. The agent opens the diff, confirms that only comments were added, and runs the test suite to be sure nothing else changed:

bash
uv run pytest -q
uv run ruff check src

4. Add the CI job

The prompt: "Run ty on every pull request and show errors as annotations."

The agent creates .github/workflows/typecheck.yml:

yaml
name: typecheck
on:
  pull_request:
  push:
    branches: [main]
jobs:
  ty:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v6
      - run: uv sync --dev
      - run: uv run ty check --output-format github

A pull request that reintroduces the original bug now fails with an annotation on the exact line, for example unresolved-attribute: Attribute 'email' is not defined on 'None' in union 'Customer | None'.

5. Burn the baseline down by rule

The prompt: "Fix the 40 invalid-assignment ignores and show me what is left."

bash
grep -rn "ty: ignore\[invalid-assignment\]" src | wc -l

The agent fixes those call sites (usually a wrong annotation or a missing None check), deletes the matching comments, and reruns uv run ty check. Because unused-ignore-comment is a warning, any ignore that is no longer needed is reported, so stale comments do not pile up. Each rule gets its own small pull request.

6. Turn on the editor feedback

The prompt: "How do I get these errors in VS Code?"

The agent tells Mei to install the official ty extension, which disables the Python extension's built-in language server by default. For Neovim 0.11 or newer the agent adds vim.lsp.enable('ty') after installing nvim-lspconfig.

Real-World Example

Mei runs the first step on a Tuesday morning and sees 312 diagnostics, 140 of them unresolved-attribute, the same family as the two incidents. She does not ask the team to fix them. By lunchtime the baseline pull request is open: 312 added comments, no code changes, all 118 tests passing, and a CI job that finishes in about 6 seconds. The next day a colleague's pull request adds customer = repo.find(email) followed by customer.plan; CI fails with an annotation on that line, and the bug is fixed before review. Over the following three weeks the team removes the ignores one rule at a time and the count falls from 312 to 41.

Related Skills

  • ty — runs the type check, holds the configuration and writes the baseline ignore comments
  • uv — adds ty as a pinned dev dependency and runs it in the project environment
  • ruff — keeps linting and formatting separate from type checking
  • github-actions — runs the check on every pull request

Related use cases