sushi-module.toml
The file a module writes to say what it is. hub reads it from a checkout inside the workspace;
when it is absent, hub falls back to its own catalog entry for a module it already knows. A
checkout that carries one is recognised whether or not the catalog lists it.
It sits at the repository root, beside CMakeLists.txt. The dependency fragment lives under
cli/ because hub owns that format; the manifest is the module’s own identity and belongs
where a reader looks first.
The file
# What this module is. `hub` reads this when the checkout is in a workspace; when it is
# absent, `hub` falls back to its own catalog entry for a module it already knows.
[module]
name = "sushiruntime" # the name on the command line and the directory under the root
alias = "sr" # the module's own CLI program name
distribution = "source" # "source" to clone, "binary" for a compiled release
repo = "https://github.com/sushisystems/sushiruntime.git"
# fragment = "cli/sushistack.deps.toml" # optional; this is the default
The keys
| Key | Required | What it is |
|---|---|---|
name |
yes | The name on the command line, and the directory the checkout sits in |
alias |
yes | The module’s own CLI program name, accepted wherever a name is |
distribution |
yes | source to clone, binary for a module sold as a compiled release |
repo |
no | The git clone URL. A module that is never cloned by name may omit it |
fragment |
no | Path to the dependency fragment, relative to this file. Defaults to cli/sushistack.deps.toml, which is where all six repositories keep it |
Three keys are required and two are not, because a required key that every file spells the same way is a constant six repositories have to repeat.
name must equal the directory the checkout sits in. Every module’s cmake resolves a sibling by
the flat <workspace>/<module> layout, so a manifest that disagrees would lie about where the
module is; a reader raises rather than believing it.
What a reader does with a shape it does not know
A key it does not know is ignored, so a newer module can add one without breaking an older
hub.
A table it does not know is an error that names the file. This is not symmetry for its own
sake. Until 2026-09-22 the dependency fragment’s reader skipped every top-level key it could not
read, and sushidsp’s whole fragment — a required sdl2 among it — went unprovisioned without
a word. A section a reader silently drops is a section nobody knows is missing.
hub reads this file and never writes it. A module owns its own manifest.
When both a manifest and a catalog entry exist
The checkout wins. A module’s CLI is installed from the checkout, so the alias the checkout
declares is the one that came true on the machine; the catalog is hub’s own copy and can be
older than what is on disk. hub status lists the catalog’s modules in catalog order, then the
self-describing ones in name order, so two commands list them the same way twice.
A manifest that will not read is reported rather than obeyed. A command acting on one module
says so and stops; hub status, which describes the whole workspace, names the file as a warning
and describes everything else.
What the manifest does not do
It does not open the catalog. hub add <name> clones from a repo URL it must know before any
checkout exists, so a name only a manifest knows cannot be added by name — the manifest
describes a checkout that is already on disk. A module can therefore be known to hub status
and unknown to hub add, and both commands say so plainly.
Where it is used
- The catalog it falls back to:
cli/sushihub/catalog.toml. - The other file a module owns: its dependency fragment at
cli/sushistack.deps.toml, which says what to install rather than what the module is. - The design behind both:
../design/WORKSPACE_DECOUPLING.md§3.1 and §3.2.

