Morphir TOML Configuration Specification
Status and scope
This document specifies the morphir.toml configuration format used by Morphir tooling in this repository.
- Status: Draft (versioned and intended to become the authoritative reference)
- Applies to: Configuration parsed into
pkg/config.Config - Out of scope: Morphir IR JSON format (see the IR specification and schemas)
morphir.yaml is a supported second serialization of this configuration model. See the Morphir YAML configuration specification.
Files and discovery
Morphir tooling treats a directory as a project or workspace when it contains exactly one primary configuration in one of these layouts:
| Layout | TOML | YAML |
|---|---|---|
| Root | morphir.toml | morphir.yaml |
| Hidden | .morphir/morphir.toml | .morphir/morphir.yaml |
| Dot-config | .config/morphir/config.toml | .config/morphir/config.yaml |
The six primary paths are alternatives. A loader MUST reject a directory that contains more than one of them and name every conflicting path. It MUST NOT choose a layout or serialization by precedence.
Global user configuration may use the platform config directory or the .morphir directory in the user's home. See the global user path resolution rules for XDG, macOS, Windows, and conflict handling.
This spec focuses on the file format, not the multi-source merge rules. For merge precedence and merge behavior, see Morphir TOML Configuration Merge Rules.
Data model
morphir.toml is a TOML document. The semantics are defined by its mapping to an equivalent JSON-like object model:
- TOML tables like
[workspace]map to JSON objects like{ "workspace": { ... } } - Dotted tables like
[toolchain.morphir-elm.tasks.make]map to nested objects like:toolchain["morphir-elm"]["tasks"]["make"]
- Arrays map to JSON arrays
- Inline tables map to JSON objects
Top-level keys
All top-level keys are optional; absent sections use defaults.
morphir: Core Morphir settings (IR version constraints)workspace: Workspace discovery and output layoutproject: Project metadata (single-project config, or root project in a workspace)ir: IR processing settingscodegen: Code generation settingscache: Cache settingslogging: Logging settingsui: UI / TUI settingsfrontend: Frontend parsing settingssources: Remote source settingsdependenciesanddev-dependencies: Project dependencies and development-only dependenciesextensions: Extension definitionstasks: Project task definitions (intrinsic or command tasks)workflows: Named workflows (staged orchestration of targets)bindings: External binding type-mapping configuration (WIT/Protobuf/JSON)toolchain: Toolchain definitions (external tool adapters and task catalogs)
Section specifications
[morphir]
version(string, optional): SemVer constraint indicating compatible Morphir IR versions for the project (example:"^3.0.0"). Empty means “any”.min_cli_version(string, optional): Minimum Morphir CLI version required to work with this configuration.dev_mode(bool, optional, default:false): Enables development-mode behavior.
[workspace]
root(string, optional): Workspace root directory. Empty means “directory containing the config file”.output_dir(string, optional, default:".morphir"): Output directory for generated artifacts, relative to the workspace root.members(string[], optional): Glob patterns used to discover workspace member projects.exclude(string[], optional): Glob patterns excluded from member discovery.default_member(string, optional): Default member path when none is specified.
[project]
name(string, optional): Project identifier (kebab-case, PascalCase, dotted).version(string, optional): Project version.source_directory(string, optional): Source directory containing project source files.exposed_modules(string[], optional): Modules exposed by the project’s public API.module_prefix(string, optional): Optional module prefix for qualified names.description(string, optional): Short description of the project.license(string, optional): SPDX license identifier.repository(string, optional): URL of the project's source repository.authors(string[], optional): Project authors.output_directory(string, optional, default:".morphir/out"): Directory for project-level build output.
[project.decorations.<decorationId>]
Decorations are sidecar metadata schemas/values attached to IR nodes.
display_name(string, optional): Human-readable name (UI label).ir(string, optional): Path to the decoration schema IR file.entry_point(string, optional): Fully-qualified type reference of the decoration root type, in the formPackage:Module:Type.storage_location(string, optional): Path to the decoration values file.
[ir]
format_version(int, optional, default:4): IR format version (supported range: 1–10). Version 4 is where active development happens. Version 3 remains supported; a project stays on it by setting this field explicitly.strict_mode(bool, optional, default:false): When true, validation warnings are treated as errors.mode(string, optional, default:"vfs"): One ofclassic,vfs.
[codegen]
targets(string[], optional): Code generation targets (examples:"go","typescript","scala","json-schema").template_dir(string, optional): Custom templates directory.output_format(string, optional, default:"pretty"): One ofpretty,compact,minified.
[cache]
enabled(bool, optional, default:true)dir(string, optional): Cache directory path (empty means default).max_size(int64, optional, default:0): Max cache size in bytes (0 = unlimited).
[logging]
level(string, optional, default:"info"): One ofdebug,info,warn,error.format(string, optional, default:"text"): One oftext,json.file(string, optional): Log file path (empty = stderr).
[ui]
color(bool, optional, default:true)interactive(bool, optional, default:true)theme(string, optional, default:"default"): One ofdefault,light,dark.
[frontend]
Frontend parsing settings.
language(string, optional): Source language handled by the frontend parser.emit_parse_stage(bool, optional, default:true): Emit the parse-stage intermediate output.emit_parse_stage_fatal(bool, optional, default:false): Treat parse-stage errors as fatal.
[sources]
Remote source settings (morphir_common::remote::config::RemoteSourceConfig). Unlike most sections in this document, these fields serialize in camelCase, not snake_case.
enabled(bool, optional, default:true): Whether remote sources are enabled.allow(string[], optional): Glob patterns. If non-empty, only URLs matching an entry are allowed.deny(string[], optional): Glob patterns denied even whenallowmatches. Takes precedence overallow.trustedGithubOrgs(string[], optional): Trusted GitHub organizations/users.
[sources.cache]
directory(string, optional): Cache directory (defaults to a platform cache directory undermorphir/sources).maxSizeMb(int, optional, default:0): Maximum cache size in MB (0= unlimited).ttlSecs(int, optional, default:0): TTL for cached sources in seconds (0= never expire).
[sources.network]
timeoutSecs(int, optional, default:30): Connection timeout in seconds.httpProxy(string, optional): HTTP proxy URL.httpsProxy(string, optional): HTTPS proxy URL.maxRedirects(int, optional, default:10): Maximum number of redirects to follow.userAgent(string, optional): User agent string.
[dependencies] and [dev-dependencies]
Maps of dependency name to a version constraint or a detailed table. dependencies lists the project's dependencies; dev-dependencies lists dependencies needed only for development.
[dependencies]
acme-sdk = "^1.2.0"
local-lib = { path = "../local-lib" }
upstream = { git = "https://example.com/upstream.git", tag = "v2.0.0" }
[dev-dependencies]
test-utils = { workspace = true }
Each entry is either:
- A version string: a SemVer constraint.
- A table:
version(string, optional)path(string, optional)git(string, optional)tag(string, optional)branch(string, optional)rev(string, optional)workspace(bool, optional)
[extensions.<name>]
path(string, optional)url(string, optional)command(string, optional)args(string[], optional)enabled(bool, optional, default:true)config(table, optional): Extension-specific configuration.
Secret values
Some settings hold credentials. A conforming loader MUST treat a value at a position the schema declares as secretValue as secret: it MUST NOT display, log, or serialize the value, and tooling MUST obtain it only through an explicit exposing operation. Schema version 1 defines secretValue but does not yet reference it from any property; the rule takes effect as soon as a credential field such as registry.token is declared with that type.
A secret can also be supplied as a secret reference, which names where to obtain the secret instead of containing it:
[registry]
token = { env = "GITHUB_TOKEN" }
password = { file = "~/.config/morphir/registry-password" }
command_token = { command = ["gh", "auth", "token"] }
keyring_token = { keyring = { service = "github.com", account = "damre" } }
A secret reference has exactly one of these four shapes. A loader MUST recognise these shapes at every position, not only at positions the schema declares as secret.
env: the secret is the value of the named environment variable. A missing or empty variable is an error when the secret is resolved.file: the secret is the file's UTF-8 contents with one trailing\nor\r\nremoved. A relative path resolves against the directory of the configuration file that declares the reference; a leading~expands to the user's home directory. A missing, unreadable, non-UTF-8, or empty file is an error when the secret is resolved.command: the non-empty string array names a program followed by its arguments. Morphir executes that program directly, without a shell, with standard input closed. It runs in the declaring configuration file's directory, or in the process current directory when the reference has no declaring file. The program must succeed and write non-empty UTF-8 text to standard output after one trailing\nor\r\nis removed.keyring: the mapping has exactly the non-empty string fieldsserviceandaccount. Morphir reads the matching password from the native operating-system keyring. It does not create, update, or delete keyring entries. A missing, unreadable, or empty entry is an error when the secret is resolved.
Any other table, including one with mixed discriminator keys, extra keys, an empty command, or an incomplete keyring mapping, is not a secret reference.
Resolution happens only when tooling explicitly requests one dotted configuration key. It resolves that one winning leaf and MUST NOT traverse or resolve other references. The resolved value is protected: formatting redacts it, ordinary serialization is unavailable, and callers need an explicit exposure operation to read it. Resolution failures identify the requested key, reference kind, or safe source metadata, but MUST NOT disclose resolved secret text.
Displaying the configuration, reporting sources, validating, decoding, and normal loading MUST NOT resolve references. A reference MAY be displayed verbatim because it contains no secret; a plain-string secret MUST be displayed as a placeholder such as <redacted>.
For merging, a secret reference is a leaf: a higher-precedence reference replaces a lower one entirely (see the merge rules).
The shared schema defines the four reference shapes. Implementations built on morphir-rust require Rust 1.88 or later.
Tasks and workflows
[tasks.<taskName>]
Tasks are project-scoped execution units. Each task is either:
- Intrinsic: a built-in Morphir action (
kind = "intrinsic";action = "...") - Command: an external command (
kind = "command";cmd = ["..."])
A string value is shorthand for a command task run through the shell: build = "cargo build".
depends and run relate to the pre-existing depends_on and cmd/action fields as follows:
dependsis an accepted alternative spelling ofdepends_on. A task MUST NOT set bothdepends_onanddepends.runis the string form of a command task: it is equivalent to the string shorthand above, and its presence implieskind = "command". A task MUST NOT set bothrunandcmd, and MUST NOT set bothrunandaction.
The schema enforces the two MUST-NOT rules above (a task cannot declare both members of either pair). It does not separately enforce that
runimplieskind = "command"whenkindis omitted, because doing so would require restructuring the intrinsic/command task variants in the schema. A conforming loader MUST still apply the implication: a task withrunset andkindomitted (and no conflictingaction) is a command task, not an intrinsic one.
Common task fields:
depends_on(string[], optional)depends(string[], optional): Alternative spelling ofdepends_on(see above).pre(string[], optional)post(string[], optional)inputs(string[], optional)outputs(string[], optional)params(table/object, optional): Arbitrary parametersenv(table/object, optional):string -> stringmounts(table/object, optional): mount name to permission ("ro"/"rw")description(string, optional)run(string, optional): Shell command to run (alternative tocmd; see above).cwd(string, optional)
Intrinsic task fields:
kind:"intrinsic"(or omitted; omitted defaults to intrinsic, unlessrunis present withoutaction, in which case the task is a command task per the rule above)action(string, optional): Intrinsic action identifier (example:morphir.pipeline.compile)
Command task fields:
kind:"command"cmd(string[], optional): Command and arguments
[workflows.<workflowName>]
Workflows orchestrate targets in ordered stages.
description(string, optional)extends(string, optional): Base workflow name to inherit from (design/behavior may evolve)stages(array, optional): Array of stage objects:name(string, optional)targets(string[], optional)parallel(bool, optional)condition(string, optional)
Toolchains
[toolchain.<toolchainName>]
Toolchains define how to acquire and run external tools, and enumerate tasks they provide.
enabled(bool, optional): If set, explicitly enable/disable the toolchain. If absent, tooling may auto-enable.version(string, optional)working_dir(string, optional)timeout(string, optional): Go-style duration (example:"5m")env(table/object, optional):string -> string
[toolchain.<toolchainName>.acquire]
backend(string, optional): Acquisition backend (examples:"path"; others may be planned)package(string, optional): Package identifier (backend-specific)version(string, optional): Version constraint (backend-specific)executable(string, optional): Executable name/path (backend-specific)
[toolchain.<toolchainName>.tasks.<taskName>]
exec(string, optional)args(string[], optional)fulfills(string[], optional): Targets this task fulfills (example:["make"])variants(string[], optional): Supported variants (example:["Scala", "TypeScript"])env(table/object, optional):string -> string
Inputs
Toolchain task inputs support both forms:
- Array form:
inputs = ["src/**/*.elm"](treated as file patterns) - Table form:
files(string[], optional)artifacts(table/object, optional):string -> stringreferences (example:{ ir = "@morphir-elm/make:ir" })
Outputs
Outputs are a map of named artifacts:
[toolchain.<tc>.tasks.<t>.outputs.<outputName>]path(string, optional)type(string, optional)
Machine-readable schema
This specification is accompanied by a JSON Schema for the equivalent JSON model:
https://morphir.finos.org/schemas/morphir-config-v1.yamlhttps://morphir.finos.org/schemas/morphir-config-v1.json