CLI Reference
The sigil command-line tool provides all development and runtime functionality.
Running Programs
Running Scripts
sigil <filepath> [args…] runs in scripting mode: it loads the scripting prelude, exposes script arguments, and prints only explicit output. Executable files using #!/usr/bin/env sigil follow the same path. See Shell Scripting for the preloaded APIs and short names.
Uncaught errors are printed to stderr with concise details and a source location when available. Use sigil --error-history script.sgl to include expanded call history. Place this option before the script filename; later arguments belong to the script.
Evaluating Files
sigil eval -f <file.sgl>Evaluates the specified Sigil source file with ordinary explicit imports, without the scripting prelude or script-argument context.
Example:
sigil eval -f hello.sglEvaluating Expressions
sigil eval '<expression>'Evaluates a Sigil expression and prints the result. --quiet suppresses that result, while --error-history expands error diagnostics. Both options also work with eval -f. Errors still exit nonzero. Captured call history can include completed calls and macro expansion rather than a live stack.
Examples:
sigil eval '(+ 1 2 3)'
# Output: 6
sigil eval --quiet '(println "Hello!")'
# Output: Hello!Adding Library Paths
Use -L to add directories to the library search path:
sigil eval -L lib -f main.sglInteractive REPL
sigil replStarts an interactive Read-Eval-Print Loop. Type expressions to evaluate them. Press Ctrl+D or type ,q to exit.
Building Projects
sigil build
Build a package and its dependencies:
sigil build # Build all workspace packages
sigil build sigil-json # Build specific package with deps
sigil build sigil-cli --config release # Build with specific configConfigurations:
dev— Development build (default)debug— Debug build with symbolsrelease— Optimized release build with modules bundled into a self-contained executable
Running Your Application
sigil run
Build and run your application:
sigil run # Build dev config and run entry point
sigil run --config release # Build release config and run
sigil run a --dry-run -t x # Everything after run's own options goes to the programThe sigil run command automatically builds any out-of-date modules before running the application's entry point (defined by entry: in package.sgl).
-t / --task still runs a task instead of the entry point, and prints Deprecated: use 'sigil task' instead; it is removed before 1.0. Use `sigil task`. Until then, sigil run -t <task> a b gives a step task its arguments through (task-arguments) from (sigil build).
sigil run's own options (-t, --config, --redirects, -v, --profile) come first. The first argument that is not one of them, and everything after it, goes to the program unchanged, however much it looks like an option: sigil run app --dry-run -t x passes app --dry-run -t x. Use -- to pass an argument that starts with - first: sigil run -- --help. The entry point reads its arguments from (command-line), as the built program would.
Tasks
sigil task
Run a named job of the project, or one a dependency provides:
sigil task # List tasks (also: sigil task --list)
sigil task build # A step task of this project
sigil task stage-news site/ # A script task of this project, with arguments
sigil task substratic:publish-web build/web --dry-run # A dependency's script task
sigil task substratic: # List one dependency's tasks
sgx substratic:publish-web build/web --dry-run # The same as sigil task ...A task is one of two kinds:
- A step task is a build pipeline declared in
tasks:(build,testandcleanexist by default). It runs in-process over the build context and takes no arguments:sigil task build extrais refused.--configand-vapply to it. - A script task is a Sigil shell script declared under
provides: script-tasks:(below). Every argument after its name reaches the script unchanged, options included:sigil task t -v -- -L xgives the script("-v" "--" "-L" "x").
sigil task's own options (--list, --names, -c/--config, -v, -h) come before the task name; parsing stops at the name.
Resolution. A bare name is always one of this project's own tasks: its step tasks (for a workspace of several packages, its workspace-level tasks) and its own script tasks. A dependency's tasks are reached only with its package prefix, <pkg>:<name>, where <pkg> is the dependency's name:. Only the project's direct dependencies qualify (listed in dependencies: or dev-dependencies:), and only their script tasks: a dependency's step tasks are its own build. A dependency can therefore never override one of the project's tasks or stand in for a missing one. An unknown bare name is an error that names any dependency providing a task of that name (Did you mean substratic:publish-web?) and runs nothing. Nothing is fetched: a dependency must be installed, and sigil task refuses missing or stale dependencies as sigil run does. Redirects apply: under SIGIL_REDIRECTS or a leading sigil --redirects F, a redirected dependency's tasks come from the redirect target.
Script tasks never run implicitly. sigil build, sigil test, dependency builds and sigil deps install never run one; a script task runs only when someone names it.
Running a script task. It runs through the same door as sigil <file>: the shell prelude, (script-args), the caller's working directory. (script-dir) is the task file's directory, and (project-root) is the root of the project sigil task ran in (for a dependency's task, the consuming project). The task file's directory, and any load-path: directories, go first on the library path for that run, so a task can keep its library modules beside it (tasks/substratic/tasks/manifest.sgl as (substratic tasks manifest)). Before it runs, one line on stderr names its source:
sigil task: substratic:publish-web (substratic 0.3.0 @ 1a2b3c4d)
@ is followed by the locked commit (git), sha256: and the content address (registry), path DIR (path dependency), or redirected to DIR. The script's exit status is sigil task's.
Declaring script tasks. Script tasks are quoted data under provides: in package.sgl, so a package can declare them without requiring a newer Sigil:
provides: (list
script-tasks: '((publish-web
file: "tasks/publish-web.sgl"
description: "Publish a checked site tree"
usage: "DIR [--preview | --dry-run]")
(stage-web
file: "tasks/stage-web.sgl"
description: "Stage the deploy tree")))| Key | |
|---|---|
| name | a symbol matching [a-z0-9-]+, not starting with -; not build, test or clean |
file: | required; relative to the package root, no .., and it must not resolve outside the package (a symlink out is refused when the task runs) |
description: | required; one line |
usage: | optional; one line, shown by --list |
load-path: | optional; a list of package-relative directories added to the library path for the run |
Any other key is an error. An invalid declaration is refused with exit status 78 and a message naming the package, the task and the key. One name may not be both a step task and a script task of the same package. tasks/ is the convention for task files, not a rule; keeping them outside any directory a build task compiles (such as src/) keeps them out of every build.
Listing. sigil task --list prints each task's name, kind (steps or script), source and description, the project's first, then each dependency's with its prefix. --names prints only the names, one per line.
sgx
sgx is sigil task under a short name. sigil cli install, sigil cli use and sigil cli upgrade write $SIGIL_HOME/bin/sgx, an sh wrapper that runs the active version through the sigil wrapper:
#!/bin/sh
# sigil-managed: sgx (task runner)
SIGIL_HOME="${SIGIL_HOME:-$HOME/.sigil}"
exec "$SIGIL_HOME/bin/sigil" task "$@"An existing bin/sgx without that marker line is left alone. A sigil binary started under the name sgx (a link or a copy) also behaves as sigil task.
The dependency index and sigil deps verify
sigil deps install and sigil deps update write .sigil/deps.index: for each entry in .sigil/deps, what its package.sgl declares (name, version, sigil: floor, script tasks, step task names, provides: keys, source directories), the sha256 of that package.sgl, and for a dependency in the shared store ($SIGIL_HOME/deps) the sha256 of its whole tree. sigil task reads dependencies' tasks from it, and every command's startup reads their source directories from it, instead of evaluating each dependency's package.sgl again. (A path dependency's package.sgl is still read by the missing-dependency check.)
The index is keyed by content, never by modification time. It is used only while sigil.lock hashes the same and the running sigil is the one that wrote it; otherwise running or listing a dependency's tasks refuses with exit status 78 and asks for sigil deps install, and startup reads package.sgl files as before. A path dependency or a workspace member changes without a reinstall, so its entry is used only while its package.sgl still hashes the same; a redirected dependency is always read from its redirect target.
sigil deps verify # re-hash every store tree against the indexsigil deps verify re-hashes each store tree against what was recorded at install, and for a git checkout also asks git whether any tracked file differs from the pinned commit (which catches a change made before the install, when the recorded hash already includes it). It exits 0 when every store tree matches, 1 when one changed, differs from its commit or is missing, and 78 without a usable index. Path dependencies and workspace members are listed as skipped.
The index records absolute paths, so a project that was moved or copied does not trust it (dependency tasks ask for sigil deps install; startup reads package.sgl files as before).
sigil completions
eval "$(sigil completions bash)" # in ~/.bashrc
eval "$(sigil completions zsh)" # in ~/.zshrc, after compinitCompletes sigil's subcommands, and task names for sigil task and sgx (including pkg:name), from sigil task --names in the current project.
Testing
sigil test
Run project tests:
sigil test
sigil test <pattern> # Run matching testsOther Commands
sigil repl
Start an interactive REPL:
sigil replsigil format
Format Sigil source files:
sigil format <file.sgl>
sigil format --check <file.sgl> # Check without modifyingsigil docs
Documentation tools:
sigil docs build <source> <output>
sigil docs serve <output>sigil cli
CLI management commands:
sigil cli install # Install sigil to ~/.sigil
sigil cli upgrade # Download latest version
sigil cli use <ver> # Switch to a specific version
sigil cli versions # List installed versions
sigil cli prune # Remove old versions
sigil cli env # Print shell configurationupgrade and use read the release list from the Sigil package registry (https://pkg.usesigil.org, or the URL in SIGIL_REGISTRY) and download the binary by its content hash. Before anything is installed, sigil checks the whole chain itself: the registry's key list must be signed by the root key built into this sigil, the release list must be signed by a toolchain key from that list, and the downloaded binary must have the sha256 and size the release list gives. No minisign program is needed.
- If the registry cannot be reached, or does not have the release list,
sigilprintsRegistry unavailable, using Codeberg.and uses Codeberg's release metadata instead, which is checked by HTTPS and its sha256 list. If the registry's signed release list did arrive but the binary itself was not served, the Codeberg download must have exactly the sha256 and size the signed list gives. - If the registry answers but what it serves fails a check (a bad signature, a key without the right role, a release list older than one already seen, or a binary with the wrong hash),
sigilprintsVerification failed; nothing was installed.with the reason, and stops. It does not fall back to Codeberg in that case. sigil cli use <ver>for a release the registry does not carry (releases from before the registry) prints a note and downloads it from Codeberg.
sigil remembers the newest sequence numbers it has verified, per root key, in $SIGIL_HOME/registry-seen-seq, so a mirror cannot serve an older release list either. Deleting the file resets that memory.
sigil changes
Release management:
sigil changes new # Create a new changeset
sigil changes status # Show pending changes
sigil changes version # Bump version based on changes
sigil changes changelog # Generate changelogGlobal Options
| Option | Description |
|---|---|
-v, --verbose | Verbose output |
-q, --quiet | Minimal output |
--version | Show version |
--help | Show help |
Environment Variables
| Variable | Description | Default |
|---|---|---|
SIGIL_PATH | Library search path (colon-separated) | Current directory |
SIGIL_HOME | Sigil installation and global dependency-state directory | ~/.sigil |
SIGIL_REGISTRY | Package registry base URL, for packages and for sigil cli upgrade/use. A mirror changes where bytes come from, never which keys verify them | https://pkg.usesigil.org |
NO_COLOR | Disable colored output | Not set |
SIGIL_DEPS_TRACE_DROPPED | Set to 1 to trace dependency constraints the resolver discarded | Not set |
SIGIL_ALLOW_STALE_DEPS | Set to 1 to build, test or run even though .sigil/deps does not match sigil.lock | Not set |
Tracing discarded dependency constraints
The resolver deduplicates by package name: the first declaration of a package to be resolved wins, and any later version range for that same name is discarded. This is normal and usually correct, because a library declaring sigil: "^0.17" is stating what it was built against rather than pinning the host's runtime.
Note (2026-08-25):sigil: "^0.17"above is the RETIRED spelling — thesigil:field is now a bare minimum version (sigil: "0.17") and range operators there are refused on host manifests; installed copies of old releases still carry carets and are read as their floor. Seedocs/reference/package-sigil-field.md. Operators remain valid for dependencyversion:fields, which is what this trace is about.
It also means a version range you wrote in package.sgl can have no effect on the resolve, with nothing in the output saying so. SIGIL_DEPS_TRACE_DROPPED=1 makes those discards visible:
SIGIL_DEPS_TRACE_DROPPED=1 sigil deps installEach discarded constraint prints one line on stderr:
DROPPED <site> <package> want=<range> have=<version> <verdict>
| Field | Meaning |
|---|---|
site | git-dep, workspace-member, or transitive — which resolution path the discarded constraint arrived on |
want | the range that was discarded, or - when the arrival path carries no range |
have | the version already resolved for that package |
verdict | SATISFIED (the resolved version meets the discarded range), UNSATISFIED (it does not), NO-RANGE, UNPARSEABLE, or UNKNOWN-INSTALLED-VERSION |
UNSATISFIED on an ordinary package is the interesting case: something in your dependency graph asked for a version range that the resolve does not meet, and the build is proceeding anyway. UNSATISFIED on sigil-lib or sigil-stdlib is expected and not a problem — the runtime family follows the host project's sigil: field, so a dependency's own range for it is advisory.
The trace never changes what gets resolved. It only reports.
Installed dependencies that do not match sigil.lock
sigil build, sigil test and sigil run stop with exit code 78 when a link in .sigil/deps points at a different commit than sigil.lock names:
✗ sigil test refused: .sigil/deps does not match sigil.lock.
project: /home/me/my-app
[lock-vs-disk] sigil.lock and the installed motif are different commits
package: motif
locked: 55c9e747…
installed: 046651cf…The links are written by the last sigil deps install in that checkout, and git checkout does not move them, so switching to a branch whose lock differs leaves the old code in place with nothing in git status to say so. The usual fix is sigil deps install. To run against what is installed anyway, set SIGIL_ALLOW_STALE_DEPS=1. Workspace members, from-path dependencies and dependencies redirected with SIGIL_REDIRECTS or sigil build --redirects are not compared; sigil test --redirects skips the check, and sigil run --redirects checks every dependency the redirects do not replace. SIGIL_BUILD_COHERENCE=off does not turn it off.
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Command-line usage error |
| 3 | Compilation error |
| 4 | Runtime error |
| 78 | Configuration error (EX_CONFIG) — e.g. a malformed sigil: field, .sigil/deps links that do not match sigil.lock, or a coherence refusal under SIGIL_BUILD_COHERENCE=enforce; retrying unchanged cannot succeed |
Examples
Development Workflow
# Create and run a new project
sigil init my-app
cd my-app
sigil run # Build and run the app
# Run a standalone script
sigil eval -f myprogram.sgl
# Run with library path
sigil eval -L lib -f main.sgl
# Start REPL for experimentation
sigil replBuilding for Distribution
# Build a package
sigil build sigil-cli --config release
# Install the CLI
./build/release/bin/sigil cli installRunning Tests
# Run all tests
sigil test
# Run specific tests
sigil test "test-parser"