mach
A CLI tool that converts Markdown files to rich text and copies the result to your system clipboard. Paste formatted text directly into emails, Slack messages, Google Docs, or any app that supports rich text.
Installation
make build
# binary is at ./build/mach
# or install to /usr/local/bin:
bash install.sh
Usage
mach <file> [flags]
Convert a Markdown file and copy to clipboard:
mach notes.md
Also display the RTF output in the terminal:
mach notes.md -d
Write an RTF file next to the input (e.g. notes.md → notes.rtf):
mach notes.md -o
Write to a specific path:
mach notes.md -o=/tmp/output.rtf
Flags
| Flag | Description |
|---|---|
-i |
Input format (default: md) |
-t |
Output format (default: rtf) |
-o |
Output to file; -o derives path from input, -o=path writes to path |
-d |
Display converted text in terminal |
-v |
Print version |
Config
Optional config file at ~/.config/mach/config.json:
{
"input_type": "md",
"output_type": "rtf"
}
Flag values override config values.
Supported Markdown
- Headings (H1–H6)
- Bold, italic, strikethrough
- Inline code and fenced code blocks
- Ordered and unordered lists
- Task lists (
- [x]/- [ ]) - Blockquotes
- Links (rendered as clickable hyperlinks)
- Tables (GFM)
- Horizontal rules
- Images (rendered as
[image: alt text]placeholder)
Technical Details
Conversion Pipeline
mach uses goldmark to parse Markdown into an AST, then walks the tree with a custom renderer that emits RTF directly. There is no intermediate HTML-to-RTF conversion and no dependency on external tools like textutil or pandoc. The RTF renderer is pure Go.
For clipboard, a second pass converts the Markdown to HTML using goldmark's built-in HTML renderer. Both formats are placed on the clipboard so that every app gets the type it expects.
Dependencies
Clipboard: OS Differences
The clipboard is the only OS-specific code in the project. No build tags are used; the binary is cross-platform via a runtime.GOOS switch.
macOS — Uses a small Swift snippet executed via swift - that writes to NSPasteboard. Three pasteboard types are set:
| Type | Purpose |
|---|---|
public.html |
Web apps (Slack, Gmail, Google Docs) |
public.rtf |
Native apps (TextEdit, Word, Pages) |
public.utf8-plain-text |
Plain text fallback (required by Electron apps like Slack) |
pbcopy is not used because it can only set plain text — it has no way to specify the pasteboard type.
Linux — Uses xclip to set clipboard content with text/html MIME type. xclip must be installed (sudo apt install xclip).
Build
Version is stored in the VERSION file and injected at build time via ldflags:
go build -ldflags "-X mach/cmd.Version=$(cat VERSION)" -o build/mach .
The Makefile handles this automatically with make build.