前言¶
Python 項目裏常見的一套工具鏈是這樣的:pip 裝依賴,virtualenv 管環境,flake8 做檢查,black 做格式化,isort 排 import,mypy 做類型檢查,pre-commit 再把這些鉤到 Git 上。配置往往散落在 requirements.txt、setup.py、.flake8、mypy.ini 裏,Agent 寫代碼時還經常隨手執行 pip install,或者手動 source .venv/bin/activate。
Astral 這一側已經把包管理、檢查、格式化收成了 uv、ruff,類型檢查也有同門的 ty。問題是:人可以按文檔慢慢遷,Agent 默認仍可能沿用舊命令。Trail of Bits 把內部模板 cookiecutter-python 裏的選擇,寫成了 Agent Skill modern-python,用來約束新項目怎麼建、舊項目怎麼遷、單文件腳本怎麼聲明依賴。
這是什麼¶
modern-python 是 Trail of Bits 在 trailofbits/skills 市場裏發佈的一條 Skill,插件作者署名爲 William Tan。官方描述是:用 uv、ruff、ty 配置 Python 項目;在創建項目、寫帶依賴的獨立腳本,或從 pip / Poetry / mypy / black 遷移時使用。
它基於通用的 SKILL.md 格式,因此在 Claude Code、Codex CLI、Cursor 這類支持 Agent Skill 的工具裏都可以加載。倉庫把它歸在 Development 一類,和安全審計類 Skill 放在同一個 marketplace 裏。實踐規範來自 Trail of Bits 自己的 cookiecutter 模板,不是另一套平行標準。
Skill 明確寫了不適用的情況:用戶要求保留舊工具鏈時不要強行替換;需要 Python 3.11 以下時不要用這套工具;Python 不是主語言的混合倉庫也不要套上去。
核心工具¶
Skill 把推薦工具和被替換的舊工具列成了一張表,交叉對照 GitHub 上的 SKILL.md 與官方文檔後,內容一致:
| 工具 | 作用 | 替換對象 |
|---|---|---|
| uv | 包與依賴管理 | pip、virtualenv、pip-tools、pipx、pyenv |
| ruff | 檢查和格式化 | flake8、black、isort、pyupgrade、pydocstyle |
| ty | 類型檢查 | mypy、pyright |
| pytest | 測試與覆蓋率 | unittest |
| prek | Git hooks | pre-commit |
ty 來自 Astral(與 uv、ruff 同一團隊)。Astral 官方文檔把它定位爲用 Rust 寫的類型檢查器,當前仍處於 beta,Skill 仍推薦用它替代 mypy / pyright。實際落地時要把這點算進風險:規則和診斷在小版本之間仍可能變。
prek 是 j178/prek,Rust 實現、單二進制、兼容已有的 .pre-commit-config.yaml。Skill 把它寫成比 pre-commit 更快、且不依賴 Python 運行時的替代。
除開發工具外,Skill 還附帶一組安全相關能力,主要跑在 pre-commit 或 CI 裏:
| 工具 | 作用 | 運行時機 |
|---|---|---|
| shellcheck | Shell 腳本檢查 | pre-commit |
| detect-secrets | 密鑰檢測 | pre-commit |
| actionlint | GitHub Actions 語法校驗 | pre-commit、CI |
| zizmor | Workflow 安全審計 | pre-commit、CI |
| pip-audit | 依賴漏洞掃描 | CI、手工 |
| Dependabot | 依賴自動更新 | 定時 |
作爲 Claude Code 插件安裝時,倉庫還帶了一個 SessionStart hook:給 python、pip、pipx、uv 加上 PATH shim。Agent 直接跑 python 或 pip install 會被攔截,並提示改成 uv run / uv add 這類命令。grep python、which python 不受影響,因爲這時 python 只是參數,不是被執行的命令。只把 SKILL.md 拷進 Skill 目錄時,不一定帶上這個 hook,以實際安裝方式爲準。
幾條硬性約定¶
Skill 把常見反模式寫成了對照表,寫作時代理應優先按「右側」執行:
| 不要這樣做 | 改用 |
|---|---|
[tool.ty] 裏寫 python-version |
[tool.ty.environment] 下的 python-version |
uv pip install |
uv add 和 uv sync |
手工改 pyproject.toml 加依賴 |
uv add / uv remove |
hatchling 作爲 build backend |
uv_build(多數項目夠用) |
| Poetry | uv |
requirements.txt |
腳本用 PEP 723,項目用 pyproject.toml |
| mypy / pyright | ty |
用 [project.optional-dependencies] 裝開發工具 |
[dependency-groups](PEP 735) |
source .venv/bin/activate |
uv run |
| pre-commit | prek |
三條原則在文檔裏反覆出現:依賴只通過 uv add / uv remove 管理;命令一律 uv run,不要手工激活虛擬環境;開發/測試/文檔依賴放進 [dependency-groups],不要放進給用戶安裝的 extras。
安裝與啓用¶
Claude Code¶
官方 marketplace 安裝分兩步。先加入 Trail of Bits 的插件市場:
/plugin marketplace add trailofbits/skills
再安裝 modern-python 插件:
/plugin install trailofbits/skills/plugins/modern-python
也可以先執行 /plugin menu 瀏覽後再裝。官方 Quick Start 裏給出的調用示例是:
Use the modern-python skill to create a new Python project with uv, ruff, and pytest
Codex CLI¶
倉庫 README 寫明 Codex 可以直接加載 Claude 的 marketplace,不需要額外的 sidecar 元數據:
codex plugin marketplace add trailofbits/skills
codex plugin list
codex plugin add modern-python@trailofbits
最後一條裏的插件名與倉庫中 plugins/modern-python 目錄名一致。
通用 Skill 安裝(Cursor 等)¶
skills.sh 上的安裝命令是:
npx skills add https://github.com/trailofbits/skills --skill modern-python
這條命令按 Agent Skills 的通用目錄約定把 SKILL.md 裝進當前工具使用的 skills 路徑。裝好後,直接描述任務即可,例如「按 modern-python 給這個倉庫配 uv 和 ruff」,或「把現有 pip + requirements.txt 遷到 uv」。
典型用法¶
Skill 用一棵決策樹區分四類工作:單文件腳本走 PEP 723;不打算分發的多文件項目走最小 uv 配置;可複用的包走完整項目配置;已有倉庫走遷移指南。
1. 最小項目¶
不打算發佈到 PyPI 的多文件項目,官方 Quick Start 如下:
uv init myproject
cd myproject
uv add requests rich
uv add --group dev pytest ruff ty
uv run python src/myproject/main.py
uv run pytest
uv run ruff check .
依賴進 pyproject.toml 和 uv.lock,一次性試用某個包則用 uv run --with,不要寫進項目依賴:
uv run --with requests python -c "import requests; print(requests.get('https://httpbin.org/ip').json())"
uv run --with httpx pytest
2. 完整包項目¶
從零開始時,Skill 會先問是否用 Trail of Bits 的 cookiecutter 一次生成完整腳手架(含 pyproject.toml、src/ 佈局、依賴組、hooks、GitHub Actions 和安全掃描):
uvx cookiecutter gh:trailofbits/cookiecutter-python
不用模板時,用 uv 創建可分發的包:
uv init --package myproject
cd myproject
生成的目錄結構是:
myproject/
├── pyproject.toml
├── README.md
├── src/
│ └── myproject/
│ └── __init__.py
└── .python-version
SKILL.md 裏給出的關鍵配置如下。依賴組不要手工改,用 uv add --group 維護:
[project]
name = "myproject"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = []
[dependency-groups]
dev = [{include-group = "lint"}, {include-group = "test"}, {include-group = "audit"}]
lint = ["ruff", "ty"]
test = ["pytest", "pytest-cov"]
audit = ["pip-audit"]
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["ALL"]
ignore = ["D", "COM812", "ISC001"]
[tool.pytest]
addopts = ["--cov=myproject", "--cov-fail-under=80"]
[tool.ty.terminal]
error-on-warning = true
[tool.ty.environment]
python-version = "3.11"
[tool.ty.rules]
possibly-unresolved-reference = "error"
unused-ignore-comment = "warn"
安裝依賴:
uv sync --all-groups
# 或只裝某一組
uv sync --group dev
Skill 還建議在倉庫裏放一個 Makefile,把日常命令收口到 uv run:
.PHONY: dev lint format test build
dev:
uv sync --all-groups
lint:
uv run ruff format --check && uv run ruff check && uv run ty check src/
format:
uv run ruff format .
test:
uv run pytest
build:
uv build
3. 單文件腳本:PEP 723¶
只有一個文件、但又需要第三方庫時,不要再配一份 requirements.txt。Skill 的參考文檔要求把元數據寫進腳本註釋,用 uv run 執行:
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests",
# "rich",
# ]
# ///
import requests
from rich import print
response = requests.get("https://httpbin.org/ip")
print(response.json())
uv run script.py
也可以用 uv 維護腳本依賴:
uv init --script myscript.py
uv add --script myscript.py requests
uv remove --script myscript.py requests
官方參考也寫了限制:PEP 723 沒有 dependency groups、不能 editable install、沒有 lockfile,多次運行時解析到的版本可能不同。需要這些能力時改用完整的 pyproject.toml。
4. 從舊工具鏈遷移¶
用戶明確要求遷移時,Skill 才走這條路徑;用戶要留 pip / Poetry / mypy 時,文檔要求尊重現有流程。
從 requirements.txt + pip 遷到 uv:
uv init --bare
# 逐個添加,不要直接改 pyproject.toml
uv add requests rich
# 或從 requirements.txt 導入(複雜版本約束可能要手工處理)
grep -v '^#' requirements.txt | grep -v '^-' | grep -v '^\s*$' | while read -r pkg; do
uv add "$pkg" || echo "Failed to add: $pkg"
done
uv sync
隨後刪除 requirements.txt、requirements-dev.txt 和舊虛擬環境(venv/、.venv/),並把 uv.lock 納入版本控制。
從 setup.py / setup.cfg 遷移時:先 uv init --bare,把 install_requires 用 uv add 搬進去,開發依賴用 uv add --group dev,再把名稱、版本、描述等元數據拷到 [project],最後刪除 setup.py、setup.cfg、MANIFEST.in。
從 flake8 + black + isort 遷到 ruff:
uv remove flake8 black isort
# 刪除 .flake8,以及 pyproject.toml 裏的 [tool.black]、[tool.isort]
uv add --group dev ruff
uv run ruff format .
uv run ruff check --fix .
從 mypy / pyright 遷到 ty:
uv remove mypy pyright
# 刪除 mypy.ini、pyrightconfig.json,以及 [tool.mypy] / [tool.pyright]
uv add --group dev ty
uv run ty check src/
描述裏提到可以從 Poetry 遷到 uv,但 SKILL.md 的遷移章節沒有單獨列出 Poetry 的逐步命令,只在反模式表裏把 Poetry 標成應替換爲 uv。遇到 Poetry 項目時,應按倉庫裏的 references/migration-checklist.md 覈對,不要把 pip 那套步驟直接套上去。
適用場景與注意事項¶
適合用這條 Skill 的情況包括:新建 Python 包或內部項目;給已有倉庫補 pyproject.toml、lint、測試;寫帶第三方依賴的單文件腳本;用戶明確要求從 pip / flake8 / black / mypy 遷走。
不適合的情況文檔寫得很直接:必須支持 Python 3.11 以下;用戶明確要留 Poetry、mypy、black;Python 只是倉庫裏的配角。
使用時還有幾處需要留意:
- 最低版本是 3.11。
requires-python = ">=3.11"和 ruff 的target-version = "py311"是配套的,不能只改其中一個。 - ty 仍是 beta。 Skill 把它當作默認類型檢查器,但 Astral 自己說明 API 與診斷都還不穩定。對類型檢查結果很敏感的倉庫,遷移前要先在分支上跑一遍
uv run ty check src/,看誤報是否可接受。 - 覆蓋率門檻默認 80%。 舊項目第一次接 pytest-cov 時,這個數字很容易把 CI 打紅,需要按倉庫現狀調整,而不是原樣粘貼。
ruff的select = ["ALL"]很嚴。 官方配置用ignore關掉了D(pydocstyle)、COM812、ISC001,其餘規則都開。接到老代碼上會有大量告警,需要按模塊逐步收緊,而不是指望一次--fix全部乾淨。- 插件 hook 只在插件安裝路徑下生效。 Claude Code / Codex 按 marketplace 安裝時會攔截裸
python/pip;僅同步SKILL.md時,Agent 仍可能寫出舊命令,提示詞裏最好寫明「不要用 pip,用 uv add / uv run」。 - 參考文檔比 SKILL.md 更細。 同目錄下還有
pyproject.md、uv-commands.md、ruff-config.md、testing.md、pep723-scripts.md、prek.md、security-setup.md、dependabot.md、migration-checklist.md。做完整遷移或安全掃描時,應讓 Agent 繼續讀這些文件,而不是隻靠 SKILL 正文裏的摘要。
小結¶
modern-python 做的事情很具體:把 Trail of Bits cookiecutter 模板裏已經在用的工具鏈(uv、ruff、ty、pytest、prek)寫成 Agent 可執行的規範,並附帶從 pip / setup.py / flake8 / mypy 遷過來的步驟。它解決的不是「Python 該不該現代化」,而是 Agent 默認仍會 pip install、手工改 pyproject.toml、激活虛擬環境這一類操作。
官方地址:
- Skill 目錄:https://github.com/trailofbits/skills/tree/main/plugins/modern-python/skills/modern-python
- 插件說明:https://github.com/trailofbits/skills/tree/main/plugins/modern-python
- 文檔站:https://trailofbits-skills.mintlify.app/plugins/modern-python
- skills.sh:https://skills.sh/trailofbits/skills/modern-python
- 模板倉庫:https://github.com/trailofbits/cookiecutter-python