Skip to content

v1.0.0

Latest

Choose a tag to compare

@juanmaguitar juanmaguitar released this 14 Aug 13:45
· 1 commit to trunk since this release
eb3acb3

WordPress Contributor Toolkit v1.0.0

The toolkit is a desktop app that takes a contributor from nothing to a working wordpress-develop checkout, lets them try the patch that already exists on a Trac ticket, and lets them send their own work back — as a file, as a mentor handoff, or as a real pull request — without leaving the app and without a push credential on disk.

It is built for the person sitting down at a Contributor Day with no local WordPress environment and two hours to spend.

What earns the 1.0 name is the second half of that sentence. Earlier releases stopped at a running development site; the contribution itself happened somewhere else. It now happens in the app. Everything below is what changed since v0.1.2, across one beta and two release candidates.

A site ready for work: Start dev server, Start build watch, Review & submit changes, the Trac ticket panel and the patch panel


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 setup checklist running clone, install and build as one continuous chain

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).

A site listing the tickets that have work stored in it, most recently used first

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.
  • 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. A ticket closed wontfix years ago no longer reads exactly like one filed last week.
  • The ticket's pull requests, listed and applyable (#136). Newest first, each with its state and date, in GitHub's own colours (#243) — green OPEN, purple MERGED, red CLOSED, where red is a label and not a warning. 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 .diff attached 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/.patch with Apply…, non-patches shown but marked as such.
  • "Latest" means newest commit, not most recently touched (#140, #281). The pill is meant to point you at the freshest fix across both lists, 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.
  • Ticket reading is harder to fool or strand (#300, #333). A freshly linked ticket no longer leaves "Reading ticket…" stuck; historical Trac ticket: 56320 citations count as real pull-request links while incidental number mentions do not; and a Trac navigation that never finishes reaches the 90-second timeout and cleans up its hidden window instead of leaving the renderer waiting forever.

A linked Trac ticket showing its details and the pull requests that reference it

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.json moves so an install runs before the rebuild. The applied patch is recorded so it can be reverted after a restart, and the revert control tells the truth when there is nothing left to revert (#189).
  • Apply a PR straight from a pasted URL or number (#142), without it having to be linked to the ticket.
  • New or deleted empty files survive the round trip (#315, #322), including the /dev/null side a Git-format patch needs for an addition or a deletion.

The patch preview listing the files a patch touches before anything is applied

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.

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.
  • 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, so 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 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. The branch survives and the ticket stays linked; only its work is rewound.
  • Discard explains why it is unavailable (#330), naming 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 one preserves the error and its recovery information.

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.
  • 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 submission screen: the diff first, with the GitHub pull request, Trac attachment and mentor-handoff destinations beside it

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 running and then do nothing. A patch that does move the lockfile, or a trunk reset, still needs the build directory and node_modules to 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.

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 running which/where. A site's folder can be opened while it is still being cloned (#212).
  • Debug your WordPress code (#217). The blueprint sets WP_DEBUG, WP_DEBUG_LOG, WP_DEBUG_DISPLAY, SCRIPT_DEBUG and WP_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.
  • Adminer sits with the other running-site destinations (#268): site URL · wp-admin · Adminer, leaving the action row for actions. And a wp-admin link sits beside the site URL (#250) in both the checklist step and the site page — the app used to show you admin / password next to a screen it gave you no way to reach.

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.
  • Line endings are handled without changing repository policy (#342). The Windows CRLF workaround is now an in-memory view given to isomorphic-git when no local value is set, instead of core.autocrlf=true written into every managed repository's config on every platform. An explicit local choice passes through unchanged, and nothing writes .git/config.

The three-step progress panel for updating a site to the latest trunk

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 — so Ready! 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.
  • "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.
  • Clearer and safer on every platform: the editor opens with a visible window on Windows (#201), and main.js is held to using windowsHide only 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); it says which files need a rebuild and why (#210) and points contributors at the terminal for a rebuild or reinstall (#187); it stops promising a dark mode the window does not have (#206); it 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.md and .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).
  • The CI package cache no longer breaks packaging (#265). No branch had produced a signed macOS or Windows artifact for a while, because the cache lived inside the checkout and electron-builder tried to package it.
  • The guide and its screenshots match the shipped 1.0 workflow (#310, #334, #336, #337, #339), including applied layers, failed-apply recovery, ticket bases, the submission destinations, the GitHub device-code step, captured mail and the recovery states — plus the recommendation to create your first site at home before a Contributor Day rather than on the venue's shared connection.

Changes since v1.0.0-rc.2

  • Line-ending compatibility no longer rewrites repository config (#342) — the one behaviour change.
  • Documentation: submission-workflow screenshots (#336), recovery states and captured mail (#337), preparing sites before a Contributor Day (#339).

Downloads

Full changelog from v0.1.2: v0.1.2...v1.0.0

Changes since v1.0.0-rc.2: v1.0.0-rc.2...v1.0.0


Found something broken, or something that could be clearer? Use the feedback button in the app, which opens this feedback form, or file it directly with the issue templates. The app has no telemetry, so feedback and issues are the only signal the project gets about where it helps and where contributors still get stuck.

Contributions are welcome too: the toolkit is maintained in the WordPress organisation, and CONTRIBUTING.md is the map of what runs on every pull request and what is expected before one is opened.