How to give Claude a persistent role that survives a new chat

You set up custom instructions. You wrote “you are a senior backend engineer, be concise, push back on bad ideas.” It worked for about four exchanges and then drifted back to being agreeable and generic. Every new chat, you start the same negotiation again.

The reason is that custom instructions describe a personality, and a personality has nothing to hold it in place. What you actually want is a role: a thing that owns something specific, has a written standard it is measured against, and remembers what it did last time. That is a different object, and you have to build it — but it is four files and an hour, and this page is all of it.

Why “act as a senior engineer” stops working

Three reasons, and they compound.

It is a costume, not a job. “Senior engineer” says how to sound. It does not say what this role is responsible for or what would count as failing. With nothing to fail against, every answer passes, and a thing that passes every time drifts toward whatever is easiest to produce — which is agreement.

It has no yesterday. A role that cannot remember what it recommended last week cannot notice that it is recommending the opposite this week. Consistency is not a personality trait; it is a consequence of reading your own previous output.

It has no refusal. The single most useful thing you can write down is not what a role should do, it is what it must not accept. “Be rigorous” is unfalsifiable. “Refuse a migration plan with no rollback step” is checkable in one glance, and checkable instructions survive where adjectives do not.

What a role actually is: four things

A name that is a job. Not “Assistant” and not “Helper” — a job you could hire for. “Backend reviewer.” “Release manager.” The name constrains the scope, which is most of the work.

What it owns, stated as consequences. Not a list of tasks — the thing that goes wrong when nobody owns this. “What goes wrong when nobody owns this: schema changes ship without migrations and we find out in production” tells the role more than five bullet points of duties, because it names the failure it exists to prevent.

A bar. One paragraph describing what a good outcome looks like in the hands of the person receiving it. Not “high-quality code review.” Something like: “The author reads it once, knows exactly what to change, and does not have to ask what was meant. If they have to ask a clarifying question, it failed.”

Judges. Two to four of them, each a person with a stake, not a checklist item. Each one gets a name and one line of what they would refuse. This is the part people skip and it is the part that does the work, because “would the on-call engineer refuse this at 3am” is a question with an answer, whereas “is this good” is not.

The role file, in full

Put this at roles/backend-reviewer.md. Adapt the content; keep the shape.

# Backend Reviewer

## What this is
A standing accountability. Every session doing this work starts by reading this file.

## Accountable for
Every change that touches the database, the queue, or a public endpoint.
What goes wrong when nobody owns this: schema changes ship without migrations,
endpoints change shape without a version, and we find out from a customer.

## Who I work for
The engineer who opened the pull request, who has already moved on to the next
thing and will read this once on their phone.

## How I think
- A review that lists ten things gets none of them done. Name the one that matters.
- Name the failure, not the preference. "This deadlocks under concurrent writes"
  beats "I'd use a different pattern here."
- If I cannot say what breaks, it is a preference, and preferences go last or nowhere.

## When it is good
The author reads it once, changes exactly what was named, and never asks what
was meant.

## Who else judges it
- **the_oncall_at_3am** - Refuses anything that could page them with no rollback
  written down. Refuses a migration with no reverse.
- **the_author_on_their_phone** - Refuses a review longer than one screen.
  Refuses a comment that names a problem without naming the fix.

## Already decided
- postgres_not_mongo - decided 2026-08-14. Do not reopen.
- We deploy on Thursdays. Friday deploys need a written reason.

## What I did last
(the loading step fills this in)

Two sections earn their place and are usually missing.

“Already decided” kills the most expensive failure mode there is: re-arguing a settled question every few weeks. Each line is a decision and a date. When one genuinely changes, add a new line with the new date rather than editing the old one, so the history survives.

“What I did last” is what turns a description into something with continuity. It is filled in at load time, not written by hand.

Making it load every time

Three ways, cheapest first.

Project instructions. If your assistant has a project or workspace with a persistent instruction file, paste the role file there. It loads on every session in that project with no effort. This is the right answer for one person and one project, and it is where most people should stop.

A file the session reads first. Keep roles/backend-reviewer.md in the repository and open every session with “read roles/backend-reviewer.md before anything else.” Slightly manual, but it versions with your code, survives across machines, and other people on the team get it for free — which project instructions do not give you.

Loaded by a tool. If you can add an MCP server or a tool call, have the role file fetched at the start of a run rather than pasted. This is the only one of the three that works for something running on a schedule with no human to paste anything.

However it loads, the closing move is the same and it is the one that matters:

Append to roles/backend-reviewer.md under “What I did last”: what this session reviewed and what was decided. If a new standing decision was made, add it under “Already decided” with today’s date.

A role that reads and never writes is a costume again after two weeks.

Where the judges do their work

Do not fold judges into the prompt as tone. Run them as a separate pass, after the output exists, each one holding only its own criteria and the artefact — never the brief, and never told what to conclude.

Concretely: produce the review, then ask, in a fresh context, “You are the_oncall_at_3am. You refuse anything that could page you with no rollback written down. Here is a review. Pass or fail, and the one line you turned on.” A judge that has read the brief will find reasons the work is fine. A judge that has only read the output tells you the truth, because it has nothing invested in it.

Two to four judges. Fewer and everything passes. More and everything fails, and you stop running them.

Scaling past one role

One role in one file is easy. Three roles that hand work to each other is where it gets interesting and where the file layout starts to matter:

roles/
  backend-reviewer.md
  release-manager.md
  runs/
    backend-reviewer/2026-09-01.md
    release-manager/2026-09-01.md

Give each role its own runs/ directory. When one role needs something another owns, it writes a task file into that role’s directory rather than doing it itself — and the receiving role reads its own directory at the start of its next run. That single rule keeps roles from quietly absorbing each other’s jobs, which they will otherwise do within a fortnight, at which point you are back to one generic assistant with extra steps.

Related