From signed up to live, one owner per step

Onboarding

9 of 11 clients stuck for over a year never paid a cent, and 59 of 85 live clients have no owner recorded. Nothing below starts before payment, and every step has a name attached.

Owner: Pau · Checked Sep 8, 2026

The checklist

1

Payment confirmed

Setup fee cleared in Stripe. Nothing else on this list starts before this is checked.

Hanz
2

Client assigned an owner

One name recorded against the client record before any build work. This is the field that's empty on 59 of 85 live clients today.

Hanz
3

Site type & tier selected

Personal, Podcast, or Business (see Pricing), plus templated vs. custom theme.

Hanz
4

Content collected & site built

Initial articles, About/Home/Contact copy gathered, site built and shared back for the client's review. Moving an existing site? Follow Site Migration.

Tori
6

Launch gate passed, Live Site email sent

GSC, Plausible, and Bing all confirmed working (see the gate below), then send the Live Site template.

Pau

Launch gate: don't call it live until:

  • Google Search Console is verified for the domain.Included in the $299 setup, see Pricing.
  • Plausible Analytics is installed and recording pageviews.Check the Plausible dashboard shows live traffic, not just "site added".
  • Bing Webmaster Tools + IndexNow are set up.18 of 85 live sites currently never got this. It depends on someone remembering, which is why it's a gate now, not a step to trust.

Moving an existing WordPress, Webflow or Substack site onto our platform

Site Migration

The goal is simple: the client loses no traffic. Every URL Google knows about either still works on the new site or 301-redirects to the right new page, and every post and photo comes across. Work the 9 steps in order. Each item has a short line under it saying why it matters.

Owner: Pau · Checked Oct 14, 2026

The 4 rules that matter most
  • Keep the exact same slug wherever our structure allows it. Never "clean up" a slug.
  • A URL with traffic or backlinks never gets dropped. At minimum it gets a 301.
  • Nothing may point to the old site. No images, files or links on the old domain or old CDN, because they break when it shuts down.
  • The client doesn't cancel the old platform until the day-30 check passes.

The checklist at a glance

1

List every URL that matters

One master sheet of old URLs, ranked by traffic and backlinks. Details ↓

Before build
2

Map each old URL to a new one

Same slug, or a 301. Details ↓

Before build
3

Move the posts

Title, slug, body, original date, SEO fields. Details ↓

Build
4

Move the photos & files

Full resolution, re-hosted on our media. Details ↓

Build
5

Inventory everything else

Pages, nav, DNS & email, tracking, forms. Details ↓

Build
6

Pre-launch checks on the preview URL

Counts match, redirects work, nothing points to the old site. Details ↓

Before launch
7

Cutover

Content freeze, then switch the domain. Details ↓

Launch day
8

Verify on the live site

Same day, then days 3, 14 and 30. Details ↓

Day 0–30
9

Hand over & log it

Trello comment, client preferences, URL sheet saved. Details ↓

Day 30

Step 1 · List every URL that matters (before touching the CMS)

  • Get Google Search Console access.Ask the client to add ash@nickgray.net as a Full user. GSC is the most important source: it shows which pages actually get clicks and links.
  • Export from GSC: Performance → Pages (last 16 months), Indexing → Pages (indexed and not indexed), and Links → Top linked pages.The pages with clicks and outside links are the ones that cost rankings if they break.
  • Grab the old sitemap (/sitemap.xml or /sitemap_index.xml).The full list of what the old site says it has.
  • Take a backlink snapshot. Ask Claude for /vs3-backlink-snapshot.Keeps a record of which URLs other sites link to.
  • Crawl the live site.Catches pages that are linked but missing from the sitemap.
  • Copy the old site's existing redirects.We have to keep these. WordPress: Redirection plugin, Yoast Premium, Rank Math or .htaccess. Webflow: Site settings → Publishing → 301 redirects. Substack has none.
  • Merge it all into one master URL sheet, remove duplicates, sort by clicks + backlinks.Columns: old_url · type (post / page / category / tag / author / media / other) · GSC clicks · backlinks · new_url · action (same slug / 301 / drop) · migrated? · verified?. The top 20–50 rows get checked by hand after launch.

Step 2 · Map each old URL to a new one

  • Keep the same slug wherever possible.Posts and pages both live at the root, /{slug}/, not under /blog/. See How our URLs work below.
  • Give every URL whose shape can't exist here its own 301.Example: /2019/05/my-post/ or /p/my-post → /my-post. There are no wildcard rules, so it's one row per old URL. Use the platform cheat sheets below.
  • Fill new_url and action for every row.Anything with traffic or backlinks gets "same slug" or "301", never "drop".
  • Check for slug clashes between pages and posts.If a page and a post share a slug, the page wins and the post disappears.
  • Substack only: was it on the client's own domain?If it lived on name.substack.com, we can't redirect it. Tell the client and have them link the new site from their Substack about page and last post. Also agree before cutover what happens to the newsletter.

Step 3 · Move the posts (top priority)

For every post, carry over:

  • Title and slug, exactly.Slug comes from the URL sheet. A changed slug is a broken URL.
  • Full body: headings, lists, bold/italic, quotes, tables, and embeds (YouTube, Vimeo, tweets, Spotify, podcasts, Instagram).
  • Original publish date.Never let it default to today. Google and readers both rely on dates.
  • Cover image, excerpt and categories.
  • SEO title and meta description, plus the social (OG) image if it differs from the cover.Pull them from Yoast / Rank Math, Webflow SEO settings, or Substack's SEO fields.
  • Noindex stays noindex.If a page was hidden from Google on the old site, keep it hidden.
  • Ask the client about drafts and paywalled posts.Drafts are left out by default. Paywalled Substack posts export with the full text, so the client decides whether they go public.

For whoever runs the import: posts with images or quotes go in with pw create (Lexical upload nodes), because pw article publish rejects them. --publish-at schedules an import. After any pw patch, run pw deploy <slug>, because patching doesn't deploy on its own.

Step 4 · Move the photos & files (top priority)

  • Download every image at full resolution, not the resized thumbnails.WordPress: the originals in /wp-content/uploads/ (drop the -300x200 size endings). Webflow: the website-files CDN. Substack: substackcdn.com. Webflow images can vanish once the client cancels, so download them first.
  • Upload them to our media and point every reference at our copy.Nothing in the content may still load from the old domain or CDN.
  • Alt text, captions and photo credits come across.Where alt text is missing, ask Claude for /vs3-alt-text.
  • Downloadable files: PDFs, lead magnets, slide decks.These often have backlinks. Check them in GSC.
  • Logo, favicon, headshots, hero image.Neon and marquee themes fall back to the logo as the hero background when there's no hero image.
  • Image URLs that rank in Google Images or have backlinks get a 301 to the new media URL.
  • No oversized photos.Body photos are capped at 700px. Check with /seo-images or PageSpeed.

Step 5 · Inventory everything else (go through it with the client)

This is the list that's easy to miss.

Site structure

  • All static pages: About, Contact, Speaking, Media/Press, Work With Me, Now, Books, Podcast, Testimonials.
  • Header and footer navigation, in the same order.
  • Footer content and legal pages: copyright, social links, Privacy, Terms, Disclaimer, affiliate disclosure.
  • Pages the client wants retired.Write them down. They still get a 301.

SEO

  • Meta titles and descriptions on pages too, not only posts.
  • Schema (Person, Organization, Book, Podcast).Rebuild it through the tenant fields / extraJsonLd.
  • Canonical tags that point elsewhere (cross-posted content) and any robots.txt customisations.
  • Internal links inside posts point to the new paths.Rewrite /blog/x, /p/x, /2019/05/x links directly. Don't rely on redirects for our own links.

Domain, DNS & email (where most migrations break)

  • Export all the client's current DNS records before switching nameservers: MX, SPF/DKIM/DMARC, CNAMEs for email tools, Calendly, etc.Re-create them with pw dns, or the client's email stops working.
  • Keep the Search Console verification TXT record.If it's lost in the move, the client loses GSC access.
  • Run pw domain add first, then send the nameserver pair it returns.Cloudflare can assign a different pair per domain, so never send a pair from memory. See Domains & DNS.
  • Note who holds the registrar login (client or us).

Tracking & integrations

  • Analytics and tags (optional): GA4, Google Tag Manager, Meta Pixel, LinkedIn Insight, etc.Not every client has these. Only carry over what the old site already uses, and add it with our deferred-loading pattern so it doesn't slow the site. We confirm it works after launch (step 8).
  • Newsletter signup form: which provider (ConvertKit, Mailchimp, Beehiiv, Substack) and the form embed code.We only connect their existing form to the new site. The client keeps managing their list and newsletter in their own tool, so we don't export or move subscribers.
  • Contact form destination, booking widgets (Calendly, SavvyCal), payment and affiliate links, and any custom header/footer code.

Facts

  • Run /fact-check on the bio, About page and any claims before the site goes live.
Tell the client up front, we don't carry these over: blog comments (we can export them for their records), membership areas, paywalls, shops, and plugins with no equivalent here. List the plugins and decide each one with the client.

Step 6 · Pre-launch checks (on the preview URL)

  • Post count matches the old site, minus any agreed drops.
  • Every row in the URL sheet has a new_url and an action.
  • Nothing still points to the old domain or CDN.Search the content export: pw content-export <slug>.
  • No slug clashes between pages and posts.
  • All redirects are created (pw get redirects), and none lead to a 404 or chain through another redirect.
  • Top 20 posts compared side by side with the old site: images, embeds, formatting, dates.
  • Key pages checked on mobile.
  • WordPress sites: run /vs3-migration-diff <slug>.It diffs the URLs, tests the redirects, checks that images load, and recovers images at risk.

Step 7 · Cutover

  • Agree the date and time with the client (Manila time).
  • Content freeze.Anything the client publishes on the old site after the export has to be migrated too, so ask them to stop posting there.
  • Switch the domain, then re-create the DNS records from step 5. Ask Claude to "add a custom domain".Nameserver mode is the default. A site that hasn't changed within about 3 minutes of a build is normal.
  • Keep the old site reachable for at least 30 days (WordPress: at old.<domain>).It's the fallback and the image source if anything was missed. The client must not cancel it yet.

Step 8 · Verify on the live site (the live site is the truth)

Same day

  • Every URL in the sheet returns a 200, or one 301 that lands on a 200.Script it over the sheet and fill in the verified? column.
  • Top 20–50 traffic URLs checked by hand.
  • www redirects to the main domain.
  • Email still works.Send a test to the client's address.
  • Plausible is recording pageviews, and the client's own analytics and pixels (if they have any) are firing.This is where tracking gets confirmed, after launch, once real traffic hits the new site.
  • Forms submit (including the newsletter signup), and /sitemap.xml lists the new URLs.
  • The launch gate is passed: GSC, Plausible, Bing + IndexNow.

In Search Console

  • Submit the new sitemap.
  • Request indexing (URL Inspection) on the top 10–20 pages.
  • No "Change of Address" needed when the domain stays the same.Only use it if the domain itself changed.

Days 3, 14 and 30

  • Watch GSC → Indexing → Pages for "Not found (404)" spikes.Add a redirect for anything that shows up.
  • Compare GSC clicks and impressions with the pre-migration baseline.A small dip in weeks 1–2 is normal. A drop that stays on specific URLs means a bad redirect.
  • Run /audit <slug>, then /vs3-seo-audit.
  • Day 30 with no issues: the client can shut down the old platform.

Step 9 · Hand over & log it

  • Comment on the client's Trello card (Nick + Pau board): what moved, how many redirects, anything dropped, follow-ups.
  • Save the client's standing preferences in the CLAUDE.md at the root of their site-* repo.
  • Store the master URL sheet with the client's files.It's the record that nothing was lost.

Reference · How our URLs work

Plan every redirect around these rules.

WhatURL on our platformNotes
Home/
Posts/{slug}/At the root, not under /blog/.
Pages/{slug}/Also at the root. If a page and a post share a slug, the page wins.
All posts/blog/
Category/category/{slug}/
Anything elseA redirectRedirects collection in Payload. 301 by default.

Redirects: matching ignores capitals and trailing slashes. Chains get flattened automatically and loops are rejected. Saving one rebuilds the site. The target can be a path or a full URL. No wildcards, so every old URL needs its own row. Use pw for everything, never raw REST or curl.

Reference · Platform cheat sheets

WordPress
Old URLWhat to do
/my-post/Already matches. Same slug, no redirect.
/2019/05/my-post/Slug my-post + 301 from the dated path.
/blog/my-post/Same slug + 301 from /blog/my-post.
/category/x/Matches. Create the category with the same slug.
/tag/x/We have no tags. 301 to the closest category, or /blog/.
/author/name/301 → /about/.
/page/2/Only if GSC shows traffic. 301 → /blog/.
/feed/301 → our feed if the theme has one, otherwise /blog/.
/?p=123Ignore. Query strings can't be matched, and WordPress already pointed these at the real URL.
/wp-content/uploads/…Only redirect images that rank or have backlinks (step 4).

After import, ask Claude for /wp-migration-setup. Keep the old WordPress alive at old.<domain> during the transition.

Webflow
Old URLWhat to do
/blog/my-postSame slug + 301. The prefix might be /post/, /articles/, etc. One row per post.
/about, /contactSame slug.
/blogMatches our /blog/. Any other prefix (e.g. /articles) gets a 301 → /blog/.
/category/xCreate the category with the same slug, 301 if the path differs (e.g. /blog-categories/x).

Images live on website-files.com and can disappear when the client cancels Webflow. Download everything first.

Substack
Old URLWhat to do
/p/my-postSame slug + 301 from /p/my-post.
/archive301 → /blog/.
/aboutSame slug.
/podcast, /s/{section}Map to a page or category, then 301.

Redirects only work if the Substack was on the client's own domain. Moving that domain disconnects it from Substack, so agree the newsletter plan first. Export the posts via Settings → Exports (posts come as HTML). The subscriber list stays with the client.

Copy → Paste → Send

Email Templates

Every client-facing template lives here, grouped by where it fires in the lifecycle. Hit Copy to grab the subject and body together.

Owner: Hanz · Checked Sep 8, 2026

Sending rule: generic, no-personal-touch client email (status updates, credentials, cancellation) goes out from Ash. Anything tied to a specific person's relationship with the client (a call follow-up, a domain question routed to Pau) sends from that person.

Site Launch

Live Site

Send once the domain is confirmed pointing to the new site: see Point to Nameservers below for how to get there.

SubjectYour site is live!

Hi [Name],

The domain now lives under the site we've built! You can view it here → [site URL]

Please disregard any email notification you might receive about a published article on your site while we finish polishing things up.

If there's anything you'd like changed or updated, let us know and we'll work on it.

Fires: after the launch gate passesFrom: AshThen: archive the onboarding checklist

Point to Nameservers

Always the default path. We pull the client's existing DNS into our system first, so nothing (especially email) breaks during the swap. See Domains & DNS for the Cloudflare backup.

SubjectPoint your domain to your new site

Hi [Name],

Now that we've finalized the site and it's ready to go live, we need your help pointing your domain to the site we built. Please update the nameservers on your registrar (I believe that's [registrar, e.g. GoDaddy]) to these two:

- nia.ns.cloudflare.com
- vasilii.ns.cloudflare.com

We've already pulled in your existing DNS records, so email and anything else pointed at the domain will keep working through the switch. If you need a hand, book a call with Pau here → https://cal.com/team-nick-pau/10min

Thank you!

Fires: once the site is built and ready for the domain switchFrom: PauThen: run the launch-gate checks in Onboarding

Cancellation

Client Ending Service

Client ending their PersonalWebsites.org service.

SubjectWe're sorry to see you go

Hi [Name],

Thank you so much for letting us know; it has been great working with you.

Are you planning to host the site on your end? If so, we're happy to keep hosting it for one more month for free so you have time to get set up and confirm the site is live on your end before switching nameservers/DNS. If not, we're happy to take the site down right away.

We've also attached the ZIP file containing all your posts, pages, and media. Please note that the themes are not included in the export.

If there's anything else you need help with, just let us know.

Fires: client confirms they're ending serviceFrom: AshThen: Mo produces the ZIP export

Open question: is the free extra month of hosting still policy, and does Mo still produce the ZIP export? Neither has been reconfirmed recently. Check with Pau/Mo before leaning on this template for an edge case.

Sales & Calls

Intro / New Sales

Blocked: Nick needs to confirm whether this is Hanz's or his to own before it gets written. See the open question on this page.

Blocked on Nick

Login Credentials

Never send a password in plain text over email. This template sends a reset link instead.

SubjectYour PersonalWebsites.org login

Hi [Name],

Here's how to get into your site's backend:

Login page: [admin URL]
Email: [client email]

We don't send passwords by email. Click "Forgot password" on the login page and it'll send you a reset link directly.

Let us know if you get stuck.

Fires: client asks for backend accessFrom: AshThen: nothing, one and done unless they lock themselves out

Monthly Call

Cadence is set by the client's tier: see Pricing (Basic is quarterly, Pro/Premium/Legacy are monthly or weekly).

SubjectBooking our check-in call

Hi [Name],

Time for our regular check-in! Grab a slot that works for you here:

[booking link]

A few things to think about before we chat:
- Any updates, wins, or new content ideas since we last spoke
- Anything on the site you'd like changed

See you soon!

Fires: per the client's call cadenceFrom: Tori (content) or Hanz (account)Then: log notes on the client's card

Thanks for The Call Today!

Hi! Thanks for the call today. I enjoyed our chat.

Please send me the following just like we discussed on the phone:

I'll circle back once everything is completed.

Fires: right after any client callFrom: whoever took the callThen: wait on the client's reply

You Missed Our Call Today

Hi,

Just wanted to follow up as it looks like we missed each other on our scheduled call today.

I totally understand today might have gotten busy: it happens. At your earliest convenience, you can grab a new time that works best for you here:

[your booking link: see the Calendar Links in Resources]

Looking forward to chatting whenever it's convenient for you.

Fires: client no-shows a booked callFrom: whoever the call was withThen: wait for rebooking

Buying, adding, transferring

Domains & DNS

DNS came up 59 times in two months, the loudest thing in the company. It's always the nameserver path. The Cloudflare account is a backup, not a second option to pick between.

Owner: Pau · Checked Sep 8, 2026

The two nameservers

Send these with the Point to Nameservers template. Before you send it, pull the client's existing DNS into our system first. That's what keeps their email and anything else on the domain alive during the switch.

nia.ns.cloudflare.com
vasilii.ns.cloudflare.com
nia.ns.cloudflare.com vasilii.ns.cloudflare.com

After the client says it's done, check:

  • Both nameservers resolve on the domain (registrar lookup or dig NS <domain>).
  • Existing DNS records survived, especially MX/email. This is why we pull them in first, but confirm it actually held.
  • SSL certificate issued and the site loads on the client's own domain, not just the personalwebsites.org staging URL.
  • Launch gate passed: GSC, Plausible, Bing (see Onboarding) before sending the Live Site email.

Backup path · Cloudflare account access

Only when the nameserver swap stalls

Add Nick as admin on the client's Cloudflare account

We manage DNS directly on the client's behalf instead of waiting on them. This is a fallback, not a client-comfort judgment call. It isn't reached for by default.

Open setup guide →

2026: VS3 Monthly Packages

Pricing

Setup fees and monthly tiers by site type, pulled from the packages doc, plus where clients sign up.

Owner: Pau · Checked Sep 8, 2026

Open question: is the Custom Theme's "from $1,000" on top of the $299 setup fee, or the total? The page currently reads as $1,299 total; our records say $1,000 is the total. This needs Nick to settle before it's quoted again. Check with him before promising a number.

Personal Website

4 monthly tiers

One-time

Setup Fee $299
  • Plausible Analytics
  • Google Search Console
  • Payload CMS & Astro front-end, 10+ themes
  • 2–4 initial articles from your content
  • Home, About & Contact pages
  • robots.txt + sitemap.xml
  • Bing setup + IndexNow support
Custom Theme from $1,000
  • Full site redesign from your inspirations
  • Up to 3 revisions

Monthly plans

Basic $29/mo

Best for: staying visible with minimal effort

  • Hosting + all current & future themes
  • 30-min check-in call per quarter
  • 1–2 custom articles / quarter
  • 1× monthly curated short-form post
  • Basic SEO + light link building
  • Ongoing technical support
Pro $99/mo

Best for: original insights & growing SEO authority

  • Hosting + all current & future themes
  • Launch strategy call with our writer
  • 30-min check-in call / month
  • 2–3 custom articles / month
  • 2× bi-weekly curated short-form posts
  • Custom featured images per article
  • Premium SEO + basic link building
  • Custom landing pages
  • Ongoing technical support
Premium $199/mo or $299/mo
  • Hosting + all current & future themes
  • Launch strategy call with our writer
  • Weekly 30-min check-in call
  • 4 custom articles / month
  • 2× bi-weekly curated short-form posts
  • Custom featured images per article
  • Premium SEO + basic link building
  • Custom landing pages
  • Ongoing technical support
Legacy Premium Confirm still sellable $299/mo

Best for: full personal-brand content support

  • Hosting + all current & future themes
  • Launch strategy call with our writer
  • Weekly content call
  • 1 long-form + 2 short-form articles / week
  • Ongoing curated short-form publishing
  • LinkedIn + newsletter content support
  • Premium SEO, optimized for AI/LLM visibility
  • Fast, priority support

Podcast Website

1 monthly tier

One-time

Setup Fee $299
  • Plausible Analytics
  • Google Search Console
  • Payload CMS & Astro front-end, 10+ themes
  • 3 initial show-notes pages from recent episodes
  • Home, About & Contact pages
Custom Theme from $1,000
  • Full site redesign from your inspirations
  • Up to 3 revisions

Monthly plans

Basic $49/mo

Best for: staying visible with minimal effort

  • Hosting + all current & future themes
  • 30-min check-in call per quarter
  • 2 show-notes pages / month (1 new + 1 backdated until caught up)
  • Basic SEO + light link building
  • Ongoing technical support

Business Website

1 monthly tier

One-time

Setup Fee $299
  • Plausible Analytics
  • Google Search Console
  • Payload CMS & Astro front-end, 10+ themes
  • 3 initial articles from your content
  • Home, About & Contact pages
  • Integration with basic CRMs or chat bots
Custom Theme from $1,000
  • Full site redesign from your inspirations
  • Up to 3 revisions

Monthly plans

Pro Biz $199/mo
  • Hosting + all current & future themes
  • Launch strategy call with our writer
  • 30-min check-in call / month
  • 1–2 custom articles / month
  • 2× bi-weekly curated short-form posts
  • Custom featured images per article
  • Premium SEO + basic link building
  • Ongoing technical support

Active Discount Codes

CodeDiscountNotes
FRIENDS200OFF $200 off One-time, setup fee
VIP200 $200 off One-time, setup fee
FRIENDS300OFF $300 off One-time, setup fee
FRIENDS100OFF $100 off One-time, setup fee
CHERYLANN50 $50 off One-time, setup fee
TOMGRUNDY50 $50 off One-time, setup fee

Pulled from Stripe coupon screenshots in the doc: all fixed amounts off, applied once, against the one-time setup fee. Stripe's internal promo_… API IDs and live redemption counts are left off this page; check Stripe directly before relying on redemption limits.

Design library

Themes

12 themes in the catalog today, named below so this answers something on a client call. Custom builds are tracked in the CMS, not on this page.

Owner: Pau · Checked Sep 8, 2026

Custom builds: a hand-kept list of custom-theme sites used to live here. It went stale twice after a bulk theme refresh wiped it. The real source of truth is the tenant's CMS record (siteType: custom plus excludeFromBulkRefresh), not a list on this page. Check the CMS, or run an audit, before quoting or touching a site as "custom."

Everything else

Resources

Backend access, calendar links, content rules, content topics, what's already automated, and the affiliate program.

Owner: Pau · Checked Sep 8, 2026

Client-Facing Guides

How to login / use backend

Not written yet

Content Rules

Every piece of client-facing or published content follows three rules:
1. Facts only: no invented stats, quotes, or claims.
2. Fact-check before publishing: verify against the source, don't assume.
3. No em dashes: use a period or colon instead.

Already Automated

These already run through Claude, so ask for them instead of redoing them by hand.

Ask forWhat happens
setup and audit <tenant>Fills positioning fields, sets theme/nav/hero, then runs the full onboarding QA and fixes mechanical issues
add a custom domainConnects, verifies, or removes a domain via Cloudflare, either nameserver or dns-records mode
audit <tenant>Finds broken links/images, missing alt/OG/meta, migration junk, stale WP URLs
publish this article for <client>Ingests a Google Doc, writes SEO metadata, uploads the hero image, publishes, verifies live
customize <tenant>'s hero/homepageHand-edits the tenant's Astro repo without breaking future theme refreshes
seo audit / seo checkFull-site or single-page SEO analysis with a prioritized fix list
blog audit / rewrite blogScores existing posts, replaces fabricated stats, fixes formatting and schema
fix hero photo on mobileReframes a cropped hero portrait per-tenant, survives theme refreshes

Not the full list. There are 47 of these skills. Ask "what can you automate for X" if what you need isn't above.