Template · Marketing

Blog post from a brief

Label an issue blog, or post a brief to a webhook. Claude Code researches the topic and proposes three angles. You pick one at the approval gate, it writes the post with sources, an editor model checks it against your voice and flags unsupported claims, and the approved draft is sent to your CMS or docs tool.

Download .json

LinearMKT-77Why finance teams are moving off spreadsheets for closeblog
Pipeline
  1. Research angles Claude Code · Sonnet
  2. Pick an angle You
  3. Write the post Claude Code · Sonnet
  4. Edit for voice and claims Claude API · Opus 5
  5. Approve draft You
  6. Send draft to CMS Shell
CMS draftThe close checklist is the product1,180 words · 6 sources · voice check passedDraft
The pipeline

What each step does

  1. Research angles

    Claude Code · Sonnet

    Researches the topic on the web and proposes three angles, each with a hook, outline and sources.

  2. Pick an angle

    You

    You pick one angle and can add notes for the writer.

  3. Write the post

    Claude Code · Sonnet

    Writes the post for the picked angle and checks every fact against its sources.

  4. Edit for voice and claims

    Claude API · Opus 5

    An editor model checks voice and unsupported claims, and sends the draft back until it passes.

    If it fails, goes back to Write the post, up to 2 times.

  5. Approve draft

    You

    Shows you the final draft. Reject with a comment and it is rewritten.

  6. Send draft to CMS

    Shell

    Posts the title and Markdown to your CMS or docs tool through a webhook.

Set it up

From copy to first run

  1. Copy the pipeline JSON with the button above.
  2. In Jimothy, open Pipelines → New pipeline, paste it under “Or import a pipeline JSON” and click Import.
  3. Fill in the variables below under Pipeline settings → Variables.
  4. Triggers → Add trigger → Linear, Jira or GitHub, filtered to the blog label. Or a Webhook trigger with title (topic) and description (brief).
Variables

What to fill in

The prompts and commands read these as {{vars.<name>}}. The examples are placeholders: replace them with your own.

VariableWhat to put in itExample
companyWho is publishing, and what you sell.Acme, a reporting tool for finance teams
audienceWho the post is for.Controllers and finance managers at companies of 50 to 500 people
voiceYour style guide in a few sentences. The editor step enforces it.Plain, specific and a little dry. Short paragraphs. Concrete examples over adjectives. N…
publishWebhookUrlWhere approved drafts go, e.g. a Zapier hook that creates a Google Doc, Notion page or CMS draft.—
Show the pipeline JSON
{
  "jimothyPipeline": 1,
  "name": "Blog post from a brief",
  "description": "Researches a brief, offers three angles to pick from, writes and edits the post, and sends the approved draft on.",
  "icon": "sparkles",
  "color": "#ec4899",
  "repo": {
    "mode": "scratch"
  },
  "concurrency": 2,
  "variables": {
    "company": "Acme, a reporting tool for finance teams",
    "audience": "Controllers and finance managers at companies of 50 to 500 people",
    "voice": "Plain, specific and a little dry. Short paragraphs. Concrete examples over adjectives. No hype words, no exclamation marks, no \"in today’s fast-paced world\".",
    "publishWebhookUrl": ""
  },
  "steps": [
    {
      "id": "angles",
      "name": "Research angles",
      "type": "agent",
      "description": "Researches the topic on the web and proposes three angles, each with a hook, outline and sources.",
      "harnessId": "claude-code",
      "model": "sonnet",
      "timeoutMinutes": 20,
      "prompt": "We are {{vars.company}}, writing for {{vars.audience}}.\n\nTopic: {{issue.title}}\nBrief:\n{{issue.description | default:\"(no brief beyond the title)\"}}\n\nResearch the topic on the web: what has already been written, what the audience argues about, and data we could cite. Then propose exactly three distinct angles for a blog post, each in this shape:\n\n### Angle 1: <working headline>\n- Hook: <the opening idea in one sentence>\n- Argument: <the post's claim in two sentences>\n- Outline: <four to six section headings>\n- Sources: <the URLs it would lean on>\n\nYour final answer is the three angles and nothing else."
    },
    {
      "id": "pick",
      "name": "Pick an angle",
      "type": "approval",
      "description": "You pick one angle and can add notes for the writer.",
      "dependsOn": [
        "angles"
      ],
      "choices": {
        "fromStep": "angles",
        "mode": "single"
      },
      "approvalMessage": "Pick the angle to write for **{{issue.title}}**. Add a comment with anything the writer should know."
    },
    {
      "id": "draft",
      "name": "Write the post",
      "type": "agent",
      "description": "Writes the post for the picked angle and checks every fact against its sources.",
      "harnessId": "claude-code",
      "model": "sonnet",
      "dependsOn": [
        "pick"
      ],
      "timeoutMinutes": 30,
      "systemPrompt": "You write for {{vars.company}}. Audience: {{vars.audience}}. Voice: {{vars.voice}}",
      "prompt": "Write the blog post for this angle:\n\n{{steps.pick.selected}}\n{{#if steps.pick.comment}}\nNotes from the editor who picked it: {{steps.pick.comment}}\n{{/if}}\nOriginal brief: {{issue.description | default:\"(none)\"}}\n\nOpen the sources and check every fact you use; drop anything you can't confirm. 900 to 1,400 words. Markdown, starting with a # headline, with a \"Sources\" list of the URLs you used at the end. Your final answer is the post and nothing else.{{#if steps.edit.output}}\n\nThe editor reviewed your previous draft. Address every point:\n{{steps.edit.output}}{{/if}}{{#if steps.approve.output}}\n\nYour previous draft was rejected with this feedback. Rewrite it:\n{{steps.approve.output}}{{/if}}"
    },
    {
      "id": "edit",
      "name": "Edit for voice and claims",
      "type": "agent",
      "description": "An editor model checks voice and unsupported claims, and sends the draft back until it passes.",
      "harnessId": "anthropic-api",
      "model": "claude-opus-5",
      "dependsOn": [
        "draft"
      ],
      "timeoutMinutes": 10,
      "passPattern": "VERDICT:\\s*APPROVE",
      "loopBackTo": "draft",
      "maxLoops": 2,
      "prompt": "You are the editor. Voice guide: {{vars.voice}}\n\nDraft:\n{{steps.draft.output}}\n\nList concrete problems only: sentences that break the voice guide, claims or numbers without a source in the Sources list, sections that drift from the headline's argument, and anything a {{vars.audience}} reader would find vague. Quote the sentence for each. End with exactly one line: VERDICT: APPROVE if it's ready, otherwise VERDICT: CHANGES_REQUESTED."
    },
    {
      "id": "approve",
      "name": "Approve draft",
      "type": "approval",
      "description": "Shows you the final draft. Reject with a comment and it is rewritten.",
      "dependsOn": [
        "edit"
      ],
      "loopBackTo": "draft",
      "maxLoops": 3,
      "approvalMessage": "Send this draft on? Reject with a comment to have it rewritten.\n\n---\n\n{{steps.draft.output}}"
    },
    {
      "id": "publish",
      "name": "Send draft to CMS",
      "type": "shell",
      "description": "Posts the title and Markdown to your CMS or docs tool through a webhook.",
      "dependsOn": [
        "approve"
      ],
      "timeoutMinutes": 2,
      "command": "printf '{\"brief\":%s,\"title\":%s,\"markdown\":%s}' {{issue.key | json}} {{steps.draft.output | first_line | json}} {{steps.draft.output | json}} | curl -fsS -X POST -H 'Content-Type: application/json' --data @- {{vars.publishWebhookUrl}}"
    }
  ]
}