Skip to content

elci.toml

Every Elci project has an elci.toml file at its root. This page lists every table and key, the values each one accepts and the rules the compiler enforces. Unknown tables and keys are errors, so a typo never goes unnoticed.

elci.toml uses a small, strict subset of TOML:

  • A table header is a line like [project] or [validators.treasury]. Each table may appear once.
  • Each setting is key = value on one line. A key may be quoted, as in "Julc.Math" = "...".
  • A value is either a quoted string, such as "src", or an array of quoted strings on the same line, such as ["src", "lib"].
  • Strings cannot contain escapes (\) or embedded quotes.
  • Comments are whole lines starting with #. A comment after a value is an error.
  • A key may appear only once per table.

A project configures either one or more [validators.<name>] tables or one [entrypoint] function, never both:

  • Validator projects produce deployable scripts. Use elci check, build, test and apply.
  • Function projects have an [entrypoint] for elci eval, which runs a function and prints its value and cost. They are for experiments and helper code, not for deployment.

Required in every project.

KeyRequiredValue
source-directoriesyesArray of directories holding source modules, relative to the project. At least one; each must exist.
targetyesMust be "plutus-v3-pv11-uplc-1.1.0", the only supported target.
julc-versionyesMust equal the Julc version the compiler is pinned to, currently "0.1.0-pre20-ebaf028-SNAPSHOT". elci --version prints it.
library-jarsnoArray of JAR paths, relative to the project, that contain on-chain Java library sources. See Java libraries.
expected-abinoPath of a committed abi.json to compare with the build. Function projects only; validators set it in their own table.

A module A.B must live at A/B.elm inside exactly one source directory. Two files defining the same module are an error.

One table per deployed script. The name becomes the output directory build/validators/<name>/ and the name you use in elci apply --validator, in tests and in --validator options. It must be 1 to 64 characters: lowercase letters, digits, - or _, starting with a letter.

KeyRequiredValue
boundaryyesMust be "julc-strict-v1", the strict data boundary.
spendat least one handlerHandler for spending, as "Module.function".
mintHandler for minting.
withdrawHandler for reward withdrawals.
certifyHandler for certificates.
voteHandler for governance votes.
proposeHandler for governance proposals.
parametersnoArray of deployment parameter names, in application order.
spend-datumno"required" (default), "optional" or "absent". Needs a spend handler.
expected-abinoPath of a committed abi.json; check, build and apply fail if the new ABI differs.

Rules:

  • Handlers name an exposed function as "Module.function", for example "Treasury.spend". Each handler key adds a purpose to the same script, so one table is always one script hash.
  • Parameter names start with a lowercase letter, followed by letters, digits or _, and must be unique. Every handler receives all parameters as its leading arguments, in this order, so their types must agree across handlers.
  • Handler signatures depend on the purpose and spend-datum:
HandlerRequired type
spendparameters -> datum -> redeemer -> ScriptContext -> Bool
spend with spend-datum = "optional"parameters -> Maybe datum -> redeemer -> ScriptContext -> Bool
spend with spend-datum = "absent"parameters -> redeemer -> ScriptContext -> Bool
mint, withdraw, certify, vote, proposeparameters -> redeemer -> ScriptContext -> Bool

Adding, removing or changing a handler changes the script and its hash. See validators and purposes and datums and redeemers.

The single function of a function project.

KeyRequiredValue
moduleyesThe module name, such as "Main".
functionyesAn exposed top-level function or value with a concrete type, such as "main".
purposenoOnly "function", the default.
boundarynoOnly "julc-strict-v1".

Validator purposes in [entrypoint] were removed. purpose = "spend" fails with a message telling you to move the handler into a [validators.<name>] table.

Maps Elm-style module names to on-chain Java library classes:

[java-modules]
"Julc.Math" = "org.julclang.stdlib.lib.MathLib"
"Acme.Pricing" = "acme.Pricing"

The key is the module name you import; the value is the fully qualified class name. A mapping is only read when a module imports it. A module name cannot be both a source module and a Java module. Julc.TypedMap and Julc.TypedArray are reserved by the core Map and Array modules and cannot be remapped. The core module names Basics, List, Maybe, Result, String, Tuple, Map, Dict, Array, Value, Interval and Tx, the reserved names Set and Elci, and names starting with Elci. cannot be keys. See standard library for the bundled classes.

KeyRequiredValue
source-directoriesnoArray of directories holding test modules. Default ["tests"].

A missing default tests directory simply means there are no tests. Test modules are never part of check, build or the deployed scripts. See unit tests.

This project uses every validator setting: two scripts, a shared parameter, an optional datum, a pinned ABI, a Java library JAR, a second source directory and a custom test directory.

elci.toml
# Settings for the whole project.
[project]
source-directories = ["src", "lib"]
target = "plutus-v3-pv11-uplc-1.1.0"
julc-version = "0.1.0-pre20-ebaf028-SNAPSHOT"
library-jars = ["libs/pricing.jar"]
# One script with two purposes and a deployment parameter.
[validators.treasury]
boundary = "julc-strict-v1"
parameters = ["admin"]
spend = "Treasury.spend"
withdraw = "Treasury.withdraw"
spend-datum = "optional"
expected-abi = "abi/treasury.json"
# A second, independent script.
[validators.badge]
boundary = "julc-strict-v1"
parameters = ["admin"]
mint = "Badge.mint"
[java-modules]
"Julc.Math" = "org.julclang.stdlib.lib.MathLib"
"Acme.Pricing" = "acme.Pricing"
[tests]
source-directories = ["spec"]
$ elci check
validator badge (mint): checked; 229 FLAT bytes; plutus-v3-pv11-uplc-1.1.0
validator treasury (spend, withdraw): checked; 603 FLAT bytes; plutus-v3-pv11-uplc-1.1.0

With spend-datum = "optional", the spend handler’s datum is a Maybe:

src/Treasury.elm
spend : PubKeyHash -> Maybe Int -> () -> ScriptContext -> Bool
spend admin datum _ ctx =
case datum of
Just limit ->
ctx.txInfo.fee <= Math.max limit (Pricing.fee limit 100)
Nothing ->
signedBy admin ctx

This is what elci init my-project --purpose function creates:

elci.toml
[project]
source-directories = ["src"]
target = "plutus-v3-pv11-uplc-1.1.0"
julc-version = "0.1.0-pre20-ebaf028-SNAPSHOT"
[entrypoint]
module = "Main"
function = "main"
purpose = "function"
MistakeMessage
Wrong julc-versionELCI4001: Julc version does not match this compiler; expected julc-version = "0.1.0-pre20-ebaf028-SNAPSHOT"
Wrong targetELCI4001: Unsupported target; expected plutus-v3-pv11-uplc-1.1.0
Misspelled keyELCI4001: Unknown configuration key: [project] name
Unknown tableELCI4001: elci.toml:6: unknown configuration section: dependencies
Missing boundaryELCI4001: Missing configuration key: [validators.main] boundary
Bad validator nameELCI4001: elci.toml:6: invalid validator name 'Main'; use lowercase letters, digits, '-' or '_', starting with a letter (at most 64 characters)
No handlerELCI4001: elci.toml:6: [validators.main] configures no handler; add one of mint, spend, withdraw, certify, vote, propose
Handler without moduleELCI4001: elci.toml:9: [validators.main] spend = "spend" must name an exposed function as "Module.function"
spend-datum without spendELCI4001: elci.toml:6: [validators.main] spend-datum requires a spend handler
Both project kindsELCI4001: elci.toml mixes [entrypoint] with [validators.*]; use one form
Neither project kindELCI4001: elci.toml must configure at least one [validators.<name>], or an [entrypoint] function
expected-abi in [project] of a validator projectELCI4001: [project] expected-abi applies to [entrypoint] projects; set expected-abi in each [validators.<name>] table
Unquoted valueELCI4001: Expected a quoted string without escapes: julc-strict-v1
Comment after a valueELCI4001: Expected a quoted string without escapes: "0.1.0-pre20-ebaf028-SNAPSHOT" # pinned
Multi-line arrayELCI4001: elci.toml:3: expected key = value
Missing source directoryELCI4001: Source directory not found: my-project/lib
Remapping a core libraryELCI4001: my-project/elci.toml:6: [validators.main]: [java-modules] may not remap Julc.TypedMap, which the Elci core library uses for org.julclang.stdlib.lib.TypedMapLib
Mapping a core module nameELCI4001: my-project/elci.toml:6: [validators.main]: [java-modules] may not map Value, a module name of Elci's core library
ABI changedELCI4001: my-project/elci.toml:9: [validators.main]: ABI drift from abi/main.json; compare constructor tags, field order, handler roles and parameters

Each message is printed after elci: and the command exits with status 1.