workflow-toolchain
Set up, adopt, or update the bitwise-media-group/toolchain shared mise task library in a repository — mount it as a git submodule at .mise/ pinned to the latest release tag, write the root mise.toml (
Files1
View on GitHubSKILL.mdplugins/workflow/skills/workflow-toolchain/SKILL.md
GitHubSet up the bitwise toolchain
bitwise-media-group/toolchain is the org's shared build layer:
pinned developer tools, one mise task archetype per primary language, and the house lint/license policy. A repo
consumes it as a git submodule mounted at .mise/, pins its own language runtime in a root mise.toml, and keeps a
one-line Makefile. The reusable CI workflows run those mise tasks, so this is also the CI contract — wire the callers
with the actions-reusable-workflows skill.
This skill is the procedure. The library's own docs at the release you pin are the source of truth for archetype details, knobs, and runtime versions — they move faster than this skill, so read them instead of recalling them.
1. Resolve the latest release and read its docs
url=https://github.com/bitwise-media-group/toolchain.git
tag=$(git ls-remote --tags --refs --sort=-v:refname "$url" 'v*.*.*' | head -n1 | sed 's|.*refs/tags/||')
src=$(mktemp -d "${TMPDIR:-/tmp}/toolchain.XXXXXX")
git clone --quiet --depth 1 --branch "$tag" "$url" "$src"
Read from $src, in this order: docs/getting-started/adopt.md (the three files and housekeeping),
docs/archetypes/index.md (which archetype), docs/archetypes/<archetype>.md (its knobs), and README.md. A repo on
the old layout also reads docs/reference/migrating.md. The same pages are published at
https://oss.bitwisemedia.uk/toolchain/, but that site tracks the newest release — the clone matches the tag you pin.
2. Pick exactly one archetype
| The repo is… | Archetype |
|---|---|
| a Go CLI or service | go |
| a TypeScript library or GitHub Action | node |
| a Python package, or a Zensical docs-only site | python |
| a SwiftPM package or CLI | swift |
| a Terraform/OpenTofu module or environment | terraform |
| Markdown/YAML with nothing to build or test | common only |
Archetypes do not stack: mise merges included task files whole-task and the later include wins, so a second
archetype silently replaces the first's fmt/lint/build/test/ci/pr. A second language becomes repo-local
tasks inside the primary archetype. If the language is ambiguous, ask.
3. Mount the submodule at the tag
git submodule add --name toolchain "$url" .mise
git -C .mise -c advice.detachedHead=false checkout --quiet "$tag"
git config -f .gitmodules submodule.toolchain.branch "$tag"
git add .gitmodules .mise
The mount point is load-bearing: mise reads .mise/config.toml as its own config (shared [settings], [tools],
[vars]), and every task path assumes .mise/. Recording the tag as the submodule branch is what lets Renovate's
git-submodules manager propose each newer tag. git submodule add -b <tag> does not work — it only accepts
branches.
4. Write the root mise.toml
Take the archetype's block from adopt.md at the pinned tag. Its shape:
[tools]
# the repo's language runtime — the library never pins it. go also pins
# "go:golang.org/x/vuln/cmd/govulncheck"; python and terraform pin nothing.
go = "<version from adopt.md, or the latest stable>"
[vars]
# structural knobs from docs/archetypes/<archetype>.md, e.g. app / app_pkg for go
[task_config]
includes = [".mise/common/tasks.toml", ".mise/archetypes/go/tasks.toml"] # common first, then one archetype
A common-only repo includes just .mise/common/tasks.toml. Repo-local tasks go in [tasks]; to redefine an
archetype task, put it in a repo tasks.toml appended after the archetype in includes.
5. Reduce the Makefile to one include
include .mise/archetypes/<archetype>/include.mk
(include .mise/common/include.mk for common only.) Every make <target> forwards to mise run <target>; make-side
prerequisites (pr: docs) go beneath the include. CI never calls make.
6. Housekeeping
.gitignore— the outputsadopt.mdlists for the archetype (coverage/, plusnode_modules/,.venv/,site/,.build/,.swiftpm/,dist/as applicable)..licenseignore— only generated files the defaults don't already skip (a node action listsdist/**).- No prose or workflow-lint config — prettier, markdownlint, actionlint and zizmor read the house defaults from
.mise/. Commit your own.prettierrc.yamletc. only to override one wholesale. - Remove what the toolchain replaces —
tools/go.modtool modules, linterdevDependencies,.bin/, hand-written Makefile targets, and no-op task stubs (CI skips tasks a repo doesn't define).
7. Verify
mise trust --all # once per clone; CI trusts the workspace itself
mise tasks # or: make help
make lint # then build / test where the archetype defines them
Updating and the never-re-lock rule
Renovate bumps .mise to each new tag. By hand: git -C .mise fetch --tags, check out the new tag, update
submodule.toolchain.branch in .gitmodules, and stage both. Shared tool pins live inside the library, so
never run mise lock or mise upgrade in a consumer — it writes into the submodule. Lock only the repo's own pins
(mise lock <tool>), and change shared pins upstream in the toolchain repo.