name: markout-output-formats
version: 0.35.2
description: >-
Use when you need output other than default Markdown — plain text / Unicode, ANSI terminal
(Spectre), pretty aligned tables, or TSV/JSONL exports — or when one model must serve several
formats from a single render path (a CLI --format switch). Also covers semantic inline code
that renders as Markdown code spans but decodes to plain text in TSV/JSONL. Pick the format with
a formatter + MarkoutWriterOptions; never hand-build TSV/JSONL.
Don't decompile the assembly or web-search the API — the multi-format idioms are all here.
Output formats — one model, many formats
Default Serialize(...) emits Markdown. Pass a formatter (and optional MarkoutWriterOptions)
to get other formats. The anti-pattern is per-format string building (string.Join("\t", ...)); let
Markout project the same model to each format so columns/headers stay consistent.
Required setup
Markout has no reflection fallback. Every report needs a partial context registering each model
type and a Serialize call that passes it. [MarkoutSerializable] is optional customization, not
a prerequisite for registration.
using Markout;
[MarkoutSerializable(TitleProperty = nameof(Title))]
public class Report
{
public string Title { get; set; } = "";
[MarkoutSection(Name = "Rows")] public List<Row>? Rows { get; set; }
}
[MarkoutSerializable]
public class Row { public string Name { get; set; } = ""; public int Count { get; set; } }
[MarkoutContext(typeof(Report))]
[MarkoutContext(typeof(Row))] // every user element type of a List<T>, too
public partial class ReportContext : MarkoutSerializerContext { }
var ctx = ReportContext.Default; // the `ctx` passed in the examples below
Formatters
MarkoutSerializer.Serialize(r, Console.Out, ctx); // Markdown (default)
MarkoutSerializer.Serialize(r, Console.Out, new MarkdownFormatter(), ctx); // Markdown, explicit
MarkoutSerializer.Serialize(r, Console.Out, new PlainTextFormatter(), ctx); // plain text / logs (ASCII, no pipes)
MarkoutSerializer.Serialize(r, Console.Out, new UnicodeFormatter(), ctx); // Unicode box-drawing tables
MarkoutSerializer.Serialize(r, Console.Out, new TableFormatter(), ctx); // compact pretty rows
using Markout.Ansi.Spectre; // extra package
MarkoutSerializer.Serialize(r, Console.Out, new SpectreFormatter(AnsiConsole.Console), ctx); // ANSI
Markout.Ansi.Spectre is a separate NuGet package; Markdown/plain/table/TSV/JSONL need only Markout.
Graph sections become Markdown edge tables by default. To embed the same
graph as Mermaid without rebuilding it, select the Markdown graph mode:
MarkoutSerializer.Serialize(
report,
Console.Out,
new MarkdownFormatter(MarkdownGraphMode.Mermaid),
ctx);
TableFormatter modes + writer options
TableFormatter + MarkoutWriterOptions.TableMode selects the tabular shape:
var opts = new MarkoutWriterOptions
{
TableMode = MarkoutTableMode.Tsv, // Pretty | Tsv | Jsonl
IncludeDescription = false,
IncludeSections = new HashSet<string> { "Results" },
JsonTypedValues = true, // JSONL: emit numbers and booleans as JSON values
MaxItems = 3, // cap rows; JSONL stays record-only when rows are skipped
};
MarkoutSerializer.Serialize(report, Console.Out, new TableFormatter(), ctx, opts);
MarkoutTableMode.Pretty— columns aligned to a uniform start position.MarkoutTableMode.Tsv— stablesnake_caseheaders; never emits embedded tabs/newlines in cells.MarkoutTableMode.Jsonl— one record per row, carrying only that row's keys (heterogeneous).MaxItems = Ncaps every table to N rows. Presentation and TSV output append... and {count} more; JSONL omits the notice because every line must remain a data record. Apply the cap only to presentation options when TSV/JSONL exports must remain complete. (Or cap a property with[MarkoutMaxItems(3)]and an optionalEllipsisFormat.)
Central multi-format dispatch (the CLI --format pattern)
Route one model through one method so every command gets every format for free:
static void Render<TView, TJson>(TView view, OutputFormat fmt, MarkoutSerializerContext ctx)
{
switch (fmt)
{
case OutputFormat.Text: MarkoutSerializer.Serialize(view, Console.Out, new PlainTextFormatter(), ctx); break;
case OutputFormat.Md: MarkoutSerializer.Serialize(view, Console.Out, new MarkdownFormatter(), ctx,
new MarkoutWriterOptions { MaxItems = 3 }); break; // first 3 rows + "... and N more"
case OutputFormat.Table: MarkoutSerializer.Serialize(view, Console.Out, new TableFormatter(), ctx); break;
case OutputFormat.Tsv: MarkoutSerializer.Serialize(view, Console.Out, new TableFormatter(), ctx,
new MarkoutWriterOptions { TableMode = MarkoutTableMode.Tsv }); break;
case OutputFormat.Jsonl: MarkoutSerializer.Serialize(view, Console.Out, new TableFormatter(), ctx,
new MarkoutWriterOptions { TableMode = MarkoutTableMode.Jsonl, JsonTypedValues = true }); break;
}
}
If a format needs byte-exact output (e.g. a verbatim packet), bypass Markout for that one case and keep Markout for the structured formats — don't try to force it.
Format promises (rely on these)
- Markdown table cells normalize
|to|(not\|). - TSV uses stable
snake_caseheaders and never embeds tabs/newlines in cells. - Pretty renders the same projection as TSV, aligned.
Format-neutral inline code
Store code-like values with semantic <code>...</code> tags. XML-escape angle brackets inside
the tags:
row.Operation = "<code>dotnet test</code>";
row.Signature = "<code>Result<T> Parse<T>(string value)</code>";
Markdown renders code spans such as `Result<T> Parse<T>(string value)`. Pretty, TSV, and
JSONL remove the tags, decode the entities, and emit plain text. Do not store raw backticks or use
[MarkoutDisplayFormat("`{0}`")]; that hard-codes Markdown into the model.
JSONL must still go through Markout:
var jsonl = new MarkoutWriterOptions
{
TableMode = MarkoutTableMode.Jsonl,
JsonTypedValues = true,
};
MarkoutSerializer.Serialize(report, Console.Out, new TableFormatter(), ctx, jsonl);
Do not substitute System.Text.Json: it does not apply Markout's table projection, stable property
names, or semantic-tag decoding.
Guardrails
- One model → many formats; never hand-assemble TSV/JSONL rows.
- Reach for
IncludeSections/IncludeDescriptionto trim exports rather than a second model. - Spectre/ANSI needs the
Markout.Ansi.Spectrepackage; the rest do not.
Next.js App Router Expert
Development
A skill that turns Claude into a Next.js App Router expert.
README Generator
Development
Creates professional and comprehensive README.md files for your projects.
API Documentation Writer
Development
Generates comprehensive API documentation in OpenAPI/Swagger format.