Design: design_docs/DESIGN_SHELL_INTEGRATION.md.
behavior.shell_integration = falsegates local sessions only; agents always create the control server (they can't see host preferences). Propagate the flag at agent spawn (env for bootstrap transports likeNEWT_AGENT_MODE, an arg for direct spawns) if disabling remotely turns out to matter.newt cp --wait(long-poll an operations endpoint for completion, exit code from the operation result).- Per-terminal pane affinity (
NEWT_TERMINALis already injected),--jsonoutput, user-command invocation by title.
Design: design_docs/DESIGN_AGENT_VFS_MOUNTS.md, design_docs/DESIGN_ENRICHERS_AND_RESOURCES.md.
- Hairpin
get_property_sheet— the one path-targetedFilesystemverb still not diverted. Gated onRemoteVfsDescriptor::has_extended_properties()(false today, andRemoteVfsdoesn't remote the verb), i.e. it needs the "local property sheets in a remote session" feature, not just a hairpin arm. - WSL is the one transport still bootstrapped non-login, so its agent never sources
~/.profileand starts with a barerPATHthan awsl.exeshell would. It can't just take-lclike SSH:WslLaunchexecs the agent directly with no handshake, so RPC starts on the first byte of stdout and any profile that prints a banner would corrupt the stream. Give WSL the sameNEWT:handshake asSpawnSpec::Bootstrap(which skips non-NEWT:lines precisely to absorb login-shell chatter), then enablelogin_shellfor it. - Host-key prompts and "are you sure you want to add fingerprint" flows for SSH ride the existing askpass channel; verify the same UX with
StrictHostKeyChecking=accept-newsetups. - Agent-VFS pane mounts aren't enriched (enrichment is session-level; the sub-agent's
--serve-vfsmode has no enricher dispatcher). Needs per-VFS enricher routing, the wayVfsverbs remote, if it proves wanted. Vfs-level remoting of the property-sheet verbs (API_VFS_*constants +RemoteVfs/VfsDispatcherarms) — deferred untilLocalVfsgrows a sheet (xattrs); nothing crosses that layer today. (Design:design_docs/DESIGN_VFS_PROPERTY_SHEETS.md.)
Design: design_docs/DESIGN_PLATFORM_LOCATIONS.md. Doctrine (platform mounts → LocalVfs, discovery/enrichment only, no native SMB/NFS/FTP clients) is settled. Volumes are classified and listed in the VFS selector, queried when it opens (no change events).
- Eject/unmount a volume from the VFS selector (×), dispatched by what mounted it:
gio mount -u(gvfs),udisksctl unmount(media),diskutil unmount(macOS). - Volumes of agent mounts (SSH, containers): the sub-agent has no Hot Paths provider.
- Breadcrumb/header enrichment via a pushed location-prefix → label map (open question whether v1).
- Per-profile start directory (
start_directoryon spawn-style connection profiles): explicit, so it beats the remembered location, WinSCP-style. - Record sessions when the OS ends the process on Windows (
WM_QUERYENDSESSION/WM_ENDSESSIONat logoff/shutdown) and Linux (SIGTERM from the session manager). Today only macOS'sapplicationShouldTerminate:path records; elsewhere a logoff loses whatever changed since each window last closed.
HotPaths.module.scssdeleteBtn hover keeps anopacity !important; HistoryNavigator and SortMenu each keep two!importants fighting Menu.module'sdata-highlightedstyling — all need a structural fix in Menu.module.scss to remove.
- A platform token layer (
:root[data-platform=…]) over the shared design, with components never branching on platform: the system UI font and size, the system accent colour (AccentColorin WebKit on macOS,UISettingson Windows, the appearance portal'saccent-coloron GNOME/KDE), GNOME's flat borderless buttons (--color-control-*), per-platform control heights. Window chrome is the one structural difference: a unified title bar on macOS.
- Review the file-list icons as a whole. Today a name maps through the seti theme's
mapping.json(src/lib/fileIcons.ts), and anything unmapped gets the plain text-lines glyph — executables, installers and app bundles included. Known gaps:.exe/.msi/.com/.cmdare unmapped though seti'swindowsglyph (used for.bat) fits; the font'sappleglyph (U+E002) is unused and suits app bundles; a package (Annotation::Package) shows its name's file glyph, which reads oddly for.app; an extensionless Unix executable has no icon of its own — seti has none, nerd-symbols hascod-file_binary/cod-terminalbut in an outline style next to seti's filled ones; installers and images (.dmg,.pkg,.deb,.rpm,.apk) are unmapped. Decide one consistent source (seti only, or seti plus a matching subset of nerd-symbols), whether the lookup takes the mode (execute bits) and package-ness besides the name, and what a non-.apppackage (.rtfd, a photo library) shows. The drag ghost (getFileIconCharinPane.tsx) should follow whatever the list does.
- Drag-out for non-host-local sources (S3/SFTP/remote sessions) needs materialization: either download-to-tempdir before the native drag starts (reuse the
download_and_openpattern), or per-platform file-promise APIs (NSFilePromiseProvider / CFSTR_FILEDESCRIPTOR / XDS) — no cross-platform crate wraps those today.
- Alternate view (Alt+F3, reserved): F3, but always opening in text/hex whatever the file's type. Quick View's Mod+Shift+F3 is provisional.
- Editor (F4) is UTF-8 only (other files open read-only). Reuse the viewer's encoding catalogue and sniffer (
viewer/encoding.rs) on open, re-encode on save with the same encoding, and give the editor its own Encoding menu. WriteOptions::replaceon local Windows:ReplaceFileWkeeps attributes, ACLs and alternate data streams, and refuses where it can't (hard links viaGetFileInformationByHandle's link count). Editor saves write in place there until then.- Prev/next file navigation from the viewer window (
viewer_next_file/viewer_prev_file, defaultn/p, arrows navigating at fit zoom in image mode). The keybinding side is ready (viewer commands live in the central registry); what remains is the session side — ask MainWindowState for the pane-order neighbor of the same class and re-target the window, generic across viewer modes. - Decode-in-Rust fallback for formats the webview can't render (TIFF on Windows, HEIC off macOS, RAW via embedded-preview extraction). Big surface — deliberately deferred.
- SVG in image mode is degenerate (no natural size → transform-based zoom rasterizes blurry); a vector-aware path would size the
<img>element instead of transforming it. - Downscale quality: composited CSS transforms sample bilinearly with no mip chain on both WebKit and WebView2. If real-world images shimmer at fit zoom, swap in a pre-downscaled rendition below 100% (static images only).
Design: design_docs/DESIGN_7Z_VFS.md (newt) and
~/src/iluvatar/design_docs/DESIGN_STREAM_ENGINE.md (iluvatar).
- Implement
Vfs::revalidatefor the archive VFSes (zip, tar, 7z, compressed files). The trait is wired through to the navigation layer (called when a pane crosses into a VFS that advertisesVfsDescriptor::can_revalidate); the archive impl should stat the origin file's mtime against the value captured at mount time and rebuild the index in place if it drifted, returningRefreshed. Mount identity (VfsId,mount_meta,origin) must be preserved so history entries remain valid; flipcan_revalidateto true on the descriptors. - Test 7z archives from other writers. The corpus is written by 7-Zip 26.03 on macOS (
sevenz/fixtures/regenerate.py; zstd via py7zr, which 7-Zip cannot write); 7-Zip on Windows (attribute conventions,\names, NTFS times without the unix extension), p7zip, Keka and WinRAR's 7z are untested. - PPMd folders: port ppmd-rust's Ppmd7 decoder (CC0/MIT-0) to the push model; no checkpoints (the model is the state), so a PPMd folder decodes from its start like ZIP's cursor path.
- Check that the pane surfaces the "Decoding · folder n of m" progress during a read, not only during mounting: a cold read deep into a huge solid block decodes forward once (about 1.5 s per 100 MB of packed data in a release build) before the first byte comes back.
- Split volumes (
.7z.001) and SFX stubs: volumes need sibling reads through the upstream VFS. - 7z writer: a BCJ x86 stage for executables (liblzma's filter chain has it; 7-Zip puts
.exe/.dllthrough BCJ2, which we cannot write), and header compression/encryption (-mhe). - Spool quota and memory threshold as preferences; today
SpoolConfig::default()(32 MiB in memory, unlimited disk) is wired at session start. - Folder index memory is bounded per folder (256 MiB budget), not per mount; a mount over many huge solid folders can add up. An LRU across folders would cap it.
- VAT/virtual and sparable partition maps (packet-written CD-RW/DVD±RW dumps) — currently a clean "unsupported" error.
.imgsupport via content sniffing: the extension is ambiguous (raw disk images with partition tables vs raw ISO9660/UDF), so claiming it needs a cheap probe before mount rather than an extension match.- El Torito boot catalog: expose boot images as synthetic entries at the mount root.
Design: design_docs/DESIGN_EXCLUSIVE_WRITES.md.
- SFTP answers
NotSupportedtocreate_newandrename_no_replace, so copies and moves to SFTP still stat every destination.create_newisSSH_FXF_EXCL(the refusal is a bareSSH_FX_FAILURE, classified by an lstat, asrenamealready does). The no-replace rename needs the plain v3SSH_FXP_RENAME, whichopenssh-sftp-client'sFs::renamenever sends to a server offeringposix-rename; its low-level write end is private, so this wants an upstream change. - Custom S3 endpoints never offer
create_new. Verify which stores honourIf-None-Matchon PutObject, CompleteMultipartUpload and CopyObject (MinIO, R2, Ceph RGW, …) and allow them. - Confirm on Windows (derived from MS-FSA, not run):
CREATE_NEWover a directory fails as access denied, classified toAlreadyExistsbycreate_new_refusal;rename_no_replaceover a file and a directory, and a case-only rename;copy_withinundercreate_new(reservation, thenCopyFileExWover it).
- Gated on versioned releases rather than nightly snapshots: an AppStream metainfo file (
org.newt-fm.newt.metainfo.xml, installed besidenewt.desktop), which wants a real<releases>history. A security reporting policy belongs to the same milestone.
- Live announcements: navigation finishing, operations completing or failing, selection counts, "Loading…" states — one polite live region fed from the existing flows, rather than per-component
aria-live. - Screen-reader modes for the terminal (xterm.js
screenReaderMode) and editor (MonacoaccessibilitySupport, whoseautocan't detect a reader inside a webview): detect a running reader natively (NSWorkspace.isVoiceOverEnabled,SPI_GETSCREENREADER,org.a11y.Status.ScreenReaderEnabledon D-Bus), publish it in state, and let a preference override it. - Keyboard gaps: Settings' category sidebar is click-only (tabs have roles but no key handling); the key-capture field's clear (×) button acts on mousedown only, and Enter/Space on it is captured as a key.
- Regression check: the scene harness can assert ARIA snapshots (e.g. the focused file row is the list's active descendant) and run axe-core over every scene.
-
TerminalHandleis minted per session (Local::new()persession.rs), so every window's first terminal is handle 0. Nothing routes by handle alone today (terminal output travels on each session's own IPC channel), but the next thing that does will cross-talk. Kill the class rather than the instance: either a process-wide counter, or makeTerminalHandlecarry its session. See "Window-targeted events" in CLAUDE.md. -
Local macOS is the one place the app's own
PATHis patched by hand ([environment] extra_path) rather than inherited: a Finder-launched.apphas no login shell above it. The visible seam: the terminal gets-land so has the user's fullPATH, while a Newt-spawned command gets launchd's plusextra_path, so a tool can work when typed and fail as a command. The cure is what VS Code does — probe once at startup ($SHELL -ilc, marker-delimited JSON on stdout so profile chatter can't corrupt it, bounded by a timeout since a profile can block forever on a prompt) and thread the result as a base env rather thanset_var(edition 2024, andshell.rsdeliberately doesn't mutate our own environment). Not worth it until the manual patching actually bites. -
Auto-remount VFSes (including dead agent mounts) when navigating into a dead history entry. Today such entries render correctly (cached display path, "unmounted" badge, skipped during overlay stepping) but jumping to one fails. Needs mount metadata stored on the history entry so the navigation can transparently re-establish the connection.
-
Bump
specta/specta-typescript/tauri-spectapast rc.22 / 0.0.9 / rc.21 once a release includes the fix for specta-rs/specta#498: rc.25 overflows the stack exportingserde_json::Value. The port itself is small —Type::inline/referencebecomedefinition(&mut Types)(specta_as!,common::Error, the wirePathBuf),TypeCollectionbecomesTypesin theFunctionArgimpls, container#[specta(rename)]becomes#[serde(rename)],FileChunk.dataneeds#[specta(type = Vec<u8>)]beside itsserde_bytes, andBigIntExportBehavior::Numberbecomes the builder'sdangerously_cast_bigints_to_number().
Release engineering:
- One version source (
src-tauri/Cargo.toml,package.jsonandtauri.conf.jsoneach say 0.1.0 independently), a tag-driven release workflow, and a mapping onto deb (1.0.0~rc.1), rpm (no-) and MSI (numeric only) versions. Same-version snapshots don't upgrade under apt/dnf. - Sign Windows builds (MSI,
newt.exe, andnewt-agent.exe, which UAC shows as "Unknown publisher" for elevated sessions). - An update check against the
downloads/latest.jsonCI already publishes. publishrewriteslatest.jsonfrom the current run alone, so a lean run drops the Intel Mac, ARM Windows and ARM Linux downloads a full run published. Merge instead.- CI on
macos-latestandwindows-latest(clippy + tests); today only Linux builds on push. Pin the toolchain (rust-toolchain.toml), andlibc = "*"insrc-tauri/Cargo.toml. - macOS: fail the release when signing secrets are missing, verify with
codesign --verify --deep/spctl/stapler validate, setminimumSystemVersion(the frontend usescolor-mix(), Safari 16.2, while Vite targetssafari13). Trash goes through Finder AppleScript (trash-rsDeleteMethod::Finder) under the hardened runtime withoutNSAppleEventsUsageDescription; considerNsFileManager. Guide users to Full Disk Access on TCC-denied paths. - The remote agent cache (
scripts/bootstrap.sh,newt-agent-${NEWT_HASH}) isn't keyed by triple, so a home shared between architectures execs the wrong agent forever. The cleanup loop also deletes other versions' agents, and the/tmp/newt-$(id -u)fallback (and/tmp/newtinagent_cache_dir()) accepts a directory another user created first. A raw-uploadhead -cshort read leaves a truncated agent that is reused. - Elevated sessions from the AppImage: root can't exec the agent from the FUSE mount.
NEWT_AGENT_DIRalso leaks into terminal shells. - Settle identifiers before 1.0: keychain service
com.newt.credentialsvsorg.newt-fm.newt,newt.desktopvs reverse-DNS. - Linux packages depend on libappindicator, which the binary doesn't link; no CI step test-installs a package.
cargo deny(licences, advisories; bincode 1.3 is unmaintained), and WiX 6 → 7 wording innewt.wxs/build-msi.ps1.- On Windows,
--help/--versionprint nothing (GUI subsystem), the MSI doesn't add to PATH and is per-machine only. cargo tauri buildfrom source bundles the 0-byte stub agents frombuild.rswithout complaint;agent_hashreads ~100 MB of agents with blocking I/O on every connect.- Write supported OS versions and Install/Update/Troubleshooting/Uninstall into FEATURE_DUMP for the manual.
Correctness and UX:
- File clipboard: Mod+C/Mod+V are path-text only, and paste after copying in Explorer/Finder errors or navigates to a bare name.
- Files opened externally from remote/archive VFSes are temp copies never uploaded back (edits lost silently) and never deleted; a failed launch only logs.
- Natural, locale-aware name sort (
IMG_10sorts beforeIMG_2). - Toggle-selection key is
Helpon macOS (absent on current keyboards) and hardcoded inPane.tsx; make it a rebindable command. - Quick search: Shift/AltGr letters can't start it (AZERTY digits, uppercase names), and nothing guards IME composition (
isComposing), so committing a CJK candidate with Enter opens the focused file. - FIFOs and device files are opened as regular files: copy and view hang (or copy
/dev/zeroforever). - S3
CopySourceisn't URL-encoded (s3/mod.rs,s3/properties.rs): keys with%,+or non-ASCII copy the wrong object, and a rename then deletes the source. - Case-insensitive destinations:
Makefileandmakefilefrom a case-sensitive source collide mid-operation (likewise NFC/NFD and Windows trailing dots); detect before writing. - Pack to Archive can target one of its own sources (
foo.zippacked as zip in place) and, after Overwrite, truncates it to an empty archive; a failed destination stat is treated as absent; a symlinked destination is written through. - Linux trash on a root-owned mount falls back to copy-then-delete into
~/.local/share/Trashwith no progress or cancel. - Delete removes by path after the scan, so a directory swapped for a symlink in between redirects it (CVE-2022-21658 class; matters for elevated sessions).
- Non-UTF-8 file names can't be operated on (lossy wire paths).
- Skipping a file-vs-directory conflict doesn't skip the directory's contents (each child then errors).
- Huge directories: sync commands do O(n) work on the main thread shared by all windows, and a streaming listing is re-cloned and re-sorted every 100 ms under the view-state lock.
- The remote connection log (stderr of an agent run at
RUST_LOG=info, including full operation-request Debug dumps) grows without bound and is re-serialised on every publish. - macOS file watching roots an FSEvents stream at
/per pane per wait. std::env::current_dir().unwrap()increate_local_services(deleted launch directory),bind("localhost:0").unwrap()in the file server.- Two instances clobber
state.jsonand race on a fixedsessions.json.tmp;UpdatePublisher::publishcan emit out of order. - Properties: owner/group by name silently does nothing; Windows has no attribute editor.
- Reconnect is mouse-only,
safeSilent, and its bar uses undefined colour tokens (--foreground,--error-foreground). - Terminal: the keys that escape xterm are hardcoded, so rebinding
focus_panes/toggle_terminal_panelstrands focus; Close/Clear/Select All are menu-only; font, size and scrollback aren't settings. - Window close/quit kills busy terminals without asking;
Mod+Qis Ctrl+Q off macOS. - Copy/Move can't take a relative destination (
../backup/) and Create Directory doesn't createa/b/c; errors there are native popups over the dialog. - Errors carry no path ("Permission denied (os error 13)"); file names aren't bidi-isolated (RLO spoofing).
- Light theme
--color-fg-muted(#929292) is below WCAG AA; undefined tokens--color-hover,--color-bg-hover. - No undo for file operations; no OS notification when a background operation finishes or stops on a prompt; no minimum window size.
- Bookmarks have no Settings tab (the dialog-is-the-file rule); Mod+H doesn't persist.
- Cmd/Ctrl+W doesn't close viewer and editor windows; Alt+F5 is taken by GNOME; F11 is Show Desktop on macOS.
connections.tomlreads as empty on any parse error and is written non-atomically.- Files materialised from downloads/archives get no Mark-of-the-Web or quarantine; the file server sends no
Cache-Control: no-storeandAccess-Control-Allow-Origin: *. - Archive containing a symlink
d -> ~/.sshandd/authorized_keys: check copy-out can't write through the link. - Windows named pipes (elevation, shell control, askpass) use the default DACL, readable by Everyone;
/tmpsocket names are predictable. - Host-side RPC dispatch trusts a compromised remote: clipboard read/write via shell control, askpass prompts with arbitrary text,
API_HOST_FETCH_AGENTtriple path joins, a 4 GiB frame reservation. - SSH/SFTP hosts aren't preceded by
--(-oProxyCommand=from a sharedconnections.toml). - FEATURE_DUMP drift: Open Config File (says built-in editor), Escape (says clears selection), Rename (says full name), terminal paste, Settings categories,
[environment], hidden files, ownership.
- Reveal in Newt / New Newt Window Here from Finder, Explorer, Nautilus, Dolphin; single instance (
design_docs/DESIGN_FILE_MANAGER_INTEGRATION.md) - Compare & synchronize directories
- Custom styling / theming