DEV Community

SN
SN

Posted on

I Built TextRecast: A Local Windows Writing Assistant with .NET and an SLM

The TextRecast application icon

Writing tools are useful, but I did not want to copy text into a separate website every time I needed to improve a sentence. I also wanted an option that did not send the selected text to a cloud inference API.

That idea became TextRecast, an open-source Windows utility that rewrites selected text inside the application where I am already working.

Select some text, click the floating TextRecast button, choose an operation, and apply the result back to the original selection. The language model runs locally on the CPU.

What TextRecast can do

TextRecast currently supports:

  • Improving grammar, spelling, punctuation, wording, and clarity
  • Making selected text shorter or longer
  • Summarizing longer selections
  • Changing the tone to Professional, Casual, Friendly, Formal, or Direct
  • Replacing the original selection without requiring a manual copy-and-paste cycle

There is no account, API key, or text-processing cloud service involved. Normal formatting runs locally after the model has been installed.

Why local inference?

The main goal was not to build another chat interface. It was to create a focused editing tool that stays close to the text being edited.

Local inference provides a few useful properties:

  • Selected text is not submitted to a model API.
  • The tool continues working without an internet connection after model installation.
  • There is no per-request API cost.
  • The model lifecycle is controlled by the application.

TextRecast itself does not maintain a formatting history or write selected and generated text to log files.

There is still an important Windows-specific caveat: the fallback capture and replacement paths temporarily use the clipboard. Windows clipboard history, clipboard synchronization, or third-party clipboard managers may retain that content. Users working with sensitive text should disable those features.

The technology stack

TextRecast is built with:

  • WPF and .NET 10 for the Windows desktop application
  • LLamaSharp for local GGUF inference
  • Qwen2.5-1.5B-Instruct-GGUF as the initial small language model
  • Windows UI Automation for reading selected text when supported
  • Native Windows clipboard, window-focus, and input APIs for fallback capture and replacement
  • MSTest for workflow, prompt, chunking, and clipboard integration tests

The default model uses the Q4_K_M quantization. It is small enough to be practical on ordinary x64 Windows computers while still being useful for focused rewriting tasks.

Keeping the architecture replaceable

Although TextRecast currently ships with a Qwen model profile, the infrastructure is named around the more general concept of an SLM rather than one model family.

The solution is split into three main projects:

TextRecast.App ----------> TextRecast.Core
       |
       +-----------------> TextRecast.Infrastructure
                                   |
                                   +------> TextRecast.Core
Enter fullscreen mode Exit fullscreen mode

TextRecast.App contains WPF presentation and application composition. TextRecast.Core contains formatting requests, workflows, contracts, results, and platform-independent models. TextRecast.Infrastructure contains LLamaSharp inference, model installation, and Windows integrations.

This separation means a future model can reuse installation, checksum verification, storage, chunking, inference lifecycle, and application workflow components. A model with a different chat format only needs an appropriate model profile and prompt builder.

First launch without bundling a 1.1 GB model

I did not want every source clone or application download to include a large model binary.

When TextRecast starts, it looks for:

  1. A valid model packaged beside the application
  2. A valid model previously installed for the current Windows user

If neither exists, a setup window downloads the model. The download can be cancelled or retried, and the UI reports both transfer and verification progress.

The installer does not trust a completed HTTP request by itself. It downloads to a uniquely named partial file, checks the expected file size and SHA-256 digest, and only then moves the file into its final location:

%LOCALAPPDATA%\TextRecast\Models
Enter fullscreen mode Exit fullscreen mode

A failed or cancelled partial download is never treated as an installed model.

After installation, the first formatting request loads the model into memory. Later requests reuse the same model instance, so they usually begin faster.

Replacing text safely is harder than pasting

Generating text is only half of this application. Replacing the correct selection without damaging unrelated text or clipboard contents requires more care.

The replacement flow is approximately:

Capture selected text
        |
        v
Generate locally with the SLM
        |
        v
Revalidate window, process, age, and selected text
        |
        v
Snapshot clipboard formats
        |
        v
Paste the replacement
        |
        v
Restore and verify the clipboard snapshot
Enter fullscreen mode Exit fullscreen mode

Before replacement, TextRecast verifies that the original window still exists, belongs to the same process, and contains the expected selection. Captured selections expire after a limited period instead of remaining valid indefinitely.

The clipboard snapshot owns deep copies of its captured formats rather than retaining a live Windows data object. After replacement, TextRecast rebuilds the clipboard and reads every captured format back to verify restoration. If replacement succeeds but restoration cannot be verified, the result window remains open and displays a warning instead of immediately disappearing.

The integration test for this path runs on a Windows STA thread. It captures Unicode text and a custom binary stream, temporarily replaces the clipboard, restores both formats, verifies their contents, and finally restores the clipboard that existed before the test.

Packaging the application

The Windows x64 release is published as a self-contained .NET application. Users do not need to install .NET 10 separately.

I chose a complete ZIP rather than distributing only one executable because the application also depends on native inference libraries and legal notice files. Every file in the archive needs to remain together.

The release package does not include the model, so the initial application download remains much smaller. The model is obtained through the verified first-launch flow described above.

Trying TextRecast

The packaged application requires:

  • Windows 10 or Windows 11 on x64 hardware
  • The current Microsoft Visual C++ x64 Redistributable
  • Approximately 1.5 GB of available disk space
  • An internet connection for the first model download

To try it:

  1. Download the complete Windows x64 ZIP from the Releases page.
  2. Extract the complete archive.
  3. Run TextRecast.exe.
  4. Allow the verified model installation to finish.
  5. Select editable text in another application and click the floating TextRecast button.

Because early builds are not code-signed, Windows SmartScreen may display a warning. Always verify that the archive came from the official repository release.

Building from source

Development requires the .NET 10 SDK. From the repository root:

dotnet restore TextRecast.slnx
dotnet build TextRecast.slnx -c Release --no-restore
dotnet test TextRecast.slnx -c Release --no-build
dotnet run --project src/TextRecast.App/TextRecast.App.csproj
Enter fullscreen mode Exit fullscreen mode

The CI workflow also verifies formatting, runs the complete test suite, builds in Release configuration, and publishes the self-contained Windows artifact.

Current limitations

TextRecast is an early release, and its boundaries are intentional:

  • It currently targets Windows x64 only.
  • Inference is CPU-only, so large selections take longer.
  • The first model download is approximately 1.1 GB.
  • The source application must support UI Automation selection or standard copy-and-paste shortcuts.
  • Windows may block simulated input when the source application runs as administrator and TextRecast does not.
  • Local inference improves privacy, but clipboard history and third-party clipboard managers remain outside the application's control.
  • The application is not yet code-signed.

These are useful constraints to state explicitly. "Local" should describe what the application actually does, not become a vague promise that ignores the operating system around it.

What comes next?

The SLM abstraction leaves room for additional local model profiles and prompt formats. I also want to continue improving performance, compatibility across Windows applications, accessibility, and the first-run experience based on real usage.

For now, the goal is deliberately focused: select text, transform it locally, verify that the original selection is still safe to replace, and return the result to the application where the work is happening.

If that workflow sounds useful, take a look at TextRecast on GitHub. Issues and technical feedback are welcome while the project is still taking shape.

Top comments (0)