markit-markdown-converter

Convert files, URLs, and media to markdown using the markit-ai CLI and SDK with pluggable converters and LLM support.

22 stars

Best use case

markit-markdown-converter is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Convert files, URLs, and media to markdown using the markit-ai CLI and SDK with pluggable converters and LLM support.

Teams using markit-markdown-converter should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/markit-markdown-converter/SKILL.md --create-dirs "https://raw.githubusercontent.com/Aradotso/trending-skills/main/skills/markit-markdown-converter/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/markit-markdown-converter/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How markit-markdown-converter Compares

Feature / Agentmarkit-markdown-converterStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Convert files, URLs, and media to markdown using the markit-ai CLI and SDK with pluggable converters and LLM support.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# markit-markdown-converter

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

markit converts almost anything to markdown: PDFs, Word docs, PowerPoint, Excel, HTML, EPUB, Jupyter notebooks, RSS feeds, CSV, JSON, YAML, images (with EXIF + AI description), audio (with metadata + AI transcription), ZIP archives, URLs, Wikipedia pages, and source code files. It works as a CLI tool and as a TypeScript/Node.js library, supports pluggable converters, and integrates with OpenAI, Anthropic, and any OpenAI-compatible LLM API.

---

## Installation

```bash
# Global CLI
npm install -g markit-ai

# Or as a project dependency
npm install markit-ai
# bun add markit-ai
# pnpm add markit-ai
```

---

## CLI Quick Reference

```bash
# Convert a file
markit report.pdf
markit document.docx
markit slides.pptx
markit data.xlsx
markit notebook.ipynb

# Convert a URL
markit https://example.com/article
markit https://en.wikipedia.org/wiki/Markdown

# Convert media (requires LLM API key for AI features)
markit photo.jpg
markit recording.mp3
markit diagram.png -p "Describe the architecture and data flow"
markit receipt.jpg -p "List all line items with prices as a table"

# Output options
markit report.pdf -o report.md          # Write to file
markit report.pdf -q                    # Raw markdown only (great for piping)
markit report.pdf --json                # Structured JSON output

# Read from stdin
cat file.pdf | markit -

# Pipe output
markit report.pdf | pbcopy
markit data.xlsx -q | some-other-tool

# List supported formats
markit formats

# Configuration
markit init                              # Create .markit/config.json
markit config show                       # Show resolved config
markit config get llm.model
markit config set llm.provider anthropic
markit config set llm.model claude-haiku-4-5

# Plugins
markit plugin install npm:markit-plugin-dwg
markit plugin install git:github.com/user/markit-plugin-ocr
markit plugin install ./my-plugin.ts
markit plugin list
markit plugin remove dwg

# Agent integration
markit onboard                           # Adds usage instructions to CLAUDE.md
```

---

## AI / LLM Configuration

Images and audio always get free metadata extraction. AI-powered description and transcription requires an API key.

```bash
# OpenAI (default)
export OPENAI_API_KEY=sk-...
markit photo.jpg

# Anthropic
export ANTHROPIC_API_KEY=sk-ant-...
markit config set llm.provider anthropic
markit photo.jpg

# OpenAI-compatible APIs (Ollama, Groq, Together, etc.)
markit config set llm.apiBase http://localhost:11434/v1
markit config set llm.model llama3.2-vision
markit photo.jpg
```

`.markit/config.json` (created by `markit init`):

```json
{
  "llm": {
    "provider": "openai",
    "apiBase": "https://api.openai.com/v1",
    "model": "gpt-4.1-nano",
    "transcriptionModel": "gpt-4o-mini-transcribe"
  }
}
```

Environment variables always override config file values. Never store API keys in the config file — use env vars.

| Provider    | Env Vars                              | Default Vision Model  |
|-------------|---------------------------------------|-----------------------|
| `openai`    | `OPENAI_API_KEY`, `MARKIT_API_KEY`    | `gpt-4.1-nano`        |
| `anthropic` | `ANTHROPIC_API_KEY`, `MARKIT_API_KEY` | `claude-haiku-4-5`    |

---

## SDK Usage

### Basic File and URL Conversion

```typescript
import { Markit } from "markit-ai";

const markit = new Markit();

// Convert a file by path
const { markdown } = await markit.convertFile("report.pdf");
console.log(markdown);

// Convert a URL
const { markdown: webMd } = await markit.convertUrl("https://example.com/article");

// Convert a Buffer with explicit type hint
import { readFileSync } from "fs";
const buffer = readFileSync("document.docx");
const { markdown: docMd } = await markit.convert(buffer, { extension: ".docx" });
```

### With OpenAI for Vision + Transcription

```typescript
import OpenAI from "openai";
import { Markit } from "markit-ai";

const openai = new OpenAI(); // reads OPENAI_API_KEY from env

const markit = new Markit({
  describe: async (image: Buffer, mime: string) => {
    const res = await openai.chat.completions.create({
      model: "gpt-4.1-nano",
      messages: [
        {
          role: "user",
          content: [
            { type: "text", text: "Describe this image in detail." },
            {
              type: "image_url",
              image_url: {
                url: `data:${mime};base64,${image.toString("base64")}`,
              },
            },
          ],
        },
      ],
    });
    return res.choices[0].message.content ?? "";
  },

  transcribe: async (audio: Buffer, mime: string) => {
    const res = await openai.audio.transcriptions.create({
      model: "gpt-4o-mini-transcribe",
      file: new File([audio], "audio.mp3", { type: mime }),
    });
    return res.text;
  },
});

const { markdown } = await markit.convertFile("photo.jpg");
```

### With Anthropic for Vision

```typescript
import Anthropic from "@anthropic-ai/sdk";
import OpenAI from "openai";
import { Markit } from "markit-ai";

const anthropic = new Anthropic(); // reads ANTHROPIC_API_KEY from env
const openai = new OpenAI();       // reads OPENAI_API_KEY from env

// Mix providers: Claude for images, OpenAI Whisper for audio
const markit = new Markit({
  describe: async (image: Buffer, mime: string) => {
    const res = await anthropic.messages.create({
      model: "claude-haiku-4-5",
      max_tokens: 1024,
      messages: [
        {
          role: "user",
          content: [
            {
              type: "image",
              source: {
                type: "base64",
                media_type: mime as "image/jpeg" | "image/png" | "image/gif" | "image/webp",
                data: image.toString("base64"),
              },
            },
            { type: "text", text: "Describe this image." },
          ],
        },
      ],
    });
    return (res.content[0] as { text: string }).text;
  },

  transcribe: async (audio: Buffer, mime: string) => {
    const res = await openai.audio.transcriptions.create({
      model: "gpt-4o-mini-transcribe",
      file: new File([audio], "audio.mp3", { type: mime }),
    });
    return res.text;
  },
});
```

### Using Built-in Providers via Config

```typescript
import { Markit, createLlmFunctions, loadConfig, loadAllPlugins } from "markit-ai";

// Reads .markit/config.json and env vars automatically
const config = loadConfig();

// Load any installed plugins
const plugins = await loadAllPlugins();

// Create instance with built-in providers + plugins
const markit = new Markit(createLlmFunctions(config), plugins);

const { markdown } = await markit.convertFile("report.pdf");
```

---

## Writing a Plugin

Plugins let you add new formats or override built-in converters. Plugin converters run before built-ins.

### Basic Converter Plugin

```typescript
// my-plugin.ts
import type { MarkitPluginAPI } from "markit-ai";

export default function (api: MarkitPluginAPI) {
  api.setName("my-format");
  api.setVersion("1.0.0");

  api.registerConverter(
    {
      name: "myformat",
      accepts: (info) => [".myf", ".myfmt"].includes(info.extension ?? ""),
      convert: async (input: Buffer, info) => {
        // info.extension, info.mimeType, info.fileName available
        const text = input.toString("utf-8");
        const markdown = `# Converted\n\n\`\`\`\n${text}\n\`\`\``;
        return { markdown };
      },
    },
    // Optional: declare so it appears in `markit formats`
    { name: "My Format", extensions: [".myf", ".myfmt"] },
  );
}
```

### Override a Built-in Converter

```typescript
// better-pdf-plugin.ts
import type { MarkitPluginAPI } from "markit-ai";

export default function (api: MarkitPluginAPI) {
  api.setName("better-pdf");
  api.setVersion("1.0.0");

  // Runs before built-in PDF converter, effectively replacing it
  api.registerConverter({
    name: "pdf",
    accepts: (info) => info.extension === ".pdf",
    convert: async (input: Buffer, info) => {
      // Custom PDF extraction logic
      const markdown = `# PDF Content\n\n(extracted with custom logic)`;
      return { markdown };
    },
  });
}
```

### Register a Custom LLM Provider

```typescript
import type { MarkitPluginAPI } from "markit-ai";

export default function (api: MarkitPluginAPI) {
  api.setName("gemini-provider");

  api.registerProvider({
    name: "gemini",
    envKeys: ["GOOGLE_API_KEY"],
    defaultBase: "https://generativelanguage.googleapis.com/v1beta",
    defaultModel: "gemini-2.0-flash",
    create: (config, prompt) => ({
      describe: async (image: Buffer, mime: string) => {
        // Call Gemini API here
        return "Image description from Gemini";
      },
    }),
  });
}
```

### Install and Use a Plugin

```bash
# Install from file
markit plugin install ./my-plugin.ts

# Install from npm
markit plugin install npm:markit-plugin-dwg

# Install from git
markit plugin install git:github.com/user/markit-plugin-ocr

# Verify
markit plugin list

# Remove
markit plugin remove my-format
```

---

## Common Patterns

### Batch Convert a Directory

```typescript
import { Markit } from "markit-ai";
import { readdirSync, readFileSync, writeFileSync } from "fs";
import { extname, basename, join } from "path";

const markit = new Markit();
const inputDir = "./docs";
const outputDir = "./docs-md";

const files = readdirSync(inputDir);
for (const file of files) {
  const ext = extname(file);
  if (![".pdf", ".docx", ".html"].includes(ext)) continue;

  const buffer = readFileSync(join(inputDir, file));
  const { markdown } = await markit.convert(buffer, { extension: ext });
  const outName = basename(file, ext) + ".md";
  writeFileSync(join(outputDir, outName), markdown);
  console.log(`Converted: ${file} → ${outName}`);
}
```

### Convert URL List

```typescript
import { Markit } from "markit-ai";

const markit = new Markit();
const urls = [
  "https://example.com/article-1",
  "https://example.com/article-2",
  "https://en.wikipedia.org/wiki/TypeScript",
];

const results = await Promise.all(
  urls.map(async (url) => {
    const { markdown } = await markit.convertUrl(url);
    return { url, markdown };
  })
);

for (const { url, markdown } of results) {
  console.log(`\n## ${url}\n\n${markdown.slice(0, 200)}...`);
}
```

### CLI in Agent/Automation Scripts

```bash
# Structured JSON for programmatic parsing
markit report.pdf --json

# Raw markdown for piping (no spinner, no extra output)
markit report.pdf -q > report.md

# Pipe into another CLI tool
markit https://example.com/article -q | wc -w

# Process multiple files in a shell loop
for f in docs/*.pdf; do
  markit "$f" -o "out/$(basename "$f" .pdf).md"
done
```

---

## Supported Formats Reference

| Format      | Extensions                              |
|-------------|-----------------------------------------|
| PDF         | `.pdf`                                  |
| Word        | `.docx`                                 |
| PowerPoint  | `.pptx`                                 |
| Excel       | `.xlsx`                                 |
| HTML        | `.html`, `.htm`                         |
| EPUB        | `.epub`                                 |
| Jupyter     | `.ipynb`                                |
| RSS/Atom    | `.rss`, `.atom`, `.xml`                 |
| CSV/TSV     | `.csv`, `.tsv`                          |
| JSON        | `.json`                                 |
| YAML        | `.yaml`, `.yml`                         |
| XML/SVG     | `.xml`, `.svg`                          |
| Images      | `.jpg`, `.png`, `.gif`, `.webp`         |
| Audio       | `.mp3`, `.wav`, `.m4a`, `.flac`         |
| ZIP         | `.zip`                                  |
| Code        | `.py`, `.ts`, `.go`, `.rs`, and more    |
| Plain text  | `.txt`, `.md`, `.rst`, `.log`           |
| URLs        | `http://`, `https://`                   |

Run `markit formats` to see the full live list including any installed plugins.

---

## Troubleshooting

**AI description/transcription not working**
- Ensure the correct env var is set: `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`
- Run `markit config show` to verify the resolved provider and model
- For custom API bases (Ollama, etc.), confirm the server is running and the model supports vision

**Plugin not loading**
- Run `markit plugin list` to confirm it's installed
- Check the plugin exports a default function matching `(api: MarkitPluginAPI) => void`
- Try reinstalling: `markit plugin remove <name>` then `markit plugin install <source>`

**PDF returns empty or garbled markdown**
- The built-in converter uses text extraction (not OCR). Scanned PDFs need an OCR plugin.
- Try a custom plugin or pre-process with an OCR tool first.

**Stdin (`markit -`) not working**
- Pipe content directly: `cat file.pdf | markit -`
- Ensure the file type can be detected from content; use explicit hints if needed.

**Config not being read**
- Config is loaded from `.markit/config.json` relative to the current working directory
- Run `markit init` to create it, then `markit config show` to verify

Related Skills

```markdown

22
from Aradotso/trending-skills

---

mdv-markdown-visualization

22
from Aradotso/trending-skills

MDV — Markdown superset for documents, dashboards, and slides with embedded charts, KPI stats, and data visualizations exported to HTML or PDF.

zeroboot-vm-sandbox

22
from Aradotso/trending-skills

Sub-millisecond VM sandboxes for AI agents using copy-on-write KVM forking via Zeroboot

yourvpndead-vpn-detection

22
from Aradotso/trending-skills

Android app that detects VPN/proxy servers (VLESS/xray/sing-box) via local SOCKS5 vulnerability, exposing exit IPs and server configs without root

xata-postgres-platform

22
from Aradotso/trending-skills

Expert skill for Xata open-source cloud-native Postgres platform with copy-on-write branching, scale-to-zero, and Kubernetes deployment

x-mentor-skill-nuwa

22
from Aradotso/trending-skills

AI-powered X (Twitter) content strategy skill that distills methodologies from 6 top creators + open-source algorithm data into actionable writing, growth, and monetization guidance.

wx-favorites-report

22
from Aradotso/trending-skills

End-to-end pipeline to extract, decrypt, and visualize WeChat Mac favorites from encrypted SQLite DB into an interactive HTML report.

wterm-web-terminal

22
from Aradotso/trending-skills

Web terminal emulator with Zig/WASM core, DOM rendering, and React/vanilla JS bindings

worldmonitor-intelligence-dashboard

22
from Aradotso/trending-skills

Real-time global intelligence dashboard with AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking

witr-process-inspector

22
from Aradotso/trending-skills

CLI and TUI tool that explains why processes, services, and ports are running by tracing causality chains across supervisors, containers, and shells.

wildworld-dataset

22
from Aradotso/trending-skills

WildWorld large-scale action-conditioned world modeling dataset with 108M+ frames from a photorealistic ARPG game, featuring per-frame annotations, 450+ actions, and explicit state information for generative world modeling research.

whatcable-macos-usb-inspector

22
from Aradotso/trending-skills

macOS menu bar app that identifies USB-C cable capabilities and charging diagnostics using IOKit