Archived historical document. This records an earlier plan or investigation, not current developer guidance. LinuxFiles is an independent Linux-only fork with no upstream sync or Windows support. See the current policy and developer guidance.
Branching (2026-10-05):
mainis the single integration branch.linux/mainis retired (frozen at the last merge). Releases are tags: the rollingnightlypre-release (every push tomain) and stablelinux-v*tags.
Status: phases 0–7 done (2026-10-06); phase 8 optional · draft v1 · 2026-10-04 · fork base 0e3c17ca4 (in sync with files-community/Files main)
The upstream policy overrides earlier merge-preservation and Windows-restoration guidance below. LinuxFiles no longer merges upstream; the upstream remote is read-only and individual fixes are cherry-picked selectively. Windows leaf projects, their build references, Windows CI/MSIX packaging, and sync/pruning automation are removed. Windows code inside Files.App remains for later stages. Preserve MIT/MPL licenses and NOTICE credit.
The remaining sections record the original porting plan and its completed phases.
This section overrides anything below that conflicts with it.
The owner decided to focus on Linux first. Windows support is revisited only after the Linux version works.
- The Windows build no longer has to stay green; Windows workflows have been removed.
- We still put platform code behind
Files.Platform.Abstractionsinterfaces. That keeps the Linux code clean and gives selectively imported fixes clear platform boundaries. Windows-only code may be excluded from the build or left uncompiled instead of carefully wrapped. - Fork autonomy: agents may push branches, open and merge PRs on
MemerGamer/LinuxFilesfreely. Never touch upstream.
- No native Wayland in Uno. Linux runs on X11, which means XWayland on Wayland sessions. Fractional scaling can be blurry. Custom title bars and drag regions are no-ops, so we use system decorations.
- Outbound file drag & drop throws
NotImplementedException. A drag leaving the window may crash the app. The clipboard cannot publish file lists. Both are core features. New workstream L-DND fixes them, preferably as an upstream Uno contribution, otherwise with our own X11 selection/XDND owner. - Not implemented, so guard them or replace them:
ResourceManager().MainResourceMap: switch toResourceLoader.GetStringElementCompositionPreview.GetScrollViewerManipulationPropertySet: StickyHeaderBehaviorAppInstance: replace with D-Bus or a Unix socket- AccessKey/KeyTips
- Mica/Acrylic
InputNonClientPointerSourceregions- WebView2 Profile/Settings
- InteractionTracker modifiers
- Supported: InputKeyboardSource, AppWindow move/resize, multiple windows, TabView (no tear-out), ContentDialog, TeachingTip, ItemsRepeater, x:Load, VSM, runtime theme switching, KeyboardAccelerator, ExpressionAnimation, CompositionPath (fed from SKPath instead of Win2D), inbound XDND, and reading files from the clipboard.
- Known gap: no AT-SPI accessibility on Linux in Uno.
- Unproven: ListView/GridView performance with 10k–100k items. Needs spike P0-PERF.
| Phase | Goal | Parallelism |
|---|---|---|
| 0 | Toolchain, CI, Uno spike, research. Extra spikes: P0-PERF (10k/100k items) and P0-DND (outbound XDND + file clipboard prototype) ✅ Done (2026-10-04). | parallel |
| 1 | Abstraction skeleton (Files.Platform.*, tests, DI) ✅ Done (2026-10-04). |
serial, small |
| 2 | Linux bring-up: make Files.App compile and launch on Uno net10.0-desktop. Retarget Controls + App to Uno. Exclude Windows-only folders (Compile Remove). Replace Win32/WinRT calls with interface calls, backed by stub or simple Linux implementations. Fix compile errors folder by folder. ✅ Done (2026-10-05): the app compiles, launches and runs on Linux; the compat-off criterion moved to Phase 4. |
parallel by folder ownership |
| 3 | Real Linux backends per interface (enumeration, watcher, file ops, trash, launcher, thumbnails, drives, clipboard…), with unit tests ✅ Done (2026-10-05): every interface has a Linux backend with unit tests. | parallel, one agent per interface |
| 4 | Replace the legacy WinRT storage layer (BaseStorageFile/Folder) with OwlCore storables, then switch Win32 compat mode off (moved from Phase 2). ✅ Done (2026-10-05, P4-Z): compat mode is off by default and the desktop build has 0 errors, which also meets Phase 2's criterion |
parallel work packages (see Phase 4 plan, Revision 3) |
| 5 | UI blockers and UX parity: L-DND, SpeedGraph, StickyHeader, title bar, previews, single instance ✅ Done (2026-10-06): drag and drop, client-side title bar with tabs, previews, grouped virtualization, KDE service menus. | parallel |
| 6 | Desktop integration and packaging (FileManager1 D-Bus, .desktop, Flatpak/AppImage/AUR) ✅ Done (2026-10-06): AppImage, Flatpak and AUR packaging, nightly CI, idempotent tagged releases; 0.1.0-alpha1 is drafted. |
parallel |
| 7 | Hardening (performance, HiDPI, themes, localisation) ✅ Done (2026-10-06): HiDPI scale detection, translation fallback and key checks, keyboard accessibility, authenticated root actions. Known gap: light-theme toolbar focus fading. | parallel |
| 8 | (Optional) Restore Windows: multi-target again, Windows backends behind the same interfaces | later |
The Phase 2 workstreams in §7.3 still define folder ownership. Their goal is now "compiles and works on Linux", not "Windows code wrapped without behaviour change".
- Win32 compat mode is off by default since P4-Z (2026-10-05) (
FilesWin32Compat=falseinDirectory.Build.props). The desktop build no longer compiles Win32/Shell code or builds the CsWin32 assembly.-p:FilesWin32Compat=truestill works as an opt-in inventory lens: it compiles the Windows-only folders against CsWin32 and definesFILES_WIN32_COMPAT. Nothing compiled that way runs on Linux. Linux CI builds with compat off and fails on any error. (Until P4-Z compat mode was the default. Switching it off was Phase 2's exit criterion and became Phase 4's on 2026-10-05.) - Nullable diagnostics are warnings on
-desktop, because Uno's annotations differ from WinUI's. Re-enable once the build is clean. - Stubbed behaviour is tagged
// LINUX-TODO(<area>). Userg -n LINUX-TODO srcto find the backlog.
- File operations: same-device move (
rename) and cross-device move recursion are still path-based. Userenameat/unlinkaton directory handles. Destination-side folders are also addressed by path. - Trash: a small TOCTOU window between the restore containment check and the move. Fix with
openat/renameaton directory handles. - Thumbnailer sandbox: no seccomp filter.
--new-sessionmitigates TIOCSTI. - Shared native interop lives in
src/Files.Platform.Linux/Native/([LibraryImport]only). Reuse it; don't add new P/Invoke elsewhere.
Files is a WinUI 3 / Windows App SDK app (~130k LOC C#, 136 XAML files / ~30k XAML lines). Porting it to Linux is two largely independent problems:
- UI framework — WinUI 3 does not run on Linux. Recommendation: Uno Platform (Skia desktop, X11 + Wayland).
Uno re-implements the
Microsoft.UI.XamlAPI surface, so the XAML (1,688x:Bind, 168x:Load, 1,084ThemeResource) and ~17k lines of code-behind carry over largely intact. An Avalonia rewrite would cost 5–10× more. - OS integration — this is the bigger cost and is the same regardless of UI choice:
- CsWin32 /
Windows.Win32: 137 files, 609PInvoke.call sites, ~400 APIs inNativeMethods.txt - WinRT
Windows.Storage: 128 files, 806StorageFile/StorageFolderhits (the legacyBaseStorageFilelayer) - Registry (22 files),
ApplicationData(20 files), MSIX/packaged-app APIs, Shell COM (context menus, thumbnails, IFileOperation, preview handlers)
- CsWin32 /
Strategy: introduce a platform abstraction layer, move Windows code behind it unchanged, then add a Linux backend and an Uno head. The Linux desktop build must keep working at every step.
- Independent fork. Use clear platform seams and selectively cherry-pick upstream fixes with attribution. Do not merge upstream branches; see upstream-policy.md.
- Linux build stays green. Every PR must build the desktop app and remaining Linux tests.
- Drop, don't port, Windows-only features (listed in §6). Hide them in the UI on Linux via a capability flag.
- Managed first, native second. Prefer
System.IO,FileSystemWatcher, SharpCompress, TagLibSharp, Tmds.DBus over P/Invoking GLib. Use GIO only where a managed path is clearly worse (thumbnails, mime/app info). - Respect repo rules (
CLAUDE.md): CRLF line endings,.editorconfig, no newDllImport/ComImport, AOT-safe code, no edits to generated CsWin32 output.
| Project | TFM today | Linux verdict |
|---|---|---|
| Files.Shared | net10.0 | Portable (remove win-* RIDs; LogPathHelper redaction is Windows-path-only) |
| Files.Core.Storage | net10.0 (OwlCore.Storage) | Portable — the right foundation, but barely used by the app |
| Files.Core.SourceGenerator | netstandard2.0 | Portable |
| Files.App.Storage | windows | Split: Ftp/, Legacy/NativeStorageLegacy portable; Windows/ stays Windows |
| Files.App.Controls | windows (WinUI) | Clean of Win32/Composition — ports to Uno with minor changes |
| Files.App | windows (WinUI, MSIX) | The bulk of the work |
| Files.App.CsWin32 | windows | Windows-only |
| legacy Windows COM server | windows (OOP WinRT server) | Drop on Linux |
| legacy Windows update-task project | windows (MSIX update task) | Drop on Linux |
| legacy Windows launcher / OpenDialog / SaveDialog | C++ vcxproj | Drop on Linux (see §6 for replacements) |
| tests/* | windows (Appium/WinAppDriver, WinUI gallery) | No unit tests exist today |
All csproj files hard-code RuntimeIdentifiers=win-x86;win-x64;win-arm64, including the neutral ones.
| Folder | .cs | Files w/ Win32/WinRT | Coupling |
|---|---|---|---|
| Utils | 140 | 80 | Very high (Shell/, Storage/StorageItems, Signatures, Taskbar, Cloud) |
| Helpers | 56 | 24 | High (Helpers/Win32/, Registry) |
| Services | 58 | 15 | Concentrated in Services/Windows, Services/Storage |
| ViewModels | 85 | ~35 | Medium-high; 31 also reference XAML types |
| Actions | 172 | 28 | Low — ~62% already platform-neutral |
| Data | 256 | 25 | Low OS coupling, high UI coupling |
Gotcha:
.gitignore's[Ww]in32/rule makesrgskipsrc/Files.App/Helpers/Win32/. Always search withrg --no-ignore.
- File-operations stack —
Utils/Storage/Operations/{FileOperationsHelpers,ShellFilesystemOperations,FilesystemOperations}.cs,Utils/Shell/ShellFileOperations2.cs,Files.App.Storage/Windows/WindowsBulkOperations*(~3.7k LOC, IFileOperation on STA). ViewModels/ShellViewModel.cs(3,578 LOC) — directory enumeration (FindFirstFileExFromApp),ReadDirectoryChangesWwatcher, thumbnails,DangerousGetFolder*. The single most important seam.Helpers/Win32/Win32Helper.Storage.cs(1,211 LOC) +Win32PInvoke.Methods.cs— attributes, ADS, icons, PowerShell.- Legacy WinRT storage layer —
Utils/Storage/StorageItems/*(BaseStorageFile/Folder,System*,Shell*,Zip*,Ftp*,Virtual*), referenced by 61 files. - Shell item / PIDL layer —
Utils/Shell/ShellItem.cs,ShellFolderExtensions.cs,WindowsStorableHelpers.Shell.cs. - Context menus —
Utils/Shell/{ContextMenu,OpenWithMenu,ShellNewMenuHelper,ContextMenuWorkerPool}.cs. - Icons & thumbnails —
WindowsStorableHelpers.Icon.cs,FileThumbnailHelper,IconCacheService(29 consumers). - Security/ACL —
StorageSecurityService.cs,WindowsObjectPicker.cs. - Clipboard/DnD —
Utils/Shell/ShellDataObject.cs, 36 files usingDataPackage/OLE. - Startup —
Program.cs(WinAppSDKAppInstancesingle-instance redirection,LocalSettings),App.xaml.cs.
Directory watching is implemented separately in five places (ShellViewModel, SidebarViewModel,
QuickAccessWidgetViewModel, QuickAccessManager, LibraryManager). Unify these behind one interface.
| Area | File(s) | Plan |
|---|---|---|
| DirectComposition / child HWND hosting | Data/Items/WindowEx.cs, ShellPreviewViewModel.cs |
Windows-only; exclude on Linux |
| Mica/Acrylic backdrop | Helpers/UI/AppSystemBackdrop.cs |
No-op on Linux |
| Custom title bar / drag regions | MainPage.xaml.cs, MainWindow.xaml.cs, DragZoneHelper.cs |
Use Uno's extend-into-titlebar support where available; fall back to system decorations |
| InteractionTracker swipe nav | Helpers/Navigation/NavigationInteractionTracker.cs |
Make optional, disabled on Linux at first |
| Composition animations | ShellPanesPage.xaml.cs, StickyHeaderBehavior.cs |
Check on Uno Skia; degrade gracefully |
| Win2D | StatusCenter/SpeedGraph.cs, FontFileHelper.cs |
Rewrite with SkiaSharp (or Path geometry) |
| TabView tear-out | UserControls/TabBar/TabBar.xaml.cs |
Disable tear-out on Linux at first |
| WebView2 / MediaPlayerElement | FilePreviews/HtmlPreview, MediaPreview |
Uno WebView (WebKitGTK) / Uno MediaPlayer (libVLC), or defer |
| ColorCode.WinUI | code preview | Shim on ColorCode.Core |
| Tray icon | Utils/Taskbar/SystemTrayIcon*.cs |
StatusNotifierItem over D-Bus (later) |
InputKeyboardSource |
16 files incl. ViewModels | Verify Uno support; otherwise wrap behind IKeyboardStateService |
Files.Shared (net10.0) — unchanged
Files.Core.Storage (net10.0) — unchanged (OwlCore contracts)
Files.Platform.Abstractions (net10.0) — NEW: interfaces + capability flags, no implementations
Files.Platform.Linux (net10.0) — NEW: Linux implementations
Files.App.Storage — split: portable parts → net10.0; Windows/ retained for later removal
Files.App.Controls — multi-target: net10.0-windows (WinAppSDK) + net10.0-desktop (Uno)
Files.App — multi-target: net10.0-windows (WinAppSDK) + net10.0-desktop (Uno Skia)
Backend selection in AppLifecycleHelper via services.AddWindowsPlatform() / services.AddLinuxPlatform(), each
defined in its own extension file so workstreams never collide in AppLifecycleHelper.cs.
| Interface | Wraps today | Linux implementation |
|---|---|---|
IFileSystemEnumerator |
Win32StorageEnumerator, FindFirstFileEx in ShellViewModel |
FileSystemEnumerable + statx via File.GetUnixFileMode / Mono.Unix |
IFolderWatcherFactory |
ReadDirectoryChangesW, WindowsFolderChangeWatcher, RecycleBinWatcher |
FileSystemWatcher (inotify) |
IFileOperationsService |
IFilesystemOperations, ShellFilesystemOperations, ShellFileOperations2, WindowsBulkOperations |
Managed copy/move with progress, conflict resolution, cancellation; rename(2) fast path |
IFileAttributesService |
attribute/compression/size-on-disk/ADS methods of Win32Helper.Storage |
stat, hidden = dot-prefix, xattrs |
ITrashService |
IStorageTrashBinService |
freedesktop Trash spec ($XDG_DATA_HOME/Trash, per-mount .Trash-$uid) |
IThumbnailService / IIconProvider |
FileThumbnailHelper, StorageItemIconHelpers, ImagingService, icon extraction |
XDG thumbnail cache + generation (SkiaSharp), freedesktop icon theme + shared-mime-info |
IShellContextMenuService |
ContextMenu, OpenWithMenu, ShellNewMenuHelper |
Open With from .desktop/mimeapps.list; New from ~/Templates; no 3rd-party extensions |
ILauncherService |
Launcher.*, LaunchHelper, FileAssociationHelpers, InvokeWin32ComponentAsync |
xdg-open, .desktop Exec parsing, gio launch |
IClipboardService |
Clipboard/DataPackage, ShellDataObject |
text/uri-list + x-special/gnome-copied-files (+ KDE cut marker) |
IDriveService |
IRemovableDrivesService, DriveHelpers, WindowsDriveManager, format/label |
UDisks2 over D-Bus (Tmds.DBus), /proc/self/mountinfo fallback |
INetworkService |
StorageNetworkService (WNet) |
GVfs mounts (gio mount), list /run/user/$uid/gvfs |
ICloudDetector |
CloudDrivesDetector (registry/SyncRoot) |
Scan known folders (Dropbox, Nextcloud, OneDrive-abraunegg, rclone, GVfs google-drive) |
ISettingsStore / IAppDataPaths |
ApplicationData.Current.*, RegistryHelpers, WindowsIniService |
JSON in $XDG_CONFIG_HOME/files/, cache in $XDG_CACHE_HOME/files/ |
IElevationService |
runas, RunPowershellCommandAsync |
pkexec helper |
IRecentItemsService |
WindowsRecentItemsService |
recently-used.xbel |
IQuickAccessService |
WindowsQuickAccessService, PinnedFoldersManager |
GTK bookmarks + xdg-user-dirs |
ISecurityService |
StorageSecurityService, WindowsObjectPicker |
POSIX owner/group/mode editor (+ optional POSIX ACLs) |
IArchiveService |
StorageArchiveService (SevenZipSharp + bundled 7z*.dll) |
SharpCompress (managed), or system 7z CLI for 7z write |
IFileTagsStore |
ADS :files stream + registry |
user.xdg.tags xattr + existing SQLite DB |
ISingleInstanceService |
WinAppSDK AppInstance in Program.cs |
Unix domain socket in $XDG_RUNTIME_DIR |
IShellIntegration |
jump list, start menu, taskbar, tray, wallpaper | No-op, except wallpaper (gsettings/portal) and tray (SNI, later) |
IPlatformCapabilities |
— | Flags used by UI to hide unsupported features |
Each phase lists its exit criteria. Phases 2 and 3 overlap heavily once Phase 1 has landed.
- Install the .NET SDK on the Linux dev box (
sudo pacman -S dotnet-sdk). Done whendotnet --list-sdksshows 10.x. - Baseline verified on Linux (SDK 10.0.112, 2026-10-04): Files.Shared, Files.Core.Storage and
Files.Core.SourceGenerator build with 0 errors/warnings, including
-r linux-x64;Files.Apprestores with-p:EnableWindowsTargeting=true. Thewin-*RIDs are therefore not a blocker; clean them up only when the neutral projects are packaged for Linux. - Spike A (Uno): a throwaway Uno Skia desktop app on net10.0 that hosts
Files.App.Controls(Omnibar, Sidebar, BreadcrumbBar, Toolbar) and onex:Bind-heavy page. Confirm on X11 and Wayland. Record API gaps (InteractionTracker, InputKeyboardSource, AppWindow title bar, TabView). - Spike B (WinAppSDK ↔ Uno coexistence): confirm
Files.App.Controlscan multi-targetnet10.0-windows10.0.26100.0+net10.0-desktopwith CommunityToolkit 8.x. - Add a Linux CI job (
ubuntu-latest): build neutral projects + run new unit tests. - Exit: neutral projects build in Linux CI; spike report written to
docs/linux-port/spikes.md; Uno vs Avalonia decision confirmed.
- Create
Files.Platform.Abstractions(interfaces from §4.1 +IPlatformCapabilities), the former Windows platform project,Files.Platform.Linux(empty), and atests/Files.Platform.Tests(MSTest, net10.0) project. Add them toFiles.slnx. - Add
AddWindowsPlatform()/AddLinuxPlatform()DI entry points; callAddWindowsPlatform()fromAppLifecycleHelper. - Exit: Windows build and behaviour unchanged; new projects build on Linux.
Each workstream: define its interface methods from real call sites, implement them in the former Windows platform project by moving or wrapping existing code, then update call sites to use the interface. No behaviour change on Windows.
- Exit per workstream: zero direct
PInvoke./Windows.Storage/Registry calls remaining in the workstream's owned consumer files (checked withrg --no-ignore); Windows CI green.
- Implement each interface in
Files.Platform.Linuxwith unit tests intests/Files.Platform.Tests(temp-dir based, run in Linux CI). Order by dependency: settings/paths → enumerator → watcher → file ops → trash → launcher → attributes → thumbnails/icons → drives → clipboard → archives → tags → quick access/recent → network/cloud → elevation → security. - Exit: each interface has a Linux implementation with tests passing on Linux CI.
- Migrate the 61 consumers of
BaseStorageFile/BaseStorageFolder/IStorageItemonto OwlCore storables (Files.Core.Storage) + the Phase 2 interfaces.ShellViewModelfirst, then properties, search, archives (Zip*), FTP, virtual folders. - Kept on a single owner (or a strictly serialized queue), because almost everything touches
ShellViewModel. - Exit:
Utils/Storage/StorageItems/*is no longer referenced by the Linux build. Superseded by the Revision 3 exit below, which is met. The legacy items (FtpStorage*,SystemStorage*,ZipStorageFolder.IsZipPath,BaseStorage*) still compile on Linux behindLINUX-TODO(storage)and remain follow-up work.
The two are one project: the legacy items (Zip*, NativeStorageFile, VirtualStorageItem, Shell*, SystemStorageFolder) call
Win32 themselves, so compat can only go once they are gone, and FilesWin32Compat=false is the proof.
Inventory (from d532ee2, lower bounds): legacy layer 24 files / 5.7k lines; 57 consumer files (~330 refs) to migrate;
Windows.Storage.IStorageItem 111 refs in 25 files; DangerousGet*Async 44 calls. Compat-only code: 41 files / 9k lines in
Files.App, 26 files / 2.5k lines in Files.App.Storage. Compat off breaks ~109 files / 615 lines outside #if WINDOWS;
public contracts expose CsWin32 types (SHOW_WINDOW_CMD, WIN32_ERROR, IWindowsStorable); Linux fallbacks live inside
compat-only files (Win32Helper.Storage.cs etc.) and must move first. Live Linux hazards: StorageHelpers.ToStorageItem (fixed in #45),
CachedSizeProvider/FileSizeCalculator (FindFirstFileEx), IsZipPath assuming \ (browsing inside archives broken).
Design: path-first (IFileSystemEnumerator → ListedItem, IFileOperationsService); OwlCore storables only where a
hierarchy/stream is needed (archives, FTP, Home, path resolution, preview streams); no WinRT IStorageItem on Linux. Windows
code moves byte-identical into *.Windows.cs (excluded on desktop by one glob) or small #if WINDOWS blocks. No new Win32 shims.
Add first, delete last; default build stays green. Contracts (P4-0, then frozen): IStorableResolver/IStorableRoute,
IStorageItemWithPath.Storable (+ StorableWithPath), ShowWindowCommand, FileSecurityResult; later
IArchiveService.OpenEntryAsync, IFileStatService.TryGetFileId (dev:ino replaces FRN), IFileAttributesService,
IArchivePasswordPrompt. DI via services.AddStorables().
Work packages (one owner per file; shared files append-only; only P4-0/P4-Z touch the compat switch):
| WP | Days | Scope | Depends | Model |
|---|---|---|---|---|
| P4-0 | 1–2 | Contracts, local route, *.Windows.cs glob, compat-off check script + baseline |
– | strong |
| P4-K | 1–2 | Live hazards: size providers, FileSizeCalculator, layout prefs, tags, IFileStatService |
0 | mid |
| P4-A | 2–3 | Archives: read-only ArchiveFolder, OpenEntryAsync, Decompress actions, / in IsZipPath |
0 | strong |
| P4-B | 2–3 | Operations + history + status center; Windows ops → Windows-only | 0 | strong |
| P4-C | 2–3 | Resolution, enumerators, search; DangerousGet* → resolver |
0 | mid + strong review |
| P4-D | 1 | FTP onto Files.App.Storage/Ftp |
0 | mid |
| P4-E | 2–3 | ShellViewModel (single owner) + ShellViewModel.Windows.cs |
C, A | strong |
| P4-F | 2–3 | Properties + security; IFileAttributesService |
0 | mid |
| P4-G | 2 | Previews (keep #43/#44 hardening), ListedItem, layouts, toolbar, Git, helpers |
0 | mid |
| P4-H | 2–3 | Actions, navigation, factories, libraries, shortcuts; capability-hidden commands | 0 | mid |
| P4-I | 1–2 | Window chrome, settings UI, tab bar, hotkeys | 0 | cheap/mid |
| P4-J | 2–3 | Home/widgets/sidebar/drives/cloud; portable widget contract | 0 | mid + strong contract |
| P4-Z | 1–2 | Flip FilesWin32Compat=false, fix leftovers, delete #if WINDOWS IStorageItem members, CI job blocking |
all | strong |
Order: P4-0 → wave 1a (K, A, B, C, H, I) → wave 1b (F, D, G, J) → E → Z. Critical path ≈ 10 working days.
Status (2026-10-05): all 14 packages are merged or in review; P4-E (#73) and P4-Z close the phase. Compat off by default, 0 errors, headless smoke
test passed (browse, copy/move, trash/restore, browse into a zip, Properties, search, live updates), and the Linux CI compat-off build is blocking.
Gate after every merge: normal desktop build passes; -p:FilesWin32Compat=false error count ratchets down vs
docs/linux-port/compat-off-baseline.txt; rg --no-ignore 'BaseStorage|StorageItems\.|Windows\.Win32|PInvoke\.|Win32Helper\.' on the WP's
files (outside *.Windows.cs) → 0. Exit: compat off by default, 0 errors, headless smoke run passes, CI compat-off job blocking.
- 5a: Multi-target
Files.App.Controls(Windows + Uno). - 5b: Multi-target
Files.App; exclude Windows-only files on Linux withCompile Remove+*.Windows.cs/*.Linux.csnaming convention rather than scattering#if. - 5c: Resources: load
.reswon Uno (Uno supports.reswvia its resource generator; verify) — the 1,332 lookups are centralised inResourceHelpers/StringExtensions, so only those need changing. - 5d: Startup: new Linux
Program/host usingISingleInstanceServiceand argv parsing; replaceLocalSettingsusage inProgram.cs,AdvancedViewModel,TabBar,WindowEx,ActiveSessionTracker. - 5e: UI blockers from §3.4: SpeedGraph on SkiaSharp, backdrop/title-bar fallbacks, TabView tear-out off, InteractionTracker optional, previews degraded.
- 5f: Hide unsupported features via
IPlatformCapabilities(Security tab, Libraries, Signatures, Compatibility, shortcuts→.desktop, etc.). - Exit:
dotnet run -f net10.0-desktopopens Files on Linux, navigates, lists, copies/moves/deletes/trashes, opens files with default apps, renders thumbnails.
org.freedesktop.FileManager1D-Bus service (ShowFolders/ShowItems/ShowItemProperties): the Linux equivalent oflegacy Windows launcher..desktopentry,inode/directoryMIME association, AppStream metainfo, icons.- Packages: Flatpak (primary; needs
--filesystem=host,org.freedesktop.Flatpakspawn for launching host apps carefully considered), AppImage, AURPKGBUILD. - Optional: StatusNotifierItem tray,
xdg-desktop-portalFileChooser backend (replaces Open/SaveDialog — XL, defer). - Exit: installable package; Files can be set as the default file manager.
- Linux UI smoke tests (Uno runtime tests or a lightweight harness), performance on 100k-entry folders, HiDPI, Wayland vs X11, GNOME/KDE themes, localisation, accessibility (AT-SPI via Uno).
| Windows feature | Linux decision |
|---|---|
| Shell preview handlers (COM, DComp hosting) | Drop; rely on built-in previews |
| 3rd-party shell context-menu extensions | Drop; Open With + Templates + custom actions only |
Libraries (.library-ms) |
Drop |
| Authenticode signatures tab | Drop |
| Compatibility tab | Drop |
| NTFS ACL Security tab / object picker | Replace with POSIX owner/group/permissions editor |
.lnk / .url shortcuts |
Read-only support optional; create symlinks / .desktop Link entries |
| Jump lists, Start-menu pinning, taskbar progress | Drop (taskbar progress could use Unity LauncherEntry D-Bus later) |
| legacy Windows COM server, BackgroundTasks, MSIX update task | Drop |
| Open/Save dialog replacement (C++ COM) | Defer; portal backend in Phase 6 |
| WSL distro listing, PowerShell helpers | Drop |
| Format drive dialog | Replace with gnome-disks launch if present, else hide |
| Store/sideload updater | Drop; updates come from the package manager |
| Role | Model | Responsibilities |
|---|---|---|
| Planner / architect / reviewer | Opus 5.5 | Phase gates, interface design, splitting work packages, reviewing every PR diff, resolving cross-workstream conflicts |
| Implementer | Sonnet 5.5 | One work package each: code changes in an isolated git worktree, unit tests |
| Runner | Haiku 4.5 | Builds, test runs, rg inventories, git sync/merge, CI log triage. No source edits |
- Opus writes work packages (WP) for the wave: goal, owned files/folders, interface contract, acceptance checks, explicit "do not touch" list.
- Sonnet agents run one per WP, each in its own git worktree on branch
linux/<phase>-<wp>. - Haiku runs the build/test matrix for each branch:
dotnet buildon Linux for neutral and Linux projects, unit tests, and anrg --no-ignorecoupling check against the WP's owned files. It reports pass/fail plus a capped log. - Opus reviews the diff (correctness, CRLF,
.editorconfig, AOT rules, no scope creep), then merges intomainin dependency order. - Review upstream fixes selectively and cherry-pick with attribution. No weekly upstream merges or sync PRs.
Windows builds can't run locally on Linux. Validate them through GitHub Actions on windows-2025-vs2026, with a
Haiku agent polling gh run results.
Rule: a file belongs to exactly one workstream per wave. Two files are hot and must be serialized:
ShellViewModel.cs: W1, then W8, then Phase 4.Actions/**: only W5 edits it.
| WS | Scope | Owns | Depends on |
|---|---|---|---|
| W1 | Enumeration + watchers | Utils/Storage/Enumerators, watcher parts of ShellViewModel, SidebarViewModel, QuickAccessManager, LibraryManager |
P1 |
| W2 | File operations | Utils/Storage/Operations, Utils/Shell/ShellFileOperations2.cs, WindowsBulkOperations* |
P1 |
| W3 | Attributes, properties, security | Helpers/Win32/Win32Helper.Storage.cs, ViewModels/Properties/**, StorageSecurityService, Utils/Signatures |
P1 |
| W4 | Shell UX | Utils/Shell/** (except ShellFileOperations2, LaunchHelper), ShellPreviewViewModel, Services/PreviewPopupProviders |
P1 |
| W5 | Launcher, clipboard, elevation | Helpers/Navigation, Utils/Shell/LaunchHelper.cs, Win32Helper.Process.cs, Actions/** |
P1 |
| W6 | Drives, network, cloud, trash | Services/Storage/*{Devices,Network,TrashBin}*, Utils/Cloud, DriveHelpers, MtpHelpers |
P1 |
| W7 | Settings store, app data, registry, shell integration | Services/Settings, Services/Windows/*, Utils/Taskbar, RegistryHelpers, ApplicationData call sites |
P1 |
| W8 | Thumbnails, icons, imaging | FileThumbnailHelper, StorageItemIconHelpers, ImagingService, IconCacheService, ListedItem image parts |
W1 |
| W9.x | Linux implementations | New files only, in Files.Platform.Linux/<Area>/ + tests |
matching W1–W8 interface |
| W10 | Legacy storage removal (Phase 4) | Utils/Storage/StorageItems/**, ShellViewModel |
W1, W2, W8 |
| U1 | Uno: Controls | src/Files.App.Controls/** |
Phase 0 spikes |
| U2 | Uno: App head, startup, resources | Program.cs, App.xaml.cs, csproj, ResourceHelpers |
U1, W7 |
| U3 | Uno: UI blockers | files in §3.4 | U2 |
Suggested concurrency: 4–6 Sonnet agents at once. W1, W2, W5, W6, W7 and U1 can run fully in parallel right after Phase 1.
WP-ID: W2-a
Goal: Introduce IFileOperationsService; Windows impl wraps ShellFilesystemOperations
Owns: src/Files.App/Utils/Storage/Operations/**, the former Windows file-operations backend
Must not edit: ShellViewModel.cs, Actions/**, AppLifecycleHelper.cs
Contract: (interface signature pasted here by Opus)
Acceptance: - Windows CI green
- rg --no-ignore 'PInvoke\.|ShellFileOperations2' on owned consumer files → 0 hits
- CRLF preserved, no new DllImport/ComImport
Runner checks: dotnet build src/Files.Platform.Abstractions; dotnet test tests/Files.Platform.Tests
| Risk | Impact | Mitigation |
|---|---|---|
| Uno gaps (InteractionTracker, title bar, TabView tear-out, InputKeyboardSource) | UI features missing | Phase 0 spike; degrade behind capability flags |
Upstream churn in hot files (ShellViewModel, layout pages) |
Painful merges | Selective, reviewed cherry-picks; clear platform boundaries |
| Windows build can't be verified locally | Silent Windows breakage | Mandatory Windows CI on every linux/* PR |
| File-operation correctness (data loss) | Critical | Extensive temp-dir unit tests; cross-device move, conflict, cancel, permission-denied, symlink cases |
| Performance of managed enumeration / thumbnails | Sluggish large folders | Benchmarks against 100k entries; batch stat; async thumbnail queue with XDG cache |
| Flatpak sandbox vs file manager needs | Limited access | --filesystem=host; document; AppImage/AUR as alternatives |
| Native AOT / trimming with Uno + new code | Build failures | Keep AOT analyzers on; follow CLAUDE.md reflection rules |
Localisation pipeline (.resw/MRT) |
Missing strings | Centralised loader swap in Phase 5c |
Install the SDK(done; neutral projects build on Linux).- Phase 0: Linux CI job (one Sonnet WP, Haiku verifies).
- Run Spikes A and B (Sonnet in worktrees, Opus reviews). Confirm the Uno decision.
- Phase 1 skeleton (one Sonnet WP, serial).
- Launch the Phase 2 wave: W1, W2, W5, W6, W7, U1 in parallel.