margo

package module
v0.0.23 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: MIT Imports: 51 Imported by: 0

README

Margo

Margo, a pink Go gopher holding a rendered document in a publishing atelier.

Margo turns Markdown into standalone HTML, linked static sites, PDF documents, and versioned Margo Marpit-compatible presentation decks. Use one margo command from a terminal or the root Go module from an application. Applications retain ownership of URLs, navigation, storage, and deployment.

Install

Margo requires Go 1.27.0 or newer:

go install github.com/araihu/margo/cmd/margo@latest
# Or pin a root release:
go install github.com/araihu/margo/cmd/margo@vX.Y.Z

Starting with v0.0.3, each root GitHub Release provides prebuilt archives for Linux, macOS, and Windows on amd64 and arm64. Download the archive for your platform, verify it against checksums.txt, extract it, and place margo or margo.exe on PATH.

Release binaries use CGO_ENABLED=0. They discover an installed Chromium when PDF output needs it; they do not download a browser or load native WebKit libraries.

Start with the CLI

Create docs/index.md:

---
title: My first Margo site
language: en
---

# My first Margo site

Edit this file and watch the browser reload.

Start the development server:

margo serve ./docs --open

Margo recursively discovers Markdown, builds the site in memory, chooses an available local port, and reloads connected browsers after successful changes. The development server is not for production.

Build the same tree for publication when it is ready:

margo site ./docs --output-dir ./dist

The destination must not already exist. A successful build writes linked HTML pages, local assets, and margo-manifest.json to dist.

For one document instead of a site:

margo check docs/index.md
margo html docs/index.md --output index.html
margo pdf docs/index.md --output document.pdf

html produces a standalone page. PDF output requires a supported installed Chromium executable; margo doctor reports available engines.

Raw HTML and iframe markup are denied by default. For a trusted documentation build that intentionally embeds HTML, opt in explicitly at the command boundary, for example margo serve ./docs --allow-unsafe-html or margo site ./docs --allow-unsafe-html. The alias --allow-raw-html is also accepted. The switch is not persisted in document frontmatter or policy JSON; each consuming application must review that security decision.

Start with the Go library

Install the root module:

go get github.com/araihu/margo@latest

Compile Markdown, render it, and write a standalone HTML page:

package main

import (
	"context"
	"log"
	"os"

	"github.com/araihu/margo"
)

func main() {
	ctx := context.Background()
	compiler := margo.New()

	document, err := compiler.Compile(ctx, margo.Source{
		Name:    "hello.md",
		Content: []byte("---\ntitle: Hello\nlanguage: en\n---\n\n# Hello\n"),
	})
	if err != nil {
		log.Fatal(err)
	}

	rendered, err := compiler.Render(ctx, document)
	if err != nil {
		log.Fatal(err)
	}

	page, err := margo.RenderStandalone(rendered)
	if err != nil {
		log.Fatal(err)
	}
	if err := page.Render(ctx, os.Stdout); err != nil {
		log.Fatal(err)
	}
}

The equivalent Go opt-in is margo.New(margo.WithUnsafeHTML()). It passes through document-authored HTML, including arbitrary iframes, so only enable it for content and hosts you trust.

Use margo.Check for the same preflight available through margo check. Supply margo.WithCheckAssetReader when checks must read local assets. Charts remain opt-in for library consumers:

compiler := margo.New(margo.WithExtension(charts.Extension()))
Choose an output from Go

The root module is the compiler and semantic renderer; it is not a single Convert function and it does not own a filesystem or HTTP server. Compile and render once, then choose the projection your host owns:

Need Public package and entrypoint Host responsibility
One standalone HTML document margo.RenderStandalone Write or serve the rendered component
A composed HTML page margo.RenderHTML and margo.RenderHTMLPage Mount the declared dependency handlers and own the shell
A linked site site.Build or site.BuildConfig Supply sources/config, write Result.Artifacts, and deploy
A PDF pdf/chromium.New and pdf.Engine.Export Select an installed Chromium executable and pass the runtime descriptor
A presentation deck.Render, then the PDF engine for PDF output Use the versioned deck profile and validate the selected geometry

site.Build returns exact, sorted artifacts without writing them. A minimal caller-owned publication loop looks like this:

package main

import (
    "context"
    "log"
    "os"
    "path/filepath"

    "github.com/araihu/margo"
    "github.com/araihu/margo/site"
)

func main() {
    ctx := context.Background()
    result, err := site.Build(ctx, site.Request{
        SourceRoot: ".",
        Sources:    []site.Source{{Path: "guide.md", Content: []byte("# Guide\n")}},
        Compiler:   margo.New(),
        Assets:     site.AssetsInline,
    })
    if err != nil {
        log.Fatal(err)
    }
    for _, artifact := range result.Artifacts {
        filename := filepath.Join("dist", filepath.FromSlash(artifact.Path))
        if err := os.MkdirAll(filepath.Dir(filename), 0o755); err != nil {
            log.Fatal(err)
        }
        if err := os.WriteFile(filename, artifact.Content, 0o644); err != nil {
            log.Fatal(err)
        }
    }
}

The site CLI adds the exact margo-manifest.json, staging, and no-replace publication behavior around this lower-level API. For programmatic PDF output, render the standalone component into bytes, obtain a validated descriptor with rendered.RuntimeDescriptor("ri-00000001"), create an engine with an explicit installed browser path, and call Export with a non-empty execution ID such as margo.ExecutionID("pdf-guide-1"). The versioned PDF package documentation and versioned Chromium engine documentation show the renderer-neutral request fields. deck.Render follows the same compile/render boundary and exposes Result.RuntimeDescriptor for a PDF projection. The CLI remains the shortest path when the host does not need to own these lifecycle seams.

The complete PDF handoff is small enough to keep in an application helper:

var html bytes.Buffer
page, err := margo.RenderStandalone(rendered)
if err != nil {
    return err
}
if err := page.Render(ctx, &html); err != nil {
    return err
}
descriptor, err := rendered.RuntimeDescriptor("ri-00000001")
if err != nil {
    return err
}
engine, err := chromium.New(chromium.Config{ExecutablePath: os.Getenv("MARGO_CHROMIUM_PATH")})
if err != nil {
    return err
}
result, err := engine.Export(ctx, pdf.Request{
    HTML: html.Bytes(), Runtime: descriptor,
    ExecutionID: margo.ExecutionID("pdf-guide-1"),
    Page: pdf.PageConfig{Size: pdf.PageA4, Orientation: pdf.Portrait,
        Margins: pdf.Margins{Top: 24, Right: 22, Bottom: 26, Left: 22}},
})
if err != nil {
    return err
}
return os.WriteFile("guide.pdf", result.PDF, 0o644)

The snippet assumes the surrounding function imports bytes, os, github.com/araihu/margo/pdf, and github.com/araihu/margo/pdf/chromium. MARGO_CHROMIUM_PATH must point to an installed executable; an empty value is rejected rather than downloaded or silently replaced.

Use go doc github.com/araihu/margo, go doc github.com/araihu/margo/site, go doc github.com/araihu/margo/pdf, and go doc github.com/araihu/margo/deck against the exact module version in your go.mod; the package comments contain the supported lifecycle and security boundary. Build the CLI explicitly with go build -o margo ./cmd/margo. go build . builds the root library archive, not the margo executable.

Build static sites

margo site and margo serve accept either a Markdown directory or a site configuration file.

Use the defaults

Point either command at a directory tree to discover .md and .markdown files recursively:

margo serve ./docs
margo site ./docs --output-dir ./dist

Directory builds map source files to .html, validate Markdown links and fragments, and use local assets by default. Use --assets inline when each generated page should embed its dependencies.

Configure a publication

Add site.yaml when the site needs explicit identity, navigation, themes, layout composition, locales, a base URL, or a base path. serve automatically uses site.yaml from its input directory. Name the config explicitly with site:

margo serve .
margo serve ./site.yaml --open
margo site ./site.yaml

Configured sites take their source, output, asset, and publication settings from the file and also produce sitemap.xml and llms.txt. The configured output defaults to dist when omitted. See showcase.yaml for a complete configuration.

Site builds project authors, publishedAt, modifiedAt, and tags into semantic article metadata and into each page record in the site report and margo-manifest.json. Archive, tag, RSS, and Atom pages remain consumer-owned; the deterministic route records are the input for those indexes.

Semantic layouts and documentation families

Configured sites can opt into semantic page layouts and documentation families. The site selects one trusted layout kind: article, landing, or docs. Page content never names a raw frame, shell, executable command, or Go module. Only docs owns navigation chrome, search, sidebars, tables of contents, pagination, and documentation families.

The configuration shape is:

layout:
  kind: docs
  default:
    families: [module, cli]
    sidebar: true
    toc: true
    content:
      layout: article
  values:
    family: default

layout.default declares site-only defaults for the selected kind. layout.values applies the site-level override patch. A directory can select a declared docs family in _layout.yaml:

values:
  family: module

The reserved _layout.yaml file is discovered from the source root through the page's nearest directory and is never published. A Markdown page can apply the final patch through top-level frontmatter:

---
layout:
  kind: landing
---

Resolution order is site defaults, directory patches from root to nearest, then Markdown frontmatter. Within one kind, maps merge recursively, scalars replace, and arrays replace completely. Changing kind creates a typed boundary: values from another kind do not cross it. Unknown kinds, properties, values, or docs families fail in preflight before artifacts are emitted.

Docs families are declared centrally by layout.default.families. Directory and Markdown patches can select a family but cannot declare one. default always exists, family order controls secondary navigation, and non-default families must own at least one docs page. Landing and article pages have no family identity.

The landing layout is for a conversion-oriented page: it has no sidebar, table of contents, breadcrumbs, pagination, or page-action toolbar. The docs layout provides family-local navigation, document context, and scoped pagination when neighbors exist. The Margo showcase publishes Tour at /, Module at /module/, the CLI overview at /cli/, and one CLI command page under /cli/COMMAND/ for each documented command. Static artifacts remain directory index.html files, while public links, canonicals, search, family navigation, sitemap, llms.txt, and rewritten Markdown use the directory routes, including base-path and locale prefixes. The former root feature pages are retired. Retired Tour feature routes return HTTP 404, produce no artifacts, and have no redirect or hidden compatibility page.

Sites without layout retain existing top-level frame or shell behavior. Existing componentdocshell consumers remain supported. Typed layout is mutually exclusive with those top-level presentation authorities.

Add page actions

Pages can opt into source and download controls through frontmatter:

margo:
  actions:
    markdown: true
    pdf: true

markdown: true retains the source beside the generated page and adds Copy page and View as Markdown actions. pdf: true also publishes a pre-rendered PDF and adds Download PDF. PDF publication implies Markdown retention.

To include the exact, accessible chart-data tables in a pre-rendered PDF, use the object form of the PDF action. Its mode defaults to pre-rendered:

margo:
  actions:
    pdf:
      printChartData: true

The boolean and string forms remain unchanged. printChartData is only valid for pre-rendered PDFs; client printing follows the browser's print behavior.

Use the browser's current page instead of publishing a PDF artifact:

margo:
  actions:
    pdf: client

Client printing follows the active site theme. Pre-rendered PDFs use the materialized document brand and stay independent of the surrounding site shell. Generated actions refer only to same-site artifacts.

Development server behavior

margo serve [INPUT_DIR|CONFIG] [--host HOST] [--port PORT] [--open] builds, watches, and serves a site from memory with live reload. With no input it uses the current directory. A directory containing site.yaml uses that config; another directory uses Margo's default linked-site output. Explicit config files must end in .yaml or .yml.

The server binds 127.0.0.1 by default. Without --port, it tries 8080, 8000, 3000, 1313, and 4000 before asking the operating system for any available port. After the preferred list is exhausted, the operating system selects any available port. An explicit port is strict and fails when it cannot be bound. --open opens the chosen URL in the default browser.

Margo watches configured Markdown, YAML, CSS, images, and other local assets recursively. For configured sites, only the source tree, site config, and declared local asset roots are watched; unrelated top-level siblings are ignored, including conventional build-output, log, report, and temporary directories such as build/ and screenshots/. A successful rebuild atomically replaces the in-memory snapshot and reloads connected browsers. A failed rebuild prints diagnostics and keeps serving the last successful site. The configured output directory is excluded from watching and is never written by serve.

The development server has no TLS, authentication, authorization, rate limiting, or deployment contract. Binding a non-loopback --host exposes the content and prints a warning. Do not use it in production.

Reference

Documentation map and upstreams

Start at the published Margo guide, then choose the CLI workflows or Go module guide. The command pages are executable references: each one pairs the installed margo COMMAND --help surface with a copyable fixture. The repository README is the portable version of that guide for offline or GitHub-first discovery.

Margo is an adapter and policy boundary around upstream projects, not a fork of their public contracts:

Upstream Where it influences Margo What Margo pins or constrains
Goldmark CommonMark parsing and fenced extensions Margo's normalized semantic document and closed metadata
Goshtoso Accessible document components, themes, tokens, and shell primitives Host-owned composition and Margo-scoped document styles
Goshtoso Charts Optional goshtosochart extension and exact-data tables Explicit opt-in registration and static deck projection
Muamba Build-time asset materialization and provenance Locked runtime assets; no runtime download
Mermaid Embedded diagram runtime for Mermaid fences Vendored version/configuration and sanitized SVG profile
templ Go component rendering Margo's semantic fragment and dependency contracts
Chromedp / Chromium Browser validation and PDF export Explicit installed executable; no browser download or silent fallback
Marpit Vocabulary inspiration for the deck projection Versioned Margo profile, not universal Marpit compatibility

The authoritative dependency versions are in go.mod; the repository's design record explains the boundaries and rejected alternatives. An upstream release can change Margo only through an intentional dependency or profile update, followed by the compatibility and browser gates.

Themes, policies, and IDE validation

Themes are host configuration, not document capabilities. A configured site selects a built-in modern theme or declares a local theme entry with css_url and token_catalog; the deck profile accepts only its built-in modern, goshtoso, and minimal catalog. Start with the site theme example and deck theme rules, then run margo check before publishing. Arbitrary CSS, remote backgrounds, and unknown token names are rejected before artifacts are written.

Policies are trusted host input. Create a JSON file with "schemaVersion": "margo-policy/v1", validate it in an IDE against margo schema policy, and pass it with --policy to check, html, site, pdf, or deck. A policy can authorize only the exact HTTPS iframe origins, sanitized raw HTML profile, resource ceilings, and per-target projections it declares; frontmatter cannot elevate it. The policy guide and generated reference document every field, default, limit, and security effect.

For site.yaml, emit margo schema site once per installed binary and attach the resulting file to the YAML language server as a JSON Schema. For Markdown frontmatter, attach margo schema document; for policy JSON, attach margo schema policy. These schemas describe field names and types for editor completion, while margo check and margo site remain the authority for cross-file checks such as missing assets, route links, duplicate locales, and theme availability.

CLI commands

margo check INPUT [--target html|site|pdf|deck] [--allow-unsafe-html]
margo html INPUT [--output PATH|-] [--force] [--allow-unsafe-html]
margo site INPUT_DIR|CONFIG [--output-dir OUTPUT_DIR] [--assets local|inline] [--allow-unsafe-html]
margo serve [INPUT_DIR|CONFIG] [--host HOST] [--port PORT] [--open] [--allow-unsafe-html]
margo pdf INPUT --output PATH|- [PDF flags] [--allow-unsafe-html]
margo deck INPUT [--format html|pdf] [--output PATH|-] [PDF flags] [--allow-unsafe-html]
margo doctor
margo version
margo --version
margo help [command]
margo completion SHELL [--no-descriptions]
margo schema policy
margo schema document
margo schema site
margo schema doctor-report
margo schema check-report
margo schema runtime-descriptor
margo schema runtime-report
margo schema deck-layout-evidence
margo schema deck-pdf-artifact-report

INPUT for check, html, pdf, and deck is a path or - for stdin. site takes a directory or YAML configuration, not stdin. Commands write artifacts and command reports to stdout; errors and diagnostics go to stderr. --diagnostics text is the default, while --diagnostics json selects JSON. Errors exit nonzero. Warnings remain visible without blocking check.

html writes to stdout by default. deck defaults to HTML on stdout. pdf and deck --format pdf require --output PATH or --output -. html, pdf, and deck refuse to replace existing output unless --force is present. Directory-based site builds require --output-dir; configured builds use the config's output when the flag is omitted. Site output must not already exist.

All rendering commands accept --policy FILE for a trusted host policy. They also accept --allow-unsafe-html (or the --allow-raw-html alias) to opt into passing through arbitrary authored HTML and iframe markup; the default remains deny. Ordinary Markdown, local images, Mermaid, tables, and code need no policy. html and pdf also accept --title TEXT and --lang TAG. margo schema emits the exact embedded Draft 2020-12 schema bytes for the installed Margo version, including configuration, command-report, runtime, and deck-evidence kinds.

Check

margo check INPUT [--target html|site|pdf|deck] [--policy FILE] [--allow-unsafe-html] [--diagnostics text|json] checks Markdown compatibility without rendering. The target defaults to HTML. It reports raw HTML, unavailable images, incompatible SVG, invalid frontmatter, legacy Mermaid configuration, empty image alternatives, missing document language, skipped headings, empty links, and relative links for standalone targets. With --target site, ordinary relative Markdown links are left to the multi-page site build, which resolves and validates them after indexing all source documents. Findings identify the source, line, field pointer, and a remediation hint.

HTML

margo html INPUT [--output PATH|-] [--force] [--title TEXT] [--lang TAG] [--policy FILE] [--allow-unsafe-html] [--diagnostics text|json] renders one standalone HTML page. The output default is -.

Site

margo site INPUT_DIR|CONFIG [--output-dir OUTPUT_DIR] [--assets local|inline] [--policy FILE] [--allow-unsafe-html] [--diagnostics text|json] builds a linked site. Output is staged beside the destination and published by rename only after a successful build.

PDF

margo pdf INPUT --output PATH|- [--force] [--engine auto|chromium|native] [--engine-path PATH] [--page-size A4|Letter] [--orientation portrait|landscape] [--margin-top MM] [--margin-right MM] [--margin-bottom MM] [--margin-left MM] [--image-overflow limit|allow] [--relative-links strip|error|keep|resolve] [--base-url URL] [--title TEXT] [--lang TAG] [--print-chart-data] [--policy FILE] [--allow-unsafe-html] [--diagnostics text|json] renders a PDF.

Defaults are --engine auto, A4 portrait, and readable document margins of 24 mm top, 22 mm right, 26 mm bottom, and 22 mm left unless margo.page supplies a page preference. Explicit flags override document preferences. To remove all margins, set all four margin flags to 0 for full bleed. --image-overflow limit is the default; --image-overflow allow permits images to exceed the printable content box.

The default --relative-links strip keeps visible text while removing relative PDF link targets. --base-url URL selects resolve unless --relative-links was set; explicit resolve requires --base-url.

All v1 chart families (bar, line, pie, doughnut, and scatter) accept renderer: interactive; omitting it preserves static SVG. Interactive scatter accepts one point or value per declared category. Multi-sample scatter remains available through the static renderer. One formatted semantic exact-data table follows each chart in HTML. Those tables are omitted from PDF by default; --print-chart-data includes them for standalone PDFs, while margo.actions.pdf.printChartData: true includes them in configured pre-rendered PDFs.

Interactive charts are supported by standalone HTML, sites, and margo pdf (PDF rasterizes the chart for print). margo deck is intentionally static for both its HTML and PDF projections: omit renderer or set renderer: static. margo check --target deck reports chart.renderer_target_unsupported with a remediation hint when an interactive chart is supplied.

For corporate PDF branding, use a configured site with site.name, a local SVG site.logo, and margo.actions.pdf: true; the resulting pre-rendered page PDF uses that name and logo. The complete, copyable configuration and the boundary between pre-rendered PDFs, browser printing, and standalone margo pdf are in the margo pdf branding guide.

Current releases use installed Chromium. auto tries an explicit --engine-path, MARGO_CHROMIUM_PATH, discovered Chromium-family executables, then a native slot. Native backends are compiled out, so selecting --engine native does not make WKWebView, WebView2, or WebKitGTK available. Margo never downloads a browser. A selected engine that fails does not fall back to another engine.

Page geometry can also be declared in document metadata:

margo:
  page:
    size: Letter
    orientation: landscape
    margins:
      top: 12
      right: 0
      bottom: 12
      left: 0

Margin sides are independent. Omit a side to retain its target default or set it to 0 for full bleed on that edge.

Deck

margo deck INPUT [--format html|pdf] [--output PATH|-] [--force] [--engine auto|chromium|native] [--engine-path PATH] [--page-size A4|Letter] [--orientation portrait|landscape] [--margin-top MM] [--margin-right MM] [--margin-bottom MM] [--margin-left MM] [--image-overflow limit|allow] [--slide-size 16:9|4:3|custom] [--slide-width N --slide-height N] [--slide-unit px|mm|cm|in|pt|pc|Q] [--print-chart-data] [--policy FILE] [--allow-unsafe-html] [--diagnostics text|json] renders the versioned Margo Marpit-compatible v0.0.1 deck profile.

Its defaults are HTML to stdout, --engine auto, A4, portrait, and zero margins. PDF decks require --format pdf and an explicit output path or -. PDF deck links use the same default strip policy as margo pdf. --image-overflow limit is the default for PDF decks. Deck PDF validation requires an installed Chromium-compatible engine; selecting --engine native fails with cli.deck_validator_unavailable instead of claiming visual validation.

Deck PDFs use compact print styling and natural-height table reflow when --print-chart-data is enabled, so supported multi-row tables remain complete inside the fixed slide canvas. If a larger table still cannot fit, Margo reports the affected slide and suggests reducing the chart data or choosing a larger slide size.

Deck authoring accepts YAML frontmatter, top-level CommonMark thematic breaks, heading-divider pagination, local/spot directives, presenter-note comments, the built-in modern, goshtoso, and minimal themes, and the closed columns, sidebar, compare, metrics, timeline, and demo layout catalog. Mermaid, tables, code, images, and supported Goshtoso charts keep the same accessible extension projections used by the other Margo targets, with charts using the static renderer in both deck formats. Layout classes and slot names are validated before rendering; arbitrary HTML/CSS, remote backgrounds, custom Marpit themes, and unregistered extension ID allocators are rejected with diagnostics.

See the margo deck structural-layout guide for a complete copyable deck covering every layout, exact slot cardinalities, presenter-note scope, and recovery guidance.

--slide-size 16:9 selects a 1280x720 logical canvas and --slide-size 4:3 selects 960x720. For custom geometry, pass positive dimensions with --slide-width, --slide-height, and --slide-unit; slide geometry cannot be combined with the legacy document --page-size or --orientation flags. HTML uses a responsive visual stage while retaining logical coordinates. PDF decks compare every page MediaBox edge and page count against the selected canvas before publication.

Doctor, version, and completion

margo doctor [--diagnostics text|json] reports PDF engine candidates and reasons. margo version and margo --version print the version and compiled engine capabilities without probing external engines. margo completion SHELL [--no-descriptions] prints completion for bash, zsh, fish, or powershell. SHELL is bash, zsh, fish, or powershell; the --no-descriptions flag applies to all four generators.

Go packages

Every supported package ships in the root module. The links below pin the current release line so pkg.go.dev does not resolve an old historical nested module; replace v0.0.17 with the exact release in your go.mod when needed:

Import path Purpose Primary entrypoint
github.com/araihu/margo Compile Markdown and project rendered documents to HTML. margo.New, then Compile and Render
github.com/araihu/margo/assets Serve and inspect embedded Muamba runtime assets. assets.MuambaHTTPHandler
github.com/araihu/margo/charts Register optional static and printable interactive Goshtoso chart fences. charts.Extension
github.com/araihu/margo/deck Parse and render accessible HTML presentation decks. deck.Render
github.com/araihu/margo/pdf Define PDF engine, request, page, and link-policy contracts. pdf.Engine.Export
github.com/araihu/margo/pdf/chromium Export Margo HTML through an explicitly selected installed Chromium executable. chromium.New
github.com/araihu/margo/pdf/engines Discover and select PDF engine candidates. engines.Discover
github.com/araihu/margo/pdf/native Expose the stable platform-native capability boundary. native.Probe
github.com/araihu/margo/pdf/platform Verify locked platform probe contracts for native-engine work. platform.Bootstrap
github.com/araihu/margo/ssg Define and validate layout-neutral frame, shell, composition, binding, and resource contracts. ssg.ResolveComposition
github.com/araihu/margo/site Build deterministic multi-page HTML sites from caller-supplied site-relative sources or a validated config. site.Build, site.LoadConfig, site.BuildConfig

cmd/margo is the CLI program, not a library API. internal/... packages are unsupported implementation details. profiles/, tools/optimistic-renderer, and charts/tools/optimistic-renderer are test and developer tools, not release surface. Directory discovery and publication are CLI-only; site.Build receives caller-supplied []site.Source values.

margo.RenderHTML projects a rendered document to an HTMLResult containing one semantic article.margo-document. margo.RenderHTMLPage provides a generic page shell without claiming a publication domain. HTMLPageInput leaves composition and dependency choices with the host:

page, err := margo.RenderHTMLPage(htmlResult, margo.HTMLPageInput{
	DependencyMode: margo.HTMLDependenciesLocal,
	Head:           siteMetadata(),
	Header:         siteNavigation(),
	BeforeContent:  documentContext(),
	Footer:         siteFooter(),
})

Use HTMLDependenciesInline for a self-contained page. With HTMLDependenciesLocal, mount each handler at its own path:

mux := http.NewServeMux()
mux.Handle("/assets/", goshtosoassets.Handler())
mux.Handle("/margo-assets/", margo.HTMLAssetHandler())
mux.Handle(chartassets.Prefix, chartassets.Handler()) // /charts/assets/

goshtosoassets.Handler owns /assets/; margo.HTMLAssetHandler owns only /margo-assets/; chartassets.Handler owns /charts/assets/. The Margo handler does not serve either dependency mount.

The versioned Go API reference is the stable release surface. Do not add a separate requirement for a historical nested module such as github.com/araihu/margo/pdf; select the root module instead:

go get github.com/araihu/margo@v0.0.17

Releases and module history

Every supported package belongs to the root module and one root release tag. Starting with v0.0.3, releases include margo_VERSION_OS_ARCH archives and SHA-256 digests in checksums.txt. Unix archives use .tar.gz; Windows archives use .zip and contain margo.exe.

The historical submodule tags remain unchanged. Consumers that required github.com/araihu/margo/pdf, github.com/araihu/margo/charts, or github.com/araihu/margo/cmd/margo as separately versioned modules must remove those old requirements and select a root Margo release. An old nested module can otherwise shadow the package supplied by the root module.

Contribute and verify

See CONTRIBUTING.md for prerequisites, generated-file rules, local checks, and the pull-request workflow.

Run the repository as one module:

GOWORK=off GOFLAGS=-mod=readonly go test -race ./...
GOWORK=off GOFLAGS=-mod=readonly go vet ./...
CGO_ENABLED=0 GOWORK=off GOFLAGS=-mod=readonly go build -o margo ./cmd/margo
Local CI with Dagger

Margo's portable CI logic uses Dagger v0.21.8. These functions also back the GitHub Actions adapters:

dagger call required
dagger call portable-release-shape
scripts/prepare-dagger-git.sh
dagger call snapshot --git-bundle=.dagger-git.bundle export --path=dist
dagger call musl
dagger call pages-site export --path=_site

Go modules and compiler outputs use separate Dagger cache volumes. Published Pages and GitHub releases remain explicit provider-side effects; local functions only validate or produce their input artifacts.

Local calls generate an isolated local execution nonce. CI adapters write a validated .dagger-ci-context.json: pull requests receive per-PR untrusted caches, while main and releases use separate trusted domains. Tests and verification always run; only dependency and compiler cache volumes persist.

Security

See SECURITY.md for private vulnerability reporting.

License

Margo is licensed under the MIT License.

Documentation

Overview

Package margo compiles Markdown into immutable semantic documents and projects them to HTML.

The shortest library path compiles one source, renders its semantic content, then places that content in a standalone HTML document:

compiler := margo.New()
document, err := compiler.Compile(ctx, margo.Source{
	Name:    "guide.md",
	Content: markdown,
})
if err != nil {
	return err
}
rendered, err := compiler.Render(ctx, document)
if err != nil {
	return err
}
page, err := margo.RenderStandalone(rendered)
if err != nil {
	return err
}
return page.Render(ctx, output)

A Compiler freezes its options at construction and supports concurrent Compile and Render calls. A compiled Document remains bound to the Compiler configuration that created it. Pass WithExtension to New to register optional integrations such as charts.

The root package is the common compile/render layer, not a high-level filesystem converter. Choose the boundary after rendering: use RenderStandalone for one offline HTML page, RenderHTML and RenderHTMLPage for a host-composed page, package site for linked-site artifacts, package deck for a presentation, and package pdf with pdf/chromium for browser-backed PDF output. The site, PDF, and deck packages document the additional publication and runtime-descriptor steps; the margo CLI is the shortest path when the host does not need to own those seams.

Check performs read-only compatibility analysis without rendering. Host applications own capability policy through WithHostPolicy and WithCheckPolicy; document metadata cannot grant capabilities. Raw HTML is denied by default; a trusted host can explicitly opt into authored HTML and iframe passthrough with WithUnsafeHTML.

RenderHTML exposes a semantic fragment and its dependency requirements. RenderHTMLPage composes that result into a host-owned page, while RenderStandalone creates Margo's self-contained document shell. Host-owned static sites can compose RenderHTML output; PDF and deck workflows reuse the same compilation and runtime contracts.

Package margo does not provide a production HTTP server. The margo serve CLI command is a local development preview with file watching and live reload.

templ: version: v0.3.1020

templ: version: v0.3.1020

templ: version: v0.3.1020

Index

Constants

View Source
const (
	HTMLStylesURL       = "/margo-assets/document.css"
	TableSortRuntimeURL = "/margo-assets/table-sort.js"
	CodeCopyRuntimeURL  = "/margo-assets/code-copy.js"
)
View Source
const (
	// MinOutputBytes and MaxOutputBytes are the immutable root output policy
	// bounds. They are deliberately int64 so optional modules can copy the value
	// without narrowing it before their own checked arithmetic.
	MinOutputBytes int64 = 1
	MaxOutputBytes int64 = 64 << 20
)
View Source
const (
	ThemeModern   = "modern"
	ThemeGoshtoso = "goshtoso"
	ThemeMinimal  = "minimal"
)
View Source
const MaxDocumentBytes int64 = 16 << 20

MaxDocumentBytes bounds source bytes before any renderer or extension runs.

View Source
const MaxPolicyBytes = 64 << 10
View Source
const RuntimeProtocolV1 = "margo-runtime/v1"
View Source
const RuntimeProtocolV2 = "margo-runtime/v2"

Variables

View Source
var (
	ErrCheckAssetOutsideRoot = errors.New("check asset is outside its source root")
	ErrCheckAssetTooLarge    = errors.New("check asset exceeds its byte limit")
	ErrCheckAssetNotRegular  = errors.New("check asset is not a regular file")
)
View Source
var (
	ErrNilDocument              = errors.New("margo: nil document")
	ErrCompilerDocumentMismatch = errors.New("compiler.document_config_mismatch")
)

Functions

func AssetHandler

func AssetHandler() http.Handler

AssetHandler serves only the embedded non-runtime asset set. Mount it at /assets/ in an embedded application.

func CanonicalRuntimeProjection

func CanonicalRuntimeProjection(report RuntimeReport) ([]byte, error)

func HTMLAssetHandler

func HTMLAssetHandler() http.Handler

func HTMLRequirementCapability

func HTMLRequirementCapability(requirement HTMLRequirement) (string, error)

func OutputSchema added in v0.0.18

func OutputSchema(kind SchemaKind) ([]byte, error)

OutputSchema returns the exact JSON Schema shipped for a versioned Margo output envelope. These schemas are also available to the jsonschema fence through margo://schema/v1/output/<name> references.

func RenderHTMLDependencies added in v0.0.3

func RenderHTMLDependencies(requirements HTMLRequirements, mode HTMLDependencyMode) (templ.Component, error)

RenderHTMLDependencies materializes a validated requirement graph as HTML tags. Inline mode produces a self-contained component; local mode preserves the reviewed local URLs from the graph.

func RenderHTMLPage

func RenderHTMLPage(result *HTMLResult, input HTMLPageInput) (templ.Component, error)

func RenderStandalone

func RenderStandalone(result *RenderResult, options ...any) (templ.Component, error)

RenderStandalone assembles a deterministic, offline HTML component. The variadic any accepts both standalone options and the existing compiler WithTheme option for ergonomic compatibility; unsupported compiler options are rejected.

func Schema added in v0.0.5

func Schema(kind SchemaKind) ([]byte, error)

Schema returns detached exact bytes shipped with this Margo version.

func Standalone

func Standalone(result *RenderResult, options ...any) (templ.Component, error)

Standalone is a short alias for RenderStandalone.

func ValidateDocumentToken

func ValidateDocumentToken(token DocumentToken, value string) error

ValidateDocumentToken validates both the versioned key and a conservative value grammar. CSS declarations, URLs, braces, and control characters are never accepted through this API.

func ValidateHTML

func ValidateHTML(fragment string) error

ValidateHTML validates a fragment against the versioned margo-html-v1 allowlist. It deliberately returns an error instead of rewriting unsafe markup so callers cannot mistake a partially sanitized tree for accepted document content.

func ValidateRenderInstanceID

func ValidateRenderInstanceID(value RenderInstanceID) error

func ValidateResourceSize

func ValidateResourceSize(size int64, limits ResourceLimits) error

ValidateResourceSize applies a positive configured limit without allowing integer wraparound or an accidental unlimited zero value.

func ValidateRuntimeDescriptor

func ValidateRuntimeDescriptor(descriptor RuntimeDescriptor) error

func ValidateRuntimeReport

func ValidateRuntimeReport(descriptor RuntimeDescriptor, executionID ExecutionID, report RuntimeReport) error

func ValidateToken

func ValidateToken(name, value string) error

ValidateToken accepts only bounded, value-only theme tokens. In particular, it never accepts CSS functions that can resolve host state or external data.

Types

type AdjacentMapper

type AdjacentMapper struct {
	Extension string
}

AdjacentMapper writes the HTML sibling of a source file.

func (AdjacentMapper) Map

func (m AdjacentMapper) Map(sourcePath string) (string, error)

type ArtifactDigest

type ArtifactDigest [32]byte

ArtifactDigest identifies the exact bytes emitted by an exporter.

func ArtifactDigestOf

func ArtifactDigestOf(data []byte) ArtifactDigest

ArtifactDigestOf hashes the exact emitted bytes without a domain prefix.

func (ArtifactDigest) String

func (f ArtifactDigest) String() string

type ArtifactFingerprint

type ArtifactFingerprint [32]byte

ArtifactFingerprint identifies the deterministic meaning of one emitted artifact. It intentionally excludes transport-only execution identity.

func (ArtifactFingerprint) String

func (f ArtifactFingerprint) String() string

type ArtifactSink

type ArtifactSink interface {
	Commit(context.Context, io.Reader, ArtifactDigest) (CommitResult, error)
}

ArtifactSink publishes a completely staged artifact. Implementations must not make destination bytes visible until the input has passed all pre-publication validation owned by the caller.

type AssetRef

type AssetRef struct {
	Path      string
	MediaType string
	SHA256    string
	Content   []byte
}

AssetRef identifies a validated asset and, for overrides, carries its already-materialized bytes. Callers cannot make an override fetch at render time.

func EmbeddedAsset

func EmbeddedAsset(name string) (AssetRef, error)

EmbeddedAsset returns one of the assets reviewed into the binary.

type AssetSet

type AssetSet struct {
	IDs []string
}

AssetSet is the defensive asset identity projection for a result.

type AtomicFileSink

type AtomicFileSink struct {
	Target string
	Force  bool
	// contains filtered or unexported fields
}

AtomicFileSink stages one complete artifact beside its destination and publishes it with the platform's atomic no-replace primitive. O2 never replaces an existing destination; force replacement is owned by O3.

func (*AtomicFileSink) Commit

func (s *AtomicFileSink) Commit(ctx context.Context, r io.Reader, expected ArtifactDigest) (CommitResult, error)

Commit implements ArtifactSink. Before the visibility linearization point, every failure is not_committed and the destination is left untouched. An ambiguous platform result is classified with a read-back instead of being guessed as a failed publication.

type BlockedRequest

type BlockedRequest struct {
	URL          string `json:"url"`
	ResourceType string `json:"resourceType"`
}

type Brand

type Brand struct {
	Header    templ.Component
	Footer    templ.Component
	LogoAlt   string
	Backdrop  AssetRef
	Watermark string
	Stamps    []string
	Tokens    map[DocumentToken]string
}

Brand is the trusted, declarative subset of standalone branding. Header and Footer are Go components; document-authored markup never populates them.

func PDFBrand added in v0.0.6

func PDFBrand(name, pageTitle string, logo AssetRef) Brand

PDFBrand returns the small editorial furniture shared by PDF projections. The supplied logo is already materialized, so PDF rendering remains offline and does not depend on the surrounding application shell.

func (Brand) Validate

func (b Brand) Validate() error

Validate rejects invalid overrides instead of falling back to embedded assets or silently dropping unsafe customization.

type CheckAssetReader added in v0.0.4

type CheckAssetReader interface {
	ReadAsset(context.Context, string, string, int64) ([]byte, error)
}

CheckAssetReader supplies local assets to Check without coupling library users to the host filesystem.

type CheckOption added in v0.0.4

type CheckOption func(*checkConfig) error

CheckOption configures compatibility analysis.

func WithCheckAssetReader added in v0.0.4

func WithCheckAssetReader(reader CheckAssetReader) CheckOption

WithCheckAssetReader enables missing-asset and SVG compatibility checks.

func WithCheckExtension added in v0.0.4

func WithCheckExtension(registration ExtensionRegistration) CheckOption

WithCheckExtension enables an extension's read-only fence validation during compatibility analysis.

func WithCheckPolicy added in v0.0.4

func WithCheckPolicy(policy Policy) CheckOption

WithCheckPolicy evaluates compatibility against the same host capability ceiling used for compilation. Document metadata has no capability authority.

func WithCheckTarget added in v0.0.5

func WithCheckTarget(target RenderTarget) CheckOption

WithCheckTarget selects the output projection analyzed by Check.

func WithCheckUnsafeHTML added in v0.0.18

func WithCheckUnsafeHTML() CheckOption

WithCheckUnsafeHTML mirrors WithUnsafeHTML for the read-only compatibility checker. It is intentionally opt-in because raw HTML and iframe content are otherwise denied before any renderer is invoked.

type ColorMode

type ColorMode string

ColorMode selects the light or dark Goshtoso token family independently from the document theme.

const (
	ColorModeLight ColorMode = "light"
	ColorModeDark  ColorMode = "dark"
)

type CommitOutcome

type CommitOutcome string

CommitOutcome describes what is known about a destination after an artifact sink returns. Sinks must never collapse an uncertain filesystem state into a successful commit or a claim that the destination is unchanged.

const (
	CommitNotCommitted        CommitOutcome = "not_committed"
	CommitCommitted           CommitOutcome = "committed"
	CommitDurabilityUncertain CommitOutcome = "durability_uncertain"
	CommitUnknown             CommitOutcome = "unknown"
)

type CommitResult

type CommitResult struct {
	Outcome CommitOutcome
	Target  string
	Digest  ArtifactDigest
	Bytes   int64
}

CommitResult is the transport identity returned by an ArtifactSink.

type Compiler

type Compiler struct {
	// contains filtered or unexported fields
}

Compiler owns one immutable configuration snapshot and is safe for concurrent Compile and Render calls.

func New

func New(options ...Option) *Compiler

New freezes options and returns a reusable compiler.

func (*Compiler) Compile

func (c *Compiler) Compile(ctx context.Context, source Source) (*Document, error)

Compile snapshots source and returns an opaque immutable document.

func (*Compiler) Render

func (c *Compiler) Render(ctx context.Context, document *Document, options ...RenderOption) (*RenderResult, error)

Render creates an immutable result. Semantic rendering is added by the later render-plan task; this early contract still enforces compiler binding.

func (*Compiler) SupportsRenderIDAllocator added in v0.0.7

func (c *Compiler) SupportsRenderIDAllocator() bool

SupportsRenderIDAllocator reports whether every registered extension has opted into the deck render-wide identity capability.

type CompilerConfigFingerprint

type CompilerConfigFingerprint [32]byte

CompilerConfigFingerprint identifies the frozen compiler configuration.

func (CompilerConfigFingerprint) String

func (f CompilerConfigFingerprint) String() string

type Diagnostic

type Diagnostic struct {
	Code     string   `json:"code"`
	Severity Severity `json:"severity"`
	Source   string   `json:"source"`
	Line     int      `json:"line"`
	Column   int      `json:"column"`
	Pointer  string   `json:"pointer"`
	Message  string   `json:"message"`
	Hint     string   `json:"hint"`
}

Diagnostic is a stable, serializable problem projection.

func Check added in v0.0.4

func Check(ctx context.Context, source Source, options ...CheckOption) ([]Diagnostic, error)

Check performs read-only compatibility analysis without rendering. Findings are deterministic and carry stable source positions and remediation hints.

type DiagnosticError

type DiagnosticError struct {
	Diagnostics []Diagnostic
}

DiagnosticError carries one or more stable diagnostics without exposing parser internals.

func (*DiagnosticError) Error

func (e *DiagnosticError) Error() string

type Document

type Document struct {
	// contains filtered or unexported fields
}

Document is an immutable compiled source. Its internal representation is deliberately opaque so parser and policy details remain versioned internals.

func (*Document) Assets

func (d *Document) Assets() AssetSet

Assets returns a defensive value copy.

func (*Document) Diagnostics

func (d *Document) Diagnostics() []Diagnostic

Diagnostics returns a defensive slice copy.

func (*Document) Metadata

func (d *Document) Metadata() Metadata

Metadata returns a defensive value copy.

type DocumentFingerprint

type DocumentFingerprint [32]byte

DocumentFingerprint identifies the immutable compiled meaning.

func (DocumentFingerprint) MarshalJSON

func (f DocumentFingerprint) MarshalJSON() ([]byte, error)

func (DocumentFingerprint) String

func (f DocumentFingerprint) String() string

func (*DocumentFingerprint) UnmarshalJSON

func (f *DocumentFingerprint) UnmarshalJSON(data []byte) error

type DocumentPreferences added in v0.0.5

type DocumentPreferences struct {
	Page    *PagePreference
	Actions *PageActions
}

type DocumentToken

type DocumentToken string

DocumentToken is the versioned, bounded CSS custom-property surface.

const (
	TokenFontBody       DocumentToken = "--document-font-body"
	TokenFontHeading    DocumentToken = "--document-font-heading"
	TokenContentWidth   DocumentToken = "--document-content-width"
	TokenLineHeight     DocumentToken = "--document-line-height"
	TokenCodeTheme      DocumentToken = "--document-code-theme"
	TokenPageBackground DocumentToken = "--document-page-background"
)

type EffectivePolicy

type EffectivePolicy struct {
	RawHTML         RawHTMLMode   `json:"rawHTML"`
	InputBytes      int64         `json:"inputBytes"`
	OutputBytes     int64         `json:"outputBytes"`
	Iframe          *IframePolicy `json:"iframe,omitempty"`
	AllowUnsafeHTML bool          `json:"allowUnsafeHTML,omitempty"`
}

EffectivePolicy is the immutable intersection stored on a compiled Document. It is a value, not a pointer, so renderers cannot mutate the compiler's decision after Compile.

type ExecutionID

type ExecutionID string

type ExtensionCheck added in v0.0.4

type ExtensionCheck func(context.Context, ExtensionNode) error

ExtensionCheck performs read-only preflight validation for one detached fence payload under the same immutable extension configuration.

type ExtensionFactory

type ExtensionFactory func(RenderContext) (ExtensionSession, error)

ExtensionFactory creates an independent render session for one operation.

type ExtensionIdentity

type ExtensionIdentity struct {
	Name              string   `json:"name"`
	Version           string   `json:"version"`
	ConfigurationHash string   `json:"configurationHash,omitempty"`
	Capabilities      []string `json:"capabilities,omitempty"`
}

ExtensionIdentity is the stable, serialized identity of one registered extension. ConfigurationHash is optional for the small root fixtures but is included in the compiler fingerprint whenever supplied.

type ExtensionNode

type ExtensionNode struct {
	Fence string
	// Info is the complete fenced-code info string, including the fence name
	// and any optional key/value arguments after it. Extensions that need a
	// source reference (for example, jsonschema) can interpret it without
	// having to re-parse Goldmark nodes.
	Info    string
	Payload []byte
	Source  SourcePosition
	// BaseURL and AssetReader are populated for compatibility checks. They are
	// intentionally optional so existing third-party extensions remain source
	// compatible while extensions can safely resolve bounded local resources.
	BaseURL     string
	AssetReader CheckAssetReader
	// Target identifies the output projection being checked. Rendered
	// extension nodes leave this unset because render options are applied
	// after compilation; compatibility checkers can use it for target-specific
	// authoring contracts.
	Target RenderTarget
	// contains filtered or unexported fields
}

ExtensionNode is an immutable detached fence payload.

type ExtensionRegistration

type ExtensionRegistration struct {
	Identity ExtensionIdentity
	Fences   []string
	Factory  ExtensionFactory
	Check    ExtensionCheck
	// contains filtered or unexported fields
}

ExtensionRegistration binds one immutable factory to its owned fences.

type ExtensionSession

type ExtensionSession interface {
	Render(context.Context, ExtensionNode, io.Writer) error
}

ExtensionSession is a per-render instance returned by a factory.

type FilesystemCheckAssetReader added in v0.0.4

type FilesystemCheckAssetReader struct{}

FilesystemCheckAssetReader reads bounded regular files after resolving symlinks and proving that the real target remains below the real root.

func (FilesystemCheckAssetReader) ReadAsset added in v0.0.4

func (FilesystemCheckAssetReader) ReadAsset(ctx context.Context, root, name string, limit int64) ([]byte, error)

type FlatMapper

type FlatMapper struct {
	OutputDir string
	Extension string
}

FlatMapper writes each known source file directly below OutputDir.

func (FlatMapper) Map

func (m FlatMapper) Map(sourcePath string) (string, error)

type FontCheck

type FontCheck struct {
	Family string `json:"family"`
	Query  string `json:"query"`
	Loaded bool   `json:"loaded"`
}

type HTMLDependencyMode

type HTMLDependencyMode string
const (
	HTMLDependenciesLocal  HTMLDependencyMode = "local"
	HTMLDependenciesInline HTMLDependencyMode = "inline"
)

type HTMLFingerprint

type HTMLFingerprint [32]byte

func (HTMLFingerprint) String

func (f HTMLFingerprint) String() string

type HTMLMetadata

type HTMLMetadata struct {
	Title       string   `json:"title"`
	Description string   `json:"description"`
	Language    string   `json:"language"`
	Slug        string   `json:"slug"`
	Authors     []string `json:"authors,omitempty"`
	PublishedAt string   `json:"publishedAt,omitempty"`
	ModifiedAt  string   `json:"modifiedAt,omitempty"`
	Tags        []string `json:"tags,omitempty"`
}

type HTMLOption

type HTMLOption func(*htmlConfig) error

func WithHTMLHeader

func WithHTMLHeader() HTMLOption

type HTMLPageInput

type HTMLPageInput struct {
	Theme           ThemeName
	ColorMode       ColorMode
	DependencyMode  HTMLDependencyMode
	ThemeStylesheet AssetRef
	Head            templ.Component
	Header          templ.Component
	BeforeContent   templ.Component
	Footer          templ.Component
	// contains filtered or unexported fields
}

HTMLPageInput configures a generic complete HTML document. Head, Header, BeforeContent, and Footer are caller-owned composition seams; Margo does not infer canonical URLs, social metadata, or publication semantics here.

type HTMLRequirement

type HTMLRequirement struct {
	ID        string
	Kind      HTMLRequirementKind
	LocalURL  string
	Integrity string
	LoadAfter []string
	Inline    AssetRef
}

type HTMLRequirementKind

type HTMLRequirementKind string
const (
	HTMLStylesheet  HTMLRequirementKind = "stylesheet"
	HTMLScript      HTMLRequirementKind = "script"
	HTMLRuntimeRole HTMLRequirementKind = "runtime-role"
)

type HTMLRequirements

type HTMLRequirements struct {
	// contains filtered or unexported fields
}

func MergeHTMLRequirements added in v0.0.3

func MergeHTMLRequirements(groups ...HTMLRequirements) (HTMLRequirements, error)

MergeHTMLRequirements validates, deduplicates, and dependency-orders one or more requirement groups without exposing Margo's internal storage.

func (HTMLRequirements) List

func (r HTMLRequirements) List() []HTMLRequirement

type HTMLResult

type HTMLResult struct {
	// contains filtered or unexported fields
}

func RenderHTML

func RenderHTML(result *RenderResult, options ...HTMLOption) (*HTMLResult, error)

func (*HTMLResult) Diagnostics

func (r *HTMLResult) Diagnostics() []Diagnostic

func (*HTMLResult) Fingerprint

func (r *HTMLResult) Fingerprint() HTMLFingerprint

func (*HTMLResult) Fragment

func (r *HTMLResult) Fragment() templ.Component

func (*HTMLResult) Metadata

func (r *HTMLResult) Metadata() HTMLMetadata

func (*HTMLResult) PlainText

func (r *HTMLResult) PlainText() string

func (*HTMLResult) Requirements

func (r *HTMLResult) Requirements() HTMLRequirements

type IframePolicy added in v0.0.5

type IframePolicy struct {
	AllowedOrigins []string          `json:"allowedOrigins"`
	Sandbox        []SandboxToken    `json:"sandbox"`
	ReferrerPolicy ReferrerPolicy    `json:"referrerPolicy"`
	Projections    TargetProjections `json:"projections"`
}

IframePolicy is host-owned. Documents provide only src, title, width, and height; they cannot widen these capabilities.

type InstanceAllocator

type InstanceAllocator struct {
	// contains filtered or unexported fields
}

func NewInstanceAllocator

func NewInstanceAllocator() *InstanceAllocator

func (*InstanceAllocator) Next

type InstanceRegistry

type InstanceRegistry struct {
	// contains filtered or unexported fields
}

func NewInstanceRegistry

func NewInstanceRegistry() *InstanceRegistry

func (*InstanceRegistry) Reserve

func (r *InstanceRegistry) Reserve(value RenderInstanceID) error

type LayoutMetrics

type LayoutMetrics struct {
	ScrollWidth  int64 `json:"scrollWidth"`
	ScrollHeight int64 `json:"scrollHeight"`
}

LayoutMetrics is the quantized layout projection used by artifact identity. Runtime implementations may carry richer metrics in their own schema; C8 only commits the stable dimensions needed by the core identity seam.

type Manifest

type Manifest struct {
	Entries []ManifestEntry `json:"entries"`
}

Manifest is a defensive, deterministic collection of output identities.

func (Manifest) Clone

func (m Manifest) Clone() Manifest

Clone returns a manifest whose entry storage is independent of the source.

func (Manifest) Digest

func (m Manifest) Digest() string

Digest returns the domain-separated SHA-256 of the canonical sorted manifest. It panics only when the in-memory value cannot be canonicalized; callers that accept external data should call Validate first.

func (Manifest) Validate

func (m Manifest) Validate() error

Validate checks path and duplicate invariants before a manifest is emitted.

type ManifestEntry

type ManifestEntry struct {
	Path   string         `json:"path"`
	Digest ArtifactDigest `json:"digest"`
}

ManifestEntry binds one output path to its exact artifact bytes.

type Metadata

type Metadata struct {
	Name        string
	BaseURL     string
	Title       string
	Description string
	Language    string
	Slug        string
	Authors     []string
	PublishedAt string
	ModifiedAt  string
	Tags        []string
	Margo       DocumentPreferences
	Additional  map[string]any
}

Metadata is the immutable normalized metadata projection exposed by a RenderResult. Additional frontmatter fields are added by the parser task.

type Option

type Option func(*compilerConfig) error

Option configures a Compiler before it is frozen by New.

func WithExtension

func WithExtension(registration ExtensionRegistration) Option

WithExtension registers one factory before New freezes the registry.

func WithHostPolicy

func WithHostPolicy(policy Policy) Option

WithHostPolicy supplies the host ceiling. Validation happens at Compile so an invalid value produces a stable diagnostic rather than a construction panic.

func WithTheme

func WithTheme(name string) Option

WithTheme is the small root theme option consumed by the C4 binding tests; the full token/theme registry is owned by later root tasks.

func WithUnsafeHTML added in v0.0.18

func WithUnsafeHTML() Option

WithUnsafeHTML opts a compiler into passing through document-authored HTML, including arbitrary iframe markup. The option is intentionally separate from Policy so a project cannot accidentally persist this capability in a reusable policy file; callers must make the decision at compiler setup.

type OutputMapper

type OutputMapper interface {
	Map(sourcePath string) (string, error)
}

OutputMapper maps one known source file to one output path. It performs no discovery, globbing, collision resolution, or filesystem writes.

type PDFMode added in v0.0.6

type PDFMode string

PDFMode selects how a site's PDF action is fulfilled.

const (
	PDFModePreRendered PDFMode = "pre-rendered"
	PDFModeClient      PDFMode = "client"
)

type PageActions added in v0.0.6

type PageActions struct {
	Markdown       bool    `json:"markdown,omitempty"`
	PDF            bool    `json:"pdf,omitempty"`
	PDFMode        PDFMode `json:"pdfMode,omitempty"`
	PrintChartData bool    `json:"printChartData,omitempty"`
}

PageActions selects optional artifacts and controls emitted by a site generator. PDF publication also retains the Markdown source for the page.

func (PageActions) EffectivePDFMode added in v0.0.6

func (actions PageActions) EffectivePDFMode() PDFMode

func (PageActions) UsesClientPDF added in v0.0.6

func (actions PageActions) UsesClientPDF() bool

type PageMarginPreference added in v0.0.5

type PageMarginPreference struct {
	Top    *float64
	Right  *float64
	Bottom *float64
	Left   *float64
}

PageMarginPreference keeps every side optional so an author can override one side without discarding the built-in values for the others. Pointers distinguish an omitted side from an explicit zero used for full bleed.

type PagePreference added in v0.0.5

type PagePreference struct {
	Size          string
	Orientation   string
	ImageOverflow string
	Margins       *PageMarginPreference
}

type Policy

type Policy struct {
	SchemaVersion string        `json:"schemaVersion,omitempty"`
	RawHTML       RawHTMLMode   `json:"rawHTML"`
	InputBytes    int64         `json:"inputBytes"`
	OutputBytes   int64         `json:"outputBytes"`
	Iframe        *IframePolicy `json:"iframe,omitempty"`
}

Policy describes a host capability ceiling. A zero Policy is not a valid explicit host policy; callers that do not provide one receive the built-in deny/MaxOutputBytes ceiling.

func DefaultPolicy added in v0.0.5

func DefaultPolicy() Policy

DefaultPolicy returns the least-authoritative host policy and documented resource defaults for this Margo version.

func ParsePolicyJSON added in v0.0.5

func ParsePolicyJSON(input []byte) (Policy, error)

ParsePolicyJSON validates canonical v1 JSON before applying documented defaults and semantic origin normalization.

type PreserveMapper

type PreserveMapper struct {
	SourceRoot string
	OutputDir  string
	Extension  string
}

PreserveMapper preserves a source file's path relative to SourceRoot under OutputDir.

func (PreserveMapper) Map

func (m PreserveMapper) Map(sourcePath string) (string, error)

type Projection added in v0.0.5

type Projection string

Projection selects how an authorized iframe is represented for one target.

const (
	ProjectionDeny        Projection = "deny"
	ProjectionStaticLink  Projection = "static-link"
	ProjectionInteractive Projection = "interactive"
)

type RawHTMLMode

type RawHTMLMode string

RawHTMLMode is the versioned raw-HTML capability vocabulary.

const (
	RawHTMLDeny      RawHTMLMode = "deny"
	RawHTMLSanitized RawHTMLMode = "sanitized"
)

type ReferrerPolicy added in v0.0.5

type ReferrerPolicy string
const ReferrerNoReferrer ReferrerPolicy = "no-referrer"

type RenderContext

type RenderContext struct {
	EffectivePolicy EffectivePolicy
}

RenderContext is the only root-to-extension policy delivery seam. It is a value so a session cannot mutate the compiler or another render operation.

type RenderIDAllocator added in v0.0.7

type RenderIDAllocator interface {
	Allocate(kind, sourceKey string) string
	Resolve(kind, sourceKey string) (string, bool)
}

RenderIDAllocator is the render-wide identity capability used by deck and trusted extensions. The pair (kind, sourceKey) is idempotent and resolves to one stable HTML ID for the lifetime of a render.

type RenderInstanceID

type RenderInstanceID string

type RenderOption

type RenderOption func(*renderOptions) error

RenderOption configures one immutable render operation.

func WithRenderIDAllocator added in v0.0.7

func WithRenderIDAllocator(allocator RenderIDAllocator) RenderOption

WithRenderIDAllocator provides a trusted render-wide identity allocator.

func WithRenderTarget added in v0.0.5

func WithRenderTarget(target RenderTarget) RenderOption

WithRenderTarget selects iframe and security projection for this render. Omission defaults to HTML for backward-compatible library calls.

func WithTableSort

func WithTableSort(mode TableSortMode) RenderOption

WithTableSort selects the table sorting projection for one render.

type RenderResult

type RenderResult struct {
	// contains filtered or unexported fields
}

RenderResult is an immutable render projection safe for concurrent access.

func PrepareHTMLRenderResult added in v0.0.7

func PrepareHTMLRenderResult(result *RenderResult) (*RenderResult, error)

PrepareHTMLRenderResult relocates trusted chart extension scripts out of an editorial fragment and into the result's dependency graph. Complete HTML shells (standalone pages and presentation decks) can then place those dependencies in their own lifecycle-controlled region without weakening the fragment policy that rejects executable markup.

func (*RenderResult) Assets

func (r *RenderResult) Assets() AssetSet

Assets returns a defensive asset copy.

func (*RenderResult) Content

func (r *RenderResult) Content() templ.Component

Content returns the immutable templ component.

func (*RenderResult) Diagnostics

func (r *RenderResult) Diagnostics() []Diagnostic

Diagnostics returns a defensive diagnostic slice.

func (*RenderResult) DocumentFingerprint added in v0.0.3

func (r *RenderResult) DocumentFingerprint() DocumentFingerprint

func (*RenderResult) Metadata

func (r *RenderResult) Metadata() Metadata

Metadata returns a defensive metadata copy.

func (*RenderResult) RuntimeDescriptor added in v0.0.3

func (r *RenderResult) RuntimeDescriptor(instance RenderInstanceID) (RuntimeDescriptor, error)

func (*RenderResult) Target added in v0.0.5

func (r *RenderResult) Target() RenderTarget

Target returns the normalized output target used for this render.

type RenderTarget added in v0.0.5

type RenderTarget string

RenderTarget selects one explicit artifact projection without changing the target-neutral compiled document.

const (
	TargetHTML RenderTarget = "html"
	TargetSite RenderTarget = "site"
	TargetPDF  RenderTarget = "pdf"
	TargetDeck RenderTarget = "deck"
)

type ResourceLimits

type ResourceLimits struct {
	DocumentBytes int64
}

ResourceLimits contains the host's document resource ceilings.

type RuntimeDescriptor

type RuntimeDescriptor struct {
	Protocol            string                    `json:"protocol"`
	DocumentFingerprint DocumentFingerprint       `json:"documentFingerprint"`
	RenderInstanceID    RenderInstanceID          `json:"renderInstanceID"`
	Tasks               []RuntimeTask             `json:"tasks"`
	ValidationRequest   *RuntimeValidationRequest `json:"validationRequest,omitempty"`
}

func ComposeRuntimeDescriptors added in v0.0.3

func ComposeRuntimeDescriptors(document DocumentFingerprint, instance RenderInstanceID, parts ...RuntimeDescriptor) (RuntimeDescriptor, error)

func ParseRuntimeDescriptor

func ParseRuntimeDescriptor(data []byte) (RuntimeDescriptor, error)

type RuntimeReport

type RuntimeReport struct {
	Protocol            string                     `json:"protocol"`
	DocumentFingerprint DocumentFingerprint        `json:"documentFingerprint"`
	RenderInstanceID    RenderInstanceID           `json:"renderInstanceID"`
	ExecutionID         ExecutionID                `json:"executionID"`
	Status              RuntimeStatus              `json:"status"`
	Tasks               []RuntimeTaskReport        `json:"tasks"`
	FontChecks          []FontCheck                `json:"fontChecks"`
	BlockedRequests     []BlockedRequest           `json:"blockedRequests"`
	Layout              LayoutMetrics              `json:"layout"`
	Diagnostic          *Diagnostic                `json:"diagnostic"`
	ValidationIdentity  *RuntimeValidationIdentity `json:"validationIdentity,omitempty"`
}

func ParseRuntimeReport

func ParseRuntimeReport(data []byte) (RuntimeReport, error)

type RuntimeStatus

type RuntimeStatus string
const (
	RuntimePending RuntimeStatus = "pending"
	RuntimeRunning RuntimeStatus = "running"
	RuntimeReady   RuntimeStatus = "ready"
	RuntimeFailed  RuntimeStatus = "failed"
)

type RuntimeTask

type RuntimeTask struct {
	ID          string   `json:"id"`
	Kind        string   `json:"kind"`
	InputSHA256 string   `json:"inputSHA256"`
	DependsOn   []string `json:"dependsOn"`
}

type RuntimeTaskReport

type RuntimeTaskReport struct {
	ID           string            `json:"id"`
	Kind         string            `json:"kind"`
	InputSHA256  string            `json:"inputSHA256"`
	OutputSHA256 string            `json:"outputSHA256"`
	OutputBytes  int64             `json:"outputBytes"`
	Status       RuntimeTaskStatus `json:"status"`
	ErrorCode    string            `json:"errorCode"`
}

type RuntimeTaskStatus

type RuntimeTaskStatus string
const (
	RuntimeTaskPending   RuntimeTaskStatus = "pending"
	RuntimeTaskRunning   RuntimeTaskStatus = "running"
	RuntimeTaskSucceeded RuntimeTaskStatus = "succeeded"
	RuntimeTaskFailed    RuntimeTaskStatus = "failed"
)

type RuntimeValidationIdentity added in v0.0.7

type RuntimeValidationIdentity struct {
	BrowserProfile   string `json:"browserProfile"`
	EngineName       string `json:"engineName"`
	EngineVersion    string `json:"engineVersion"`
	PlatformProfile  string `json:"platformProfile"`
	FontBundleDigest string `json:"fontBundleDigest"`
}

RuntimeValidationIdentity records values observed by the validator rather than caller assertions.

func (RuntimeValidationIdentity) Validate added in v0.0.7

func (identity RuntimeValidationIdentity) Validate() error

type RuntimeValidationRequest added in v0.0.7

type RuntimeValidationRequest struct {
	ViewportWidth            uint    `json:"viewportWidth"`
	ViewportHeight           uint    `json:"viewportHeight"`
	DeviceScaleFactor        float64 `json:"deviceScaleFactor"`
	Zoom                     float64 `json:"zoom"`
	BrowserProfile           string  `json:"browserProfile"`
	ExpectedFontBundleDigest string  `json:"expectedFontBundleDigest"`
}

RuntimeValidationRequest is the profile-neutral request bound to a v2 descriptor. Deck owns the profile registry and derives the font digest; margo validates the wire shape and equality constraints.

func (RuntimeValidationRequest) Validate added in v0.0.7

func (request RuntimeValidationRequest) Validate() error

type SandboxToken added in v0.0.5

type SandboxToken string
const (
	SandboxAllowPresentation SandboxToken = "allow-presentation"
	SandboxAllowScripts      SandboxToken = "allow-scripts"
)

type SchemaKind added in v0.0.5

type SchemaKind string

SchemaKind identifies one public, version-matched configuration or output schema. Output schemas describe the stable JSON envelopes emitted by the CLI and runtime integrations.

const (
	SchemaPolicy   SchemaKind = "policy"
	SchemaDocument SchemaKind = "document"
	SchemaSite     SchemaKind = "site"

	SchemaDiagnostic            SchemaKind = "diagnostic"
	SchemaDoctorReport          SchemaKind = "doctor-report"
	SchemaCheckReport           SchemaKind = "check-report"
	SchemaSiteReport            SchemaKind = "site-report"
	SchemaSiteManifest          SchemaKind = "site-manifest"
	SchemaRuntimeDescriptor     SchemaKind = "runtime-descriptor"
	SchemaRuntimeReport         SchemaKind = "runtime-report"
	SchemaDeckLayoutEvidence    SchemaKind = "deck-layout-evidence"
	SchemaDeckPDFArtifactReport SchemaKind = "deck-pdf-artifact-report"
)

type Severity

type Severity string

Severity is the stable diagnostic severity vocabulary.

const (
	SeverityInfo    Severity = "info"
	SeverityWarning Severity = "warning"
	SeverityError   Severity = "error"
)

type Source

type Source struct {
	Name    string
	Content []byte
	BaseURL string
}

Source is one immutable compilation input after Compile returns.

type SourcePosition

type SourcePosition struct {
	Source string `json:"source"`
	Line   int    `json:"line"`
	Column int    `json:"column"`
}

SourcePosition identifies a source location without exposing Goldmark segments as a public API.

type Spool

type Spool struct {
	// contains filtered or unexported fields
}

Spool accumulates one bounded artifact. It remains invisible to the caller's destination and spills to a mode-0600 private file after MemoryLimit.

func NewSpool

func NewSpool(options SpoolOptions) *Spool

NewSpool creates a private bounded staging buffer. Zero limits select safe defaults; invalid negative limits are reported by the first write.

func (*Spool) Close

func (s *Spool) Close() error

Close removes private staging and makes the spool unusable. It is safe to call more than once.

func (*Spool) Digest

func (s *Spool) Digest() ArtifactDigest

Digest returns the exact-byte digest accumulated so far.

func (*Spool) Reader

func (s *Spool) Reader() (io.ReadCloser, error)

Reader returns a fresh replay reader positioned at byte zero.

func (*Spool) Size

func (s *Spool) Size() int64

Size returns the number of staged bytes.

func (*Spool) UsesPrivateFile

func (s *Spool) UsesPrivateFile() bool

UsesPrivateFile reports whether the memory threshold has been crossed.

func (*Spool) Write

func (s *Spool) Write(data []byte) error

Write appends bytes to the spool without exposing a destination.

func (*Spool) WriteAll

func (s *Spool) WriteAll(ctx context.Context, data []byte) error

WriteAll appends one bounded byte sequence and observes cancellation before any private stage is created or mutated.

type SpoolOptions

type SpoolOptions struct {
	MemoryLimit  int64
	MaximumBytes int64
	TempDir      string
}

SpoolOptions controls the private staging boundary used before publication.

type StandaloneOption

type StandaloneOption func(*standaloneConfig) error

StandaloneOption configures the self-contained HTML shell.

func WithAssetOverride

func WithAssetOverride(name string, asset AssetRef) StandaloneOption

WithAssetOverride supplies already-materialized bytes for one embedded asset.

func WithBrand

func WithBrand(brand Brand) StandaloneOption

WithBrand applies trusted header/footer components and validated declarative brand values.

func WithPDFBrand added in v0.0.6

func WithPDFBrand(name string, logo AssetRef) StandaloneOption

WithPDFBrand applies PDFBrand after other standalone options. This keeps command-line title overrides visible in the generated footer.

func WithPageDescription

func WithPageDescription(description string) StandaloneOption

WithPageDescription sets the optional escaped description.

func WithPageLanguage added in v0.0.4

func WithPageLanguage(language string) StandaloneOption

WithPageLanguage sets the document language using a BCP 47 language tag.

func WithPageTitle

func WithPageTitle(title string) StandaloneOption

WithPageTitle sets the escaped document title.

func WithStandaloneColorMode

func WithStandaloneColorMode(mode ColorMode) StandaloneOption

WithStandaloneColorMode selects the light or dark Goshtoso token family for both screen rendering and print/PDF projection.

func WithStandaloneTheme

func WithStandaloneTheme(theme ThemeName) StandaloneOption

WithStandaloneTheme selects the closed theme set for standalone output.

func WithTableOfContents

func WithTableOfContents() StandaloneOption

WithTableOfContents inserts one deterministic navigation landmark before the article. Entries cover heading levels two through four and reuse compiled IDs.

func WithThemeTokens

func WithThemeTokens(tokens map[DocumentToken]string) StandaloneOption

WithThemeTokens applies only the supported, bounded token keys.

type StdoutSink

type StdoutSink struct {
	Writer io.Writer
}

StdoutSink copies only a completely validated spool to its writer. Unlike a filesystem sink, stdout cannot revoke bytes after a downstream short write.

func (StdoutSink) Commit

func (s StdoutSink) Commit(ctx context.Context, r io.Reader, expected ArtifactDigest) (CommitResult, error)

type TableSortMode

type TableSortMode string

TableSortMode is the bounded sorting vocabulary exposed by the root renderer. Server-side table behavior is deliberately not part of C5.

const (
	TableSortClient TableSortMode = "client"
)

type TargetProjections added in v0.0.5

type TargetProjections struct {
	HTML Projection `json:"html"`
	Site Projection `json:"site"`
	PDF  Projection `json:"pdf"`
	Deck Projection `json:"deck"`
}

TargetProjections keeps capability decisions independent per output target.

type TerminalReport

type TerminalReport struct {
	ProtocolVersion    string
	Document           DocumentFingerprint
	RenderInstanceID   string
	ExecutionID        string
	Kind               string
	Serializer         string
	Engine             string
	TerminalStatus     string
	TerminalDiagnostic string
	PageConfiguration  any
	TaskInputHashes    []string
	TaskOutputHashes   []string
	FontChecks         []string
	BlockedRequests    []string
	Layout             LayoutMetrics
}

TerminalReport is the immutable runtime projection consumed by artifact identity. ExecutionID routes a live execution and is deliberately excluded from the artifact preimage.

type ThemeName

type ThemeName string

ThemeName identifies a built-in or host-provided theme.

Directories

Path Synopsis
Package charts provides optional chart integration for Margo.
Package charts provides optional chart integration for Margo.
tools/optimistic-renderer command
Command optimistic-renderer creates a deterministic standalone HTML review artifact with the optional Goshtoso Charts extension enabled.
Command optimistic-renderer creates a deterministic standalone HTML review artifact with the optional Goshtoso Charts extension enabled.
cmd
margo command
Package deck parses Margo Markdown and renders accessible HTML presentation decks.
Package deck parses Margo Markdown and renders accessible HTML presentation decks.
examples
blog command
blog/site
Package site builds the checked blog-style HTML example.
Package site builds the checked blog-style HTML example.
internal
browserlaunch
Package browserlaunch centralizes host-browser process safeguards.
Package browserlaunch centralizes host-browser process safeguards.
canonicaljson
Package canonicaljson provides the deterministic JSON byte routine used by Margo identity preimages.
Package canonicaljson provides the deterministic JSON byte routine used by Margo identity preimages.
cmd/schema-docs command
devserver
Package devserver implements Margo's development-only site server.
Package devserver implements Margo's development-only site server.
htmlpolicy
Package htmlpolicy implements the closed margo-html-v1 fragment profile.
Package htmlpolicy implements the closed margo-html-v1 fragment profile.
pdf
Package pdf defines renderer-neutral contracts for exporting Margo HTML to PDF.
Package pdf defines renderer-neutral contracts for exporting Margo HTML to PDF.
chromium
Package chromium exports immutable Margo HTML through an explicitly selected installed Chromium-family executable.
Package chromium exports immutable Margo HTML through an explicitly selected installed Chromium-family executable.
native
Package native defines the stable capability boundary for platform-native PDF engines.
Package native defines the stable capability boundary for platform-native PDF engines.
platform
Package platform verifies the locked platform probe contract without selecting, downloading, or implementing a PDF engine.
Package platform verifies the locked platform probe contract without selecting, downloading, or implementing a PDF engine.
Package site builds deterministic multi-page HTML sites from Markdown inputs.
Package site builds deterministic multi-page HTML sites from Markdown inputs.
Package ssg contains the layout-neutral contract used by Margo static sites.
Package ssg contains the layout-neutral contract used by Margo static sites.
tools
optimistic-renderer command
Command optimistic-renderer creates a deterministic standalone HTML review artifact from one Markdown source file.
Command optimistic-renderer creates a deterministic standalone HTML review artifact from one Markdown source file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL