Short link: https://go.dev/s/proposal-proposal-2026
Since I took over leading Go's proposal process in late 2024, I've been thinking deeply about its strengths and faults. I believe deeply in its goals of transparency and community involvement, but that while its foundations are solid, its process failures mean it doesn't always live up to its goals. I don't think these process failures are something that can be addressed piecemeal, so this is my attempt at a holistic update to the proposal process. The basic outline isn't so different: anyone can file a proposal, discussion all happens in the open, and decisions are made after careful consideration by a small group of experts. This proposal is largely about technical updates throughout the process to better achieve its goals.
Abstract
The proposal process is Go’s engine of change. It’s a critical way the community shapes and informs the evolution of Go. But it also has some clear flaws: a backlog that is growing 23% year-over-year with a median age of over two years, and a manual prioritization process that is neither transparent nor community-informed. To resolve these bottlenecks, this proposal refines the process by:
- Establishing a formal triage process to engage proposals quickly and make fast, early decisions,
- Using weighted community emoji voting to transparently prioritize proposals for review,
- Splitting proposal review into domain-specific tracks to scale throughput and create the capacity to bring in community .
Background
The Go proposal process is a vital mechanism for ensuring the Go project’s development remains transparent and community-driven, and for maintaining the Go platform’s incredibly high standards of compatibility and simplicity. The proposal process was first formalized in 2015 and evolved between 2015 and 2019 for better transparency and to handle large and contentious changes. This period also marked a shift from rigid stability bordering on ossification to pragmatic evolution.
The proposal process is a careful balance of many factors. It is designed to make irreversible decisions that are subject to the Go compatibility promise, while also maintaining Go’s uniformity of design. Over the past several years, we’ve introduced technical mechanisms to lower the risk of making such decisions, such as language versions, forward compatibility, and GOEXPERIMENT, but the proposal process is necessarily heavyweight because “yes is forever.” The process is also designed to protect the attention of the small proposal review group and prevent receive livelock by strictly balancing our intake of proposals with our output of decisions. At the same time, anyone can file a proposal, and this openness is at the heart of the proposal process.
The public proposal process has critically shaped the Go project, but these factors, combined with time and growth, have led to several problems. These problems are felt by the community and many of them can be seen in the data, such as in figure 1. The backlog of unreviewed proposals is growing by 23% year over year, and the median age of a proposal in the backlog now exceeds two years. Today, there’s no process for prioritizing this massive backlog, so which proposals enter review and when is frustratingly opaque and fails to broadly account for community input. Meanwhile, this backlog would be growing far faster were it not for the heroics of a few self-nominated contributors triaging incoming proposals. This triage work is thankless and often leads to conflict (nobody likes having their proposal closed!). At the same time, accepted proposals also often languish, leading to confusion and wasted work. Finally, since the proposal review committee itself is small while covering diverse expertise, often only one or two people have the expertise to evaluate any given proposal and there are inevitable gaps.
Figure 1. The proposal process by the numbers. “New” shows the number of new proposals filed in each year. “Backlog” shows the total number of proposals that have been filed but not reviewed as of Jan 1 each year. “Early reject” shows how many proposals were closed without review in each year, including by ad hoc triage. “Review” shows how many proposals passed through the proposal review committee within each year. The last four rows show the outcomes of the review process. “Backlog”, “Hold”, and “Accepted” are inventory states that show the total number of proposals in that state on Jan 1. “Early Reject”, “Implemented”, and “Declined” are terminal states and only show the proposals that entered that state in a given calendar year.
Overview of the proposed process
Figure 2. An overview of the flow of a proposal through the proposed process. The four columns represent the phases a proposal passes through. Blue boxes represent people processes and green pills represent decisions, often with supporting data.
We propose a refined process to align the mechanics of proposals with our principles. This process divides a proposal's lifecycle into four distinct phases (figure 2):
- Incoming: The entry point for a newly filed proposal. Here, an asynchronous, lightweight triage decides if a proposal meets the bar for review or should be closed with a standard rationale.
- Ready: Where proposals wait in a public queue and the community can indicate interest using emoji voting. The triaged priority is combined with weighted emoji votes to determine how quickly a proposal enters active review.
- Active: Domain-specific review tracks meet weekly to review active proposals. Sessions are timeboxed by proposal controversy to isolate “easy” proposals from “hard” ones. As these groups decide on proposals, they pull in Ready proposals based on priority, track, and controversy.
- Decided: Like now, proposals have a one week final comment period after a review track recommends “accept” or “decline.” A final review group also checks all proposals recommended for “accept” for uniformity of design.
The specific mechanics and rules for each phase are detailed in the following sections.
Detailed mechanics
Proposal triage
The newly formed proposal triage group will consist of 3–5 individuals. Their role is twofold: reviewing new proposals to determine whether they meet the bar for proposal review and providing initial prioritization. By formalizing this process and establishing a small, designated group, we aim to distribute the workload more equitably, provide a consistent framework for triage, and ensure decisions reflect a wider range of perspectives while also officially recognizing the efforts of triage members. Unlike proposal review—a stringent process for making high-confidence, irreversible decisions—proposal triage is designed for making reversible decisions through asynchronous and lightweight voting rather than consensus.
For each proposal, each member of the proposal triage can select one of three actions:
- Vote to close, with a rationale. Closure requires a ⅔ supermajority with a minimum of two “close” votes (vc ≥ ⅔ n ∧ vc ≥ 2).
- Vote ready for proposal review, with a track, initial priority, and a controversy level. Promoting a proposal to proposal review requires a vote of at least ⅓ of the group, again with a minimum of two “ready” votes (vr > ⅓ n ∧ vr ≥ 2). (For a group of 3 to 5 members, this always means two “ready” votes are sufficient.) The process is intentionally biased toward this outcome.
- Request revision or clarification. This indicates the triage member thinks there isn’t enough information to decide whether to close or promote a proposal, or that the proposal simply needs more work before review. The member should post their question or critique to the issue, and automation will hide the proposal from the member’s triage dashboard until there’s further discussion. At that point, they can review if their question has been answered and vote, post again, or simply mark it as still unresolved. After 30 days, if it remains unresolved and is still in the Incoming state, this automatically flips to a “close” vote.
To reduce anchoring bias, members cannot see how others vote on a proposal until they themselves have voted, but they can change their vote after. (Some common causes for changing one’s vote may be if a member first votes to open, and then sees someone else found a duplicate; or if their decision overlooked an important aspect that another reviewer surfaced.) Since voting is asynchronous, a proposal will be considered triaged once there are enough votes to pass the threshold; it does not require everyone to vote. If a proposal does pass the voting threshold, after 24 hours without any changes to votes, automation will post the outcome to the proposal issue. This delay is to allow for second thoughts, to give time for other votes to come in (though additional votes couldn’t undo the outcome), and to build in some debouncing.
Triage group members are always welcome to perform routine issue gardening as well. For example, if an issue is filed as a proposal, but is actually a feature request, any member of triage (or anyone gardening) can simply move it out of the proposal process, mark it with the FeatureRequest label, and suggest filing concrete proposals as sub-issues. Likewise, if an issue filed as a proposal is actually just a bug or doesn’t affect any surface subject to the Go compatibility promise, anyone gardening can move it out of the proposal process.
Open question: How do we catch up with the current backlog? It would be valuable to work through the backlog, at minimum to assign the metadata that informs the rest of the process. But we don’t want to dump 800 proposals on a volunteer triage group. Most will be trivial to triage, but some will not.
Closure rationales
A vote to close must include a rationale, either one of the following standard rationales, or a write-in rationale:
- Backwards-incompatible change
- Insufficient information for proposal review
- Duplicate of rejected proposal #N without new rationale (closed as duplicate)
- Duplicate of open proposal #N (closed as duplicate)
We can refine and expand these rationales over time. If a proposal is closed, automation will post the rationales and handles of those who voted to close. Proposal triage isn’t intended to be anonymous, so posting handles avoids unintentionally obscuring identities through automation.
Appeals
Closure can be appealed if there is additional information or context to consider. The exact mechanism for this is TBD; most likely it will be by posting a comment to the proposal bot on GitHub. An appealed closure will go back into proposal triage. We may put a limit on the number of times a proposal can be appealed.
Ready for proposal review
For a proposal to be ready for proposal review, it must be backwards-compatible, and must not reintroduce a settled idea without significant new rationale.
It must also satisfy some structural requirements:
- It must describe the problem being solved, propose a concrete solution (not just a request for a solution), and provide rationale for the solution.
- For proposals where adherence to the Go Compatibility Promise isn’t obvious, it must include a discussion of compatibility.
- If a proposal would create a new way to do something that is already possible, it must justify why it is a significant improvement and discuss whether a
go fixupgrade is possible. - More complex proposals should include a discussion of alternate approaches and why they were rejected in favor of the given solution, as well as advantages, and disadvantages of the specified approach.
The degree of structure in a proposal should be commensurate with its complexity; trivial proposals need only a few sentences of justification, while complex proposals should follow the proposal template. We will update the rather minimal GitHub proposal issue template to better guide people into meeting these requirements.
A proposal does not need to be perfect or have clear community consensus to be considered Ready.
A vote that a proposal is ready for proposal review will also include three pieces of metadata that inform the rest of the process: a track, an initial priority, and a controversy level. If the triage group votes that a proposal is ready for review, it enters the Ready state.
The track, priority, and controversy level will be recorded by the proposal automation in GitHub issue fields (a fairly new GitHub feature), which are searchable and always visible in the right hand bar of an issue.
Track. We’ll discuss the possible review tracks in the section on multi-track proposal review. We combine the tracks from the triage votes by taking their mode, with simple random selection if there’s more than one mode. If there’s disagreement on the track, then probably any of the selected tracks is reasonable, and proposal review itself can move a proposal to a different track if it turns out to be better suited to another track.
Priority. A vote for ready also establishes an initial priority. There are five priority levels:
- Urgent - Must be reviewed immediately. A proposal to revisit a change that is about to become irreversible, or a proposal to revisit a reversible change that has just become public. To be used sparingly. An urgent proposal directly enters the Active state, meaning it will be reviewed immediately.
- Next major - A proposal specifically targeting the next major release. Generally a proposal that’s required in order to unblock other work in the Go project, or part of a multi-release change, or a proposal that’s already available as a GOEXPERIMENT and ready for general release. A next major proposal does not directly enter the Active state, but it skips the queue, so it will be reviewed as soon as there’s capacity to do so. Like urgent, this should be used sparingly.
- High - A proposal that would impact a large fraction of Go’s users, or a proposal that would have a large impact on specific segments of users.
- Medium
- Low - A proposal with minimal or very narrow impact.
We combine the priorities from the triage votes by taking the highest priority. The top two levels–urgent and next major–are strict and bypass community prioritization to go straight to the proposal committee. The other three levels–high, medium, and low–are probabilistic and feed into community prioritization, which we’ll discuss in the next section.
Controversy. The final component of a vote for ready is controversy. Controversy captures size, complexity, and impact, and estimates how much discussion a proposal will require before reaching a decision. There are four controversy levels:
- Trivial - A simple addition with a clear definition, a clear use case, and obviously no backwards-compatibility issues. Likely to be approved or rejected in a single review session. Decision time: days.
- Minor - A localized change that may require some review of naming, signature, or semantic details, but has no broader ecosystem side-effects and clearly fits in with existing API and/or design. Decision time: weeks.
- Substantial - A change that introduces a new capability or mental model and requires active design synthesis, but has alignment on the overall direction. Decision time: months.
- Contentious - Proposals where the technical trade-offs are heavy, the ecosystem impact is massive, and reaching a true Go-like consensus requires exhaustive deliberation. Decision time: quarters to years.
We combine the controversy levels from the triage votes by simply averaging their numerical values (with ties rounded up). We’ll describe the use of controversy levels in detail below, but in short they are used to box proposal review time and ensure the “easier” proposals don’t get drowned out by discussion on the difficult ones.
Community-informed prioritization
Currently the proposal process has almost no way for the community to weigh in on what’s important. I propose we officially use GitHub emoji votes to drive prioritization of when proposals enter review. To be clear, emoji votes would purely influence when a proposal gets reviewed, not how it is decided.
The “base weight” of a proposal will be determined by its triaged priority. The exact weights are TBD, but for initial tuning let’s say high is worth 50 points, medium 25 points, and low 10 points. From there, we add a community weight based on the number of “thumbs-up” votes on the top post, weighted by contributor level. Again, exact weights are TBD, but for initial I propose a vote from an approver is 5 points and otherwise a vote is 1 point. Weighting votes elevates the input of those more familiar with the Go project, and serves to prevent Sybil attacks and gaming the system.
The weighting scheme is sure to be refined over time. Currently, the median number of thumbs-up votes a proposal receives is just 1, and the 90th percentile is just 16, though the tail is quite long (details in figure 3). This aligns with the initial weights proposed above, but changing the incentives will also change community behavior. We may adjust the weights, or introduce logarithmic scaling if virality turns out to be a problem. Furthermore, we are working on a more detailed contributor ladder that should give a more robust basis for contributor weighting if and when it gets adopted. Finally, giving more weight to approvers is an easy place to start, but we want to expand this system to reward and incentivize many forms of active participation in the project, not just code contributions.
Figure 3. A sorted value plot, showing the number of “thumbs-up” votes received by every proposal ever filed. 1.4% of proposals have more than 100 votes and are not shown here. Four proposals ever (0.07%) have had over 1,000 up-votes.
Aside: Votes in the current backlog
While we don’t formally use emoji votes for anything today, that doesn’t mean the community hasn’t been providing input this way. A few existing proposals are clearly at the top and are sure to be picked up soon after we adopt vote-based prioritization. That’s okay. However, several of those proposals are actually feature requests that don’t meet the criteria for a Ready proposal, though there are concrete proposals buried within them. Part of this transition will be cleaning up that distinction and pulling concrete proposals out of these umbrella issues as sub-issues that can be reviewed as proposals.
There’s intentionally no downvoting mechanism, such as counting “thumbs-down” emoji, because we don’t want to actively encourage downvoting or enable negative brigading that could suppress controversial but valuable discussions.
When a proposal review committee is ready to take on another proposal—that is, to move it from Ready to Active—we select randomly by weight from the Ready proposals. If there are any Ready proposals given next major priority by the triage group, then this selection is limited to those. Because urgent proposals bypass this lottery entirely, and next major proposals move to the front of the queue, critical and release-blocking work is always fast-tracked. For general proposals, this probabilistic approach means high-priority proposals are very likely to be selected for review, while also ensuring low-priority proposals have some chance of getting reviewed, rather than being permanently starved at the bottom of a strict queue.
Scaling proposal review through multi-track review
The proposal review committee is clearly a bottleneck in the current system. Increasing its throughput would require either spending less time discussing each individual proposal, having everyone spend more time on proposal review, or adding more people. While some proposals could certainly stand less discussion, we don’t want to sacrifice the quality of outcomes, and we’re all too busy to spend more time on proposal review. However, adding more people to the single proposal review committee would almost certainly run headlong into Brooks’s Law, increasing communication and consensus overhead and reducing throughput. Hence, I propose we split proposal review into multiple tracks by subject area. In a way, we already have multiple tracks with the Go language change committee and the Go command working group, and these work well for those domains. This would formalize and expand on that. Initially, we propose the following tracks, though these will evolve as the project’s needs change:
- Language changes
- Go command
- Static language tooling (
go/*,x/tools, etc), compiler, core language facilities (reflect,sync,hash,maps,slices,unique,weak, etc), algorithms (math,sort,containers/*) - Security & cryptography (
crypto/*), production surface (net/*,encoding/*,log, etc), reliability (testing, race detector, etc), dynamic diagnostics (runtime/metics, pprof, etc)
The triage process will select a finer-grained track (such as “static language tooling”) so we can rebalance the proposal review committees as necessary, while still keeping the number of meetings reasonable.
Some proposals are likely to move through multiple committees. For example, language change proposals often touch on the compiler, runtime, and/or language tooling, so they may start in the language change track, but then also pass through another track before acceptance.
In addition to better scaling the proposal review process, the other goal of multi-track review is to create the capacity to invite more of the Go contributor community into the proposal process. We believe creating tracks will enable this without simply bogging down the process.
The proposal review process
Each proposal review track can have its own specifics, but by default the group for each track will meet for one hour, once per week, to discuss, review, and respond to Active proposals.
Urgent proposals enter the Active state directly from triage, and get reviewed first in a session. However, we assume that, most of the time, there won’t be any urgent proposals.
Urgent proposals aside, to prevent head-of-line blocking, we divide our weekly meetings into distinct timeboxes based on controversy: 15 minutes for trivial proposals, 20 minutes for minor proposals, and 25 minutes for substantial and contentious proposals. This is exactly like having an express lane at the supermarket: low-controversy proposals get dedicated time so they don't get stuck waiting behind a single contentious proposal (like a massive language change) that requires weeks of debate. In fact, the proposal review committee has been using a controversy metric for active proposals for the past year and it seems to help move smaller proposals along faster once they enter discussion.
Within each timebox, we discuss Active proposals in a random order. If we get through all of the Active proposals in a controversy level before the end of the timebox, then we bring in a new Ready proposal for the same track and controversy level, using the probabilistic priority scheme described above. This approach intentionally limits the number of Active proposals at any given time to roughly how many can be discussed in one session and to keep from overwhelming reviewers with too much context. Of course, discussion times vary, so committees are unlikely to get to every Active proposal in every session. That’s okay, and the random order within each timebox is meant to reduce bias here. We may explore other ways to mitigate oversized Active sets in the future.
Proposal review committees are allowed to use their discretion to bypass priority-based selection, but this is meant as an escape hatch. They are generally expected to follow the system. If such overrides happen often, then we need to revisit the system.
The discussion of each proposal aims to either make a decision, pose a question to be further discussed on the issue, or determine an action item. After each proposal is discussed, the committee should post a summary of the discussion to the proposal issue, along with their question(s) or action item(s). If the follow-up is expected to take a long time (for example, it requires some non-trivial redesign of a proposed API), the committee can put a proposal on “hold” to indicate that they’re waiting on some bigger follow-up action and will check in periodically to see if that’s been done.
Aside: The queueing theory behind this process
This controversy-partitioning scheme borrows the basic insight from Size Interval Task Assignment (SITA) in queueing theory. In SITA, incoming jobs are assigned a work estimate, which is used to partition jobs across servers so one server handles all of the “quick” jobs, another handles all of the “long” jobs, etc. Proposal review timeboxes serve the purpose of multiple servers. SITA is well-suited to heavy-tailed work distributions, which is certainly true of the proposal process, as shown in figure 4. One way the proposal process clearly diverges from SITA is that reviewing a proposal is not a run-to-completion job—it frequently blocks on someone else’s turn—so we keep multiple “jobs” going at once. At the same time, we don’t want too many active proposals at once lest we encounter the human equivalent of cache thrashing. Hence, we combine SITA-style partitioning with an adaptive admission control scheme.
*Figure 4\. The time that proposals spend in review is heavy-tailed, as shown by this cumulative distribution of days spent in review for proposals decided in the past three years.*
The role of proposal review itself remains the same. This is currently described as: “The principal goal of the review meeting is to make sure that proposals are receiving attention from the right people, by cc'ing relevant developers, raising important questions, pinging lapsed discussions, and generally trying to guide discussion toward agreement about the outcome. The discussion itself is expected to happen on the issue tracker, so that anyone can take part. The proposal review meetings also identify issues where consensus has been reached and the process can be advanced to the next step.”
If a proposal review committee recommends declining a proposal, it will be publicly marked as “likely decline” for at least five days (often seven) for final comments. The next session will check for substantive arguments on the proposal issue and, barring such arguments, will mark it as “declined.”
If a proposal review committee recommends accepting a proposal, they:
- Update the proposal issue with a self-contained write-up of the final proposal (or a link to a clear write-up already on the proposal issue) and optionally an overview of rationale and alternatives considered,
- mark the proposal “likely accept”, and
- send the proposal to a “final review” group.
The final review group’s role is solely to check for design uniformity across the entire Go platform. They are not there to reevaluate the technical merits of a proposal, and are expected to trust the track committee’s domain expertise. Once a proposal has been in “likely accept” for at least five days without substantive arguments, and is approved by the final review group, it moves to “accept.”
Once we have more experience, we’ll reevaluate the final review step. Initially, this is a hedge against switching to multi-track review, to make sure we don’t lose our current single point of broad visibility. It also mirrors the process for the current language change and go command groups, which in practice either decline proposals or recommend that the main committee accept them. The final review group will meet weekly at first, but may switch to an asynchronous process or we may find it’s simply unnecessary.
Trivial proposals follow a more lightweight process and bypass final review. However, if they aren’t moved to “likely accept” or “likely decline” in one session, then they get moved to the minor controversy timebox for later sessions.
Implementation
We foresee three components to implementing this updated process: documentation, transition tooling, and automation.
For documentation, we will update https://github.com/golang/proposal#readme (which has drifted quite a bit from the process we follow even today), establish a proper GitHub issue template for filing general proposals, and refresh the issue template for language change proposals.
For transition tooling, we will build one-off tooling to transition our proposal state into GitHub issue fields. This will replace our current proposal state-related issue labels and the proposal project. Issue fields are far more structured and remain searchable. We plan to do this before building new automation because the existing automation is relatively simple, so it should be easier to change the existing automation and then build the new automation from a clean slate.
Much of this updated process will be made possible by more sophisticated automation.
Currently, the proposal process is managed through a Google Sheet plus a combination of tools that sync information to and from GitHub. While this sheet is the source of truth, essentially all information in it gets exported to the proposal minutes issue, the proposal project, and automated posts and label updates to individual proposal issues. The whole process is quite clunky and error-prone and clearly won’t scale to multiple tracks or a more complex queueing approach. We’ve been through many versions of this process, tracked variously through spreadsheets, docs, and GitHub projects. General-purpose tooling never really fits what we need.
Hence, we intend to build a dedicated system for the proposal process. There will be a triage interface for the triage group, a review interface for the proposal review committees, and likely a public dashboard with an overview of proposals and their states. Like now, all decisions and “permanent state” will be captured in GitHub. We will continue to automatically post updates to a proposal minutes issue, but will probably merge the different tracks into a single issue. The proposal system itself will only store “transient” state, such as triage votes before the decision threshold has been reached, or draft proposal review state during a review session.
Conclusion
The proposal process is essential to Go's success, but it needs to scale with the community. By formalizing triage, bringing community-driven prioritization to the backlog, and enabling parallel review tracks, we can create a sustainable, scalable process that is more transparent and community-informed. These refinements preserve the core values of the Go proposal process while ensuring we can continue to evolve the Go ecosystem effectively. I look forward to feedback on this approach and to iterating on these mechanics together.
Acknowledgements
Thank you to the many, many people who have weighed in on this proposal, from my initial spit-balling to the crafting of this text. Special thanks go to Robert Griesemer, Mateusz Poliwczak, Damien Neil, Alan Donovan, Ian Lance Taylor, Michael Pratt, and Sean Liao.