---
title: File Conversion
---

# File Conversion

## What it is

Omniscio can convert a file from one format to another **entirely on your machine** —
PDF to Markdown (plus Word, PowerPoint, OpenDocument, EPUB, RTF, and legacy Office
documents → Markdown), DOCX to PDF, images (PNG / JPEG / WebP / GIF / TIFF / SVG / AVIF,
HEIC iPhone photos → JPEG/PNG), audio/video (MP4 to MP3, video → animated GIF, a still
frame from a video, MKV / AVI, FLAC / Ogg / Opus / AAC / AIFF), data (CSV ↔ JSON ↔ YAML,
CSV → table), spreadsheets (Excel XLSX ↔ CSV/JSON, XLSX → Markdown/HTML), subtitles
(SRT ↔ VTT), and image → PDF — with optional quality/size controls and, in the app,
batch conversion of many files at once. No external service, no upload,
**no cost**, no AI tokens — the conversion runs locally.

It is **agent-first**: any AI session Omniscio spawns can convert a file as a native
capability with zero setup. For people there are two surfaces: a **one-click
"Convert to Markdown"** action for PDFs where you add them (a project's Auto Context
docs and chat attachments), and a full **File Converter** tool (in development) that
converts any supported format — both covered in "In the app" below. The File Converter
also has an optional **Download from web** mode — a **separate opt-in** you switch on in
Settings on top of the converter — where you paste a URL (YouTube, Vimeo, Loom, Twitter/X,
TikTok, Zoom, a direct media link) and Omniscio downloads it to your computer.

## Where to find it

### How an agent uses it

Every Omniscio-spawned agent is told in its system prompt that it can convert files. To
convert, the agent calls Omniscio's local control server:

```
POST http://127.0.0.1:19519/convert
Authorization: Bearer <token>        # the AMC_CLI_TOKEN env var, or ~/.amc/cli-token
Content-Type: application/json

{ "inputPath": "/abs/path/report.pdf", "to": "md" }     # optional: "outputPath", "options"
```

Response:

```
{ "ok": true, "outputPath": ".../report.md", "fromFormat": "pdf", "toFormat": "md", "bytes": 1234 }
```

The converted file is written **next to the original** (or at `outputPath`); it
**never overwrites** an existing file — on a name clash it writes a suffixed copy
(`report-1.md`). On failure the reply is `{ "ok": false, "error": "<friendly message>" }`.

**Quality/size options (optional).** Add an `"options"` object to control the output —
each value is clamped to a safe range: `imageQuality` (1–100, for jpeg/webp/avif),
`maxDimension` (px — scale an image down, aspect kept), `audioBitrateKbps` (for mp3/aac/
m4a/ogg/opus), `videoMaxHeight` (px — e.g. 720/1080). Omit `options` for the defaults.
Example: `{ "inputPath": "/abs/photo.png", "to": "jpeg", "options": { "imageQuality": 70, "maxDimension": 1920 } }`.

An agent can also **download media from a URL** the same way, via `POST /download`:

```
POST http://127.0.0.1:19519/download
Authorization: Bearer <token>        # the AMC_CLI_TOKEN env var, or ~/.amc/cli-token
Content-Type: application/json

{ "url": "https://www.youtube.com/watch?v=...", "mode": "audio" }   # mode: video | audio | original
```

The reply is `{ "ok": true, "outputPath": ".../Downloads/Title.mp3", "bytes": 1234, "title": "Title" }`.
The file lands in the user's **Downloads** folder (Omniscio chooses it — the caller sends only
`{ url, mode }` and can't redirect it); it never overwrites. `mode` is `video` (MP4),
`audio` (MP3, needs ffmpeg), or `original` (best available). Needs `yt-dlp` (and `ffmpeg`
for audio/best); a missing tool replies with a friendly "install it from Settings →
Connected Tools". Apply-immediately, shares the 10/min mutation bucket, kill switch
`AMC_DISABLE_URL_DOWNLOAD`.

### In the app: convert a PDF to Markdown

Two places surface a **"Convert to Markdown"** action when you add a PDF — both run
the same on-device engine ($0, private, text-only):

- **Project docs (Auto Context).** Right-click a PDF in a project's docs list →
  **Convert to Markdown**. A dialog asks whether to **Keep both** (leave the PDF,
  add the new `.md`) or **Replace PDF** (move the original to the trash _after_ a
  successful conversion). The new `.md` becomes auto-injected context like any other
  text doc, so every engine — not just Claude — reads it.
- **Chat attachments.** Attach or paste a PDF, then click the small convert button on
  its chip. The PDF is swapped for a pasted-text chip carrying the extracted Markdown,
  which sends inline with your message.

**Text-only, by design.** Extraction pulls the PDF's text layer — excellent for normal
PDFs, but a **scanned / image-only PDF yields little** (there is no OCR). On the
project-docs **Replace** path this is a hard safety: if extraction comes back empty the
original PDF is **never** deleted, so you can't lose the only copy.

### In the app: the File Converter tool

A standalone **File Converter** opens from the toolbar / window menu (and the mobile
header menu), or — on desktop — from its icon in the **projects rail**. It is **in
development** — hidden by default and revealed per-user via **Settings → Optional
Features** (the `fileConverterEnabled` toggle; it moved out of the experimental Lab
section on 2026-07-07, still in-development and off by default); turning it on adds its toolbar button and the
gated rail icon. On desktop it opens **inside the main workspace, not as a full-screen
takeover** — your projects sidebar stays on the left, the **Recent conversions**
history takes the sessions-sidebar slot, and the converter fills the main panel; you
leave it by clicking another project (there's no close button). On a phone it fills
the screen with the history stacked below.
Before you pick anything, the landing screen shows a **"What you can convert"** summary —
each format group (**Documents / Data / Images / Audio & Video / Subtitles**) on its own row
with the input formats it accepts shown as chips, plus a **"Show what each turns into"**
toggle that expands the full per-format detail (e.g. "MP4 video → MP3 audio, WAV audio, WebM
video") on demand — read live from the engine so it always matches what's actually possible.
Once open, pick with **Choose files** — one file or several at once (or drop a single file
onto it). One file shows only the formats it can actually become — same grouping — you pick
one and hit **Convert**; picking several routes into the batch flow (below).

- **Desktop** — a file chosen with **Choose files** converts straight off disk and writes
  the new file **next to the original** (never overwriting); the result shows the path with
  **Copy path**, **Open**, and **Show in folder** buttons. A **dropped** file converts and
  **downloads** instead (for security, a dropped file is handled by its contents, not its
  location) — so use **Choose files** to save next to the original or to convert a very large
  file. **Open** previews the result **inside Omniscio** for the
  formats it can render — Markdown, plain text, HTML, and images (PNG / JPEG / WebP / GIF /
  SVG) — and hands everything else (PDF, Word, audio, video, and TIFF, which a browser
  can't draw inline) to your computer's **default app**; **Show in folder** reveals it in
  your file manager. Omniscio will only ever open a file **it just converted** (an internal
  allow-list blocks any other path), so the screen can't be tricked into opening something
  else on your computer.
- **Mobile / web** has no filesystem, so the file's bytes are sent over the connection,
  converted, and the result **downloads** in the browser. Because of how the phone talks
  to the app, mobile is capped at roughly **9 MB in / 5 MB out** — a bigger file (e.g. a
  long video) is desktop-only, and you get a clear "convert it on your computer" message.

It runs the **same on-device engine** as the agent route ($0, private, no AI tokens) and
only ever offers conversions the engine can really do.

The converter sits beside a **"Recent conversions"** history — a sidebar on desktop,
stacked below the converter on a phone. Every conversion you run is remembered **on that
device** (it survives an app restart, keeps the latest ~50, and doesn't sync to other
devices). Click a past row to re-open its result — with the same **Open / Show in folder**
buttons — and **Clear** forgets the list (with a confirm + Undo) without touching the
converted files themselves.

### In the app: download from the web

The File Converter has a second mode — a **Convert a file / Download from web** switch at
the top (**desktop only**). Pick **Download from web**, paste a link — **YouTube, Vimeo,
Loom, Twitter/X, TikTok, Zoom**, a direct media link, and the 1000+ other sites `yt-dlp`
supports — choose **Video (MP4)**, **Audio only (MP3)**, or **Best available**, and hit
**Download**. The file is fetched with `yt-dlp` and saved to your **Downloads** folder
(never overwriting — a name clash writes a suffixed copy); the result shows the path with
a **Copy path** button.

- **A separate opt-in (off by default).** The downloader is turned on independently of the
  File Converter — enable **"File Converter — Download from web"** in **Settings → Features**.
  With it off, the File Converter is **conversion-only** and this tab isn't shown. It's kept
  apart from conversion on purpose: downloading from YouTube / TikTok / etc. is a terms-of-service
  - copyright surface unrelated to converting your own files.
- **Desktop only.** A download lands a real file on disk, so the tab is hidden on mobile
  (a phone can't receive a large video over the mobile size cap).
- **Public videos only.** Omniscio does **not** read your browser or sign you in, so private /
  login-only videos can't be downloaded — you'll get a clear "this needs a sign-in or
  passcode" message rather than a mysterious failure.
- **Passcode field (optional).** For a **Zoom** cloud recording or another
  password-protected link, type its passcode into the **Passcode** box and Omniscio unlocks the
  download with it. Leave it blank for public videos.
- **It stays up to date by itself (Windows).** Download sites like TikTok and Twitter/X
  change constantly, so Omniscio keeps its own copy of the `yt-dlp` engine and refreshes it in
  the background (verified by checksum) — so these keep working instead of breaking over
  time. If a refresh can't run (offline, or your antivirus blocks it) Omniscio quietly falls
  back to the `yt-dlp` on your system; nothing breaks. Kill switch:
  `AMC_DISABLE_YTDLP_AUTOUPDATE=1`.
- **Single video per link** — a playlist URL downloads just the one video you pasted, not
  the whole playlist.
- **Download only what you have the right to.** This is a neutral utility for media you're
  entitled to — your own uploads and recordings, public-domain or licensed content. Respect
  each site's terms of service and copyright; it does not strip DRM or bypass paywalls.
- **Safe by construction** — the link is validated (a public `http`/`https` address) and
  `yt-dlp` runs in a sandboxed child process (no shell), with a size cap and a generous
  timeout so a giant or stuck download can't run away; a failed/partial download cleans
  itself up. Kill switch: `AMC_DISABLE_URL_DOWNLOAD=1`.
- **Also drivable from the CLI** — agents and scripts can trigger a download with
  `POST http://127.0.0.1:19519/download` and a JSON body `{ url, mode }`, mirroring
  `/convert` (apply-immediately, bearer-auth; MAIN binds the Downloads destination — the
  caller sends only `{ url, mode }`). See "How an agent uses it" below.

## How it behaves

### Supported conversions

- **Documents** — Markdown, HTML, PDF, DOCX, plain text. Direct and chained routes:
  `md↔html`, `html→pdf`, `html→docx`, `docx→html/text`, plus `md→pdf`, `md→docx`,
  `docx→pdf` (chained through HTML).
- **Documents → Markdown (high-fidelity on-device reader)** — **Word** (`.docx`, `.doc`),
  **PowerPoint** (`.pptx`, `.ppt`), **OpenDocument** (`.odt`, `.ods`, `.odp`), **EPUB**,
  **RTF**, and legacy Excel (`.xls`) all convert **to Markdown**, with clean GFM tables.
  `docx→md` and `pdf→md` run through this reader for higher fidelity and automatically
  fall back to the built-in extractor if it can't read a file — so nothing regresses. (PDF
  tables still flatten — a PDF has no reliable table grid — and a scanned/image-only PDF
  needs OCR, which this on-device reader does not do.)
- **Data** — CSV, JSON, YAML. `csv→json` / `csv→md` / `csv→html` (Markdown & HTML
  tables), `json→csv`, `json↔yaml`, plus `csv→yaml` / `yaml→csv` (chained through JSON).
- **Spreadsheets** — Excel **XLSX** ↔ CSV/JSON, and `xlsx → md/html` tables (reads the
  first sheet; runs fully on-device). Legacy `.xls` and OpenDocument `.ods` also convert
  **to Markdown** via the document reader above.
- **Images** — PNG, JPEG, WebP, GIF, TIFF, AVIF (any ↔ any), plus **HEIC** (Apple
  iPhone photos) → JPEG/PNG, SVG → PNG/JPEG, and **image → PDF** (PNG/JPEG direct;
  any other raster via PNG).
- **Audio** — MP3, WAV, M4A, FLAC, Ogg, **Opus**, AAC, AIFF — any audio ↔ any audio.
- **Video** — MP4, MOV, WebM, MKV, AVI — any video ↔ any video; extract the audio
  (any video → any audio); **video → animated GIF** (MP4/MOV/WebM) and **GIF → video**;
  **grab a still frame** (any video → PNG/JPEG).
- **Subtitles** — SRT ↔ VTT (caption format swap; VTT→SRT drops VTT-only styling /
  positioning and renumbers cues).

The engine picks the route automatically: a direct converter when one exists, or a
safe two-step chain (so `md→pdf` runs `md→html→pdf`, `csv→yaml` runs `csv→json→yaml`).

**Quality & size options.** For any conversion you can control the output — image
quality and max size, audio bitrate, video resolution. In the File Converter tool an
**Options** panel shows only the knobs that apply to your chosen format; agents pass an
`"options"` object to `/convert` (see above). Omit them for sensible defaults.

**Batch (desktop).** The main **Choose files** button takes **several files at once** — pick
more than one and it batches them: choose one target format and it converts them all — saved
next to their originals — with a per-file result list (Open / Show in folder on each). Up to
100 files at a time; one file failing never stops the rest. (Batch uses the file picker, not
drag-and-drop — for security a dropped path carries no access token; dropping several files
shows a one-click **Choose several files** action that opens the picker.)

### Requirements

Documents, images (including **HEIC**), and subtitles work out of the box — no system
dependency (HEIC decoding ships as a bundled WebAssembly codec). **Audio and video
need `ffmpeg`** on your system (the same dependency the screen recorder uses). If it
is missing, the conversion returns a clear message to install it from **Settings → Connected Tools**.

**Download from web needs `yt-dlp`** (and `ffmpeg` for the MP3/best modes). On **Windows**
Omniscio fetches and maintains its own up-to-date copy of `yt-dlp` automatically (in the
background, verified by checksum), so you usually don't need to install it — and it stays
current as download sites change. `ffmpeg` (and `yt-dlp` on macOS/Linux) come from
**Settings → Connected Tools** (one-click install). If a needed tool is missing you get a clear
message naming it (you may need to restart Omniscio after installing so it's picked up on the
PATH).

### Safety & cost

- **Free + private** — runs entirely on your machine; files never leave it; no AI tokens.
- **Non-destructive** — only ever creates a NEW file; never deletes or overwrites your originals.
- **Bounded** — an input-size cap, a per-conversion timeout, a small concurrency gate,
  and per-format guards against malicious **"expansion bombs"** (a tiny crafted file that
  would blow up into gigabytes — e.g. a YAML alias/anchor bomb, an SVG declaring enormous
  dimensions, or a zip-container document like `.pptx`/`.odt`/`.epub`) stop a job from
  running away or freezing the app; an over-the-line file fails
  with a friendly message instead. Kill switch `AMC_DISABLE_FILE_CONVERSION=1`.

### Limitations (this version)

- The general drag-and-convert UI — the **File Converter** tool — is **in development**
  (gated behind `fileConverterEnabled`, in Settings → Features), and its
  **Download from web** tab is a further **separate opt-in** (`webMediaDownloadEnabled`, also in
  Settings → Features, off by default); the always-on in-app convert action is
  **PDF→Markdown** (project docs + chat, above).
- Office / OpenDocument / EPUB / RTF files convert **to Markdown only** — they're read as
  a source, not produced as an output (you can't convert _to_ `.pptx`/`.odt`/etc.).
- **Conversion** takes a local file (the agent `/convert` route and the convert UI both
  work on a path/bytes, not a URL). To pull media FROM a URL, use the **Download from web**
  UI (desktop) or the `POST /download` CLI route — both fetch a public link into Downloads.
- Lossy conversions are best-effort: PDF→text drops layout, and a scanned (image-only)
  PDF has no extractable text (no OCR in this version).

---

_For agents with repo access:_ the engine is in
`src/main/services/conversion/`, exposed via the
`POST /convert` CLI route and the `CONVERT_FILES_SHIM` spawn-prompt fragment in
`src/main/process/spawn-build.ts`. Invariants + tests: the engine in
`file-conversion-contract.md`,
the user-facing File Converter tool in
`file-converter-contract.md`.

## Related

Converting is one of the local utilities an agent can reach through the CLI control surface; the same surface is what backs [heap snapshot diagnostics](heap-snapshot-diagnostics.md) and the other agent-facing tools.
