Config

NAME

App::Ariza::Config - the per-app ariza.toml manifest

SYNOPSIS


use App::Ariza::Config;

my $cfg = App::Ariza::Config.load('/path/to/App-Moneymoor'.IO);

say $cfg.app-name;            # App::Moneymoor
say $cfg.app-exec;            # moneymoor
say $cfg.app-display;         # Moneymoor
say $cfg.bundle-platforms;    # (macos-arm64 linux-x86_64-glibc windows-x86_64)
say $cfg.bundle-native;       # (notcurses sqlcipher)
say $cfg.installer-repo;      # m-doughty/App-Moneymoor
say $cfg.updates-enabled;     # False unless [updates] opts in
say $cfg.ci-ariza-source;     # fez  (or a URL zef can install from)
say $cfg.smoke-command;       # moneymoor --version
say $cfg.licensing-strict;    # False
say $cfg.licensing-third-party;   # ({name => Inter, spdx-license => OFL-1.1})

# Every smoke command as argv, with paths substituted in:
.say for $cfg.smoke-commands(:exec($launcher), :raku($raku), :tmp($scratch));
# (/…/bin/moneymoor --version)
# (/…/rakudo/bin/raku -e use App::Moneymoor::DB; … /…/scratch)

.note for $cfg.warnings;      # unrecognised keys, if any

DESCRIPTION

ariza.toml lives in the app's repository, not in ariza's. It is how an application declares what it is and what a bundle of it needs, so that ariza stays a general tool rather than a list of special cases about specific apps.

THE V1 SCHEMA


[app]
name = "App::Moneymoor"      # dist name
exec = "moneymoor"           # launcher/binary name
display = "Moneymoor"

[bundle]
platforms = ["macos-arm64", "linux-x86_64-glibc", "windows-x86_64"]
native = ["notcurses", "sqlcipher"]
smoke = "{exec} --version"   # command template run by ariza smoke

[installer]
repo = "m-doughty/App-Moneymoor"   # where the releases live
warm = "--version"                 # run once at install time; false skips it

[updates]
enabled = true                     # weekly managed-install prompt

[ci]
ariza-source = "fez"         # how the scaffolded workflows install ariza

[licensing]
strict = false               # an unattributed native pack fails the build

[app]

All three keys are required; a manifest missing any of them dies at load time naming the key and the file.

  • name — the distribution name as zef knows it (App::Moneymoor, colons and all), not the repository directory name.

  • exec — the launcher name: the command a user types, the basename of the binary inside a bundle, and the {exec} expansion in bundle.smoke.

  • display — the human-facing name, for window titles, desktop entries and Start Menu shortcuts. Required rather than derived, because the correct capitalisation of a product name is not something a tool should be guessing at.

[bundle]

Every key optional.

  • platforms — which App::Ariza::Platform slugs to build for. Each entry must be a slug ariza knows; an unknown one is a hard error (see below). Absent means an empty list.

  • native — names of native libraries the bundle has to carry beyond the Raku runtime itself. Free-form strings in v1; a later phase gives them meaning.

  • smoke — what ariza smoke runs against a freshly built bundle to prove it works. See below.

bundle.smoke

Three shapes, in increasing order of how much you need:


# One command:
smoke = "{exec} --version"

# Several:
smoke = ["{exec} --version", "{exec} --help"]

# Commands that must not go anywhere near a shell:
smoke = [
    ["{exec}", "--version"],
    ["{raku}", "-e", '''
use App::Moneymoor::DB;
…
''', "{tmp}"],
]

A string entry is split on whitespace. An array entry is taken word for word, verbatim — which is the only way to express a command containing spaces, quotes, or an entire program, and the reason the schema grew an array form at all. Nothing is ever passed through a shell, in either form, so there is no quoting layer to get wrong.

The two entry shapes cannot be mixed in one file: Config::TOML enforces the pre-1.0 rule that an array's elements are all of one type, so a list is either all strings or all arrays. That is a limitation of the parser rather than of this schema — smoke-argvs is happy to accept either — and the workaround is to write the whole list as argv arrays, which is the better form anyway.

[installer]

  • repo — the GitHub owner/name whose releases the generated end-user installers download from. App::Ariza::Installer builds three URLs out of it: the releases/latest redirect it reads a tag from, the bundle asset, and that asset's .sha256 sibling.

Optional in the schema — an app that is not published anywhere has no repository to name — but required by ariza installers, which says so rather than rendering a script that 404s.

The value must be exactly owner/name. A full URL, a trailing .git, or a stray space is a hard error for the same reason an unknown platform slug is: the shape is closed, so a typo cannot be a future feature, and the resulting 404 lands on a stranger's machine rather than on the author's.

  • warm — the arguments the generated installers run the freshly installed launcher with, once, before they print the parting message. Defaults to --version.

Whatever a first launch has to do that later ones do not — paging a few hundred megabytes off a cold disk, building a per-user state directory, touching a keychain — is done there, while the installer is on screen saying so, rather than the first time the user actually wants the application.

Four spellings:


[installer]
warm = "--version"            # arguments, whitespace-split
warm = ["--check", "--quiet"] # the same, word for word
warm = true                   # the default arguments, said out loud
warm = false                  # no warm-up step at all

An empty string or array is an error rather than either of the two things it might mean. Running the launcher with no arguments starts the application, and a full-screen application does not return — the installers deliberately impose no timeout, so that spelling would be a hang. false is how you say "skip it", and arguments the app returns from are how you say anything else.

The warm-up never fails an install. See App::Ariza::Installer.

Placeholders

{exec} is expanded by smoke-command against app.exec. App::Ariza::Smoke expands rather more, against a bundle it has just unpacked:

  • {exec} — the launcher, < <bundle>/bin/<exec> >

  • {raku} — the bundled interpreter

  • {site} — the bundle's module repository

  • {native} — the staged native libraries

  • {bundle} — the bundle root

  • {tmp} — a writable scratch directory, created per run

A placeholder that nothing supplies is an error, not an empty string: a smoke command with a hole in it does not fail, it silently runs something else.

[updates]

enabled is a boolean and defaults to false. When true, bundles carry the managed-install update coordinator and trusted local installer snapshot described by App::Ariza::Update. The coordinator checks at most weekly and offers the user install-now, ask-next-time and ignore-this-version choices.

Enabling updates requires installer.repo. The repository is not duplicated in this table: discovery and the private exact-candidate installer must use the same GitHub release identity as the public generated installers.

[ci]

One key, optional, read only by App::Ariza::CI when it scaffolds an app's GitHub Actions workflows.

  • ariza-source — where the generated release.yml installs ariza itself from. "fez" (the default) renders zef install --/test 'App::Ariza:ver<0.2.2+>:auth<zef:apogee>'; the version floor prevents an older bundler from silently rebuilding a release and the author qualifier prevents a same-named distribution from satisfying it. Anything else is passed to zef verbatim, which is how a repository URL gets used before ariza is published, or while a release is being tested:


[ci]
ariza-source = "https://github.com/m-doughty/App-Ariza.git"

Whichever is chosen, the other is rendered beside it as a comment, so switching between them in a hurry is an uncomment rather than a remembering exercise.

Unlike a platform slug this is not a closed set — anything zef install accepts is legitimate, and enumerating those here would date badly — so only an empty value is an error, because it renders a workflow step that installs nothing and succeeds.

[licensing]

Everything about what a bundle redistributes is read out of the bundle itself — a native pack's own licensing kit, each installed distribution's META6.json license, ariza's record of the vendored runtime. This table is for the two things that are not readable from anywhere: how strict to be about a payload nobody attributed, and what the app ships that ariza cannot see.

Every key is optional, and an app that writes none of it still gets a complete THIRD-PARTY.md.


[licensing]
# A native pack with no licensing manifest is a warning and a visible
# "unattributed" row by default. `true` makes it a failed build.
strict = true

# The application's own row. Every field defaults from the app's
# META6.json (and its LICENSE file), so most apps need none of this.
[licensing.app]
copyright = "Copyright 2026 A Person"
project-url = "https://example.org/moneymoor"
notes = "The bundled build enables the encrypted-store feature."

# Anything the app ships that ariza cannot see: fonts, datasets,
# artwork, a vendored C library of its own.
[[licensing.third-party]]
name = "Inter"
version = "4.0"
spdx-license = "OFL-1.1"                   # a text ariza ships
copyright = "Copyright 2016 The Inter Project Authors"
project-url = "https://rsms.me/inter/"
files = ["resources/fonts/Inter-*.ttf"]

[[licensing.third-party]]
name = "The cover artwork"
spdx-license = "CC-BY-4.0"                 # one it does not: name a file
license-files = ["licenses/CC-BY-4.0.txt"] # path in THIS repository
files = ["resources/art/*.png"]

# A distribution in the closure whose own metadata is wrong or absent.
[[licensing.dists]]
name = "Some::Ancient::Module"
spdx-license = "Artistic-2.0"
notes = "Its META6 has no license field; confirmed from its LICENSE."

The three row tables share one vocabulary — id, name, version, spdx-license, conveyed-under, copyright, project-url, source, notes, license-files, files — and it is deliberately the same vocabulary a native pack's third-party.json uses, so an app describes a bundled font in the words a pack describes FFmpeg in. licensing.app takes neither id (there is one application) nor files (the bundle is the file); licensing.dists corrects a distribution ariza already found, so it takes neither id, source nor files.

license-files entries are paths inside the app's repository, never absolute: a licence text belongs to the repository that declares it, and an absolute path in a committed config file is a path that exists on one machine. Where a row omits them, ariza uses the text it ships for the row's SPDX identifier — it ships Artistic-2.0, MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-2.0, GPL-3.0, AGPL-3.0, Zlib, ISC, X11, OFL-1.1, Unlicense and a public-domain statement — and an identifier it has no text for is a hard error naming this key as the fix.

NOASSERTION

spdx-license = "NOASSERTION" is SPDX's own spelling for "somebody looked and could not determine the licensing", and it is accepted in a [[licensing.dists]] or [[licensing.third-party]] row — after looking, as a declaration on the record. No licence text is looked up for it, since there is none, and the generated document says in words that licensing was not asserted and points at the component's own repository.

It is available nowhere else. A distribution whose own metadata says NOASSERTION fails like any other missing licence (nobody has looked yet), [licensing.app] may not say it about the application itself (there is nobody to look on its behalf), and licensing.strict refuses a bundle that contains one — strict means every component names a licence, and "we could not find one" is not a name.

name and spdx-license are required in a [[licensing.third-party]] row, name in a [[licensing.dists]] one; anything else is optional. See App::Ariza::Licensing for what is done with them.

UNKNOWN KEYS WARN; WRONG TYPES DIE

The house rule, shared with App::Ariza::Versions and App::Shigur::Config: unrecognised keys at any level go into warnings and loading continues, so one manifest can serve several ariza versions. Wrong types die immediately, naming the dotted path and the expected shape:


ariza: app.name must be a string
ariza: bundle.platforms must be an array of strings
ariza: bundle.native must be an array of strings

Keys beginning with // are ignored silently, at any level, matching every other ariza config file.

The one value that is not forward-compatible

An unknown platform slug in bundle.platforms dies rather than warning:


ariza: bundle.platforms contains unknown platform 'macos-aarch64'
       (expected one of: linux-aarch64-glibc, ..., windows-x86_64)

installer.repo is the same kind of value and dies the same way:


ariza: installer.repo must look like 'owner/name'
       (got 'https://github.com/m-doughty/App-Moneymoor')

The reasoning is asymmetric on purpose. An unknown key costs nothing to ignore — some future ariza understands it. An unknown slug is a closed-set value: the set is exactly what ariza can build for, so a typo cannot be a future feature, and ignoring it would produce a release quietly missing a platform the author asked for. macos-aarch64 for macos-arm64 is the exact mistake this catches.

METHODS

load(IO() $dir = $*CWD --> App::Ariza::Config)

Load $dir/ariza.toml.

load-file(IO() $path --> App::Ariza::Config)

Load a manifest from an exact path.

Both die — with distinct messages — on a missing file, an unreadable file, malformed TOML, a document that is not a table, a wrongly-typed value, or a missing required [app] key.

An empty file is a valid, empty TOML document, so it fails on the honest complaint — "app.name is required" — rather than as "malformed". (Config::TOML rejects an empty document outright, so load-file short-circuits before handing it over.)

smoke-argvs(--> List)

Every configured smoke command as raw argv, in order: string entries split on whitespace, array entries verbatim. Empty entries are dropped.

smoke-commands(*%vars --> List)

The same, with {placeholder} substitutions applied. {exec} defaults to app.exec and can be overridden; every other name comes from %vars. A surviving {...} dies naming the known placeholders.

smoke-command(--> Str)

The first smoke command as one display string with {exec} expanded, or the undefined Str when none is configured. For showing a human what will run — smoke-commands is for running it.

licensing-strict(--> Bool) / licensing-app(--> Hash) / licensing-third-party(--> List) / licensing-dists(--> List)

The [licensing] table: whether an unattributed native pack fails the build, the app's own row, the rows it declared for what ariza cannot see, and the corrections it declared for distributions whose metadata is wrong. All four are empty-but-defined for a config that omits the table, so a caller never has to test for it.

warnings(--> List) / path(--> IO::Path)

The unrecognised keys found while loading, and the file loaded from.

AUTHOR

Matt Doughty

COPYRIGHT AND LICENSE

Copyright 2026 Matt Doughty

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

App::Ariza v0.2.4

bundler and distribution tool for Raku terminal apps

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

Config::TOML:ver<0.1.3+>:auth<zef:raku-community-modules>JSON::Fast:ver<0.19+>:auth<cpan:TIMOTIMO>Template::Jinja2:ver<0.3.0+>:auth<zef:apogee>

Test Dependencies

Provides

  • App::Ariza
  • App::Ariza::Bundle
  • App::Ariza::CI
  • App::Ariza::Config
  • App::Ariza::Installer
  • App::Ariza::Launcher
  • App::Ariza::Licensing
  • App::Ariza::Native
  • App::Ariza::Platform
  • App::Ariza::Rakudo
  • App::Ariza::Resources
  • App::Ariza::Runner
  • App::Ariza::Site
  • App::Ariza::Smoke
  • App::Ariza::Tools
  • App::Ariza::Update
  • App::Ariza::Versions

The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

Built with Podlite — the markup and publishing tools behind this site.