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. Its packages include:

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

The web stack (tur-httpd, tur-template, tur-tourist, tur-tls, tur-ws-client/tur-ws-server) and the data/DSP spices (tur-frame, tur-stats, tur-signal, tur-ecs, ...) live there too -- see their per-spice guides. 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.

Globally installed spices

A spice you installed with tur install can be consumed as a library by declaring it :global -- there is no tur add flag for this yet, so write the entry by hand:

:spices #map{
  "notebook" #map{:global true}
}

It resolves through the install registry rather than <project>/spices/, so nothing is fetched and no tur.lock row is written (as with a :path dep). If the spice is not installed, tur fetch says so and fails rather than letting the build reach module not found. :global takes neither :url nor :path -- those name a different resolution source. See Global Spices as Libraries for the full rules.


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 #map{
    "geom" #map{: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 #map{
  "test" #map{: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 \
  --opt BUILD_SHARED_LIBS=OFF --opt BUILD_EXAMPLES=OFF

This appends a :cmake-deps entry to build.tur:

(defpackage my-app
  :name    "my-app"
  :version "0.1.0"
  :cmake-deps #map{
    "raylib" #map{:url     "https://github.com/raysan5/raylib"
                  :ref     "5.5"
                  :options #map{:BUILD_SHARED_LIBS "OFF"
                                :BUILD_EXAMPLES   "OFF"}}
  })

When tur build runs it:

  1. Generates cmake/CMakeLists.txt from the :cmake-deps block (via the automatic tur fetch).
  2. Invokes CMake to fetch and compile the C library.
  3. Reads cmake/spice-deps-manifest.json for include dirs, lib dirs, link libs, and link flags.
  4. Passes those flags to cc automatically.

Step 3's link flags are what make a Cocoa- or Objective-C-backed library (glfw, raylib) link on macOS: they carry the -framework Cocoa / -framework IOKit entries CMake records on the target, which cannot be spelled as -l. They also carry the dep's artifact by full path, so a target whose name differs from its library's (glfw's target glfw builds libglfw3.a) resolves correctly. Both are derived automatically from :targets; see :link-libs and :link-flags overrides for when you need to override them.

Declare the C symbols you need in Turmeric with extern-c (no header include is needed for the declarations themselves; an inline-C body that wants the header can hoist #include <raylib.h> to file scope with a __tur_include__ marker -- see the C integration guide):

(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 cmake/CMakeLists.txt 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

sh tur audit

It lists; it does not verify. There is no signature or maintainer-key checking -- an earlier version of this bullet promised GPG keys, and no key infrastructure exists to check them against. A :path dep is reported but not flagged as unpinned: it resolves from local source and has nothing to pin, and flagging it would train you to ignore the warning that matters.


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. To change its ref, edit the :spices entry for 'geom' in build.tur, then run tur fetch --update.
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.

A spice can declare which compiler versions it supports with :tur-version; if your tur is below that floor the build stops with TUR-E0621 (above a declared ceiling is TUR-W0623, a warning, and a malformed range in the spice's own manifest is TUR-E0622) -- see Declaring a compiler version range.


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> --opt 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