Repository navigation
feat: ffmpeg is looked for on PATH, then in the Tools Directory, and wtsexporter only there (#1053) - #1996
Conversation
…wtsexporter only there The desktop app names its Tools Directory, ~/message-crate/tools, makes it at start, and passes it to the server it starts with the new `serve --tools-dir`. ffmpeg and ffprobe are looked for on PATH and then in that directory, by the app and by the server alike; a server started by hand finds ffmpeg on PATH or makes no Previews or Thumbnails. wtsexporter is always the app's own copy in the Tools Directory, and a missing copy is reported as missing. Deleted: the ffmpeg directory field in Settings → System, the MESSAGE_CRATE_BIN and WTSEXPORTER variables, the lookups beside the app (the program's directory, lib/ and the parent's lib/), and the Tauri commands probe_ffmpeg_tools and set_ffmpeg_tools_dir with their callers. The new tools_status command feeds one status line each for ffmpeg, ffprobe and wtsexporter in Settings → System → Media, and the Import form's check for missing ffmpeg. Part of #1053 (step 2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
The install line from #1936 (the fork's tag archive, --force, double quotes) meets step 2 of #1053 (wtsexporter found only in the Tools Directory): AGENTS.md keeps the install line and the link into the Tools Directory, the changelog keeps both Upgrading bullets, and the not-found and broken-shim messages point at the Tools Directory with #1936's hints. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
mbeisser1
left a comment
There was a problem hiding this comment.
Review of 547f8f7 (origin/main merged in; the merge review of the conflict resolution found nothing). Findings whose line is outside the diff follow; the rest are line comments.
docs/src/content/docs/docs/user/import-sources/whatsapp.md— Spec · spec —whatsapp.md:27says the app "finds the program when it is on thePATHthe app was started with, or when the environment variableWTSEXPORTERholds the full path to it." After this PR both are false, and a reader who follows the page'spipxstep gets a WhatsApp import that cannot find wtsexporter. Spec: "TheWTSEXPORTERvariable and thePATHsearch for it are deleted." Leaving it until step 5 is a broken instruction, not stale wording: replace the sentence with the Tools Directory and the link step contributing.md gained. Step 5 still removes thepipxstep. (Standards reports the same page as arulebreak.)CHANGELOG.md— Spec · spec —CHANGELOG.md:345(#1936's Upgrading bullet, from main) says to install the fork "with the line on the guide's WhatsApp page". That line is apipxinstall ontoPATH, which this PR's bullet above it says is no longer searched. Add the link into~/message-crate/tools, or point at the #1053 bullet.docs/src/content/docs/docs/user/features/messages/attachments-and-media.md— Spec · spec —attachments-and-media.md:81,features/owner/troubleshooting.md:112andfeatures/messages/import.md:234still send the reader to the deleted ffmpeg directory field, andsystem.md:58now links to attachments-and-media, which describes that field. Spec: "Deleted: the ffmpeg directory field in Settings → System". Step 5 names only the System page and the troubleshooting section, so change these lines here, or file an issue that names them. (Standards reports the same three pages as arulebreak.)CHANGELOG.md— Spec · spec — Step 1 question: creating a lone~/message-crate/toolsis acceptable. The issue fixes where the Tools Directory is and says the programs sit besidedata/, not inside it ("The programs stay where they are."), so steps 2 to 4 do not depend ondata/,staging/or--data-dir. But the issue's 2026-10-05 comment "Step 1 is done" is wrong: onmainonly the glossary and ADR record it. File a follow-up issue for step 1 as a whole (thedata/andstaging/directories, the server started with--data-dir ~/message-crate/data, the default Staging Directory moved, the button renamed) and link it from the PR body. Also, step 4 of the PR's "How to Test" (Convert with ffmpeg only in the Tools Directory,psshowing--tools-dir) was not run; the body should say so.
…missing ffmpeg on PATH and ffprobe in the Tools Directory would be two builds, perhaps of different versions, working on one file. The lookup now takes both from PATH when both are there, else both from the Tools Directory, and one found only in each place is an error naming both paths. Settings -> System shows that as "not used" with the reason. The Import form names the program it can't use (ffmpeg, ffprobe, or both) from tools_status, instead of always saying ffmpeg, and points at Settings -> System for the Tools Directory. The form's validation message points there too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
A release file put in the Tools Directory without chmod +x showed as found in Settings -> System and failed at run time with "Permission denied". On Unix the lookup now needs an executable bit, and a file without one is reported as not executable, with the chmod hint. Settings shows that as "not used" with the reason. The program is still not run at lookup, because a pipx shim is slow to start, so a link to a broken shim is found and the run-time hint covers it. The doc comment says so, in place of the sentence about PATH, which the lookup no longer reads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…Directory test wtsexporter_in reads no environment, so setting WTSEXPORTER and MESSAGE_CRATE_BIN could not make the test fail. The test keeps what it can check: a copy outside the Tools Directory is not found, and the error names the Tools Directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…ble_name The Settings test spelled wtsexporter and wtsexporter.exe out again. executable_name is now public, and the test reads it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
run_directories.rs kept its own "message-crate" for the default Staging Directory beside app_directories.rs's MESSAGE_CRATE_DIRECTORY_NAME. It now reads that one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
It searches nothing: it checks the directory is made and named to the lookups. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… later step adds The comments in tools.rs, tauri.ts and SystemSection.tsx described what #1053's download step would add. They now say the shape is tagged by state, one tag per state, so a state can be added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
On macOS an app opened from the Dock or Finder gets a PATH without Homebrew's directories, so a Homebrew ffmpeg is not found once the ffmpeg directory field is gone. The lookup stays PATH, then the Tools Directory, and the download is the real fix. Until then the not-found line in Settings -> System names the Tools Directory to put the program in, the Import form's blocked message says to put it there, and the System page of the user guide says how to link Homebrew's ffmpeg and ffprobe into it. The page also lists the "not used" line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
It said the path was shown as ~/message-crate/tools. Settings shows the full path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… PATH On a new machine pipx ensurepath changes only the shell's start-up files, so ~/.local/bin is not on PATH in the shell that runs the setup, command -v prints nothing, and the link fails. pipx environment names the directory pipx put wtsexporter in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
The page said the app finds wtsexporter on PATH or through WTSEXPORTER, both of which this branch removes, so a reader who followed the pipx step got an import that could not find the program. It now says the app runs wtsexporter only from the Tools Directory that Settings -> System shows, and gives the line that links the pipx install there, or copies wtsexporter.exe there on Windows. The pipx step stays until the download. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…reader's terms The entry sat under Features although most of it removes a field and changes where programs are looked for, and its headline said ffmpeg was looked for in one place when the installed copy comes first. It now sits under Design with a true headline, and leaves the paths and the server flag to the Upgrading bullet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…to the Tools Directory It sent the reader to a pipx install onto PATH, which the bullet above it says is no longer searched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… Directory Attachments and media, Troubleshooting and Import still sent the reader to the ffmpeg directory field, which this branch removes. They now name the Tools Directory and the status lines Settings -> System shows, and quote the Import form's new message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… or both in the Tools Directory With ffmpeg on PATH and ffprobe nowhere, "Put it in the Tools Directory" led to ffprobe and ffmpeg in two places, which neither is used from. The row names the program that was found, and with both missing says to put both in the Tools Directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…"and" One missing program goes beside the other one, or both go in the Tools Directory; the Tools Directory alone would split them. Both unusable read "ffmpeg and ffprobe", not "or". Settings → System shows each program's state, and a missing program has no reason there to show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… a dash Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…exporter too Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…, or both in the Tools Directory Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…rogram can't be used A program found in two places is not missing, and Settings shows it too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… converts with the same ffmpeg Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…tory instead of pointing at another bullet Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…_file_name `executable_name` read as any program's name once it was re-exported from the crate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…gain Only a complete pair was remembered, so with one program missing or the two in two places every lookup searched PATH again and ran -version on each program it found: once per file staged and once per Asset shown. Each file's answer is now kept by path, under the same generation as the pair, beside its modified time, size and permissions. A repeated lookup runs nothing; a file that appears, changes or is made executable is run once, so a program put in place later is still found without a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
… not used, and why The pass said "ffmpeg was not found" when both were found, one on PATH and the other in the Tools Directory. The warning now carries the reason the lookup gives, and a missing program is named, ffprobe included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
The whatsapp-exporter tests and the desktop app's Tools Directory test each set a file's mode with their own code. Both now call media::testutil::write_with_mode, which whatsapp-exporter takes through the testutil feature as the desktop app already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
…nly a -version answer The pair found was kept, so a pair that left PATH and appeared in the Tools Directory was not found until a restart. A failed -version was kept too, beside the file's modified time, size and permissions; a file Gatekeeper blocked, or one missing a shared library, stayed unusable after the fix, because the fix changes none of those. Every lookup now searches PATH and then the Tools Directory again, which reads only file metadata. Only a file that answered -version is kept, by path, beside its modified time, size, permissions and, on Unix, its status change time, inode and device, so a file replaced in place is run again. A failure is never kept and is run again on the next lookup. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1
mbeisser1
left a comment
There was a problem hiding this comment.
Re-review of the fix commits (Standards and Correctness, step 4 of the review), pinned to 10a37c3. Every finding below is fixed in this push.
Correctness · bug web/src/screens/settings/SystemSection.tsx / ImportRunView.tsx: with ffmpeg on PATH and ffprobe nowhere, "Put it in the Tools Directory" led into the two-places state. Fixed in 84550e1, 08d1b88, 79aca07: the hint says to put it beside the other one, or both in the Tools Directory.
Correctness · bug crates/server/server/src/media_queue.rs: in the two-places state the server logged "ffmpeg was not found". Fixed in 1e84d88: tools_unavailable names the programs as not used with the lookup's reason, and names a missing program; two tests.
Correctness · bug crates/libs/media/src/tools.rs: only a complete pair was cached, so a missing or split state spawned -version per file and per asset. Fixed in d58d98a and 10a37c3: the stat-only search runs every call; a successful -version is cached per program by path and a stamp (mtime, size, mode, and on Unix ctime, inode, device); a failure is never cached, so a Gatekeeper approval, a missing library installed, or a passing failure is retried without a restart; a pair that moved from PATH to the Tools Directory is found on the next call. Tests for each.
Correctness · bug crates/libs/media/src/tools.rs (FileStamp): a cached "does not run" by mtime, size and mode alone stayed wrong after a Gatekeeper approval or a missing .so installed; a file replaced with cp -p kept a stale "runs". Fixed in 10a37c3 (above).
Correctness · bug crates/libs/media/src/tools.rs: the cached pair was never checked again, so a pair removed from PATH and copied into the Tools Directory kept returning the deleted paths. Fixed in 10a37c3 (above).
Standards · rule SystemSection.tsx: not used - reason joined clauses with a dash. Fixed in 401215c.
Standards · rule system.md:57: "ffmpeg not used" named the wrong program for the wtsexporter row. Fixed in 467b34c: <program> not used, one line per reason.
Standards · judgement exporters.rs:19: "shows which is missing" also covered the not-used case. Fixed in f03b015.
Standards · judgement ImportRunView.tsx: "ffmpeg or ffprobe" when both are unusable; "with the reason" wrong for a missing program. Fixed in 08d1b88.
Standards · judgement CHANGELOG.md:98: unclear subjects. Fixed in 53479e2.
Standards · judgement CHANGELOG.md:345: "as the bullet above says". Fixed in cc6e3a3.
Standards · judgement whatsapp.md:27: "points it at". Fixed in 8920b68.
Standards · judgement wtsexporter.rs:70: public executable_name says nothing about whose. Fixed in d95315e: wtsexporter_file_name.
Standards · judgement media/src/tools.rs:276: fn split. Fixed in 6ec0092: found_in_two_places_error.
Standards · judgement src-tauri/src/commands/tools.rs:139: repeated set_permissions helper. Fixed in b49002d: media::testutil::write_with_mode shared.
|
Review summary for 10a37c3.
|
Feature Description
Step 2 of #1053: the desktop app and the server it starts look for ffmpeg and ffprobe in two places only,
PATHand then the Tools Directory (~/message-crate/tools). wtsexporter is always the app's own copy in the Tools Directory. Settings → System → Media has nothing to type: it names the Tools Directory and shows one status line each for ffmpeg, ffprobe and wtsexporter, with the path found or that the program is missing.The download (step 3) is not here, so on a computer without the programs every line reads "not found" until a person installs ffmpeg on
PATHor puts the files in the Tools Directory by hand.User Story
As a person running the desktop app, I want the app and its server to find ffmpeg and wtsexporter in one known place, so that the download in step 3 has one directory to fill and nothing in Settings asks me to type a path.
Implementation Details
mediacrate (crates/libs/media/src/tools.rs).find_tool(name, search_path, tools_dir)searches eachPATHdirectory, then the Tools Directory, and nowhere else. A file that does not answer-versionis passed over.set_tools_dirnames the Tools Directory for the whole process. The beside-the-program,lib/, parentlib/,MESSAGE_CRATE_BINand bare-name lookups are gone.probe_ffmpeg_toolsandFfmpegToolsProbeare replaced byffmpeg_path(),ffprobe_path()and a publicrequire_ffmpeg(), whose error names the missing tool and where it was looked for. For tests,testutilcan replacePATH(set_search_path), sohide_ffmpegstill hides a real ffmpeg.crates/exporters/whatsapp-exporter/src/wtsexporter.rs). The lookup reads onlymedia::tools_dir(). TheWTSEXPORTERvariable,PATH,cli/andMESSAGE_CRATE_BINare no longer read. A missing copy is an error that names the Tools Directory.PINNED_HINTis unchanged, as WhatsApp replies link only once a fork release records full_key_id and reply_key_id #1936 asked; the lookup's error text still uses it.serve --tools-dir <dir>setsServerConfig::tools_dir, which is#[serde(skip)]. The config file has no key for it, and atools_dirkey is refused as an unknown key. A relative path resolves like--static-dir.server::runcallsmedia::set_tools_dirbefore anything runs ffmpeg. The CLI reference is regenerated.src-tauri). At start the app makes~/message-crate/tools(app_directories::use_tools_dir_in) and names it to its own lookups.Launchcarries it to the server as--tools-dir.commands/ffmpeg.rs(probe_ffmpeg_tools,set_ffmpeg_tools_dir) is deleted, which also covers the last part of Desktop commands write, delete, open and run what the window names, with guards whose root the window supplies #1127. The newtools_statuscommand returns{ toolsDir, ffmpeg, ffprobe, wtsexporter }, and each program is{ state: "found", path }or{ state: "missing" }. The status is tagged so that step 3 can add a downloading state and a failed state without changing these two.SystemSectiondrops the field, its debounce and its localStorage key.lib/ffmpeg-tools.ts, which applied the saved directory at start, is deleted. The Import form's missing-ffmpeg check callsinvokeToolsStatus. The Import review's line no longer points at the deleted field.A decision the issue left open. Step 1, the Message Crate Directory with
data/,staging/andtools/, has not landed onmain: no commit or PR builds it. This PR therefore defines the Tools Directory as{home}/message-crate/tools, the place the issue's layout decided, and makes only that directory.data/andstaging/stay as they are for step 1. Step 1 as a whole is filed as #1999.Key Files Changed
crates/libs/media/src/tools.rs: the lookup cut to PATH, then the Tools Directorycrates/exporters/whatsapp-exporter/src/wtsexporter.rs: wtsexporter from the Tools Directory onlycrates/server/server/src/{cli,config,server}.rs:serve --tools-dirsrc-tauri/src/app_directories.rs,main.rs,local_server.rs,commands/tools.rs(new),commands/ffmpeg.rs(deleted)web/src/screens/settings/SystemSection.tsx,web/src/lib/tauri.ts,web/src/screens/import/useImportJob.tsHTTP API Changes
/v1route changes. The server CLI gainsserve --tools-dir.Database Changes
schema/sql/*.sqlchanged (every database rebuilds empty and re-imports; the fingerprint is computed, nothing to bump)How to Test
cargo test -p media:path_is_searched_before_the_tools_directory,the_tools_directory_is_searched_when_path_has_no_ffmpeg,a_tool_that_cannot_run_is_passed_over,message_crate_bin_is_not_searched,a_tool_that_arrives_later_is_found.cargo test -p whatsapp-exporter wtsexporter_is,cargo test -p message-crate-server -- cli::tests::serve config::tests::a_config_cannot_name_a_tools_directory,cargo test --manifest-path src-tauri/Cargo.toml -- tools.cd web && npx vitest run src/screens/settings/SystemSection.test.tsx src/screens/import.cargo tauri devwith nothing on 8080. Settings → System → Media shows~/message-crate/toolsand the three lines.psshows the server started with--tools-dir. With ffmpeg uninstalled and copied into~/message-crate/tools, Convert still works. Not run: the Convert run with ffmpeg only in the Tools Directory and thepscheck of--tools-dirwere not done for this PR.Run here:
./scripts/check-pr.sh;cargo testfor media, message-staging, message-crate-core, whatsapp-exporter, demo-seed and message-crate-server; thesrc-tauritests; the full Vitest suite (2128 tests); andastro checkindocs/. All pass.Browser check with the Playwright MCP, Vite on 5173 against the server on 8080. In the browser, Settings → System shows the desktop-only stub, which now names "the media tools". With a stubbed
__TAURI_INTERNALS__that answerstools_status, the Media part shows the Tools Directory,Found ffmpeg - /usr/bin/ffmpeg,Found ffprobe - /usr/bin/ffprobeandwtsexporter not found, and has no input. A real desktop window was not opened. Thesrc-tauritests cover the command, the directory and the server flag.Checklist
./scripts/check-pr.shpasses and formatter rewrites are committedRelated Issues
Part of #1053 (step 2). Steps 3 to 5 remain, so this does not close it. It also removes the two commands that #1127's note asked step 2 to delete.
Left for step 5, as the brief limited the user-guide change to the System page:
docs/src/content/docs/docs/user/import-sources/whatsapp.md:26still says the program is found onPATHor throughWTSEXPORTER.docs/src/content/docs/docs/user/features/messages/attachments-and-media.md:81and:86,features/messages/import.md:234andfeatures/owner/troubleshooting.md:112still name the ffmpeg directory field, and the old review line is quoted at:86.The developer setup in
AGENTS.mdandcontributing.mdgains a link from thepipxwtsexporter into~/message-crate/tools, so a developer's WhatsApp import still runs. #1936 moves that install to the fork's tag, and the two edits may conflict.Screenshots / Demo
Settings → System → Media, with the desktop process stubbed: a "Tools directory" row with
/home/demo/message-crate/tools, then three status lines. There are no inputs.Deployment Notes
Upgrading: the
MESSAGE_CRATE_BINandWTSEXPORTERenvironment variables and the saved ffmpeg directory are no longer read. Docker is unchanged, because its image has ffmpeg onPATH.🤖 Generated with Claude Code
https://claude.ai/code/session_017gbWRfTT5AEWW1D6hTNDr1