Post Output Formats

markata-go can generate multiple output formats for each post beyond the standard HTML. This enables use cases like providing raw markdown for API consumers, plain text for accessibility, ANSI terminal output for curl, or generating social media preview cards.

Configuration

Configure output formats in your markata-go.toml:

[markata-go.post_formats]
html = true       # Standard HTML (default: true)
markdown = true   # Raw markdown source (default: true)
text = true       # Plain text output (default: true)
ansi = true       # ANSI terminal output (default: false)
og = true         # OpenGraph card HTML (default: true)

By default, HTML, Markdown, plain text, and OG formats are enabled. ANSI output is opt-in so you can add rich terminal rendering without introducing escape sequences into existing .txt endpoints.

Per-Post Overrides

Site config sets the defaults, and individual posts can override them in frontmatter:

---
title: "Release Notes"
post_formats:
  markdown: false
  ansi: true
  og: false
---

Merge rules:

Available Formats

HTML (default)

The standard HTML output, generated by default.

Output: /your-post/index.html

[markata-go.post_formats]
html = true  # This is the default

Markdown

Outputs the raw markdown source with reconstructed frontmatter. Useful for: - "View Source" links on your site - API consumers who want raw content - Copy-paste workflows

Output: /your-post.md (canonical) with redirect from /your-post/index.md

[markata-go.post_formats]
markdown = true  # Enabled by default

The markdown output includes the original frontmatter:

---
title: "Your Post Title"
description: "Post description"
date: 2026-01-22
published: true
tags:
  - example
---

Your original markdown content...

Plain Text

Outputs a plain terminal-friendly version of the rendered page, perfect for: - Standard web txt files (robots.txt, llms.txt, humans.txt) - Screen readers and accessibility tools - Command-line readers (curl, wget) - Low-bandwidth situations - Text-based browsers

Output: /your-post.txt (canonical) with redirect from /your-post/index.txt

[markata-go.post_formats]
text = true  # Enabled by default

The text output includes terminal-safe structure derived from the rendered page: - Title, description, and date - Headings, links, emphasis, and separators - Image and video references as readable URLs - Blockquotes, admonitions, lists, and tables - Readable code blocks without ANSI escapes

Example output:

My Post Title
=============

A description of the post.

Date: January 22, 2026

The actual content of the post in plain text form...

ANSI Terminal

Outputs a richer terminal-first version of the rendered page with ANSI color and emphasis.

Output: /your-post.ansi (canonical) with redirect from /your-post/index.ansi

[markata-go.post_formats]
ansi = true  # Disabled by default; opt in when you want terminal styling

ANSI output uses the active site palette when possible and preserves terminal-friendly formatting for: - headings and emphasis - links and metadata - image and video references - blockquotes and admonitions - lists, rules, and tables - syntax-highlighted code fences

Use it with curl, less -R, or any ANSI-capable pager:

curl https://example.com/your-post.ansi
curl https://example.com/your-post.ansi | less -R
curl https://example.com/your-post.txt

/your-post.txt stays free of ANSI escape codes. /your-post.ansi is the explicit opt-in rich terminal variant.

OpenGraph Card (OG)

Generates a special HTML page optimized for screenshot tools to create social media preview images. The page is sized at 1200x630 pixels (standard OG image dimensions).

Output: /your-post/og/index.html

[markata-go.post_formats]
og = true

Using OG Cards for Social Images

The OG card HTML is designed to be captured by screenshot tools like Puppeteer or Playwright:

// Example with Puppeteer
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1200, height: 630 });
await page.goto('https://yoursite.com/your-post/og/');
await page.screenshot({ path: 'og-image.png' });

The default OG card template includes: - Post title (large, prominent) - Frontmatter media when present (image → cover_image → og_image → video, videos render as video tags) - Author name and site URL - Publication date - Theme palette and background styling

You can customize the OG card appearance by providing your own post-og.html template. If no post-specific OG template exists, og-card.html is used as a fallback.

Shared OG/Feed/Embed Media Helpers

OG cards, feed cards, and embed cards now share a media pipeline so the same image/video looks identical in every context. All three templates should:

Only relative URLs and media hosted on the safe domain allowlist receive the sizing/presenter treatment. The default allowlist includes dropper.wayl.one, dropper.waylonwalker.com, and dropper-dev.wayl.one, but you can add or override entries via [markata-go.templates.media] in your markata-go.toml. Untrusted hosts skip the extra query params and auto-generated posters so you stay in control of which domains get the richer metadata. Custom templates can still opt out entirely by using their own helpers instead of with_size/poster_url.

Standard Web Txt Files

markata-go supports generating standard web txt files at their expected canonical URLs:

File Purpose
/robots.txt Robot exclusion standard for web crawlers
/llms.txt AI/LLM guidance file for language models
/humans.txt Human-readable site credits

To create these, simply add markdown files with the appropriate slugs:

<!-- robots.md -->
---
title: "Robots"
slug: robots
published: true
---

User-agent: *
Allow: /
Disallow: /private/
<!-- llms.md -->
---
title: "LLMs"
slug: llms
published: true
---

# LLMs.txt

This site welcomes AI training on its content.

## Guidelines
- Attribution appreciated
- Commercial use allowed

With text format enabled (default), these generate: - /robots.txt - The canonical robots.txt file - /robots/index.txt - Redirect for backwards compatibility - /robots/index.txt/index.html - HTML redirect for static hosts - /llms.txt - The canonical llms.txt file - /llms/index.txt - Redirect for backwards compatibility - /llms/index.txt/index.html - HTML redirect for static hosts

Reversed Redirects

For .txt, .ansi, and .md formats, markata-go uses reversed redirects to ensure content is at the canonical URL:

Canonical Location Redirect From
/my-post.md /my-post/index.md
/my-post.txt /my-post/index.txt
/my-post.ansi /my-post/index.ansi

This is the opposite of HTML, which uses directory-based URLs:

Canonical Location Redirect From
/my-post/index.html /my-post.html

The reversed approach ensures standard web files like robots.txt work correctly while maintaining backwards compatibility with directory-based URLs.

Clean URLs

markata-go generates both canonical files and redirects for maximum compatibility:

User requests Canonical file Notes
/my-post.md /my-post.md Direct access to canonical
/my-post/index.md Redirects to /my-post.md Backwards compatibility
/my-post.txt /my-post.txt Direct access to canonical
/my-post/index.txt Redirects to /my-post.txt Backwards compatibility

This means users can use either URL style:

# All of these work:
curl https://example.com/my-post.md         # Canonical
curl https://example.com/my-post/index.md   # Redirects to canonical

# Standard web txt files work at expected URLs:
curl https://example.com/robots.txt
curl https://example.com/llms.txt

The redirects use HTML meta refresh for maximum compatibility across browsers and HTTP clients.

When you enable alternate formats, markata-go automatically displays format links on your posts and feeds. These appear in the post footer (for posts) or feed header (for feeds).

For posts with markdown, text, or og enabled, visitors see: - View as: Markdown | Text | Card

For feeds, visitors see subscription options: - Subscribe: RSS | Atom | JSON | Markdown | Text

Copying Posts for Chat and Notes

Post pages also expose a Copy this post control near the top of the article. It is designed for the common workflow of dropping a post into Slack, Teams, notes apps, or a code editor without manually selecting the page. Set components.post_copy.enabled = false to hide the menu without disabling the post-format files (see Configuration).

Available copy modes:

The rich option uses the browser clipboard API to write both text/html and text/plain payloads. When that API is unavailable, markata-go falls back to plain-text clipboard writes so copying still works in older browsers.

Content Negotiation

markata-go's canonical short URLs (/slug.md, /slug.txt) plus HTML directory pages (/slug/index.html) enable server-side content negotiation. This allows clients to request their preferred format using HTTP Accept headers.

How It Works

Instead of requesting a specific file, clients request the directory URL:

GET /my-post/
Accept: text/plain

The server returns the appropriate format based on the Accept header.

Nginx Configuration

server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    # MIME types for txt/md files
    location ~ \.(txt|md)$ {
        default_type text/plain;
        charset utf-8;
    }

    location / {
        # Try exact file first (for /robots.txt), then negotiate by Accept header
        try_files $uri $uri/index.html @negotiate;
    }

    location @negotiate {
        # Map Accept header to file extension
        set $ext "html";

        if ($http_accept ~* "text/plain") {
            set $ext "txt";
        }
        if ($http_accept ~* "text/markdown") {
            set $ext "md";
        }

        # Strip trailing slash for canonical format files
        set $base $uri;
        if ($base ~ "^(.+)/$") {
            set $base $1;
        }

        # Try the negotiated format, falling back to index.html
        try_files $base.$ext $uri/index.html =404;
    }
}

Note: The try_files order is important. Files like /robots.txt are served directly because $uri matches the exact file before falling back to content negotiation.

Caddy Configuration

example.com {
    root * /var/www/html
    file_server

    # MIME types for txt/md files
    @txtmd path *.txt *.md
    header @txtmd Content-Type "text/plain; charset=utf-8"

    @wantsText {
        header Accept *text/plain*
    }
    @wantsMarkdown {
        header Accept *text/markdown*
    }

    # Rewrite to plain text when requested
    handle @wantsText {
        uri strip_suffix /
        rewrite * {path}.txt
    }

    # Rewrite to markdown when requested
    handle @wantsMarkdown {
        uri strip_suffix /
        rewrite * {path}.md
    }

    # Try exact file first (for /robots.txt), then index.html
    try_files {path} {path}/index.html {path}.html
}

Note: Caddy's file_server naturally serves exact files first, so /robots.txt works correctly without additional configuration.

Apache Configuration

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/html

    # Enable content negotiation
    Options +MultiViews

    # Define type mappings
    AddType text/html .html
    AddType text/markdown .md
    AddType text/plain .txt

    # Set charset for text files
    AddDefaultCharset UTF-8

    # Prefer HTML by default
    DirectoryIndex index.html index.md index.txt

    # Ensure exact files are served first (for /robots.txt)
    <Directory /var/www/html>
        RewriteEngine On
        # If the exact file exists, serve it directly
        RewriteCond %{REQUEST_FILENAME} -f
        RewriteRule ^ - [L]
        # Otherwise fall through to MultiViews negotiation
    </Directory>
</VirtualHost>

Note: The RewriteCond %{REQUEST_FILENAME} -f rule ensures that canonical files like /robots.txt are served directly before MultiViews content negotiation kicks in.

Testing Content Negotiation

Use curl to test different formats:

# Request HTML (default)
curl https://example.com/my-post/

# Request plain text
curl -H "Accept: text/plain" https://example.com/my-post/

# Request markdown
curl -H "Accept: text/markdown" https://example.com/my-post/

# Request with quality values
curl -H "Accept: text/plain;q=0.9, text/html;q=0.8" https://example.com/my-post/

Homepage with index.md

markata-go provides special handling for index.md files to create homepages and directory-based URLs:

File Path Generated URL
./index.md / (homepage)
docs/index.md /docs/
blog/guides/index.md /blog/guides/

Creating a Homepage

Simply create an index.md file in your content root:

---
title: "Welcome to My Site"
description: "A personal blog about programming"
published: true
template: home.html
---

# Welcome

This is my homepage content...

This generates /index.html as your site's homepage, allowing custom content instead of requiring a feed with empty slug.

Directory Index Pages

Create index.md files in subdirectories for section landing pages:

docs/
  index.md          -> /docs/
  getting-started.md -> /docs/getting-started/
  guides/
    index.md        -> /docs/guides/
    advanced.md     -> /docs/guides/advanced/

Example Configuration

A typical configuration enabling all formats:

[markata-go]
url = "https://example.com"
title = "My Site"

[markata-go.post_formats]
html = true      # Standard pages
markdown = true  # View source support
text = true      # Plain text for accessibility
og = true        # Social card generation

Automation Example

Here's a complete workflow for generating social images:

  1. Enable OG format in your config: toml [markata-go.post_formats] og = true

  2. Build your site: bash markata-go build

  3. Generate screenshots with a script: bash #!/bin/bash for og_page in output/*/og/index.html; do post_dir=$(dirname $(dirname "$og_page")) slug=$(basename "$post_dir") npx puppeteer screenshot \ --viewport 1200x630 \ "file://$og_page" \ "$post_dir/og-image.png" done

  4. Reference in templates: html <meta property="og:image" content="{{ config.url }}{{ post.href }}og-image.png">

Upgrading homepage format outputs

Homepage Markdown and text are served from /index.md and /index.txt. Older builds could create redirect directories at these paths. Incremental builds automatically replace those generated directories with files. If a conflicting directory contains other content, the build stops and preserves it; inspect the reported path before moving that content or rebuilding into an empty output directory.

See Also