A podcast episode, start to finishPodcast Production
Three Claude skills that take one recording from a calendar invite to published show notes and cover art.
PodcastMEDIA
CreatorEric Melchor
Runs perEpisode
Skills3, chained
Time back~2 hrs / episode
Before — by hand2 h 30 m
Research, script, email, write-up, Canva — spread across four apps and two days.
After — with Claude30 m
Two short check-ins from Eric, one review pass, one manual step in Canva.
≈ 2 hours savedper episode — roughly a full working week back over a year of twice-monthly episodes.
Overview
What this card automates
The 3rd Space Bucharest podcast is short and casual — five to fifteen minutes, recorded over Google Meet with people from the community. The recording is the easy part. Everything around it is not: researching a guest well enough to ask a question they haven't answered fifty times, writing a script that sounds like Eric and not like LinkedIn, turning a rough set of AI meeting notes into publishable show notes, and appending two correctly-sized graphics to a Canva archive without breaking the layout.
Three skills cover that arc. Guest prep runs before the recording, show notes after it, and graphics after that. Each one is a written procedure Claude follows — not a prompt you retype every time. They read from the same Google Calendar, Gmail, Drive and Canva accounts Eric already uses, so nothing new had to be set up and nothing new has to be maintained.
Crucially, this is not a hands-off machine. Two of the three stages deliberately stop and wait for Eric, because the input only he has — what a guest told him at an event, which of two Canva archives is live — is exactly what makes the output worth publishing.
Before
How this used to get done
Per episode, by hand, across Calendar, LinkedIn, Google Docs, Gmail and Canva.
Research the guest. LinkedIn, their site, a search or two, hunting for one detail worth opening on.30 min
Write the interview script. Twelve-ish questions, a couple translated into Romanian, in the same format as every previous episode.35 min
Write the guest's heads-up email. Meet link, show format, five sample questions, pasted and re-edited each time.10 min
Write show notes. Read back the meeting notes, land on a title that isn't boring, write a description that isn't generic.30 min
Write the Instagram caption. Rework the description into short lines, then pick hashtags that aren't spam.15 min
Build the two graphics. Find a photo, add a page to each Canva archive, retype the title and byline, fix the episode number.30 min
Total, per episode≈ 2 h 30 m
After
The three stages, in order
Each stage is one skill. They run in sequence because each one needs what the last one produced — the graphics can't be made until the title exists.
1Before
Guest preppodcast-guest-prep
Turns a calendar invite into an interview script and a guest email, without Eric opening a browser.
Finds the next event titled podcast recording — 15 min between Eric Melchor and… and pulls the guest, their email and the Meet link.
Reads the bio the guest wrote themselves in the Cal.com booking notes — usually the best material available.
Reads the guest's LinkedIn PDF (summary, experience, awards only) and searches the web for one genuine contrast worth opening on.
Writes the full script as a .docx in Eric's established format — fixed intro, 10–14 short questions, two to four with a Romanian translation underneath, fixed outro — and files it in the Podcast Prep folder.
Drafts the casual “see you at 15:00 tomorrow” email in Gmail with the Meet link hyperlinked and five of the lighter questions previewed.
Waits for EricBefore researching anything, it stops and asks for two or three things about the guest that aren't findable online, plus a LinkedIn PDF. Nothing else happens until he answers — a script built without that is the generic one he'd have written himself.
2After
Show notes & captionpodcast-description
Turns the auto-generated meeting notes into a publishable title, description and Instagram post.
Finds the recording's notes doc in Drive by searching loosely rather than matching an exact title, because the title format drifts.
Checks the Podcast Descriptions folder for an existing write-up, matching on guest and date, since repeat guests exist.
Writes a title with a Bucharest or Romanian hook, plus two or three alternates — intriguing, not descriptive, under twelve words.
Writes a two-paragraph description in Eric's voice and an Instagram caption of four to seven short lines with 8–12 hashtags.
Saves it all as one Google Doc, then re-reads the doc to confirm the content actually landed.
Flags every timeAny guest link it couldn't verify, any detail it had to interpret from a vague passage in the notes, and whether the AI Circle link is still a placeholder.
3Publish
Episode graphicspodcast-graphics
Appends the square cover and the wide thumbnail as new pages on two existing Canva archives.
Works out which episodes still need artwork by diffing the show-notes folder against the pages already in the Canva archive.
Takes the recommended title and the guest's name exactly as the show-notes doc spells them, diacritics included.
Derives the episode number from the last page's byline rather than guessing it.
Appends one 3000×3000 page and one 1920×1080 page, sets the guest photo to 50% opacity, and places the title and byline text.
Still manualBackground removal on the guest photo happens in Canva by hand — the skill flags it rather than pretending it's done.
Stack
What it runs on
No new software. Every tool here was already part of the workflow.
Nine things that went wrong, and are now written down
Most of these were found the hard way. They live inside the skills as explicit warnings, which is the real difference between a skill and a prompt.
LinkedIn "Activity" is not their work
That section is mostly reposts and likes of other people's content. Treat it as the guest's own and you open the interview asking about something they never said.
Don't sharpen a vague line into a specific claim. If the notes say "themself" and "a client", it's because the AI didn't know — not an invitation to assign a gender, a number or a job title.
Already published once: a client described as "themself" went out as "her".
It mishears company names
Any brand or product name spoken aloud has to be cross-checked against a written source — usually the guest's own email domain.
One studio’s name came through as an acronym. The guest’s email domain gave away the real spelling.
Never build a URL from a spoken handle
Links get published under the guest's name and can't be retracted. A URL is only publishable if it comes from the invite domain, a verified site, or Eric.
3rdspacebucharest.com has been heard as "thirdspacerous.com".
Romanian diacritics break the matching
Drive filenames strip them, Canva pages keep them. GuestName and Guest Nâmé have to be normalised on both sides, or every guest with an accent in their name looks like a new episode forever.
Symptom: duplicate pages appended to the archive.
Repeat guests need a date, not a name
Matching on guest name alone silently skips a legitimate second episode with someone who's been on before.
Always match on guest and recording date.
The Canva byline is three text regions
A plain text replacement collapses them into one and destroys the superscript "rd" in 3rd Space. Two targeted find-and-replace operations are required instead.
Damage is invisible until the file is opened weeks later.
Google Docs can be created, not edited
The connector can make a file and trash it, but not change its contents. A doc with the wrong text has to be replaced, which clutters the folder.
Get it right before creating. One doc per run.
Episode numbers are derived, never guessed
The number comes from parsing the last page of the archive. If the two archives disagree, they've drifted — stop and ask rather than appending blind.
Also: two Canva designs with the same title means one is stale.
Copy this
The skills themselves
The whole thing, with every personal detail swapped for a {{PLACEHOLDER}}. Paste one into Claude and it will interview you and fill the blanks in before it runs anything — you never have to hunt through it for someone else’s folder names.
podcast-guest-prep/SKILL.md · template
---
name: "podcast-guest-prep"
description: "Prepares {{HOST_FIRST_NAME}} for an upcoming {{SHOW_NAME}} podcast recording. Finds the guest from his Google Calendar (events titled \"podcast recording - 15 min between {{HOST_NAME}} and {Guest}\"), pauses to ask {{HOST_FIRST_NAME}} for insider context and a LinkedIn PDF, researches the guest online, writes a full interview script as a .docx in the exact style of his existing \"{{PREP_FOLDER}}\" docs, and creates a Gmail draft of his casual \"see you tomorrow\" guest prep email (never auto-sent). Use this whenever {{HOST_FIRST_NAME}} mentions a podcast recording, a podcast guest, interview questions, prepping for a guest, \"who's my next podcast guest\", \"get me questions for [name/tomorrow's] interview\", \"send the podcast prep email\", or anything about his {{SHOW_NAME}} podcast — even if he doesn't name a guest, name a file type, or explicitly ask for \"a doc.\""
---
## Before the first run — set this up for yourself
**Claude: do this section before anything else.** This skill was written for a
different business and every personal detail in it has been replaced with a
`{{PLACEHOLDER}}`. Interview the person you're working with, one question at a
time, then rewrite this file with their answers and delete this section. Do not
run the workflow until every placeholder is filled.
- `{{HOST_NAME}}` — What's your full name, as it should appear as the host?
- `{{HOST_FIRST_NAME}}` — What should I call you in these instructions?
- `{{SHOW_NAME}}` — What's the podcast called?
- `{{HOST_EMAIL}}` — Which email address do you book and send from?
- `{{CALENDAR_EVENT_PATTERN}}` — What do your recording events look like in your calendar? Paste one title exactly as it appears.
- `{{BOOKING_TOOL}}` — How do guests book — Cal.com, Calendly, something else? Does the booking form ask them anything about themselves?
- `{{PREP_FOLDER}}` — Which folder should the interview scripts go into?
- `{{EPISODE_LENGTH}}` — How long is an episode, and how many questions do you want?
- `{{SECOND_LANGUAGE}}` — Do you want some questions translated into a second language? Which?
- `{{OPENING_LINE}}` — How do you open every episode? Give me the exact words.
- `{{OUTRO_LINE}}` — And how do you close it? Exact words again.
- `{{SHOW_VIBE}}` — In one or two sentences, what should a guest expect — fast and playful, or considered and deep?
If they don't know an answer yet, leave that placeholder in place and tell them
which one is still open — don't invent a value.
---
# Podcast Guest Prep
{{HOST_FIRST_NAME}} runs the {{SHOW_NAME}} podcast: short (5-10 min), casual interviews recorded over Google Meet. Before each recording he needs two things: an interview script for himself, and a light "see you tomorrow" heads-up email to the guest. This skill produces both from the calendar event plus whatever inside knowledge {{HOST_FIRST_NAME}} has about the guest.
## Step 1: Find the recording
Search the calendar (`search_events` with query like "podcast recording", or `list_events` with `fullText: "podcast recording"`) rather than assuming an event ID.
- If {{HOST_FIRST_NAME}} names a guest or a date, filter to that event.
- If this is running as part of the daily automated check, look for a recording starting in the next ~24 hours.
- Otherwise default to the next upcoming recording.
- If several candidates match, ask {{HOST_FIRST_NAME}} which one rather than guessing.
Real event titles follow this exact pattern: `{{CALENDAR_EVENT_PATTERN}}`. Pull the guest's name from the title and confirm it against the attendee list.
## Step 2: Identify the guest
The guest is whichever attendee isn't `{{HOST_EMAIL}}` or `{{HOST_SECOND_EMAIL}}`. Their email address is where the prep email goes.
Read the event's `description` field closely. {{HOST_FIRST_NAME}}'s booking flow ({{BOOKING_TOOL}}) often includes an "Additional notes:" section where the guest already wrote a short bio in their own words when they booked the slot. This is usually the richest, most reliable material you'll get — treat it as the backbone of your research, not an afterthought.
## Step 3: Ask {{HOST_FIRST_NAME}} for context + LinkedIn PDF — then stop
{{HOST_FIRST_NAME}} usually knows something about the guest that no amount of searching will surface — they met at one of his events, they have a running joke, they told him something offhand. Those details are what make his questions land, so ask before researching rather than after. Post this message, filling in the blanks from the calendar event:
```
Found your next recording: {Guest Name} on {date} at {time}.
To prep the best questions:
1. Tell me 2-3 interesting things about {Guest Name} that I wouldn't find online — personal, funny, or surprising.
2. If you have their LinkedIn, export it as a PDF (More → Save to PDF) and upload it here.
```
**⚠️ HUMAN IN THE LOOP — stop here and wait for {{HOST_FIRST_NAME}}'s reply before doing anything else.** Don't research, don't draft, don't create files. This applies to automated runs too: when the daily scheduled check fires, post the message and end the run. {{HOST_FIRST_NAME}} replying is what restarts the flow — the value of this skill comes from his input, and a script built without it is the generic one he'd have written himself.
If {{HOST_FIRST_NAME}} replies that he has nothing to add or no LinkedIn, that's a fine answer — continue with what you have.
## Step 4: Research the guest
Start with what {{HOST_FIRST_NAME}} gave you, then fill gaps online.
**If {{HOST_FIRST_NAME}} uploaded a LinkedIn PDF**, read only these sections: **Summary, Experience, Education, Licenses & Certifications, Honors & Awards, Volunteering**. Ignore "Activity", "Posts", and "Recent activity" entirely — those are mostly reposts and likes of *other people's* content, so treating them as the guest's own words or work leads to questions about things they never said or did. That's an embarrassing way to open an interview.
Then web-search the guest's name, plus "LinkedIn," plus any company or place names from their booking notes or {{HOST_FIRST_NAME}}'s context. You're not writing a biography — you're hunting for one genuine contrast or hook: a professional identity paired with something surprising, human, or offbeat (a hobby, a habit, an unlikely detour, a strong opinion). Every one of {{HOST_FIRST_NAME}}'s existing scripts is built around exactly this kind of juxtaposition — an M&A executive who reads Agatha Christie for fun, a debt-recovery exec who's obsessed with Mozart and sci-fi, a Samsung/Apple veteran who now plays padel. Generic LinkedIn-summary bios make for boring questions; specific, slightly unexpected details make for good ones. {{HOST_FIRST_NAME}}'s own tidbits from Step 3 usually beat anything online — lean on them first.
## Step 5: Write the interview script
Read `references/examples.md` now — it has three full real scripts {{HOST_FIRST_NAME}} has actually used. Match their structure and voice closely; the instructions below are a skeleton, the examples are the real spec.
Structure, in order:
1. **Opening line**, verbatim: "{{OPENING_LINE}}"
2. **Hook paragraph** introducing the guest by full name and setting up the contrast from Step 4. Sometimes this works best as two short bulleted lists (professional side vs. personal side) — see the examples for the pattern.
3. **Transition line**, verbatim: "Okay lets jump in:"
4. **10-14 questions.** Short, punchy, conversational — never multi-part or essay-style. Mix professional-angle questions, playful/personal ones, and a couple tied to the {{SHOW_NAME}} community (past events they've attended, {{CITY}}/expat life, culture). Work at least one of {{HOST_FIRST_NAME}}'s Step 3 tidbits in as a question — that's the whole reason you asked. For 2-4 of the more reflective questions, add a {{SECOND_LANGUAGE}} translation on the line directly below, matching the examples — this is a deliberate, recurring pattern, not something every question needs.
5. **Closing question**, verbatim: "Okay, where can people learn more about you?"
6. **Outro**, verbatim except the guest's first name: "{{OUTRO_LINE}}"
Use the `docx` skill to actually build this as a Word file (don't just hand back plain text) — read that skill before generating the file.
**File name:** `{YYYY-MM-DD}_PodcastPrep_{GuestFirstLast}.docx` (no spaces in the name part, dashes in the date) — matches {{HOST_FIRST_NAME}}'s existing naming exactly.
Before creating anything, search Drive for a file with that name (or containing the guest's name and "PodcastPrep") so you don't duplicate a script that already exists.
Upload into the **"{{PREP_FOLDER}}"** folder (inside "{{PODCAST_FOLDER}}" in {{HOST_FIRST_NAME}}'s Drive — search for it by name rather than hardcoding an ID, since folder IDs aren't portable). When uploading, set `disable_conversion_to_google_type: true` so it lands as an actual .docx like the rest of the folder, not a converted Google Doc.
## Step 6: Draft the guest prep email
Always create this as a **Gmail draft, never send it automatically** — {{HOST_FIRST_NAME}} reviews and sends it himself. Before drafting, check existing drafts/sent mail to that guest so you don't duplicate one.
Template (fill in the blanks, keep the voice otherwise unchanged). Create the draft as HTML and hyperlink the word "link" to the Google Meet URL rather than pasting the raw URL — it reads cleaner and {{HOST_FIRST_NAME}} doesn't want the long meet.google.com string sitting in the email body:
```
Subject: See you at {start time, e.g. 15:00} tomorrow
Hey {Guest first name}! See you at {start time} tomorrow at <a href="{Google Meet link from the event}">link</a>
Show format:
Length:
5–7 minutes
Vibe:
Fast. Casual. Playful. Slightly chaotic. Don't overthink your answers. Say the first thing that pops into your head. We don't want to spend more than 30 seconds on each question. Goal is to have fun, not be serious : )
Sample questions I may ask:
{5-6 of the lighter, punchier questions from the script — skip the deep/philosophical ones and anything with a {{SECOND_LANGUAGE}} translation. This should read breezy, not like a therapy session.}
Talk soon!
{{HOST_FIRST_NAME}}
```
Only adjust "tomorrow" in the subject/body if the email is going out same-day or the framing genuinely doesn't fit — otherwise keep it as-is, it's {{HOST_FIRST_NAME}}'s established voice.
## Running this automatically
{{HOST_FIRST_NAME}} wants a daily check of tomorrow's calendar to kick this off without him having to ask. That belongs in a scheduled task that calls this skill, not inside the skill itself — see the scheduled task set up alongside this skill.
Because of the pause in Step 3, an automated run is a **nudge, not a finished deliverable**: it finds the recording, posts the ask for context and the LinkedIn PDF, and stops. {{HOST_FIRST_NAME}} answering is what produces the script and the draft. If no recording is found for tomorrow, do nothing — no need to report back that there's nothing to prep.
Since the ask has to reach {{HOST_FIRST_NAME}} with enough runway for him to reply and for the flow to finish before the recording, it's worth having the scheduled task fire ~2 days out rather than the morning of.
---
name: "podcast-description"
description: "Writes the show notes AND {{SOCIAL_PLATFORM}} caption for a {{SHOW_NAME}} podcast episode {{HOST_FIRST_NAME}} has already recorded. Reads the \"{{NOTES_SOURCE}}\" doc (or transcript) from the recording in Google Drive, crafts an intriguing {{LOCAL_FLAVOUR}}-themed episode title, a short casual description, and an {{SOCIAL_PLATFORM}} post with hashtags, then saves it all as a Google Doc in {{HOST_FIRST_NAME}}'s \"{{NOTES_FOLDER}}\" Drive folder with a \"Connect with {{HOST_FIRST_NAME}}\" section at the bottom. Use whenever {{HOST_FIRST_NAME}} mentions writing a podcast description, show notes, an episode title, an {{SOCIAL_PLATFORM}} post or caption for an episode, \"describe the episode I just recorded\", \"write up the podcast with [guest]\", \"podcast description for [name]\", or anything about publishing/promoting a recorded {{SHOW_NAME}} episode. This is the AFTER-recording skill — podcast-guest-prep is the before-recording one."
---
## Before the first run — set this up for yourself
**Claude: do this section before anything else.** This skill was written for a
different business and every personal detail in it has been replaced with a
`{{PLACEHOLDER}}`. Interview the person you're working with, one question at a
time, then rewrite this file with their answers and delete this section. Do not
run the workflow until every placeholder is filled.
- `{{HOST_NAME}}` — What's your full name, as it should appear as the host?
- `{{HOST_FIRST_NAME}}` — What should I call you in these instructions?
- `{{SHOW_NAME}}` — What's the podcast called?
- `{{HOST_EMAIL}}` — Which email address do you book and send from?
- `{{NOTES_SOURCE}}` — What produces your recording notes or transcript, and where do they land?
- `{{NOTES_FOLDER}}` — Which folder should the finished write-ups go into?
- `{{LOCAL_FLAVOUR}}` — Do your titles lean on a place, a language or a running theme? Give me a few examples of the flavour you want.
- `{{SOCIAL_PLATFORM}}` — Which platform is the caption for?
- `{{ALWAYS_HASHTAGS}}` — Which two or three hashtags go on every single post?
- `{{YOUR_LINKS}}` — Which of your own links belong at the bottom of every write-up?
If they don't know an answer yet, leave that placeholder in place and tell them
which one is still open — don't invent a value.
---
# Podcast Description
After {{HOST_FIRST_NAME}} records an episode of the {{SHOW_NAME}} podcast (short, casual, 5–15 min interviews over Google Meet), he needs a publishable write-up: an intriguing title, a short description, and an {{SOCIAL_PLATFORM}} caption. This skill produces all three from the recording's Gemini notes and saves them as one Google Doc.
The companion skill `podcast-guest-prep` handles the *before* side. This one runs *after*.
## What can and can't be undone
The Drive connector can **create** files, **trash** them (`trash_file`, recoverable from Drive's trash), and change their **title/folder** (`update_file`). It **cannot edit file content**.
So a doc with wrong content can't be corrected in place — the fix is to create a replacement and trash the original. That's recoverable but messy, and it churns {{HOST_FIRST_NAME}}'s folder. Get the content right before calling `create_file`; create exactly one doc per run.
## Autonomy: what to decide alone, what to stop and ask
**Decide alone, no check-in:** title and alternates, tone, which details to feature, bullet selection, {{SOCIAL_PLATFORM}} caption wording, hashtag selection, filename, date, doc layout.
**Stop and ask {{HOST_FIRST_NAME}}:** anything involving a guest's links/handles that isn't verified (see Step 4), tagging a guest's {{SOCIAL_PLATFORM}} account, and any claim about a guest that the notes don't clearly support (see Step 3). These get published under the guest's name and can't be retracted once posted.
## Step 1: Find the recording notes
Gemini auto-saves a notes doc to Drive for every recording. **Do not match on the full title pattern** — it drifts. Specifically: the timezone flips `EEST`→`EET` at the end of October, the `15 min` segment changes if {{HOST_FIRST_NAME}} changes his {{BOOKING_TOOL}} slot length, and "{{NOTES_SOURCE}}" is Google branding that may be renamed.
Search loosely and widen only if needed:
1. `title contains '{{NOTES_SOURCE}}' and title contains '{{HOST_NAME}}'`
2. If that's empty: `title contains 'podcast recording'`
3. If still empty: `fullText contains 'podcast recording' and mimeType = 'application/vnd.google-apps.document'`
4. If still empty, also check the second account's files: add `sharedWithMe = true`. {{HOST_FIRST_NAME}} operates both `{{HOST_EMAIL}}` and `{{HOST_SECOND_EMAIL}}`, and podcast material has landed in both.
The notes docs are **scattered across several different parent folders** — there is no single folder to list. If {{HOST_FIRST_NAME}} has since consolidated them into one folder, prefer `parentId = '{that folder}'`, which is far more reliable than any title match.
Selecting the episode:
- If {{HOST_FIRST_NAME}} names a guest, filter to that guest.
- If he says "the one I just recorded" or names no one, take the most recent by `createdTime`.
- If two recordings share a date, or several plausibly match, **ask** — don't pick.
- If nothing is found, say so plainly and stop. Never reconstruct an episode from the calendar event alone, and never report "no recording" without having tried searches 2–4 above.
Read the doc with `read_file_content`. The **Details** section carries the specifics worth writing about; **Summary** is generic. Ignore "Next steps" and the Gemini footer.
## Step 2: Check for an existing doc and a style reference
List the **"{{NOTES_FOLDER}}"** folder (find it by name: `title contains '{{NOTES_FOLDER}}' and mimeType = 'application/vnd.google-apps.folder'`).
- **Duplicate check:** match on guest name *and* recording date, not guest name alone — {{HOST_FIRST_NAME}} has repeat guests, and matching on name alone would silently skip a legitimate second episode. If a doc for this exact episode exists, tell {{HOST_FIRST_NAME}} and stop rather than creating a near-duplicate.
- **Style reference:** if the folder contains a doc {{HOST_FIRST_NAME}} has marked as the reference (or if he's named one), read it and match its voice and structure. **A real example overrides the style rules below.**
- **Canonical links:** if the folder contains a links file (`_links`, `_links.md`, or similar), read it. It is the source of truth for all URLs — {{HOST_FIRST_NAME}}'s and the guests'.
## Step 3: Write the title and description
**Title.** Intriguing, not descriptive. Lean on a {{LOCAL_FLAVOUR}} where it works — neighborhoods (Primăverii, Floreasca, Dorobanți), landmarks (Arcul de Triumf, Cișmigiu), {{SECOND_LANGUAGE}} words and spellings (*noroc*, *dor*, *nu negocia*, *București*), local texture. Hook it to the single most surprising specific in the notes; specific beats clever. Under ~12 words. Don't make the guest's name the whole title. Avoid "Unpacking...", "The Art of...", and colon-heavy LinkedIn-speak. Give **one recommendation plus 2–3 alternates**.
**Description.** Hard limits: **two short paragraphs maximum**, plus **3–5 teaser bullets** only if the episode has distinct threads. One paragraph is fine. Casual and friendly — how {{HOST_FIRST_NAME}} talks at his events. Humor lightly applied; one good wink beats three forced jokes, and never at the guest's expense. Name the guest and what they do in the first sentence or two, then get to the interesting part. Use real specifics — a description that could describe any episode has failed. No hashtags, no emoji, no "In this episode, we dive deep into..."
**Accuracy rules — these matter more than the prose:**
- Gemini's notes are a *paraphrase of speech*, not a transcript. Do not sharpen a vague paraphrase into a specific claim.
- If the notes are non-committal about a detail, stay non-committal. Gemini writes "themself" and "a client" precisely because it doesn't know — do not assign a gender, a number, a job title, or a company that isn't stated. (This has already gone wrong once: a client described as "themself" was published as "her.")
- **Cross-check company and product names against a verified source.** Gemini mishears them. A studio's name came through as an acronym; the guest's invite email domain gave away the real spelling.
- Watch for **internal contradictions** in the notes and don't repeat them. One set said a blog was founded in 2008 *and* had a "20-year history." When the notes disagree with themselves, use the detail you can verify and drop the other.
- Never present anything as a direct quote. The notes contain none.
- If something reads like it might have been sarcasm or a throwaway joke, don't feature it — or ask {{HOST_FIRST_NAME}}.
- If the notes are thin, say so and write shorter rather than padding with invention.
- If the episode was conducted mostly in {{SECOND_LANGUAGE}}, ask {{HOST_FIRST_NAME}} which language he wants the write-up in before writing.
**Guest's name:** spell it exactly as it appears in the notes and calendar invite, diacritics included (diacritics included). In the *filename* only, strip diacritics and spaces.
## Step 4: Links — the highest-risk part of this skill
**Gemini transcribes spoken URLs and handles badly.** It has rendered a spoken domain two different wrong ways in two different episodes.
Rules:
- **{{HOST_FIRST_NAME}}'s three links are fixed** (Step 6) and always safe to use.
- **A guest link may only be published if** it comes from the folder's canonical links file, from the guest's email domain in the calendar invite, from the guest's own verified website, or {{HOST_FIRST_NAME}} confirms it. A quick `web_fetch` of the candidate domain both confirms it exists and often surfaces their real social links in the footer — do this rather than guessing.
- **Never construct a URL** from a handle or domain heard only in the notes. If a handle was spoken and can't be verified, leave it out and tell {{HOST_FIRST_NAME}}.
- **If the notes and the invite disagree, ask.** Example: one guest's notes gave one spelling of their domain while their invite email gave another.
## Step 5: Write the {{SOCIAL_PLATFORM}} post
Goes in the doc **below the description**, above Connect with {{HOST_FIRST_NAME}}. Written so {{HOST_FIRST_NAME}} can paste it straight into {{SOCIAL_PLATFORM}} — no instructions, no placeholders he has to fill in except a guest tag if unverified.
- **Open with a hook**, not an announcement. The first line has to survive the "…more" cutoff. Never open with "New episode out now!"
- **4–7 short lines**, single line breaks between them, not paragraphs. {{SOCIAL_PLATFORM}} captions are read as a vertical list, not prose.
- Same casual voice as the description, but punchier and more direct. One joke, max.
- Name the guest and what they do, briefly.
- **Close with a CTA** — new episode is live, link in bio.
- **Emoji: none by default.** {{HOST_FIRST_NAME}} doesn't use them in his written material. If he asks for them later, keep it to one or two.
- **Tagging the guest:** only tag an {{SOCIAL_PLATFORM}} handle that's been verified per Step 4. If the guest's IG isn't confirmed, write their name plainly and flag it — don't guess at an @.
**Hashtags.** Own block at the end of the caption, after a blank line.
- **Always include, every episode: the two in `{{ALWAYS_HASHTAGS}}`.**
- Add **6–10 more** relevant to the episode: mix broad reach (`#podcast`, `#SEO`, `#entrepreneurship`) with local and niche (your city, your industry, topic-specific ones).
- Total 8–12. Not a wall of 30 — it reads as spam and {{SOCIAL_PLATFORM}} doesn't reward it.
- CamelCase multi-word tags for readability: `#YourShowName`, not `#yourshowname`.
## Step 6: Connect with {{HOST_FIRST_NAME}}
The doc always ends with this section — heading directly above the three bullets, links live, in this order:
**Connect with {{HOST_FIRST_NAME}}**
- [{{SHOW_NAME}}]({{WEBSITE}}) — sign up to hear about events & new podcast episodes
- [{{PROGRAMME_NAME}}]({{WEBSITE}}) — get on the waitlist
- [{{SHOW_NAME}} on {{SOCIAL_PLATFORM}}]({{INSTAGRAM}})
⚠️ The AI Circle bullet is a **placeholder** pointing at the main site — the real waitlist URL is unknown. If the folder's links file has it, use that instead. Otherwise use it as-is and remind {{HOST_FIRST_NAME}} it's still a placeholder.
## Step 7: Create the Google Doc
Create with `create_file` as a **Google Doc** (not .docx — this folder is Google Docs, unlike {{PREP_FOLDER}}).
- `parentId`: the "{{NOTES_FOLDER}}" folder, found by name — never a hardcoded ID.
- `title`: `{YYYY-MM-DD}_PodcastDescription_{GuestFirstLast}` — the **recording date** from the notes, not today's date; no spaces or diacritics in the name part.
- Body as `textContent` with `contentMimeType: 'text/html'`, conversion enabled, so headings, bullets, and hyperlinks survive. Always use real anchor tags.
Layout, in order:
1. Recommended title (heading)
2. `Alternate titles:` list
3. Description (+ bullets)
4. Optional guest links line
5. **{{SOCIAL_PLATFORM}} Post** (heading) — caption, then hashtag block
6. Connect with {{HOST_FIRST_NAME}}
Keep the {{SOCIAL_PLATFORM}} caption as plain paragraph lines with no bullets or links inside it, so {{HOST_FIRST_NAME}} can copy the block cleanly into the app.
**Verify after creating.** The `fileSize` in the create response is unreliable (it returns `1` even for a full document). Always call `read_file_content` on the new doc to confirm the content landed.
## Step 8: Report back
Give {{HOST_FIRST_NAME}} the doc link, plus the recommended title, the description, and the {{SOCIAL_PLATFORM}} caption pasted in chat so he can react without opening anything. Then explicitly flag, every time:
- any guest link or handle that went in unverified, was left unlinked, or was omitted
- any detail you had to interpret from a vague or self-contradicting passage in the notes
- whether the AI Circle link is still the placeholder
Keep it short. Don't re-explain the episode to him — he was there.
---
name: "podcast-graphics"
description: "Builds the Canva episode artwork for a {{SHOW_NAME}} podcast episode: a 3000x3000 square cover and a 1920x1080 thumbnail, each appended as a new page to {{HOST_FIRST_NAME}}'s existing Canva archive designs. Scans the \"{{NOTES_FOLDER}}\" Drive folder for episodes that don't have graphics yet, then uses the title, guest name and episode number from the show-notes doc plus a guest photo from Google Drive (or found on the web if Drive has none), sets the photo to 50% opacity, and flags the background-removal step. Use whenever {{HOST_FIRST_NAME}} mentions a podcast cover, cover art, episode graphic, thumbnail, artwork, \"make the graphics for [guest]\", \"any new episodes to make graphics for\", \"cover for the episode I just published\", \"find a photo of the guest\", Canva podcast template, or anything about visuals for a {{SHOW_NAME}} episode. Also runs unattended on a schedule. This runs AFTER podcast-description (which writes the title) — podcast-description is the show-notes skill, podcast-guest-prep is the before-recording one."
---
## Before the first run — set this up for yourself
**Claude: do this section before anything else.** This skill was written for a
different business and every personal detail in it has been replaced with a
`{{PLACEHOLDER}}`. Interview the person you're working with, one question at a
time, then rewrite this file with their answers and delete this section. Do not
run the workflow until every placeholder is filled.
- `{{HOST_NAME}}` — What's your full name, as it should appear as the host?
- `{{HOST_FIRST_NAME}}` — What should I call you in these instructions?
- `{{SHOW_NAME}}` — What's the podcast called?
- `{{HOST_EMAIL}}` — Which email address do you book and send from?
- `{{NOTES_FOLDER}}` — Which folder holds the finished show-notes docs?
- `{{COVER_DESIGN}}` — What's your square cover archive called in Canva, and what size are the pages?
- `{{THUMB_DESIGN}}` — And the wide thumbnail archive?
- `{{BRAND_COLOUR}}` — What's the background colour on your covers?
- `{{BYLINE_FORMAT}}` — How is the byline written on an existing page? Copy it exactly, including season and episode numbering.
- `{{PHOTO_SOURCE}}` — Where do guest photos come from?
If they don't know an answer yet, leave that placeholder in place and tell them
which one is still open — don't invent a value.
---
# Podcast Graphics
Every published {{SHOW_NAME}} episode gets two graphics, both built from the same three pieces of text plus one photo:
- **Square cover**, 3000×3000 — for the podcast host / Apple / Spotify
- **Wide thumbnail**, 1920×1080 — for YouTube and LinkedIn
They are not separate files per episode. Each lives as **one more page appended to an existing Canva archive design**, so episode 15 becomes page 15. This skill's whole job is to add that page correctly to each archive.
`podcast-description` writes the title and runs first. This one runs after.
## The two archive designs
Find them with `search-designs` — do not trust the IDs below blindly, but do use them to confirm you found the right thing.
| | Title | ID | Page size |
|---|---|---|---|
| Cover | `{{COVER_DESIGN}}` | `{{COVER_DESIGN_ID}}` | 3000×3000 |
| Thumbnail | `{{THUMB_DESIGN}}` | `{{THUMB_DESIGN_ID}}` | 1920×1080 |
If a search turns up two designs with a matching title, or the page counts of the two archives disagree with each other, **stop and ask {{HOST_FIRST_NAME}} which is live**. Appending to a stale copy is invisible until he opens the wrong file weeks later.
There is also a Canva **brand template** `{{BRAND_TEMPLATE_ID}}` ("{{BRAND_TEMPLATE}}"). It is a frozen snapshot with **no autofill dataset** — `get-brand-template-dataset` returns `{}`. Never try to autofill it and never use it as the source. It exists only as the thing {{HOST_FIRST_NAME}} shares with other people.
## Anatomy of a page
Both page sizes have identical structure, only scaled. Background `{{BRAND_COLOUR}}`. Three elements:
1. **Title** — one TEXT element, bold white serif (`fontRef YAEw17BKkvo`), top-left, wraps to 3–4 lines.
2. **Byline** — one TEXT element, white sans (`fontRef YAFcfmNq6UY`), bottom-left, holding **three separate regions**:
- `"{Guest Name}\n3"`
- `"rd"` ← this is the superscript in "{{BUSINESS_NAME}}"
- `" Space {{CITY}}\nSeason {S}, ep {N}"`
3. **Photo** — a RECT with a replaceable IMAGE fill, right side, deliberately oversized so it bleeds off the bottom and right edges of the page. The fill area is roughly 2020×2020 on the cover. **The photo sits at 50% opacity** with its background removed.
⚠️ **Never call `replace_text` on the byline element.** It collapses all three regions into one and destroys the superscript "rd". Use two `find_and_replace_text` operations instead — one for the guest name, one for the `Season {S}, ep {N}` string. `replace_text` is fine (and correct) for the title, which is a single region.
## Step 1: Find which episodes still need graphics
This is the entry point for every run, including unattended ones. **Exception:** if {{HOST_FIRST_NAME}} names a guest or episode, skip the scan and go straight to that one.
**The queue is a diff between two lists.**
1. List every doc in the **"{{NOTES_FOLDER}}"** Drive folder (`{{NOTES_FOLDER_ID}}`; find it by name — `title contains '{{NOTES_FOLDER}}' and mimeType = 'application/vnd.google-apps.folder'` — and use the ID only to confirm you landed in the right place). Filenames follow `{YYYY-MM-DD}_PodcastDescription_{GuestFirstLast}`, so each one gives you a recording date and a guest.
2. Read the byline of every page in the thumbnail archive. That gives you the guest name and episode number already published for each page.
3. Anything in list 1 with no page in list 2 needs graphics.
**Matching the two lists is where this goes wrong.** Two traps:
- **Diacritics.** Filenames strip them, the Canva pages keep them — `GuestName` in Drive is `Guest Nâmé` on the page. Normalize both sides (strip diacritics, drop spaces, lowercase) before comparing, or every episode with a {{SECOND_LANGUAGE}} name will look new forever and you'll append duplicates.
- **Repeat guests.** {{HOST_FIRST_NAME}} has had the same person on twice. Match on guest *and* recording date, never guest alone, or a legitimate second episode gets silently skipped.
**Then:**
- **Nothing new** — say the archives are up to date, name the last episode on them, and stop. Do not go looking for something to do.
- **Exactly one** — proceed with it.
- **Several** — list them oldest first and confirm with {{HOST_FIRST_NAME}} before starting. Then do them **one at a time, fully, in date order**, since each one's episode number depends on the previous page having landed. Never batch the page appends.
## Step 2: Gather the episode's three facts
Read the show-notes doc with `read_file_content`. Use the **recommended** title, not one of the alternates. The title on the graphic and the title in the show notes must match exactly — never invent or paraphrase one. Spell the guest's name exactly as the doc writes it, diacritics included.
**Episode number** is derived, never guessed. Take the last page of the thumbnail archive, parse its byline for `Season {S}, ep {N}`, and the new page is `ep {N+1}` in the same season. If the two archives' last pages disagree on episode number, stop and ask — they have drifted, and appending blind makes it worse. If {{HOST_FIRST_NAME}} says a new season has started, ask him to confirm the season and starting episode number.
## Step 3: Get the guest photo into Canva
### 3a. Drive first
Photos live in the Drive folder **"Podcast Guest Photos"** (`1KWEXLXk3rn0kXNRUjAMrwrjZk8teE9xz`, inside "{{PODCAST_FOLDER}}"). {{HOST_FIRST_NAME}} drops a photo named after the guest. Match loosely on surname — filenames will not be tidy. If a photo is there, use it and skip to 3c.
**A cut-out PNG here is worth more than anything else in this skill.** If the file already has a transparent background, the whole run finishes clean with no manual step (see Step 4d). Note in your report whether the Drive photo was a cut-out or not.
**The sharing check is not optional.** Canva pulls the photo over the public internet via `upload-asset-from-url`. Before uploading, call `get_file_permissions` on the photo and confirm a permission with `type: anyone` exists. If it doesn't:
> A file that isn't link-shared still returns HTTP 200 — it serves a **Google sign-in page**. Canva imports that HTML as if it were the image and the upload "succeeds". You will not see the failure until the thumbnail comes back wrong.
So: if there's no `anyone` permission, stop and ask {{HOST_FIRST_NAME}} to set the **Podcast Guest Photos folder** to "Anyone with the link — Viewer" (one-time setup; new photos inherit it). Do not proceed on hope.
Upload with `url: https://drive.google.com/uc?export=download&id={fileId}`.
### 3b. Web search — only when Drive has nothing
Don't ask permission to search; Drive coming up empty is the trigger. Never search when a Drive photo exists.
**Where to look, in preference order.** Photos the guest published of themselves are both more current and less awkward than a stray press shot:
1. Their LinkedIn profile photo, personal site, or "about" page
2. Their company's team/leadership page
3. Conference or event speaker pages (these are reliably dated — the event year is right there)
4. Recent press, interviews, podcast appearances
A personal site is usually the jackpot: WordPress serves images from `/wp-content/uploads/{YYYY}/{MM}/`, which dates every file for free, and the originals are full resolution. Pull the page HTML and harvest the upload paths directly rather than trusting a search-result thumbnail.
**Beware of decoys on the guest's own site.** Their pages are full of images that are not them — stock models in the testimonial sections, logos, and portraits of other people (a mentor, a trainer, a co-founder). **Actually look at every candidate before shortlisting it.** Filenames lie; a file called `Untitled-design16.jpg` on a coach's homepage was a stock model, and a portrait in her own uploads folder turned out to be her trainer.
Cross-check the person too — {{SECOND_LANGUAGE}} names repeat, and a wrong face published under the guest's name is the worst failure this skill can produce. A single name search will surface several people; company plus city plus role from the show-notes doc is usually enough to disambiguate.
Skip stock and wire-agency photos, and skip group shots and photos where the guest isn't clearly the subject.
**Age.** The bar is nothing older than 7 years — compute the cutoff year from today's date, don't hardcode it. Photo files carry no reliable date, so infer it from context: the WordPress upload path, the article's publish date, the event year on a speaker page, "joined in 2023" on a team page. Make your best call, pick the most current-looking option, and **say what you inferred and how confident you are**. Don't discard a good photo just because the page is undated — flag it as unverified and move on.
**Resolution matters.** The cover fill area is about 2020×2020, so anything under ~800px on the short side will look soft when {{HOST_FIRST_NAME}} exports at 3000×3000. Judge the *usable* area, not the file size: a 2000×961 banner where the guest occupies the right third is effectively a 700px photo. Prefer the largest true portrait; LinkedIn thumbnails and social avatars are usually too small.
**Show {{HOST_FIRST_NAME}} three candidates before using any of them.** For each: a preview, the source page, the inferred date and your confidence, and the pixel dimensions. Say which ones you rejected and why. Wait for him to pick. If you can only find one or two usable photos, present what you have and say so rather than padding the list.
### 3c. Upload and verify
Upload the chosen photo with `upload-asset-from-url` and keep the returned `asset.id` (`MA...`). Both pages use the same asset.
Canva fetches the URL server-side and **some hosts reject it** — Wikimedia returns 403, and LinkedIn CDN URLs are signed and expire. If the upload fails or the returned thumbnail isn't the photo, move to the next candidate rather than retrying the same URL. Always look at the returned asset thumbnail before building anything on top of it. The `smart_tags` on the uploaded asset are a useful sanity check — a portrait should come back tagged `portrait`, `smile`, `person`, not `logo` or `text`.
## Step 4: Append the page
For each archive, in this order (cover first, then thumbnail):
**4a. Duplicate the last page onto the end.** `merge-designs` inserting a page from the design into itself:
```json
{ "type": "modify_existing_design", "design_id": "{archive}",
"operations": [{ "type": "insert_pages",
"source": { "type": "design", "design_id": "{archive}", "page_numbers": [{lastPage}] }}] }
```
`merge-designs` requires explicit confirmation before it runs. Show {{HOST_FIRST_NAME}} exactly what will be appended to which design and wait for his go-ahead — one confirmation covering both archives is fine. Never include a `delete_pages` operation in these calls.
**4b. Fill in the new page.** `read-design` with `open_transaction: true` and `filter.page_indices: [{newPage}]`, capturing the thumbnail first as your before-image. Locator IDs are regenerated on every copy — read them fresh, never reuse IDs from a previous run. Then one `edit-design` call:
- `replace_text` on the title element → the episode title
- `find_and_replace_text` on the byline → old guest name to new guest name
- `find_and_replace_text` on the byline → `Season {S}, ep {N}` to `Season {S}, ep {N+1}`
- `update_fill` on the photo RECT → the uploaded asset ID
- `update_opacity` on the photo RECT → **`0.5`**
The opacity is the house style: the guest sits at half strength against the magenta so the title stays dominant. `update_opacity` takes 0–1, so Canva's "Transparency 50" is `0.5` here. Apply it in the same call as the fill — a page committed at full opacity means reopening a transaction to fix it.
**4c. Look at the result before committing.** Compare the returned thumbnail against the before-image and check:
- Does the title fit? It should wrap to **3–4 lines and never collide with the photo or the byline**. The archive's titles run roughly 40–55 characters. A longer one will overflow or crowd the image — if it does, shorten it (drop a subtitle, cut a clause) rather than shrinking the font, and tell {{HOST_FIRST_NAME}} what you changed and why.
- Did the superscript survive? The byline must still read "3ʳᵈ Space {{CITY}}", not "{{SHOW_NAME}}" flat.
- Is the photo the guest, and is it at half strength — not a sign-in page, not a grey box, not fully opaque?
If anything is wrong, **`finalize: "cancel"`** and fix the inputs. Do not commit and patch afterward; a committed page can't be deleted without dragging {{HOST_FIRST_NAME}} through the exact-phrase deletion protocol.
Only when it looks right: `edit-design` with `finalize: "commit"` and no operations.
**4d. Background removal — the one step that cannot be automated.**
Canva's Background Remover is an **editor-only feature**. There is no `edit-design` operation for it and no API path; this was confirmed directly against Canva's own help. Do not pretend otherwise, do not try to fake it with cropping or shapes, and do not silently skip mentioning it.
So unless the source photo was already a cut-out:
> **Tell {{HOST_FIRST_NAME}}, every run, in the report: open each new page in Canva, select the photo, click BG Remover.**
**Order matters, and getting it wrong looks bad.** At 50% opacity a photo that still has its background washes a pale rectangle across the right half of the page and the title becomes unreadable on top of it. That is the expected in-between state, not a bug — but say so, so the half-finished page doesn't read as a broken result.
Two ways to make the manual step disappear, worth mentioning when it comes up:
- {{HOST_FIRST_NAME}} saves cut-out PNGs into **Podcast Guest Photos**, and Step 3a finds them already transparent.
- He installs the Claude in Chrome extension, after which the BG Remover click can be driven in the editor. Only raise this if he asks about automating it — don't assume the extension is connected, check first.
## Step 5: Export and hand over
Call `get-export-formats` first, then `export-design` as `png`, `export_quality: "pro"`, `pages: [{newPage}]` — once per archive. If the background still needs removing, say plainly that these exports are the pre-BG-removal state and he'll want to re-export after.
**The PNGs cannot be saved into Google Drive.** The Drive connector's only write path takes file bytes inline, and these images are far too large for that; embedding them into a Doc by remote URL does not work either (Google silently drops the image). Do not attempt either. Give {{HOST_FIRST_NAME}} the download links in chat instead — they stay valid roughly 12 hours — and remind him Canva's own Share → Google Drive works if he wants them filed.
## Step 6: Report
Short. Give him:
- Both Canva edit links, with the page number for each
- Both PNG download links
- The title, guest name and episode number as they now appear on the graphics
- **The BG Remover reminder**, every time the photo wasn't already a cut-out
- If the photo came from the web: the source URL, the inferred date and your confidence — so he can swap it if he'd rather use his own
- Anything you shortened, guessed, or worked around
- If more episodes are still queued, what's left
Don't describe the episode back to him — he recorded it.
## Running unattended
On a schedule, Step 1 is the whole point: most runs will find nothing and should end silently rather than manufacturing work. When a run *does* find a new episode, it still needs {{HOST_FIRST_NAME}} for the `merge-designs` confirmation, the photo choice, and the BG Remover click — so a scheduled run's job is to surface the episode and the photo candidates and wait, not to publish pages on its own.
## Standing gotchas
- **Drive has no delete and no edit tool.** Anything created there is permanent. Create nothing speculatively.
- **Canva page deletion needs {{HOST_FIRST_NAME}} to type `I approve the deletion` verbatim.** No paraphrase counts. Avoid needing it.
- {{HOST_FIRST_NAME}} operates two accounts, `{{HOST_EMAIL}}` and `{{HOST_SECOND_EMAIL}}`. If a Drive search comes up empty, retry with `sharedWithMe = true`.
- Canva's `upload-asset-from-url` rejects some hosts outright. Drive and GitHub raw work; Wikimedia 403s.
- A web-sourced photo is a stopgap. When one gets used, suggest {{HOST_FIRST_NAME}} save a cut-out copy into Podcast Guest Photos so repeat guests never need searching or background-removing again.
To use one:
Copy the text above.
In Claude, create a new skill and paste it in as SKILL.md.
Say “set this skill up for me”. It will ask you a dozen short questions — your show name, your folders, how you open an episode — and rewrite itself with your answers.
Run it once on something low-stakes and watch where it stops to ask you something. Those pauses are the part that makes it work.
Built byEric MelchorFounder, 3rd Space Bucharest. Running on every episode of the 3rd Space Bucharest podcast through the 2026 season.
More cards in 3rd Space AI Workflows — each one a real workflow from a real member, with the skill attached.
Social life mode: on
Twenty-five seats a month. One email a week. That's the whole arrangement.