Write Mode vs Rewrite Mode in FluidVoice: Functional Differences Explained

FluidVoice’s RewriteModeService operates in two distinct functional states: Write Mode creates new content from scratch when no text is selected, while Rewrite Mode modifies existing captured text by enriching prompts with context blocks and instruction wrappers.

The altic-dev/FluidVoice repository implements an AI-powered writing assistant that adapts its behavior based on whether the user is generating fresh content or editing existing text. The RewriteModeService class in Sources/Fluid/Services/RewriteModeService.swift orchestrates these workflows through distinct code paths that handle prompt construction, LLM communication, and analytics tracking differently depending on the presence of selected text.

How the Modes Are Triggered

The service determines which mode to enter by checking the originalText property at the start of the request cycle.

Write Mode activates when no original text is present (originalText.isEmpty). This occurs in two scenarios: when startWithoutSelection() is explicitly called, or within processRewriteRequest when the text buffer is empty (lines 65–74 and 89–95). The service sets isWriteMode = true to signal this state.

Rewrite Mode activates when text has been captured via captureSelectedText() or supplied manually through alternative input methods. In this case, the service sets isWriteMode = false (lines 50–58) and treats the captured content as context for modification.

// Write Mode entry point
let service = RewriteModeService()
service.startWithoutSelection()          // Forces isWriteMode = true
await service.processRewriteRequest("Draft a project proposal email.")

// Rewrite Mode entry point  
let service = RewriteModeService()
if service.captureSelectedText() {      // Captures current selection
    await service.processRewriteRequest("Make this more concise.")
}

Prompt Construction and LLM Interaction

The functional differences extend deeply into how each mode constructs the conversation history sent to the language model.

In Write Mode, the prompt remains unadorned. The service creates a single message object:

Message(role: .user, content: prompt)

This direct passthrough (lines 94–96) assumes the user wants generative output without contextual constraints.

In Rewrite Mode, the service builds a structured prompt that explicitly separates instructions from context. The implementation wraps the user input with "User's instruction:" prefixes and, when selected text exists, appends an "Apply the instruction to the selected context" block (lines 99–115). Additionally, the system prompt may be enriched with a dedicated context block derived from the selected text (lines 120–128), ensuring the LLM understands it is editing rather than creating.

User Experience and Interface Differences

The UI layer in Sources/Fluid/Views/RewriteModeView.swift presents distinct interfaces based on the active mode.

When originalText is empty, the interface displays a generic placeholder prompting users to "Ask the AI to write anything for you" (lines 98–103). This supports the creative, open-ended nature of Write Mode.

When text is selected, the UI shifts to an editing paradigm. It displays an "Original Text" panel showing the captured content and provides instruction prompts like "Edit Selected Text" (lines 64–71, 96–104). This visual feedback reinforces that the AI will transform existing material rather than generate new prose.

Analytics and Telemetry Tracking

The service distinguishes these workflows for analytics purposes through the write_mode boolean flag recorded in SettingsStore.

According to the source code (lines 39–44), successful requests log write_mode as true when operating in Write Mode and false when in Rewrite Mode. This distinction enables product teams to analyze whether users primarily use FluidVoice for content creation or editing tasks.

Summary

  • Write Mode triggers when originalText.isEmpty, setting isWriteMode = true via startWithoutSelection() or empty buffer detection in processRewriteRequest.
  • Rewrite Mode requires captured text via captureSelectedText(), setting isWriteMode = false and enabling context-aware prompt engineering.
  • Prompt structure differs significantly: Write Mode sends raw user input, while Rewrite Mode wraps instructions and injects context blocks into both user and system messages.
  • UI adaptation in RewriteModeView.swift shows generic writing prompts for Write Mode and "Original Text" panels for Rewrite Mode.
  • Analytics tracking records the boolean write_mode flag to distinguish creation from editing workflows.

Frequently Asked Questions

How does FluidVoice detect whether to use Write Mode or Rewrite Mode?

FluidVoice detects the mode by checking if any text is selected when the service initializes. If originalText is empty when processRewriteRequest begins, the service sets isWriteMode = true and enters Write Mode. If captureSelectedText() successfully populates the buffer, or if text is supplied manually, the service sets isWriteMode = false and enters Rewrite Mode.

What happens to the LLM prompt in Rewrite Mode compared to Write Mode?

In Write Mode, the service sends the raw user prompt as a single user message. In Rewrite Mode, the service constructs a complex prompt that prefixes the instruction with "User's instruction:" and appends the selected text within a context block, explicitly instructing the LLM to apply changes to the provided context rather than generating new content.

Can I manually force Write Mode even if text is selected?

Yes. Calling startWithoutSelection() explicitly forces Write Mode by clearing any existing selection and setting isWriteMode = true before processing the request. This bypasses the automatic detection logic that normally checks originalText.isEmpty.

Where does FluidVoice track which mode was used?

The service tracks mode usage in Sources/Fluid/Services/RewriteModeService.swift (lines 39–44) by recording the write_mode boolean flag to analytics when a request succeeds. This flag reads from the isWriteMode property, which is set during mode initialization and persists throughout the request lifecycle.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →