create-python-project-github-en — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited create-python-project-github-en (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Scaffold a complete modern Python project from mkdir to first PyPI publish.
ASCII Safety Rule - applies to all generated text, docs, code, and comments:
# -*- coding: utf-8 -*-) is NOT required in Python 3(UTF-8 is the default). Omit it unless targeting legacy tooling.
Toolchain decisions (rationale in references/toolchain-rationale.md):
| Concern | Tool |
|---|---|
| Env / dep management | uv (never pip or pipx) |
| Build backend | hatchling |
| Linter + formatter | ruff |
| Test runner | pytest |
| Type checker | mypy (opt-in, not CI-blocking) |
| CI/CD | GitHub Actions |
| PyPI release | Trusted Publishing (OIDC, no tokens) |
| Devcontainer | .devcontainer/maintainer/ |
| Supply chain audit | pip-audit==2.10.0 |
| CLI framework | typer (gives --install-completion for free) |
Before writing any file, ask the user for:
my-cool-lib).Derived Python package name = PROJECT_NAME with hyphens -> underscores.
3.12).library, cli, or both.my-tool).If already provided in the conversation, extract from context and confirm before proceeding.
Phase Check:
mkdir PROJECT_NAME
cd PROJECT_NAME
git init
git checkout -b mainCreate .gitignore - use the template in references/gitignore.md.
Phase Check:
git status shows clean repo with .gitignore present.Create LICENSE with the MIT license text:
MIT License
Copyright (c) YEAR AUTHOR_NAME
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.Phase Check:
LICENSE file exists with correct author and year.Create the src/ layout (PEP 517 best practice):
PROJECT_NAME/
+-- src/
| +-- PACKAGE_NAME/
| +-- __init__.py # contains __version__ = "0.1.0"
+-- tests/
| +-- __init__.py
| +-- test_PACKAGE_NAME.py
+-- docs/
+-- .devcontainer/
| +-- maintainer/
+-- .github/
| +-- workflows/
+-- .gitignore
+-- CHANGELOG.md
+-- LICENSE
+-- README.md
+-- pyproject.tomlFor cli/both style, also create src/PACKAGE_NAME/cli.py.
Seed src/PACKAGE_NAME/__init__.py:
"""PROJECT_DESCRIPTION"""
__version__ = "0.1.0"Seed tests/test_PACKAGE_NAME.py:
"""Basic smoke tests for PACKAGE_NAME."""
import PACKAGE_NAME
def test_version():
assert PACKAGE_NAME.__version__ == "0.1.0"Phase Check:
__init__.py contains __version__.Use the correct template from references based on packaging style:
references/pyproject-library.toml.mdreferences/pyproject-cli.toml.mdSubstitute all PROJECT_NAME, PACKAGE_NAME, GITHUB_USER, AUTHOR_NAME, AUTHOR_EMAIL, PYTHON_MIN placeholders.
Mandatory pyproject.toml fields (validate with check_pyproject_meta.py):
license with value MITauthors with name and emailkeywords (non-empty list)Programming Language :: Python :: 3.x[project.urls] with Homepage, Repository, Issues, Changeloghatchling in [build-system.requires] only - never in dependency-groupsFor CLI/both style, add typer to dependencies:
dependencies = [
"typer>=0.12",
]Type stubs: For every third-party dependency lacking inline types, add its stub to dev optional-dependencies (e.g. types-PyYAML, types-requests).
Phase Check:
uv sync runs without errors.python check_pyproject_meta.py passes all 18 tests.Python supply chain defaults - non-negotiable:
uv (never pip, never pipx) for all installs.uv lock + uv sync for reproducible installs.pyproject.toml..env files.~/.ssh.Dockerfile supply chain audit pattern (Python):
# Install tools via uv
RUN uv tool install ruff
# Audit step (pip-audit has no uv equivalent yet)
RUN pip install --no-cache-dir "pip-audit==2.10.0" \
&& pip-audit --skip-editable \
&& pip uninstall -y pip-auditPhase Check:
pyproject.toml has pinned version bounds for all dependencies..env - confirmed.Skip this phase if PACKAGING_STYLE is library.
Use Typer - it provides --install-completion for bash/zsh/fish for free.
Seed src/PACKAGE_NAME/cli.py:
"""CLI entry point for PROJECT_NAME."""
from __future__ import annotations
import typer
app = typer.Typer(help="PROJECT_DESCRIPTION")
@app.command()
def main(
version: bool = typer.Option(False, "--version", help="Show version and exit."),
) -> None:
"""Main entry point."""
if version:
import PACKAGE_NAME
typer.echo(f"PROJECT_NAME {PACKAGE_NAME.__version__}")
raise typer.Exit()
# TODO: implement commands here
typer.echo("Hello from PROJECT_NAME!")
if __name__ == "__main__":
app()After install, show the user how to enable shell completion:
# bash
CLI_COMMAND --install-completion bash
# zsh
CLI_COMMAND --install-completion zsh
# verify
CLI_COMMAND --helpPhase Check:
uv run CLI_COMMAND --help runs without errors.uv run CLI_COMMAND --install-completion bash runs without errors.uv run CLI_COMMAND --version prints the correct version.Create .devcontainer/maintainer/devcontainer.json using the template in references/devcontainer.md.
Phase Check:
.devcontainer/maintainer/devcontainer.json is valid JSON.Create .github/workflows/ci.yml using the template in references/ci-workflow.md.
Python version matrix - always include all three:
python-version: ["3.12", "3.13", "3.14"] # adjust lower bound to PYTHON_MINAdd a mandatory pip-audit job to ci.yml:
audit:
name: Supply chain audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: pip-audit
run: uv run pip-audit --skip-editableCI job order: lint -> typecheck -> audit -> test (fail fast on lint/audit before burning test matrix minutes).
Create .github/workflows/publish.yml using the template in references/publish-workflow.md.
Trusted Publishing (OIDC) requirements:
environment: name: pypipermissions: id-token: writeattestations: truePYPI_TOKEN secret needed.Create .github/workflows/set-label-triage-to-new-issue.yml:
name: Triage new issues
on:
issues:
types: [opened]
jobs:
triage:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/github-script@v7
with:
script: |
github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['triage']
})Phase Check:
3.14 as highest version.audit job present and runs before test.v* tags.environment: pypi present in publish workflow.# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.1.0] - YYYY-MM-DD
### Added
- Initial releaseRequired sections: title, description, CI/PyPI/Python/License badges, Install, Usage, Development (uv sync --all-extras, uv run ruff check ., uv run pytest), Shell completion section (CLI projects only: CLI_COMMAND --install-completion bash), License line pointing to LICENSE (MIT).
Phase Check:
CHANGELOG.md has [Unreleased] section.README.md has install instructions and CI badge.uv sync
uv run ruff check .
uv run ruff format --check .
uv run pytest
uv build
git add .
git commit -m "chore: initial project scaffold"
git remote add origin https://github.com/GITHUB_USER/PROJECT_NAME.git
git push -u origin mainThen instruct the user to configure Trusted Publishing on pypi.org:
PROJECT_NAMEGITHUB_USERPROJECT_NAMEpublish.ymlpypigit tag v0.1.0
git push origin v0.1.0Phase Check:
uv run ruff check . returns no violations.uv run ruff format --check . returns no violations.uv run pytest passes.uv build produces .whl and .tar.gz in dist/.main succeeds.When delivering a project or multi-file output, always package it as a .tar.gz archive. The archive is the canonical deliverable.
tar --exclude='.venv' \
--exclude='.git' \
--exclude='__pycache__' \
--exclude='.pytest_cache' \
--exclude='dist' \
-czf PROJECT_NAME.tar.gz PROJECT_NAME/Present the archive as the primary download. Individual files may also be shown but the archive is the canonical deliverable.
Phase Check:
.venv, .git, __pycache__, .pytest_cache, dist/.uv sync works from the extracted directory.Read these when needed - do not load all at once:
| File | When to read |
|---|---|
references/pyproject-library.toml.md | Phase 4, library style |
references/pyproject-cli.toml.md | Phase 4, cli/both style |
references/ci-workflow.md | Phase 8, CI workflow |
references/publish-workflow.md | Phase 8, publish workflow |
references/devcontainer.md | Phase 7, devcontainer |
references/gitignore.md | Phase 1, .gitignore |
references/toolchain-rationale.md | If user asks why a tool was chosen |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.