Consuming Spices Guide

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.


Official First-Party Spices

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.


Adding Spices

Official spices from turmeric-spices

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.

Third-party spices from a Git URL

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.

Local path spices (development)

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.


What tur add Changes

Before 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"}
  })

Fetching and Updating

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

The Lock File

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.


Importing Spice Modules

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.


Optional Spices

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.


C/CMake Dependencies

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:

  1. Generates cmake/SpiceDeps.cmake from the :cmake-deps block.
  2. Invokes CMake to fetch and compile the C library.
  3. Reads cmake/spice-deps-manifest.json for include dirs, lib dirs, and link libs.
  4. Passes those flags to 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.


Security


Conflict Resolution

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.


Common Error Messages

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.

CLI Quick Reference

# 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

See Also