appscript.dev
Automation Advanced

Build a multi-step AI agent workflow

Chain Claude prompts to complete a Northwind task end to end — research → draft → critique → finalise.

Published Feb 11, 2026

A single “write me a blog post about X” prompt gets you a single take — and it shows. Northwind’s marketing posts came back flat: factually thin, no real structure, the kind of draft an editor has to rebuild from scratch.

This workflow treats the model less like a vending machine and more like a small team. It runs four prompts in sequence — research the facts, draft from those facts, critique the draft, then revise against the critique. Each step’s output feeds the next, so the model improves its own work the way a writer and an editor would in two passes. The final draft is genuinely closer to publishable.

What you’ll need

  • An Anthropic API key saved as ANTHROPIC_API_KEY in Script Properties — see Store API keys and secrets securely.
  • A topic to run through the flow. The script takes it as an argument and returns every intermediate result, so you can inspect any stage.

The flow

  1. Research — gather the key facts.
  2. Draft — write a first version from those facts.
  3. Critique — identify specific weaknesses.
  4. Revise — produce a final version addressing the critique.

The script

// Model used for every step. Sonnet is worth it here — each stage
// reasons over the previous stage's output.
const MODEL = 'claude-sonnet-4-6';

// Token ceiling per call. Generous enough for a short post plus
// its research and critique.
const MAX_TOKENS = 1000;

/**
 * Runs a topic through a four-step research → draft → critique → revise
 * chain, returning every intermediate result.
 *
 * @param {string} topic - The subject to write about.
 * @returns {{research: string, draft: string, critique: string, final: string}}
 */
function runAgentFlow(topic) {
  if (!topic) {
    throw new Error('runAgentFlow needs a topic.');
  }

  // 1. Research: collect raw facts before any writing happens.
  const research = callClaude(
    `What are 5 key facts about Northwind's ${topic}? Bullets only.`);

  // 2. Draft: write a first version grounded in those facts.
  const draft = callClaude(
    `Write a 200-word post about Northwind's ${topic} using these facts:\n${research}`);

  // 3. Critique: have the model find concrete weaknesses in its draft.
  const critique = callClaude(
    `Critique this draft. List 3 specific weaknesses to address.\n\n${draft}`);

  // 4. Revise: produce a final version that answers the critique.
  const final = callClaude(
    `Revise the draft addressing these critiques.\n\n` +
    `Draft:\n${draft}\n\nCritique:\n${critique}`);

  Logger.log(`Agent flow complete for topic: ${topic}`);
  return { research, draft, critique, final };
}

/**
 * Minimal Anthropic API call. The key lives in Script Properties — it
 * is never pasted into the code.
 *
 * @param {string} prompt - The user prompt to send.
 * @returns {string} The model's text reply.
 */
function callClaude(prompt) {
  const key = PropertiesService.getScriptProperties()
    .getProperty('ANTHROPIC_API_KEY');
  const res = UrlFetchApp.fetch('https://api.anthropic.com/v1/messages', {
    method: 'post',
    contentType: 'application/json',
    headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01' },
    payload: JSON.stringify({
      model: MODEL,
      max_tokens: MAX_TOKENS,
      messages: [{ role: 'user', content: prompt }],
    }),
    muteHttpExceptions: true,
  });
  return JSON.parse(res.getContentText()).content[0].text.trim();
}

How it works

  1. runAgentFlow takes a topic and bails out early if none was passed.
  2. Research asks for five bulleted facts — no prose. Pinning the format keeps this step a clean input for the next one.
  3. Draft writes a 200-word post, with the research bullets pasted in so the draft is grounded rather than invented.
  4. Critique feeds the draft straight back and asks for three specific weaknesses. Asking for specific points avoids vague “make it better” notes.
  5. Revise sends both the draft and the critique together and asks for a final version. The model now has a target to fix against, not a blank page.
  6. The function returns all four strings, so you can read the research and critique as well as the final — useful when the output still misses.
  7. callClaude is one helper used by every step; the API key stays in Script Properties.

Example run

Calling runAgentFlow('onboarding process') returns an object whose stages build on one another:

  • research- Onboarding takes 3 days on average, - 90% of new clients complete a kickoff call, …
  • draft — a 200-word post, accurate but a little generic.
  • critique1. No concrete example. 2. Weak opening line. 3. Buries the 3-day stat.
  • final — the same post, opening with the 3-day stat and a real example woven in.

The jump from draft to final is the point of the workflow — the second pass fixes what the first one missed.

Run it

This is an on-demand job. Because runAgentFlow takes an argument, call it from a small wrapper:

function runOnboardingFlow() {
  const result = runAgentFlow('onboarding process');
  Logger.log(result.final);
}

Select runOnboardingFlow, click Run, approve the authorisation prompt the first time, then read the final draft in the execution log.

Watch out for

  • Four calls per run. Each one costs tokens and time, so a flow is several times the price and latency of a single prompt. Run it deliberately, not in a loop.
  • The total runtime of four sequential calls can approach the six-minute execution limit on a slow day. If it does, persist each stage’s output and resume rather than restarting the whole chain.
  • Errors are not handled per step. muteHttpExceptions stops a hard failure, but a bad response from step 2 still poisons steps 3 and 4. Check each result is non-empty before passing it on if reliability matters.
  • The critique step can be polite to a fault. If revisions feel cosmetic, push the prompt — ask for the single biggest flaw, or score the draft out of ten.
  • More steps is not always better. Research → draft → critique → revise is a solid default; adding a fifth and sixth pass tends to drift, not improve.

Related