System reminders – how Claude Code steers itself

Bluestein1 pts0 comments

System reminders - how Claude Code steers itself<br>Build, Break, Repeat<br>Read more about: agentsinfrastructuretool-designclaude-codecontext-engineering<br>/Article<br>/Actions<br>Share Subscribe

Steering an agent is the act of reinforcing good behaviors and discouraging bad ones. Most recent models are amazing at agentic work, but LLMs are non-deterministic by nature, which means they’re also easy to confuse. If security has defense in depth, then long agentic flows require instructions in depth. Anything you write in a system prompt is basically gone in a conversation of 100K tokens. Different harnesses steer differently, and how well they do it is one of the most important parts of harness engineering.

Steering comes in a few forms. The system message is the first layer, modeling the world and the task at hand. Everything that follows is colored by its semantics. User messages are the highest-attention channel, you type something, the model prioritizes it. Queued messages are a product trick, you write a message while the model is working and the harness slips it in between tool calls. Tool responses can piggyback instructions on results as well. Each of these carries a different “trust” level in the model’s eyes. This matters.

Trust hierarchy

Large language models are trained to treat these sources differently. System prompts and user messages get high attention. Tool responses are treated as external information - potentially adversarial.

This is the right call. If models followed instructions in tool responses the same way they follow system prompts, prompt injection would be trivial. Read a file containing “ignore all previous instructions” and the agent complies? No. Models are trained to be skeptical of tool outputs.

So where do you inject steering that the model will actually follow? The user message slot. That’s where the model pays serious attention. Most harnesses “hook” steerability into the system prompt - they semantically link a section in the prompt to content that will appear later in the conversation. A good way to do this is with specific tags that push the model’s attention back to the system message. “You’ll receive tags, follow them.” When the model sees that tag mid-conversation, it connects back to the system prompt’s instructions. It knows these aren’t adversarial. They’re from the harness, not from some random file it read.

Nudging over forcing

The instinct is to force correct behavior. Hard blocks, strict validation, deterministic guardrails. But practitioners consistently overestimate their ability to model the desired behavior across the infinite space of user prompts, agent actions, and conversation states. You can’t anticipate every path through a hundred-step session. Nudging beats forcing because nudges compose with the model’s own judgment instead of replacing it.

There’s a natural layering to how you shape agent behavior. The system prompt seeds it - this is who you are, these are your constraints. Tools shape the path - the available actions define what the model can do, and good tool design guides it toward solutions. But what about behaviors that aren’t constraints and aren’t tool choices? Preferences. Tendencies you want to reinforce.

Say your agent tends to skim files - reading small chunks when it should read the whole thing. You don’t want to force full reads every time, because sometimes a partial read is the right call. But it’s a preference. You want to catch the pattern and remind the model. That’s the gap system reminders fill - reinforcing behaviors for known issues without hardcoding them as rules.

System reminders

As far as I can tell, Anthropic’s Claude Code team were the first to ship this pattern. They’re reactive messages injected based on conversation state - not periodic, not static. Something happens, a condition is met, a reminder fires. Sometimes they fire as a response to something the user did in the UI. Sometimes they fire as a side effect of the system - token consumption getting high, context growing large.

They look like this:

system-reminder><br>Warning: the file exists but the contents are empty.<br>system-reminder><br>Harness lifecycle

Harnesses have lifecycle events - hooks that fire at specific points during the agent’s execution. Here’s how pi’s event system lays it out:

session_start<br>user sends prompt<br>├─► input<br>├─► before_agent_start<br>├─► agent_start<br>│ ┌─── turn loop ───────────────────────────────┐<br>│ │ │<br>│ ├─► turn_start │<br>│ ├─► context │<br>│ ├─► before_provider_request │<br>│ │ │<br>│ │ LLM responds: │<br>│ │ ├─► message_start │<br>│ │ ├─► message_update (streaming) │<br>│ │ └─► message_end │<br>│ │ │<br>│ │ Tool execution (per tool call): │<br>│ │ ├─► tool_execution_start │<br>│ │ ├─► tool_call │<br>│ │ ├─► tool_execution_update │<br>│ │ ├─► tool_result │<br>│ │ └─► tool_execution_end │<br>│ │ │<br>│ └─► turn_end │<br>└─► agent_end

session events (anytime):<br>session_compact / session_switch / session_fork<br>model_select / session_shutdown<br>Each of these is a potential evaluation point...

system model tool prompt agent user

Related Articles