filesmith runs every Filesmith operation from a terminal: convert, compress, resize, upscale,
removebg, generate and the PDF tools, plus the helpers formats, doctor, setup and skill. It
uses the same engine and the same bundled tools as the app (ffmpeg, ImageMagick, mutool, CaesiumCLT,
7-Zip, Ghostscript, LibreOffice, Real-ESRGAN), so results match the app's. It works offline, except for
the one-time setup of the AI tools. It never overwrites anything: outputs get a collision-free name next
to each source or in --out. It runs fine while the app is open, and its jobs never appear in the app's
queue or Completed view.
- The installer puts the command line in
<install>\resources\cli(by default%LOCALAPPDATA%\Programs\Filesmith\resources\cli) and adds that folder to the per-user PATH. Terminals opened after the install see it; terminals that were already open do not. - cmd and PowerShell run
filesmith.cmd. Git Bash, MSYS and Claude Code's Bash tool run the extensionlessfilesmithsh shim (LF endings). Both start the installedFilesmith.exein Node mode (ELECTRON_RUN_AS_NODE=1) with--use-system-caandNODE_USE_ENV_PROXY=1. - cmd expands
%NAME%inside arguments, even quoted. For file names that contain%, use PowerShell or Git Bash. - Ctrl+C cancels: see Ctrl+C and unfinished outputs for how it works in the installed command and its one limit (output redirected in cmd or PowerShell).
- Windows PowerShell 5.1 decodes captured native output with the OEM code page, so non-ASCII paths in
--jsonoutput come out garbled. Run[Console]::OutputEncoding = [Text.Encoding]::UTF8first, or use Git Bash. PowerShell 7 is not affected. - Installing, updating or uninstalling Filesmith closes every running
Filesmith.exe, a running CLI job included.
filesmith <verb> <inputs...> [options]
filesmith pdf <tool> <inputs...> [options]
filesmith generate "<prompt>" [options]
filesmith <helper> [args] [options]
- Shape. Verbs are the sidebar verbs:
convert,compress,resize,upscale,removebg(alsoremove-bg,remove-background),generate. PDF tools:merge,split,burst,extract-text,to-images,extract-images,compress. Helpers:formats,doctor,setup,skill,help. Options may come before, between or after inputs;--ends options, so a file named-x.pngisfilesmith resize --percent 50 -- -x.png. Long flags only, plus-o(--out) and-h(--help);--name valueand--name=valueboth work; verbs, flags and values are case-insensitive. A barefilesmithprints the help. - Inputs. Files, folders (their own files;
--recursivedescends; files the verb cannot take areskipped; dot-files,Thumbs.dbanddesktop.iniare ignored), globs (*.png,**/*.jpg, expanded by Filesmith itself, case-insensitive, so they also work in cmd and PowerShell) and-(paths from stdin, one per line). Duplicates are dropped and the order is kept (it matters forpdf merge). A missing path isNOT_FOUND, a glob without matches isNO_MATCH. - Options mirror the app. Each flag is the app's setting label in kebab-case, each value the label
the app shows (
--quality smaller|balanced|best,--gpu full|balanced). Units are optional (--bitrate 192k,--factor 4x,--percent 50%). Defaults are the app's defaults, except thatconvertrequires--to.filesmith formats [verb]lists every target, value and model. - Never overwrite, and dry runs. Output names follow the app's rule:
name.extif free, elsename (tag).ext, elsename (tag 2).ext; foldersbase,base (2). There is no--force.--dry-runvalidates everything, prints the planned outputs and writes and downloads nothing. Planned names are predictions; the real names are in thedoneevents.--outcreates the folder (with parents) when it is missing;generatewrites to the current folder unless--outis given. - Unfinished outputs never get the final name. While a job runs, its final name holds an empty
placeholder and the tool writes
name (tag).filesmith-part.ext(folders:base.filesmith-part) in the same folder; only a job that succeeds renames it onto the final name. A failed or canceled job removes both. Treat*.filesmith-part*entries as work in progress, never as results. - Output formats. Human output by default: one line per file (
ok,skip,fail) and a summary on stdout, a progress line on stderr when it is a terminal, in the app queue's format ([2/5] photo.png 62%(4s),workingwhen there is no percentage).--jsonprints NDJSON events on stdout only (see below). - Exit codes.
0all ok or skipped;1some job failed (ordoctorfound a failure, orsetupfailed);2usage error or a requirement that fails for every input, nothing ran;130canceled with Ctrl+C.
- Ctrl+C (once) cancels the run: every job emits
canceled, the tools (ffmpeg and the rest) are stopped, unfinished outputs are removed, the summary is printed and the exit code is 130. In cmd there is no "Terminate batch job (Y/N)?" prompt any more. A second Ctrl+C leaves at once, still stopping the tools and removing this run's unfinished outputs. - How, in the installed command.
Filesmith.exein Node mode is a GUI-subsystem program that Electron attaches to the terminal's console after start-up, and in that process Windows never delivers Ctrl+C to Node'sSIGINThandler: the default handler ends the process at once (0xC000013A). So the CLI reads the console itself in raw mode, where the Ctrl+C key arrives as the byte 0x03 instead of a signal (src/cli/consoleCtrlC.ts). Plain Node (npm run cli) usesSIGINTas usual. - Ctrl+Break, closing the window, a hard kill (
taskkill /F, or Windows sending Ctrl+C programmatically withGenerateConsoleCtrlEvent) still endFilesmith.exeat once, with no summary and no exit 130. A small detached watchdog (src/cli/watchdog.ts, started with the first output) then stops the tools the run left running and removes its part files and placeholders, so nothing half-written stays behind. - Limit: output redirected in cmd or PowerShell (
filesmith ... > out.txt,| findstr). Then Windows startsFilesmith.exewithout a console, so the Ctrl+C key never reaches it: the run finishes (cmd then asks "Terminate batch job (Y/N)?"). Close the run withtaskkill /IM Filesmith.exe /Fif you must; the watchdog cleans up. Git Bash pipes and Claude Code's Bash tool are not affected by this, as they do not cancel with a key press anyway. - Manual check (also automated in
e2e/cli-packed.spec.ts): in a new cmd window runfilesmith compress "<a long video>" --codec h265, press Ctrl+C at about 20 %:stop,1 canceled,echo %ERRORLEVEL%prints 130, noffmpeg.exein Task Manager, and only the source in the folder.
From the help pages (filesmith <verb> --help):
filesmith convert *.heic --to jpg
filesmith convert book.pdf --to cbz --resolution 200 --page-format png
filesmith convert comics\ --to cbz --compression normal --out D:\Out
filesmith compress *.jpg --quality 70
filesmith compress lecture.mov --codec h265 --scale 50
filesmith compress report.pdf --level smallest --greyscale
filesmith resize *.png --percent 25
filesmith resize hero.jpg --width 1920
filesmith resize photos\ --recursive --height 1080 --out D:\Small
filesmith upscale old.jpg --factor 2
filesmith upscale frame.png --model pid --dry-run
filesmith upscale scans\*.png --model anime --gpu balanced --json
filesmith removebg product.jpg --fill white
filesmith removebg portrait.png --image beach.jpg
filesmith removebg logo.png --color "#1e1e1e" --dry-run
filesmith generate "a lighthouse at dusk" --count 4 --size 1216x832
filesmith generate "a red kettle" --model flux1-dev --seed 42 --json
filesmith generate "a paper boat" --style anime --out D:\Art --dry-run
filesmith pdf merge cover.pdf body.pdf appendix.pdf
filesmith pdf split thesis.pdf --pages 1-3,10
filesmith pdf to-images slides.pdf --resolution 200 --out D:\Frames
With --json, stdout carries one JSON object per line (UTF-8, \n), and stderr carries nothing an
agent needs. Every line has v (1), event and ts (ISO time). Paths are absolute, sizes in bytes;
fields that do not apply are left out, never null (except pct).
event |
Fields |
|---|---|
run |
command, version, dryRun, inputs, options |
plan |
id, input (array for merge), inSize, op, output, outputKind, ready, code, message, hint |
start |
id, input, inSize, op |
progress |
id, pct (or null), etaSec, message |
done |
files: id, input, output, outputKind, inSize, outSize or files, ms, seed (generate); setup: tool, path, alreadyDone; skill: path, updated, previousVersion |
skipped |
id, input, code, message |
error |
id, input (both absent for run-level errors), code, message, hint |
warning |
code, message |
canceled |
id, input |
check |
doctor, setup: id, group, status (ok, warn, fail, skip), detail, fix |
step |
setup: step, pct, bytes, totalBytes, etaSec, detail (dry run) |
heartbeat |
setup: step, elapsedSec (every 5 s while a step has no percentage) |
formats |
data |
version |
version |
summary |
ok, failed, skipped, canceled, inBytes, outBytes, ms, exitCode |
id is the 1-based job number in input order, the same in a dry run and the real run. Error codes:
USAGE, NOT_FOUND, NO_MATCH, UNSUPPORTED_KIND, SAME_FORMAT, OUT_DIR_MISSING, TOOL_MISSING,
SETUP_REQUIRED, GPU_UNSUPPORTED, RAR_MISSING, PASSWORD, TOOL_FAILED, CANCELED, INTERNAL.
Schema v1 is additive-only: new events, fields and codes may appear; renaming or removing one bumps v.
The source of this table is resources/skill/filesmith/reference.md (Events section).
The app has a console panel at the bottom of the files view (spec
docs/superpowers/specs/2026-10-06-console-design.md). It runs filesmith commands only; for anything
else, use a terminal.
- Open and close.
Ctrl+`(anywhere in the app, except while a dialog is open) toggles it. The bottom strip of the centre column holds the Console button, which shows the running command's percentage while the panel is closed; the strip hides while the panel is open. The panel header has Clear (disabled while a command runs) and Minimise. Drag the top edge (or focus it and use Up and Down) to resize. Open state, height, folder and history are remembered. - Type commands without the prefix:
convert *.heic --to webp,doctor,formats. The line is split into plain arguments and handed to the CLI; nothing runs through a shell, so&,|and>are just text. Anything that is not a filesmith command is refused, in the panel and again in the main process.-(file names from stdin) is refused too. - Built-ins:
cd <folder>(the folder commands run in;cd -goes back,cd ~is your user folder,cd D:a drive root; the last folder is remembered, else Downloads),clear(or Ctrl+L),help,history(the last 100 commands; Up and Down recall them). Tab completes commands, flags, values and file names. - Output is the CLI's human output, with a progress line in the queue's format (
photo.png 62%(4s)) and a bar. Each finished command showsexit <code>and its time. A finished run with outputs offers Show in File Explorer; right-click an output line for Show in File Explorer and Open in default app. - One command at a time. Console runs do not join the app's queue or the Completed view, and the queue keeps working while one runs. Outputs use the same never-overwrite naming as the CLI.
- Stop (in the header while a command runs) or Ctrl+C cancels a run: the current file is stopped, part files are removed and the run ends with exit 130. A second Stop ends it at once (the process tree is killed after 5 s at most). With nothing running, Ctrl+C clears the input.
- Plumbing: each command forks
out/main/cli.jswithELECTRON_RUN_AS_NODE. WhenCliIO.eventsis set, the CLI tees its NDJSON events to it; under a fork they travel over the IPC channel. The parent cancels with the'interrupt'IPC message (twice for a hard stop), never with a console Ctrl+C.
Jobs never download anything. filesmith setup <tool> is the only command that does, with byte progress,
ETA, heartbeats and a cross-process lock (the app and the CLI never install the same tool at once). Every
setup takes --dry-run, which lists the steps, sizes, disk and GPU verdicts.
| Command | Downloads, and where |
|---|---|
setup removebg |
uv (if absent) into %APPDATA%\Filesmith\uv, rembg as a uv tool into %APPDATA%\Filesmith\uv-tools, the model into %APPDATA%\Filesmith\models\rembg. CPU only. |
setup pid |
The PiD upscaler (repo, Python env, weights) into %APPDATA%\Filesmith\pid, about 6 GB. Reuses weights found in ComfyUI. |
setup spandrel [--comfy <dir>] |
Nothing when a ComfyUI Python already has torch and spandrel; otherwise the shared engine env in %APPDATA%\Filesmith\pid. |
setup comfy --folder <path> |
Nothing. Records the ComfyUI folder (or --url <http://host:port>) and rescans its models. |
setup generate --model <name> |
The missing companion files for one model, sha256-checked. Never installs ComfyUI itself. |
setup realesrgan |
Nothing (bundled). Prints the models and the user model folder. |
- GPU gates. PiD and spandrel need an NVIDIA GPU with compute capability 7.5 or higher and driver
525 or newer; a failing gate is
GPU_UNSUPPORTED(exit 2). Real-ESRGAN needs any Vulkan GPU, which is not probed up front (doctor --deepruns a tiny upscale). Generate has no gate; removebg is CPU. - Removing.
setup remove <removebg|pid|spandrel>moves the folders to the Recycle Bin, up to 5 GB and 5,000 files (the Recycle Bin's practical limit). Larger folders (a PiD install) need--permanent, otherwise the command stops with exit 1 and names the size and the flag. filesmith doctor(read-only) shows what is installed, what is missing and the exactfixcommand.
Filesmith ships a Claude Code skill (resources/skill/filesmith: SKILL.md with the working rules and
reference.md with every flag, event and code). Install it into %USERPROFILE%\.claude\skills\filesmith
with filesmith skill install (or --dry-run to preview; filesmith skill status checks it), or with
the Install Claude skill button in Settings > CLAUDE. Both write the absolute shim path into the skill
as a fallback for sessions started before PATH changed, and stamp the app version
(metadata.filesmith-version). Files other than SKILL.md and reference.md in that folder are left
alone; replaced files go to the Recycle Bin. The installer never installs the skill on its own.
Verified 2026-10-04 on this machine, source: running node_modules/electron/dist/electron.exe with
ELECTRON_RUN_AS_NODE=1:
- Electron 43 runs Node 24.18.
fs.globSyncexists (the CLI's glob expansion uses it).--use-system-cais accepted, so downloads trust the Windows certificate store.NODE_USE_ENV_PROXY=1routesfetchthroughHTTPS_PROXY.process.resourcesPathis the install'sresourcesfolder in Node mode.require('electron')returns a path string in Node mode, so the engine never importselectron; it reads its paths fromsrc/main/env.ts(set bysrc/main/index.tsfor the app and bysrc/cli/bootstrap.tsfor the CLI).- Ctrl+C never reaches a
SIGINT/SIGBREAKhandler in Node mode: the process ends with 0xC000013A. Measured 2026-10-05 with a 6-line script underelectron.exeand plainnode.exe; the same loss reproduces in any GUI-subsystem process (pythonw) that registers a console control handler beforeAttachConsole, while one registered after it works. Raw-mode console input does reach the process (see Ctrl+C above). With stdout redirected, Electron does not attach a console at all. - The
runAsNodeElectron fuse must stay on, or the shims stop working (the release workflow's packed-CLI smoke test fails loudly if it is ever turned off).
npm run build && npm run cli -- <args>runs the CLI fromout/main/cli.jswith your system Node (for examplenpm run cli -- convert photo.png --to webp --json).- Unit tests:
test/cli-*.test.ts(parser, catalog, help, options, inputs, planner, runner, reporters, helpers), plustest/env.test.ts,test/skill.test.ts,test/path-ps1.test.tsandtest/cli-graph.test.ts(the CLI's import graph never reacheselectron). Runnpm test. - Process-level tests:
e2e/cli.spec.tsrunsout/main/cli.jsend to end (build first), ande2e/skill.spec.tscovers the Settings > CLAUDE button. Runnpm run test:e2e. e2e/cli-packed.spec.tsruns the shims in the install layout and skips unlessdist/win-unpackedexists. It includes the console Ctrl+C test:e2e/ctrlc-console.ps1runs the cmd shim in a new (minimized) console, writes a Ctrl+C key record into the console input and reports the exit code and the console text. Build it withnpx electron-builder --win dir --publish never(afternpm run build), thennpx playwright test e2e/cli-packed.spec.ts.