Flows, Chat & Commands
Windsurf has four distinct interaction modes. Knowing which to use for which task is the difference between productive AI-native development and frustrating back-and-forth. This module goes deep on each mode -- when to use it, how to structure prompts for it, and how to chain modes together for complex development workflows.
Understanding the Four Modes
Flows (Agentic)
Multi-step tasks requiring planning and execution across files. Describe the goal; Cascade plans and executes. Best for feature implementation, large refactors, test generation, migration tasks, and anything touching more than two files.
Chat Mode
Conversational Q+A about your codebase. "How does the auth middleware work?", "What calls this function?", "Explain this regex." Cascade answers with codebase-grounded context. No file edits are made.
Inline Completions
Real-time line and block completions as you type. Context-aware -- Cascade considers the full file and semantically related files. Accept with Tab. Use for routine code where the pattern is clear and you want zero interruption.
Slash Commands
/explain, /fix, /test, /refactor, /doc -- targeted actions on selected code. Faster than writing a full Flow prompt for single-function tasks. Use for focused, bounded edits to one function or class.
Flows -- Deep Dive
Flows are Windsurf's most powerful mode. When you press Cmd+I and describe a goal, you are not asking for a code snippet -- you are delegating an entire development task. Cascade creates a plan, shows it to you for approval, then executes it across as many files as needed, running terminal commands to verify its work.
Anatomy of a Good Flow Prompt
A Flow prompt has five components. You do not need all five for every task, but the more you provide, the better the output:
- Goal: What should exist when this Flow is done? "Add a rate limiter to the API." Be specific about the end state, not the steps.
- Constraints: What patterns must be followed? "Use the token bucket algorithm. Store state in Redis." Constraints prevent Cascade from making choices you would reject.
- File references: Where should this code live? "Implement in src/middleware/rate_limiter.ts. Tests in tests/rate_limiter.test.ts." Explicit paths prevent Cascade from creating files in unexpected locations.
- Test expectations: What should the tests verify? "Test: 101st request within one minute returns 429. Test: requests from different IPs are tracked independently." Concrete test cases force Cascade to think about edge cases.
- Convention references: Which existing code to follow? "Follow the same middleware pattern as @src/middleware/auth.ts." This grounds Cascade in your project's actual style rather than generic patterns.
Add rate limiting to the API.
Add a token-bucket rate limiter to the FastAPI app. Limit: 100 requests per minute per API key. Store bucket state in Redis (connection from @src/config/redis.py). Return 429 with Retry-After header when exceeded. Implement in src/middleware/rate_limiter.py. Tests in tests/test_rate_limiter.py: test limit exceeded, test different API keys tracked independently, test bucket refill after timeout. Follow middleware pattern from @src/middleware/auth.py.
Flow Types by Task Category
Different development tasks call for different Flow structures:
| Task Type | Flow Structure | Example Prompt Opening |
|---|---|---|
| New feature | Goal + files + tests + conventions | "Add a wishlist feature to ShopMate..." |
| Refactoring | Current state + target state + constraint (no API changes) | "Refactor UserService to use repository pattern. Do not change the public API..." |
| Migration | From + to + scope + verification | "Migrate all Jest tests to Vitest. Start with src/services/..." |
| Test generation | Target file + coverage expectations + edge cases | "Write comprehensive tests for @src/services/payment.ts covering..." |
| Bug fix | Bug description + reproduction + expected fix approach | "Fix: checkout fails when cart has items from two different warehouses..." |
| Documentation | Target files + doc style + audience | "Add JSDoc to all exported functions in src/api/. Include param types and examples..." |
Automation Patterns with Flows
Experienced Windsurf users develop reusable Flow patterns for repetitive tasks. Here are the most common automation patterns:
The Scaffold Pattern: Use a Flow to create the complete file structure for a new feature, then fill in the details with inline completions. This is faster than writing each file manually because Cascade ensures all the imports, types, and wiring are consistent from the start.
# Scaffold a complete new feature with all required files
Scaffold a new "order tracking" feature for ShopMate:
1. Model: shopmate/models/order_tracking.py
- OrderStatus enum: pending, shipped, delivered, returned
- TrackingEvent: timestamp, status, location, carrier_message
- OrderTracking: order_id, events list, current_status, estimated_delivery
2. Repository: shopmate/repositories/tracking_repository.py
- get_tracking(order_id) -> OrderTracking
- add_event(order_id, event) -> TrackingEvent
- get_orders_by_status(status) -> list[OrderTracking]
3. Service: shopmate/services/tracking_service.py
- Uses tracking_repository (injected)
- update_tracking(order_id, carrier_data) -- parses carrier webhook
- get_customer_tracking(order_id, customer_id) -- with auth check
4. Router: shopmate/api/routes/tracking.py
- GET /orders/{order_id}/tracking
- POST /webhooks/carrier (for carrier status updates)
5. Tests: tests/test_tracking.py
- Test each repository method
- Test service auth check
- Test webhook parsing
Follow all conventions in .windsurfrules.
The Migration Pattern: For systematic changes across many files (updating imports, changing API patterns, migrating to a new library), use a Flow that processes files in batches. Do not try to migrate everything in one prompt -- break it into logical groups.
# Migrate in batches, not all at once Migrate the service layer from direct DB queries to the repository pattern. Start with ONLY these two services: 1. @src/services/user_service.py -> extract queries to @src/repositories/user_repository.py 2. @src/services/product_service.py -> extract queries to @src/repositories/product_repository.py Rules: - Services depend on repository interfaces, not concrete implementations - Repository methods return domain models, not SQLAlchemy rows - Do NOT change any router code -- service public APIs must stay the same - Run: pytest tests/services/ after each file to verify nothing breaks # After this succeeds, do the next batch in a separate Flow.
The Test-First Pattern: Write failing tests first, then implement. This produces better code because Cascade has a concrete verification target.
The Review-Then-Implement Pattern: Use Chat to discuss the approach, then use a Flow to implement it. This two-step process catches design issues before any code is written.
Chat Mode -- Deep Dive
Chat mode (Cmd+L) is for understanding, not building. It is your codebase-aware rubber duck. Unlike a generic ChatGPT conversation, Windsurf Chat has access to your semantic index, so when you ask "How does the auth middleware work?", it reads the actual auth middleware file, traces its call chain, and explains your specific implementation -- not a generic description of middleware patterns.
Effective Chat patterns:
- Architecture exploration: "Trace the request flow from when a user clicks 'Buy Now' to when the order is saved in the database. List every file involved."
- Impact analysis: "If I change the User model to add a 'preferences' JSON field, which services, repositories, and tests would need to be updated?"
- Trade-off discussions: "Should we use WebSockets or Server-Sent Events for real-time order tracking, given our current FastAPI setup and expected load of 500 concurrent users?"
- Code archaeology: "Why does the payment service have two different retry mechanisms? Which one is actually being used?"
- Learning from codebase: "Show me 3 examples of how error handling is done in the service layer. Are they consistent?"
Chat mode will never modify your files, even if you ask it to. If Chat suggests a code change, switch to a Flow or slash command to implement it. This is a deliberate safety feature -- Chat is for learning and planning, not for making changes. If you find yourself asking Chat to "fix this," you should be in Flow mode instead.
Slash Commands -- Deep Dive
Slash commands are the middle ground between inline completion (too small) and Flows (too big). Select a block of code, type a slash command, and Cascade applies a focused transformation.
| Command | What It Does | When to Use | Example |
|---|---|---|---|
| /explain | Explains the selected code in plain language | Unfamiliar code, complex regex, inherited code | Select a regex; /explain |
| /fix | Identifies and fixes bugs in the selection | Known bug in a specific function | Select broken function; /fix "off-by-one error in pagination" |
| /test | Generates tests for the selected code | Adding tests for a single function or class | Select a utility function; /test |
| /refactor | Restructures code without changing behaviour | Cleaning up a single function | Select a long if-else chain; /refactor "use a dictionary dispatch" |
| /doc | Adds documentation (docstrings, JSDoc, etc.) | Undocumented function that needs docs | Select a class; /doc "Google-style docstrings" |
You can add natural language after any slash command to refine the instruction. "/fix" by itself tells Cascade to find and fix whatever is wrong. "/fix the pagination is returning one extra item when total is evenly divisible by page_size" gives it a precise target. The more specific you are, the better the result.
Inline Completions -- Deep Dive
Inline completions are the fastest interaction mode -- you just type, and Cascade predicts what comes next. What makes Windsurf's completions different from simple autocomplete is context awareness. Cascade considers:
- The full content of the current file
- Semantically related files (if you are writing a service, it reads the repository it should call)
- Your .windsurfrules conventions
- Recently edited files in the session
- Import patterns and type definitions
This means when you start typing a new function that calls your UserRepository, Cascade already knows the repository's method signatures and will complete the calls correctly, including parameter names and types.
Press Tab to accept the completion. Press Escape to dismiss it. If the completion is partially right, accept it and then edit the parts that need changing -- this is often faster than rejecting and retyping from scratch. If you find completions distracting while thinking, you can temporarily disable them in Settings without losing the other Windsurf features.
Chaining Modes Together
The most productive Windsurf workflows chain multiple modes in sequence. Here is a common pattern for implementing a new feature:
- Chat -- "How does the existing notification system work? What patterns should a new notification type follow?"
- Chat -- "What are the trade-offs between queuing notifications vs sending them synchronously, given our current architecture?"
- Flow -- "Implement a new email notification for wishlist restock, following the patterns we just discussed. Write failing tests first."
- Inline completion -- Manually add a few edge case tests that Cascade missed, using completions to write them quickly.
- /fix -- If a specific test is failing, select the failing function and use /fix with the error message.
This pattern -- understand, plan, implement, refine -- mirrors how experienced developers work. The difference is that each step is faster because Cascade carries context through the entire chain.
Triggers and External Tool Integration
Flows can interact with external tools through the terminal. Any command-line tool available in your environment can be part of a Flow:
- Linters: "Run eslint on the changed files after implementation and fix any issues."
- Type checkers: "Run mypy on the service layer after changes and resolve any type errors."
- Database migrations: "Generate an Alembic migration for the new OrderTracking model."
- API testing: "Start the dev server, run the integration test suite against localhost:8000, and fix any failures."
- Docker: "Rebuild the Docker image and run the containerised tests."
Because Cascade can read terminal output and react to it, these integrations create powerful feedback loops. Cascade writes code, runs the linter, reads the warnings, fixes them, re-runs the linter -- all without your intervention.
Decision Framework: Which Mode?
| Scenario | Best Mode | Why |
|---|---|---|
| Implement a new feature across 5 files | Flow | Needs planning + multi-file coordination |
| Fix a specific known bug | /fix or Flow | Either works; /fix faster for a single function |
| Understand unfamiliar inherited code | Chat | Q+A with codebase context, no edits needed |
| Write a function you know the shape of | Inline completion | Pattern is clear, no planning needed |
| Add JSDoc to all exported functions | Flow | Repetitive multi-file task -- automate it |
| Explain what a regex does | /explain | Single-item, no file edits needed |
| Migrate tests from Jest to Vitest | Flow | Multi-file, systematic change |
| Write tests for one specific function | /test | Bounded to one function, no broader context needed |
| Discuss trade-offs before implementing | Chat | Exploration, no code changes yet |
| Add a field to a Pydantic model | Inline completion | Simple, pattern-following addition |
| Rename a variable across a file | /refactor | Bounded, mechanical transformation |
| Create a complete CRUD module | Flow | Model + repository + service + router + tests |
ShopMate -- Which Mode to Use
## ShopMate Development: Right Windsurf Mode for Each Task ## FLOW (Cmd+I) -- multi-file, needs planning: "Add a new ShopMate feature: [description], following .windsurfrules" "Add a new brand to ShopMate (PetThreads) with its own voice and budget" "Migrate all ShopMate Claude calls to use the new logged_create() wrapper" "Add integration tests for the customer chat multi-turn session" "Refactor shopmate/api/main.py -- it is getting too long, split into sub-routers" ## CHAT (Cmd+L) -- understand before you build: "How does the multi-brand system work? Walk me through a describe_for_brand() call" "What would break if I changed the model in logged_create from Haiku to Sonnet?" "Why does safe_reply() sometimes return the fallback message for perfectly fine replies?" ## SLASH COMMANDS -- single function, no planning needed: /explain -- understanding a prompt template or RAG query /fix -- a specific bug: "wrong brand voice being applied" /test -- tests for a new describe_product() variant /doc -- docstring for ShopMateChat class /refactor -- simplify the multi-brand YAML loading ## INLINE COMPLETION -- pattern is obvious: Adding a new field to a Pydantic model (ProductIn, CampaignIn) Writing another tool definition following the existing pattern Adding a new brand to brands.yaml
Common Flow Anti-Patterns
These mistakes reduce Flow quality and waste credits:
| Anti-Pattern | Problem | Better Approach |
|---|---|---|
| Mega-Flow: "Refactor the entire codebase" | Too broad; Cascade cannot hold the full plan in context | Break into focused Flows per module or layer |
| No test expectations | Cascade writes superficial tests or skips them | Specify concrete test cases and edge cases |
| No file references | Cascade creates files in unexpected locations | Specify target file paths explicitly |
| Vague constraints | "Make it good" gives Cascade no criteria to optimise for | Specify patterns, libraries, and conventions |
| Using Flow for a one-line change | Overkill; wastes time on planning | Use inline completion or /fix |
| Not referencing .windsurfrules | Cascade uses generic patterns instead of your conventions | End with "Follow conventions in .windsurfrules" |
Hands-On Exercises
For each of these tasks, decide which mode you would use and write a one-sentence justification: (a) Add a "last login" timestamp to the User model. (b) Understand how the payment retry logic works. (c) Create a complete new API endpoint with tests. (d) Fix an off-by-one error in the pagination helper. (e) Add type annotations to all functions in utils.py. Compare your answers with the decision table above.
Choose a feature you want to add to a project. Write a complete Flow prompt following the Scaffold Pattern shown above. Include: (1) all files to be created, (2) the key functions/classes in each file, (3) at least 3 specific test cases, (4) references to existing code for conventions. Submit the Flow and review the plan before Cascade executes. How close was the plan to what you expected?
Pick a moderately complex task (e.g., adding caching to an existing endpoint). First, use Chat to explore: "How does the current caching work? What patterns exist? What would you recommend for this endpoint?" Then, take the recommendation and turn it into a Flow prompt. Compare the quality of the Flow output when you did this two-step process vs. going straight to a Flow without the Chat exploration.
Find a file in your project with poor documentation. Use /doc on 5 different functions to add docstrings. Then use /explain on the most complex function to see if the AI-generated docstring matches the AI-generated explanation. Time yourself -- how long does documenting 5 functions take with slash commands vs. writing them manually?
Identify a small, safe migration in your project (e.g., updating import paths, switching a utility function to a newer API, adding type annotations). Write a batch-style Migration Pattern Flow for just 2-3 files. Run it and verify the tests pass. Then do the next batch. Reflect: was the batch approach more reliable than trying to do everything at once?