v1.0.0-rc.2
Pre-releaseWordPress Contributor Toolkit v1.0.0-rc.2
This is the second release candidate for 1.0. The first candidate went back onto real ticket work, and this is what that testing found: an applied patch is now treated as somebody else's named layer instead of as contributor-owned work; patch failures distinguish the contributor's edits from stale upstream code; older ticket bases are explained honestly; and the ticket readers no longer miss historically linked pull requests or spin forever on a stalled Trac load.
It is still a pre-release. Please try it on a real ticket and report anything that breaks: use the feedback button or the installation-bug issue template.
The changes since v0.1.2 are below.
New since v1.0.0-rc.1
Applied work stays attributed to its author
- An applied patch is a named layer, not an undo blob (#318). The app keeps the patch or pull request's identity while a contributor works on top of it, so Revert removes that layer without pretending the contributor authored it.
- A contributor cannot submit somebody else's applied work as their own (#332). Attributed or published submission stays blocked while an external patch or pull request remains applied. An unattributed Save a copy remains available as the recovery path.
- A failed apply says whose work is in the way (#313). When a pull request fails in a file the contributor edited, the explanation names that local work instead of automatically blaming the pull request author and asking for a rebase.
- Conflict warnings are measured against the ticket's base (#302), not against its most recent parked save. A contributor's own saved work no longer disappears from the collision calculation.
Ticket bases tell the truth
- The app says when a ticket's original base is unknown (#317) instead of quietly substituting current trunk and presenting a guess as history.
- A ticket created from older trunk gets a clear warning (#323). Updating the site does not silently rebase existing ticket work; the notice explains that patches may no longer apply and points to the existing safe exit when a fresh base is needed.
- Discard explains why it is unavailable (#330). Both discard entry points now name the operation that must finish or stop first, instead of looking inert.
- A successful discard clears the patch error it resolved (#331), while a failed discard preserves the error and recovery information.
Patch files keep empty additions and deletions
- New or deleted empty files survive patch generation (#315), including the
/dev/nullside required for additions and deletions. - Git-format empty-file sections are read correctly (#322), so applying such a patch does not silently omit the file whose content happens to be zero bytes.
Ticket loading is harder to fool or strand
- Freshly linked tickets no longer leave “Reading ticket…” stuck (#300). The scrape generation now advances before the automatic read begins, so its completion is still recognized.
- Historical
Trac ticket: 56320citations count as real links (#333), while incidental number mentions and longer ticket numbers remain excluded. - A Trac navigation that never finishes reaches the existing 90-second timeout (#333) and cleans up its hidden window instead of leaving the renderer waiting forever.
Smaller fixes around the contribution flow
- Adminer sits with the other running-site destinations (#268): site URL · wp-admin · Adminer, leaving the action row for actions.
- Local coding-agent directories stay out of generated patches and pull requests (#36). Managed sites receive precise per-repository exclusions for Claude Code, Codex, Cursor, Windsurf, Gemini CLI and Cline files; existing exclude rules and tracked files are preserved.
- The guide and screenshots match the final 1.0 ticket workflow (#310, #334), including applied layers, failed-apply recovery, ticket bases and the current setup interface.
New since v1.0.0-beta.1
Setup runs itself
- The initial checklist is one chain, not four clicks (#246). After the clone finishes, install and build now start on their own and run to the end — the shape the app already used for a trunk update and for a patch apply, applied to setup at last. Walk away during a ten-minute clone at a Contributor Day and you come back to an environment you can work in, not to a checklist waiting on you.
- Stop can end a running
npm install(#274). Nothing in the app could, because a running install lived in a different registry than the one Stop consulted. That never mattered while install was reached by a button; it is the condition that makes running it unattended reasonable. - A step says "Ready", not "In progress", until its action actually runs (#258). Install npm dependencies used to announce itself as in progress while nothing was installing — which reads as "the app is already doing this" and invites you to wait instead of to click.
- "Start here" points at the one thing to do next (#252, in #254 #256 #260 #263). One tested resolver decides the single pending action for the current state and the matching block gets an accent ring, a pill and a scroll into view — through setup, and afterwards across the update banners, the dev-server and review buttons, the ticket panel, a running apply, and a staged patch preview. It is announced to screen readers as Next step: …, and it clears when the action completes, not on a timer.
The build watch is its own thing
- The build watcher has its own button, its own status and its own log (#247). It used to share one lifecycle with the PHP server: no state of its own, no output of its own, and — because it held the terminal's "running" lock for its whole life — it silently blocked every one-shot action while it ran. Now it starts and stops on its own, next to the dev-server button, with a dot that means something: green watching, amber building, red an unexpected exit, grey stopped. Its output goes to a Build watcher tab instead of into the terminal. Starting the server still auto-starts the watch; stopping the server leaves it running, so you get compile-on-save without a server.
- Applying a patch and updating trunk lean on that watch instead of fighting it (#262). A patch that does not move the lockfile, with a watch running, is applied and left for the watch to rebuild — no build of its own, no interruption. That is the case that used to print
A command is already runningand then do nothing. A patch that does move the lockfile, or a trunk reset, still needs the build directory andnode_modulesto itself, so the watch is paused for the duration and resumed after — with the PHP server up throughout. Update to latest trunk no longer requires stopping the dev server first.
When a patch will not apply
- The refusal says how much failed, why, and what to do next (#282). It used to name one file and stop — the same sentence whether one region of twenty missed or all twenty did, which are opposite decisions for the contributor. Now every failing region reports why: its surroundings changed, or its change looks already present, told apart by whether the region's reverse fits. Each carries the lines it wanted to make and a searchable anchor line verified to exist in your file — because a hunk's own line numbers are coordinates in the file as the patch author had it, and on an old patch they miss by exactly the drift that made it fail. The apply itself is unchanged: still all-or-nothing, still nothing written to the checkout.
- "Latest" now means newest commit, not most recently touched (#281). The pill is meant to point you at the freshest fix, and it was ranked by GitHub's
updated_at— which a comment, a label or a bot sweep bumps as hard as a push. On Trac #62064 an upstream force-push of trunk restamped roughly 2,580 open pull requests inside one window; the two on that ticket landed 19 seconds apart in that sweep, and the app crowned the one whose newest code is from November 2024 — which no longer applies — over the one from April 2026, which does.
What the ticket actually says
- A linked ticket shows its own facts (#292). Summary, status, resolution, type, milestone, component, keywords and age, read off the same embedded Trac page the attachment list already uses — same one-time human check, no second challenge. The status pill folds the resolution in, because "closed (fixed)" and "closed (wontfix)" are opposite instructions to a contributor. Component and keywords are links, using Trac's own query URLs lifted from the page. A ticket closed
wontfixyears ago no longer reads exactly like one filed last week. - Discard all changes rewinds the ticket to its base (#270). On a ticket-linked site it appeared to do nothing: the modal shows your work diffed against the ticket branch's base, so it includes the parked WIP commit — but discard only reset the tree to the branch HEAD, keeping that commit, and the modal reloaded identically. It now rewinds to the same base the diff is taken against. The branch survives and the ticket stays linked; only its work is rewound. Throwing the branch away is still what Delete this ticket's work is for.
Quieter, clearer, more accessible
- Completed actions are confirmed by an accessible toast (#253). Patch saved, trunk updated, patch applied, pull request opened, working tree reset — these used to complete silently or leave an inline sentence you may not have been looking at, and none of the success notices reached a screen reader. One service now carries them: success announces politely and dismisses itself, an error announces assertively and stays until dismissed, a double-click reads as one notice, and a confirmation for an action taken inside a modal is still seen.
- The log panes read as consoles (#280). One font shared with the terminal, so the columns of a PHP stack trace line up, and colour by severity per line —
fatal · warning · deprecated · notice · trace · ready— soReady! WordPress is running on …no longer has the same weight as four repeated deprecation warnings above it, and a fatal no longer sits in the same wall of grey as a notice. - A wp-admin link beside the site URL (#250), in both the checklist step and the site page. The app showed you
admin/passwordnext to a screen it gave you no way to reach. - "Forget this site" is gone (#266). It was sold as the safe exit — the guide said outright that forget is reversible, delete is not — and it was the one menu action with no way back: it dropped the path from the registry and left the checkout on disk with nothing in the app able to readopt it. It comes back when a site can genuinely be added back.
- The CI package cache no longer breaks packaging (#265). No branch had produced a signed macOS or Windows artifact since the last version bump, because the cache lived inside the checkout and electron-builder tried to package it. This is why there is an rc.1 to download at all.
Everything from v1.0.0-beta.1 (new since v0.1.2 )
The headline of the beta was that the patch flow goes both ways: you can pull the work that already exists on a Trac ticket into your checkout and test it, and you can send your own change back — as a file, as a mentor handoff, or as a real pull request — without leaving the app.
Work more than one ticket in the same site
A site is the expensive part — a clone of wordpress-develop, an npm install, a first build. A ticket is the cheap part.
- Every linked ticket gets its own branch inside the site (#108, #168), so moving between tickets is a file swap of seconds rather than another clone and another install. What you edited for one ticket is not in the tree while you are on another, and the patch you submit for a ticket contains only that ticket's changes.
- The site's tickets get their own card (#185, #242) — Other tickets on this site while one is linked, Your tickets on this site when none is, most recently used first — so coming back does not depend on remembering a number.
- A switch narrates itself (#205): saving your work on the ticket you are leaving, checking which files change, swapping files with a percentage, ready. A half-finished swap marks the site and refuses further ticket actions rather than leaving you to discover it.
- Edits made before you picked a ticket are asked about, not decided for you (#238, #218), because trunk is never committed to; and the unsubmitted-changes note counts a ticket's whole work, parked commits included (#241).
- Pull request states are coloured in GitHub's own colours (#243) — green OPEN, purple MERGED, red CLOSED, where red is a label and not a warning.
Try the work already on a ticket
The Contributor-Day failure this prevents: several people writing overlapping patches because none of them could see anybody else's.
- A site knows which Trac ticket it is for (#123). Asked optionally at creation — "What are you working on?" — or set, changed and cleared later, surviving restarts. Parsing accepts what a contributor actually pastes: a bare number,
#12345, or any core Trac URL with an anchor, trailing slash or?format=still attached. - The ticket's pull requests, listed and applyable (#136). Newest first, each with its state and date; Apply… fetches that PR's diff into the preview → apply → rebuild flow.
- The ticket's Trac attachments too (#139). On many good-first-bugs the patch is a
.diffattached to the ticket, not a PR. Because Trac serves the attachment list only to a real browser, one click opens the ticket in an embedded window, you clear the proof-of-work challenge once, and the app scrapes the list into a native view — each.diff/.patchwith Apply…, non-patches shown but marked as such. - A "Latest" pill marks the most recent patch across both (#140), PR or attachment.
Apply a patch, then rebuild
- Choose a patch file → preview → apply and rebuild (#135). The preview lists the files the patch touches, flags collisions with your own edits, names binary files it will skip, and says whether
package-lock.jsonmoves so an install runs before the rebuild. The applied patch is recorded so it can be reverted after a restart. - Apply a PR straight from a pasted URL or number (#142), without it having to be linked to the ticket.
- Honest empty state (#189): the revert control tells the truth when there is no patch left to revert.
Send your change back
- The patch flow names its destinations, each with its real cost (#166). Attaching to Trac saves the file and deep-links this site's ticket attach page; nothing is uploaded, no account is asked for. Create patch, because it makes a file, it does not submit one.
- Mentor handoff, zero accounts (#166). The saved patch carries a provenance header — handle, event, ticket, base revision, date — so someone else can push it and the props still land on whoever wrote it.
- Open a pull request from the app, with no push credential on disk (#179). Device-code sign-in, then fork, commit and pull request through GitHub's API. Nothing is written to disk and the token is forgotten on quit. The OAuth application belongs to the WordPress organisation, so no contributor sees an individual's name on their consent screen. Verified end to end on macOS and Windows against
wordpress-develop, with checks running and props-bot picking the PRs up. - Every pull request gets a testable description a reviewer can read in five minutes (#170), with a notes field placed above the paperwork (#204). Two facts from the core handbook a first-timer cannot guess are stated inline: PRs on GitHub are not monitored and must be attached to a Trac ticket to be considered, and nothing is merged on GitHub — which is why the flow ends by sending you back to Trac.
- The destinations are grouped by who does the sending (#200), and the diff sits first, with the destinations beside it (#207), because the code is what you opened the screen to look at.
Open and debug your code without leaving the app
- Open in editor and Show in Finder / Explorer / file manager on every site (#158). First use offers a picker of the editors found on the machine; after that the button names the editor and launches straight through. Because a packaged app does not inherit the shell
PATH, detection stats absolute install locations rather than runningwhich/where. - Open a site's folder while it is still being cloned (#212).
- Debug your WordPress code (#217). The blueprint sets
WP_DEBUG,WP_DEBUG_LOG,WP_DEBUG_DISPLAY,SCRIPT_DEBUGandWP_DISABLE_FATAL_ERROR_HANDLER, so notices, deprecations,_doing_it_wrong()and — crucially — a real fatal surface as themselves instead of behind WordPress's recovery screen. The debug log gets its own tab, with the file's path, Show in folder, Copy and Clear.
Keep a site current
- Update to latest trunk, at any time, without recreating the site (#111). Sites used to be pinned forever to the trunk of the day they were cloned, so patches aged against a frozen snapshot and stopped applying on Trac. The site header shows "trunk as of <date>"; past 14 days an amber notice warns that patches you create may not apply, and Update to latest trunk in the ☰ menu re-fetches, reinstalls dependencies if they changed, and rebuilds.
Clearer, and safer, on every platform
- The editor opens with a visible window on Windows (#201), and
main.jsis held to usingwindowsHideonly where it belongs (#224). - The app shows the directory it created from the moment it creates it (#223), and says what actually went wrong when a folder will not open (#211).
- Only http and https addresses open externally (#121).
- Says which files need a rebuild, and why (#210), and points contributors at the terminal for a rebuild or reinstall (#187).
- Stops promising a dark mode the window does not have (#206).
- Refuses to delete a path that is not a registered site (#138), and the quit sweep covers all four child-process registries (#163).
Under the hood
- A LICENSE file and license metadata (#102), README badges for the latest release and total downloads (#101), and download counts recorded on a metrics branch (#103, #105), documented in
STATS.md(#106). - The agent-review setup moved to an agent-neutral standard in
AGENTS.mdand.github/instructions(#112, #125, #127) after the credential-carrying CI review was retired. - Substantial new test coverage around the IPC handlers, the child-process modules, logging and the trunk-update flow (#131, #153–#157), and the renderer bundle is no longer committed (#122).
Downloads
- macOS (Apple Silicon):
wordpress-contributor-toolkit-1.0.0-rc.2-mac-arm64.dmg - Windows (x64):
wordpress-contributor-toolkit-1.0.0-rc.2-win-x64.exe - Linux (x64):
wordpress-contributor-toolkit-1.0.0-rc.2-linux-x86_64.AppImage
Full changelog from v0.1.2: v0.1.2...v1.0.0-rc.2
Changes since rc.1: v1.0.0-rc.1...v1.0.0-rc.2
Changes since v1.0.0-beta.1: v1.0.0-beta.1...v1.0.0-rc.2