Skip to Content
AgentsContent Repurposer

Content Repurposer

[Live — April 2026] · agent__content-repurposer · Claude Sonnet 4.6

Transforms approved content (blog posts, reports, social posts, newsletters) into derivative formats in a single batch job. Source-constrained — extracts and reformats, does not invent new claims.

Related: Blog Writer · Social Post Writer · Email Writer


Overview

FunctionTransform approved content into derivative formats (social post, email, ad copy, thread, carousel, landing page)
TypeBatch worker — Content
ModelClaude Sonnet 4.6 (via adapter-claude-local)
Queueagent__content-repurposer
Concurrency3 batches; 10 jobs/minute rate limit
Credits0.5 cr per derivative format
PlanPro+
StatusLive (April 2026)
Workerpackages/agents/src/workers/content-repurposer.worker.ts

Triggers

TriggerWhenWho initiates
ManualClient clicks “Repurpose Content” on an approved blog post detail pageClient (dashboard)

The “Repurpose Content” button (apps/dashboard/src/app/(dashboard)/blog/[id]/BlogPostDetail.tsx) renders only when post.status === "client_approved". It opens RepurposeModal.tsx where the client picks one or more target formats. On submit, repurposeContent() server action creates Activity records and enqueues this worker.


Input

interface ContentRepurposerJobData { batchId: string; // UUID grouping all derivatives in this run tenantId: string; tenantName: string; sourceDeliverableId: string; // ID of source BlogPost / Report / SocialPost / EmailNewsletter sourceActivityId: string; // Activity linked to the source deliverable sourceType: "blog_post" | "report" | "social_post" | "newsletter"; sourceContent: string; // Full markdown / text content sourceVersion: number; // Source record version at time of repurposing targetFormats: Array<{ type: "social_post" | "email_newsletter" | "ad_copy" | "thread" | "carousel" | "landing_page"; platform?: string; // For social_post: "linkedin" | "instagram" | "facebook" | "x" activityId: string; // Pre-created Activity record for this derivative }>; templateId?: string; // FK → RepurposingTemplate (custom prompt override) agentRole?: string; wakeReason?: string; }

Activity records are created before the job is enqueued (one per target format, status: "pending", deliverablePeriodId: null).


Repurposing Matrix

SourceSupported target formats
blog_postsocial_post, email_newsletter, ad_copy, thread, carousel, landing_page
reportsocial_post, email_newsletter, thread, carousel
social_postad_copy, thread
newslettersocial_post, ad_copy

Invalid source → target combinations throw immediately before credits are reserved.


Output

Each derivative is persisted and the associated Activity is updated:

Target typeDB tableKey fields
social_postSocialPostbodyText, hashtags, engagementHook, contentType, platform; status: "dm_review"
email_newsletterEmailNewslettersubject, preheader, content; status: "dm_review"
ad_copyActivity outputPayloadheadline, description, cta, targetAudience
threadActivity outputPayloadtweets[] (order, text, type: hook/body/cta)
carouselActivity outputPayloadslides[] (order, title, text, visualSuggestion), caption, hashtags
landing_pageActivity outputPayloadheadline, subheadline, hero/problem/solution/benefits sections, CTAs

After each derivative: Activity.status → "awaiting_approval", Activity.outputPayload = raw JSON.


How It Works

  1. Validate all repurposing paths against the matrix.
  2. Fetch tenant contextClientContext.content and BrandVoice.guidelines are injected into every prompt.
  3. Reserve creditstargetFormats.length × 0.5 credits reserved upfront; unused credits released on batch-level failure.
  4. Emit agent:started.
  5. For each target format (sequentially):
    • Build prompt via buildRepurposePrompt() — selects built-in system prompt by key "${sourceType}_to_${targetType}", or uses RepurposingTemplate.promptTemplate if templateId provided.
    • Call Claude (temperature: 0.7, maxTokens: 2000).
    • Parse JSON via extractJson() (handles fenced code blocks and raw JSON; balanced-brace parser).
    • Save derivative via saveDerivative() switch statement.
    • Activity.status → "awaiting_approval", Activity.outputPayload = content.
    • Consume 0.5 credits.
    • On per-format failure: mark activity "failed", log error, continue to next format (batch is not aborted).
  6. Save RepurposingAnalytics record.
  7. Write activity log and send in-app notification (“Content Repurposing Complete — N of M derivatives generated”).
  8. Emit agent:completed with durationMs.

System Prompts

One built-in prompt per source→target path. All prompts:

  • Instruct Claude to extract/reformat from source without inventing new claims
  • Specify the exact JSON schema Claude must output
  • Platform-specific tone/format rules for social posts (LinkedIn professional, Instagram hook-first, etc.)

Custom templates override via RepurposingTemplate.promptTemplate (DB model).

Prompts also include CLIENT CONTEXT and BRAND VOICE GUIDELINES when available on the tenant.


HITL Gates

Derivatives follow the standard 2-gate workflow:

GateApproverPortal
DM reviewDM reviewerDM Portal
Client reviewClientDashboard

Cost Profile

DerivativesCreditsApprox. LLM tokens
1 format0.5 cr~2,000–3,000 tokens
3 formats1.5 cr~6,000–9,000 tokens
6 formats3.0 cr~12,000–18,000 tokens

Cost is ~50% of from-scratch generation because source content eliminates research steps.


Error Handling

FailureBehaviour
Invalid repurposing pathThrows immediately; credits never reserved
Missing activityIdServer action guards (if (!post.activityId) return error)
Per-format Claude failureActivity marked "failed"; batch continues; credits not consumed for that format
Batch-level exceptionUnreserved credits released; agent:failed emitted; job retried (attempts: 2, exponential backoff 5 s)

E2E Tests

apps/dashboard/tests/e2e/blog-flow.spec.ts — Step 7 (8 tests):

  • Button visible only on client_approved posts; hidden on dm_review
  • Modal opens with 6 format cards
  • Submit disabled when no format selected
  • Social Post card shows platform picker (LinkedIn / Instagram / Facebook / X)
  • Cancel closes modal
  • Email Newsletter + Social Post full submit: success banner + DB Activity record verification

© 2026 Leadmetrics — Internal use only