A Local-First Windows Assistant: Full-Text File Search, Clipboard Capture, and One-Key Bug Filing
Note: All images in this article are UI mockups. File names, paths, and list contents have been pixelated; no real data is shown.
1. Origin: Tiny Tasks Grind Away an Hour Every Day
A large part of my daily work is spent on "finding things":
- An Excel file sent in a WeChat group, downloaded and then I forget which folder it's in;
- A proposal written three months ago, I only remember two characters from its title;
- A piece of copied text I want to save, but two days later I'm digging through chat history;
- Filing a bug requires a screenshot, annotations, and pasting into a Feishu spreadsheet, a seven- or eight-step ritual;
- Account passwords scattered across memos, Notepad, and browser bookmarks.
None of these things is hard by itself, but doing them dozens of times a day exhausts you. Existing tools are either too heavy, or they require logging in and uploading data to the cloud, which I don't trust.
So I wrote my own: a tray-resident Windows desktop efficiency assistant. All data stays local, and most features work with no internet connection.
The tech stack is simple: Electron 33 + Vue 3, the database is sql.js (a WASM build of SQLite, pure JS, no compilation), stored in the local %APPDATA% directory. Closing the window shrinks it to the tray; it doesn't occupy the taskbar.
2. What It Can Do Now
The app uses a "sidebar + multiple pages" structure. Each functional module handles its own concerns and shares one local database. The five hotkey entries below are the ones I use most.
1. Ctrl+Shift+C: Clipboard Capture
Copy anything, press a hotkey, and the content is grabbed: automatically clean formatting → compute content hash for deduplication → call a large model to generate a one-sentence summary → save to the local database.
I treat it as a "scratchpad collector." The capture library only keeps the current day's content and auto-clears the next day, so it never becomes a second dumpster. When no large-model API is configured, the summary falls back to a local rule engine; the feature still works, just less intelligently.
2. Ctrl+Alt+F: Full-Disk Quick File Search (This Feature Is the Focus)
This is the feature I spent the most time on and the one I use most.
Everyday scenario: a translucent panel pops up at the top of the screen, you type two characters, results appear within a few hundred milliseconds, and pressing Enter opens the file. It's like macOS Spotlight, but for Windows, and it can also search file content.
What it currently supports:
- Dual channel: file name + content. If the file name doesn't hit, it scans document content (PDF, Word, Excel, Markdown, plain text can all have text extracted) and returns the 30-character snippet before and after the hit position, with keyword highlighting;
- Type filter: entering
ext:pdfsearches only PDFs, or you can click the "Document" icon on the right; - Multiple-word combination:
发票 2024means both words must be present;-草稿excludes anything containing "草稿"; - Regex precise filtering: wrap in
/regex/, filters only file names and paths, good for cases like^2026-.*复盘; - Three categories: Programs (reads Windows actual usage records, sorted by most recently opened), Operations (clipboard capture library, Enter copies), Documents;
- Non-empty empty state: when nothing is typed, it directly lists the 10 most recently modified documents;
- Full keyboard operation: ↑↓ to select, Enter to open, Ctrl+Enter to locate the folder, Ctrl+C to copy the path, Esc to close; right-click also offers "Move to Recycle Bin".
Real performance data (indexed 269,000 files, the total of my own projects, code, WeChat files, and download directories):
| Operation | Measured latency |
|---|---|
| File-name keyword search | ~55–150 ms |
| Content keyword search | ~210–350 ms |
| Regex filter on file names | ~235–330 ms |
| Empty-state recent files list | ~100–200 ms |
3. Three Engineering Pits Behind the Quick Search
A "looks-simple" search box hides plenty of traps; here are three representative ones.
Pit 1: No Full-Text Index; Hard Scan Only
The SQLite compiled by sql.js has no FTS5 full-text index module; the log line no such module: fts5 spells death. So content search has to be a LIKE full-table scan, 260,000 rows and 400 million characters, carried purely by the CPU.
The way to survive is controlling the scan scope:
- The index only picks useful directories (Desktop / Documents / Downloads, customizable);
node_modules,.git,dist, and similar directories are skipped outright; - Compiled artifacts, images, audio/video, archives, and other extensions only record file names, never read content; the file name is still searchable, but parsing time isn't wasted;
- Text files larger than 2MB get a placeholder written in, to avoid re-reading them repeatedly;
- Background incremental builds skip files that haven't changed, based on modification time and file size.
Pit 2: Database Ballooned to 1GB, Startup Slowed
When indexing hit 260,000 files, the single database file grew to 1.07 GB. sql.js's flaw is that it reads the entire database into memory, so every startup reads this whole blob, and writing a single setting rewrites the entire database—the main UI visibly stutters.
The solution is splitting the database:
- The main database
assistant.dbkeeps only business data (settings, captures, meeting notes, bug records, credentials), after splitting it's only 45 KB; - The index database
search-index.dbholds the 260,000-row file index separately; it's lazy-loaded at the first search; - The migration doesn't use VACUUM (compressing a 1GB database doubles memory usage), but instead creates a new empty database, copies only the business tables, and replaces the old one—one migration of 269,589 rows, verified for correctness.
I also added a startup warm-up: 3 seconds after the app starts, the index database is read into memory in the background, so the first time you press Ctrl+Alt+F, you don't wait an extra 900+ milliseconds.
Pit 3: Real Acrylic and Rounded Corners on Windows Is an Impasse
Referencing macOS's white translucent panel, I initially used the Windows system-level Acrylic material. The result: the system material isn't affected by window clipping—it always fills the entire rectangular window. The corners are always square, and under dark theme it adds a black overlay.
Tried using setShape to clip rounded corners; Acrylic ignores it outright. The final solution was to abandon the system material and switch to a pure transparent window + gradient + dual inner shadows:
- The panel uses a gradient that's slightly brighter at the top and slightly darker at the bottom to create "thickness";
- Two inner shadows simulate the reflection on glass edges, no outer shadow (outer shadows appear black on transparent windows);
- The collapsed state is a narrow capsule; it expands into the full panel on mouse hover. Expanding and collapsing don't change the window height, only switch child elements, avoiding full-window repaint flicker.
Now the panel doesn't go gray on dark desktops, and the corners are clean 16px rounded.
4. Three Extra Features Built Along the Way
Ctrl+Shift+S: Screenshot Annotation → One-Key Bug Filing to Feishu
Press hotkey → full-screen screenshot → annotate with arrows, rectangles, ellipses, brush, text → fill in title and severity → automatically uploads the screenshot, aggregates by day into a Feishu spreadsheet, and returns the document link.
The screenshot flow has a mandatory order: capture the screen first, then show the window. If reversed, the screenshot window itself will be captured in the image, and the second screenshot is always the residue of the first.
On the Feishu side, details matter: uploaded images must use the docx_image type attached to a specific document; image blocks in the document must go through the three steps "create empty block → attach material → update block"; the link can't be assembled from open.feishu.cn—you have to query metadata separately. These were all discovered one by one.
Ctrl+Shift+O: Screenshot OCR
Uses the same screenshot flow, goes through text recognition, and copies the result directly after recognition. Photographing a PPT during a meeting or capturing an error log goes faster than typing by hand.
Credential Vault
Main password + PBKDF2-SHA256 (600,000 iterations + random salt) + AES-256-GCM encryption. Credential data is physically isolated from the capture library. After 5 consecutive wrong main-password entries, the vault locks for 1 minute. Account passwords no longer live scattered in Notepad.
5. Real Pitfalls, a Few Picked Out
- Reasoning model responses can't take
content[0].textdirectly: models like Qwen first emit athinkingblock. Taking the first one directly yields empty; you must filter by type then concatenatetext, and raisemax_tokensto 4096, otherwise the thinking process can eat up the quota. - PDF parsing library version must be pinned:
pdf-parsev2 is an ESM rewrite with native dependencies, and it throwspdfParse is not a functionin the main process; pinning to 1.1.1 (pure JS) is stable. - Shortcut icons can't be fetched directly: calling the icon interface on a
.lnkreturns a generic blank icon; you must resolve to the target exe first. - Concurrent searches can return out of order: hitting the same keyword twice quickly can let the earlier request come back later, overwriting the latest result with an empty list. Added a version counter; only the latest write updates the UI.
- Main-process code doesn't hot-reload: electron-vite only hot-reloads the renderer layer; changing the main process requires a manual restart, otherwise you fall into the self-doubt of "the code changed but nothing happened."
6. After All This, What Did It Actually Change?
Honestly, the benefit isn't a pretty number like "300% more efficient," but three very small things:
- Finding files no longer carries a mental burden. No need to remember paths; two words suffice. Press Ctrl+Alt+F, type two characters, Enter.
- Things have a place to go. The capture library clears daily, credentials go into the vault, bugs automatically land in a Feishu spreadsheet—no more constantly carrying "where did I put that thing" in your head.
- The data is yours. Everything stays local, no uploads, no login, no dependency on a service staying alive. It works offline, and data isn't lost when a service shuts down.
This tool has no plan to be open-sourced, because it's tailor-made for "my way of working": receiving files via WeChat, filing bugs every day, occasionally digging up old proposals, always looking for passwords. Someone else might find half the features useless.
But the whole process validated one thing: the little moves that make you go "ugh, here we go again"—collect them into one automation, and the payoff is bigger than you expect. Even just saving a few presses of "open folder, flip through directories, copy path."
If you're also on Windows and constantly crash while finding files, tools like Everything can be a stopgap. To really get it comfortable, you have to mold the tool into your own hand.