Repository navigation
Roadie
Roadie answers one question: is my staging a safe copy of production? It copies production to staging with every customer pseudonymised, live payment and mail keys swapped for test keys and cron, webhooks and mail turned off. Then it reads the finished copy, checks it and signs a pass or fail report. It also makes a staging copy that another tool already made safe in place. This page explains where Roadie fits, what it changes and how it works.
rhythm roadie demo # a built-in shop: plan, copy, verify; no network, about a second
rhythm roadie plan --from shop.sql --to staging.sql # every change a copy would make; nothing changes
rhythm roadie copy --from ssh://deploy@shop.com/var/www/shop --to /var/www/staging --url https://staging.shop.test
rhythm roadie prepare /var/www/staging # make a staging that WP STAGING or a host panel made safe
rhythm roadie verify /var/www/staging # check any staging copy: real people, live keys, side effectsRoadie ships as its own binary (rhythm-roadie). You normally run it through rhythm roadie (or the short alias rhythm ro): rhythm roadie and rhythm-roadie are the same command. Install it with rhythm install roadie (rhythm v0.9.0 or later); see Install. Run rhythm roadie on its own in a terminal and it asks what to do: copy, prepare, verify, plan, the demo or a config file.
Generic data masking tools don't know WordPress. WordPress staging tools don't remove your customers. Roadie does both and proves it, in one free, local binary.
Important
Use Roadie only on sites you own or are authorised to copy. A pseudonymised copy is still personal data under the GDPR (Article 4(5), Recital 26): order totals, dates, products and anything Roadie can't recognise in free text stay. Keep copies and reports as protected as the live site. Never push a staging database back to production: its customers are fake. See Security and limits and Responsible use.
| Tool | Asks | Looks at |
|---|---|---|
| Tuner | Is my site safe? | what an attacker can find |
| Soundcheck | Did my change break anything? | what visitors see and do, by mouse and by keyboard |
| Echo | Is my site still saying what it should? | everything the site sends |
| Roadie | Is my staging a safe copy of production? | the copy you test on |
| Sightread | What will this update really change? | the code an update brings |
They work on the same change. Tuner says a plugin needs updating and Sightread reads the update before you install it. Roadie gives you a staging copy to install it on, with no real customer in it, no live key and nothing that can send. Soundcheck shows what the update did to the pages and Echo what it did to the messages: the copy Roadie makes sends its mail to Echo. The last line of every copy suggests rhythm echo up, then rhythm soundcheck run <url>. copy --soundcheck runs Soundcheck on the copy for you.
| What | Page | |
|---|---|---|
| 👤 Pseudonymises people | Users, customers, orders, addresses, comments, order notes, form entries, mail logs, Action Scheduler arguments and session data. Each real person gets one fake everywhere, inside PHP serialized and JSON values too. Fakes use reserved domains and fictional phone ranges, so they can never reach anyone. | Pseudonymisation, Profiles |
| 🔑 Swaps live keys | Stripe, PayPal, WooPayments, Square, Braintree, Mollie, Razorpay, Adyen, Klarna, Authorize.net, Flutterwave, SendGrid, Mailgun, Postmark, SES, Twilio, Jetpack and more, in the database, wp-config.php and .env. A live key becomes the test key you set, or is blanked. WordPress salts and Laravel's APP_KEY are regenerated. |
Live keys |
| 🔇 Turns side effects off |
WP_ENVIRONMENT_TYPE=staging, the Echo seal for mail, WP-Cron, Action Scheduler, WooCommerce webhooks, gateways to test mode, Subscriptions staging mode, Jetpack offline, the AutomateWoo queue, Laravel's queue and mailer, plus noindex and a crawler block. |
Kill switch |
| 🔗 Rewrites URLs | Production's URL to staging's in every form (https://, //, www., JSON-escaped, URL-encoded), inside serialized values with their lengths fixed. Multisite hosts by map. |
Copy and prepare |
| ✅ Proves it | Every copy ends with a verify that reads what was written, never what Roadie believed it changed. In exact mode it checks that no production value it replaced survives anywhere, in eight encodings. The result is a signed report anyone can check. | Verify and reports |
Roadie knows WordPress (single and multisite), WooCommerce (legacy and HPOS), Action Scheduler, Subscriptions, AutomateWoo, Gravity Forms, WPForms, Contact Form 7 with Flamingo, Ninja Forms, Fluent Forms, MailPoet, Easy Digital Downloads, MemberPress, LearnDash, five mail logging plugins, Laravel with Cashier and any SQL schema you describe. rhythm roadie profiles lists them.
-
Before you test on a copy of production.
copyfrom a dump, a site folder,ssh://, a WP-CLI@aliasor a database, to the same kinds of target. Nothing real is written to your disk on the way. -
After WP STAGING, WP Migrate or a host panel made a staging.
preparefixes it in place, after a backup. -
After a plugin update on staging.
prepare --only side-effectsputs the kill switch back without touching the data. -
To check any staging, or a dump someone sends you.
verifylooks for real-looking people, live keys, production URLs and side effects that are still on. With--from <production dump>it checks every real value exactly. - Every night in CI. The GitHub Action refreshes staging from production, verifies it and fails the job when something is left. See CI.
-
For an auditor or a client. The signed report says what was checked, what wasn't and who ran it.
report checkproves it wasn't changed since.
Roadie doesn't copy files or uploads, edit web server config, clear Redis or search indexes, or block outbound traffic at the host. The plan names each of these when it applies; Security and limits lists them all.
flowchart LR
P["production<br/>dump, site, ssh://,<br/>@alias or DSN"] -- "read-only" --> I["pass 1: index<br/>schema, people,<br/>URLs, stack"]
I --> G{"guards<br/>is the target<br/>production?"}
G -- "no" --> K["kill switch<br/>files first"]
K --> T["pass 2: transform<br/>fakes, keys,<br/>URLs, side effects"]
T --> S["staging<br/>dump, site, ssh://,<br/>@alias or DSN"]
S --> V["verify<br/>reads the copy"]
V --> R["signed report<br/>.roadie/reports/"]
-
Read production, read-only. A site's database credentials come from
wp-config.phpor.env, read as text: PHP never runs. Over ssh, Roadie runs only a fixed list of read commands (the list). A stream that must be read twice is spooled encrypted with a key held only in memory. - Index. Pass 1 reads the schema and every personal value, detects the stack, the profiles and production's URLs. It builds the set of real values exact mode checks for.
-
Refuse production. A target that matches
production:, is the source, or says it is production is refused before anything is written. A site or database target needs a typed confirmation, or--confirm-targetin CI. -
Kill switch first. On a site target,
wp-config.php,.envand the mu-plugins are written before the import starts, so nothing can send while it runs. - Transform and write. Pass 2 streams the rows through the rules to the target: a dump file written atomically, or a database import. A dump is never piped to a database client: only allowlisted statements are re-emitted (dump safety).
-
Verify. The copy is read back and checked. The report is signed with your key and written to
.roadie/reports/.
Roadie keeps its settings in .roadie/config.yaml (commit it; it never holds a secret) and writes everything else next to it: signed reports under .roadie/reports/<UTC time>Z-<command>-<target>/, prepare backups under .roadie/backups/, the consistency key in .roadie/key when you keep one and basic-auth snippets in .roadie/basic-auth/. Inside a git repository those four paths are added to .git/info/exclude. The report signing key lives in your config folder (~/.config/rhythm/roadie/signing.key on Linux). See Configuration.
| You want to… | Read |
|---|---|
| Try it, then make your first copy | Getting started |
| Understand copy, prepare and plan in detail | Copy and prepare |
| Copy from ssh, an alias or a database | Sources and targets |
| See what each plugin's rule changes | Profiles |
| Know what a fake looks like and how keys work | Pseudonymisation |
| Swap live keys for test keys | Live keys |
| Know what is switched off and how to undo it for a test | Kill switch |
| Read a verify and check a signed report | Verify and reports |
| Copy a Laravel app, your own schema or a network | Laravel, Generic SQL and Postgres, Multisite |
| Refresh staging every night | CI |
| Look up a setting or a flag | Configuration, CLI reference |
| Know what Roadie promises and can't do | Security and limits, FAQ |
| Fix an error | Troubleshooting |
← Benchmark · Home · Getting started →
rhythm · Useful ideas. Working systems. · Check only sites you own or have permission to test. Keep staging sealed (responsible use) · This wiki is published from wiki/ in the rhythm repository; suggest changes there with a pull request.
Get started
rhythm in depth
Tuner
- Overview
- Your first scan
- Reading results
- Choosing checks
- Requests and politeness
- Output and reports
- Batch scans
- Local scans
- Integrity and malware
- Changes and notifications
Tuner in depth
- Known vulnerabilities
- PHP advisories
- CI and code scanning
- GitHub Action
- Config file
- Watch and serve
- Writing checks
- Check packs
- Finding reference
- CLI reference
- Coming from Wordfence CLI or WPScan
- FAQ and troubleshooting
Soundcheck
- Overview
- Your first check
- Reading results
- Review and accept
- Discovery
- Page health
- Visual changes
- Interactions
- Forms and flows
- Cache
- Speed
- Accessibility and SEO
- EAA mode
- Keyboard walkthrough
- Accessibility statement
Soundcheck in depth
- CI
- CI baselines and PR comments
- Configuration
- Error rules and exec
- WordPress updates
- Fleet and client reports
- History
- Import from BackstopJS and Lost Pixel
- Firefox and WebKit
- CLI reference
- FAQ and troubleshooting
- Benchmark
Echo
- Overview
- Your first run
- Connectors
- Sealing staging
- Echo Inbox
- Messages and checks
- Checks and rules
- Attachments
- Actions and compare
- With Soundcheck
- Replay
- Deliverability
Echo cookie consent
Echo in depth
- Docker and DDEV
- Agency hub and reports
- Schedule
- MCP server
- Conformance kit
- CI
- Configuration
- API
- CLI reference
- FAQ and troubleshooting
- Benchmark
Roadie
- Overview
- Getting started
- Copy and prepare
- Sources and targets
- Profiles
- Pseudonymisation
- Live keys
- Kill switch
- Verify and reports
Roadie in depth
- Laravel
- Generic SQL and Postgres
- Multisite
- CI and the GitHub Action
- Configuration
- Security and limits
- CLI reference
- Troubleshooting
- FAQ and honest limits
- Benchmark
Sightread
- Overview
- Your first review
- Signal reference
- Allow and baseline
- Sources and integrity
- With Soundcheck and Roadie
- Watch
Sightread in depth
- CI and the GitHub Action
- Configuration
- Output and reports
- Security model
- CLI reference
- FAQ and honest limits
- Benchmark
Project