Project configuration (incan.toml)¶
This is the reference for the incan.toml project manifest format. For a practical guide to managing dependencies, see:
Managing dependencies.
Overview¶
incan.toml is an optional project manifest that lives at your project root. It declares project metadata, build configuration, Incan library dependencies, Rust crate dependencies, and optional vocab companion crate settings.
Project-aware commands discover it by walking upward from the current working directory, and file-oriented commands may also resolve it from the provided source path.
my_project/
├── src/
│ └── main.incn
├── tests/
│ └── test_main.incn
├── incan.toml # Project manifest
└── incan.lock # Generated lock file (commit to VCS)
You can scaffold a full new project (manifest, entry point, starter test, README, and .gitignore) with incan new. Use incan init when you already have a directory and want to add Incan project files there.
[project]¶
Project metadata. All fields are optional.
[project]
name = "my_app"
version = "0.1.0"
description = "A short description of what this project does"
authors = ["Alice <alice@example.com>"]
license = "MIT"
readme = "README.md"
requires-incan = ">=0.2"
[project.scripts]¶
Named entry points for CLI commands:
[project.scripts]
main = "src/main.incn" # This is the default entry point if no other is set
migrate = "src/migrate.incn" # This is an example of a named entry point called "migrate"
incan new and incan init set main = "src/main.incn" by default. When main is set, incan lock can run without a FILE argument.
[project.features]¶
Optional feature flags that can enable optional dependencies:
[project.features]
full = ["fancy_logging", "metrics"]
[build]¶
Build configuration. All fields are optional.
[build]
rust-edition = "2021" # Rust edition for the generated Cargo.toml (default: compiler-chosen)
profile = "release" # Cargo build profile
target = "x86_64-unknown-linux-gnu" # Cross-compilation target
source-root = "src" # Source root for module resolution (default: convention-based)
source-root¶
The directory where the compiler and test runner look for user modules. Resolution order:
- Explicit: if
source-rootis set, that directory is used (relative to project root) - Convention: if a
src/directory exists at the project root, it is used automatically - Fallback: the project root itself (flat layout)
Most projects use the conventional src/ layout and don't need to set this field. It exists for projects that keep their source in a different directory (e.g. lib/).
[tool.incan.envs]¶
Named project environments define reusable command contexts for incan env. They are useful when a project has different test, build, or release workflows that need different environment variables, working directories, or script arguments. The ambient default environment is always available; defining [tool.incan.envs.default] customizes it.
[tool.incan.envs.default]
env-vars = { INCAN_NO_BANNER = "1" }
[tool.incan.envs.default.scripts]
test = ["incan", "test", "tests/"]
[tool.incan.envs.release]
extends = ["default"]
env-vars = { INCAN_FANCY_ERRORS = "1" }
[tool.incan.envs.release.scripts]
build = ["incan", "build", "src/main.incn", "--locked"]
Fields:
| Field | Type | Description |
|---|---|---|
extends |
list of strings | Other environments to merge before this one |
detached |
bool | Do not include default automatically |
cwd |
string | Working directory for scripts, relative to the project root unless absolute |
env-vars |
table | Environment variables to inject into the process |
scripts |
table of string lists | Script names mapped to argv lists |
Use the environment with:
incan env list
incan env show release
incan env run release build
See Project lifecycle reference for merge and resolution rules.
[tool.incan.metadata]¶
Checked contract metadata settings for project-declared model bundles.
[tool.incan.metadata]
model-bundles = ["contracts/order_summary.json"]
Fields:
| Field | Type | Description |
|---|---|---|
model-bundles |
list of strings | Canonical model bundle JSON files to validate, materialize during build/run, embed into .incnlib artifacts when publishable, and expose through incan tools metadata model. |
Bundle paths are resolved relative to the project root unless absolute. See Checked contract metadata for the bundle schema and tooling commands.
[vocab]¶
Optional companion crate configuration for library-defined DSL metadata.
[vocab]
crate = "vocab_companion"
Use this only for library projects that export vocab entries. Projects without custom library DSLs can omit the section entirely.
Fields¶
| Field | Type | Description |
|---|---|---|
crate |
string | Path to the vocab companion crate directory, relative to project root unless absolute |
During incan build --lib, the compiler:
- resolves
[vocab].crate - validates that the directory contains
Cargo.tomlandsrc/lib.rs - runs
cargo buildfor that companion crate - derives the vocab payload from the companion crate's
library_vocab()registration - packages the resulting metadata into the built
.incnlibartifact
If the companion crate registers a desugarer via incan_vocab::DesugarerRegistration, incan build --lib also packages the matching Wasm artifact from the companion crate's build output. Any intermediate serialized metadata is a tooling concern (rather than part of the author-facing contract).
[dependencies]¶
Incan library dependencies available in all contexts. (Note: for Rust crates, see [rust-dependencies]).
[dependencies]
mylib = { path = "../mylib" }
[rust-dependencies]¶
Rust crate dependencies available in all contexts (build, run, test).
String shorthand¶
For simple registry dependencies with just a version:
[rust-dependencies]
serde = "1.0"
rand = "0.8"
Table form¶
For dependencies that need features, sources, or other options:
[rust-dependencies]
tokio = { version = "1.35", features = ["full"] }
serde = { version = "1.0", features = ["derive"], default-features = true }
All fields¶
| Field | Type | Description |
|---|---|---|
version |
string | Cargo SemVer version requirement (required for registry) |
features |
list | Cargo features to enable |
default-features |
bool | Whether to include default features (default: true) |
optional |
bool | Mark as optional (see below) |
package |
string | The actual crate name if renaming (e.g. serde-json) |
git |
string | Git repository URL (mutually exclusive with path) |
branch |
string | Git branch (requires git) |
tag |
string | Git tag (requires git) |
rev |
string | Git commit hash (requires git) |
path |
string | Local path, relative to incan.toml location |
[rust-dev-dependencies]¶
Dependencies available only in test contexts (tests/ directory). Same syntax as [rust-dependencies].
[rust-dev-dependencies]
criterion = "0.5"
test_helpers = { path = "../test-helpers" }
Importing a dev-only crate from production code is a compile-time error:
error: Rust crate `criterion` is dev-only and cannot be imported from production code
hint: Move the dependency to [rust-dependencies], or import it only from tests.
Overlap rules: If the same crate appears in both [rust-dependencies] and [rust-dev-dependencies], the version, source, and default-features must match. Features are unioned, and the crate is treated as a normal dependency.
[rust-dependencies.optional]¶
Syntactic sugar for declaring optional (rust) dependencies. Entries here are equivalent to setting optional = true:
[rust-dependencies.optional]
fancy_logging = "0.3"
metrics = { version = "1.0", features = ["prometheus"] }
is equivalent to:
[rust-dependencies]
fancy_logging = { version = "0.3", optional = true }
metrics = { version = "1.0", features = ["prometheus"], optional = true }
Optional dependencies generate a Cargo feature gate. Enable them at build time:
incan build src/main.incn --cargo-features fancy_logging
Legacy alias tables¶
[rust.dependencies] and [rust.dev-dependencies] remain supported as backward-compatible aliases for [rust-dependencies] and [rust-dev-dependencies].
Prefer the non-nested table names in new manifests.
Dependency sources¶
Registry (default)¶
The default source is crates.io. Version is required:
[rust-dependencies]
serde = "1.0"
tokio = { version = "1.35", features = ["full"] }
Git¶
Specify a git repository URL with exactly one of branch, tag, or rev:
[rust-dependencies]
my_internal_lib = { git = "https://github.com/company/lib.git", tag = "v1.0.0" }
bleeding_edge = { git = "https://github.com/company/lib.git", branch = "main" }
pinned = { git = "https://github.com/company/lib.git", rev = "abc1234" }
Strict mode and git branches
When building with --locked or --frozen, git dependencies using branch = "..." are rejected because branches are not reproducible. Use tag or rev instead.
Path¶
Local path dependencies, relative to the incan.toml location:
[rust-dependencies]
shared_utils = { path = "../shared-utils" }
Package renames¶
Use package to use a different crate name than the dependency key. For example:
[rust-dependencies]
json = { package = "serde_json", version = "1.0" }
This lets you import rust::json instead of import rust::serde_json.
Complete example¶
[project]
name = "my_web_app"
version = "0.1.0"
description = "A web application built with Incan"
authors = ["Alice <alice@example.com>"]
[project.scripts]
main = "src/main.incn"
[build]
rust-edition = "2021"
[vocab]
crate = "vocab_companion"
[dependencies]
mylib = { path = "../mylib/target/lib" }
[rust-dependencies]
tokio = { version = "1.35", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sqlx = { version = "0.7", features = ["runtime-tokio", "postgres"] }
[rust-dependencies.optional]
fancy_logging = "0.3"
[rust-dev-dependencies]
criterion = "0.5"
[tool.incan.envs.default]
env-vars = { INCAN_NO_BANNER = "1" }
[tool.incan.envs.default.scripts]
test = ["incan", "test", "tests/"]
See also¶
- Managing dependencies - Practical guide
- Rust interop - Inline version annotations
- CLI reference -
incan new,incan init,incan version,incan env, and dependency flags - Project lifecycle reference - Version bump and environment semantics
- Author library DSLs with
incan_vocab- Companion crate workflow