
Python Pep Author
- 67 installs
- 191 repo stars
- Updated July 24, 2026
- pproenca/dot-skills
python-pep-author is a Claude Code skill for security. It helps solo builders move faster with AI-assisted coding.
Key points
- python-pep-author
- Security
- AI-coding skill
Python Pep Author by the numbers
- 67 all-time installs (skills.sh)
- +5 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #1,189 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pproenca/dot-skills --skill python-pep-authorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 67 |
|---|---|
| repo stars | ★ 191 |
| Last updated | July 24, 2026 |
| Repository | pproenca/dot-skills ↗ |
How do I helps with security tasks during ai-assisted development?
Helps with security tasks during AI-assisted development.
Who is it for?
Best when you're working on security and need structured help with python-pep-author.
Skip if: Teams with no security needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with security tasks during ai-assisted development, or when python-pep-author is a claude code skill for security. it helps solo builders move faster with ai-assisted coding.
What you get
Structured output aligned to python-pep-author: python-pep-author; Security; AI-coding skill.
Files
Write a Python Enhancement Proposal (PEP)
A PEP is the design document the Python community uses to propose a new language feature, a stdlib change, an interoperability standard, or a process/informational guideline. This skill takes an author from a rough idea to a correctly-formatted, process-compliant draft ready for submission to the python/peps repository.
The hard parts of a PEP are not the prose — they are getting the type right, the header preamble valid, the sections complete to the acceptance bar, and following the process (vetting, sponsorship, review). This skill bundles two scripts for the deterministic parts and reference docs for the judgement calls.
When to Apply
- The user asks to write / draft / structure a PEP or a "Python Enhancement Proposal".
- The user wants to propose a Python language or standard-library feature and needs it written up formally.
- The user has an idea they've been discussing on the Python Discourse and wants to turn it into a PEP draft.
- The user needs the PEP template, header fields, or section structure explained or generated.
- The user is revising an existing PEP (changing status, adding a Resolution, addressing review feedback).
Do not use this skill for internal company RFCs / design docs (use dev-rfc) — a PEP is specifically a proposal to the upstream CPython / Python community governed by PEP 1.
Prerequisites
- Bash + coreutils (
awk,sed,grep,date) for the two scripts — present by default on macOS/Linux. - A clone of, or a fork of, github.com/python/peps only when you're ready to submit (Step 6). Drafting needs no repo.
- No Python runtime is required to draft or lint; the reference implementation (if any) is the author's separate codebase.
Workflow Overview
1. Vet the idea ────► 2. Choose the type ────► 3. Scaffold the file
(is it PEP-able?) (Standards/Info/Process) (scripts/new-pep.sh)
│
6. Submit ◄──── 5. Self-check ◄──── 4. Draft each section
(sponsor, PR) (scripts/check-pep.sh) (to the acceptance bar)
│
▼
7. Review & resolution ──► update Status + Resolution header1. Vet the idea (before writing anything)
A PEP that duplicates prior work or isn't community-wide in scope will be rejected on sight. Post the idea to the Ideas category of the Python Discourse first (or the Typing / Packaging category if specialised). Confirm it's original, applicable to the whole community, and not already settled by a past discussion. See references/workflow.md for venues and what to check.
2. Choose the PEP type
There are exactly three: Standards Track, Informational, Process. The type determines required headers (e.g. Python-Version, Resolution) and the bar for acceptance. Pick with references/pep-types.md.
3. Scaffold the file
Generate a valid, correctly-headed reStructuredText file rather than hand-typing the preamble (the field set and ordering are exact):
scripts/new-pep.sh \
--title "A short descriptive title" \
--author "Random J. User <random@example.com>" \
--type "Standards Track" \
--python-version 3.15 # Standards Track only; omit otherwiseThis writes pep-9999.rst (9999 = placeholder; PEP editors assign the real number), sets Status: Draft and today's Created date, and enforces the 44-character title limit. Run scripts/new-pep.sh with no args for full usage.
4. Draft each section
Fill the body sections in the canonical PEP 12 order: Abstract → Motivation → Specification → Rationale → Backwards Compatibility → Security Implications → How to Teach This → Reference Implementation → Rejected Ideas → Open Issues → Acknowledgements → Footnotes → Change History → Copyright. Each section has a specific job and a quality bar — read references/sections.md before drafting, and consult references/header-fields.md for any header you need to fill in (Sponsor, Discussions-To, Requires, etc.).
The acceptance bar (from PEP 1): the proposal must be a clear and complete description, represent a net improvement, have a solid implementation that doesn't unduly complicate the interpreter, and be "pythonic". Write to that bar.
5. Self-check the draft
Lint the headers and required structure before showing it to anyone:
scripts/check-pep.sh pep-9999.rstIt verifies the required headers are present, the title length, valid Status/Type values, the Created date format, the mandatory CC0 copyright notice, and an Abstract section — reporting PASS / WARN / FAIL and exiting non-zero on any FAIL. Fix every FAIL.
6. Submit
If no co-author is a CPython core developer, you must first find a sponsor (a core developer who shepherds the PEP). Then fork python/peps, add pep-NNNN.rst, list authors/sponsors in .github/CODEOWNERS, and open a pull request. PEP editors review for format and soundness and assign the number. Full steps and the role definitions are in references/workflow.md.
7. Review & resolution
When the authors (and sponsor) judge it ready, content review and the accept/reject decision rest with the Steering Council (or an appointed PEP-Delegate). On a decision, update the Status and add a Resolution header linking to the pronouncement. The full status lifecycle and valid transitions are in references/status-lifecycle.md.
Reference Files
| File | Read it when |
|---|---|
| references/workflow.md | Vetting, finding a sponsor, submitting, the review process, the roles, transferring ownership |
| references/pep-types.md | Choosing between Standards Track / Informational / Process |
| references/header-fields.md | Filling any preamble field — formats, required vs optional, examples |
| references/status-lifecycle.md | Setting or changing Status, understanding valid transitions, the Resolution header |
| references/sections.md | Drafting the body — what each section must contain, RST conventions, the acceptance bar |
Scripts
| Script | What it does |
|---|---|
scripts/new-pep.sh | Scaffolds a valid pep-NNNN.rst from the template, substituting the header fields and enforcing the title-length limit |
scripts/check-pep.sh | Lints a PEP draft against PEP 1 / PEP 12 rules (headers, status/type, date format, copyright, abstract) |
The template the scripts use lives at assets/templates/pep-template.rst — copy it directly if you'd rather fill the headers by hand.
Gotchas
See gotchas.md. The most common early mistakes: skipping the Discourse vetting step, choosing Standards Track for what is really a Process PEP, omitting the mandatory CC0 copyright notice, and a title over 44 characters.
Related Skills
dev-rfc— internal/company RFCs, design docs, and architecture docs (not upstream Python proposals).
PEP: @@PEP@@
Title: @@TITLE@@
Author: @@AUTHOR@@
Sponsor:
PEP-Delegate:
Discussions-To:
Status: @@STATUS@@
Type: @@TYPE@@
Topic:
Requires:
Created: @@CREATED@@
Python-Version: @@PYTHON_VERSION@@
Post-History:
Replaces:
Superseded-By:
Resolution:
Abstract
========
[A short (~200 word) description of the technical issue being addressed.
A reader should be able to decide from the abstract alone whether this PEP
is relevant to them.]
Motivation
==========
[Clearly explain why the existing language specification is inadequate to
address the problem the PEP solves, or why a new informational/process
document is needed. This is critical for PEPs that want to change the
language: reviewers who do not understand the motivation will not engage.]
Specification
=============
[Describe the syntax and semantics of any new feature precisely enough to
be implemented. Be language-lawyerly: cover edge cases, error behaviour,
and interactions with existing features. New language features should
specify changes to the grammar where applicable.]
Rationale
=========
[Explain why particular design decisions were made. Describe alternate
designs that were considered and why they were rejected, and how the
proposal compares with prior art / similar features in other languages.
The rationale should provide evidence of consensus and document dissent.]
Backwards Compatibility
=======================
[Describe potential impact and severity on pre-existing code. This section
is REQUIRED for any PEP that introduces backwards incompatibilities; state
explicitly "There are no backwards compatibility concerns." if there are
none.]
Security Implications
=====================
[How could a malicious actor abuse this feature? What new attack surface,
if any, does it create? State explicitly if there are none.]
How to Teach This
=================
[How should this feature be introduced to new and experienced Python users?
What documentation, tutorials, or mental models make it learnable?]
Reference Implementation
========================
[Link to any existing implementation and describe its state (e.g.
proof-of-concept, in review). The reference implementation must be complete
before the PEP is granted "Final" status, but need not exist before the PEP
is accepted.]
Rejected Ideas
==============
[Record significant alternative ideas raised during discussion and explain
why they were not pursued. This prevents the same proposals from being
re-litigated and shows reviewers that the design space was explored.]
Open Issues
===========
[List points that are still being decided or discussed. Resolve and remove
these before requesting final review — an Accepted PEP should have no open
issues.]
Acknowledgements
================
[Optionally thank the people who contributed to the discussion and design of
this PEP.]
Footnotes
=========
[A collection of footnotes referenced elsewhere in the PEP, using the
``[#label]_`` / ``.. [#label]`` reStructuredText footnote syntax.]
Change History
==============
[Optionally summarise major revisions, newest first, each as a dated bullet
that corresponds to a Post-History entry, e.g.:
- DD-MMM-YYYY
- Sub-bullet describing what changed in this revision.]
Copyright
=========
This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.
Gotchas
Real failure points discovered while building and reviewing this skill. Newest first.
Format:
### <Short title of the failure point>
What went wrong, why, and how to avoid it.
Added: YYYY-MM-DDSpecification comes before Rationale in PEP 12
It is tempting to justify the design (Rationale) before specifying it. The canonical PEP 12 order is Abstract → Motivation → Specification → Rationale → Backwards Compatibility. Describe what you propose, then why. The template and sections.md follow this order. Added: 2026-05-21
Empty header lines can fool a naive linter
The template ships every optional field as an empty Field: line (e.g. Resolution:). A linter that checks only for the field name will report it present, giving false assurance. check-pep.sh uses a value-aware has_value() so empty scaffold lines do not satisfy the conditional checks (Resolution, Discussions-To, Python-Version). Added: 2026-05-21
date +%b is locale-sensitive
PEP 1 requires the English three-letter month in Created (e.g. 21-May-2026). Under a non-English locale (LC_TIME=fr_FR), date +%b yields mai, which is wrong and even fails check-pep.sh's own dd-mmm-yyyy regex. new-pep.sh forces LC_ALL=C on the date call. Added: 2026-05-21
Multiple authors need RFC 2822 continuation lines
A single Author: A, B line is invalid — each author goes on its own continuation line indented 8 spaces. Pass --author "A <a@x>, B <b@y>" (comma-separated); new-pep.sh splits them onto continuation lines automatically. Added: 2026-05-21
Python-Version is Standards Track only
Setting Python-Version on a Process or Informational PEP is wrong. new-pep.sh errors if --python-version is combined with a non-Standards-Track --type, and check-pep.sh warns if the header has a value on a non-Standards-Track PEP. Added: 2026-05-21
Created is the date a number is assigned, not the draft date
PEP 1 defines Created as the date the PEP was assigned a number (at editor approval), which may be later than when you scaffold the file. new-pep.sh stamps today and prints a reminder to update it if the number is assigned on a different date. Added: 2026-05-21
{
"version": "0.1.0",
"organization": "dot-skills",
"technology": "Python / PEP process",
"discipline": "composition",
"type": "automation",
"date": "May 2026",
"abstract": "Guides an author end-to-end through writing a Python Enhancement Proposal: vetting the idea, choosing the PEP type, scaffolding a valid reStructuredText pep-NNNN file, drafting each section to the acceptance bar, linting the headers against PEP 1 / PEP 12 rules, and navigating the sponsor, submission, and Steering Council review process.",
"references": [
"https://peps.python.org/pep-0001/",
"https://peps.python.org/pep-0012/"
]
}
The Header Preamble (RFC 2822 Fields)
Every PEP starts with an RFC 2822 style header block, ending at the first blank line. Fields appear in the order below. This is the most error-prone part of a PEP — scripts/check-pep.sh validates it.
Field reference
| Field | Required? | Value / format |
|---|---|---|
PEP | Required | The PEP number (unpadded, e.g. 8). Use 9999 as a placeholder until editors assign one. |
Title | Required | Short, descriptive title — maximum 44 characters. |
Author | Required | Name <email> or just Name. One author per line (RFC 2822 continuation) for multiple. |
Sponsor | Optional | The sponsoring core developer. Omit if a co-author is a core developer. |
PEP-Delegate | Optional | The individual the Steering Council appointed to decide this PEP. |
Discussions-To | Optional* | URL of the canonical discussion thread. *Expected once the PEP is past Draft. For mailing lists, link to the thread in the archives — not a bare mailto:. |
Status | Required | One of the lifecycle statuses — see status-lifecycle.md. New PEPs start at Draft. |
Type | Required | Standards Track, Informational, or Process — see pep-types.md. |
Topic | Optional | One of Governance, Packaging, Release, Typing. Sub-index tag, not the type. |
Requires | Optional | PEP number(s) this PEP depends on. |
Created | Required | Date the PEP was assigned a number, format dd-mmm-yyyy (e.g. 21-May-2026). |
Python-Version | Optional | Target release M.N (e.g. 3.15). Standards Track only. |
Post-History | Optional | Dates + URLs of Discussions-To posts, e.g. ` 21-May-2026 <URL>__ `. |
Replaces | Optional | PEP number this one renders obsolete (pairs with Superseded-By on the older PEP). |
Superseded-By | Optional | PEP number that renders this PEP obsolete. |
Resolution | Optional* | A dd-mmm-yyyy date linked (RST) to the post making the accept/reject pronouncement, e.g. ` 21-May-2026 <URL>__ `. Required for Standards Track once resolved. |
Format rules that catch people out
- `Author` format is exact:
Random J. User <random@example.com>with an email, or
Random J. User without. Multiple authors each go on their own continuation line:
Author: Random J. User <random@example.com>,
Another Person <another@example.com>- `Title` ≤ 44 characters. This is a hard limit (it has to fit the PEP index). The
scaffold and lint scripts both enforce it.
- `Created` is `dd-mmm-yyyy` with a three-letter English month:
01-Feb-2026, not
2026-02-01 and not 1-Feb-2026 without the leading zero.
- `Sponsor` vs core-dev authorship: if any author is a core developer, leave
Sponsor out entirely. Don't list a sponsor "for safety" — it signals no author has commit rights.
- `Discussions-To` must point at a specific thread, not a list's landing page, so
reviewers land on the actual conversation.
- `Replaces` / `Superseded-By` are reciprocal: when PEP B supersedes PEP A, A gets
Superseded-By: B and B gets Replaces: A. Setting only one side is inconsistent.
- `Resolution` is mandatory for resolved Standards Track PEPs. Add it together with
the Status change to Accepted / Rejected / Withdrawn.
Minimal valid Draft header (Standards Track)
PEP: 9999
Title: Add frobnication to the standard library
Author: Random J. User <random@example.com>
Status: Draft
Type: Standards Track
Created: 21-May-2026
Python-Version: 3.15scripts/new-pep.sh generates exactly this (with the full optional-field skeleton).
Choosing the PEP Type
Every PEP is exactly one of three types, set in the Type: header. The type drives which headers are required and the bar the proposal is held to. Getting this wrong is a common early mistake — a process change dressed up as a feature, or vice versa.
The three types
Standards Track
Describes a new feature or implementation for Python, or an interoperability
standard supported outside the standard library for current Python versions before
a later PEP adds stdlib support.
Use it for: new syntax, new builtins, new stdlib modules/APIs, changes to the language or interpreter, and cross-implementation standards.
Implications:
- Typically carries a `Python-Version` header (the release the feature targets).
- The `Resolution` header is required once resolved (accepted/rejected/withdrawn).
- Needs a reference implementation (complete before
Final). - Held to the full acceptance bar: clear & complete, net improvement, solid implementation, pythonic.
Informational
Describes a Python design issue, or provides general guidelines or information to the
community, but does not propose a new feature.
Use it for: design guidance, conventions, or community information where adoption is optional. Informational PEPs do not necessarily represent consensus or a recommendation — users and implementers are free to ignore them.
Implications:
- No
Python-Version, no reference implementation, no net-improvement-of-the-language bar. - May be marked Active if it is an ongoing document never meant to be "completed".
Process
Describes a process surrounding Python, or proposes a change to (or an event in) a
process. Like Standards Track PEPs, but applied to areas **other than the language
itself**.
Use it for: changes to the development workflow, decision-making, release cadence, governance, or the PEP process itself. Process PEPs require community consensus and, unlike Informational PEPs, users are typically not free to ignore them. Examples: PEP 1 (this process) and PEP 13 (governance) — both Active.
Quick decision guide
| If the proposal… | Type |
|---|---|
| Adds/changes language syntax, a builtin, or a stdlib API | Standards Track |
| Defines an interoperability standard across implementations | Standards Track |
| Offers optional guidance or information, proposes no feature | Informational |
| Changes how the project/community operates (workflow, governance, releases) | Process |
Ask: "Does this change Python the language/library, or change how the Python project operates, or is it just information?" Language/library → Standards Track. How the project operates → Process. Pure information with no mandate → Informational.
Topic (a separate axis)
The optional Topic: header is not the type. It tags a PEP into a sub-index and takes one of: Governance, Packaging, Release, Typing. A Standards Track typing PEP, for example, has Type: Standards Track and Topic: Typing.
Body Sections, RST Conventions, and the Acceptance Bar
The body follows the preamble. assets/templates/pep-template.rst has the full skeleton; this file explains what each section is for and the bar it must clear. Only the Copyright section is strictly mandatory, but a serious Standards Track PEP needs Abstract, Motivation, Rationale, Specification, and Backwards Compatibility to stand a chance. Source: PEP 12.
The acceptance bar (write to this)
From PEP 1, a PEP is accepted only if it is: 1. a clear and complete description of the enhancement, 2. a net improvement, 3. backed by a solid implementation that doesn't unduly complicate the interpreter (if applicable), and 4. "pythonic".
Every section below exists to demonstrate one of these. If a section doesn't move a reviewer toward "yes" on one of them, tighten it.
Sections
| Section | Required? | Its job |
|---|---|---|
| Abstract | Strongly recommended | ~200-word technical summary. A reader decides from this alone whether the PEP concerns them. |
| Motivation | Effectively required for Standards Track | Why the current spec/situation is inadequate. Reviewers who don't grasp the motivation won't engage — this is the section that earns attention. |
| Specification | Required for Standards Track | Syntax and semantics precise enough to implement. Be language-lawyerly: edge cases, errors, interactions with existing features, grammar changes. |
| Rationale | Recommended | Why these design decisions; what alternatives were considered and why rejected; prior art in other languages. Shows consensus and records dissent. |
| Backwards Compatibility | Required if there are incompatibilities | Impact and severity on existing code, and migration. State explicitly when there are none. |
| Security Implications | When applicable | New attack surface a malicious actor could exploit. State explicitly when there is none. |
| How to Teach This | For feature additions | How to introduce the feature to new and experienced users; docs and mental models. |
| Reference Implementation | Before Final | Link + state of the implementation. Must be complete before Final, not before acceptance. |
| Rejected Ideas | Recommended | Alternatives raised in discussion and why they were dropped — prevents re-litigation. |
| Open Issues | While unresolved | Points still being decided. Resolve and remove before final review. |
| Acknowledgements | Optional | Thank the people who contributed to the discussion and design. |
| Footnotes | As needed | Citations using RST footnote syntax. |
| Change History | Optional | Major revisions, newest first, each a dated bullet matching a Post-History entry. |
| Copyright | Mandatory | The dual public-domain / CC0 notice (verbatim below). |
Section order matters. Note thatSpecificationcomes beforeRationalein
the canonical PEP 12 template — describe what you propose, then justify why.
Mandatory copyright notice (verbatim)
Copyright
=========
This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.scripts/check-pep.sh fails the draft if the CC0-1.0-Universal notice is missing.
reStructuredText conventions
PEPs are UTF-8 reStructuredText. The conventions that matter:
- Section headers use an underline of punctuation at least as long as the title:
- First level:
=underline - Second level:
-underline - Third level:
'underline - Capitalise each word; acronyms stay all-caps. Leave two blank lines before the next section heading.
- Code / literal blocks: end the lead-in line with
::then indent the block 4
spaces, or use .. code-block:: python.
- Links: inline as `
link text <https://example.com>__`. Reference other PEPs
and RFCs with the roles :pep:\8\` and :rfc:\2822\` rather than raw URLs.
- Footnotes: cite with `
[#label]_in the text and define with`.. [#label]
content`` in the Footnotes section.
- Lists: bullets with
-/*/+; numbered with1./a.; definition lists are a
term line followed by an indented definition.
Auxiliary files
Diagrams: pep-XXXX-Y.ext (serial Y from 1) or anything inside a pep-XXXX/ subdirectory. Prefer SVG/PNG, legible in light and dark mode.
Status Lifecycle
The Status header tracks where a PEP is in its life. Setting it to a value the process doesn't allow (or skipping the Resolution header on a decision) is a common slip. Source: PEP 1.
The statuses
| Status | Meaning |
|---|---|
| Draft | Initial state of every new PEP; under discussion and revision. |
| Deferred | No progress is being made (or no PEP-Delegate is available). A PEP editor can move it back to Draft. |
| Accepted | Approved for implementation; the reference implementation is not yet complete. |
| Provisional | "Provisionally Accepted": accepted for inclusion in the reference implementation, but more user feedback is needed before Final. May still be Rejected or Withdrawn even after shipping in a release. |
| Final | The reference implementation is complete and merged into the main source repository. |
| Active | For Informational/Process PEPs that are ongoing and never meant to be "completed" (e.g. PEP 1, PEP 13). |
| Rejected | Reviewed and decided against — not a good idea. |
| Withdrawn | The author decided it's a bad idea, or accepted a competing proposal as better. |
| Superseded | Rendered obsolete by a later PEP. Carries a Superseded-By header; the newer PEP carries Replaces. |
Valid transitions
Draft ──► Deferred ──► Draft (stalled, then revived)
Draft ──► Rejected | Withdrawn
Draft ──► Accepted ──► Final
Accepted ──► Provisional ──► Final
Accepted | Provisional ──► Rejected | Withdrawn
Rejected | Withdrawn | Final | Superseded ──► Active (meta-PEPs only)Notes that trip people up:
- **
Accepted→Rejected/Withdrawnis allowed only before the change ships in a
Python release.** Once released, an accepted PEP can't be un-accepted (only Provisional PEPs can be reversed post-release).
- **A PEP-Delegate stepping down (or being asked to) overrules any prior
acceptance/rejection and reverts the PEP to Draft.**
- `Active` is reachable only for Informational/Process meta-PEPs that are living
documents.
The Resolution header on a decision
When a PEP becomes Accepted, Rejected, or Withdrawn, update the PEP accordingly: at minimum change Status and add a Resolution header with a direct link to the post making the decision (posted to the PEPs category of the Python Discourse). For Standards Track PEPs the Resolution header is mandatory; check-pep.sh flags its absence.
Reaching Final
Final requires the reference implementation to be complete and merged. A PEP can be Accepted without it, but not Final. Don't set Final while the implementation is still in review.
The PEP Process: From Idea to Resolution
The PEP process is as much about building consensus as about writing a document. The author's job is to champion the idea, document dissent fairly, and shepherd it through review. Source of truth: PEP 1.
The roles
| Role | Who | What they do |
|---|---|---|
| Author / Champion | Anyone | Writes the PEP, drives discussion, builds consensus, documents dissent. |
| Sponsor | A core developer (or a community member approved by the Steering Council) | Required only if no co-author is a core developer. Guides the author through the logistics; recorded in the Sponsor header. |
| PEP Editors | A small team, reached via @python/pep-editors on GitHub | Manage the administrative/editorial side: assign PEP numbers, check format and soundness, change statuses. They are not responsible for correctness. |
| PEP-Delegate (formerly BDFL-Delegate) | A core developer the Steering Council approves to decide a specific PEP | Has authority to approve or reject that PEP; recorded in PEP-Delegate. |
| Steering Council | The elected council (PEP 13) | Final authority on acceptance/rejection. May delegate to a PEP-Delegate. |
| Typing Council | PEP 729 | For type-system PEPs, gives the Steering Council a recommendation. |
Step 1 — Vet the idea (pre-PEP discussion)
Public vetting saves the author time: it weeds out ideas already rejected in prior discussions, confirms the idea is original, and confirms it's applicable to the whole community rather than just the author. Do this before drafting.
Post to the appropriate venue:
- Ideas category of the Python Discourse — general proposals.
- Typing category — static typing ideas.
- Packaging category — packaging ideas.
Once vetted, a draft PEP is presented to the same venue to be made well-formatted, high quality, and to address initial concerns.
Step 2 — Determine your path (core dev or not?)
- If one or more co-authors are core developers, they follow the submission steps below directly.
- Otherwise, the author(s) must find a sponsor first. A sponsor is a core developer (or SC-approved community member) who agrees to shepherd the PEP. Record them in the
Sponsorheader. PEP-editors team members and Typing Council members are pre-approved to act as sponsors.
Step 3 — Submit the PEP
1. Fork the python/peps repository. 2. Create pep-NNNN.rst, where NNNN is the next available PEP number not used by a published or in-PR PEP. 3. In the header: put the number in PEP:, set Type: to one of the three types, set Status: Draft. 4. Update .github/CODEOWNERS so any co-authors/sponsors with write access are listed for your file. 5. Push to your fork and open a pull request.
PEP editors then review for: a sound and complete idea that makes technical sense; an accurate title; correct language and code style; and valid reStructuredText (checked automatically). Approval is not a guarantee of correctness — that stays with authors and reviewers. Once approved, editors assign the PEP number.
Reasons editors may deny PEP status: duplication of effort, being technically unsound, not providing proper motivation or addressing backwards compatibility, or not being in keeping with the Python philosophy.
Core developers with write access may claim a number and commit a new PEP directly,
taking on the tasks editors would normally handle.
Step 4 — Discussion and revision
Draft PEPs are freely open for discussion and modification at the authors' discretion until submitted for review. Substantive content changes should generally be proposed first on the PEP's Discussions-To thread; copyedits and corrections can go straight to a GitHub issue or PR. Record discussion threads in Post-History.
Step 5 — Review and resolution
When the authors (and sponsor, if any) judge the PEP ready for final review, content review and acceptance become the Steering Council's responsibility, formally initiated by opening a Steering Council issue.
- Any suitably experienced core developer may offer to be the PEP-Delegate by notifying the SC (and the authors/sponsor). The SC generally approves such self-nominations by default, but may decline (e.g. conflict of interest).
- If no volunteer steps forward and no suitable candidate can be found, the PEP is marked Deferred until one is available.
- For type-system PEPs, request a recommendation from the Typing Council via its issue tracker.
Acceptance criteria (a PEP must meet all): a clear and complete description of the enhancement; the enhancement is a net improvement; the implementation (if any) is solid and does not unduly complicate the interpreter; and the proposal is "pythonic".
The reference implementation must be complete before a PEP becomes Final, but not before it is accepted. Pronouncements of resolution are posted to the PEPs category of the Python Discourse; link to that post from the Resolution header.
After resolution — modifying a PEP
Once a PEP reaches Accepted, Final, Rejected, or Superseded, it is a historical document, not a living spec, and is no longer substantially modified. Exceptions:
- Provisional (or, with SC approval, Accepted) Standards Track PEPs may be updated from implementation experience — note the changes in the PEP.
- Active (Informational/Process) PEPs may be updated over time to reflect changing practice.
Transferring PEP ownership
Sometimes a PEP needs a new champion (the original author lost time/interest or went quiet). A bad reason is disagreement with the PEP's direction. To take over: fork, make the ownership change, open a PR, and mention both the original author and @python/pep-editors. It's preferable to keep the original author as a co-author. If the original author is unresponsive, the PEP editors make a unilateral decision.
Auxiliary files
Diagrams and other support files are named pep-XXXX-Y.ext (XXXX = PEP number, Y = serial number from 1, ext = extension), or placed in a pep-XXXX/ subdirectory (no naming constraints inside it). Prefer browser-friendly formats (SVG, PNG) that are legible in both light and dark mode.
Copyright
Each new PEP must be dual-licensed: public domain and CC0-1.0-Universal. The mandatory closing notice is in sections.md.
#!/usr/bin/env bash
# check-pep.sh — Lint a PEP draft against PEP 1 / PEP 12 rules.
# Part of: python-pep-author
#
# Checks the RFC 2822 header preamble and required structure, reporting each
# check as PASS / WARN / FAIL. Exits non-zero if any check FAILs so it can gate
# a commit or PR.
set -euo pipefail
usage() {
echo "Usage: check-pep.sh <pep-file.rst>" >&2
exit "${1:-1}"
}
[[ $# -eq 1 ]] || usage
case "$1" in -h|--help) usage 0 ;; esac
FILE="$1"
[[ -f "$FILE" ]] || { echo "Error: file not found: $FILE" >&2; exit 1; }
PASS=0; WARN=0; FAIL=0
pass() { printf ' PASS %s\n' "$1"; PASS=$((PASS + 1)); }
warn() { printf ' WARN %s\n' "$1"; WARN=$((WARN + 1)); }
fail() { printf ' FAIL %s\n' "$1"; FAIL=$((FAIL + 1)); }
# --- Extract the header preamble: everything before the first blank line ---
HEADER="$(awk 'NF==0{exit} {print}' "$FILE")"
header_value() {
# $1 = field name; echoes the first value (lead text stripped), empty if absent.
printf '%s\n' "$HEADER" | sed -n "s/^$1:[[:space:]]*//p" | head -n1
}
has_value() {
# True only if the field is present AND has a non-empty value. The PEP template
# ships optional fields as empty "Field:" lines, so presence alone is not enough.
[[ -n "$(header_value "$1")" ]]
}
echo "Linting PEP: $FILE"
echo
# --- Required headers (PEP 1) — must be present AND non-empty ---
for f in PEP Title Author Status Type Created; do
if has_value "$f"; then
pass "required header present: $f"
else
fail "missing or empty required header: $f"
fi
done
# --- Title length (max 44) ---
TITLE="$(header_value Title)"
if [[ -n "$TITLE" ]]; then
if (( ${#TITLE} <= 44 )); then
pass "Title is ${#TITLE} chars (<= 44)"
else
fail "Title is ${#TITLE} chars (max 44): \"$TITLE\""
fi
fi
# --- Type is one of the three valid values ---
TYPE="$(header_value Type)"
case "$TYPE" in
"Standards Track"|"Informational"|"Process") pass "Type is valid: $TYPE" ;;
"") : ;; # already reported missing above
*) fail "Type must be 'Standards Track', 'Informational', or 'Process' (got: '$TYPE')" ;;
esac
# --- Status is a recognised value ---
STATUS="$(header_value Status)"
case "$STATUS" in
Draft|Active|Accepted|Provisional|Deferred|Rejected|Withdrawn|Final|Superseded)
pass "Status is valid: $STATUS" ;;
"") : ;;
*) fail "Status is not a recognised value (got: '$STATUS')" ;;
esac
# --- Created date format dd-mmm-yyyy ---
CREATED="$(header_value Created)"
if [[ -n "$CREATED" ]]; then
if printf '%s' "$CREATED" | grep -qE '^[0-3][0-9]-[A-Z][a-z]{2}-[0-9]{4}$'; then
pass "Created is dd-mmm-yyyy: $CREATED"
else
fail "Created must be dd-mmm-yyyy, e.g. 21-May-2026 (got: '$CREATED')"
fi
fi
# --- Python-Version: expected on Standards Track, disallowed elsewhere ---
if [[ "$TYPE" == "Standards Track" ]]; then
if has_value Python-Version; then
pass "Python-Version present (Standards Track)"
else
warn "Standards Track PEPs usually set Python-Version"
fi
elif [[ -n "$TYPE" ]] && has_value Python-Version; then
warn "Python-Version is set but Type is '$TYPE' (Python-Version is for Standards Track only)"
fi
# --- Discussions-To expected once past Draft ---
if [[ -n "$STATUS" && "$STATUS" != "Draft" ]]; then
if has_value Discussions-To; then
pass "Discussions-To present"
else
warn "Status is '$STATUS' but Discussions-To is empty"
fi
fi
# --- Resolution required for resolved Standards Track PEPs ---
case "$STATUS" in
Accepted|Rejected|Withdrawn|Final)
if has_value Resolution; then
pass "Resolution header present for status $STATUS"
elif [[ "$TYPE" == "Standards Track" ]]; then
fail "Standards Track PEP in status $STATUS must have a Resolution header"
else
warn "Status $STATUS usually records a Resolution link"
fi
;;
esac
# --- Superseded consistency ---
if [[ "$STATUS" == "Superseded" ]] && ! has_value Superseded-By; then
warn "Status is Superseded but no Superseded-By header"
fi
# --- Abstract section (strongly recommended) ---
if grep -qE '^Abstract[[:space:]]*$' "$FILE"; then
pass "Abstract section present"
else
warn "no 'Abstract' section found (strongly recommended)"
fi
# --- Mandatory CC0 copyright notice ---
if grep -q "CC0-1.0-Universal" "$FILE"; then
pass "Copyright / CC0-1.0-Universal notice present"
else
fail "missing mandatory CC0-1.0-Universal copyright notice"
fi
echo
echo "Summary: $PASS passed, $WARN warnings, $FAIL failed"
if (( FAIL > 0 )); then
echo "Result: FAIL — fix the items above before submitting." >&2
exit 1
fi
if (( WARN > 0 )); then
echo "Result: OK with $WARN warning(s)"
else
echo "Result: OK"
fi
#!/usr/bin/env bash
# new-pep.sh — Scaffold a new Python Enhancement Proposal (PEP) reStructuredText file.
# Part of: python-pep-author
#
# Fills the RFC 2822 header preamble from the bundled PEP template, sets a Draft
# status and today's Created date, and enforces the 44-character title limit.
# PEP numbers are assigned by the PEP editors, so the number defaults to a 9999
# placeholder — replace it once a number is assigned.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMPLATE="$SCRIPT_DIR/../assets/templates/pep-template.rst"
usage() {
cat >&2 <<'EOF'
Usage:
new-pep.sh --title "<title>" --author "<Name <email>>" --type <type> [options]
Required:
--title "<title>" Short PEP title (max 44 characters)
--author "<Name <email>>" e.g. "Random J. User <random@example.com>"
--type <type> "Standards Track" | Informational | Process
Options:
--out <path> Output file (default: ./pep-<NNNN>.rst)
--pep <number> PEP number (default: 9999 — editors assign the real one)
--status <status> Initial status (default: Draft)
--python-version <M.N> Target Python version (Standards Track only)
-h, --help Show this help
Example:
new-pep.sh --title "Add frobnication to the stdlib" \
--author "Random J. User <random@example.com>" \
--type "Standards Track" --python-version 3.15
EOF
exit "${1:-1}"
}
# --- Defaults ---
TITLE=""
AUTHOR=""
TYPE=""
PEP_NUM="9999"
STATUS="Draft"
PYVER=""
OUT=""
# --- Parse arguments ---
while [[ $# -gt 0 ]]; do
case "$1" in
--title) TITLE="${2:-}"; shift 2 ;;
--author) AUTHOR="${2:-}"; shift 2 ;;
--type) TYPE="${2:-}"; shift 2 ;;
--pep) PEP_NUM="${2:-}"; shift 2 ;;
--status) STATUS="${2:-}"; shift 2 ;;
--python-version) PYVER="${2:-}"; shift 2 ;;
--out) OUT="${2:-}"; shift 2 ;;
-h|--help) usage 0 ;;
*) echo "Error: unknown argument: $1" >&2; usage ;;
esac
done
# --- Validate template ---
if [[ ! -f "$TEMPLATE" ]]; then
echo "Error: template not found at $TEMPLATE" >&2
echo " This script must run from inside the python-pep-author skill." >&2
exit 1
fi
# --- Validate required arguments ---
missing=""
[[ -z "$TITLE" ]] && missing="$missing --title"
[[ -z "$AUTHOR" ]] && missing="$missing --author"
[[ -z "$TYPE" ]] && missing="$missing --type"
if [[ -n "$missing" ]]; then
echo "Error: missing required argument(s):$missing" >&2
usage
fi
# --- Validate type ---
case "$TYPE" in
"Standards Track"|"Informational"|"Process") ;;
*) echo "Error: --type must be 'Standards Track', 'Informational', or 'Process' (got: '$TYPE')" >&2; exit 1 ;;
esac
# --- Python-Version applies to Standards Track only (PEP 1) ---
if [[ -n "$PYVER" && "$TYPE" != "Standards Track" ]]; then
echo "Error: --python-version applies to Standards Track PEPs only (type is '$TYPE')." >&2
echo " Drop --python-version, or set --type 'Standards Track'." >&2
exit 1
fi
# --- Validate title length ---
if (( ${#TITLE} > 44 )); then
echo "Error: --title is ${#TITLE} characters; PEP titles must be at most 44." >&2
exit 1
fi
# --- Validate PEP number is numeric (for filename zero-padding) ---
if ! [[ "$PEP_NUM" =~ ^[0-9]+$ ]]; then
echo "Error: --pep must be a number (got: '$PEP_NUM')" >&2
exit 1
fi
PADDED="$(printf '%04d' "$PEP_NUM")"
# --- Derive Created date and output path ---
# Force the C locale so the month is always the English three-letter form PEP 1
# requires (e.g. "May"); +%b is locale-sensitive otherwise.
CREATED="$(LC_ALL=C date +%d-%b-%Y)"
[[ -z "$OUT" ]] && OUT="./pep-${PADDED}.rst"
# --- Format the author(s) onto RFC 2822 continuation lines (one per line) ---
# PEP 1 requires each author on a separate continuation line indented 8 spaces.
format_authors() {
local raw="$1" out="" a
local IFS=','
read -ra parts <<< "$raw"
for a in "${parts[@]}"; do
a="${a#"${a%%[![:space:]]*}"}" # ltrim
a="${a%"${a##*[![:space:]]}"}" # rtrim
[[ -z "$a" ]] && continue
if [[ -z "$out" ]]; then
out="$a"
else
out="$out,"$'\n'" $a"
fi
done
printf '%s' "$out"
}
AUTHOR="$(format_authors "$AUTHOR")"
if [[ -e "$OUT" ]]; then
echo "Error: $OUT already exists. Choose a different --out or remove it first." >&2
exit 1
fi
# --- Render the template (literal substitution, safe for <, >, &, / in values) ---
# Drop the Python-Version line entirely when no version is supplied.
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ -z "$PYVER" && "$line" == Python-Version:* ]]; then
continue
fi
line="${line//@@PEP@@/$PEP_NUM}"
line="${line//@@TITLE@@/$TITLE}"
line="${line//@@AUTHOR@@/$AUTHOR}"
line="${line//@@TYPE@@/$TYPE}"
line="${line//@@STATUS@@/$STATUS}"
line="${line//@@CREATED@@/$CREATED}"
line="${line//@@PYTHON_VERSION@@/$PYVER}"
printf '%s\n' "$line"
done < "$TEMPLATE" > "$OUT"
echo "Created $OUT"
echo " PEP: $PEP_NUM (placeholder — PEP editors assign the real number)"
echo " Title: $TITLE"
echo " Type: $TYPE"
echo " Status: $STATUS"
echo " Created: $CREATED"
echo
echo "Next steps:"
echo " 1. Fill in the body sections (see references/sections.md)."
echo " 2. Lint it: $SCRIPT_DIR/check-pep.sh $OUT"
echo
echo "Note: 'Created' is set to today. PEP 1 defines it as the date the PEP is"
echo " assigned a number — update it if a number is assigned on a later date."
Related skills
FAQ
What does python-pep-author do?
python-pep-author is a Claude Code skill for security. It helps developers move faster with AI-assisted coding.
When should I use python-pep-author?
When you need to helps with security tasks during ai-assisted development, or when python-pep-author is a claude code skill for security. it helps developers move faster with ai-assisted coding.
What are the main capabilities?
python-pep-author; Security; AI-coding skill.