March 18, 2026 · ~9 min read
Give your AI agent an identity
A model with no identity is a smart typewriter. Here is the small pack of files that turns it into your agent, the load order that keeps it sane, and the templates to paste in tonight.
TL;DR: An AI agent without an identity is a smart typewriter. It forgets who it is every turn, leaks across roles, and drifts in tone. The fix is not one bigger system prompt. The fix is a small pack of six files (soul, identity, user, agents, tools, memory) that your loader merges in a defined order. Start with the templates below and you have a working identity in an afternoon.
Your agent has no identity by default
Without an identity file pack, every new session starts from scratch. The model knows English. It knows a lot of facts. It does not know it is your agent, working inside your product, talking to your user, with your red lines.
That shows up in three annoying ways.
It is amnesiac. Ask it what you asked yesterday and it has no idea. Every conversation begins the same way. Useful for a general chat tool. Painful for an agent that is meant to ride with you for months.
It has no boundaries. A plain model will happily go anywhere the conversation pushes it. Write the marketing copy, draft the legal disclaimer, post to the team channel on your behalf. Without a written boundary, "should I?" is up to the last thing somebody typed.
Its tone drifts. Formal in the morning, chatty by 4 p.m., vaguely corporate when it hits a topic it is unsure about. That is a model imitating its nearest training example, not a voice.
Identity is the fix. Not a longer prompt. A small set of files that answer who the agent is, what it will not do, who it is talking to, and what it has learned so far.
One system prompt is not enough
The usual first instinct is to keep stuffing the system message. "You are a helpful assistant that... and also... and remember to... and never..." A few weeks in, the string is 2,000 tokens of instructions that contradict each other.
Split it instead. Named files, each with a single job, merged by your loader:
| File | Holds |
|---|---|
soul.md |
Non-negotiables: principles and red lines |
identity.md |
Name, role, voice |
user.md |
Who the human is (timezone, goals) |
agents.md |
Workspace rules and learned facts |
tools.md |
How to use each integration safely |
memory.md |
Distilled long-term facts |
Two more files round it out. memory/YYYY-MM-DD.md is a daily scratchpad you distill into memory.md when something is worth keeping. local.md is a gitignored override file for personal tweaks on your own laptop.
This is a loader pattern, not a file-format pattern. Flutter apps load them as bundled assets. Next.js apps read them from a /prompts folder at build time. Python and Rust do the same with their package-data equivalents. Firebase Remote Config stores them as versioned strings. The files are the shape, not the runtime.
What belongs in each file
Short version of the template. Keep each one small so you actually read it when you edit it.
soul.md is the character sheet. Be useful without filler. Have opinions when they help. Try to solve it before asking. Prefer evidence. External actions (send, post, pay) need care; internal work (read, organise) can be bolder. Short list. Do not let it grow into tool docs.
identity.md is the name and the voice. Who the agent is, what to call it, the two or three adjectives that describe how it talks. "Precise, patient, concise" is enough. Three hundred words at most.
user.md is the human. Name, timezone, language preference, a couple of goals they care about, what they dislike and what they appreciate. It is not a CRM record. If you are logging "last seen 8 days ago", you are doing something wrong.
agents.md is the workspace. Project rules, learned preferences, the one time last month when the agent did X and it broke Y. This is where "continual learning" actually lives.
tools.md is one section per integration. What the tool is for, how the agent calls it, what never to paste into it (API keys, real customer data), where the output goes. Treat it as a short safety briefing, not an API reference.
memory.md is the distilled record. Dated sections of "here is what stuck". You promote entries from the daily memory/YYYY-MM-DD.md file when they deserve to survive sessions.
local.md is for the one laptop. "Use the staging API on this machine". "Dark mode for demos". It overrides everything else except the human's next message. Never committed.
Load order matters more than the files do
A file pack without a precedence rule is chaos. Which one wins when two disagree? The answer has to be written down.
Here is the ladder, low to high. Later rows override earlier ones.
┌──────────────────────────────┐ low
│ Model defaults │
├──────────────────────────────┤
│ User-global settings │
├──────────────────────────────┤
│ Shared team / project rules │
├──────────────────────────────┤
│ Repo / app-bundled rules │
├──────────────────────────────┤
│ local.md (not committed) │
├──────────────────────────────┤
│ Current user message │ high (wins)
└──────────────────────────────┘
Two rules that matter.
One: the committed files (soul, identity, user, agents, tools, memory) are your team's shared baseline. Edit them in PRs. Review them like code.
Two: if the user tells the agent something in the current chat that clearly contradicts an older rule, the current message wins. "Today, ignore the usual weekly summary format" works. That is the whole point of having a live human in the loop.
State this explicitly in your loader: "Loaded instructions override defaults. The current user message overrides loaded instructions." Then the agent does not have to guess.
Cache what is stable, re-send what is not
Big cost savings live here. Split everything you send the model into two layers.
A stable prefix is the soul, identity, safety rules, tool usage norms, and tone. It does not change from turn to turn. Most providers can cache it and charge less for the cached tokens.
A dynamic suffix is today's memory, the active tool list for this session, the user's current environment (OS, repo, branch), and a short "earlier messages summarised below" note if you have compacted.
Send the prefix the same way every time. Version it (v3, v4) and log which version was used so you can bisect regressions. Never edit cached prefix text without a version bump. That one rule will save you from a class of bugs that is otherwise fun to debug at 11 p.m.
Paste-ready templates
Three files to get you started. Drop them into self/ or agent/ or config/agent/ (the folder name does not matter, only the contents do).
# soul.md
## Core
- Be useful without filler or fake enthusiasm.
- Have opinions when they help; say so when you are not sure.
- Try to solve it before asking the human.
- Prefer evidence over guesses.
- External actions (send, post, pay) need care; internal work (read, organise) can be bolder.
## Boundaries
- Private data stays private. Do not leak secrets into logs or paste sites.
- When unsure whether something is public or risky, ask first.
- You are not the human's voice in group settings unless they ask.
## Vibe
One line: [how should talking to this agent feel? e.g. calm, direct, a little dry].
# identity.md
**Name:** [AGENT_NAME]
**What the human calls you:** [SHORT_NAME]
**Role:** [one sentence, e.g. "coding partner in the IDE", "field service copilot"]
**Vibe:** [two or three adjectives, e.g. precise, patient, concise]
**Where I live:** [product or repo name, or "the user's devices"]
**What I optimise for:** [e.g. shipping working code, clarity, safety]
**What I do not pretend to be:** [e.g. lawyer, doctor, breaking news source]
# user.md
**Name:** [FULL_NAME]
**What to call them:** [PREFERRED_NAME]
**Timezone:** [TZ]
**Language preference:** [e.g. English]
## What they care about
- [goal 1]
- [goal 2]
## Work context
- Projects or domains: [apps, job, studies]
- Things they dislike: [e.g. vague estimates, walls of text]
- Things they appreciate: [e.g. concrete steps, diffs, checklists]
Fill the brackets. Delete the hints. Commit it. That is the minimum identity.
Two prompts you can steal tonight
The first one gets you a starter pack. Paste this into any chat model along with a short description of your product:
You are helping me create an AI agent identity pack. I will describe my
product and my user in a paragraph. Draft me these files:
1. soul.md - principles and boundaries, under 200 words
2. identity.md - name, role, voice, under 150 words
3. user.md - the human this agent serves, under 200 words
4. tools.md - one section each for the three tools I name
Rules:
- Concrete, not generic. No "empower" or "seamless".
- Red lines are specific actions, not vibes.
- Leave [BRACKETS] where you need more input from me.
Here is my product and user:
[paste your paragraph]
The second one is the nightly distill. Run it at the end of the day against memory/YYYY-MM-DD.md:
Here is today's raw daily memory file. Distill it into four sections for
memory.md. Keep bullets that would still matter in three weeks. Drop
routine chit-chat, temporary context, and anything already captured in
an earlier memory.md section.
Sections to produce:
- Primary requests and intent
- Key decisions
- Files or systems touched (only if useful later)
- Pending or next time
Be brutal. If nothing survives, say so.
[paste today's file]
Both prompts get better every time you iterate on them. Save the good version into your own repo so future-you does not rewrite it from scratch.
Five mistakes that quietly break identity
Soul bloat. The soul.md file grows to three pages of edge cases and turns into tool documentation. Move rules about how to call an API into tools.md. Keep soul short and ethical.
user.md treated as a CRM. Someone adds "last login 2026-03-12" and the file starts tracking engagement. Stop. If a fact does not change how the agent helps, it does not belong there.
No load-order decision. Two files contradict, the agent picks the one it read most recently, behaviour drifts, nobody can reproduce the bug. Write the precedence ladder into your loader's code comment. Make it boring.
Daily logs inside the cached prefix. If you drop today's memory/YYYY-MM-DD.md into the stable prefix, you have broken caching and paid full price for every turn. Daily memory is suffix. Distilled memory is prefix.
Never updating any of it. The whole point is continual learning. If agents.md has not changed in two months and you have been using the agent daily, either your agent is perfect (it is not) or you have forgotten the system exists. Put a line in your week-review checklist to edit at least one of these files.
Where to go from here
Three small steps that fit in an evening.
One: pick a home for the pack. Flutter ships it as bundled assets with a version in pubspec.yaml. Next.js reads from a /prompts folder at build time. Python uses importlib.resources. Firebase Remote Config stores versioned strings. Your call, but decide before you start writing.
Two: version your stable prefix and log the version on every API call. You want to be able to answer "which prompt was live when that regression happened?" in one query.
Three: write today's memory/YYYY-MM-DD.md file even if nothing dramatic happened. "Today I set up the identity pack." That is the first row of your agent's memory. Tomorrow it will feel less like talking to a chatbot and more like picking up where you left off.
An agent with identity is not magic. It is a few files, read in a known order, updated on purpose. Build the habit and the rest of the stack gets easier.