Skip to content

Projects & shape.toml

shape.toml is the project-level source of truth for module resolution, dependencies, extensions, and build behavior.

[project]
name = "demo"
version = "0.1.0"
entry = "src/main.shape"
[modules]
paths = ["lib"]
[dependencies]
utils = { path = "../utils" }
[[extensions]]
name = "python"
path = "./extensions/libshape_ext_python.so"
autoload = true
[build]
target = "bytecode"
opt_level = 1
output = "dist/"
[build.external]
mode = "update" # or "frozen"

Project metadata and required entrypoint for project execution. When shape.toml exists, shape requires [project].entry (no implicit REPL fallback).

FieldTypeDescription
namestringPackage name (required if other fields set)
versionstringSemver version
entrystringEntry script path
authorsstring[]Author names
shape-versionstringMinimum Shape version
licensestringSPDX license identifier
repositorystringRepository URL

Additional module search roots.

Shape module dependencies.

Supported forms:

  • { path = "..." } — local path (also supports .shapec bundles)
  • { git = "...", tag = "..." } (or branch / rev)
  • "^1.2" or { version = "^1.2" } — semver registry dependency

Bundle dependencies: if the path points to a .shapec file, or a .shapec file exists alongside the directory, the pre-compiled bundle is used. See Packages & Building.

Registry resolution is semver-based and includes transitive constraint solving. By default it uses ~/.shape/registry/index and ~/.shape/registry/src, and can be overridden with SHAPE_REGISTRY_INDEX / SHAPE_REGISTRY_SRC.

Loadable runtime extensions (.so modules), discovered through the unified loader.

Required fields:

  • name
  • path

Optional:

  • autoload = true|false
  • [extensions.config] (module-specific options)

Build configuration for shape build.

FieldTypeDefaultDescription
targetstring"bytecode"Build target ("bytecode" or "native")
opt_levelinteger0Optimization level (0-3)
outputstringOutput directory

Controls external artifact refresh in unified lockflow:

  • update: allow refresh and lock updates
  • frozen: require existing lock artifacts

Extensions can claim custom TOML sections in shape.toml. Any section not recognized as a built-in ([project], [modules], [dependencies], [dev-dependencies], [build], [[extensions]]) is captured as an extension section.

[project]
name = "my-project"
version = "1.0.0"
[native-dependencies]
libcurl = { linux = "libcurl.so.4", macos = "libcurl.dylib" }
[custom-config]
api_key_env = "MY_API_KEY"

Extensions declare which sections they handle through the ABI. Unclaimed sections produce validation warnings. See Extensions for the claiming mechanism.

For native ABI resolution and lock guarantees, use the canonical Native C Interop chapter.

That chapter defines provider semantics (system/path/vendored), target-qualified targets entries (os-arch[-env]), host resolution, and frozen-mode safety requirements for [native-dependencies].

  • Project mode uses shape.lock in the project root.
  • Standalone scripts use <script>.lock.
  • Native artifacts in those lockfiles are host-target- and fingerprint-specific, so one committed lockfile may contain multiple variants for different machines.

Both include dependency pinning and compile-time artifacts.

Project shape.toml and script frontmatter are mutually exclusive during execution. If a script is inside a project, use shape.toml only.

The Shape LSP validates shape.toml directly and provides completion, hover, and diagnostics for known sections and keys.