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.

MeasureWith deftWithout

Fewer tokens, less time, same work.

100 tasks written the way a person asks. Totals cover the 85 that deft supports.

85/85tasks solved with deft, 78 without
3 vs 70failed commands, with deft and without
27%fewer tokens, counting uncached input plus output
57%less time, wall clock per task
Under 10 msfor a help answer, measured on the release binary
50 MBbinary, about; ffmpeg and yt-dlp are separate

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.

GroupTasksTokensTime
convert363% less tokens80% less time
pdf2042% less tokens68% less time
md436% less tokens87% less time
image1835% less tokens53% less time
sheet931% less tokens53% less time
video167% less tokens5% less time
audio619% more tokens2% more time
subtitle533% more tokens11% less time
archive457% more tokens44% 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, images
  • compareCompare two PDFs: text and pixels
  • compressMake smaller: --level, --target-size 2MB
  • cropTrim pages: --margin, --box, --auto
  • decryptRemove a password you know
  • deleteRemove pages: --pages 2,5-7
  • encryptProtect with a password (AES-256)
  • extract-imagesSave embedded pictures, unchanged
  • fieldsList form fields and their values
  • fillFill a form from JSON: --data values.json
  • flattenBake forms and annotations into pages
  • from-imagesOne page per image
  • from-mdTypeset Markdown as PDF
  • grayscaleRemove colour, keeping text as text (Ghostscript)
  • mergeJoin PDFs in the given order
  • metaRead metadata and bookmarks, or set --title --author
  • numberAdd page numbers: --format
  • ocrMake a scan searchable
  • redactBlack out for good: --box or --text
  • repairRebuild a damaged PDF (Ghostscript)
  • resizeFit pages to --page-size a4
  • rotateTurn pages clockwise: --angle 90, --pages
  • searchFind text: --text invoice
  • selectKeep and reorder pages
  • splitSplit: per page, --every N, --ranges
  • stripRemove metadata
  • to-docxEditable Word file, layout not kept
  • to-imagesRender pages: --dpi, --pages
  • to-mdText as Markdown paragraphs
  • to-pdfaConvert for archiving as PDF/A-2 (Ghostscript)
  • to-sheetPull tables out by text position
  • to-textExtract text
  • watermarkStamp text or an image on pages

image

Resize, crop, convert, compress, filters, montage, OCR

  • infoFormat, dimensions, EXIF orientation, GPS
  • adjustChange --brightness, --contrast, --saturation, --gamma
  • blurGaussian blur: --radius 5, or a --box region
  • compressSmaller file: --quality, --target-size 200KB
  • convertChange format: --to png|jpg|webp|avif|gif|tiff|bmp|ico
  • cropCut a region: --box x,y,w,h or --aspect 16:9
  • diffCompare two images; marks changed pixels in red
  • faviconWebsite icon set: favicon.ico and PNG sizes
  • flipMirror: --direction horizontal|vertical
  • framesSave each frame of an animated GIF as PNG
  • grayscaleRemove colour
  • invertNegative: flip every colour
  • metaRead EXIF, or set --title --author --copyright --date
  • montageTile images into a grid: --cols 3 --size 300x300
  • ocrRead the text in an image (tesseract)
  • padAdd a border or canvas: --border 20, --size 1080x1080
  • resizeScale: --size 800x, 1920x1080, 50%
  • rotateTurn clockwise by any angle (EXIF is applied first)
  • sharpenUnsharp mask: --radius 2
  • stripRemove EXIF, GPS and text metadata
  • to-gifAnimate images into a GIF: --fps 2
  • to-pdfOne page per image
  • to-videoSlideshow: --duration, --fps, --audio
  • transparentMake a colour see-through: --color white --fuzz 10
  • trimCut away plain borders, matching the corner colour
  • watermarkAdd text or a logo: --text, --image, --position

video

Trim, crop, speed, convert, compress, GIF, frames (ffmpeg)

  • infoDuration, size, frame rate, codecs
  • add-audioReplace or mix the soundtrack: --audio song.mp3
  • add-subtitlesAdd subtitles: burned into the picture, or --soft
  • chunkCut into equal parts: --length 10:00
  • compressSmaller file: --level, --target-size, --max-height
  • convertChange container and codec: --to mp4|webm|mov|mkv
  • cropCut a region: --box or --aspect 1:1
  • downloadSave a video: --resolution 720p, --to mp4|webm|mkv
  • extract-audioSave the soundtrack: --to mp3|m4a|wav|flac|ogg
  • extract-subtitlesSave an embedded subtitle track: --to srt|vtt
  • fadeFade: --fade-in 1 --fade-out 2
  • framesSave frames as images: --fps 1 or --at 0:05,0:10
  • from-imagesSlideshow: --duration, --fps, --audio
  • mergeJoin videos; --transition fades
  • muteRemove the audio track
  • padFit into a frame with bars: --size 1080x1920
  • repeatRepeat a video: --count 3 plays it three times
  • resizeScale: --size 1280x, x720, 50%
  • reversePlay backwards, picture and sound
  • rotateTurn clockwise: --angle 90
  • speedSpeed up or slow down: --factor 2 or --factor 0.5
  • splitCut out a part: --from 0:10 --to-time 0:25
  • stabilizeSteady shaky footage, or --denoise grain
  • stackPlay side by side: --direction
  • stripRemove metadata; no re-encode
  • thumbnailOne frame as an image, or --at a time
  • to-gifAnimated GIF: --fps, --size, --from, --to-time
  • watermarkAdd text or a logo: --text, --image, --position

audio

Convert, trim, merge, fade, speed, tag, normalize (ffmpeg)

  • infoDuration, codec, sample rate, channels
  • chunkCut into equal parts: --length 10:00
  • compressRe-encode as MP3 at --bitrate (kbps)
  • convertChange format: --to mp3|m4a|wav|flac|ogg|opus
  • denoiseReduce steady background noise such as hiss or hum
  • fadeFade in or out: --fade-in 2 --fade-out 3
  • from-videoSave the soundtrack: --to mp3|m4a|wav|flac|ogg
  • mergeJoin audio files in order
  • mixPlay files on top of each other, such as voice over music
  • normalizeEven out loudness (EBU R128)
  • remove-silenceCut silent parts: --threshold -40 --min-silence 0.5
  • reversePlay backwards
  • speedChange tempo, keeping pitch: --factor 1.5
  • splitCut out a part: --from 0:10 --to-time 0:25
  • stripRemove tags and cover art; no re-encode
  • tagSet tags: --title --artist --album --year, cover --image
  • volumeRaise 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, images
  • from-htmlConvert the content to a Word document
  • from-mdWrite a Word document with headings, lists, tables, images
  • from-pdfEditable Word file, layout not kept
  • replaceFind and replace text in Word, keeping the formatting
  • to-htmlConvert to a web page
  • to-mdConvert to Markdown, keeping headings, lists and tables
  • to-pdfTypeset as PDF, content not layout
  • to-textExtract plain text

subtitle

SRT/VTT: convert, shift, burn in, extract

  • infoNumber of lines, start and end time
  • burnAdd subtitles: burned into the picture, or --soft
  • convertChange format: --to srt|vtt|txt|md
  • from-videoSave an embedded subtitle track: --to srt|vtt
  • shiftMove all timing: --by 2.5 (later) or --by -1 (earlier)

slides

PowerPoint: extract text, Markdown outline, PDF handout

  • infoSlide count, titles, images, notes
  • from-mdMake a deck: each heading or --- starts a slide
  • to-mdOutline in Markdown: a heading per slide, bullets, images
  • to-pdfHandout PDF of slide content
  • to-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|jsonl
  • diffCompare two documents by structure, across formats
  • formatPretty-print or minify: --compact, --sort-keys
  • mergeDeep-merge documents; later files win
  • queryQuery 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, columns
  • convertChange format: --to csv|xlsx|json
  • dedupeDrop repeated rows, by whole row or --columns
  • extractTake a sheet or range: --sheet, --range A1:D20
  • filterKeep matching rows: --where "age > 30 and city = 'Oslo'"
  • from-pdfPull tables out by text position
  • groupGroup and total: --columns city --values sales --agg sum
  • joinJoin two tables on a key: --on id --how left
  • mergeStack tables; a shared header is kept once
  • pivotPivot table: --rows city --columns year --values sales
  • queryRun SQL over tables or a SQLite file: --sql 'select ...'
  • selectKeep, reorder or --drop columns
  • sortSort rows: --columns age,name --descending
  • splitSplit up: --sheets, --columns city or --every 1000
  • statsPer-column counts, empties, min, max, mean, sum
  • to-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 tables
  • from-htmlConvert to Markdown; scripts and styles are dropped
  • from-pdfText as Markdown paragraphs
  • to-docxWrite a Word document with headings, lists, tables, images
  • to-epubMake an e-book; each top-level heading starts a chapter
  • to-htmlRender to a styled HTML page, or --fragment
  • to-pdfTypeset Markdown as PDF
  • to-pptxMake a deck: each heading or --- starts a slide
  • tocInsert 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 1280x800
  • to-docxConvert the content to a Word document
  • to-mdConvert to Markdown; scripts and styles are dropped
  • to-pdfMake a PDF; --browser keeps the CSS
  • to-textExtract the readable text

epub

E-books: info, to text, Markdown and PDF

  • infoTitle, author, language, chapters, images, words
  • from-mdMake an e-book; each top-level heading starts a chapter
  • to-mdConvert the whole book to Markdown
  • to-pdfTypeset the book as PDF
  • to-textExtract plain text in reading order

email

EML files: headers, text, attachments

  • infoFrom, to, subject, date, attachments
  • attachmentsSave the attached files
  • to-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 ZIP
  • createPack files and folders: --to zip|tar.gz|tar.xz|7z
  • extractUnpack into a folder
  • listList entries without unpacking

youtube

Info, download, audio, subtitles, thumbnail (yt-dlp)

  • infoTitle, duration, channel, chapters, qualities
  • audioSave only the sound: --to mp3|m4a|opus
  • downloadSave a video: --resolution 720p, --to mp4|webm|mkv
  • playlistList the videos of a playlist or channel
  • subtitlesTranscript: --lang en,zh --to md|txt|srt|vtt
  • thumbnailSave the cover image

file

Any file: hash, duplicates, batch rename, base64, encoding

  • base64Encode to base64, or --decode back to bytes
  • duplicatesFind files with identical content; deletes nothing
  • encodingConvert text encoding, normally to UTF-8; fixes line endings
  • hashChecksums: --algorithm md5|sha1|sha256|sha512|blake3|crc32
  • joinPut parts back together, in the order given
  • organizeCopy files into folders: --group type|ext|month
  • renameBatch rename: --find, --replace, --name, --case; --preview
  • splitCut 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.com
  • readDecode 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.pdf
  • infoType, size, pages, dimensions, duration
  • findSearch commands by intent
  • schemaJSON Schema of a command's inputs and options
  • engineManage external programs such as ffmpeg and yt-dlp
  • skillPrint or install the agent skill
  • doctorCheck 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.

  1. git clone https://github.com/firstprayer/deft
  2. cd deft && cargo install --path crates/deft-cli --locked
  3. deft doctor
  4. deft skill install --agent allTeaches Claude Code and Codex that deft exists.
  • Release binariesPlanned
  • Install scriptPlanned
  • Homebrew tapPlanned
  • cargo install deftcliPlanned