Stop Re-Priming Claude Code by Hand
The context you paste at the start of every session, put into one file you invoke with /prime.

What you will do: take the block of context you paste at the start of every Claude Code session and put it in one file, so you type
/primeinstead. About fifteen minutes.Who this is for: you come back to the same project across many sessions, and you keep re-pasting the same “here is the project, here is where things stand” preamble before real work starts.
Who should skip it: if you open a fresh project every time, or never re-explain anything, there is nothing here for you.
You need: Claude Code (a recent 2.1.x release; the mechanics here were checked against the docs on 9 August 2026), a project you return to, and a shell.
Every session starts the same way. You open Claude Code and spend the first few minutes telling it where you are. This is the project. Here is what you changed last time. Here is the thing that is half-finished. Leave the migration alone. You have typed some version of that briefing fifty times, and you are the one keeping it in your head and re-entering it by hand.
That is a prompt you repeat, and a prompt you repeat should be a command you type. Claude Code lets you save one as a file and invoke it with a slash. The good version does more than paste static text back at you: it runs a couple of commands and reads a couple of files first, so the context arrives already filled with your project’s current state. By the end of this you will have /prime, and starting a session will be one word.
One file becomes one command
The smallest possible version is a single file with one line in it. In your project, create .claude/skills/prime/SKILL.md (a prime folder with a SKILL.md inside it):
Summarise where this project stands and what I should work on next.
Save it. In Claude Code, type / and prime shows up in the list; run /prime and the agent does what the file says. The folder name is the command: a prime folder gives you /prime. Claude Code watches existing skills folders and picks up a new or edited skill the moment you save it, no restart. The one exception is the very first time: if .claude/skills/ did not exist when you started the session, restart Claude Code once so it begins watching the new folder, and saves are live after that.
That is already a command, and it already saves you the typing. But it is static. It says the same sentence every session and knows nothing about what actually changed since last time. The next step is where it earns its place.
Make it load your real state
Two small pieces of syntax turn the file from a saved sentence into a live briefing.
A line that starts with !`command` runs that shell command and drops its output into the file before Claude reads it. The docs call this dynamic context injection: “the command runs first, and its output gets inserted into the prompt,” so the agent receives the actual data, not the instruction to go and get it.1 A line with @path/to/file inlines that file’s contents the same way. Put them together and /prime can walk in already knowing your latest commits, your uncommitted changes, and whatever notes you keep.
Open that same file and replace its one line with the fuller version below, which you can adapt to any repository. Swap NOTES.md for the short file where you keep current project state, not your whole project history:
---
description: Load where this project stands and print a short situation report
argument-hint: "[optional focus area]"
allowed-tools: Bash(git log *) Bash(git status *)
---
Recent work on this branch:
!`git log --oneline -10`
Branch and uncommitted right now:
!`git status --short --branch`
Current state notes, read in full:
@NOTES.md
Give me a four-line situation report: what branch I am on, what changed
recently, what is unfinished, and what to pick up next. If I named a focus
area ($ARGUMENTS), orient every line to it.
The point is what the reader on the other end receives. Not “go check git” but the actual log, the actual dirty files, the actual notes, already in front of the model, followed by a request to make sense of them. $ARGUMENTS is whatever you typed after the command, so /prime the auth refactor pushes “the auth refactor” into that placeholder and the report orients to it. The two lines at the top of the frontmatter are optional labels: description is the text that shows beside /prime in the menu, and argument-hint is the grey prompt after it.

To show it doing real work, here is ours. Our project is a large notes vault whose rulebook says: before you touch anything, read the pipeline status, read the working briefing, read the vault vitals, and check none of it is stale. That was three files and a freshness check we opened by hand at the start of every session. Our /prime injects all of it and ends with a read. Invoked against our live state, it returned:
1. Pipeline: red. One red alert, a knowledge-review backlog; two yellow,
the weekly cleanup twelve days overdue and a staging queue filling up.
2. Binding constraint: the output bottleneck. Six pieces ship-pending,
all marked critical, the oldest sixty-four days. Ship before building.
3. Last session: perfected and shipped the opening piece of a new series.
4. Next: take one of the built-and-parked series pieces to publish-ready.
That is the whole payoff: the state of the project, the one thing that matters most, and where to start, assembled before I said a word. Those four lines are ours, from our injects; run the git template above and /prime hands you the same shape filled with your own project, your commits and dirty files and notes in place of our pipeline and briefing.
Let it run without asking
Unless those commands are already allowed by your own permission settings, Claude Code stops and asks the first time each injected command runs. The allowed-tools line in the frontmatter above pre-approves them for you, so /prime runs clean:
allowed-tools: Bash(git log *) Bash(git status *)
Each entry is a pattern: Bash(git log *) means “any command starting with git log, no prompt,” and Bash(git status *) does the same for git status. These two pre-approve only the reads /prime actually needs; anything else stays subject to your normal permission prompts. A blanket Bash(git *) would pre-approve git push, git reset, and every other git command without a prompt too, so keep the grant to the narrow pair. It is scoped to the turn that /prime runs in and clears when you send your next message, so you are not opening a standing hole in your permissions either.
One honest wrinkle from ours: our freshness line runs TZ='Europe/London' date, and the leading TZ= assignment does not always match the command prefix cleanly, so the first run still asks once. We approve it and move on. If one of your lines keeps prompting despite an allowed-tools entry, that mismatch is why; simplify the command or approve it the once.
One caution that matters more once the file is not yours to begin with: a skill runs shell commands and can pre-approve its own tools, so treat one you pulled from someone else’s repository like a script you are about to run. Read its !` lines and its allowed-tools before you invoke it.
Why not just put this in CLAUDE.md?
If Claude Code already reads a CLAUDE.md at the start of every session, a fair question is why this is not a few more lines there. The docs draw the line by what changes. CLAUDE.md is for facts that hold every session: your conventions, your architecture, the guidance you want in front of Claude every time. It loads into every session, which makes it the wrong home for anything that moves underneath it.
/prime is for the things that move. Where the tests live belongs in CLAUDE.md; what you touched last, what is uncommitted, the one thing on fire this morning, all of that is different by the next session, and you want it recomputed when you ask rather than hand-edited into a file.
That is the real move here, and it is bigger than one command. The durable thing to save is the procedure that fetches the state. A commit list or a status line goes stale the moment you write it down; a command that runs git and reads your notes fetches the current answer every time. Keep the procedure narrow, though: whatever /prime injects stays in the conversation and costs tokens on every later turn, so its job is to locate the work, not to preload your whole project. If it starts turning into a project dump, stop adding files.
You may see the older one-file form
If you read around, you will find the same trick written as a single .claude/commands/prime.md file with no folder. That is the older shape, and it still works: a .claude/commands/prime.md and a .claude/skills/prime/SKILL.md both create /prime and behave the same way. The skills folder is the form the docs point you to now, and the reason is room to grow. A folder holds more than the one file, so it carries supporting scripts when your /prime gets ambitious, and a skill can let Claude reach for it on its own when it fits (add disable-model-invocation: true to keep it strictly manual, /prime only). If you already have a one-file command, leave it alone, it keeps working. Reach for the folder when the command outgrows a single file, and if you ever keep both under one name, the skill wins.
When it does not fire
- It is not in the
/list. You are probably not in the project, or the file is not at.claude/skills/prime/SKILL.md(the folder has to be namedprimeand the fileSKILL.md). A skill in~/.claude/skills/instead works in every project. - It runs, but Claude never reaches for it on its own and the menu shows no hint. The frontmatter did not parse. A malformed YAML block does not remove the skill:
/primestill works, but it loads with empty metadata, so thedescriptionno longer matches. Start Claude Code with--debugto see the parse error, then line up the---fences. - It prompts for permission every single run. Your
allowed-toolspattern does not match the command you inject. Line the prefix up exactly, for exampleBash(git log *)for agit logline. $1is not what you expected. In the skills model, indexed arguments are zero-based:$0is the first argument,$1the second. Reach for$ARGUMENTSwhen you just want “everything I typed,” and leave positions alone unless you genuinely need them.- The output did not appear. The injection only fires from a
!`…`backtick span with a leading!. A command sitting in a plain fenced block is shown to the model as text, not run.
Prove it loads
Do not take my word that the injection fired. Run /prime and read the top of what comes back. If it references your actual latest commit message and your actual files, the commands ran and the state is real. If it hands you generic advice that would fit any repository, nothing injected: your !`…` or @ lines are the place to look. A command that prints the same thing regardless of your project is just a saved sentence, which is where we started.
Once it loads real state, you have turned a paragraph you retyped every session into one word, and the machine does the fetching. That is the pattern for the whole series: a thing you do by hand, moved into a tool you set up once and then just run. This one only read your project. The next rung is about letting Claude Code change it safely: a guardrail that stops the agent before it edits a file you marked off-limits. That is the next Runbook.
Sibling piece, same tool, different job: Never Let Claude Code Tell You It’s Done wires a test the agent cannot talk its way past.
Footnotes
-
Claude Code documentation: dynamic context injection and slash-command syntax. ↩