Skip to content
PrepMint

How it works

Where an instruction belongs: prompt, system prompt, or project instructions

Every assistant offers the same five containers for an instruction, and the same sentence is a permanent rule in one and a single-turn suggestion in another. The placement rule across vendors: what survives a new conversation, what survives a context trim, what gets re-billed every turn, and what outranks what.

Rohan Surve9 min read

Last reviewed

You wrote one sentence — always use British spelling — and it worked. Then it stopped: in the next conversation, or forty messages into a long one, or in the one surface where you actually needed it. Nothing about the sentence changed.

The wording was never the variable. Every assistant has four or five places an instruction can live, and the same sentence is a permanent rule in one and a single-turn suggestion in another. Each vendor documents its own containers; nobody writes down the rule that runs across all of them.

Five containers, different names in every product

Strip the branding and every tool offers the same set:

  • The turn — what you type in this message.
  • The system or developer message — what the application sends ahead of you, invisibly.
  • A per-conversation container — a Project's instructions, a custom GPT's instructions.
  • A per-user setting — Cursor's User Rules, a global preferences screen.
  • A repo file the tool readsCLAUDE.md, AGENTS.md, .cursor/rules.

Cursor states the reason the last four exist plainly: "Large language models don't retain memory between completions. Rules provide persistent, reusable context at the prompt level."

Every container above the first is a machine that retypes something on your behalf, on a schedule — and the schedule is what breaks.

Ask five questions about any container before you use it

Whatever the product calls it, these properties decide whether your instruction is followed:

  1. Does it survive a new conversation?
  2. Does it survive a context trim — compaction, summarisation, a full window?
  3. Is it re-sent on every turn, and therefore paid for on every turn?
  4. What outranks it when something else disagrees?
  5. What happens when two containers contradict each other?

Most people evaluate a container on question 1 alone. Questions 2 and 4 cause more failures.

Precedence is a documented chain, not a vibe

Your instruction usually lost because something above it said otherwise, and there is a published ordering for exactly this. OpenAI's Model Spec assigns every instruction a level of authority — Root, System, Developer, User, Guideline, and No Authority — and the rule is blunt: "Instructions with higher authority override those with lower authority."

The API surfaces the same ordering as message roles. In the Responses API, "developer messages are instructions provided by the application developer, prioritized ahead of user messages." Anything passed through the instructions parameter "will take priority over a prompt in the input parameter."

Cursor publishes its own chain for rule sources — Team Rules, then Project Rules, then User Rules — and Claude Code's CLAUDE.md locations load "from broadest scope to most specific, so a project instruction appears in context after a user instruction."

That chain is also why a custom GPT's instructions beat yours. In the Model Spec's terms, "In ChatGPT and OpenAI's other first-party products, developers may also play a role by creating third-party extensions" — so the person who built the GPT is holding the developer seat, and you are not.

Nothing you type as a user, and nothing you commit to a repo file, outranks the application's own developer message. If you only hold the user seat, precedence is not on your side.

Within one level, the last thing said wins

This is the half of precedence nobody mentions, and it explains the most confusing symptom of all: an instruction obeyed early and quietly abandoned later.

The Model Spec says the assistant follows "all system, developer and user instructions except for those that conflict with a higher-authority instruction or a later instruction at the same authority." It spells out the mechanism too — "An instruction is superseded if an instruction in a later message at the same level either contradicts it, overrides it, or otherwise makes it irrelevant".

Two competitions are running. Across levels, authority wins; within a level, recency wins. That is why correcting yourself mid-chat works so reliably, and why a casual aside in message 30 can retire the careful instruction from message 3 — supersession, not forgetfulness.

What survives a new conversation

Only the containers that are re-sent by something other than you.

A turn message does not survive, and neither does a system message you sent once: the instructions parameter "only applies to the current response generation request", so chaining turns with previous_response_id leaves earlier instructions out of context entirely.

Per-conversation containers survive within their scope and nowhere else. Claude's Projects "allow you to create self-contained workspaces with their own chat histories and knowledge bases", and within one you can "define project instructions for each project to further tailor Claude's responses." Start a chat outside the project and those instructions do not exist.

Repo files survive because the tool re-reads them: CLAUDE.md files are "loaded into the context window at the start of every session," and Cursor includes rule contents "at the start of the model context."

What survives a context trim

Different question, different answer, and this one costs people afternoons. Claude Code's documentation puts it exactly right: "What happens to your instructions depends on how they were loaded".

Its compaction table is the clearest published version of this. The system prompt is unchanged, because it was never part of message history. Project-root CLAUDE.md and unscoped rules are re-injected from disk. Path-scoped rules and nested CLAUDE.md files are lost until a matching file is read again — they "load into message history when their trigger file is read, so compaction summarizes them away with everything else."

The fragile case is the one you use most: an instruction you only typed into the chat. "If an instruction disappeared after compaction, it was given only in conversation, lives in a nested CLAUDE.md that hasn't reloaded yet, or is a path-scoped rule that hasn't matched a file since."

That is a design rule, not a troubleshooting note. A conversational instruction has a half-life. If it has to hold for eight hours of work, typing it is the wrong container.

Persistent means re-sent, and re-sent means re-billed

Every container that survives occupies space in every request, which makes it a budget rather than a filing cabinet.

The billing is not hypothetical: "Even when using previous_response_id, all previous input tokens for responses in the chain are billed as input tokens in the API." Claude Code says the same of the conversation itself — old context "crowds out the files you need next and costs tokens on every message" — and of overstuffed instruction files: "Files over 200 lines consume more context and may reduce adherence."

What that costs and how a usage limit is actually spent is its own article; the reason it belongs in a piece about placement is the second clause, which matters more than the money: over-filling a persistent container degrades the instructions already in it. Which gives a usable test — an instruction that applies less than half the time does not belong in an always-on container. Scope it to a path, or say it in the turn where it matters.

A repo file is not a system prompt, however much it reads like one

This is the most useful fact in the whole subject, and Anthropic states it outright: "CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself."

So the file you committed, reviewed and argued about in a PR enters at user authority — outrankable by the developer message, supersedable by something you say later, because "Claude treats them as context, not enforced configuration."

Cursor is the same shape: rule contents are "included at the start of the model context", which is a position in a prompt, not a policy engine. Claude Code's escape hatches are --append-system-prompt for genuine system-level text, and a hook for anything that must actually happen: "Hooks execute as shell commands at fixed lifecycle events and apply regardless of what Claude decides to do."

If an instruction must hold every single time, it does not belong in any container on this page. It belongs in code.

When two containers contradict each other

They are merged, not chosen between, and the merge is where silent failures live.

Cursor: "All applicable rules are merged; earlier sources take precedence when guidance conflicts." Claude Code: "All discovered files are concatenated into context rather than overriding each other." Neither tool errors, warns, or shows you the winner.

Worse, a tie is not resolved deterministically: "If two files give different guidance for the same behavior, Claude may pick one arbitrarily." An instruction followed on Tuesday and not on Wednesday is very often two instructions, not one flaky one.

Some of the contradicting text is not in your checkout at all — team rules sync from an account, managed policy files are deployed by IT. Grepping the repository will never find them.

Attaching a document is not placing an instruction

Under the Model Spec, quoted text, file attachments and tool outputs have no authority by default: "any instructions contained within them MUST be treated as information rather than instructions to follow". Authority can be delegated to them, but only by an instruction in unquoted text that says so.

So an uploaded style guide is material, not instruction, until something in a real container tells the model to treat it as binding. The fix is one sentence in the turn or the project instructions: apply the attached guide as rules.

The placement rule

Given any instruction, in any tool, answer four questions in order:

  1. Must it happen, or is preferred good enough? Must-happen goes in code — a hook, a linter, a validator. Every container on this page is a prompt, and prompts are followed usually.
  2. How often does it apply? Every turn → a persistent container. Occasionally → the turn itself, or a path-scoped rule that loads when it is relevant.
  3. Who does it bind? Only you → the per-user setting. Everyone in this repo → the committed repo file. Everyone in the org → managed policy or team rules, the only level that survives a colleague disagreeing with you.
  4. Where must it still be alive? In a new conversation → not a chat message. After a long session compacts → not a chat message, and not a path-scoped rule.

Run the British-spelling example through it: a preference rather than a requirement (so not code), applying to everything you write (so persistent), yours rather than the team's (so the per-user setting), and needing to outlive individual chats (so not the turn). The container picks itself — and the same four questions place an instruction this page never mentioned.

When a placed instruction is ignored anyway

Three checks, in order of cost.

Was it in context at all? Not "is the file saved" — was it loaded, this session, after the last trim. Claude Code has /context for exactly that; if your tool has no equivalent, promote the instruction to the always-on container temporarily and see whether the behaviour appears.

Was it outranked? Look up, not sideways: a developer message, a team rule, a managed policy. The fingerprint is specific — everything in your instruction is honoured except the one clause somebody else has an opinion about.

Was it superseded? Look for something you said later at the same level that contradicts it, including something you never meant as an instruction. In a long conversation this is the likeliest of the three, and the easiest to fix: say it again.

Practise this topic

Reading about it is half of it. Answer some questions on the same material — scored instantly, explanation for every one, no login.

Sources

Rohan Surve

Rohan Surve is a Technical Product Manager in Bengaluru with 12 years in enterprise delivery and 0→1 product building. He works with Claude, Claude Code, Cursor and MCP daily, and built PrepMint after noticing how much of what he "knew" about these tools was half-remembered from documentation he'd skimmed once. Every question here is written from working with the tool and checked against the vendor's own docs.

More articles by Rohan Surve

Question banks on this subject