I hit one of those bugs that feels obvious after you fix it, but confusing while you’re inside it. The auto writer was producing decent drafts, then suddenly it started repeating entire sections. Same idea, same structure, sometimes almost the same wording. At first I thought the model was being lazy. Then I blamed the outline. Then I blamed temperature. None of those were the real issue.
The real problem was much simpler: I was injecting the global prompt twice.
Once I saw it, the whole thing clicked. The auto writer was not randomly repeating itself. I was accidentally telling it to follow the same high-level article instructions in two different places, then asking it to write section-by-section. That made the model treat every section like it needed to restate the full article plan.
This is the fix, how I found it, and what I changed so it does not sneak back in later.
The symptom: sections kept sounding like the intro again
The auto writer works in passes. First it builds the article structure. Then it writes each section using the section heading, a short section brief, the full article context, and the writing rules.
That setup usually gives me better control than asking for the entire article in one huge prompt. I can inspect each section, retry one piece if needed, and keep the writing closer to the outline. At least, that was the plan.
Then I started seeing this pattern:
- The intro would explain the main problem.
- The first body section would explain the same problem again.
- The second section would reintroduce the tool like the reader had never heard of it.
- The conclusion would sound like a second intro instead of a clean finish.
At first, it looked like a normal generation quality issue. Repetition happens. But this was too consistent. The repeated sections had the same shape, not just similar wording. They were following the same hidden instruction stack over and over.
That was the clue.
The first wrong guess: maybe the outline was too vague
My first move was to tighten the outline. I added clearer section briefs, better intent per heading, and notes like “do not repeat the intro.” That helped a little, but not enough.
The auto writer still kept circling back to the same framing. It would obey the section brief for a few paragraphs, then drift back into the global article pitch.
That told me the outline was not the main problem. If the section brief was present and specific, but the output still kept resetting, something else was competing with it.
So I stopped editing the content rules and started logging the actual prompt payload.
The useful debugging move: print the assembled prompt
This was the small win that cracked it open. I added a debug mode that saves the final prompt sent to the model for each section. Not the config. Not the separate prompt parts. The final assembled payload.
That distinction matters. I had been reading the source files and thinking, “This looks fine.” But source files do not show what actually gets shipped after helpers, fallbacks, defaults, and merged objects have had their say.
When I printed the final request, I found the global writing instructions in two places:
- Inside the main system-level instruction block.
- Again inside the section-specific user prompt.
Both copies were slightly different because they came through two paths in the code. That made it even messier. The model was not just seeing duplicates. It was seeing overlapping instructions with similar goals, repeated language, and slightly different ordering.
The bug was not that the writer ignored instructions. The bug was that it followed too many copies of the same instruction.
How the double-injection happened
This came from a normal builder mistake. I was moving fast and improving the prompt system in layers.
Early on, I had a simple section prompt. It included everything: tone, article goal, formatting rules, section heading, section brief, and output rules.
Later, I added a global prompt layer so every writing task could share the same base rules. That was a good idea. The problem is that I did not fully remove the older global content from the section prompt template.
So the prompt builder looked clean from a distance, but the section writer was still carrying old baggage.
| Prompt part | What it should contain | What it accidentally contained |
|---|---|---|
| Global prompt | Voice, formatting, article-level rules | Voice, formatting, article-level rules |
| Section prompt | Heading, section goal, local context | Heading, section goal, local context, and another copy of global rules |
| Final payload | One global instruction set plus one section task | Two global instruction sets plus one section task |
This is the kind of bug that hides because each individual piece looks reasonable. The global prompt was useful. The section prompt was useful. Together, they were too loud.
Why duplicate global prompts cause repeated sections
Models pay attention to patterns in the prompt. If the prompt repeats the article goal twice, the output tends to keep returning to that goal. If the prompt repeats the audience, the article keeps re-explaining who it is for. If the prompt repeats the content format, the model may keep rebuilding the same structure inside each section.
That is exactly what I was seeing.
The global prompt said something like: explain the problem, show the fix, keep it practical, document the build journey. Then the section prompt said almost the same thing again before asking for one specific section.
So every section had a hidden push to behave like a mini article. Instead of writing “here is the specific thing that happened in this step,” it kept writing “here is the whole journey again, starting from the problem.”
That is why telling it “do not repeat” did not fully work. The prompt itself was creating the repetition pressure.
The fix: one source for global instructions
I changed the prompt builder so global instructions can only enter through one path. The section prompt is no longer allowed to include global writing rules. It gets the section job and nothing more.
The new split is simple:
- Global prompt: voice, style, formatting, article-wide rules, safety rails.
- Article context: title, topic, audience, angle, outline.
- Section prompt: current heading, section brief, what came before, what this section must add.
- Output instruction: return only the section content in the expected format.
That last part matters too. I keep the output instruction narrow. If I ask for a section, I do not want the model to include a title, summary, outline, or notes about what it is doing. Just the section.
After the change, the section prompt got much shorter. That felt risky for about five seconds, then the outputs got cleaner.
The actual builder change
I did not patch this with a one-off string replace. I wanted the structure to make the mistake harder to repeat.
So I added a prompt assembly function that takes named fields and builds the final messages in a fixed order. Before this, too many pieces were allowed to concatenate their own instruction text. That gave me speed early on, but it also made the prompt harder to reason about.
Now the builder has a clean boundary:
- The global prompt is created once.
- The section prompt cannot access the global prompt string.
- The final payload is logged in debug mode.
- A small duplicate check warns me if the same global marker appears twice.
I also added a simple marker at the top of the global prompt in development mode. Something like [GLOBAL_WRITING_RULES]. The app checks the final payload and counts how many times that marker appears. If it shows up more than once, I know the builder is leaking instructions again.
That is not fancy, but it works. Sometimes a boring guardrail is the best guardrail.
The test that proved it
After changing the prompt assembly, I ran the same article request through the auto writer twice. Same topic. Same outline. Same section count. Same model settings.
The difference was easy to spot. Before the fix, the section openers kept repeating the article premise. After the fix, each section moved forward.
The article still needed editing, of course. This is not magic. But the repeated-section bug was gone. The writer was finally treating each heading like one piece of a larger draft instead of a fresh chance to restart the whole article.
I also tested a longer outline because repetition tends to get worse as the article grows. The fixed version held up better. By section six or seven, it still had some natural overlap, but not the copy-paste feeling from before.
What broke while fixing it
One thing did break. When I removed the extra global instructions from the section prompt, a few sections became too plain. They followed the brief, but lost some of the voice I wanted.
That showed me I had been using repetition as a rough way to force tone. Bad trade.
Instead of putting the full style guide back into every section, I added a short voice reminder to the section task. Not the whole global prompt. Just one line tied to the current section, like: “Write this section in the same practical builder voice, focused on what changed and why.”
That gave the model a local nudge without dragging the full article instructions back into the prompt.
The new section prompt shape
The section prompt is now closer to a work order than a style guide. It tells the writer what job this exact section has to do.
Here is the shape I settled on:
- Current heading.
- Section goal in one or two sentences.
- Previous section recap, only if needed.
- What this section should add that has not already been covered.
- Output format for this section only.
The most helpful line is “what this section should add.” That one little field keeps the writer from circling back. It gives the model a forward motion cue.
I also stopped passing the entire previous draft into every section. That was another source of soft repetition. Now I pass a short recap or a list of covered points. Less text. Better signal.
A quick checklist for spotting this bug in your own writer
If you are building something similar, this bug is easy to miss. Here is the checklist I wish I had used earlier:
- Log the final assembled prompt, not just the prompt parts.
- Search the payload for repeated instruction blocks.
- Check whether global rules appear in both system and user messages.
- Look for section prompts that still contain old article-level wording.
- Add a temporary marker to global prompts and count it before sending.
- Compare outputs before and after the prompt cleanup using the same article brief.
The key is to debug the assembled request. That is where the truth lives.
What I learned from this one
This fix reminded me that prompt systems need the same kind of structure as code. Maybe even more, because the failure mode looks like “the model wrote badly” when the real issue is often “the app asked badly.”
I also learned to be careful with helpful duplication. Repeating an instruction can feel like making it stronger, but in a multi-step writer it can make every step act like the whole task.
The better pattern is separation. Global rules set the lane. Section prompts give the next move. Context tells the writer where it is in the draft. Each part has one job.
That is the version I trust more now.
The current status
The repeated sections are fixed. The global prompt only enters once. The section writer now gets a tighter task, a cleaner context package, and a small voice reminder instead of another full instruction dump.
I’m keeping the debug prompt logs in place while I keep building. They are too useful to remove. Any time the output gets weird, I can inspect what the model actually saw instead of guessing from the UI.
This was a good builder lesson. When the writing feels repetitive, do not only edit the writing rules. Inspect the pipe. The bug might be hiding in the prompt assembly layer, quietly telling the model to start over again and again.