Clip Outreach & Pipeline

Send each prospect a short clip made for them, review every email before it goes, and send from your own Gmail: the outreach commands, the pipeline and the clip pages.

Why Clip Outreach

A cold email is easy to ignore. A short clip made for one person, about their own work (a teaser for their latest episode, a hello with their name in it), is a reason to open it and a reason to reply. Clip outreach makes that practical at the scale of a weekly list: one personalized clip per prospect, each behind a page that plays without a 5AM account, and one email per prospect that carries the link.

It is built so you stay in charge of every message:

  • You review every email before it goes. Drafts wait for your Approve, in your AI character's chat, on the web or in the apps.
  • Email leaves from your own mailbox. 5am outreach send uses your Gmail; 5AM never sends outreach from its own domain.
  • The prospect gets something useful. Their page has Download and share buttons and a link back to their episode or show, and they can claim it and publish it under their name.
  • You know what happened. Each page counts views, email opens, plays, shares, downloads, button clicks and sign-ups.

How It Fits Together

Three pieces, each usable on its own:

  • The Pipeline: the list of prospects (items), their contacts, their activity, and the email drafts awaiting review, kept by an AI character (the Sales Director by default). See Pipeline.
  • Clip pages: a page for one video, at https://5am.app/c/<token>, that plays without an account. See A page for one video.
  • The outreach commands: the batch flow that ties them together, from a CSV of prospects to sent emails and their stats. See Clip Outreach Commands.
text
CSV ─▶ prepare ─▶ clips ─▶ draft ─▶ review ─▶ send ─▶ stats
StepWhat it doesCost
preparecreates the pipeline items, writes one film per prospect and draws its contact sheetfree
clipsrenders each film, uploads it with a GIF preview and turns its page on20 AI credits per clip
draftstages one email per prospect and posts the batch to your character's chat for reviewfree
reviewyou watch each clip, edit the message, then approve or skip itfree
sendsends what you approved from your own Gmailfree
statsreads each page's countsfree

Every step works on one batch and resumes where it stopped, so a failed run picks up again instead of starting over.

The Batch (--batch)

A batch is one list of prospects you contact together, named by --batch: oct_week_1, ep_2026_10_14, whatever helps you find it again. prepare creates it, and every later command (clips, draft, review, send, stats) takes the same name, which is how the steps know which prospects, clips and drafts they work on.

  • Where it lives. A private folder on your computer, ~/.5am/outreach/<batch>/, that only your user account can open. It holds the batch's state (batch.json: each prospect and how far they got), each prospect's film, contact sheet, rendered clip and email GIF, and a log of the calls the commands made (ids only, never names or email addresses).
  • The name. 1 to 64 characters: lowercase letters, digits, _ and -, starting with a letter or digit. The name is also the campaign label on every clip link in the emails (utm_campaign=<batch>), which shows in your analytics, so never put a prospect's name or an email address in it.
  • Running a step again. With the same --batch, a command picks up where it stopped: prospects already past that step are kept, and only the rest are redone. prepare again rewrites only the rows still prepared, needs_fix or failed (after you shorten a name or widen the template), and clips again pays for a render it kept instead of rendering twice.
  • One character. The AI character chosen at prepare stays with the batch; its pipeline holds the batch's prospects and drafts.
  • When to start a new one. For each new list or week (a batch takes up to 100 prospects), and for a follow-up round to people you already emailed (--follow-up).
  • In the chat. The review card names its batch ("batch oct_week_1"), so you know which list you are approving.

Ways to Use It

  • A weekly batch from the terminal. Prepare a CSV, look at the free contact sheets, render, draft, review, send. Your first batch walks through it.
  • Review on your phone. draft posts the batch into your character's chat with a review card and pushes your phone. Watch each clip, edit the message, Approve or Skip in the chat (web or iOS) or on Android's Outreach review screen. Approving marks the draft ready; it leaves your Gmail the next time 5am outreach send runs.
  • With an AI agent. An agent can run the batch for you: prepare, render and draft. It should ask you before spending credits, leave the review to you, and send only what you approved. It can also record an email you already sent by hand, so the pipeline knows (see Recording an Email You Already Sent).
  • Just one piece. Turn on a page for one video to send a client, or work the Pipeline's approval queue with your own email flow.

What It Costs

  • 20 AI credits per rendered clip. That is the only charge in the flow.
  • clips --page-text, 5am media public-link draft and draft --personalize spend your Gemini access: your own key if you saved one, else AI credits.
  • Preparing, reviewing, sending and stats are free.

Your First Batch

What you need: the CLI signed in (5am login) with AI credits or a saved Gemini key; a Premium plan and a character with the pipeline skills (the Sales Director has them); Node.js 20+, Chrome or Chromium and FFmpeg (the clips are rendered on your machine, with the optional runtime: 5am update --runtime-only); a Gmail account with 2-step verification, so it can issue an app password.

1. Gmail, once. Your emails go out from your own Gmail through an app password: a separate 16-letter password Google issues for one app. It is not your Google password, and you can revoke it at any time without changing anything else.

To get one:

  1. Turn on 2-Step Verification for your Google account if it is not on yet: open myaccount.google.com/security and choose 2-Step Verification. Google offers app passwords only once it is on.
  2. Open myaccount.google.com/apppasswords, signing in again if Google asks.
  3. Type a name you will recognize, such as 5AM CLI, and click Create.
  4. Google shows the password once, as four groups of four letters. Copy it (the spaces do not matter) and paste it into mail setup below.

If the App passwords page says the setting is not available, 2-Step Verification is off, your account uses only security keys for it, it is a work or school account whose administrator turned app passwords off, or it is enrolled in Google's Advanced Protection.

Then store it:

sh
5am outreach mail setup --address you@gmail.com   # paste the app password at the hidden prompt
5am outreach mail test                             # one message to yourself

mail setup signs in to Gmail once to check the password (nothing is sent), then stores it. A 534 5.7.9 answer means you typed your Google account password; it has to be the app password.

Note:

Your app password stays on your computer. The CLI keeps it in your system keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows) or, where there is no keychain, in the CLI's own config file, readable only by your user account. It is used for one thing: signing in to Gmail's mail server (smtp.gmail.com, over an encrypted connection) when you send. It is never sent to 5AM's servers. 5am outreach mail clear or 5am logout deletes it from your computer, and revoking it on the App passwords page stops it working everywhere. For a one-off run or CI, set FIVEAM_GMAIL_ADDRESS and FIVEAM_GMAIL_APP_PASSWORD instead of storing it.

2. A template. Any Motion film with {{name}} in its title or a text layer, and optionally {{line}} (an episode title, a personal note), {{show}} and {{site}} for the sign-off card:

sh
5am motion generate --brief "A 15 second hello for a podcast host, their name large, then the episode title" --format 9:16 --duration 15 -o template.motion.json
5am motion lint template.motion.json

Open the file, put {{name}} where the name goes and {{line}} where the second line goes, then lint it again. The Motion Films reference covers the format.

3. A CSV. One row per prospect; only name is required.

ColumnWhat it is
namespelled as it should appear in the clip
emailwhere the message goes; a row without one is kept for a DM
websitethe show's or business's site
source_url, source_titlewhat the clip is about (the episode's page and its title), linked from the clip page
linethe {{line}} text
contextfacts for the page writer, such as the episode's show notes
show, sitethe sign-off card: the show's name and where to listen
instagram, observation, inferenceoptional research notes

5am pipeline items list --csv prospects.csv writes this shape from your pipeline.

4. Prepare (free).

sh
5am outreach prepare --csv prospects.csv --template template.motion.json --batch oct_week_1 --character "Sales Director"

--batch oct_week_1 names this batch: every later step takes the same name (see The Batch). Each row gets its pipeline item, a film with the name in it and a contact sheet. Look at every sheet in ~/.5am/outreach/oct_week_1/ before going on. A row marked needs_fix is a name that does not fit the template: shorten the name or widen the text layer and run prepare again; it redoes only the rows that need it.

5. Render (20 credits each).

sh
5am outreach clips --batch oct_week_1 --dry-run
5am outreach clips --batch oct_week_1 --yes

The dry run prices the batch and checks fonts, Chrome and FFmpeg without charging. The real run renders each film, uploads it to the album "Clip for <name>", makes a short GIF for the email, turns the clip's page on and sets its headline, description and link back to the episode. If a charge is refused, the render is kept for 24 hours: buy credits (5am credits buy) and run clips again; it pays for the kept render instead of rendering twice.

6. Draft and review.

sh
5am outreach draft --batch oct_week_1

One email per prospect is staged in your pipeline, with the clip link and the opt-out sentence, and the batch arrives in your character's chat with a review card (a push tells your phone). Review there, on the web Outreach tab, on Android's Outreach review screen, or on this computer with 5am outreach review --batch oct_week_1. What you approve is exactly what goes out.

7. Send.

sh
5am outreach send --batch oct_week_1 --dry-run
5am outreach send --batch oct_week_1 --yes

The dry run prints the exact messages and connects to nothing. The real run sends the approved drafts from your Gmail, text plus an HTML part showing the GIF, and marks each one sent in the pipeline. Nothing is ever sent twice to one person.

8. Watch the pages.

sh
5am outreach stats --batch oct_week_1 --record

Reviewing Drafts

A draft can be reviewed in four places, and they all work on the same queue: a draft approved in one reads approved in the others.

  • Your character's chat (web and iOS): 5am outreach draft posts one message per batch with a review card. Each draft shows its clip (tap to play), the recipient, the subject and the message, with Edit, Approve and Skip. --no-review-notice skips the message.
  • The Outreach tab on the character's page on the web: every draft, including the ones being sent and the history.
  • Android: Profile, Outreach, Outreach review.
  • This computer: 5am outreach review --batch <batch> opens a page to watch each clip, edit each draft and approve or skip it, then Done.

Approving never sends anything. The email leaves your Gmail when 5am outreach send runs. A reviewing character may also approve drafts that another character wrote, never its own.

Clip Outreach Commands

sh
5am outreach mail setup --address you@gmail.com      # once: a Gmail app password (2-step verification on)
5am outreach mail test                               # one message to yourself
5am outreach mail report --subject "Weekly digest" --body-file digest.md   # mails a file to yourself, nobody else
5am outreach prepare --csv prospects.csv --template template.motion.json --batch oct_week_1
5am outreach clips --batch oct_week_1 --dry-run      # the price, then --yes to render (20 credits each); --page-text writes each page's text
5am outreach draft --batch oct_week_1                # stages the drafts and posts them to your character's chat for review; --no-review-notice skips that
5am outreach review --batch oct_week_1               # or review on this computer: watch, edit, approve or skip
5am outreach send --batch oct_week_1 --dry-run       # the exact messages, then --yes to send from your Gmail
5am outreach stats --batch oct_week_1                # views, opens, plays, shares, downloads, button clicks, sign-ups per prospect
5am outreach stats --batch oct_week_1 --record       # also note the changed counts on each pipeline item

Batches and follow-ups. A batch takes up to 100 prospects (--limit), which is also the Pipeline's ceiling on drafts awaiting review, so a bigger day is several batches. A prospect who was already emailed is refused unless you pass --follow-up, and then only once --min-days-since-sent days (3 by default) have passed since the last send (for an email you recorded afterwards, since the time you gave it). One message per prospect per batch, always with the opt-out sentence ("Reply no and I will not write again."). Your own Gmail's daily volume is the real ceiling.

The message. draft fills a template with {{name}}, {{line}}, {{clip_url}} and {{sender}} (--subject, --body-file; the default is a short note with the one link). --personalize asks the character to write each body and keeps it only if it carries the clip link and nothing else. Every draft is checked before it is staged: no placeholder left, the clip link exactly once, no other web address.

Sending. send sends only drafts you approved, rereads each one from the server first (so your edits are what goes out) and refuses one that no longer carries the prospect's clip link. It reserves each draft before Gmail sees it, so two runs never send one twice. When a run cannot confirm a send (the connection broke after Gmail had the message), the draft stays in sending: look in your Gmail Sent folder, then run 5am pipeline outreach mark-sent <draftId> if it is there or release <draftId> if it is not. A message Gmail refuses for good closes its draft with Gmail's reply.

The contact sheets, the renders and the email GIFs need FFmpeg, found through --ffmpeg, $FFMPEG or PATH. The Gmail credential is kept in your keychain and cleared by 5am logout.

Pipeline

Read the pipeline an AI character (the Sales Director by default) keeps for you, and work its outreach review queue from the terminal. A character stages email drafts. You approve or reject each one, or a reviewing character does, as long as it did not write the draft. The email leaves from your own mailbox: 5am outreach send for clip outreach, or by hand followed by mark-sent. Nothing is sent by the platform. The same queue is on the character's Outreach tab on the web, in the character's chat as a review card (web and iOS), and on Android's Outreach review screen: a draft approved in one place reads approved everywhere.

sh
5am pipeline items list --stage researched          # {items, stages}
5am pipeline items list --search acme               # by name
5am pipeline items list --csv prospects.csv         # one row per item with its primary contact (--overwrite replaces the file)
5am pipeline items get <itemId>                     # contacts, activities, drafts
5am pipeline outreach list                          # staged (the default), or --status approved | sending | rejected | sent
5am pipeline outreach edit <draftId> --subject "..." --body-file message.txt   # while staged only
5am pipeline outreach approve <draftId>
5am pipeline outreach reject <draftId> --note "Lead with the episode"          # required; the character reads it
5am pipeline outreach mark-sent <draftId>           # after you sent it yourself
5am pipeline outreach mark-sent <draftId> --sent-at 2026-10-10T14:05:00Z   # an email that went out earlier, with the time it left
5am pipeline outreach release <draftId>             # a sending draft that is not in your Gmail Sent folder goes back with the approved ones

An edit must keep a draft's clip page link: one that removes it is refused (clip_link_required). A draft in sending is one 5am outreach send reserved for its Gmail attempt; settle an unconfirmed one with mark-sent or release as above.

Recording an Email You Already Sent

Sometimes a prospect is emailed before the pipeline knows about them: you wrote to them by hand, or an agent sent it from your Gmail before their item existed. Record that email, and the pipeline treats them as emailed: prepare refuses them unless you pass --follow-up, and no other draft written before the record goes to the same address.

No clip is rendered for this, so it skips prepare and draft (and needs no Chrome or FFmpeg). Use the character that keeps the pipeline (the Sales Director by default):

sh
# 1. The item: find it, or create it with its contact
5am characters skills execute <characterId> pipeline_query --input '{"mode":"get_item","name":"Acme Podcast"}'
5am characters skills execute <characterId> pipeline_upsert --input '{"entity":"item","name":"Acme Podcast","website":"https://acme.example","contacts":[{"name":"Sam Lee","email":"sam@acme.example","is_primary":true}]}'

# 2. The email as you sent it
5am characters skills execute <characterId> stage_outreach --quiet-push \
  --input '{"item_id":"<itemId>","recipient_name":"Sam Lee","recipient_email":"sam@acme.example","subject":"A teaser for your episode","body":"<the email as you sent it>"}'

# 3. Approve it and record when it left
5am pipeline outreach approve <draftId>
5am pipeline outreach mark-sent <draftId> --sent-at 2026-10-10T14:05:00Z
  • The words and the address as sent. Paste the subject and body you sent, and use the address it went to: duplicate protection works per address.
  • --quiet-push skips the notification a new draft sends you for review, since this one is already out.
  • --sent-at is the time in your Gmail Sent folder, with its zone (2026-10-10T14:05:00Z, or +02:00). A date alone (2026-10-10) means noon that day on your computer's clock (or now, for today before noon), and any date from today back 365 days works, whatever the time of day you run it. It cannot be in the future or more than 365 days ago.
  • duplicate_draft means a draft to that address is already waiting for review on the item. Edit it to the words you sent (5am pipeline outreach edit <draftId> --subject "..." --body-file sent.txt), then approve it and mark it sent with --sent-at.

The draft keeps the time you gave as its send time, so a follow-up counts its days from the real send, and the item's activity shows the email on the day it left, noted with the day you recorded it. Duplicate protection goes by when you recorded it: an approved draft to the same address written before then is never sent (send closes it as "Not sent, to avoid a duplicate"), since whoever wrote it could not have known.

A Page for One Video

Any video in your library can have a page that plays without a 5AM account (https://5am.app/c/<token>): the link to send a prospect, a client or a friend. The page offers Download and share buttons (X, LinkedIn, WhatsApp, Facebook, Instagram, TikTok, Copy link), a link back to the episode or show the clip is about, and it counts views, email opens, plays, shares, downloads, button clicks and sign-ups. Signed in, you edit it on the page itself. The person the clip is for can claim the page from its button and publish it under their name; you both edit it from then on.

sh
5am media public-link enable <mediaId> --title "Clip for Sam"      # prints publicUrl, the link to send
5am media public-link get <mediaId>                                 # the link, its counts, its text, who claimed it
5am media public-link set <mediaId> --source-url https://pod.example/ep/41 --source-title "Episode 41"   # what the clip is about
5am media public-link set <mediaId> --headline "..." --description "..." --body-file page.md   # the page's words
5am media public-link draft <mediaId> --notes-file notes.txt --apply   # Gemini writes the page about that episode (spends your Gemini access)
5am media public-link publish <mediaId> --slug episode-41            # a readable address; in search once the body has 300 characters
5am media public-link unpublish <mediaId>                           # out of search again; the slug is kept
5am media public-link disable <mediaId>                             # the old link stops working at once

set also takes --template and the page's extra media (--item, --clear-items). Publishing needs a headline of 10 characters and a description of 40. A published page lives at https://5am.app/clips/<slug> and joins search only once its body has 300 characters, so a thin page never reaches search. Outreach pages stay private until the person they were made for claims and publishes them; nothing in the outreach commands publishes a page.

Troubleshooting

You seeWhat it meansDo this
HTTP 401 invalid_tokenthe CLI session expired5am login
the network proxy at … refused to connect to 5am.appthis computer's network blocked the request before it left (a company proxy, or an AI agent's sandbox); it never reached 5AM, so your sign-in is fineallow 5am.app in the proxy or the agent's network settings, then run the command again; 5am login will not fix it
534 5.7.9 from Gmailan account password was usedmake an app password, run mail setup again
needs_fix after preparethe name does not fit the templateshorten the name or widen the layer, prepare again
ffmpeg not found on PATHthe sheets, renders and GIFs need FFmpegexport FFMPEG=/path/to/ffmpeg (or --ffmpeg <path>) and run the command again; it redoes only the failed rows
pending_finalize after clipsthe charge was refused5am credits buy, then clips again
category: credits on a draftout of AI credits for the page writer or --personalize5am credits buy, or save a Gemini key
clip_link_required on an editthe edit removed the clip page linkkeep the link in the message; move it or reword around it
a draft stuck in sendinga send could not be confirmedcheck your Gmail Sent folder, then mark-sent or release
--sent-at ... is in the future or invalid_sent_ata clock time without its zone, a time ahead of now, or one more than 365 days agocopy the time from your Gmail Sent folder with its zone, like 2026-10-10T14:05:00Z