One command instead of a throwaway script.
One binary for the file jobs agents otherwise script. In our benchmark, Codex used 27% fewer tokens and 57% less time with it.
This is how an agent finds a command. Try it: the search below uses deft's real index.
An agent doing the job.
Video slot: the demo goes here. Add site/media/demo.mp4 before hosting.
Same task, same agent.
Recorded results from the benchmark. The last task is one deft lost, because a plain tar is hard to beat.
| Measure | With deft | Without |
|---|
Fewer tokens, less time, same work.
100 tasks written the way a person asks. Totals cover the 85 that deft supports.
How it was run
- Agent
- Codex with gpt-6-luna at medium effort, in its workspace-write sandbox with no network.
- With deft
- The same setup, plus deft on the PATH and its generated skill text as
AGENTS.md. - Without
- Whatever the machine has. That included ffmpeg, Ghostscript, Pillow and pandas, so the baseline is stronger than a clean machine.
- Judging
- Checks run with Ghostscript, ffprobe, Pillow and openpyxl, not with deft's own libraries.
- Left out
- 9 tasks deft cannot do yet and 6 that need the network, which were not run.
Read this before quoting the numbers. The latest attempt counts: 22 of 188 task and arm pairs were rerun, and 8 of those went from fail to pass, 4 in each arm. One agent; Claude Code has not been measured. Deft was improved against these same tasks, so this is a development benchmark and not a held-out test.
The cases, results and harness are in evals/.
Where it helps, and where it does not
Savings come from jobs where an agent would write code. On trivial jobs deft can cost more, because the agent reads help first: it used more tokens on 31 of the 85 tasks.
| Group | Tasks | Tokens | Time |
|---|---|---|---|
| convert | 3 | 63% less tokens | 80% less time |
| 20 | 42% less tokens | 68% less time | |
| md | 4 | 36% less tokens | 87% less time |
| image | 18 | 35% less tokens | 53% less time |
| sheet | 9 | 31% less tokens | 53% less time |
| video | 16 | 7% less tokens | 5% less time |
| audio | 6 | 19% more tokens | 2% more time |
| subtitle | 5 | 33% more tokens | 11% less time |
| archive | 4 | 57% more tokens | 44% more time |
173 commands in 17 groups.
This list is generated from the source. One syntax for all of it: deft <group> <command> [inputs] [-o output]. Full table in docs/COMMANDS.md.
pdf
Merge, split, compress, encrypt, forms, OCR, compare, convert
infoPages, size, metadata, fonts, imagescompareCompare two PDFs: text and pixelscompressMake smaller: --level, --target-size 2MBcropTrim pages: --margin, --box, --autodecryptRemove a password you knowdeleteRemove pages: --pages 2,5-7encryptProtect with a password (AES-256)extract-imagesSave embedded pictures, unchangedfieldsList form fields and their valuesfillFill a form from JSON: --data values.jsonflattenBake forms and annotations into pagesfrom-imagesOne page per imagefrom-mdTypeset Markdown as PDFgrayscaleRemove colour, keeping text as text (Ghostscript)mergeJoin PDFs in the given ordermetaRead metadata and bookmarks, or set --title --authornumberAdd page numbers: --formatocrMake a scan searchableredactBlack out for good: --box or --textrepairRebuild a damaged PDF (Ghostscript)resizeFit pages to --page-size a4rotateTurn pages clockwise: --angle 90, --pagessearchFind text: --text invoiceselectKeep and reorder pagessplitSplit: per page, --every N, --rangesstripRemove metadatato-docxEditable Word file, layout not keptto-imagesRender pages: --dpi, --pagesto-mdText as Markdown paragraphsto-pdfaConvert for archiving as PDF/A-2 (Ghostscript)to-sheetPull tables out by text positionto-textExtract textwatermarkStamp text or an image on pages
image
Resize, crop, convert, compress, filters, montage, OCR
infoFormat, dimensions, EXIF orientation, GPSadjustChange --brightness, --contrast, --saturation, --gammablurGaussian blur: --radius 5, or a --box regioncompressSmaller file: --quality, --target-size 200KBconvertChange format: --to png|jpg|webp|avif|gif|tiff|bmp|icocropCut a region: --box x,y,w,h or --aspect 16:9diffCompare two images; marks changed pixels in redfaviconWebsite icon set: favicon.ico and PNG sizesflipMirror: --direction horizontal|verticalframesSave each frame of an animated GIF as PNGgrayscaleRemove colourinvertNegative: flip every colourmetaRead EXIF, or set --title --author --copyright --datemontageTile images into a grid: --cols 3 --size 300x300ocrRead the text in an image (tesseract)padAdd a border or canvas: --border 20, --size 1080x1080resizeScale: --size 800x, 1920x1080, 50%rotateTurn clockwise by any angle (EXIF is applied first)sharpenUnsharp mask: --radius 2stripRemove EXIF, GPS and text metadatato-gifAnimate images into a GIF: --fps 2to-pdfOne page per imageto-videoSlideshow: --duration, --fps, --audiotransparentMake a colour see-through: --color white --fuzz 10trimCut away plain borders, matching the corner colourwatermarkAdd text or a logo: --text, --image, --position
video
Trim, crop, speed, convert, compress, GIF, frames (ffmpeg)
infoDuration, size, frame rate, codecsadd-audioReplace or mix the soundtrack: --audio song.mp3add-subtitlesAdd subtitles: burned into the picture, or --softchunkCut into equal parts: --length 10:00compressSmaller file: --level, --target-size, --max-heightconvertChange container and codec: --to mp4|webm|mov|mkvcropCut a region: --box or --aspect 1:1downloadSave a video: --resolution 720p, --to mp4|webm|mkvextract-audioSave the soundtrack: --to mp3|m4a|wav|flac|oggextract-subtitlesSave an embedded subtitle track: --to srt|vttfadeFade: --fade-in 1 --fade-out 2framesSave frames as images: --fps 1 or --at 0:05,0:10from-imagesSlideshow: --duration, --fps, --audiomergeJoin videos; --transition fadesmuteRemove the audio trackpadFit into a frame with bars: --size 1080x1920repeatRepeat a video: --count 3 plays it three timesresizeScale: --size 1280x, x720, 50%reversePlay backwards, picture and soundrotateTurn clockwise: --angle 90speedSpeed up or slow down: --factor 2 or --factor 0.5splitCut out a part: --from 0:10 --to-time 0:25stabilizeSteady shaky footage, or --denoise grainstackPlay side by side: --directionstripRemove metadata; no re-encodethumbnailOne frame as an image, or --at a timeto-gifAnimated GIF: --fps, --size, --from, --to-timewatermarkAdd text or a logo: --text, --image, --position
audio
Convert, trim, merge, fade, speed, tag, normalize (ffmpeg)
infoDuration, codec, sample rate, channelschunkCut into equal parts: --length 10:00compressRe-encode as MP3 at --bitrate (kbps)convertChange format: --to mp3|m4a|wav|flac|ogg|opusdenoiseReduce steady background noise such as hiss or humfadeFade in or out: --fade-in 2 --fade-out 3from-videoSave the soundtrack: --to mp3|m4a|wav|flac|oggmergeJoin audio files in ordermixPlay files on top of each other, such as voice over musicnormalizeEven out loudness (EBU R128)remove-silenceCut silent parts: --threshold -40 --min-silence 0.5reversePlay backwardsspeedChange tempo, keeping pitch: --factor 1.5splitCut out a part: --from 0:10 --to-time 0:25stripRemove tags and cover art; no re-encodetagSet tags: --title --artist --album --year, cover --imagevolumeRaise or lower the level: --gain 6 or --gain -3 (dB)waveformDraw the sound wave as an image: --size 1200x240
doc
Word/ODT/RTF: to text, Markdown, HTML, PDF; find and replace
infoTitle, author, words, headings, tables, imagesfrom-htmlConvert the content to a Word documentfrom-mdWrite a Word document with headings, lists, tables, imagesfrom-pdfEditable Word file, layout not keptreplaceFind and replace text in Word, keeping the formattingto-htmlConvert to a web pageto-mdConvert to Markdown, keeping headings, lists and tablesto-pdfTypeset as PDF, content not layoutto-textExtract plain text
subtitle
SRT/VTT: convert, shift, burn in, extract
infoNumber of lines, start and end timeburnAdd subtitles: burned into the picture, or --softconvertChange format: --to srt|vtt|txt|mdfrom-videoSave an embedded subtitle track: --to srt|vttshiftMove all timing: --by 2.5 (later) or --by -1 (earlier)
slides
PowerPoint: extract text, Markdown outline, PDF handout
infoSlide count, titles, images, notesfrom-mdMake a deck: each heading or --- starts a slideto-mdOutline in Markdown: a heading per slide, bullets, imagesto-pdfHandout PDF of slide contentto-textExtract the text of every slide, form feed between slides
data
JSON/YAML/TOML/XML: convert, query with jq syntax, merge, diff
convertChange format: --to json|yaml|toml|xml|jsonldiffCompare two documents by structure, across formatsformatPretty-print or minify: --compact, --sort-keysmergeDeep-merge documents; later files winqueryQuery or edit with jq syntax: --expr '.items[].name'validateCheck syntax, or a JSON Schema with --schema
sheet
Excel/CSV/ODS tables: filter, sort, join, pivot, convert
infoSheet names, rows, columnsconvertChange format: --to csv|xlsx|jsondedupeDrop repeated rows, by whole row or --columnsextractTake a sheet or range: --sheet, --range A1:D20filterKeep matching rows: --where "age > 30 and city = 'Oslo'"from-pdfPull tables out by text positiongroupGroup and total: --columns city --values sales --agg sumjoinJoin two tables on a key: --on id --how leftmergeStack tables; a shared header is kept oncepivotPivot table: --rows city --columns year --values salesqueryRun SQL over tables or a SQLite file: --sql 'select ...'selectKeep, reorder or --drop columnssortSort rows: --columns age,name --descendingsplitSplit up: --sheets, --columns city or --every 1000statsPer-column counts, empties, min, max, mean, sumto-mdMarkdown table (first row is the header)transposeSwap rows and columns
md
Markdown to PDF, HTML, Word, EPUB; table of contents
from-docxConvert to Markdown, keeping headings, lists and tablesfrom-htmlConvert to Markdown; scripts and styles are droppedfrom-pdfText as Markdown paragraphsto-docxWrite a Word document with headings, lists, tables, imagesto-epubMake an e-book; each top-level heading starts a chapterto-htmlRender to a styled HTML page, or --fragmentto-pdfTypeset Markdown as PDFto-pptxMake a deck: each heading or --- starts a slidetocInsert a table of contents from the headings
html
HTML to Markdown, text, Word, PDF; screenshots
screenshotRender a local page to an image with Chrome: --size 1280x800to-docxConvert the content to a Word documentto-mdConvert to Markdown; scripts and styles are droppedto-pdfMake a PDF; --browser keeps the CSSto-textExtract the readable text
epub
E-books: info, to text, Markdown and PDF
infoTitle, author, language, chapters, images, wordsfrom-mdMake an e-book; each top-level heading starts a chapterto-mdConvert the whole book to Markdownto-pdfTypeset the book as PDFto-textExtract plain text in reading order
email
EML files: headers, text, attachments
infoFrom, to, subject, date, attachmentsattachmentsSave the attached filesto-textThe message as text, with its headers
archive
zip/tar/gz/xz/zst/7z: create, extract, list; ZIP passwords
addAdd files to a copy of a ZIPcreatePack files and folders: --to zip|tar.gz|tar.xz|7zextractUnpack into a folderlistList entries without unpacking
youtube
Info, download, audio, subtitles, thumbnail (yt-dlp)
infoTitle, duration, channel, chapters, qualitiesaudioSave only the sound: --to mp3|m4a|opusdownloadSave a video: --resolution 720p, --to mp4|webm|mkvplaylistList the videos of a playlist or channelsubtitlesTranscript: --lang en,zh --to md|txt|srt|vttthumbnailSave the cover image
file
Any file: hash, duplicates, batch rename, base64, encoding
base64Encode to base64, or --decode back to bytesduplicatesFind files with identical content; deletes nothingencodingConvert text encoding, normally to UTF-8; fixes line endingshashChecksums: --algorithm md5|sha1|sha256|sha512|blake3|crc32joinPut parts back together, in the order givenorganizeCopy files into folders: --group type|ext|monthrenameBatch rename: --find, --replace, --name, --case; --previewsplitCut a big file into parts: --part-size 100MB
qr
Create QR codes and barcodes; read QR codes
createMake a QR code or barcode: --text https://example.comreadDecode every QR code in an image
Any file
Commands outside a group
convertAny-to-any by extension, e.g. deft convert a.png -o a.pdfinfoType, size, pages, dimensions, durationfindSearch commands by intentschemaJSON Schema of a command's inputs and optionsengineManage external programs such as ffmpeg and yt-dlpskillPrint or install the agent skilldoctorCheck the environment and engines
Built for the agent reading it.
Help in layers
An agent reads only what it needs: groups, then commands, then options. Each layer has a token budget that tests enforce.
$ deft find "burn subtitles"
subtitle burn video -> video Add subtitles: burned into the picture, or --soft
$ deft pdf
deft pdf - commands (input -> output)
info pdf -> report Pages, size, metadata, fonts, images
compress pdf -> pdf Make a PDF smaller: --level, --target-size 2MB
delete pdf -> pdf Remove pages: --pages 2,5-7
from-images image... -> pdf One page per image, in the given order
from-md md -> pdf Typeset a PDF with headings, tables, code, images
merge pdf... -> pdf Join PDFs in the given order
number pdf -> pdf Add page numbers: --format "{n} of {total}"
rotate pdf -> pdf Turn pages clockwise: --angle 90, --pages
select pdf -> pdf Keep and reorder pages: --pages 3,1-2
split pdf -> pdf... One file per page, or --every N, --ranges 1-3,4-
to-images pdf -> png|jpg... Render pages to images: --dpi, --pages
to-text pdf -> txt Extract text (form feed between pages)
watermark pdf -> pdf Stamp text or an image on pages: --text, --image
More: deft pdf <command> --help
One line back
A result is one line that starts with ok, partial or error. Add --json for structure.
$ deft pdf compress photos.pdf
ok pdf.compress photos.pdf -> photos.compressed.pdf 704KB -> 272KB (-61%) 0.10s
$ deft pdf compress photos.pdf -o small.pdf --json
{"v":1,"ok":true,"op":"pdf.compress","items":[{"ok":true,"inputs":["photos.pdf"],"outputs":[{"path":"small.pdf","format":"pdf","bytes":278842}],"facts":{"bytes_before":720475,"bytes_after":278842,"ratio":0.387,"images_recompressed":1},"warnings":[]}],"elapsed_ms":67}
Errors that carry the fix
Every error has a stable code, and a hint when there is a concrete next step. The agent corrects itself in one turn.
$ deft pdf compress locked.pdf error INPUT_ENCRYPTED locked.pdf: the PDF is password-protected hint: add --password <password> $ deft pdf compres photos.pdf error UNKNOWN_COMMAND deft pdf has no command "compres" hint: did you mean: deft pdf compress | deft audio compress | deft image compress
Local and careful
Inputs are never overwritten and writes are atomic. Deft collects no usage data. Only commands marked [net] touch the network.
$ deft pdf compress photos.pdf error OUTPUT_EXISTS photos.compressed.pdf already exists hint: pass --force to overwrite, or choose another -o $ deft pdf compress photos.pdf --dry-run -o copy.pdf plan pdf.compress photos.pdf -> copy.pdf $ deft youtube info https://youtu.be/xxxx --offline error OFFLINE deft youtube info needs the network, but --offline is set
The launch film.
Video slot: the launch film goes here. Add site/media/launch.mp4 before hosting.
Build it today.
No release exists yet, so today you build from source. Video and audio commands need ffmpeg. Install guide.
git clone https://github.com/firstprayer/deftcd deft && cargo install --path crates/deft-cli --lockeddeft doctordeft skill install --agent allTeaches Claude Code and Codex that deft exists.
- Release binariesPlanned
- Install scriptPlanned
- Homebrew tapPlanned
- cargo install deftcliPlanned