A spice is a Turmeric package that your project depends on. This guide
covers how to find, add, fetch, and import spices -- including pure-Turmeric
spices and C library bindings via :cmake-deps.
See Developing Spices if you want to create and publish a spice of your own.
The canonical source for official spices is the turmeric-spices monorepo. It provides seven packages in three tiers:
| Spice | Description | C deps? |
|---|---|---|
tur-test |
Testing framework: describe/it/TAP output | None |
tur-math |
2D/3D vector and matrix math | None |
tur-sqlite |
SQLite3 bindings | SQLite amalgamation |
tur-raylib |
Raylib graphics and input | Raylib |
tur-json |
JSON parsing and serialization | yyjson |
tur-http |
Async HTTP/HTTPS client | mbedTLS |
tur-regex |
PCRE2 regular expression bindings | PCRE2 |
Each spice lives in its own subdirectory and is versioned independently
with a per-package tag: <spice>-vMAJOR.MINOR.PATCH.
Use tur add with --subdir to pull a spice from the monorepo:
tur add https://github.com/rjungemann/turmeric-spices \
--ref test-v0.1.0 --subdir spices/test --name test
tur add https://github.com/rjungemann/turmeric-spices \
--ref math-v0.1.0 --subdir spices/math --name math
tur add https://github.com/rjungemann/turmeric-spices \
--ref sqlite-v0.1.0 --subdir spices/sqlite --name sqlite
tur add https://github.com/rjungemann/turmeric-spices \
--ref json-v0.1.0 --subdir spices/json --name json
Each command updates build.tur and tur.lock automatically.
tur add https://github.com/alice/tur-geom --ref v0.2.1
The spice name defaults to the last path segment with any tur- prefix
stripped (tur-geom becomes geom). Override with --name:
tur add https://github.com/alice/tur-geom --ref v0.2.1 --name geometry
If --ref is omitted the tool resolves to HEAD and warns:
Warning: no --ref specified; resolved to HEAD (a1b2c3d4).
Pin with: tur add https://github.com/alice/tur-geom --ref a1b2c3d4
Always pin with an explicit tag or commit SHA to keep builds reproducible.
tur add ../tur-utils --path
Use this while actively developing a dependency alongside your project.
Local path spices are not recorded in tur.lock and are never fetched
from the network.
tur add ChangesBefore adding any spice:
(defpackage my-app
:name "my-app"
:version "0.1.0")
After tur add https://github.com/alice/tur-geom --ref v0.2.1:
(defpackage my-app
:name "my-app"
:version "0.1.0"
:spices {
"geom" {:url "https://github.com/alice/tur-geom"
:ref "v0.2.1"}
})
tur fetch # download everything in tur.lock
tur fetch --update # upgrade spices to the latest allowed versions
tur run and tur build invoke tur fetch automatically when any spice
is missing. Pass --offline to skip the network and fail if a spice is
absent:
tur run --offline
tur.lock records the resolved commit SHA and SHA-256 hash for every fetched
spice. Always commit it to version control; it is what makes builds
reproducible across machines and CI runs.
;;; tur.lock -- generated by tur. Do not edit by hand.
;;; Commit this file to version control for reproducible builds.
(deflockfile
:format-version 1
:spices {
"geom" {:url "https://github.com/alice/tur-geom"
:ref "v0.2.1"
:resolved "a1b2c3d4e5f6..."
:sha256 "abc123..."
:fetched-at "2026-05-22T09:00:00Z"}
"math" {:url "https://github.com/rjungemann/turmeric-spices"
:ref "math-v0.1.0"
:subdir "spices/math"
:resolved "d6e7f8a9b0c1..."
:sha256 "def456..."
:fetched-at "2026-05-22T09:00:03Z"}
})
Rules:
- tur fetch creates or updates tur.lock.
- tur build uses the lock and will not silently upgrade versions.
- Local :path spices are not recorded in the lock file.
- Builds fail when a fetched spice's hash does not match the lock entry.
Spice names map directly to import paths. A spice named geom that exports
geom/vector and geom/matrix is imported like any other module:
(import geom/vector :refer [vector-2d cross-product])
(import geom/matrix :as mat)
(defn main [] :int
(let [v (vector-2d 1.0 2.0)
m (mat/mat4-identity)]
(println v)
0))
The compiler resolves geom/vector to spices/geom-v0.2.1/src/vector.tur.
No extra configuration is needed.
Mark a spice :optional true when it is only needed for tests or dev
tooling. Optional spices that are absent do not cause a build error.
:spices {
"test" {:url "https://github.com/rjungemann/turmeric-spices"
:ref "test-v0.1.0"
:subdir "spices/test"
:optional true}
}
When tur test is run, optional spices are fetched so test files can import
them. When tur build is run in production, they are skipped.
Some spices (like tur-sqlite or tur-raylib) wrap a C library. When you
add them, tur build fetches and compiles the C library via CMake
automatically -- no CMake knowledge required on your end.
You can also add a C library directly to your project without going through a spice:
tur add --cmake https://github.com/raysan5/raylib --ref 5.5 \
--option BUILD_SHARED_LIBS=OFF --option BUILD_EXAMPLES=OFF
This appends a :cmake-deps entry to build.tur:
(defpackage my-app
:name "my-app"
:version "0.1.0"
:cmake-deps {
"raylib" {:url "https://github.com/raysan5/raylib"
:ref "5.5"
:options {:BUILD_SHARED_LIBS "OFF"
:BUILD_EXAMPLES "OFF"}}
})
When tur build runs it:
cmake/SpiceDeps.cmake from the :cmake-deps block.cmake/spice-deps-manifest.json for include dirs, lib dirs, and
link libs.cc automatically.Declare the C symbols you need in Turmeric with include-c and extern-c:
(include-c "raylib.h")
(extern-c InitWindow [:int :int :cstr] :void)
(extern-c CloseWindow [] :void)
(extern-c WindowShouldClose [] :bool)
(extern-c BeginDrawing [] :void)
(extern-c EndDrawing [] :void)
(defn main [] :int
(InitWindow 800 600 "Hello")
(while (not (WindowShouldClose))
(BeginDrawing)
(EndDrawing))
(CloseWindow)
0)
No -I or -L flags are needed; tur build injects them from the manifest.
CMake deps are also tracked in tur.lock with SHA-256 hashes for integrity
verification. For the generated SpiceDeps.cmake format, the manifest
schema, security considerations, and the outbound direction (publishing a
Turmeric library so CMake projects can consume it), see the
CMake/CPM integration notes.
tur.lock.
Builds fail on mismatch; no silent re-downloads.:ref to avoid moving targets.:cmake-deps entry is a trust decision equivalent to executing build
scripts from that repository. Audit before adding.tur audit (planned) will list all cmake-dep repositories and their
maintainer GPG keys.When two spices require incompatible versions of a shared dependency the build fails with a diagnostic. There is no silent multiple-version shadowing. You must either upgrade one spice or pin versions to a compatible range.
| Condition | Message |
|---|---|
No build.tur in the directory tree |
No build.tur found. Run tur new <name> to create a project. |
| Spice already in the manifest | 'geom' is already a dependency. Use tur update geom to change the ref. |
| Network failure | Failed to reach https://github.com/...: <reason> |
| Ref not found | Ref 'v99.0.0' not found in https://github.com/alice/tur-geom |
| SHA mismatch on re-fetch | Integrity check failed for 'geom'. Run tur fetch --force to re-download. |
# Add a Turmeric spice
tur add <url>
tur add <url> --ref <tag-or-sha>
tur add <url> --ref <ref> --subdir <path> --name <alias>
tur add <path> --path
# Add a C/CMake dependency
tur add --cmake <url> --ref <ref>
tur add --cmake <url> --ref <ref> --option KEY=VALUE
# Fetch and update
tur fetch
tur fetch --update
# Build and run
tur build
tur build --release
tur run
tur run --release
tur run --offline
tur test
build.tur manifest reference and tur CLIextern-c, include-c, inline-C blocks