1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# A complete verctl.toml. Every table here is live, not commented out, so
# `tests/examples.rs` parses this exact file and plans from it — the examples
# cannot drift from the schema without failing the build. Copy it and delete
# what you do not need; only [[packages]] is required.
# `cargo` and `npm` are stock drivers and `cargo` and `bun` are stock
# publishers. Redeclaring one merges over the stock recipe rather than
# replacing it, so this pair changes nothing and is here to show the shape.
# Because it is a merge, a table may carry only the field it overrides.
[]
= "toml"
= ["workspace.package.version", "package.version"]
[]
= "json"
= ["version"]
# after = "bun install" # omit and verctl infers from the lockfile
# A manifest verctl neither parses nor knows: give it a read and a write
# command instead of format+keys. A string is a mise task, an array is execvp
# (no shell). Stdin is the file; stdout is the version (read) or the whole new
# file (write), and a write also gets VERCTL_VERSION.
[]
= ["cat"]
= ["printenv", "VERCTL_VERSION"]
# Any stack publishes through one table of argv. This adds uv alongside the
# stock cargo and bun recipes without a new verb.
[]
= "package"
= ["uv", "publish"]
[[]]
= "verctl"
= "Cargo.toml"
# driver = "cargo" # inferred from the file name
[[]]
= "@org/pkg"
= "package.json"
= "bun"
= "github"
# changelog = "docs/PKG.md" # defaults to CHANGELOG.md beside the manifest
# A file name that implies nothing, so both the driver and the publisher are
# named. This is what the `plain` driver and `[publishers.twine]` above are
# for — nothing here is declared without a package that uses it.
[[]]
= "py-tool"
= "VERSION"
= "plain"
= "twine"
# One argv after every bump, on the Version PR. `stage` lists the extra paths
# it may write; any other dirty file fails the run.
[]
= ["mise", "run", "version-sync"]
= ["packages/*/src/version.rs"]
# Machines are declared once. The header names one, `labels` is how GitHub
# finds it — every label at once, so `big` is a single machine carrying three
# labels, not three machines. verctl ships no built-in machine names: this
# table is yours, and only `labels` ever reaches runs-on.
[]
= ["self-hosted", "linux", "x64"]
[]
= ["nscloud-ubuntu-24.04-amd64-4x8"]
# Omit [assets] entirely for a library. `bin` is the recipe every target
# shares; prepare/build/binary override the stock rust recipe.
[]
= "verctl"
# One [assets.NAME] table per host binary. The name is the job, the tarball,
# and the platform. darwin-arm64 and linux-x64 are built in, so naming one is
# enough — and it keeps free hosted minutes.
[]
# Name a `runner` only when the built-in machine is wrong. One tarball is one
# machine, so this is one name and never a list.
[]
= "big"
# A name outside darwin-arm64 / linux-x64 describes a platform verctl knows
# nothing about, so it must describe all of it.
[]
= "ns"
= "linux"
= "arm64"
= "aarch64-unknown-linux-gnu"
# PR and push validation. Omit [ci] for one `verify` job on ubuntu-latest.
# A job may name several machines: one check each, `verify (ns)` and
# `verify (big)`. No os/arch/triple — validation does not cross-compile.
[]
= ["ns", "big"]
# A second job is a second table, and stays a separate check.
[]
= ["ns"]
# Where served-file templates live. These are the defaults, so a repo that
# follows the convention writes no [templates] table at all. Each template
# declares its own target — see docs/served-files.md.
[]
= ".verctl/templates"
= ".jinja"
# A version spelling, named once here and listed by every file that carries it,
# so two files that say the same thing say it in one place. `match` is literal
# text with `{version}` where the version goes; `occurrences` is how often a
# listing file must say it, and both too few and too many stop the release.
[]
= "github:victor-software-house/verctl@{version}"
= "once"
# "many" is for a document whose examples come and go, where only "still
# tracked" is worth asserting. "never" guards a spelling that was retired,
# `{ exactly = 2 }` and `{ at_least = 2 }` name counts.
[]
= "verctl@{version}"
= "many"
# Files that carry a version and cannot be generated: `prepare` rewrites them
# onto the Version PR commit, which is the commit the tag names, so the released
# tree carries them. A file that must name an already-published tarball — the
# pin a repo's own release lane installs — cannot be listed here either, because
# it can only move to a version that already exists.
#
# `tool` is the structural form: a mise `[tools]` entry, plus every `?ref=v…`
# include in the same file whose URL names this repo.
[[]]
= "examples/mise.toml"
= "github:victor-software-house/verctl"
= "verctl"
# `patterns` is the textual form, for a file with no format to speak of — a
# README sentence, a bash header. A file lists the patterns it carries by name;
# a name nothing declares, a name listed twice, and a pattern no file lists all
# fail the load.
[[]]
= "README.md"
= "verctl"
= ["install", "mention"]
# The same `install` spelling, in a second file. Naming it once is the point.
[[]]
= "docs/install.md"
= "verctl"
= ["install"]