API reference

Reference

The complete public surface of Metago in one searchable page. Use browser find to jump directly to a directive, metadata field, helper, argument, or standard template.

Contents

Usage

metago              # scan the current directory, find all templates, and generate code
metago ./path       # scan another root and find all its templates
metago -v           # show verbose logs
metago --verbose

From the project root, invoke metago without arguments. It automatically discovers every .metago template beneath that root; you do not need to name or pass template files. Metago accepts one optional scan root, is silent on success unless verbose logging is enabled, and requires at least one ordinary Go package beneath that root.

Templates can live anywhere under the root you pass to metago, except inside vendor, testdata, or hidden directories. For example, running metago from a project root can use templates from metago/stringer.metago or views/fields.metago. Template names come from {{ define "name" }} blocks and must be unique across the scan root. User templates cannot use the reserved std. prefix.

Package discovery follows the same directory exclusions. Within a package, Metago scans ordinary and _test.go files while ignoring generated Metago sidecars. Test directives generate test-only sidecars: meta_test.go for the package under test and meta_<package>_test.go for its external <package>_test package.

Generation is atomic across the scan root. If any package fails, Metago changes no files. Successful runs remove stale Metago-generated sidecars and preserve other files.

Project template defaults

metago.toml configures default named arguments for your templates and must live at the project root:

[templates."std.serde".args]
runtime = "example.com/project/internal/serdejson"

Explicit arguments on //mgo:gen and //mgo:inline override configured defaults.

Directives

Metago annotations start with //mgo: and contain no space after //:

//mgo:gen stringer

The form // mgo:gen stringer is ignored.

DirectivePurpose
//mgo:gen template [Target] [args]Run a template; write output to the package meta.go.
//mgo:inline template [Target] [args]Run a template; insert output inline, up to //mgo:end.
//mgo:endTerminates an inline block. Inserted automatically.
//mgo:<namespace> [flags] [key=value]Attach metadata to its documented symbol. Generates nothing.

A name that is neither an implemented nor reserved directive is a property namespace.

Generate a sidecar file: //mgo:gen

//mgo:gen stringer
type Status string

A directive in a declaration’s doc comment targets that declaration. This attached form is called an anchored directive. Every token after the template name is an argument:

//mgo:gen std.stringer trimprefix=Status
type Status int

Here, Status is the target and trimprefix=Status is an argument. A directive in the package doc comment has no symbol target:

//mgo:gen runtime
package jsonruntime

Metago writes package-level generated code to meta.go. In test files it writes meta_test.go for internal tests or meta_<package>_test.go for external tests. All //mgo:gen annotations in the same compilation package share one sidecar. Package-level //mgo:inline is not supported.

Generate inline: //mgo:inline

//mgo:inline stringer
type Status string

After running Metago:

//mgo:inline stringer
type Status string

func (s Status) String() string { return string(s) }

//mgo:end

An anchored //mgo:inline inserts its output after the annotated symbol. Metago inserts //mgo:end automatically; on later runs it replaces only the block between the symbol and //mgo:end — the symbol itself is never touched. Inline templates may use imports; Metago adds missing imports to the same source file.

Anchored vs standalone

An anchored directive sits in a declaration’s doc comment with no blank line before the declaration. Metago infers the target, and every token after the template name is an argument:

//mgo:gen get /posts/{postID} auth=required
func (p PostRoutes) Show(w http.ResponseWriter, r *http.Request) { ... }

This invokes get for PostRoutes.Show with the positional argument /posts/{postID} and the named argument auth=required.

A directive outside a declaration’s doc comment is standalone. To name its target explicitly, put the target after the template name:

type Status string

//mgo:inline stringer Status

func (s Status) String() string { return string(s) }

//mgo:end

A declaration containing multiple names also requires an explicit target:

//mgo:gen describe Min
const Min, Max = 1, 10

A directive attached to one spec in a declaration block targets that value:

const (
	//mgo:gen describe
	DefaultTimeout = 30

	MaxAttempts = 3
)

Inline output for a spec in a declaration block is inserted after the complete block.

Stacking directives

Anchored directives compose. Several //mgo:gen///mgo:inline lines may stack on one symbol; inline outputs land one after another, in directive order, sharing a single region and a single //mgo:end. Property lines must come after the gen/inline directives in a stack — properties before a gen/inline directive in the same comment block are an error.

//mgo:inline signals
//mgo:gen validator
//mgo:api owner=core
type AuthSignals struct {
	Email string `json:"sig_email"`
}

Attach metadata: property namespaces

Every //mgo:<namespace> comment other than an implemented or reserved directive attaches metadata to a type, struct field, method, function, interface method, package-level const, or package-level var. Properties generate nothing themselves. Use them for data only generation cares about; keep struct tags for what the runtime reads (like json:). Package properties are not supported.

//mgo:api owner=core
type User struct {
	//mgo:validate required max=100
	Name string `json:"name"`

	Age int `json:"age"` //mgo:validate min=0 max=150
}

The namespace (api, validate) follows //mgo:. Subsequent bare words are flags and key=value pairs are args. Properties must be syntactically attached through a declaration’s documentation or a field’s trailing comment; metago does not attach a separated property to the nearest declaration. An unattached property reports property "<namespace>" has no symbol to attach to. Repeating a namespace on one symbol merges it: flags union, later keys win.

The following names cannot be used as property namespaces: build, config, file, format, generate, import, include, option, options, output, package, plugin, profile, and use. The following named arguments are reserved on gen and inline: build, dir, file, format, group, mode, order, output, package, scope, tags, and the mgo namespace (mgo, mgo.*, mgo_*, mgo-*). Property arguments and positional generation arguments remain unrestricted.

Templates read props with the prop, props, propHas, and propExists helpers:

{{ define "validator" }}
func (v {{ name . }}) Validate() []string {
	var errs []string
{{- range .Fields }}
{{- if propHas . "validate" "required" }}
	if v.{{ name . }} == {{ zero . }} {
		errs = append(errs, "{{ tagName . "json" }} is required")
	}
{{- end }}
{{- end }}
	return errs
}
{{ end }}

Annotation syntax

package:    //mgo:gen templateName positional key=value      (in the package doc comment)
anchored:   //mgo:gen templateName positional key=value      (in a symbol's doc comment)
standalone: //mgo:gen templateName TargetName positional key=value

Package-anchored directives have no symbol target and only support //mgo:gen. Other anchored directives target the symbol they document. Every remaining token is an argument.

In the standalone form TargetName is optional — if omitted, Metago uses the nearest type, function, const, or var. A target can be a local type (User), top-level function (BuildUser), package-level value (DefaultTimeout), local type method (Server.Serve), local package target (server.Server, server.DefaultTimeout, server.Server.Serve), or full import-path target (net/http.Client, net/http.MethodGet, net/http.Client.Do). A first token that starts with / or contains { is always a positional arg, never a target.

In both forms, key=value parts are available in .Args; other parts are positional args available in .Argv and with arg.

Aggregating annotations: .Package.Metas

Every template can read all generation annotations in the package via .Package.Metas, sorted by file then line. Each entry has .Template, .Target, .Args, .Argv, .File, .Line, .Inline, .Anchored, and .PackageScoped. This lets one annotation generate a single artifact from many others — route tables, registries, spec files:

//mgo:gen get /posts/{postID}
func ShowPost() { ... }

//mgo:gen post /posts
func CreatePost() { ... }

//mgo:gen server
type Server struct{}
{{ define "get" }}{{ end }}
{{ define "post" }}{{ end }}
{{ define "server" }}
func (s Server) Routes() []string {
	return []string{
{{- range .Package.Metas }}
{{- if or (eq .Template "get") (eq .Template "post") }}
		"{{ upper .Template }} {{ index .Argv 0 }}",
{{- end }}
{{- end }}
	}
}
{{ end }}

The empty get and post templates produce no code. Their directives still appear in .Package.Metas, where server collects them into one route list.

.Package.Metas contains generation directives only. Read property annotations from their attached symbols with prop, props, propHas, or propExists.

Template example

{{ define "stringer" }}
func ({{ receiver . }} {{ name . }}) String() string {
    return string({{ receiver . }})
}
{{ end }}

Template data

Each template receives an invocation object:

FieldMeaning
.PackagePackage metadata.
.MetaThe current generation annotation after configured argument defaults are applied.
.TypeTarget type metadata for type and method targets; otherwise nil.
.MethodTarget method metadata for a method target; otherwise nil.
.FunctionTarget function metadata for a function target; otherwise nil.
.ValueTarget package-level const/var metadata for a value target; otherwise nil.
.NameTarget symbol or method name; empty for package-scoped invocations.
.Kindpackage, struct, interface, type, method, function, const, or var.
.TypeNameTarget type, enclosing receiver type, or explicitly declared value type.
.ArgsNamed key=value arguments, including project defaults.
.ArgvPositional annotation arguments.
.FieldsTarget struct fields; also populated for method targets from the receiver type.
.MethodsConcrete or interface methods on a type/method target.
.FunctionsAll top-level functions in the package.
.Params, .ResultsParameters and results for a function/method target.
.BodyFunction/method source text inside the braces only.
.ExprConst/var initializer source text.
.ValuesTyped constants discovered for a type/method target.
.IsPackageWhether the invocation is package-scoped.
.IsType, .IsMethod, .IsFunctionTarget-kind booleans.
.IsValue, .IsConst, .IsVarPackage-value target booleans.

The nested metadata is also public template data.

Package

FieldMeaning
.NameGo package name.
.DirPackage directory for packages beneath the scan root.
.ImportPathModule import path when Metago can derive or load one.
.TypesAll declared package types.
.FunctionsAll top-level package functions.
.ValuesAll package-level const and var symbols.
.MetasGeneration annotations in deterministic file/line order. Property annotations are excluded.

Annotation (.Meta and .Package.Metas entries)

FieldMeaning
.TemplateSelected template name.
.TargetResolved source target text; empty for package-scoped directives.
.Args, .ArgvNamed and positional arguments. .Meta.Args includes project defaults; entries reached through .Package.Metas contain source arguments only.
.File, .LineDirective source file and 1-based line.
.InlineWhether the directive uses //mgo:inline.
.AnchoredWhether it is syntactically attached to a declaration.
.PackageScopedWhether it is attached to the package declaration.
.EndLineExisting //mgo:end line, or zero when no region is bound.
.AnchorEndAnchored declaration end line; zero for standalone directives.
.AnchorLineInternal attachment bookkeeping; generation annotations currently expose zero.

Type

FieldMeaning
.NameDeclared type name.
.Kindstruct, interface, or type for another defined underlying type.
.UnderlyingUnderlying source-level type expression.
.Fields, .Methods, .ValuesFields, declared methods, and discovered typed constants.
.PropsProperty namespaces attached to the type.
.File, .LineDeclaration source file and 1-based line.

Field

FieldMeaning
.Name, .TypeField name and declared source-level type expression.
.UnderlyingResolved underlying type for local named types; empty when unchanged or unresolved.
.TypeKindResolved local kind such as struct; empty when not resolved to a local type.
.FieldsNested fields when the field resolves to a local named struct.
.TagComplete unquoted struct tag.
.EmbeddedWhether the field is embedded.
.PropsProperty namespaces attached to the field.
.Line1-based declaration line.

Method, function, parameter, and value

ObjectFields and behavior
Method.Name, .Receiver, .ReceiverType, .Params, .Results, .Body, .Props, .File, .Line. Interface methods have empty receiver/body fields.
Function.Name, .Params, .Results, .Body, .Props, .File, .Line.
Parameter/result.Name, .Type, .Variadic. Unnamed parameters/results have an empty name.
Const/var value.Name, .Type, .Value, .Expr, .Kind, .Props, .File, .Line.
Property group.Group, .Args, .Argv.

For values, .Value and .Expr both contain the initializer’s source expression, not its evaluated value. .Type contains explicit source-level type text and is empty for inferred or untyped values. Metago discovers explicitly typed const specs and later specs that inherit the type in the same const block for a type target’s .Values. It does not infer typed constants written only as a conversion, such as const Answer = Code(42).

Utilities

Metago templates include normal Go template funcs like printf, len, index, eq, and, and or, plus these helpers.

Metadata

HelperDoesUse when
name .Returns the name of a type, field, method, value, or invocation.Emitting Go identifiers.
typeof .Returns the underlying type, field type, or value type.Type-specific generation.
keys .Field names for types/invocations, sorted keys for maps.Stable output ordering.
fieldNames .Field names for a type/invocation.Building field lists.
methodNames .Comma-joined method names.Summaries/debug output.

Imports

HelperDoesUse when
imports "strconv"Adds an import to generated output; emits empty string.Generated code needs imports.
imports "encoding/json" "stdjson"Adds an aliased import.Avoiding import name conflicts.

Deduplicated fragments

Use emitOnce to emit a shared declaration once per generated output:

{{ if emitOnce "example.decodeField" }}
func decodeField(...) { ... }
{{ end }}

Namespace keys by template. An empty key is an execution error.

Template diagnostics

Use fail to reject an unsupported invocation:

{{ if not (isInt .) }}
    {{ fail "requires an integer-backed target" }}
{{ end }}

Metago reports all template failures and changes no generated files if any invocation fails.

Struct tags

HelperDoesUse when
tag . "json"Raw tag value, e.g. id,omitempty.You need the full tag.
tagName . "json"First tag part, e.g. id.JSON/db/form field names.
tagOpts . "json"Options after the first comma.Option-driven behavior.
tagHas . "json" "omitempty"Checks if a tag option exists.Handling omitempty, string, etc.
tagExists . "json"Checks if the tag key exists.Distinguishing absent vs present tags.

Example:

ID int `json:"id,omitempty"`
{{ tag . "json" }}      {{/* id,omitempty */}}
{{ tagName . "json" }}  {{/* id */}}
{{ tagHas . "json" "omitempty" }}

Props

These accept a field, type, method, function, package-level value, or invocation. All are safe on symbols without props.

HelperDoesUse when
prop . "validate" "max"A key=value from a props group, or "".Reading generation metadata.
props . "validate"The whole group, with .Args and .Argv.Ranging over a group’s data.
propHas . "validate" "required"Checks if a group contains a bare flag.Boolean markers.
propExists . "pii"Checks if the group exists at all.Distinguishing absent vs empty.

Example:

//mgo:validate required max=100
Name string `json:"name"`
{{ prop . "validate" "max" }}          {{/* 100 */}}
{{ propHas . "validate" "required" }}  {{/* true */}}
{{ propExists . "db" }}                {{/* false */}}

Field filters

These accept ., .Type, or a []Field.

HelperDoesUse when
fieldsWithTag . "json"Fields with a tag key.JSON/db/form mappers.
fieldsWithoutTag . "json"Fields without a tag key.Filling defaults.
exportedFields .Exported fields.Cross-package generated code.
unexportedFields .Unexported fields.Same-package helpers.
embeddedFields .Embedded fields.Flattening/forwarding.
nonEmbeddedFields .Non-embedded fields.Normal struct field loops.

Naming

HelperDoesUse when
snake .NameUserIDuser_id.DB columns, JSON defaults.
kebab .NameUserIDuser-id.HTML/CSS/CLI names.
camel .Nameuser_iduserID.JS-facing names.
pascal .Nameuser_idUserID.Exported Go identifiers.
initial .NameUseru.Short receivers.
receiver .UserProfileup.Method receivers.
exported .NameTrue if name starts uppercase.Visibility checks.
unexported .NameLowercases first rune.Private helper names.

Strings

HelperDoesUse when
lower sLowercase.Simple names.
upper sUppercase.Constants/text.
contains s subSubstring check.Conditional output.
hasPrefix s prefixPrefix check.Name conventions.
hasSuffix s suffixSuffix check.Name conventions.
trimPrefix s prefixRemove prefix.Deriving names.
trimSuffix s suffixRemove suffix.Deriving names.
replace s old newReplace all.Name cleanup.
split s sepSplit string.Small lists.
join list sepJoin strings.Emitting lists.
quote sGo-quote a string.Safe string literals.

Types

HelperDoesUse when
isString .Resolved type is string.String-specific code.
isBool .Resolved type is bool.Boolean code.
isInt .Resolved type is any signed or unsigned integer, including uintptr.Any integer-specific code.
isUint .Resolved type is uint, uint8, uint16, uint32, uint64, or uintptr.Unsigned formatting or bounds.
isFloat .Resolved type is float32 or float64.Floating-point code.
isComplex .Resolved type is complex64 or complex128.Complex-number code.
isPrimitive .String, bool, integer, float, or complex.Primitive-only templates.
isSlice .Resolved type starts with [].Collections.
isMap .Resolved type starts with map[.Maps.
isPointer .Resolved type starts with *.Nil checks/dereferencing.
elem .Element of a resolved []T or *T; otherwise "".Collection/pointer code.
zero .Go zero-value expression for metadata or a raw type string.Defaults and initializers.

Type predicates resolve local named types. For example, type Count uint64 satisfies both isInt and isUint; a field declared as Count still resolves to uint64. typeof, by contrast, returns the target type’s underlying expression but preserves a field, parameter, or value’s declared type text.

Data

HelperDoesUse when
dict "k" vCreates a map.Passing data to nested templates.
list "a" "b"Creates a list.Inline enumerations.
get m "key"Reads a map key or exported struct field.Optional/dynamic lookups.
arg 0 / arg "key"Reads positional or named annotation args.Annotation args.
default fallback valueReturns fallback if value is zero.Optional args.

Examples:

{{ default "users" (arg "table") }}
{{ arg "table" | default "users" }}
{{ arg 0 }}

Standard templates

Standard templates are embedded in the metago binary, work without local template files, and use the reserved std. namespace. User templates cannot define names beginning with std..

std.stringer

//mgo:gen std.stringer trimprefix=Status
type Status int

Generates String() string for a primitive-backed defined type: string, bool, signed/unsigned integer, float, or complex. Declared typed constants become switch cases, with unknown values shown as Type(value) and strings quoted. A type without constants returns its underlying value’s standard text representation directly. trimprefix=value removes that prefix from constant names in the returned strings. It defaults to no trimming.

std.enum

//mgo:gen std.enum
type Status int

Supports string-, signed integer-, unsigned integer-, and float-backed types with at least one discovered typed constant. It generates:

func (v Status) String() string
func ParseStatus(value string) (Status, error)
func (v Status) Valid() bool
func StatusValues() []Status
func (v Status) MarshalJSON() ([]byte, error)
func (v *Status) UnmarshalJSON(data []byte) error

Integer and float enums strip the type name from constant names by default; override the prefix with trimprefix=value. String enums use each constant’s string value. JSON uses the same string form and rejects unknown values.

std.mock

//mgo:gen std.mock
type Store interface {
    Get(id string) (User, error)
    Save(user User) error
}

Generates MockStore, one MethodFunc field per discovered method, and forwarding methods that satisfy the interface. Assign function fields directly in tests. Interface method parameters should be named; embedded interface methods are not expanded, and variadic forwarding is not currently special-cased.

std.serde.jsonruntime and std.serde

Serde is a reflection-free JSON coder-decoder generated entirely by Metago templates. First generate the shared runtime:

// Package jsonruntime contains generated JSON support.
//
//mgo:gen std.serde.jsonruntime
package jsonruntime

Configure its import path once:

[templates."std.serde".args]
runtime = "example.com/project/internal/jsonruntime"

Then derive codecs:

//mgo:gen std.serde
type User struct {
    ID   int64    `json:"id"`
    Name string   `json:"name"`
    Tags []string `json:"tags"`
}

std.serde generates MarshalJSON and UnmarshalJSON. Without a runtime argument, generated codecs expect std.serde.jsonruntime in the same package. An explicit directive argument overrides metago.toml.

Named arguments:

ArgumentDefaultBehavior
runtime=import/pathSame packageImport the generated runtime from this path.
`strict=truefalse`false
maxinput=NDisabledReject input larger than N bytes before receiver-state allocation. Zero disables the cap.
maxdepth=N10000Maximum JSON nesting depth. Zero keeps the default.

strict accepts only true or false. maxinput and maxdepth must be unsigned 64-bit decimal integers; invalid values fail generation.

Generated paths cover built-in and methodless named scalars, pointers, slices, arrays, bytes, json.RawMessage, string-keyed maps, nested generated types, and common combinations of those shapes. Unsupported fields use encoding/json and continue to support json.Marshaler, json.Unmarshaler, encoding.TextMarshaler, and encoding.TextUnmarshaler. Structs containing anonymous fields use encoding/json for the complete struct.

Serde follows encoding/json behavior for field names and visibility, -, omitempty, omitzero, and supported string options. Decode failures are transactional: the receiver is unchanged. Decoded retained strings do not alias the input. Recursive generated pointers and containers detect cycles while encoding, and errors include field/type/JSON-kind context and offsets.

See std/serde for implementation notes, compatibility policy, reliability tests, benchmarks, and reproducible benchmark commands.