Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Product Launch Agent

An agent that coordinates everything needed to ship a feature launch:

Content (via Claude):

  • Release notes
  • Blog draft
  • Developer docs / product details sheet
  • Social posts, one per platform (X, LinkedIn, Instagram, Pinterest, TikTok, Facebook) — each paired with an image the agent chooses for that platform specifically, not one image reused everywhere

Assets (via Cloudinary):

  • Upload launch imagery/video
  • Generate social crops (Instagram, X, LinkedIn presets)
  • Generate an Open Graph image with a designed text treatment (eyebrow label + title on scrim boxes, not a flat darken)
  • Generate resized assets for other channels (email header, etc.)

Outreach (via Claude, when a target customer is described):

  • A plan recommending outreach channels and sequencing for reaching first customers
  • Ready-to-send messages per channel, each ending with an explicit call to action, each optionally paired with an image the agent chooses for that channel
  • Drafts only — the agent never sends anything; every message carries a status: "needs_review" flag rather than a warning buried in the text

Getting imagery to the agent

Two ways, and the first is the one worth building toward:

  1. Tag-based discovery (recommended). Whoever preps launch materials tags them in Cloudinary with the launch slug ahead of time — via the console, your DAM UI, or an upload pipeline — optionally setting a role custom metadata field (hero, screenshot, video). The brief then just names the slug, and the agent calls find_launch_assets to discover everything itself. Nobody has to hunt down or paste a URL.
  2. URL-based (fallback). The brief includes explicit source paths/URLs. The agent uploads and tags them via upload_launch_image — which means the next launch that reuses these assets can switch to option 1.

The agent's system prompt (src/agent.js) tells Claude to prefer (1) and only fall back to (2) for anything find_launch_assets doesn't return. The sample brief in src/index.js demonstrates the tag-based path.

Why this shape

The interesting part isn't Cloudinary's API — it's the agent loop: Claude is given a menu of tools (src/tools/tool-definitions.js) and a launch brief, and it decides which tools to call, in what order, and with what inputs. The orchestrator (src/agent.js) just executes whatever Claude asks for and feeds results back until Claude is done. Content tools themselves delegate to Claude with narrow, specialized prompts (src/tools/content-tools.js) rather than one giant prompt trying to do everything — a "specialist sub-call" pattern that scales better as you add more content types.

Cloudinary's role is intentionally narrow: store the source asset once, then derive every crop/format/overlay on demand via URL-based transformations (src/tools/cloudinary-tools.js). No re-uploading per channel.

Structured outputs, not prose

generate_social_posts and generate_outreach_messages don't return one markdown blob covering every platform/channel — they return an array of { platform, copy, imageUrl, assetReason, status } records (or channel / body for outreach). Two things make that possible:

  • The tool's input schema requires an image per platform/channel (images: [{ platform, imageUrl, assetReason }, ...]) instead of a single imageUrl applied to all of them. That's what actually fixes "every social post uses the same crop" — it's a schema constraint the agent has to satisfy, not a prompt instruction it can ignore under pressure.
  • The specialist call itself is forced into a tool call (tool_choice: { type: 'tool', name: ... } in content-tools.js) so its response is parsed JSON, not markdown the report then has to reverse-engineer by platform label. report.js never parses generated prose to find out which image goes with which post — the data already says so.

The lesson this is meant to demonstrate: when an LLM's output needs to be consumed by deterministic code, push as much of the shape as you can into the schema. A prompt that says "please vary the images" is a request; an input schema that requires one image per platform is a constraint.

Setup

npm install
cp .env.example .env
# fill in ANTHROPIC_API_KEY and your Cloudinary credentials in .env

Cloudinary credentials are in your Cloudinary console under Dashboard → Product Environment Credentials.

Run

npm start

You'll be walked through a short wizard: what kind of launch this is (technical, retail, travel, real estate, or home improvement), what you're launching, key changes/benefits, audience, tone, how to get imagery (already tagged in Cloudinary, or paste source URLs), and who you're hoping to reach as first customers (leave blank to skip outreach prep). Answering --file brief.txt instead of the wizard is also supported, for scripting: npm start -- --file brief.txt.

This will:

  1. Print each tool call as the agent makes it.
  2. Write output/<launch-slug>/report.html — a single browser-viewable launch kit, not a raw dump of everything the agent produced:
    • A cover with a hero image, launch name, a one-line description, and a Ready / Needs-your-review status breakdown computed from each tool's status field.
    • A condensed "launch kit" preview (release notes excerpt, blog preview, a few social cards, one outreach message, the outreach plan) linking down to the full versions.
    • Each deliverable rendered in a shape that resembles what it actually is — an article for the blog, a changelog for release notes, a spec sheet for product details, platform-styled cards for social posts, email/DM-styled cards for outreach messages — each with its chosen image alongside it, not in a separate gallery.
    • An asset board grouped by destination (Instagram, LinkedIn, X, Email, Open Graph, Source assets), each tile labeled with its real dimensions.
    • A collapsed "How the agent built this" section holding the agent's own summary and the full tool-call log, kept separate from the polished deliverables above it.
  3. Write output/<launch-slug>/run-results.json — the raw tool-call log (every input/output, including every Cloudinary URL), for scripting or auditing.
  4. Print a final summary from the agent, plus the exact path to report.html.

Extending it

  • New content type that's a single document (e.g. an FAQ): add a specialist function in content-tools.js returning { content, status }, add its schema to TOOLS and its case to executeTool in tool-definitions.js. No changes needed to agent.js or report.js — a generic markdown card renders anything with a content field.
  • New content type that's per-platform/per-channel (e.g. video scripts per platform): follow the generate_social_posts pattern — an input schema requiring one imageUrl/assetReason per entry, a forced tool_choice call in the specialist for the generated part, merged into an array of records. Give report.js a buildX() function to render it as its own visual shape rather than routing it through the generic card.
  • New crop/channel preset: add one line to CROP_PRESETS in cloudinary-tools.js — dimensions for the asset board come from the same object via PRESET_DIMENSIONS, so labeling stays in sync automatically.
  • Swap the model: change MODEL in config.js.
  • Persist run history / support multiple launches at once: the agent loop is stateless per call — wrap runProductLaunchAgent in whatever storage/queueing layer your app needs.

File structure

src/
  config.js               Anthropic + Cloudinary client setup
  agent.js                The orchestrator tool-use loop
  index.js                CLI entry point
  report.js               Renders run results into the launch-kit HTML report
  tools/
    tool-definitions.js   Tool schemas Claude sees + dispatcher
    content-tools.js      Claude-backed content generators
    cloudinary-tools.js   Real Cloudinary upload/transform calls

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages