Manifest and lockfile
spool reads your project’s coil.toml and writes coil.lock next to it. coil reads neither: spool turns them into flags (--root, --allow-*, --dload-pin, …) on every coil command it runs (see Project configuration). This page covers the parts spool uses and how it interprets them.
[package]
name = "my-app"
coil = ">=0.1.0" # optional engine range
[dependencies]
http = { git = "https://github.com/ardax-corp/coil-http.git", version = "^0.1" }
local = { path = "../my-lib" }
[module]
roots = ["./src"] # spool also passes .spool/deps, the stdlib and each dependency's src/
[scripts] # optional, off unless --enable-scripts
post_install = "./scripts/post-install.sh"
[package]#
| Key | Used by spool for |
|---|---|
name | The package’s name. Diagnostics for the current project use it (app when empty). |
coil | Optional engine range: the Coil toolchain versions this package supports. |
include | Optional include hook, relative to the package’s own checkout. Runs in projects that depend on it. |
spool does not read version.
Engine range#
coil is a version requirement checked against coil --version of the toolchain on COIL / PATH. Missing means any version. install, add and update check the current project and every dependency, and stop before fetching when the running toolchain is out of range:
package http requires coil >=0.2.0, running 0.1.0
[dependencies]#
Each entry is an inline table keyed by the name you use it under. Values must be strings.
| Form | Keys | Notes |
|---|---|---|
| Git | git + version or rev | git is any URL host git can clone (HTTPS, SSH, private remotes via your credentials). version is a version requirement matched against the repository’s tags, or latest for the tip of the default branch. rev pins a branch, tag or commit instead; update moves a branch pin. |
| Path | path | A local checkout, relative to the project root. No version or rev. Not written to the lockfile. |
Either form may add trusted = true (a bool): that dependency’s dload stems skip the sha256 pin (spool passes --dload-trusted STEM). The stem still needs [ffi] allow.
spool rejects a dependency that:
- combines
gitandpath—git and path cannot be combined - is a git dependency without
versionorrev—git dependency <name> needs version or rev - sets
versionorrevon a path dependency —path dependency cannot set version or rev - combines
version = "latest"withrev—git dependency <name>: version = "latest" cannot be combined with rev - uses any other key —
unknown dependency key <key> - sets
trustedto a non-bool —dependency <name> key trusted must be a bool - repeats a name —
duplicate dependency <name>
spool add edits this table for you and keeps the file’s comments:
spool add http --git https://github.com/ardax-corp/coil-http.git --version '^0.1'
spool add local --path ../my-lib
Without --version or --rev, add records *, or latest when the repository has no version tags at all. In that case it prints a one-line note:
spool: note: msgpack has no version tags; using version = "latest" (the default branch tip)
spool remove <name> drops the entry again.
Version requirements#
A requirement is a comparator, or several joined by commas (">=1.2, <2"). Tags may carry a leading v (v0.1.0). Prerelease tags are never picked by a range.
| Requirement | Matches |
|---|---|
* | Any version |
^1.2.3 | >=1.2.3 with the same major (1.x.y) |
^0.2.3 | >=0.2.3 with the same minor (0.2.x) |
^0.0.3 | Exactly 0.0.3 |
~1.2.3 | >=1.2.3 with the same major and minor (1.2.x) |
>=1.2.0, >1.2.0, <=1.2.0, <1.2.0 | The comparison |
=1.2.0 or 1.2.0 | Exactly that version — a bare version is not a caret range |
The highest matching tag wins; with none, spool reports no tag matches requirement <req>. When several dependencies need the same package, spool picks the highest tag that satisfies all of their requirements; if there is none it stops with the requesters named:
diamond conflict for base: hello requires @dev, mid requires ^1
latest#
version = "latest" follows the tip of the repository’s default branch, whatever the branch is called: spool resolves it with git ls-remote <url> HEAD. Use it for libraries that have no release tags yet.
[dependencies]
msgpack = { git = "https://github.com/ardax-corp/coil-msgpack.git", version = "latest" }
It is locked like a branch pin: the lockfile records the resolved commit with ref = 'HEAD'. install keeps that commit, and update moves it to the current tip. outdated shows the locked commit next to the current tip.
latest also works in a dependency’s own coil.toml. Two latest requirements on the same package agree, but latest together with a range or a rev is a diamond conflict:
diamond conflict for msgpack: app requires ^0.1, wrap requires latest
[module].roots#
spool passes each [module].roots entry (default ./src) to coil as --root. It links every dependency under .spool/deps/<name> (to the package’s src/) plus .spool/deps/<name>.hy when that file exists, and passes --root .spool/deps once dependencies are linked, then the stdlib unless a root already is one, then each dependency’s src/. use toml::{Toml} resolves through the file link and use greet::hello through the directory link. The src/ roots resolve a package’s own modules the way it does in its own repo: use tls::client (src/tls/client.hy), use http::url, and second top-level modules such as coil-sdl’s use simd. They come after the stdlib, so a dependency never shadows a stdlib module.
Do not add .spool/deps/<name> to [module].roots for this; an existing entry like that still works but is no longer needed. spool never edits coil.toml.
[scripts]#
Lifecycle scripts for the current project only; a dependency’s [scripts] never run during your install.
| Key | Runs |
|---|---|
pre_install / post_install | Around spool install and spool add |
pre_update / post_update | Around spool update |
Paths must be relative to the project root, without .. segments. Unknown keys are an error. Scripts run with host sh only with --enable-scripts; --ignore-scripts always wins. See Hook trust and Project scripts.
[permissions]#
What the project’s programs and tests may do on the host. spool passes each
key that is true to coil as a flag (read = true becomes --allow-read)
on every coil command it runs (build, run, check, test, debug, lsp, …). Keys: read, write, net, env,
exec, exit, attach, and all for everything. Left out means denied.
[permissions]
read = true
write = true
See Permissions.
[[ffi.native]]#
Native libraries a project loads with dload. spool download (or spool install --with-natives) reads them through coil natives dump and fetches each direct library with a url into ~/.coil/natives (override with COIL_NATIVES_DIR). spool passes each row to coil package and coil natives dump as --ffi-native name=…,version=…,path=…. Keys: name, version, path (required), package, url, sha256, requires, requires_hint.
url and sha256 are for spool download only; coil never sees them. sha256 (64 hex digits, any case; anything else is an error) checks a library spool download fetches because it is not in path yet: coil has no file to hash, so spool checks the download against the row’s sha256 before it moves it into path. Without one the library is fetched over https unchecked, with a warning, and pinned when coil package hashes it. A library already in path is hashed by coil and does not need it.
[[ffi.native]]
name = "regex"
version = "0.3.0"
path = "./native"
url = "https://example.com/coil-regex/0.3.0/libregex.so"
sha256 = "<64 hex digits of libregex.so>"
Dependency natives#
A library that ships a native names it in its own coil.toml, relative to its own checkout. coil-tls:
[ffi]
search_paths = ["./native"]
[[ffi.native]]
name = "tls"
version = "0.1.0"
path = "./native"
spool resolves these against the dependency’s checkout (the directory behind .spool/deps/<name>), never against the consumer:
- Each dependency’s
[ffi] search_pathsbecomes--ffi-search-path, after the project’s own. Only directories that exist inside the checkout count: absolute and..paths are dropped, and so is a consumer-layout path such as coil-http’s./.spool/deps/tls/native. spool build/runpass each dependency’s[[ffi.native]]rows tocoil package, for every stem the project does not declare itself. The library comes from the first search directory that holds it (the filespool testloads, so a sibling build in the project’s ownsearch_pathsstill wins), else from the row’spath.- After packaging,
spool buildcopies each pinned library into~/.coil/natives/cache/, where the executable looks first.
These paths only locate files; loading still needs [ffi] allow and a pin or trusted = true. spool does not build natives: build one in the dependency’s checkout (make -C "$(dirname "$(readlink -f .spool/deps/tls)")/native" artifact for coil-tls), or point the project’s own search_paths at a build elsewhere.
coil.lock#
spool writes coil.lock on install, add and update. Commit it: it pins every git dependency to an exact commit and content hash. Edit it only through spool.
# spool lockfile v1
# This file is generated by spool. Do not edit packages by hand.
[hooks]
allow_include = ['http']
[scripts]
post_install = './scripts/post-install.sh'
post_install_hash = 'def456…'
[[package]]
name = 'http'
git = 'https://github.com/ardax-corp/coil-http.git'
tag = 'v0.1.0'
rev = '0a973db…'
content_hash = '…'
hook_path = './hooks/include.sh'
hook_hash = 'abc123…'
[[package]]#
One row per git dependency, direct or transitive, sorted by name. Path dependencies have no row.
| Key | Required | Meaning |
|---|---|---|
name | yes | Dependency name |
git | yes | Remote URL |
tag | no | The tag the requirement resolved to |
rev | yes | Commit checked out |
content_hash | yes | Hash of the checkout’s tree; install verifies it after fetching |
ref | no | The manifest rev (branch, tag or commit) a rev-pinned dependency asked for; HEAD for version = "latest" |
hook_path, hook_hash | no | Pinned include hook path and git hash-object hash, recorded on the first opted-in run |
A [[package.native]] block under a package may pin its native library: sha256 (with stem / lib) becomes --dload-pin STEM=SHA256. spool keeps these blocks when it rewrites the lock.
[hooks]#
allow_include lists the dependencies whose include hooks you allow, managed with spool allow-include <name>. It lives in the lockfile, not in coil.toml.
[scripts]#
Path and git hash-object hash for each current-project lifecycle script (<slot> and <slot>_hash), recorded on the first opted-in run. A script whose hash no longer matches does not run.
Any other key or line is rejected as corrupt coil.lock.
Related#
- spool commands
- spool overview — hooks, scripts, cache, private git
- Project configuration (
coil.toml) — the flags each key becomes