Skip to content

comline.toml

Consumer-owned configuration for comline generate: where generated code goes, in what layout, in what form, and for which package versions. It is committed, never frozen, and never part of a published package. With no comline.toml (or an all-commented one) the defaults below apply and targets come from config.idp's code_generation.languages.

For the task-oriented walkthrough see Generating code.

[generate]

Defaults for every target.

Key Type Default Meaning
out string (path) "generated" Output root, relative to comline.toml.
layout string (template) "{{language}}/{{namespace}}.{{ext}}" Path of each generated file under out. Handlebars, strict.
mode "code" | "lib" | "dylib" "code" Emit form. code and lib are implemented for rust and typescript; dylib is planned — see Library generation.
package_versions "latest" | "all" | list "latest" Which package versions to emit — see below.
external_std bool on in lib, off in code Reference std as its own package instead of inlining it — see below.
validate_on_decode "off" | "collect" | "first" "off" Whether decoding a value runs its @validators — see below.
async bool false Generate protocols on a connection for an async driver — see below.
only list of strings — Generate just these languages, out of the ones config.idp declares — see below.

[[generate.target]]

One block per declared language you want to configure. Any key from [generate] may be repeated here to override it for that language only.

A block configures a language; it does not choose which languages are generated. That comes from config.idp alone — a declared language with no block takes the [generate] defaults, several blocks for one language give several outputs, and a block naming a language the congregation doesn't declare is an error. To generate fewer than the package declares, use only.

Key Type Meaning
language string Required. Must be one the manifest declares under code_generation.languages.
lang_version string Optional; the toolchain version to generate for. Defaults to what config.idp declared, and may raise it but never lower it (Language versions).
out, layout, mode, package_versions, external_std, validate_on_decode, async — Per-target override of the [generate] value.
flatten bool lib/dylib only, target-only (no [generate] default): write the crate straight into out instead of out/<language>/. See below.
[generate]
out    = "generated"
layout = "{{language}}/{{namespace}}.{{ext}}"

[[generate.target]]
language     = "rust"
lang_version = "1.88.0"
out          = "src/generated"

flatten

layout only governs code mode's one-file-per-schema paths — a lib-mode target ignores it entirely (comline generate warns if one is set) and always writes the crate's fixed internal shape (Cargo.toml, src/lib.rs, a file per schema under src/) rooted at out/<language>/, so two lib targets can safely share one out without their files colliding.

A target with its own dedicated out doesn't need that disambiguation — flatten = true skips it, writing the crate straight into out:

[[generate.target]]
language = "rust"
mode     = "lib"
out      = "../my-rust-crate/"
flatten  = true   # crate lands at out/, not out/rust/

Only set this when the target's out is exclusively its own — flattening a shared out across more than one lib target reintroduces the collision the default layout avoids.

external_std

Comline's standard library is implicitly available to every package, so std/http and std/validators are part of every generation request. This decides whether their code is copied into your generated output or referenced from std's own pre-generated package:

Language Package
rust comline_std (a crate, pinned by git rev)
typescript @comline/std (an npm package, by semver range)

It defaults to on in lib mode — a buildable package should depend on std rather than vendor it — and off in code mode, which has no manifest to declare a dependency in. In code mode with it on, the generated file names what to install in a comment at the top.

--external-std and --no-external-std override it for one run.

Neither package is published yet, so a lib target that references one needs it linked locally (npm link, a path override) until that changes — which is already true of @comline/runtime for any package with a protocol.

validate_on_decode

Generated code always carries a schema's @validators checks as validate() / validate_first(), for you to call. This decides whether decoding calls them too:

Value Decoding a value that fails its checks
"off" succeeds; nothing runs until you call validate()
"collect" fails, with every failed check
"first" fails, with the first failed check

It's yours to choose rather than the schema's: it changes what decoding costs, and a form that wants every problem at once and a hot path that wants to stop early want different things from the same type. With it on, a provider also refuses a call whose arguments fail their checks, the same way it refuses arguments that don't decode.

Today only the rust generator runs validators; typescript ignores this. --validate-on-decode and COMLINE_GENERATE_VALIDATE_ON_DECODE override it.

async

A protocol on a connection is generated for a blocking driver by default. async = true generates it for an async one instead:

  • rust: async handlers, <Proto>AsyncDispatcher and <Proto>AsyncSender, and an async package serve / accept / connect, for the runtime's AsyncConnection on any executor — see Rust connections. A lib package turns on the runtime's async feature.
  • typescript: nothing changes; its handlers and senders return Promises either way.

Every protocol is on a connection unless it's lockstep (the datagram framing, or JSON-RPC with no client-provided protocol); those are the same either way, and comline generate warns when async = true changes nothing. Like external_std, it's a consumer's choice: the same package can be generated async for one application and blocking for another.

only

Generate a subset of the languages config.idp declares, for a checkout that doesn't need all of them:

[generate]
only = ["rust"]

A name the congregation doesn't declare is an error, so a typo fails loudly instead of quietly generating nothing. --target narrows a single run the same way.

This is also the escape hatch when a declared language has no generator in your comline build: declaring a language means you mean it, so a missing generator is an error rather than a silent skip, and only is how you say you want fewer.

Layout variables

Variable Value
{{language}} target language, e.g. rust
{{namespace}} the schema's namespace, /-joined
{{ext}} the generator's file extension, e.g. rs
{{lang_version}} the declared language / toolchain version
{{spec_version}} the manifest's specification_version
{{package_version}} the package version being generated (see below)

package_versions

Value Effect
"latest" (default) The working tree only. No .comline/ read. {{package_version}} is the last committed version (empty if never built).
"all" Every release in the project's history (not the builds between them).
["0.3.0", "0.4.0"] Exactly those versions: releases, builds (0.3.0-dev.2) or commit hashes.

Anything but "latest" reads the content-addressable store, so the project must have been built at least once. Selecting more than one version requires {{package_version}} in layout — otherwise every version writes to the same paths. Old schemas are emitted with the current generator.

[generate]
package_versions = "all"
layout           = "{{language}}/{{package_version}}/{{namespace}}.{{ext}}"

default_framing (moved)

The framing is part of the schema, since both ends have to agree on it, so it moved to the package: config.idp's wire = { framing = "..." } (Wire defaults). A default_framing, in [generate] or in a target, is an error that names the line to write there instead:

`default_framing` moved from comline.toml to config.idp
  help: drop it here, and declare the package's framing in config.idp:
      wire = { framing = "jsonrpc" }

Precedence

Lowest to highest, applied field by field:

built-in defaults → [generate] → [[generate.target]] → COMLINE_GENERATE_* env → CLI flags
  • COMLINE_GENERATE_OUT / COMLINE_GENERATE_LAYOUT / COMLINE_GENERATE_MODE — apply to every target (a CI global). Empty values are ignored.
  • --out / --layout / --mode — apply to one target and need --target when more than one is configured.

Forward-looking

# Generate bindings for a registry dependency rather than the local schemas.
# Parsed but not yet operational — needs dependency resolution (core#6).
[generate.dependencies.stdlib]
out     = "src/gen/stdlib"
targets = ["rust"]