Marketing automation
Plan, create, and publish a bounded set of campaign content.
Use a Runlane task to coordinate an AI-assisted content pipeline. Your application supplies the model, publishing destinations, templates, credentials, approval policy, and campaign state.
Run a content pipeline
The Runlane task, retry policy, and durable steps below are real. The marked planning and publishing calls are pseudocode for your application and providers:
import { task } from '@runlane/core'
import * as z from 'zod'
const contentPlanSchema = z.object({
pieces: z.array(z.object({ id: z.string(), type: z.enum(['blog', 'thread']) })).max(20),
tone: z.string(),
})
const campaignResultSchema = z.object({ published: z.number().int(), total: z.number().int() })
export const contentPipeline = task({
id: 'marketing.content-pipeline',
schema: z.object({ topic: z.string().min(1) }),
output: campaignResultSchema,
retry: { maxAttempts: 3 },
async run({ topic }, context) {
const plan = await context.step.run('plan-content', { output: contentPlanSchema }, async ({ token }) => {
//////////////////////////////////
// MAKE YOUR API CALLS HERE
//////////////////////////////////
const result = await createContentPlan({ idempotencyKey: token, signal: context.signal, topic })
return contentPlanSchema.parse(result)
})
const published = await context.step.run('create-and-publish', { output: z.number().int() }, async ({ token }) => {
//////////////////////////////////
// MAKE YOUR API CALLS HERE
//////////////////////////////////
return createAndPublishContent({ idempotencyKey: token, plan, signal: context.signal, topic })
})
return { published, total: plan.pieces.length }
},
})The content plan is validated and capped at 20 pieces. createAndPublishContent() may generate independent pieces in parallel, but that concurrency runs inside one attempt; it is not a durable child-run join.
The final step stores the number of successfully published pieces. Pass its token to downstream providers as an idempotency key or derive stable keys for individual pieces.
Keep campaign policy in the application
Runlane coordinates the job. Your application remains the source of truth for campaign state, approvals, destination accounts, content policy, and publish history.
For customer-created campaign schedules, keep the schedule in your application and trigger Runlane when the campaign becomes due. Task-colocated schedules are static code definitions.
Before production
- Bound the number and size of generated pieces.
- Put model and publishing quotas on bounded queues.
- Require approval where publishing policy demands it.
- Make every external publish safe to repeat.
- Test partial publication and provider failures.
See save step results and limit concurrency.