{"slug": "i-built-an-agent-that-does-a-week-of-work-in-one-command", "title": "I Built an Agent That Does a Week of Work in One Command", "summary": "A developer built the Product Launch Agent, an open-source Node.js CLI that uses the Anthropic SDK and Cloudinary to turn a single command into a full product launch kit — release notes, documentation, a blog post, social posts for four platforms with correctly cropped hero images, an outreach plan, and drafted influencer DMs. The agent relies on human-tagged and approved Cloudinary assets and deterministic tools, never inventing images or sending outreach automatically, and outputs the assembled kit as an HTML report. The author says the same pattern could extend to real estate listings, support log summaries, or event recap galleries.", "body_md": "Agents are here to make work more efficient, but not to take over taste and judgment. Finding the point where an agent can save real time without quietly taking the wheel is harder than it sounds.\n\nThe Product Launch Agent below is my attempt at that sweet spot. You can find it here, on [GitHub](https://github.com/cloudinary-devs/product-launch-agent). \n\nIt leans on trusted, deterministic tools and human-curated inputs to do a week of work in one command, without taking the wheel.\n\nClone the [Product Launch Agent repository](https://github.com/cloudinary-devs/product-launch-agent), connect a Cloudinary product environment, and generate a launch kit from your own approved assets.\n\nIn about 15 minutes, you can upload and tag a launch image, let the agent find it, and generate platform-specific image variations and launch content.\n\nI used this prompt to describe the app I wanted to build.\n\n```\nBuild a Node.js CLI using the Anthropic SDK and Cloudinary.\n\nThe CLI should accept a launch brief describing the product, its key benefits, target audience, campaign strategy, and messaging.\n\nUse an agent to produce:\n\n- Release notes, product documentation, and a blog post\n- Social posts for four platforms, each with its own correctly cropped hero image\n- An outreach plan and draft direct messages for a list of influencers\n\nThe agent should use approved launch assets uploaded to Cloudinary and tagged with a launch identifier. Find those assets, create platform-specific crops and an Open Graph image with a text overlay, and pass the resulting URLs to the content-generation tools.\n\nNever invent or substitute an image when no suitable approved asset is available. Outreach messages must be drafts only and must never be sent automatically.\n\nSave the complete launch kit as a polished HTML report in:\n\noutput/<launch-name>/report.html\n```\n\n**Note:** This prompt is separate from the system prompt that guides the agent at runtime.\n\nA human team member tags and approves the images, selects the campaign strategy, and writes the messaging brief. The agent finds and formats what was approved. It does not decide what looks good or what the brand should say.\n\nOne command produces a blog post, release notes, a social campaign across four platforms, an outreach plan, and drafted DMs to a list of influencers, ready for review. Done manually, this could take a full week:\n\nYour browser does not support the video tag.\nBefore running the agent:\n\n`vesper-no-1`.\nThen the agent:\n\n`crop: 'fill'` and `gravity: 'auto'`.\nCloudinary handles asset storage, search, transformation, optimization, and delivery. The agent orchestrates the automated operations and assembles the launch kit.\n\nMake sure you have:\n\nTo try the agent quickly, use one of the sample images included in a new account. In the Media Library, select an asset and choose **Metadata > Edit Tags** to add the launch tag.\n\nYou’re ready when the agent can find your tagged asset and return at least one transformed image URL.\n\nThe same pattern can support a real estate agent that formats listings, a support agent that summarizes logs, or an events agent that creates a highlight reel and recap gallery.\n\nHere’s exactly how it works.\n\nThe repository separates the launch brief, agent loop, tools, and report generation:\n\n`index.js` gets a launch brief from the interactive wizard or a pre-created file. It passes that brief to `runProductLaunchAgent()` in `agent.js`, along with Claude’s system prompt and the available tools.\n\nThe agent loop decides which tools to call and in what order. Content tools generate the launch materials, Cloudinary tools find and transform the approved assets, and `report.js` assembles the results into an HTML report.\n\nThe main files are:\n\n```\nsrc/\n├── index.js                # entry point\n├── wizard.js               # builds the launch brief\n├── agent.js                # runs the agent loop\n├── report.js               # creates the HTML report\n└── tools/\n    ├── tool-definitions.js # schemas and routing\n    ├── content-tools.js    # content generation\n    └── cloudinary-tools.js # Cloudinary operations\n```\n\nClaude cannot access Cloudinary or generate content directly. The application gives it tools. Each tool has a name, a description, and a structured input schema that tells Claude what the tool does and what information it requires.\n\nFor example, this tool finds approved assets for a launch:\n\n```\n{\n  name: 'find_launch_assets',\n  description:\n    'Find assets already uploaded and tagged for this launch. Call this first.',\n  input_schema: {\n    type: 'object',\n    properties: {\n      tag: { type: 'string' },\n      resourceType: { type: 'string', enum: ['image', 'video'] },\n    },\n    required: ['tag'],\n  },\n}\n```\n\nThe description is part of the agent’s instructions. “Call this first” helps Claude resolve the available imagery before requesting content that depends on it.\n\nThe user uploads and tags the approved launch assets. The agent searches for them, then requests the required transformations from Cloudinary.\n\n`generateSocialCrops()` uses named presets so every platform gets a predictable output:\n\n``` js\nconst CROP_PRESETS = {\n  instagram_square: { width: 1080, height: 1080, crop: 'fill', gravity: 'auto' },\n  x_post: { width: 1600, height: 900, crop: 'fill', gravity: 'auto' },\n  linkedin_post: { width: 1200, height: 627, crop: 'fill', gravity: 'auto' },\n};\n\nconst url = cloudinary.url(publicId, {\n  transformation: [\n    {\n      ...CROP_PRESETS[platform],\n      fetch_format: 'auto',\n      quality: 'auto',\n    },\n  ],\n  secure: true,\n});\n```\n\n`gravity: 'auto'` helps Cloudinary keep the subject visible when the same source image is cropped into different shapes. `fetch_format: 'auto'` delivers an efficient format for the requesting browser, while `quality: 'auto'` balances visual quality and file size. The resulting optimized URLs are returned to Claude, which uses the appropriate image in each piece of launch content.\n\nClaude decides which tool to call next. After a tool runs, its result is added to the conversation history, so Claude can use that result when making its next decision.\n\n``` js\nconst messages = [{ role: 'user', content: brief }];\n\nfor (let turn = 0; turn < maxTurns; turn++) {\n  const response = await anthropic.messages.create({\n    model: MODEL,\n    system: SYSTEM_PROMPT,\n    tools: TOOLS,\n    messages,\n  });\n\n  messages.push({ role: 'assistant', content: response.content });\n\n  const toolUseBlocks = response.content.filter(\n    (block) => block.type === 'tool_use',\n  );\n\n  if (toolUseBlocks.length === 0) break;\n\n  const toolResults = [];\n  for (const block of toolUseBlocks) {\n    const output = await executeTool(block.name, block.input);\n    toolResults.push({\n      type: 'tool_result',\n      tool_use_id: block.id,\n      content: JSON.stringify(output),\n    });\n  }\n\n  messages.push({ role: 'user', content: toolResults });\n}\n```\n\nThe two `messages.push()` calls serve different purposes. The first records Claude’s response. The second records the results of the tools Claude requested. Together, they give Claude the context it needs to choose the next step.\n\nClaude can request several tools in one response. The application runs each one and matches every result to the original request with `tool_use_id`.\n\nThe loop stops when Claude returns a response without any `tool_use blocks`. That response is the completion signal: Claude has decided it has everything it needs for the launch kit.\n\n| Turn | Claude asks for | What comes back | \n|---|---|---|\n| 1 | `find_launch_assets` | The launch images | \n| 2 | `generate_social_crops` ,`generate_og_image` | Crop URLs and an Open Graph image URL | \n| 3 | `generate_blog_draft` | The generated blog draft | \n| 4 | Plain text; no tools | Final summary; the loop stops | \n\nThe run that produced the report above made 12 tool calls within the 14-turn limit. The limit prevents the agent from continuing indefinitely if it gets stuck.\n\nPrompts guide the agent, but important rules are also enforced in code. For example, content that embeds media cannot be generated until the application has attempted to find or upload a launch asset:\n\n``` js\nconst ASSET_STEP_TOOLS = new Set([\n  'find_launch_assets',\n  'upload_launch_image',\n]);\nconst MEDIA_DEPENDENT_TOOLS = new Set([\n  'generate_blog_draft',\n  'generate_social_posts',\n]);\n```\n\nIf no approved image is available, the agent stops rather than inventing one. As the system prompt puts it: “A fabricated image is worse than no image.” The code-level check makes that rule enforceable even if the model misinterprets the prompt.\n\nThis is the balance the application is designed to strike: Claude handles flexible orchestration, while the tools and application code control what the agent is allowed to do.\n\nIf you find the Product Launch Agent helpful, [clone the repository](http://github.com/cloudinary-devs/product-launch-agent) and connect it to your own Cloudinary product environment. Start with one tagged image and one launch brief, then expand the workflow as you learn what your team wants to automate.\n\nYou can extend the same workflow to:\n\nThese extensions turn the demo into a reusable production workflow. Cloudinary handles the repeatable media operations, while the agent orchestrates the work and leaves creative decisions to your team.\n\nShare what you generated or [open an issue](http://github.com/cloudinary-devs/product-launch-agent/issues) in the repository with your results. Tell us which Cloudinary operations you used and what you would like the agent to do next.\n\n**Search & discovery (keywords):** AI agents Cloudinary; Claude tool use; Anthropic API agents; Cloudinary asset search; Cloudinary image transformations; dynamic image URLs; `gravity: auto`; `crop: fill`; agent orchestration; deterministic tools; human-in-the-loop AI; automated content workflows; product launch automation; JavaScript SDK; media asset management.\n\n| **Cloudinary ❤️ developers** | \n|---|\n| Ready to build an agent that turns approved media into a complete launch kit? Start using Cloudinary for free and automate your image search, transformations, and delivery workflows. | \n| 👉 **[Create your free account](https://link.cloudinary.com/us4C7)** |", "url": "https://wpnews.pro/news/i-built-an-agent-that-does-a-week-of-work-in-one-command", "canonical_source": "https://dev.to/cloudinary/i-built-an-agent-that-does-a-week-of-work-in-one-command-57i7", "published_at": "2026-09-24 11:43:32+00:00", "updated_at": "2026-09-24 11:58:51.713102+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "generative-ai", "developer-tools"], "entities": ["Cloudinary", "Anthropic", "Claude", "Product Launch Agent", "Node.js"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/i-built-an-agent-that-does-a-week-of-work-in-one-command", "markdown": "https://wpnews.pro/news/i-built-an-agent-that-does-a-week-of-work-in-one-command.md", "text": "https://wpnews.pro/news/i-built-an-agent-that-does-a-week-of-work-in-one-command.txt", "jsonld": "https://wpnews.pro/news/i-built-an-agent-that-does-a-week-of-work-in-one-command.jsonld"}}