PEP 8016 - The steering council model

Here’s the text of PEP 8016, also available here:

There’s earlier discussion over here, and now that there’s a full draft @vstinner requested that we paste the full text into a new Discourse thread, so, here you go! (Of course this may get out of date if there are further tweaks in response to feedback.)

PEP 8016 – The Steering Council Model


This PEP proposes a model of Python governance based around a steering council. The council has broad authority, which they seek to exercise as rarely as possible; instead, they use this power to establish standard processes, like those proposed in the other 801x-series PEPs. This follows the general philosophy that it’s better to split up large changes into a series of small changes that can be reviewed independently: instead of trying to do everything in one PEP, we focus on providing a minimal-but-solid foundation for further governance decisions.


The main goals of this proposal are:

  • Be boring : We’re not experts in governance, and we don’t think Python is a good place to experiment with new and untried governance models. So this proposal sticks to mature, well-known, previously tested processes as much as possible. The high-level approach of a mostly-hands-off council is arguably the most common across large successful F/OSS projects, and low-level details are derived directly from Django’s governance.
  • Be simple : We’ve attempted to pare things down to the minimum needed to make this workable: the council, the core team (who elect the council), and the process for changing the document. The goal is Minimum Viable Governance.
  • Be comprehensive : But for the things we need to define, we’ve tried to make sure to cover all the bases, because we don’t want to go through this kind of crisis again. Having a clear and unambiguous set of rules also helps minimize confusion and resentment.
  • Be flexible and light-weight : We know that it will take time and experimentation to find the best processes for working together. By keeping this document as minimal as possible, we keep maximal flexibility for adjusting things later, while minimizing the need for heavy-weight and anxiety-provoking processes like whole-project votes.

A number of details were discussed in this Discourse thread, which may be useful to anyone trying to understand the rationale for various minor decisions.


The steering council


The steering council is an elected committee of 5 core team members.


The steering council’s shall work to:

  • Maintain the quality and stability of the Python language and CPython interpreter,
  • Make contributing as accessible, inclusive, and sustainable as possible,
  • Formalize and maintain the relationship between the core team and the PSF,
  • Establish appropriate decision-making processes for PEPs,
  • Seek consensus among contributors and the core team before acting in a formal capacity,
  • Act as a “court of final appeal” for decisions where all other methods have failed.


The council has broad authority to make decisions about the project. For example, they can:

  • Accept or reject PEPs
  • Enforce the Python code of conduct
  • Work with the PSF to manage any project assets
  • Delegate their authority to other subcommittees or processes

However, they cannot modify this PEP, or affect the membership of the core team, except via the mechanisms specified in this PEP.

The council should look for ways to use these powers as little as possible. Instead of voting, it’s better to seek consensus. Instead of ruling on individual PEPs, it’s better to define a standard process for PEP decision making (for example, by accepting one of the other 801x series of PEPs). It’s better to establish a Code of Conduct committee than to rule on individual cases. And so on.

To use its powers, the council votes. Every council member must either vote or explicitly abstain. Members with conflicts of interest on a particular vote must abstain. Passing requires a strict majority of non-abstaining council members.

Whenever possible, the council’s deliberations and votes shall be held in public.

Electing the council

A council election consists of two phases:

  • Phase 1: Candidates advertise their interest in serving. Only core team members may be candidates.
  • Phase 2: Each core team member can vote for zero to five of the candidates. Voting is performed anonymously. Candidates are ranked by the total number of votes they receive. In case of a tie, the candidate who joined the core team earlier wins.

Each phase lasts one to two weeks, at the outgoing council’s discretion. For the initial election, both phases will last two weeks.

The election process is managed by a returns officer nominated by the outgoing steering council. For the initial election, the returns officer will be [TBD].

The council should ideally reflect the diversity of core Python contributors, and core team members are encouraged to vote accordingly.


A new council is elected after each feature release. Each council’s term runs from when their election results are finalized until the next council’s term starts. There are no term limits.


Council members may resign their position at any time.

Whenever there is a vacancy during the regular council term, the council may vote to appoint any willing core team member to serve out the rest of the term.

If a council member drops out of touch and cannot be contacted for a month or longer, then the rest of the council may vote to replace them.

Conflicts of interest

While we trust council members to act in the best interests of Python rather than themselves or their employers, the mere appearance of any one company dominating Python development could itself be harmful and erode trust. In order to avoid any appearance of conflict of interest, at most 2 members of the council can work for any single employer.

In a council election, if 3 of the top 5 vote-getters work for the same employer, then whichever of them ranked lowest is disqualified and the 6th-ranking candidate moves up into 5th place; this is repeated until a valid council is formed.

During a council term, if changing circumstances cause this rule to be broken (for instance, due to a council member changing employment), then one or more council members must resign to remedy the issue, and the resulting vacancies can then be filled as normal.

Ejecting core team members

In exceptional circumstances, it may be necessary to remove someone from the core team against their will. (For example: egregious and ongoing code of conduct violations.) This can be accomplished by a steering council vote, but unlike other steering council votes, this requires at least a two-thirds majority. With 5 members voting, this means that a 3:2 vote is insufficient; 4:1 in favor is the minimum required for such a vote to succeed. In addition, this is the one power of the steering council which cannot be delegated, and this power cannot be used while a vote of no confidence is in process.

Vote of no confidence

In exceptional circumstances, the core team may remove a sitting council member, or the entire council, via a vote of no confidence.

A no-confidence vote is triggered when a core team member calls for one publically on an appropriate project communication channel, and another core team member seconds the proposal.

The vote lasts for two weeks. Core team members vote for or against. If at least two thirds of voters express a lack of confidence, then the vote succeeds.

There are two forms of no-confidence votes: those targeting a single member, and those targeting the council as a whole. The initial call for a no-confidence vote must specify which type is intended. If a single-member vote succeeds, then that member is removed from the council and the resulting vacancy can be handled in the usual way. If a whole-council vote succeeds, the council is dissolved and a new council election is triggered immediately.

The core team


The core team is the group of trusted volunteers who manage Python. They assume many roles required to achieve the project’s goals, especially those that require a high level of trust. They make the decisions that shape the future of the project.

Core team members are expected to act as role models for the community and custodians of the project, on behalf of the community and all those who rely on Python.

They will intervene, where necessary, in online discussions or at official Python events on the rare occasions that a situation arises that requires intervention.

They have authority over the Python Project infrastructure, including the Python Project website itself, the Python GitHub organization and repositories, the bug tracker, the mailing lists, IRC channels, etc.


Core team members may participate in formal votes, typically to nominate new team members and to elect the steering council.


Python core team members demonstrate:

  • a good grasp of the philosophy of the Python Project
  • a solid track record of being constructive and helpful
  • significant contributions to the project’s goals, in any form
  • willingness to dedicate some time to improving Python

As the project matures, contributions go beyond code. Here’s an incomplete list of areas where contributions may be considered for joining the core team, in no particular order:

  • Working on community management and outreach
  • Providing support on the mailing lists and on IRC
  • Triaging tickets
  • Writing patches (code, docs, or tests)
  • Reviewing patches (code, docs, or tests)
  • Participating in design decisions
  • Providing expertise in a particular domain (security, i18n, etc.)
  • Managing the continuous integration infrastructure
  • Managing the servers (website, tracker, documentation, etc.)
  • Maintaining related projects (alternative interpreters, core infrastructure like packaging, etc.)
  • Creating visual designs

Core team membership acknowledges sustained and valuable efforts that align well with the philosophy and the goals of the Python Project.

It is granted by receiving at least two-thirds positive votes in a core team vote and no veto by the steering council.

Core team members are always looking for promising contributors, teaching them how the project is managed, and submitting their names to the core team’s vote when they’re ready.

There’s no time limit on core team membership. However, in order to provide the general public with a reasonable idea of how many people maintain Python, core team members who have stopped contributing are encouraged to declare themselves as “emeritus members”. Those who haven’t made any non-trivial contribution in two years may be asked to move themselves to this category, and moved there if they don’t respond. Emeritus team members lose their privileges such as voting rights and commit access.

Changing this document

Changes to this document require at least a two-thirds majority of votes cast in a core team vote.


  • Maybe add compare-and-contrast with other 801x proposals?
  • Ask Ian or Ernest if they’re willing to be the initial returns officer.
  • Lots of people contributed helpful suggestions and feedback; we should check if they’re comfortable being added as co-authors
  • It looks like Aymeric Augustin wrote the whole Django doc, so presumably holds copyright; maybe we should ask him if he’s willing to release it into the public domain so our copyright statement below can be simpler.


Substantial text was copied shamelessly from The Django project’s governance document.


Text copied from Django used under their license. The rest of this document has been placed in the public domain.


I like your overall PEP :slight_smile: From my point of view, it’s (very) similar on many points to my PEP 8015.

They have a veto on adding a new member to core devs. You may mention it here.

I first used your rule to resolve a tie… but then a friend told me that two core devs can have been promoted at the same time. Please see Complete the core dev list by vstinner · Pull Request #434 · python/devguide · GitHub we don’t know when many core devs have been promoted:

(Incomplete list) Brett Cannon, Barry Warsaw, David Goodger, Fred Drake, Gregory P. Smith, Neal Norwitz, Martin v. Loewis, Raymond Hettinger, ThomasWouters, Tim Peters and Guido van Rossum commit bit predates the start of that list.

So I changed the resolution method in my PEP 8015:

In case of tie, a new vote is organized immediately between candidates involved in the tie using the same voting method and also during 1 week. If the second vote leads to a tie again, the current Steering Committee is responsible to seleect the elected member.

and for the creation of the committee:

In case of tie, a second vote is organized immediately between candidates involved in the tie and following candidates to fill the remaining seats. The vote follows the same rules as the regular committee vote. If the second vote still result in a tie, the PSF Board is responsible to elect members and decide their position in the vote result.

I chose to use the PSF Board for your [TBD]:

TODO: Contact the PSF Board to ask them if they agree with that :slight_smile:

In my PEP, I chose to reuse the external group PSF Conduct Workgroup. So I use the Code of Conduct has the law to decide when a core dev really misbehave and must be excluded from the group. Honestly, I’m not sure about that. Some people can be “counter productive” (block changes for no or “bad” reasons), but still respect the CoC.

Conduct WG is independent from the Steering Council and so can also handle CoC reports about the Council itself. But the vote of no confidence of your PEP can be used for such special case.

Voting on someone is really difficult.

Well, I have no special request to change anything. I just wanted to add some comments on this section :slight_smile:

I think the emeritus rules are unfair and would discourage new people from making significant code contributions.

Please let’s not value activity over progress. It is quite easy to make a couple of churn commits or constantly suggest new PSF initiatives.

It won’t improve the code base though — Sometimes there just isn’t much to do in certain interest areas.

Heh, thanks for the heads up!

My first inclination is towards something lighter-weight than this, like “if this can’t be determined, then use date of first commit, and if that can’t be determined either, then coin flip.”

The PSF Board doesn’t even handle the election for the PSF Board :-). IIRC Ian Cordasco handled the mechanics for the last few PSF Board elections (which use the same voting mechanism as PEP 8016), and apparently Ernest has already offered to handle the mechanics for the PEP 8001 election, so I’d ask them first?

Does the PSF Conduct Workgroup actually review individual CoC cases? My read of their charter is that they don’t…

Yeah, it’s probably useful for these escape hatches to exist, but hopefully we’ll never have to use them :frowning:

Sorry, not sure what you mean – can you expand? Why would new people avoid making significant code contributions?

I think you must be misreading the PEP here? In the text currently, literally the only way for someone to move into emeritus status without their consent is if (a) they don’t make any non-trivial contributions for 2 years (where “contribute” is explicitly not limited to writing commits, but also includes issue triaging, critiquing PEPs, reviewing PRs, etc. etc.), AND (b) they don’t respond to email suggesting they should switch to emeritus status. And once they’re in emeritus status, all they have to do to switch back is to start contributing again, no questions asked. (This last part is a clarification added today so it might not be in the snapshot pasted above.) So if someone wants to avoid moving to emeritus status, all they have to do is … not disappear entirely.

Because it’s exhausting to make significant new code contributions and people need to rest, in which case they’d lose privileges.

Several of the math experts would have already lost the commit bit under your rules (as I understood them).

Yes, I misunderstood (b) then. Still, I think it’s fundamentally wrong to codify open source treadmills in a constitution.

The PSF voter’s treadmill is one of the reasons I’m not a PSF voting member — I find it offensive to have to explicitly pledge monthly hours after all the code that I’ve given away for free.

My expectation is that we will never need a second vote thanks to Condorcet and ~100 voters. But I wanted to write down how to handle a tie “if it happens”.

OpenStack uses CIVS voting website, so Condorcet. In case of a tie… they flip a coin:

A Project Team Leader in OpenStack has a mandate of 6 months and less power, than anything described in the Python governance PEPs. So I’m not comfortable to just flip a coin.

@skrah: I understand that you can remain an idle core developer as long as you want, if you decline each request to switch to the list of emeritus developers. I don’t understand it as anyone push would force a developer to move to this list.

I concur with his need:

However, in order to provide the general public with a reasonable idea of how many people maintain Python

I tried to reach Martin von Loewis multiple times using different email addresses last years and I never succeeded to reach him. He is a good candidate for Emeritus Core Dev. They are other examples.

Maybe the PEP should explain that it’s a reversible action: if you want to contribute again, you can be moved again from Emeritus to the core dev list.

The existing procedure was to mark core devs as “inactive” in the expert’s index when they no longer responded on the bug tracker.

That is fair IMO and did not take away the commit bit. “Inactive” is also a better word than “emeritus”, which has clear age connotations.

I don’t really care about the naming, but removing the commit bit is an important security move.

Whenever I talk to security managers at work, they all ask who has write access to the code, and when I mention it includes a number of people who we haven’t heard from in years they ask if those people would know if their account is being used by someone else (that is, they’ve been hacked without noticing). Disabling push/merge permissions for someone who is inactive is the right thing to do.

1 Like

FWIW We’ve removed the commit bit in pip of anyone who hasn’t been recently active (after reaching out to them) and I don’t think anyone has had a problem with it. The expectation has always been that if they ever want to start contributing back again, a simple email will get their commit bit restored.

Honestly, I would be fine relaxing the Emeritus → Active path to even just needing to ask for it back, no questions asked. It’s not really designed to punish people who are unavailable or don’t want to participate for some period of time. It’s really just to help aid in knowing what our current, active contributors are. Things like dropping a commit bit are largely just security improvements over that.

With regards to the terminology. I don’t really care about Emeritus vs Inactive. I think the term “Emeritus” came from the original Django documentation, although I believe the reason it’s used is primarily that it implies a sense of honor/esteem for their past duties. Wikipedia has this to say about it:

In some cases, the term is conferred automatically upon all persons who retire at a given rank, but in others, it remains a mark of distinguished service, awarded to only a few on retirement. It is also used when a person of distinction in a profession retires or hands over the position, enabling their former rank to be retained in their title, e.g., “Professor Emeritus”. The term emeritus does not necessarily signify that a person has relinquished all the duties of their former position, and they may continue to exercise some of them.

In general, I’ve only ever seen the title “Emeritus” used as a sense of an honor, whereas I think the idea was to generally avoid “Inactive” because that might have negative connotations (In English at least, one of the synonyms for “Inactive” is “Lazy”).

At the end of the day though, a word is just a word, so if people feel more comfortable with Inactive over Emeritus, it doesn’t matter either way for me.

The only thing I’m not clear on is how to update this PEP. This is probably unnecessarily technical, but “modify this PEP” I assume means “directly modify this PEP” and that some form of vote or mechanism that indirectly let others update the PEP would be allowed?

Just to be ridiculously clear, this is Approval voting, correct?

I hesitated to ask the same question, so it might be worth it to mention the voting method name :slight_smile:

Yea, the idea is that this PEP represents our constitution, and changing it would require a vote of the electorate again, rather than the steering committee being able to change it directly. This protects a rogue steering committee from creating a constitutional crisis by changing the rules they themselves are governed by.

The PEP has this to say:

Changes to this document require at least a two-thirds majority of votes cast in a core team vote.

Which can be found under the Changing this document header.

Yes, it is approval voting.

Condorcet isn’t well suited to selecting multiple winners (with some algorithms you can produce a total ranking, and select the top N, but that’s sort of an unintended hack), and you make cycles more likely if you’re trying to produce a total ordering rather than just the top winner.

A positive to using Approval here is that Helios, the voting system the PSF uses, already supports it, so we can just piggy back off that going into the future. Also the downsides over Condorcet are not a super big deal here, since the outcome is limited to a single term, instead of ~forever.

1 Like

I have no problem with Approval for this use-case, I just wanted to make sure I didn’t misunderstand anything. :smile:

1 Like

OED, emeritus:

“Honourably discharged from service; (of a former office-holder, esp. a professor) retired but allowed to retain his or her title as an honour.”

I’d find it weird to discharge MvL from service, but that’s just me. If a contact attempt is made before doing so, that’s somewhat acceptable.

We’ve made plenty of non-specific attempts, though it’s possible that saying “or else we’ll remove your SSH key” would provoke more of a response. But it probably won’t, since as far as we know he doesn’t ever attempt to directly update the content of, and we don’t think anyone has stolen his key. (Yes, I’m deliberately emphasizing the good security reasons to remove his access, since he had more than most of us.)

None of this should devalue his contributions in the past. People who think it does are worried about the wrong things, IMHO.

Django actually calls this category “past team member”. I’ve seen emeritus used for this elsewhere. (Probably numpy or similar. In the scientific world the concept of emeritus professor is very familiar :-).) I’m the one who switched it from “past” to “emeritus”.

That’s exactly why I switched it, yeah. And also because emeritus in the academic context is really different than “past” or “retired”, because it implies you’re still alive and may still make contributions if you feel like it, and you keep your former eminence without your former responsibilities.

I’m also fine with “inactive” if people like this better.

And yeah, the goal is definitely not to force people to do make work! The fact is that for a decades-long project like CPython, people leave, and that’s totally fine. As a project we want to be able to cope with this reality without it creating weird and awkward situations. So the goal is to set some basic expectations around this, to make sure that we continue to credit people for their past work and aren’t pushing anyone out, but at the same time aren’t keeping around ancient SSH keys and asking people who aren’t even around anymore to set project policy.

Since Guido’s not using his time machine currently, we borrowed it: PEP 8016: add more details about how emeritus members work by njsmith · Pull Request #834 · python/peps · GitHub

The term is very familiar in Germany and means the same. I was surprised by the OED definition (presumably written by academics).

In practice, however, it would be applied to people like Atiyah. I’ve never seen it applied to anyone below 67-70.

I’m positive the community will make the right meaning abundantly clear.
Remember a certain dictator for life? I wonder how much time was spent searching for possible negative connotations there.