Classes, class packs and member balances for a US yoga, Pilates or boutique fitness studio, priced in US dollars. You own the records and run the app in your Cloudflare account. Payments stay with your existing processor. MIT licensed. First release; the product contract is the full studio system it is growing into.
The owner guides start at Getting started; the run site serves them at /docs.
Strap's run site is live at https://run-strap.com. To run it locally, install Git, then follow the same two steps as https://run-strap.com/run. Node is not required.
-
Install the launcher:
curl -fsSL https://runeditrun.com/install.sh | shBefore step 2, make the installed command available in this terminal:
export PATH="$HOME/.local/bin:$PATH" rer cli path
Run the shell startup line that
rer cli pathprints soreris also available in new terminals. The installer does not change your shell startup file. -
Clone and start Strap:
rer dev just-every/run-strap
To start it again later, run cd run-strap && rer dev.
For people who already have Node 22 or later, this is an alternative:
npx -y @runeditrun/rer dev just-every/run-strapRER installs the pinned dependencies and Node 22.20.0, builds the app, migrates local D1 and prepares an owner. First launch can take several minutes. Open the private RER_OPEN link printed in the terminal, confirm the owner and click Finish setup. Keep that link private. RER_READY is the ordinary app address. A repeated rer dev resumes or reuses the running app. On a busy Mac, RER may refuse when its 15-second process-ownership inspection times out; retry the same command. This is a launcher limitation, not a completed launch.
For your own owner email, run rer install just-every/run-strap, then from the checkout rer setup --owner-email [email protected] and rer dev. Local development sends no external email. The server keeps running in the background after the command returns; stop it with rer dev --stop. If you explicitly launch with --foreground, Ctrl-C stops that foreground process. If a saved port is occupied, run rer dev --port 8899 with an available port. Never expose local development publicly.
- Open People. Add an instructor with role
instructorand members with rolemember; activate them, then Invite to sign in. Invites establish native sessions, and only the owner grants access. To use a second local browser profile, open the terminal's privateRER_OPENlink there first, then sign out. In the second profile, open/signinand choose the invited person’s one-click sign-in. Local owner access uses the private launch link; local member access uses these invitations. Hosted email sign-in uses the configured mail sender. - Open Studio (the location under the logo) and save the studio's location and time zone. Open Packs and payments. Prepare a pack for a member with its credits, price in dollars and how long it is good for, review it, then approve. The approved amount becomes owed; no card is charged. Record payments only after receiving them through your processor, with a unique receipt reference. Credits and money balances are separate.
- Open Classes. Prepare a Monday-starting week, one row per class: name, room, day, start time on the studio's clock, minutes, spots and instructor. Review the exact draft, then publish it. Times show in the studio's time zone, the US way ("Tue, Oct 20 · 6:00 am"). For a recurring timetable, open Repeating timetable → Prepare repeating classes, then choose its date range and repeat interval. Review and publish the exact occurrences before members can book; publication does not create an endless schedule. A published class cannot be silently edited.
- Sign in as a member. Acknowledge the current waiver if the owner has published one, then book a class. A full class adds the member to its waitlist without spending a credit. Cancellation before start returns the booked credit once and promotes the first eligible waiting member with a valid credit. Members see their own balances and bookings. An assigned instructor opens Today and checks attendees in from the class roster.
- An owner can prepare a balance reminder and review its exact wording and balance before approving the text export. Balance reminders remain reviewed text exports. Owners can configure class reminder email timing in Studio; member opt-out keeps in-app notices, and failed or unavailable email creates a private follow-up task. SMS and push reminders are not available. Strap does not collect payments. Agent commands can prepare drafts, while native human owner sessions approve them.
- Import accepts the documented Mindbody member CSV shape. Paste the synthetic fixture, preview, review and apply the unchanged CSV. Imports start inactive with no credits or charges. The journal retains original source and supports resume and conflict-preserving undo.
Deactivate a person in People to revoke studio access immediately. Revoke preparation keys in Agent access and integration keys in Integrations. Waiver acknowledgement records receipt of the exact version; it is not a legal signature. The unused-identity erasure shortcut and verified owner privacy requests are documented in People and access. Supported used and imported member records can be redacted with explicit financial and document retention decisions. Unsupported related work is refused. Erasure blocks the same identity from being recreated or imported.
Stop the app, and keep exports private:
rer dev --stop
rer export --output exports/strap.rerRestore into a fresh clone of the same revision before setup or entering data:
rer install just-every/run-strap
cd run-strap
rer import --input /private/path/strap.rer --yes
rer setup --owner-email [email protected]
rer devThe original owner/member identities, classes, packs, bookings, payments, approvals, waiver acknowledgements, import originals and journals travel. Sessions, sign-in links, agent keys, integration keys, provider credentials and the development outbox do not. Re-enter private configuration and sign in again. Setup uses the archived owner's email. Damaged archives and populated destinations are refused. After erasure, restore the current post-erasure archive. An older archive plus a later --journal may be refused with erasure_epoch; the journal is an erasure fence, not a guarantee that older data can be recovered. --input accepts an absolute archive path, but this launcher requires --journal to name a file inside the destination checkout, such as exports/LATER.rer. See Backup and restore for that limited path. Offline older backups cannot discover later erasure; protect and retire old copies. rer reset --yes destroys local data and settings; export first if needed.
No domain or provider account is needed locally. For hosting, use your own Cloudflare Workers and D1 account and verified mail sender. Resource identities in wrangler.jsonc and deploy.json stay stable. Provide MAIL_FROM as your verified sender address. Required private deployment inputs are CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN, OWNER_EMAIL, SESSION_SECRET, SETUP_TOKEN, MFA_KEY and MAIL_API_KEY; supply them through your secret manager. Assisted hosting can select Resend, SendGrid or Cloudflare Email Sending in rer-setup.json. Cloudflare also needs MAIL_ACCOUNT_ID. Managed hosting assigns MAIL_PROVIDER, MAIL_FROM and MAIL_RELAY_URL and provisions the private MAIL_API_KEY; the sender passes the assigned relay URL. Local development suppresses external delivery. Never put secrets in arguments or source. Commit intended configuration changes before deploying.
rer dev --stop
rer deploy --dry-run --owner-name "Your name"
rer deploy --owner-name "Your name"Stop local development before deploying: it owns the local state while it runs. Dry run validates and builds, then reads the target secret bindings from Cloudflare. It requires CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN; without them it exits with a credentials error after the local build. Nothing is deployed by a dry run. Real deployment provisions resources, applies migrations, uploads secrets and checks health. It claims the configured owner and retires the setup token. Open the returned workers.dev origin and sign in by email. A custom domain is optional. rer signin provides owner recovery when mail is not working yet; then correct the sender/email configuration. This round verifies local runtime and dry-run behavior; real provider delivery and hosted acceptance remain unverified.
Package mode pins @runeditrun/[email protected]. The committed Base foundation was c7cb0613120074c5ffca63f610533802afbda6bd. Source adaptation, operations, agent guide.
pnpm run test:strap
pnpm run test:archive
pnpm run typecheck
rer verifyIntegration tests use real workerd/D1, native invitations/sessions and public HTTP commands, plus the public archive CLI. Build/deploy never run tests. One sharded Verify workflow runs per push commit; the separate lane runs the stranger journey.
The mark is a sea-glass stability ball with a plum band (public/brand/mark.svg; mark-dark.svg for dark grounds; hand-tuned favicon-16.svg and favicon-32.svg). The run site's look (Playfair Display headings in plum, Figtree text, white and sea-glass grounds) has its tokens in public/site/theme.css. The app's tokens are in public/rer-theme.css (the faces and the theme tokens rer's reader takes) and public/fonts/fonts.css (the rest), Strap's shared app components in public/brand/strap.css, which also dresses Base's sign-in and setup frames, and the app layout in src/strap/ui/style.ts.
rer build --site writes the static run site to dist/site: the homepage (src/site/landing), whose Run Strap opens /run, Base's Run page with the commands in src/site/run.json, and the docs rendered from docs/*.md in the order docs/site.json gives. An installed Strap serves the Lobby at / instead. rer dev serves the run site too and prints its address as RER_SITE; open its /run page for the local install commands. .github/workflows/run-site.yml publishes it to the domain in deploy-site.json only when the repository variable RUN_SITE_DEPLOY is true.
Configure STRIPE_BILLING_TEST_KEY as an installation secret and STRIPE_BILLING_WEBHOOK_SECRET as the signing secret for the Stripe endpoint at /api/strap/billing/webhook. Credentials never appear in the app or portable archives. In Studio settings, an owner with second-factor verification reviews the merchant ID from their own Stripe dashboard and its readiness. A changed credential requires another review of the same merchant. Disconnect keeps all history; restoring an archive requires a fresh review and never reauthorizes historical stored methods.
From Packs, the owner starts a one-time USD card payment for an approved, wholly unpaid plan. The payer enters their own card in Stripe-hosted checkout. Pending or uncertain outcomes are retained; another request never creates a second session. Reconcile with Stripe reads the canonical session, payment intent, captured charge and generated invoice before recording the actual receipt. Stripe can finish its invoice after returning from checkout; review the exception and reconcile again once Stripe has issued it. Existing plan access stays unchanged. Household billing, partial external receipts, recurring autopay and refunds remain their separate contract work.
The exception queue retains unmatched events and failed comparisons. Configure the endpoint for checkout completion and expiry, payment-intent success and failure, and invoice payment events. Signatures and account identity are checked before processing; signed event payloads alone never settle money. The network-edge suite exercises replay, ordering, missing events and forged envelopes. node tests/payments-sandbox.mjs runs the held-key live TEST journey through the injector; it completes hosted card checkout and deliberately replays real Stripe events with a controlled local signing secret. It does not claim external endpoint delivery.