You wrote a long single user message containing the role (“you are a senior engineer”), global rules (“always respond in JSON, never use emoji”), the task (“rewrite this function”), and the input code. The model sometimes follows the rules. The model sometimes ignores them. By turn 5 of the conversation, the rules are forgotten entirely because they live in the same channel as the task and got buried by recent input. The issue is not the model. The issue is that you put persistent rules in a turn-scoped channel. System prompts, project instructions, and user messages have different lifecycles — mixing them collapses the hierarchy.
This page walks through why the system / user split exists and how to route each piece of your prompt to the right channel.
Common causes
1. Everything in one user message
You wrote one long message instead of using the system prompt. Now rules and task compete for attention.
How to spot it: your API call has only one message with role “user”, or your chat UI conversation has all rules in the message bar.
2. Not using the system prompt at all
Some platforms hide the system prompt or call it “custom instructions” or “project instructions”. Many users do not realize it exists.
How to spot it: you have rules you want to apply every turn but you keep retyping them.
3. Restating global rules in every user message
You learned that the model forgets, so you repaste the rules each turn. This works but wastes tokens and is fragile. Some rules then conflict with the system prompt silently.
How to spot it: every user message starts with the same 5-line preamble.
4. System prompt and user message contradict
You wrote a system prompt yesterday saying “be formal” and today you write “keep it casual”. The model averages.
How to spot it: you cannot remember what is in your system prompt.
5. Tools / functions configured in user message
For agent workflows, tool definitions belong in their own slot. Inlining them in user message is parseable but the model treats them as suggestions, not contracts.
How to spot it: tool descriptions live in user prose.
Before you change anything
- List every line of your current prompt.
- Categorize each: system (persistent), user (turn-specific), tool (capability), assistant (history).
- Identify which lines change per turn vs which are persistent.
- Check what your platform actually supports (chat UI vs API differ).
- Plan where each piece will live.
Information to collect
- Full current prompt as sent.
- Your system prompt / project instructions if any.
- The conversation history if relevant.
- The output that ignored rules.
- Model and platform.
Shortest path to fix
Step 1: Identify what is persistent vs per-turn
PERSISTENT (system prompt):
- 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>
The split makes both halves cleaner.
Step 2: Move persistent rules to system prompt
In API:
messages = [
{"role": "system", "content": "<all persistent rules>"},
{"role": "user", "content": "<just this turn's task>"}
]
In ChatGPT / Claude / Gemini: use Custom Instructions, Project instructions, Saved Info, or equivalent.
In Cursor / Claude Code: use .cursorrules or CLAUDE.md.
Step 3: Keep user message focused on the immediate task
Per-turn message should contain: the new request, new inputs, 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 API workflows, make system the first message
messages = [
{"role": "system", "content": "..."}, # MUST be first
{"role": "user", "content": "..."},
{"role": "assistant", "content": "..."},
{"role": "user", "content": "..."}
]
If system appears mid-conversation, behavior is undefined across providers.
Step 5: Use tools / functions for capabilities
For agent workflows, define tools in the tools parameter of the API, not in prose. The model treats them as binding contracts with schema validation.
tools = [{
"name": "search_codebase",
"description": "...",
"input_schema": {...}
}]
Step 6: Audit and reconcile contradictions
Print your system prompt. Print your latest user message. Look for contradictions. The system prompt usually wins; if you want the user message to win on a specific point, say so explicitly: “For this turn only, override the system prompt rule about X.”
How to confirm the fix
- Same rules apply across 10 turns without re-pasting.
- User messages are short and task-focused.
- Removing the user message preamble does not change behavior (rules survived in system).
- Different turns produce different task outputs but same voice / format / role.
- Token usage per turn drops noticeably.
If it still fails
- Your platform may not support a real system prompt — check the docs.
- Some platforms truncate long system prompts — shorten and prioritize.
- Model may not strictly honor system over user — test with a deliberately contradictory user message.
- For chat UI without persistent rules, consider switching to API where the channel split is enforced.
Prevention
- Default: persistent rules in system prompt / project instructions. User messages contain only the turn’s task.
- For new chats, set the system prompt before sending any user message.
- Audit project instructions monthly — outdated rules quietly corrupt new tasks.
- For team workflows, store system prompts in version control alongside code.
- When tempted to retype rules in user message, ask “should this go in system?”
- For API workflows, use tools/functions for capabilities, not prose definitions.
Related reading
- Latest sentence overrides
- Conflicting instructions weaken output
- Prompt lacks context hierarchy
- Long prompt degrades output
- AI ignores important constraint
Tags: #Prompt #Troubleshooting