AI Podcasting
Use this skill for client-facing, agent-driven episode operations in this repository.
What This Skill Runs
Run the main CLI at scripts/ai_podcasting_client.py for episode operations:
doctor:
Verify the credential, client identity, TCR show grant, and required operation scopes.
list-episodes:
List TCR episodes with rich per-episode summaries and filters for published, unpublished,
or all.
submit-episode:
Create a retry-safe new episode via /client/v1/episodes.
update-intro-copy:
Patch intro/title/thumbnail/outro assets for an existing unpublished episode via
/client/v1/episodes/{sourceId}/intro.
update-episode-copy:
Patch showNotes, supporting assetUrls, or guests after an episode already exists via
/client/v1/episodes/{sourceId}/copy.
This skill calls the versioned WIN client API at https://api.aipodcast.ing/client/v1/...
directly. Do not send agent operations through the frontend or automate the browser UI.
WIN enforces the authenticated principal's operation scopes and allowed shows server-side.
The scripts read the token only from ~/.secrets/aipodcasting/env by default, or from the
credential file path selected by AIPODCASTING_CLIENT_API_KEY_FILE. They do not accept secret
flags or secret-value environment fallbacks.
Auth Setup
Never paste the actual API key into this skill, a payload JSON file, a command argument, or chat.
Adi shares the key out-of-band. Store it in the user's local environment before running the client.
Recommended local setup:
mkdir -p ~/.secrets/aipodcasting
printf 'AIPODCASTING_CLIENT_API_KEY=<key-from-Adi>\n' > ~/.secrets/aipodcasting/env
chmod 600 ~/.secrets/aipodcasting/env
If the secret file lives somewhere else, set AIPODCASTING_CLIENT_API_KEY_FILE to that absolute
path. This variable selects a file; it never contains the credential itself.
For direct raw API usage, send the same key as Authorization: Bearer <key-from-Adi>.
For a customer install or upgrade, follow references/client-setup.md and require a successful
doctor result before running mutations.
Use scripts/aip_local_upload_helper.py only when the user gives a local file path for a file-like
field and no source URL is available. For TCR main episode submissions, prefer a Descript web URL
copied from Descript for the main source when one exists; do not export or upload an MP4 just to
create a source link. The helper requests a purpose-specific temporary upload intent and returns
an S3 cache/ URL for the main CLI to use. Callers cannot choose a raw lifecycle prefix.
Keep this implicit in chat unless the user asks.
Media Source Rule For TCR
When a Descript project/composition/source URL exists, use that URL as the source. Do not export,
upload, or submit an MP4 just to create a source file.
The expected Descript web URL shape is:
https://web.descript.com/<project-id>/<composition-id>
Copy the actual URL from Descript. Do not fabricate IDs, and do not require an exact path shape if
Descript provides a slightly different web.descript.com source URL.
Use these shapes:
{
"mainSourceUrl": "https://web.descript.com/01234567-89ab-4cde-8f01-23456789abcd"
}
For intro updates, use:
{
"introSourceUrl": "https://web.descript.com/01234567-89ab-4cde-8f01-23456789abcd"
}
The client normalizes these source fields to the backend payload internally. Do not send raw,
recordingLink, or introFile in agent payloads.
MP4 URLs and local MP4 paths are fallback inputs only. If both a Descript URL and an MP4 are known,
submit the Descript URL and omit the MP4.
All script and reference paths in this skill are relative to the skill directory itself, not the
repository root. Do not run scripts/... from the repo root unless you first cd into this skill
directory. When in doubt, use the absolute skill path shown by the harness.
Quick Start
- Check the installed credential and grants:
python3 scripts/ai_podcasting_client.py \
--json doctor
- List episodes to find the target ID:
python3 scripts/ai_podcasting_client.py \
--json list-episodes
To include the sanitized upstream episode payload under each item:
python3 scripts/ai_podcasting_client.py \
--json list-episodes \
--publication-state published \
--include-raw
To narrow to unpublished episodes in a date range:
python3 scripts/ai_podcasting_client.py \
--json list-episodes \
--publication-state unpublished \
--start-date 2026-01-01 \
--end-date 2026-01-31
- Submit a new episode (creates a new episode; no
source_id input needed):
python3 scripts/ai_podcasting_client.py \
--json submit-episode \
--payload-file references/submit-episode.example.json
- Update intro copy for an existing episode (
source_id required):
python3 scripts/ai_podcasting_client.py \
--json update-intro-copy \
--source-id <EPISODE_SOURCE_ID> \
--payload-file references/update-intro-copy-tcr.example.json
- Update show notes or other customer-owned episode copy after creation:
python3 scripts/ai_podcasting_client.py \
--json update-episode-copy \
--source-id <EPISODE_SOURCE_ID> \
--payload-file references/update-episode-copy.example.json
- Upload a local supporting file and get a temporary public URL:
python3 scripts/aip_local_upload_helper.py \
--json --purpose thumbnail /absolute/path/to/file.png
Interface Notes
- Fixed endpoint:
https://api.aipodcast.ing/client/v1
- Fixed show:
TCR
- Auth: bearer token from
~/.secrets/aipodcasting/env or the file selected by
AIPODCASTING_CLIENT_API_KEY_FILE
- The CLI does not accept base-url overrides or env-based base URL changes.
- The CLI does not accept show selection; all submit/list operations are locked to
TCR.
submit-episode sends Idempotency-Key using the command request ID. The JSON envelope returns
that request ID, and data.idempotency_key repeats it on success. Retry an uncertain submission
with --request-id <same-id>; use a new request ID only for an intentionally separate episode.
- Local uploads are purpose-scoped
cache/ transport objects. Use episode_main,
episode_asset, episode_intro, episode_outro, or thumbnail; never treat their URLs as
permanent inventory.
- Submit, intro, and episode-copy commands reject unknown fields before making a request. Never
treat a successful response as evidence that an undocumented field was accepted.
- JSON is the default output contract. Use
--plain or --human only for operator inspection.
list-episodes returns a rich summary by default in JSON mode. Each item now includes
fields such as thumbnailText, publishing metadata, preview text for long fields, normalized
file links, and other lightweight episode context.
list-episodes defaults to --publication-state all.
list-episodes supports --publication-state all|published|unpublished, plus optional
--start-date and --end-date filters.
- Results are sorted newest-first before
--limit is applied, so --limit 5 returns the latest
five matching episodes.
- Use
--include-raw when the agent needs the sanitized upstream episode object in addition to the
default summary.
- JSON mode returns a stable envelope with:
schema_version
command
status
data
error
meta
Required Vs Optional Inputs
doctor:
Required: a credential file containing AIPODCASTING_CLIENT_API_KEY.
Run after setup or rotation and before debugging a rejected operation.
list-episodes:
Required: none.
Optional: --publication-state, --start-date, --end-date, --limit, --include-raw.
--publication-state choices:
all (default)
published
unpublished
Default JSON output includes a rich per-episode summary with fields such as:
source_id, title, show, status, thumbnailText
created_at, updated_at, publishing metadata, and guest-review flags
- preview text plus lengths for long copy fields like show notes or editor notes
- normalized file links, artwork links, deliverable links, processed-asset links, ads, and
other lightweight metadata when present
Items are sorted newest-first before
limit is applied.
The data payload also echoes the applied filters object and matched_count.
With --include-raw, each item also includes raw_episode containing the sanitized upstream
payload.
submit-episode:
Required: --payload-file with mainSourceUrl.
Show handling: always forced to TCR by the CLI.
mainSourceUrl may be either:
- a public HTTP/HTTPS URL
- a local file path, which the helper uploads first
Prefer a Descript web URL in
mainSourceUrl when a Descript project/composition/source is
available. The app accepts MP4 URLs and local MP4 paths, but the CLI will warn because those are
fallback inputs for TCR, not the preferred source. If both a Descript web URL and an exported
MP4 are known, put the Descript web URL in mainSourceUrl and omit the MP4. Do not require a
specific Descript path shape; use the Descript web URL the user or browser provides.
TCR main episode submissions reject .mp3 main-source inputs. Use the original recording,
session, or video source link instead, such as Riverside, YouTube, or a direct non-MP3 media
URL. This is not a Riverside-only allowlist.
The client normalizes mainSourceUrl to the backend submit shape automatically.
assetUrls may also be public URLs or local file paths; local paths are uploaded first.
Optional: any additional backend-supported episode fields. Use customNewsletterDraftUrl for
a client-provided Ghost newsletter draft, preview, editor, or slug URL. The client preserves
richer payloads such as deliverables.thumbnails.options,
deliverables.thumbnails.video.variants, and files.episode_outro.
update-intro-copy:
Required (command): --source-id, --payload-file.
Intended target: an existing unpublished episode.
The client supports the current app intro payload directly.
For conversation-driven usage, prefer these user-facing fields:
There are no required patch fields beyond source_id.
Common patch fields: introSourceUrl, title, videoThumbnails, thumbnailText,
transcript, instructionsToEditor, customNewsletterDraftUrl, audioThumbnailLink,
outroMusicLink.
For TCR intro source updates, prefer a Descript web URL in introSourceUrl when one exists. Do
not export, upload, or submit an MP4 for the intro source when a Descript URL is available.
customNewsletterDraftUrl stores a client-provided Ghost newsletter draft link under episode
submission metadata. It does not publish or replace the generated newsletter by itself.
videoThumbnails may be either:
- one public HTTP/HTTPS URL
- a list of public HTTP/HTTPS URLs
The client normalizes
videoThumbnails into the app's thumbnail shape:
deliverables.thumbnails.video.url = first thumbnail URL
deliverables.thumbnails.video.variants = ordered list of all provided thumbnail URLs
The client also accepts the full current app payload for non-source fields if the agent already
has it, but source updates must still use introSourceUrl.
Local paths are allowed for file-like fields. The helper uploads them and the client uses the
returned public URLs.
update-episode-copy:
Required (command): --source-id, --payload-file.
Provide at least one of:
showNotes: HTML/plain text; use an empty string or null to clear it
assetUrls: public URLs or local paths; use [] or null to clear them
guests: guest objects; use [] or null to clear them
This is the supported post-creation path for show notes. Do not send showNotes through
update-intro-copy; that command rejects it instead of silently dropping it.
Conversation Policy
When values are missing in chat context, follow this flow:
Before asking follow-up questions, scan the current chat thread and reuse any values the user already provided.
Do not ask again for values that are already clear in context.
First disambiguate the operation when the user's wording does not make it clear whether they mean a new main episode submission, a post-creation show-notes/copy update, or an intro update.
Do not assume that "submit", "update this episode", or similar phrasing selects one command.
If the intent is ambiguous, ask exactly:
"Do you want to:
- submit a new main episode source
- update show notes/supporting episode copy for an existing episode
- update intro/title/thumbnail assets for an existing episode
Reply with 1, 2, or 3."
Only continue into command-specific prompts after the user picks one.
For submit flow, ask for the missing required submit value, but in that same first reply also
surface the common optional fields the user may want to set up front.
Required submit value:
- main episode source link as either a public HTTP/HTTPS URL or a local file path.
Prefer a Descript web URL for TCR when available. MP4 URLs and local MP4 paths are accepted but
should be described as fallback inputs, not the preferred source. Do not export, upload, or
submit an MP4 when a Descript web URL is available.
Common optional submit values to mention in the same first prompt:
- title
- showNotes
- assetUrls
- editorNotes
- thumbnailText
- priority
- scheduledDate
- needsGuestReview
- guests
- customNewsletterDraftUrl
Use this default submit prompt shape when the source is missing:
"Send the main episode source as a Descript web URL if you have one. If not, send another
public HTTP/HTTPS source URL or a local absolute file path.
You can also include any of these optional fields now if you want them set on creation:
- title
- showNotes
- assetUrls
- editorNotes
- thumbnailText
- priority
- scheduledDate
- needsGuestReview
- guests
- customNewsletterDraftUrl
If you send them together, I can submit the episode in one pass."
For copy updates, use update-episode-copy. If source_id is missing, list episodes using the
publication/date context already supplied, then ask the user to select one. Ask only for
showNotes, assetUrls, or guests; never route these fields through the intro command.
Intro updates are only for unpublished episodes.
For intro updates without source_id, immediately run list-episodes with
--publication-state unpublished.
If the user already provided startDate and endDate, include them.
Do not ask the user for publication scope first.
Ask the user which episode to target using an enumerated list, not raw ids only.
Render exactly:
1. <short title> — <source_id>
2. <short title> — <source_id>
...
Then ask: Reply with the episode number or source_id.
If the user replies with a number (for example 4), map that number to the corresponding source_id and continue without asking them to repeat the full id.
Ask only for the fields the user wants to change.
Enforce a strict two-step prompt sequence for intro updates when source_id is missing:
- Step 1 message: episode list +
Reply with the episode number or source_id.
- Step 2 message (only after episode is selected): required/optional field collection.
- For intro updates, use one prompt shape by default:
"Episode selected: .
Provide any fields you want to update.
Common fields:
- introSourceUrl (prefer a Descript web URL for TCR intro source updates)
- title
- videoThumbnails (give one URL or multiple URLs)
- thumbnailText
- transcript
- instructionsToEditor
- customNewsletterDraftUrl
- audioThumbnailLink
- outroMusicLink
You only need to send the fields you want to change, and I will patch just those."
Never ask the user to pick an episode id again after step 1 is completed.
12. If optional values are unclear, omit them instead of guessing.
13. Use --dry-run only if the user explicitly wants a preview before the write call.
It is an internal preview/debug tool, not a normal client-facing step.
14. For customNewsletterDraftUrl, provide a public HTTP/HTTPS Ghost draft, preview, editor, or
slug URL. It is not a local file upload field.
15. For file-type fields (mainSourceUrl, introSourceUrl, videoThumbnails, audioThumbnailLink, outroMusicLink, and submit/copy assetUrls entries):
- The client accepts either public HTTP/HTTPS URLs or local file paths.
- If the user provides a local file path, run
scripts/aip_local_upload_helper.py first and use its returned public URL.
- Do not pass unresolved local filesystem paths to the episode API payload.
Resources
scripts/ai_podcasting_client.py: Single client interface with subcommands.
scripts/aip_local_upload_helper.py: Purpose-scoped local upload helper; returns temporary
cache/ URLs in the same stable JSON envelope.
references/submit-episode.example.json: Example payload for submit flow.
references/update-episode-copy.example.json: Example post-creation show-notes/copy payload.
references/update-intro-copy.example.json: Example payload for intro/copy patch flow.
references/update-intro-copy-tcr.example.json: Example payload for TCR-style final title/thumbnail updates.
references/client-setup.md: Customer install, credential migration, doctor, and retry contract.
1---2name: ai-podcasting3description: Submit AI Podcasting episodes and update show notes, supporting episode copy, intro, title, and thumbnails through the scoped WIN client API. Use when clients want agent-driven episode operations without the GUI, including checking access, listing TCR episodes with rich metadata and published-state filters, retry-safe episode submission, patching post-creation show notes or intro copy, uploading local inputs, or disambiguating an episode operation.4---56# AI Podcasting78Use this skill for client-facing, agent-driven episode operations in this repository.910## What This Skill Runs1112Run the main CLI at `scripts/ai_podcasting_client.py` for episode operations:13141. `doctor`:15 Verify the credential, client identity, TCR show grant, and required operation scopes.162. `list-episodes`:17 List `TCR` episodes with rich per-episode summaries and filters for `published`, `unpublished`,18 or `all`.193. `submit-episode`:20 Create a retry-safe new episode via `/client/v1/episodes`.214. `update-intro-copy`:22 Patch intro/title/thumbnail/outro assets for an existing unpublished episode via23 `/client/v1/episodes/{sourceId}/intro`.245. `update-episode-copy`:25 Patch `showNotes`, supporting `assetUrls`, or `guests` after an episode already exists via26 `/client/v1/episodes/{sourceId}/copy`.2728This skill calls the versioned WIN client API at `https://api.aipodcast.ing/client/v1/...`29directly. Do not send agent operations through the frontend or automate the browser UI.30WIN enforces the authenticated principal's operation scopes and allowed shows server-side.31The scripts read the token only from `~/.secrets/aipodcasting/env` by default, or from the32credential file path selected by `AIPODCASTING_CLIENT_API_KEY_FILE`. They do not accept secret33flags or secret-value environment fallbacks.3435## Auth Setup3637Never paste the actual API key into this skill, a payload JSON file, a command argument, or chat.38Adi shares the key out-of-band. Store it in the user's local environment before running the client.3940Recommended local setup:4142```bash43mkdir -p ~/.secrets/aipodcasting44printf 'AIPODCASTING_CLIENT_API_KEY=<key-from-Adi>\n' > ~/.secrets/aipodcasting/env45chmod 600 ~/.secrets/aipodcasting/env46```4748If the secret file lives somewhere else, set `AIPODCASTING_CLIENT_API_KEY_FILE` to that absolute49path. This variable selects a file; it never contains the credential itself.50For direct raw API usage, send the same key as `Authorization: Bearer <key-from-Adi>`.51For a customer install or upgrade, follow `references/client-setup.md` and require a successful52`doctor` result before running mutations.5354Use `scripts/aip_local_upload_helper.py` only when the user gives a local file path for a file-like55field and no source URL is available. For TCR main episode submissions, prefer a Descript web URL56copied from Descript for the main source when one exists; do not export or upload an MP4 just to57create a source link. The helper requests a purpose-specific temporary upload intent and returns58an S3 `cache/` URL for the main CLI to use. Callers cannot choose a raw lifecycle prefix.59Keep this implicit in chat unless the user asks.6061## Media Source Rule For TCR6263When a Descript project/composition/source URL exists, use that URL as the source. Do not export,64upload, or submit an MP4 just to create a source file.6566The expected Descript web URL shape is:6768```text69https://web.descript.com/<project-id>/<composition-id>70```7172Copy the actual URL from Descript. Do not fabricate IDs, and do not require an exact path shape if73Descript provides a slightly different `web.descript.com` source URL.7475Use these shapes:7677```json78{79 "mainSourceUrl": "https://web.descript.com/01234567-89ab-4cde-8f01-23456789abcd"80}81```8283For intro updates, use:8485```json86{87 "introSourceUrl": "https://web.descript.com/01234567-89ab-4cde-8f01-23456789abcd"88}89```9091The client normalizes these source fields to the backend payload internally. Do not send `raw`,92`recordingLink`, or `introFile` in agent payloads.9394MP4 URLs and local MP4 paths are fallback inputs only. If both a Descript URL and an MP4 are known,95submit the Descript URL and omit the MP4.9697All script and reference paths in this skill are relative to the skill directory itself, not the98repository root. Do not run `scripts/...` from the repo root unless you first `cd` into this skill99directory. When in doubt, use the absolute skill path shown by the harness.100101## Quick Start1021031. Check the installed credential and grants:104105```bash106python3 scripts/ai_podcasting_client.py \107 --json doctor108```1091102. List episodes to find the target ID:111112```bash113python3 scripts/ai_podcasting_client.py \114 --json list-episodes115```116117To include the sanitized upstream episode payload under each item:118119```bash120python3 scripts/ai_podcasting_client.py \121 --json list-episodes \122 --publication-state published \123 --include-raw124```125126To narrow to unpublished episodes in a date range:127128```bash129python3 scripts/ai_podcasting_client.py \130 --json list-episodes \131 --publication-state unpublished \132 --start-date 2026-01-01 \133 --end-date 2026-01-31134```1351363. Submit a new episode (creates a new episode; no `source_id` input needed):137138```bash139python3 scripts/ai_podcasting_client.py \140 --json submit-episode \141 --payload-file references/submit-episode.example.json142```1431444. Update intro copy for an existing episode (`source_id` required):145146```bash147python3 scripts/ai_podcasting_client.py \148 --json update-intro-copy \149 --source-id <EPISODE_SOURCE_ID> \150 --payload-file references/update-intro-copy-tcr.example.json151```1521535. Update show notes or other customer-owned episode copy after creation:154155```bash156python3 scripts/ai_podcasting_client.py \157 --json update-episode-copy \158 --source-id <EPISODE_SOURCE_ID> \159 --payload-file references/update-episode-copy.example.json160```1611626. Upload a local supporting file and get a temporary public URL:163164```bash165python3 scripts/aip_local_upload_helper.py \166 --json --purpose thumbnail /absolute/path/to/file.png167```168169## Interface Notes170171- Fixed endpoint: `https://api.aipodcast.ing/client/v1`172- Fixed show: `TCR`173- Auth: bearer token from `~/.secrets/aipodcasting/env` or the file selected by174 `AIPODCASTING_CLIENT_API_KEY_FILE`175- The CLI does not accept base-url overrides or env-based base URL changes.176- The CLI does not accept show selection; all submit/list operations are locked to `TCR`.177- `submit-episode` sends `Idempotency-Key` using the command request ID. The JSON envelope returns178 that request ID, and `data.idempotency_key` repeats it on success. Retry an uncertain submission179 with `--request-id <same-id>`; use a new request ID only for an intentionally separate episode.180- Local uploads are purpose-scoped `cache/` transport objects. Use `episode_main`,181 `episode_asset`, `episode_intro`, `episode_outro`, or `thumbnail`; never treat their URLs as182 permanent inventory.183- Submit, intro, and episode-copy commands reject unknown fields before making a request. Never184 treat a successful response as evidence that an undocumented field was accepted.185- JSON is the default output contract. Use `--plain` or `--human` only for operator inspection.186- `list-episodes` returns a rich summary by default in JSON mode. Each item now includes187 fields such as `thumbnailText`, publishing metadata, preview text for long fields, normalized188 file links, and other lightweight episode context.189- `list-episodes` defaults to `--publication-state all`.190- `list-episodes` supports `--publication-state all|published|unpublished`, plus optional191 `--start-date` and `--end-date` filters.192- Results are sorted newest-first before `--limit` is applied, so `--limit 5` returns the latest193 five matching episodes.194- Use `--include-raw` when the agent needs the sanitized upstream episode object in addition to the195 default summary.196- JSON mode returns a stable envelope with:197 - `schema_version`198 - `command`199 - `status`200 - `data`201 - `error`202 - `meta`203204## Required Vs Optional Inputs2052061. `doctor`:207 Required: a credential file containing `AIPODCASTING_CLIENT_API_KEY`.208 Run after setup or rotation and before debugging a rejected operation.2092. `list-episodes`:210 Required: none.211 Optional: `--publication-state`, `--start-date`, `--end-date`, `--limit`, `--include-raw`.212 `--publication-state` choices:213 - `all` (default)214 - `published`215 - `unpublished`216 Default JSON output includes a rich per-episode summary with fields such as:217 - `source_id`, `title`, `show`, `status`, `thumbnailText`218 - `created_at`, `updated_at`, publishing metadata, and guest-review flags219 - preview text plus lengths for long copy fields like show notes or editor notes220 - normalized file links, artwork links, deliverable links, processed-asset links, ads, and221 other lightweight metadata when present222 Items are sorted newest-first before `limit` is applied.223 The `data` payload also echoes the applied `filters` object and `matched_count`.224 With `--include-raw`, each item also includes `raw_episode` containing the sanitized upstream225 payload.2263. `submit-episode`:227 Required: `--payload-file` with `mainSourceUrl`.228 Show handling: always forced to `TCR` by the CLI.229 `mainSourceUrl` may be either:230 - a public HTTP/HTTPS URL231 - a local file path, which the helper uploads first232 Prefer a Descript web URL in `mainSourceUrl` when a Descript project/composition/source is233 available. The app accepts MP4 URLs and local MP4 paths, but the CLI will warn because those are234 fallback inputs for TCR, not the preferred source. If both a Descript web URL and an exported235 MP4 are known, put the Descript web URL in `mainSourceUrl` and omit the MP4. Do not require a236 specific Descript path shape; use the Descript web URL the user or browser provides.237 TCR main episode submissions reject `.mp3` main-source inputs. Use the original recording,238 session, or video source link instead, such as Riverside, YouTube, or a direct non-MP3 media239 URL. This is not a Riverside-only allowlist.240 The client normalizes `mainSourceUrl` to the backend submit shape automatically.241 `assetUrls` may also be public URLs or local file paths; local paths are uploaded first.242 Optional: any additional backend-supported episode fields. Use `customNewsletterDraftUrl` for243 a client-provided Ghost newsletter draft, preview, editor, or slug URL. The client preserves244 richer payloads such as `deliverables.thumbnails.options`,245 `deliverables.thumbnails.video.variants`, and `files.episode_outro`.2464. `update-intro-copy`:247 Required (command): `--source-id`, `--payload-file`.248 Intended target: an existing unpublished episode.249 The client supports the current app intro payload directly.250 For conversation-driven usage, prefer these user-facing fields:251 There are no required patch fields beyond `source_id`.252 Common patch fields: `introSourceUrl`, `title`, `videoThumbnails`, `thumbnailText`,253 `transcript`, `instructionsToEditor`, `customNewsletterDraftUrl`, `audioThumbnailLink`,254 `outroMusicLink`.255 For TCR intro source updates, prefer a Descript web URL in `introSourceUrl` when one exists. Do256 not export, upload, or submit an MP4 for the intro source when a Descript URL is available.257 `customNewsletterDraftUrl` stores a client-provided Ghost newsletter draft link under episode258 submission metadata. It does not publish or replace the generated newsletter by itself.259 `videoThumbnails` may be either:260 - one public HTTP/HTTPS URL261 - a list of public HTTP/HTTPS URLs262 The client normalizes `videoThumbnails` into the app's thumbnail shape:263 - `deliverables.thumbnails.video.url` = first thumbnail URL264 - `deliverables.thumbnails.video.variants` = ordered list of all provided thumbnail URLs265 The client also accepts the full current app payload for non-source fields if the agent already266 has it, but source updates must still use `introSourceUrl`.267 Local paths are allowed for file-like fields. The helper uploads them and the client uses the268 returned public URLs.2695. `update-episode-copy`:270 Required (command): `--source-id`, `--payload-file`.271 Provide at least one of:272 - `showNotes`: HTML/plain text; use an empty string or `null` to clear it273 - `assetUrls`: public URLs or local paths; use `[]` or `null` to clear them274 - `guests`: guest objects; use `[]` or `null` to clear them275 This is the supported post-creation path for show notes. Do not send `showNotes` through276 `update-intro-copy`; that command rejects it instead of silently dropping it.277278## Conversation Policy279280When values are missing in chat context, follow this flow:2812821. Before asking follow-up questions, scan the current chat thread and reuse any values the user already provided.283 Do not ask again for values that are already clear in context.2842. First disambiguate the operation when the user's wording does not make it clear whether they mean a new main episode submission, a post-creation show-notes/copy update, or an intro update.285 Do not assume that "submit", "update this episode", or similar phrasing selects one command.286 If the intent is ambiguous, ask exactly:287 "Do you want to:288 1. submit a new main episode source289 2. update show notes/supporting episode copy for an existing episode290 3. update intro/title/thumbnail assets for an existing episode291292 Reply with 1, 2, or 3."293 Only continue into command-specific prompts after the user picks one.2943. For submit flow, ask for the missing required submit value, but in that same first reply also295 surface the common optional fields the user may want to set up front.296 Required submit value:297 1. main episode source link as either a public HTTP/HTTPS URL or a local file path.298 Prefer a Descript web URL for TCR when available. MP4 URLs and local MP4 paths are accepted but299 should be described as fallback inputs, not the preferred source. Do not export, upload, or300 submit an MP4 when a Descript web URL is available.301 Common optional submit values to mention in the same first prompt:302 1. title303 2. showNotes304 3. assetUrls305 4. editorNotes306 5. thumbnailText307 6. priority308 7. scheduledDate309 8. needsGuestReview310 9. guests311 10. customNewsletterDraftUrl3124. Use this default submit prompt shape when the source is missing:313 "Send the main episode source as a Descript web URL if you have one. If not, send another314 public HTTP/HTTPS source URL or a local absolute file path.315316 You can also include any of these optional fields now if you want them set on creation:317 1. title318 2. showNotes319 3. assetUrls320 4. editorNotes321 5. thumbnailText322 6. priority323 7. scheduledDate324 8. needsGuestReview325 9. guests326 10. customNewsletterDraftUrl327328 If you send them together, I can submit the episode in one pass."3295. For copy updates, use `update-episode-copy`. If `source_id` is missing, list episodes using the330 publication/date context already supplied, then ask the user to select one. Ask only for331 `showNotes`, `assetUrls`, or `guests`; never route these fields through the intro command.3326. Intro updates are only for unpublished episodes.3337. For intro updates without `source_id`, immediately run `list-episodes` with334 `--publication-state unpublished`.335 If the user already provided `startDate` and `endDate`, include them.336 Do not ask the user for publication scope first.3378. Ask the user which episode to target using an enumerated list, not raw ids only.338 Render exactly:339 `1. <short title> — <source_id>`340 `2. <short title> — <source_id>`341 `...`342 Then ask: `Reply with the episode number or source_id.`343 If the user replies with a number (for example `4`), map that number to the corresponding `source_id` and continue without asking them to repeat the full id.3449. Ask only for the fields the user wants to change.34510. Enforce a strict two-step prompt sequence for intro updates when `source_id` is missing:346 - Step 1 message: episode list + `Reply with the episode number or source_id.`347 - Step 2 message (only after episode is selected): required/optional field collection.34811. For intro updates, use one prompt shape by default:349 "Episode selected: <source_id>.350 Provide any fields you want to update.351352 Common fields:353 1. introSourceUrl (prefer a Descript web URL for TCR intro source updates)354 2. title355 3. videoThumbnails (give one URL or multiple URLs)356 4. thumbnailText357 5. transcript358 6. instructionsToEditor359 7. customNewsletterDraftUrl360 8. audioThumbnailLink361 9. outroMusicLink362363 You only need to send the fields you want to change, and I will patch just those."364 Never ask the user to pick an episode id again after step 1 is completed.36512. If optional values are unclear, omit them instead of guessing.36613. Use `--dry-run` only if the user explicitly wants a preview before the write call.367 It is an internal preview/debug tool, not a normal client-facing step.36814. For `customNewsletterDraftUrl`, provide a public HTTP/HTTPS Ghost draft, preview, editor, or369 slug URL. It is not a local file upload field.37015. For file-type fields (`mainSourceUrl`, `introSourceUrl`, `videoThumbnails`, `audioThumbnailLink`, `outroMusicLink`, and submit/copy `assetUrls` entries):371 - The client accepts either public HTTP/HTTPS URLs or local file paths.372 - If the user provides a local file path, run `scripts/aip_local_upload_helper.py` first and use its returned public URL.373 - Do not pass unresolved local filesystem paths to the episode API payload.374375## Resources376377- `scripts/ai_podcasting_client.py`: Single client interface with subcommands.378- `scripts/aip_local_upload_helper.py`: Purpose-scoped local upload helper; returns temporary379 `cache/` URLs in the same stable JSON envelope.380- `references/submit-episode.example.json`: Example payload for submit flow.381- `references/update-episode-copy.example.json`: Example post-creation show-notes/copy payload.382- `references/update-intro-copy.example.json`: Example payload for intro/copy patch flow.383- `references/update-intro-copy-tcr.example.json`: Example payload for TCR-style final title/thumbnail updates.384- `references/client-setup.md`: Customer install, credential migration, doctor, and retry contract.