Prompt Mixes System and User Instructions

Persistent rules stuffed into the user message so the model can't prioritize them. Move them to the system / developer channel.

You wrote one long user message that bundles the role (“you are a senior engineer”), the global rules (“always respond in JSON, never use emoji”), the task (“rewrite this function”), and the input code. The model follows the rules sometimes and ignores them other times. By turn five of the conversation the rules are gone entirely, because they live in the same channel as the task and got buried under more recent input. The model is not broken. You put persistent rules in a turn-scoped channel. System instructions, project/custom instructions, and per-turn user messages have different lifecycles, and mixing them collapses the priority hierarchy the model relies on.

Fastest fix: take every rule that should apply on every turn (role, output format, tone) and move it out of the user message into the persistent channel — the system parameter in the API, or Custom Instructions / Project instructions in a chat UI. Leave only the current task and its inputs in the user message. That single move usually restores consistent behavior across the whole conversation.

This page explains why the split exists, how each major platform names the persistent channel as of June 2026, and how to route each piece of your prompt to the right place.

Which bucket are you in?

SymptomLikely causeJump to
One user message holds rules + taskEverything in one channelStep 1, Step 2
You retype the same rules every turnNot using the persistent channelStep 2
Rules hold for 2-3 turns then driftRules buried by recent turnsStep 2, Step 3
Output flips tone/format randomlySystem and user contradictStep 6
role: "system" in Claude messages[] is ignoredWrong channel for AnthropicStep 2 (Anthropic note)
Tools treated as suggestions, not contractsTools defined in proseStep 5

Common causes

1. Everything in one user message

You wrote one long message instead of using the system prompt, so rules and task now compete for attention in the same channel.

How to spot it: your API call has only one message with role user, or your chat UI conversation has all the rules typed into the message bar.

2. Not using the persistent channel at all

Many platforms hide the persistent channel behind a name like “Custom Instructions”, “Project instructions”, or “Saved info”, and a lot of users never realize it exists.

How to spot it: you have rules you want on every turn, but you keep retyping them.

3. Restating global rules in every user message

You noticed the model forgets, so you repaste the rules each turn. It works but wastes tokens, is fragile, and some of those pasted rules will silently conflict with a system prompt you set earlier.

How to spot it: every user message starts with the same five-line preamble.

4. System prompt and user message contradict

You wrote a system prompt yesterday that says “be formal” and today you type “keep it casual”. The model gets two authorities pointing opposite ways and the result wobbles.

How to spot it: you cannot remember what is in your system prompt.

5. Tools / functions configured in the user message

In agent workflows, tool definitions belong in their own slot. Inlining them in a user message is parseable, but the model treats them as suggestions rather than contracts with schema validation.

How to spot it: tool descriptions live in user prose instead of the tools parameter.

Before you change anything

  • List every line of your current prompt.
  • Categorize each line: system (persistent), user (turn-specific), tool (capability), assistant (history).
  • Mark which lines change per turn versus which are persistent.
  • Check what your platform actually supports — a chat UI and the raw API expose the channels differently.
  • Plan where each piece will live.

Collect, if you have them: the full prompt as sent, your current system / project instructions, the conversation history, the output that ignored the rules, and the exact model and platform.

Shortest path to fix

Step 1: Split persistent from per-turn

PERSISTENT (system / custom instructions):
- Role: "You are a senior backend engineer."
- Output format: "Return only valid JSON matching schema X."
- Voice rules: "No emoji. No exclamation marks."

PER-TURN (user message):
- "Rewrite the function below to add retry logic with exponential backoff."
- <code paste>

Splitting it makes both halves cleaner and easier to debug.

Step 2: Move persistent rules to the persistent channel

OpenAI API. For GPT-5.5 and every model since the o1 release, the instruction-bearing role is named developer, not system. The old system role still works (it is accepted as an alias and mapped to developer), but developer is the current name, and the platform enforces a fixed authority order of platform > developer > user, so developer instructions outrank anything the user types.

messages = [
  {"role": "developer", "content": "<all persistent rules>"},
  {"role": "user", "content": "<just this turn's task>"}
]

Anthropic (Claude) API. Claude does not use a message with role: "system". The system prompt is a top-level system parameter on the request, separate from the messages array. Putting {"role": "system", ...} inside messages is a common mistake — many Anthropic-compatible endpoints reject or ignore it.

import anthropic
client = anthropic.Anthropic()

client.messages.create(
    model="claude-opus-4-7",
    max_tokens=1024,
    system="<all persistent rules>",          # top-level, NOT a message
    messages=[{"role": "user", "content": "<just this turn's task>"}],
)

Chat UIs (as of June 2026):

  • ChatGPT — click your profile, then Settings -> Personalization -> Custom instructions. Toggle customization on and put your persistent rules there (the long-form fields cap at about 1500 characters each). For repeated work, a Project carries its own instructions for every chat inside it.
  • Claude — set persistent rules in Settings -> Profile (the “personal preferences” box that applies to all chats) or, better, create a Project and use its Project instructions / custom instructions so they auto-apply to every chat in that Project.
  • Gemini — use Saved info (and, for Gemini Gems, the Gem’s instructions) to carry rules across chats.
  • Cursor — put project-wide rules in .cursor/rules (or a top-level .cursorrules file for older setups).
  • Claude Code — put project-wide rules in CLAUDE.md at the repo root.

Step 3: Keep the user message focused on the immediate task

The per-turn message should contain only the new request, the new inputs, and anything that varies. Nothing that applies to every turn.

Bad:  "Remember: respond in JSON, no emoji, you are a senior engineer.
       Now: rewrite this function."
Good: "Rewrite this function:"
      <code>

Step 4: For the API, put the persistent channel first

For OpenAI, the developer (or system) message goes first in the array. For Claude, the system parameter is top-level, so ordering inside messages does not apply to it.

messages = [
  {"role": "developer", "content": "..."},   # first for OpenAI
  {"role": "user", "content": "..."},
  {"role": "assistant", "content": "..."},
  {"role": "user", "content": "..."}
]

If an instruction-bearing message appears mid-conversation on OpenAI, behavior is less predictable — keep your persistent rules in the first instruction message.

Step 5: Use tools / functions for capabilities

For agent workflows, define tools in the API’s tools parameter, not in prose. The model treats a declared tool as a binding contract with schema validation, instead of a soft suggestion buried in text.

tools = [{
  "type": "function",
  "function": {
    "name": "search_codebase",
    "description": "...",
    "parameters": {"type": "object", "properties": {}}
  }
}]

(On the Anthropic API the equivalent shape uses name, description, and input_schema per tool.)

Step 6: Audit and reconcile contradictions

Print your system / developer instructions. Print your latest user message. Look for conflicts. The persistent channel generally outranks the user message; if you want the user message to win on one specific point, say so explicitly: “For this turn only, override the rule about X from the system prompt.”

How to confirm it’s fixed

  • The same rules hold across 10+ turns without any re-pasting.
  • Your user messages are short and task-focused.
  • Deleting the old preamble from a user message does not change behavior — the rules survived in the persistent channel.
  • Different turns produce different task output but the same voice, format, and role.
  • Per-turn token usage drops noticeably (you stopped resending the preamble every turn).

If it still fails

  1. Your platform may not expose a real persistent channel — check its docs for “custom instructions” or “system prompt” support.
  2. Some platforms truncate long persistent instructions (ChatGPT’s custom-instruction fields cap around 1500 characters each) — shorten and prioritize.
  3. The model may not strictly honor system over user. Test it with a deliberately contradictory user message and see which one wins.
  4. On Claude, double-check you used the top-level system parameter, not a role: "system" message inside messages[].
  5. For a chat UI with no persistent channel, switch to the API, where the channel split is enforced by the request schema.

FAQ

What’s the difference between the system prompt and the user message? The system / developer channel carries persistent instructions — role, output format, tone, hard rules — and applies to every turn. The user message is per-turn: the specific request and its inputs. Persistent rules in the user message get buried by later turns and lose priority.

OpenAI: should I use the system role or the developer role in June 2026? Use developer. For every model since the o1 release (including GPT-5.5), developer is the current name for the instruction-bearing role. The old system role is still accepted and mapped to developer, so existing code keeps working, but new code should use developer.

Why is my Claude role: "system" message being ignored? Because Claude’s API does not take a system message inside messages[]. It takes a top-level system parameter on the request. Move your rules to system="..." alongside messages, not into the array.

Where is Custom Instructions in ChatGPT now? Profile menu -> Settings -> Personalization -> Custom instructions (toggle customization on). A Project also carries its own instructions for every chat inside it.

Does pasting the rules into every user message work? It mostly works but it is wasteful and fragile: you pay tokens for the preamble on every turn, and pasted rules can silently contradict a system prompt you set earlier. Set the rules once in the persistent channel instead.

Do system rules always beat user messages? Usually, but not absolutely. OpenAI enforces platform > developer > user, so developer instructions outrank the user. Strength varies by model, so for anything critical, test with a contradictory user message and keep the rule in the persistent channel.

Prevention

  • Default: persistent rules go in the system / project / custom-instructions channel; user messages carry only the turn’s task.
  • For a new chat, set the persistent channel before sending the first user message.
  • Audit project / custom instructions periodically — stale rules quietly corrupt new tasks.
  • For team workflows, store system prompts in version control alongside the code.
  • When tempted to retype a rule in the user message, ask: “should this go in the persistent channel?”
  • For API agent workflows, declare capabilities as tools/functions, not prose.

Tags: #Prompt #Troubleshooting