Not every interaction with your coding agent should have the same level of access. Sometimes users want to explore the codebase, understand how something works, or plan an implementation without the agent making any changes. Other times they want the agent to actually build features and modify code.
This is where agent modes come in. By splitting your agent into two distinct modes - full agent mode and read-only chat mode - you give users control over when the agent can take action versus when it just explores and advises.
The Problem with Always-On Agents
Imagine this: You ask your agent "How does authentication work in this project?" A helpful agent searches the codebase, finds the auth files, and explains the flow. Perfect.
But what if it decides to "improve" things along the way? Maybe it notices an outdated pattern and refactors it. Maybe it adds error handling you didn't ask for. Maybe it installs a package to "demonstrate" something.
Now you have unexpected changes in your codebase from what was supposed to be a simple question.
This happens because the agent has all the tools all the time. It can't distinguish between "explore and explain" versus "build and modify" contexts. Mode switching solves this.
Two Modes, Two Purposes
Agent Mode - Full power
- Can create and edit files
- Can run terminal commands
- Can install packages
- Can set up integrations (database, payments, auth)
- Has access to all tools including destructive operations
Chat Mode - Read-only exploration
- Can read files and search code
- Can browse the codebase structure
- Can answer questions and plan features
- Can use web search for documentation
- Cannot make any changes to files or run commands
The key insight: Chat mode isn't a dumbed-down version of agent mode. It's optimized for a different job - understanding and planning rather than executing.
Implementing Mode Logic
You'll track mode as part of your agent's state:
class CodingAgent {
private mode: 'agent' | 'chat';
constructor(options) {
this.mode = options.mode || 'agent';
}
}When initializing your agent, the mode determines which system prompt and which tools to load:
createSystemPrompt(): string {
if (this.mode === 'chat') {
return CHAT_MODE_SYSTEM_PROMPT;
}
// Use appropriate agent mode prompt
return CODING_AGENT_SYSTEM_PROMPT;
}The system prompt for chat mode needs to be explicit about limitations:
You are in CHAT MODE - a READ-ONLY exploration and planning assistant.
IMPORTANT LIMITATIONS:
- You CANNOT edit, create, or modify any files
- You CANNOT run terminal commands or execute code
- You CANNOT make any changes to the codebase
- You can ONLY read, explore, search, and plan
Your primary purpose is to:
- Explore and understand codebases thoroughly
- Answer questions about code and architecture
- Help users plan features and refactors
- Provide explanations when asked
- Suggest approaches and best practices
Strong, clear language. The agent needs to understand its constraints.
Tool Filtering by Mode
Your tool loading logic should filter based on mode:
function getToolsForMode(mode: 'agent' | 'chat') {
const chatModeTools = [
readTool,
grepTool,
globTool,
lsTool,
webSearchTool,
todoWriteTool,
browserLogsTool,
];
const agentModeTools = [
...chatModeTools,
writeTool,
editTool,
bashTool,
sqlTool,
instructionsTool,
setupSupabaseTool,
paymentsAgentTool,
killTerminalTool,
];
return mode === 'chat' ? chatModeTools : agentModeTools;
}Notice what's excluded from chat mode:
- File modification tools (write, edit)
- Action-heavy tools (sql, integrations, terminal management)
- Tools that can make destructive changes
Chat mode keeps search, read, and planning tools. That's all it needs for exploration.
Prompting Mode Switches
Here's a critical UX pattern: When chat mode identifies something that needs implementation, it should prompt the user to switch modes:
WHEN USER ASKS FOR CHANGES:
If the user asks you to make changes, edit files, or implement something:
- Tell them: "I'm in Chat mode (read-only). To make changes,
please switch to Agent mode using the dropdown."
- You cannot switch modes for them - they must do it manually via UI
This teaches the agent to recognize its boundaries and guide users appropriately.
Even better, end every response with a gentle nudge:
If you've helped plan or explain something that could be implemented:
"Want me to implement this? Switch to Agent mode using the dropdown."
This converts exploration sessions into action when the user is ready.
System Prompt Differences
Your chat mode prompt should emphasize different behaviors:
Tone for Chat Mode:
BE CONCISE. Get straight to the point.
- Short, direct answers
- Use bullet points over paragraphs
- Answer the question first, context only if needed
- Skip preambles like "Great question!"
Tone for Agent Mode:
You should be concise, direct, and to the point.
Answer with fewer than 4 lines unless user asks for detail.
Do not add explanations unless requested.
After working on a file, just stop rather than explaining what you did.
Both are concise, but chat mode optimizes for clarity and explanation while agent mode optimizes for minimal output and action.
When Users Should Use Each Mode
Guide your users on mode selection:
Use Chat Mode when:
- Learning how the codebase works
- Asking "how" or "why" questions
- Planning features before implementation
- Exploring unfamiliar code
- Understanding architecture and patterns
- Debugging by analyzing code (not fixing it yet)
Use Agent Mode when:
- Actually building features
- Fixing bugs
- Refactoring code
- Setting up integrations
- Making any changes to the codebase
- Running tests or commands
Think of chat mode as pair programming where you're just discussing. Agent mode is when you hand over the keyboard.
Handling Edge Cases
What if a user asks chat mode to implement something? The agent should respond:
I'm in Chat mode and can only read/explore. Here's how you could implement this:
1. Create a new component at src/components/Feature.tsx
2. Add state management with useState for X, Y, Z
3. Connect to the API endpoint at /api/feature
4. Import and use in the parent component
Want me to implement this? Switch to Agent mode to proceed.
It provides the plan but doesn't execute. This keeps the boundary clear while still being helpful.
Mode Persistence
Decide whether mode persists across sessions:
Session-based: Mode resets to a default (usually agent mode) on new sessions User-preference: Remember the last mode the user selected Context-aware: Default to chat mode for "how" questions, agent mode for "implement" requests
Most implementations use user-preference with agent mode as the default. This gives users control while making the common case (building things) frictionless.
Why This Matters
Mode switching gives users confidence. They know when the agent is just exploring versus when it might make changes. This reduces anxiety about unexpected modifications and makes users more willing to ask exploratory questions.
Without modes, users hesitate to ask "how does this work?" because they're worried the agent will start refactoring things. With modes, they can safely explore in chat mode and explicitly switch when ready for changes.
It's also more efficient. Chat mode agents can use smaller, faster models since they don't need the full reasoning capacity required for complex implementations. They just need to understand and explain.
Real-World Usage Patterns
Here's how this typically plays out:
- User encounters unfamiliar code
- Switches to chat mode: "Explain how the payment flow works"
- Agent explores, reads relevant files, explains the flow
- User understands the pattern
- Stays in chat mode: "How should I add subscription support?"
- Agent outlines an implementation plan with specific steps
- User reviews the plan, switches to agent mode: "Implement this"
- Agent executes the plan it just outlined
The modes complement each other. Chat mode for learning and planning, agent mode for execution.
Implementation Tips
Keep these in mind when building mode support:
Make the mode visible - Users should always know which mode they're in
Make switching easy - A dropdown or toggle in the UI, not buried in settings
Keep context - Switching modes shouldn't reset the conversation history
Different names - The agent's name can reflect the mode ("Coding Agent" vs "Chat Assistant")
Consistent boundaries - If chat mode can't edit files, it can't do it through any tool (bash, write, edit)
What's Next
You now have two modes working together - one for exploration, one for execution. But both modes need context to be effective. An agent that doesn't know about your todos, your file structure, or your design system will miss important constraints.
In the next guide, we'll cover context injection: how to dynamically provide your agent with relevant information about todos, file structures, design systems, and project state without bloating every single request.
That's where the real optimization happens.