Configuration

Everything has a working default, so a repository that has configured nothing still works: put a Markdown file in .changes, tag a commit, and the changelog follows. Configuration is for what only the project knows — where its issues and releases live — and for choices worth writing down.

The file

moneta reads omniblack.yaml, looking from the working directory up to the repository root and using the first one it finds. The file is shared with the other omniblack tools:

scopes:
  - name: history
  - name: render
  - name: ci
    internal: true

moneta:
  strict-scopes: true
  issues:
    url: "https://gitlab.com/terryp/moneta/-/issues/{{ .ID }}"
  releases:
    url: "https://gitlab.com/terryp/moneta/-/releases/{{ .Tag }}"

scopes is at the top level because it is for commits as well as fragments: moneta create offers it, and moneta commit-msg and moneta check --commits check commit scopes against it. Everything that is moneta’s alone goes under moneta:.

moneta ignores the top-level keys of other tools, so adding one does not break it. A misspelled key under moneta: is an error, and so is a bad value. Both are reported when the file is loaded, so a setting cannot silently do nothing.

An empty file, or a moneta: key with nothing under it, gives the defaults.

Moving from .moneta.yaml

moneta does not read .moneta.yaml. If one is nearer the working directory than any omniblack.yaml, moneta stops with an error rather than rendering from the defaults. With the defaults, the changelog would lose its issue and release links without a warning. To move:

  1. Put the contents of .moneta.yaml under moneta: in omniblack.yaml.

  2. Move scopes.known to a top-level scopes list, one - name: per scope.

  3. Rename scopes.strict to moneta.strict-scopes.

  4. Delete .moneta.yaml.

Templates

moneta.filename, moneta.id, moneta.issues.url, moneta.merge-requests.url and moneta.releases.url are Go text/templates. moneta render --template uses the same language, so there is one to learn rather than one per field.

Quote them. A YAML scalar that starts with {{ is a flow mapping, not a string.

Every template is tried when the file is loaded, against two different inputs. moneta refuses the configuration if the template does not parse, names a field that does not exist, or gives the same output for both inputs. The last one catches a URL with no {{ .ID }} in it, which would link every issue to the same page. These errors come at load, not in a published changelog.

Reference

Shared

scopes

The parts of the project, for fragments and for commits. Default: none. Each entry has a name, which must not be empty or be listed twice, and an optional internal. A bare string such as - parser is an error; write - name: parser.

internal: true marks a part nobody using the project can notice, such as CI or the tests. A branch whose commits are all in internal scopes needs no fragment (see Commands), and a fragment may not use an internal scope. moneta create does not offer one.

Under moneta:

changes-dir

Where fragments live, relative to the repository root. Default: .changes.

tag-prefix

What comes before the version number in a release tag. Default: v. Set it to "" for a project that tags 1.2.0.

tag-pattern

A glob that names the tags that are releases, in the syntax git tag -l uses. Default: none, and then a tag is a release only if it is a version under tag-prefix, so a latest or a deploy tag is not in the changelog. Set it when some version tags are not yours. For example, a repository that releases two components as a/v1.2.0 and b/v0.3.0 sets tag-prefix: a/v and tag-pattern: "a/v*" for the changelog of a. When you set a pattern, it is the only rule: a tag it matches is a release even if the tag is not a version. The pattern must match tag-prefix followed by a version, and it must match first-version. If it does not, moneta ignores the tags that moneta next suggests. To keep a changelog for each component, with fragments that say which component they are for, use modules instead.

first-version

What moneta next suggests when there is no release yet. Default: v0.1.0.

since

Ignore every tag at or below this one. Default: none. A project that starts to use moneta later in its life has old tags with no .changes directory. Those tags do no harm to attribution, but each one shows as an empty version. Set since to the last tag before moneta.

yank-prefix

The tag namespace that withdraws a release: yanked/v1.2.0 yanks v1.2.0, and the tag’s annotation is the reason. Default: yanked/.

content

Where entry text comes from: worktree, head or as-published. Default: worktree. It never changes which version an entry is in. With modules, it also says where a fragment’s modules: comes from. moneta render --content overrides it. Commands explains the three values.

filename

The name moneta new and moneta create give a fragment. A template over .Slug, .Year, .Month, .Day, .Hour, .Minute, .Timestamp, .Kind, .Scope, .Module and .UUID. The time fields are UTC and zero-padded. .Timestamp is all of them in one word, such as 20260925T143000Z. .Scope is every scope joined with -, and .Module is every module joined with -. .UUID is a new UUIDv7, the same one id sees. Default: {{ .Slug }}-{{ .Year }}-{{ .Month }}-{{ .Day }}-{{ .Hour }}-{{ .Minute }}.md.

id

The id: that moneta new, moneta create and moneta commit write into a fragment, so the fragment keeps its entry when it is moved or renamed. A template over the same fields as filename. Default: {{ .UUID }}. Set it to "" to write no id:; the filename stem is then the key. Entries of one kind are listed in key order, so with no id: put {{ .Timestamp }} first in filename to keep them in the order they were written. A template that gives the same id to every fragment is an error, because fragments that share an id are one entry.

strict-scopes

Reject a fragment whose scope is not in the top-level scopes, or is internal. Default: false. Setting it with no scope that is not internal is an error, because then every fragment that has a scope would fail. Commit scopes do not use this setting: they are always checked against the list when there is one.

kinds

The kinds of change, in the order the changelog shows them. Each has a name, the heading it renders under, and a bump of none, patch, minor or major. A kinds list replaces the default list. It does not add to it. Default: Keep a Changelog’s kinds.

name

heading

bump

added

Added

minor

changed

Changed

minor

deprecated

Deprecated

minor

removed

Removed

major

fixed

Fixed

patch

security

Security

patch

pre-1.0.policy

How to bump below 1.0. soften makes a breaking change a minor bump and everything else a patch. strict treats 0.x like any other major version. Default: soften.

issues.url

Makes each issue reference a link. A template over .ID, the reference as the fragment wrote it. Default: none, and references stay plain text.

issues.required

Reject a fragment that has no issues:. Default: false.

merge-requests.url

The same as issues.url, for a fragment’s merge_requests:.

check.require-fragment

Makes moneta check fail a branch that changes the project and adds no fragment, as if --require-fragment were given. --require-fragment=false turns it off for one run. Default: false. Commands explains the gate.

releases.url

Makes each release heading a link. A template over .Tag and .Module. Only the version is the link. The date and the [YANKED] marker are outside it, and Unreleased is never a link, because it has no tag. Default: none.

modules

Splits the repository into modules. Each module has its own tags, its own releases and its own changelog. Default: none, and the repository has one changelog. The Modules section below tells how they work. Each entry has these keys:

key

default

name

required

Must be unique. No /, , or whitespace.

path

none

The module’s directory, relative to the root. moneta uses the module when it runs in this directory.

tag-prefix

<name>/v

tag-pattern

<tag-prefix>*

Two modules must not match the same tag.

first-version

<tag-prefix>0.1.0

since

none

A tag of this module.

releases.url

moneta.releases.url

When you set modules, the top-level tag-prefix, tag-pattern, first-version and since have no effect, so setting one is an error. Set them on each module.

Modules

Some repositories release more than one thing. With modules, each one has its own tags and its own changelog:

moneta:
  modules:
    - name: core
      path: core
    - name: cli
      path: cmd/cli

The tags are core/v1.2.0 and cli/v0.3.0. A yank works in the same way: yanked/core/v1.2.0 withdraws core/v1.2.0.

The fragments stay in the one changes-dir. Each fragment names the modules it is for:

---
kind: fixed
modules: [core, cli]
---

Read the configuration from the shared file.

A change to shared code often ships in more than one module. One fragment that names both modules says this once. Each module announces the entry in its own next release.

Each module’s changelog uses the same rule as a repository without modules. The only difference is that it uses the module’s tags and the fragments that name the module.

moneta reads modules: in the same way as the text of the fragment: from the working tree. Thus you can correct it after a release, as you can correct a typo:

  • If you add a module to a fragment after a release, the entry goes into the first release of that module whose tag holds the fragment. That is the release that shipped it.

  • If you remove a module from a fragment, the entry goes out of the changelog of that module, released versions too.

The tags still decide which release of the module holds the entry. If the fragment is deleted, moneta reads modules: from the copy in the tag, as it does for the text. --content as-published reads modules: from the tags for every fragment, so each module shows what its tags shipped.

moneta check rejects a fragment that names no module, or a module that is not in the list. Such a fragment is not in a changelog. A fragment that was written before the repository had modules names none, and is not in any changelog. To hide the old releases, set since on each module.

The commands that read a changelog (render, next, list) work on one module. The Modules section of Commands tells how to select it.