Best Prompts to Stop OpenClaw Agents From Going Off-Track
Best Prompts to Stop OpenClaw Agents From Going Off-Track

Let's be honest: the first time you give an OpenClaw agent a task and watch it spiral into oblivion โ re-reading the same file forty times, "improving" code you never asked it to touch, or inventing tasks out of thin air โ you start questioning whether this whole AI agent thing is worth the headache.
It is. You just need better prompts.
I've spent the last few months building with OpenClaw, and the single biggest lever for getting reliable, predictable agent behavior isn't some fancy architecture pattern or a new library. It's how you write your prompts and structure your constraints. The difference between an agent that nails a task in three turns and one that burns through your API budget doing nothing useful almost always comes down to the instructions you gave it.
Here's everything I've learned about keeping OpenClaw agents on-track, with actual prompts and code you can steal.
The Core Problem: Agents Don't Know When to Stop
Before we get into specific techniques, you need to understand why agents go off-track in the first place. It's not because the model is dumb. It's because you gave it an open-ended instruction and no boundaries.
When you say "update the README," the model sees that as a starting point, not a finish line. It updates the README, then thinks, "Well, while I'm here, the package.json could use some love too." Then it spots a typo in your test file. Then it decides your CI pipeline needs a refactor.
This isn't a bug. It's a feature of how language models work โ they're completion machines. They want to keep going. Your job is to build the guardrails that tell them exactly where the road ends.
OpenClaw gives you the tools to do this. You just have to use them.
Technique 1: The Hard Stop Constraint
The simplest and most effective thing you can do is set maxTurns. Full stop. Every single OpenClaw agent you build should have this.
const result = await openClaw.run({
messages: [{
role: "user",
content: "Update the README with installation instructions."
}],
maxTurns: 5
});
Five turns is usually enough for a focused, single-objective task. If your agent can't get it done in five turns, your task is probably too vague โ which brings us to the next technique.
But maxTurns alone isn't enough. It's a safety net, not a strategy. You also need to tell the agent explicitly when it's done.
Technique 2: Explicit Completion Signals in Your Prompt
This is the one change that made the biggest difference for me. Instead of just describing what you want, describe what "done" looks like.
Bad prompt:
Update the README with installation instructions.
Good prompt:
Update the README with installation instructions for npm and yarn.
Include a code block for each package manager.
STOP after updating the README. Do not modify any other files.
Your final response should confirm what you changed and nothing else.
See the difference? The second prompt defines:
- Exactly what to include (npm and yarn, with code blocks)
- Exactly when to stop (after the README, no other files)
- Exactly what the final output should be (a confirmation)
Here's what this looks like in a full OpenClaw setup:
const result = await openClaw.run({
systemPrompt: `You are a focused task executor. You complete exactly what is asked and nothing more.
When your task is complete, provide a brief summary of what you did and stop.
Do not suggest additional improvements. Do not modify files beyond what was requested.`,
messages: [{
role: "user",
content: `Update the README.md with installation instructions for npm and yarn.
Include a code block for each package manager.
STOP after updating the README. Do not modify any other files.
Your final response should confirm what you changed.`
}],
maxTurns: 5
});
The system prompt sets the personality โ a focused executor, not an eager helper. The user message sets the task boundaries. Together, they create an agent that does its job and shuts up.
Technique 3: The Step-by-Step Scaffold
For complex, multi-step tasks, don't just describe the end goal. Give the agent a numbered plan and tell it to follow the plan exactly.
const result = await openClaw.run({
systemPrompt: `You are a methodical task executor. Follow instructions step by step.
Complete each step before moving to the next. Do not skip steps or add extra steps.
When all steps are complete, summarize what you did.`,
messages: [{
role: "user",
content: `Complete these steps in order:
1. List all .ts files in the src/ directory
2. Read each file and identify any TODO comments
3. Create a file called TODO_SUMMARY.md with a table listing:
- File path
- Line number
- TODO text
4. Report how many TODOs you found
Do NOT modify any source files. Only create the summary file.
Stop after completing step 4.`
}],
maxTurns: 15
});
Notice I bumped maxTurns to 15 here because the agent needs to read multiple files. But the numbered steps keep it on a rail. It knows exactly what to do at each stage, and the explicit "Stop after completing step 4" prevents the classic drift into bonus tasks.
Technique 4: Tool Descriptions That Prevent Misuse
Half the time agents go off-track, it's because the tool descriptions are too vague. The model doesn't know when to use each tool, so it guesses. And it guesses wrong.
Here's what most people write:
const tools = [
{
name: "read_file",
description: "Reads a file",
inputSchema: {
type: "object",
properties: {
path: { type: "string" }
},
required: ["path"]
}
}
];
Here's what you should write:
const tools = [
{
name: "read_file",
description: "Read the full contents of a file at the given path. Use this when you need to inspect file contents. Only use when you know the exact file path โ if you need to find files first, use list_files instead.",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "Exact relative file path from project root, e.g. 'src/index.ts' or 'package.json'"
}
},
required: ["path"]
}
}
];
The description now tells the model:
- What the tool does (reads full contents)
- When to use it (when you know the exact path)
- When NOT to use it (when you need to find files first โ use list_files)
- What the parameter looks like (relative path from project root, with examples)
This alone eliminates a huge class of "wrong tool" errors. The model stops calling read_file with glob patterns and stops calling search_files when it already knows the path.
Technique 5: Error Messages That Enable Recovery
When a tool fails, what the agent does next depends entirely on what you tell it. Most people return raw error strings. Smart people return structured errors with hints.
const tools = [
{
name: "read_file",
handler: async (args: { path: string }) => {
try {
return await fs.readFile(args.path, 'utf-8');
} catch (error) {
if (error.code === 'ENOENT') {
return JSON.stringify({
error: "FILE_NOT_FOUND",
message: `'${args.path}' does not exist.`,
suggestion: "Use the list_files tool to see what files are available in that directory.",
attempted_path: args.path
});
}
return JSON.stringify({
error: "READ_ERROR",
message: error.message,
suggestion: "Check if the path is correct and try again."
});
}
}
}
];
That suggestion field is doing heavy lifting. Instead of the agent hallucinating file contents (which is what happens when it gets a raw "file not found" error), it now has a concrete next step: go list the files and try again. The agent self-corrects instead of making things up.
Technique 6: Thinking Tokens for Complex Reasoning
For tasks that require multi-step reasoning โ debugging code, analyzing dependencies, planning refactors โ turn on thinking tokens. They let the model "think out loud" before acting, which dramatically reduces impulsive wrong turns.
const result = await openClaw.run({
messages: [{
role: "user",
content: "Find the bug causing the test failure in the auth module"
}],
thinking: { enabled: true, budget: "medium" },
maxTurns: 10
});
The thinking budget matters. For simple tasks, "low" keeps costs down. For complex debugging, "medium" or "high" gives the model room to reason through the problem before burning tool calls.
And here's the debugging superpower: you can read the thinking.
result.conversationHistory.forEach((msg, i) => {
if (msg.role === 'assistant') {
msg.content.forEach(block => {
if (block.type === 'thinking') {
console.log(`Turn ${i} thinking:`, block.thinking);
}
});
}
});
When an agent goes off-track, the thinking tokens tell you why. Maybe it misunderstood the task. Maybe a tool returned confusing output. Maybe your prompt was ambiguous. You can see the exact moment the reasoning went sideways and fix your prompt accordingly.
Technique 7: The Boundary Fence System Prompt
After months of iteration, here's the system prompt template I use for almost every focused OpenClaw agent:
const systemPrompt = `You are a focused task executor with access to tools.
RULES:
- Complete ONLY the task described in the user message
- Do NOT suggest improvements beyond what was asked
- Do NOT modify files unless explicitly instructed to
- If you encounter an error, try to recover once, then report the error
- When the task is complete, provide a brief summary and stop
PROCESS:
1. Understand the task
2. Plan the minimum steps needed
3. Execute each step using tools when necessary
4. Summarize what you did
5. Stop
If you can answer directly without tools, do so. Only use tools when you need to interact with files, data, or external systems.`;
This works because it establishes:
- Negative constraints (what NOT to do โ no extra improvements, no unauthorized file changes)
- Recovery behavior (try once, then report)
- A clear process (understand, plan, execute, summarize, stop)
- Tool-use judgment (don't use tools if you don't need them)
Paste this into your OpenClaw agents as a starting point and customize from there.
Putting It All Together
Here's a complete example combining every technique โ an agent that audits a codebase for security issues and produces a report:
import { OpenClaw } from 'openclaw';
const openClaw = new OpenClaw({
model: "claude-3-7-sonnet-20250219",
apiKey: process.env.ANTHROPIC_API_KEY
});
const result = await openClaw.run({
systemPrompt: `You are a security auditor. You analyze code for common vulnerabilities.
RULES:
- Only read files โ never modify them
- Focus on the directories specified by the user
- Report findings in a structured format
- If you encounter an error reading a file, skip it and continue
- Stop after producing the final report
PROCESS:
1. List files in the target directory
2. Read each relevant file
3. Analyze for security issues
4. Produce a markdown report
5. Stop`,
messages: [{
role: "user",
content: `Audit the src/api/ directory for security vulnerabilities.
Focus on:
- SQL injection
- Unvalidated user input
- Hardcoded secrets
- Missing authentication checks
Output a markdown report with:
- File path
- Line number (approximate is fine)
- Issue type
- Severity (high/medium/low)
- Recommendation
Do not modify any files. Stop after producing the report.`
}],
tools: securityAuditTools,
maxTurns: 20,
thinking: { enabled: true, budget: "medium" }
});
// Check what happened
console.log(`Completed in ${result.conversationHistory.length} turns`);
console.log(`Tokens: ${result.usage.inputTokens} in / ${result.usage.outputTokens} out`);
// Get the final report
const finalMessage = result.conversationHistory
.filter(m => m.role === 'assistant')
.pop();
console.log(finalMessage);
This agent stays on-track because every layer is constraining it: the system prompt defines its role and rules, the user message defines the exact scope and output format, maxTurns prevents runaway, and thinking tokens help it reason carefully.
Skip the Setup: Felix's OpenClaw Starter Pack
If you've read this far and thought "this is great, but I really don't want to build all these tool definitions and prompt templates from scratch" โ I get it. That was me three months ago.
Honestly, the fastest way I've found to get productive with OpenClaw agents is Felix's OpenClaw Starter Pack on Claw Mart. It's $29 and comes with pre-configured skills that handle most of the patterns I described above โ the tool definitions, error handling, boundary prompts, the works. Instead of spending a weekend wiring up file operations and debugging tool schemas, you get a working foundation and customize from there.
I'm not saying you can't build all this yourself. You clearly can โ you just read 2,000 words about how. But if your goal is to ship something with OpenClaw this week and not next month, the starter pack pays for itself in the first afternoon.
What to Do Next
Here's your action plan:
-
Add
maxTurnsto every agent you have running right now. This is the single highest-ROI change. If you do nothing else, do this. -
Rewrite your system prompts using the boundary fence template above. Add explicit RULES with negative constraints.
-
Audit your tool descriptions. Add "when to use" and "when NOT to use" guidance. Add parameter examples. Be annoyingly specific.
-
Turn on thinking tokens for any task that requires more than two tool calls. The cost is worth the reliability improvement.
-
Add structured error messages to every tool handler. Include a
suggestionfield that tells the model what to try next. -
Log your conversation history during development. When an agent misbehaves, read the transcript. The problem is almost always visible in the reasoning.
The agents aren't the hard part. The prompts are. Get those right, and OpenClaw does the rest.
Recommended for this post