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, 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)
og = true         # OpenGraph card HTML (default: true)

By default, all post formats are enabled. This allows standard web txt files like robots.txt, llms.txt, and humans.txt to work out of the box while also providing social sharing cards.

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 text version of the content, 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:

  • Title (underlined with =)
  • Description (if present)
  • Date
  • Raw markdown content

Example output:

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

A description of the post.

Date: January 22, 2026

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

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)
  • 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.

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 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

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

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:

    [markata-go.post_formats]
    og = true
    
  2. Build your site:

    markata-go build
    
  3. Generate screenshots with a script:

    #!/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:

    <meta property="og:image" content="{{ config.url }}{{ post.href }}og-image.png">
    

See Also #