 ##  [Editorial workflows with reduce and generate in Nushell](/node/148) 

    *Submitted by Lennart on Mon, 2 Feb 2026 - 13:41*  

 For a simple editorial workflow, I would almost certainly choose **`reduce`**, but the "cool" choice (and the one that feels more like an autonomous agent) is **`generate`**.

Here is how to decide based on what your "workflow" actually looks like:

### Option 1: Use `reduce` (The "Linear Polisher")

Use `reduce` if you have a **fixed set of operations** you want to run on a piece of text (e.g., "Fix Grammar" "Shorten" "Change Tone").

In this scenario, you are "folding" a list of instructions over your text.

```
let tasks = ["fix grammar", "make it sound more professional", "convert to markdown"]
let original_text = "i is writing a nushell script for agents"

let final_draft = ($tasks | reduce -f $original_text {|task, current_text|
    # Each step takes the output of the previous LLM call
    call-brain $"Apply this edit: ($task)" $current_text
})


```

- **Best for:** Consistency. You know exactly how many steps are involved.
- **Logic:** .

### Option 2: Use `generate` (The "Iterative Refiner")

Use `generate` if you want the agent to **keep editing until it’s happy**. `generate` creates a stream, which is perfect for an "Editorial Loop" where the agent looks at its own work and decides if it needs another pass.

```
# generate {|state| {out: <value_to_emit>, next: <next_state>} } <initial_state>
let initial_state = { text: "The draft...", count: 0, done: false }

let editorial_history = (generate {|state|
    if $state.done or $state.count > 3 { return null } # Exit condition

    let feedback = (call-brain "Review this text. Is it perfect? Respond with 'YES' or feedback." $state.text)
    
    if ($feedback | str contains "YES") {
        {out: $state.text, next: {done: true}}
    } else {
        let new_text = (call-brain $"Apply this feedback: ($feedback)" $state.text)
        {out: $new_text, next: {text: $new_text, count: ($state.count + 1), done: false}}
    }
} $initial_state)

let final_result = ($editorial_history | last)


```

- **Best for:** Quality. It mimics a human editor who sends back a draft multiple times.
- **Logic:** Start Is it good? No? Edit and Repeat.

### Comparison Table

Feature`reduce``generate`**Flow**Deterministic (1 2 3)Dynamic (Loop until done)**Termination**Ends when the list of tasks is emptyEnds when a condition is met (or limit reached)**Visibility**Harder to see intermediate steps mid-streamEmits every version as a stream member (great for logging)**Use Case**Batch processingSelf-correcting agents### My Recommendation

If you are building an **Agent System** with `xs`, use **`generate`**.

Why? Because `generate` allows the LLM to decide the "next state." It can output the current draft to an `xs` stream at every iteration, giving you a perfect audit trail of how the "editorial brain" evolved the text.

**Would you like me to show you how to wrap that `generate` loop so it writes every "revision" to an `xs` stream in real-time?**

Be sure to stay tuned if you want to learn more about xs (cross.stream), event sourcing and nushell with AI and LLMs.