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:
- omitted keys inherit the site-wide
[markata-go.post_formats]setting - specified keys override only that post
- template-visible
config.post_formatsfollows the resolved per-post values, so alternate links and format switchers stay in sync with generated files
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:
- Call
with_size(width, height)on photo/video URLs so the generated media query string carries precisewandhvalues that align with the pixel dimensions the template renders. Accurate sizing prevents visual drift when downstream screenshot tools or clients ingest the card. Trusted media URLs are normalized tohttpsfirst to avoid mixed-content warnings. - Use
media_urlfor raw image metadata fields such as search thumbnails when you need the URL without sizing query parameters. - Use the query/fragment-safe
is_videofilter when deciding whether to render a<video>tag, and let theposter_urlhelper resolve the poster image. - Respect the poster alias precedence:
poster_image,poster,video_poster,video_thumbnail,thumbnail,thumb.poster_urlchecks those values first, and only when none are defined does it fall back to deriving a.webpthumbnail from the video URL on allowlisted hosts.
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.
Visible Format Links
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:
URL- copies the canonical post URL.Rich- copies HTML plus plain text so chat clients can preserve headings, links, and formatting when they support rich paste.Markdown- copies the post title, URL, and raw markdown body.Text- copies the post title, URL, and a plain-text rendering of the article.
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:
-
Enable OG format in your config:
toml [markata-go.post_formats] og = true -
Build your site:
bash markata-go build -
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 -
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
- Configuration Guide - Full configuration reference
- Templates Guide - Customizing templates including og.html
- Deployment Guide - Deploying your generated site