Welcome
joy is a native C++ package and build manager with a CLI designed to feel familiar to teams that prefer cargo/uv style workflows.
Core characteristics:
- predictable command surface and lock-aware flows
- explicit dependency source semantics (
github,registry,git,path,archive) - reproducible workflows (
sync,--locked,--offline,--frozen) - machine-readable JSON output for all commands (
--json/--machine) - CLI-first developer ergonomics with objective editor integration gates
As of March 6, 2026, joy ships:
- scaffolding (
joy new,joy init) - dependency lifecycle (
add,remove,update,tree,why,outdated) - registry config/discovery (
registry,search,info) - offline/cache workflows (
fetch,vendor,cache gc) - supply-chain verification (
verify+ SBOM output) - package publishing/ownership/yank workflows (
package,publish,owner,yank) - local builds and execution (
build,sync,run) with workspace routing and named targets - metadata and diagnostics (
metadata,doctor,recipe-check,version)
Who This Book Is For
- C++ developers who want faster reproducible local builds
- contributors tracking current
joybehavior and boundaries - automation authors integrating against stable JSON envelopes/error codes
Documentation Strategy
README.mdis the overview and entrypoint.- This mdBook is the canonical detailed usage/reference documentation.
- Planned/deferred features are explicitly labeled so expectations remain clear.
Status Legend
This book documents both shipped and planned behavior.
Use these labels when reading chapters:
Shipped: available in the current codebase.Experimental: present but likely to evolve quickly.Deferred: intentionally postponed and not available yet.Planned: roadmap intent, not implemented.
When a chapter contains deferred/planned sections, it will call that out directly near the relevant heading.
Getting Started
Start here if you want your first joy project running quickly.
Recommended path:
Install
Build From Source (All Platforms)
cargo build --workspace
cargo install --path .
GitHub Release Binaries
joy publishes versioned release artifacts to GitHub Releases.
Current artifact set (subject to release workflow updates):
joy-vX.Y.Z-x86_64-unknown-linux-gnu.tar.gzjoy-vX.Y.Z-aarch64-apple-darwin.tar.gzjoy-vX.Y.Z-x86_64-apple-darwin.tar.gzjoy-vX.Y.Z-x86_64-pc-windows-msvc.zipjoy-vX.Y.Z-x86_64-pc-windows-gnu.zip(compatibility artifact)
Homebrew (Single-Repo Tap)
joy publishes and maintains Formula/joy.rb in this repository.
Install and upgrade:
brew tap harnesslabs/joy
brew install harnesslabs/joy/joy
brew upgrade joy
Scoop Metadata
Scoop metadata is maintained at:
packaging/scoop/joy.json
Release workflows publish generated package-manager metadata with concrete checksums as release artifacts.
See the Releasing reference for the exact release and packaging workflow.
Required Host Tools (for joy build / joy run)
You need host tools for local C++ builds and compiled recipe-backed dependencies:
- C++ compiler (
clang++,g++, orcl.exeon Windows MSVC) ninjacmake(for compiled recipes)git
Use joy doctor to inspect tool availability and cache/recipe health.
Quickstart
60-Second Flow
joy new hello_cpp
cd hello_cpp
joy add nlohmann/json
joy run
joy tree
What happens:
joy newscaffoldsjoy.toml,src/main.cpp, and.gitignore.joy addrecords dependency intent and runs sync-lite refresh by default.joy runbuilds the project and executes the binary.joy treeshows resolved dependency graph state.
Reproducible Follow-Up Flow
After the first run, validate deterministic state:
joy fetch
joy --frozen sync
joy --frozen build
joy --json verify --strict --sbom sbom.json
What Gets Created
Project-local state is kept under .joy/ and lock state in joy.lock.
Typical layout:
hello_cpp/
joy.toml
joy.lock
compile_commands.json
src/
main.cpp
.joy/
build/
compile_commands.<target>.json
bin/
include/
lib/
state/
dependency-graph.json
Next Steps
- Core Commands
- Dependency Source Backends
- Registry Discovery and Configuration
- Offline Fetch, Vendor, and Cache
- Troubleshooting
Workflows
These chapters explain how to use joy day-to-day, from dependency edits to reproducible CI builds.
Core Commands
This chapter covers the most common day-to-day joy command flow, including command families added after the original docs wave.
Project Scaffolding
Create a new project:
joy new demo
Initialize the current directory:
joy init
Dependency Management
Add dependencies from different sources:
joy add nlohmann/json
joy add registry:nlohmann/json --version ^3
joy add git:https://github.com/fmtlib/fmt.git --as fmtlib/fmt --rev 11.0.2
joy add path:vendor/localdep --as localdep
joy add archive:https://example.com/libfoo.tar.gz --as acme/libfoo --sha256 <sha256>
Update dependencies:
joy update
joy update fmtlib/fmt --rev 11.1.0
joy update registry:nlohmann/json --version ^3
Remove dependencies:
joy remove fmtlib/fmt
Inspect the graph:
joy tree
joy tree --locked
joy why nlohmann/json
joy why nlohmann/json --locked
joy outdated
joy outdated --sources registry
joy outdated --sources github
joy outdated --sources git
joy outdated --sources path
joy outdated --sources archive
Registry Discovery and Setup
Configure and inspect registries:
joy registry list
joy registry add internal file:///path/to/internal-index.git --default
joy registry set-default internal
joy registry list --project
Search and inspect package metadata:
joy search json --registry internal --limit 20
joy info nlohmann/json --registry internal
Build, Sync, and Run
Build and run:
joy build
joy sync
joy run
joy run -- --app-arg value
Target-specific execution:
joy build --target tool
joy run --target tool
Lockfile controls:
joy build --locked
joy sync --update-lock
joy --frozen build
Metadata, Diagnostics, and Validation
joy metadata
joy doctor
joy recipe-check
joy verify
joy verify --strict --sbom sbom.json
joy metadata and joy doctor expose compile-db/graph/lockfile state and editor-gate diagnostics for CLI-first workflows.
Cache and Offline Preparation
joy fetch
joy vendor
joy vendor --output third_party/vendor
joy cache gc
joy cache gc --aggressive
Package Publishing Workflow
joy package init acme/widgets --kind header-only --version 0.1.0
joy publish --registry internal --rev v0.1.0
joy owner add acme/widgets alice --registry internal
joy owner list acme/widgets --registry internal
joy yank acme/widgets --version 0.1.0 --registry internal
joy yank acme/widgets --version 0.1.0 --undo --registry internal
Version Metadata
joy version
joy --json version
JSON / Machine Mode
Use --json (alias --machine) for stable automation envelopes:
joy --json tree
joy --json doctor
joy --json publish --registry internal
See Machine Interface and Machine Payload Matrix.
Reproducible Workflows
joy provides lockfile and offline controls intended for repeatable CI and local rebuilds.
joy sync
joy sync resolves dependencies, materializes headers/libs, refreshes graph artifacts, and updates joy.lock when needed without compiling the final binary.
joy sync
--locked
Reject lockfile updates for commands that consume dependency state.
joy build --locked
joy sync --locked
joy run --locked
joy why nlohmann/json --locked
joy tree --locked
Use --locked in CI to reject uncommitted dependency or manifest drift.
--update-lock
Force lockfile refresh when intentional dependency/manifest changes are present.
joy sync --update-lock
joy build --update-lock
joy run --update-lock
--locked and --update-lock are mutually exclusive.
--offline
Disable network access and use only cached dependency data.
joy --offline sync
joy --offline build
joy --offline run
joy --offline outdated
If cache is cold for required sources, commands fail with stable machine-readable error codes.
--frozen
--frozen is strict CI mode:
- implies offline behavior
- disallows lockfile changes
joy --frozen sync
joy --frozen build
joy --frozen run
Cache Warmup and Vendoring
Warm cache before strict offline runs:
joy fetch
joy sync
Vendor resolved lockfile sources for controlled source snapshots:
joy vendor
joy vendor --output third_party/vendor
Verify and SBOM in CI
Use joy verify to check provenance and produce SBOM data.
joy --json verify --strict --sbom sbom.json
This validates lock provenance fields by source backend and emits a baseline joy-sbom-v1 component list.
Typical CI Pattern
joy --json doctor
joy fetch
joy --frozen sync
joy --frozen build
joy --json verify --strict --sbom sbom.json
Automation should key off error.code and documented payload fields, not human text.
Workspaces and Targets
Workspaces (Shipped)
joy supports a workspace root manifest that routes project-scoped commands to member projects.
Workspace root joy.toml:
[workspace]
members = ["apps/app", "tools/tooling"]
default_member = "apps/app" # optional
profile = "release" # optional: dev|release
Run project-scoped commands from the workspace root:
joy -p apps/app build
joy -p apps/app run
joy -p apps/app tree
joy -p apps/app sync
joy -p apps/app verify
If default_member is unset, workspace-root project commands require -p/--workspace-package.
Workspace Lockfile Behavior (Shipped)
When routed from workspace root with -p:
- lockfile path is
<workspace-root>/joy.lock - lock hash is computed from root manifest + member manifests
- lock package entries aggregate across workspace members
Use this to keep workspace member dependency state deterministic in CI.
Workspace Profile Default (Shipped)
If [workspace] profile = "release" is set, sync/build/run default to release profile for workspace-routed commands unless --release explicitly overrides behavior.
Named Targets (Shipped)
Projects can define additional binary targets using [[project.targets]].
[project]
name = "demo"
version = "0.1.0"
cpp_standard = "c++20"
entry = "src/main.cpp"
[[project.targets]]
name = "tool"
entry = "src/tool.cpp"
Build or run a named target:
joy build --target tool
joy run --target tool
Dependency Source Backends
joy supports five direct dependency source backends.
Quick Matrix
github: canonical package id (owner/repo) withrevorversionregistry: package from configured index, requiresversiongit: explicit git URL/path and explicitrevpath: local path sourcearchive: URL + required SHA-256 checksum
GitHub Source (source = "github")
joy add nlohmann/json
joy add fmtlib/fmt --rev 11.0.2
joy add fmtlib/fmt --version ^11
joy update fmtlib/fmt --rev 11.1.0
Registry Source (source = "registry")
joy add registry:nlohmann/json --version ^3
joy add registry:nlohmann/json --registry internal --version ^3
joy update registry:nlohmann/json --version ^3
Registry direct dependencies require --version.
Git Source (source = "git")
joy add git:https://github.com/fmtlib/fmt.git --as fmtlib/fmt --rev 11.0.2
joy update fmtlib/fmt --rev 11.1.0
Git source entries require --rev and do not use --version.
Path Source (source = "path")
joy add path:vendor/localdep --as localdep
joy remove localdep
Path dependencies are useful for local integration and monorepo-style source reuse.
Archive Source (source = "archive")
joy add archive:https://example.com/libfoo.tar.gz --as acme/libfoo --sha256 <sha256>
joy update acme/libfoo --sha256 <new-sha256>
Archive source requires both URL and SHA-256.
Source Filters in outdated
joy outdated --sources supports:
allregistrygithubgitpatharchive
Example:
joy outdated --sources git
Provenance in joy.lock
Lock entries include backend-specific provenance fields used by verify, vendor, and deterministic refresh flows.
See Lockfile Schema.
Registry Discovery and Configuration
joy supports user-level and project-level registry configuration.
Registry Configuration Commands
List effective registries:
joy registry list
joy registry list --project
Add/remove registries:
joy registry add internal file:///path/to/internal-index.git
joy registry add internal file:///path/to/internal-index.git --default
joy registry remove internal
joy registry set-default internal
Use --project to write project-local config under .joy/.
Search and Package Info
Search package IDs:
joy search json
joy search json --registry internal --limit 50
Inspect package versions:
joy info nlohmann/json
joy info nlohmann/json --registry internal
Typical Setup Flow
joy registry add internal file:///srv/joy-index.git --default
joy search fmt --registry internal
joy info fmtlib/fmt --registry internal
joy add registry:fmtlib/fmt --registry internal --version ^11
Troubleshooting
If registry commands fail:
- validate registry name and index path/URL
- confirm
joy registry listshows expected default - retry with
--jsonand inspecterror.code - check project-vs-user scope mismatch (
--projectvs default user scope)
Reference details: Registry Configuration.
Offline Fetch, Vendor, and Cache
These commands support deterministic dependency preparation and cache lifecycle control.
Warm Cache Without Building
joy fetch
fetch resolves current manifest dependencies and pre-populates source caches.
Vendor Lockfile Dependencies
joy vendor
joy vendor --output third_party/vendor
vendor copies lockfile-resolved sources into a project-local directory, grouped by package slug and resolved commit.
Cache Garbage Collection
joy cache gc
joy cache gc --aggressive
- default
gc: clears temporary cache paths --aggressive: also clears source/archive cache roots
Offline + Frozen Workflow
joy fetch
joy --frozen sync
joy --frozen build
For lock/source integrity checks:
joy verify
joy verify --strict --sbom sbom.json
Common Pattern for CI
joy --json doctor
joy fetch
joy --frozen sync
joy --frozen build
joy --json verify --strict --sbom sbom.json
Package Publishing and Ownership
joy supports self-hosted package publishing and ownership workflows backed by registry index mutation.
Initialize a Reusable Package Manifest
joy package init acme/widgets --kind header-only --version 0.1.0
Kinds:
header-only(default)cmake
Publish
joy publish --registry internal --rev v0.1.0
If --source-package is omitted, package id from the local package manifest is used.
Manage Owners
joy owner list acme/widgets --registry internal
joy owner add acme/widgets alice --registry internal
joy owner remove acme/widgets alice --registry internal
Yank / Unyank Releases
joy yank acme/widgets --version 0.1.0 --registry internal
joy yank acme/widgets --version 0.1.0 --undo --registry internal
Yanked versions are excluded from normal registry resolution.
Remote Registry Transport (Shipped)
publish, owner, and yank support remote git-backed registry URLs (for example file://... or hosted git remotes) via temporary checkout/commit/push flows.
Transport/auth failures are returned with stable error codes in JSON mode.
Recommended End-to-End Flow
joy registry add internal file:///srv/joy-index.git --default
joy package init acme/widgets --kind header-only --version 0.1.0
joy publish --registry internal --rev v0.1.0
joy owner add acme/widgets alice --registry internal
joy yank acme/widgets --version 0.1.0 --registry internal
joy yank acme/widgets --version 0.1.0 --undo --registry internal
Dependencies
joy supports direct dependencies from multiple source backends and uses lockfile provenance to keep resolution deterministic.
Supported Direct Source Backends
githubregistrygitpatharchive
See Dependency Source Backends for user workflows and Manifest Schema for field-level contract details.
Source-Aware Update Reporting
joy outdated --sources supports:
all(default)registrygithubgitpatharchive
Provenance + Integrity
joy.lock records source provenance fields used by:
joy verifyjoy vendor- offline/frozen dependency reuse
See Lockfile Schema.
Registry Index Dependencies
Status: Shipped (git-backed registry index mode with named registries and publish/owner/yank workflows)
joy can resolve direct dependencies from configured registry indexes while fetching source content from package source coordinates.
Configure Registries
List effective configuration:
joy registry list
joy registry list --project
Add/set default registry:
joy registry add internal file:///path/to/internal-index.git --default
joy registry set-default internal
See Registry Discovery and Configuration.
Add Registry Dependencies
Use registry: package notation with a semver requirement.
joy add registry:nlohmann/json --version ^3
joy add registry:nlohmann/json --registry internal --version ^3
Registry direct dependencies require --version <range>.
Stored Metadata
In joy.toml, registry dependencies are stored with source = "registry" plus version range and optional named registry.
In joy.lock, selected concrete versions/commits and source provenance fields are recorded for deterministic refresh and verification.
Registry Index Versions
joy supports:
- registry index
version = 1(release -> source mapping) - registry index
version = 2(optional embedded package metadata summaries)
Registry v2 summaries can include kind/include roots/dependencies plus digest for mismatch detection.
Publish/Owner/Yank Integration
Registry commands are part of the self-hosted publish loop:
joy publishjoy owner list|add|removejoy yank [--undo]
Remote git-backed registry URLs are supported in current shipped behavior.
Current Limitations (Important)
- Registry alias package support (registry name different from canonical source package id) remains deferred.
- Broader non-git registry transport models are deferred.
Recipes (Compiled Dependencies)
joy ships a curated recipe index in recipes/ for dependencies that require build/install metadata.
Examples include:
fmtlib/fmtmadler/zlibgabime/spdlogNeargye/magic_enumjarro2783/cxxopts
How Recipes Fit the Build Pipeline
When a dependency is recipe-backed and compiled:
joyresolves dependency graph + recipe metadata.- It computes ABI-sensitive cache keys/hashes.
- It builds dependency artifacts with CMake + Ninja in global cache.
- It installs headers/libs into project-local
.joy/state.
Generic CMake Fallback (Shipped)
If a dependency has no recipe but contains a top-level CMakeLists.txt, joy can run a generic CMake-first compiled fallback path.
This keeps more compiled packages usable without waiting for curated recipe additions.
Validate Recipe Metadata
joy recipe-check
joy --json recipe-check
Use this in local development and CI whenever recipe metadata changes.
Troubleshooting
Start with joy doctor and the common failure patterns in the next chapter.
Common Failures
manifest_not_found
You ran a project-scoped command outside a joy project directory.
Fix:
- run
joy initin the current directory, or - run
joy new <name>and move into the created project
Toolchain / Ninja Not Found
Use joy doctor to inspect compiler and ninja availability.
Common fixes:
- install a compiler (
clang++,g++, or MSVC toolchain) - install
ninja - install
cmakeif you use compiled dependencies
Workspace Member Errors
If running from a workspace root, use -p/--workspace-package <member> unless default_member is configured.
Common related codes:
workspace_member_requiredworkspace_member_not_foundworkspace_member_invalid
Dependency Source Validation Errors
If joy add/joy update fails with source-validation style errors:
- verify source-specific argument contract:
registry: requires--versiongit: requires--revarchive: requires--sha256
- verify prefixes are correct (
registry:,git:,path:,archive:) - use
--jsonand inspecterror.code(invalid_add_args,invalid_update_args,invalid_dependency_source)
Registry Configuration / Lookup Failures
If registry flows fail:
- verify registry exists with
joy registry list - ensure expected default registry is set (
joy registry set-default <name>) - ensure scope is correct (
--projectvs user default scope) - re-run in
--jsonmode and inspect codes such as:registry_not_configuredregistry_config_errorregistry_load_failedregistry_package_not_found
VSCode / clangd Cannot Find Dependency Headers
If you see include errors after joy add, verify:
joy syncorjoy buildhas been run after adding dependencies.compile_commands.jsonexists at project root..joy/include/...contains expected dependency headers.
joy writes:
- project root
compile_commands.json - target-specific
.joy/build/compile_commands.<target>.json
Use joy doctor and joy metadata to inspect compile-db and graph artifact state.
clangd
clangd usually auto-discovers compile_commands.json from workspace root.
VSCode C/C++ Extension (cpptools)
If cpptools does not auto-detect the compile database, set C_Cpp.default.compileCommands to project-root compile_commands.json.
Nested Dependencies Missing
If transitive dependencies appear missing:
- rerun
joy syncto refresh lockfile + graph + materialization - run
joy tree/joy why <package> - inspect
joy metadatafor graph/lockfile state
If package metadata digests disagree between sources, expect package_metadata_mismatch until metadata is reconciled.
Offline Cache Misses
If joy --offline ... fails:
joy fetch
joy sync
Then retry offline/frozen commands.
lockfile_not_found (verify / vendor)
joy verify and joy vendor require joy.lock.
Fix:
joy sync
# or
joy sync --update-lock
Verification Failures (verify_failed)
When joy verify fails:
- inspect failing package rows in JSON
data.results - check source provenance fields in
joy.lock - for archive sources, ensure
source_checksum_sha256is present and valid - if vendored source exists, compare against resolved source checksum
Publishing Transport / Auth Failures
If publish workflows fail against remote registry URLs:
- confirm registry URL is reachable and writable
- confirm git credentials/token permissions for push
- inspect JSON error code:
registry_transport_failedregistry_auth_failed
Build Failures
When joy build fails, focus on compiler diagnostics first:
- inspect ninja/compiler stderr/stdout details
- inspect generated build graph and compile DB paths in JSON payload
- use
--jsonfor stable failure envelopes
Reference
This section documents stable command contracts, schemas, machine envelopes, and operational runbooks.
Use this section when you need precise interfaces instead of task-oriented walkthroughs.
Operational runbooks:
Command Reference
This chapter maps shipped joy commands and grouped subcommands.
Use workflow chapters for task-first guidance and this chapter for quick command/flag lookup.
Global Flags
Global flags apply before subcommands:
joy --json <command>
joy --offline <command>
joy --frozen <command>
joy -p <workspace-member> <command>
Human UX controls:
joy --color auto|always|never <command>
joy --progress auto|always|never <command>
joy --glyphs auto|unicode|ascii <command>
Top-Level Commands
Project Scaffolding
joy new <name> [--force]joy init [--force]
Dependency Lifecycle
joy add <package> [--as <name>] [--rev <rev>] [--version <range>] [--registry <name>] [--sha256 <sum>] [--no-sync]joy remove <package>joy update [<package>] [--rev <rev>] [--version <range>] [--registry <name>] [--sha256 <sum>]joy tree [--locked]joy why <package> [--locked]joy outdated [--sources all|registry|github|git|path|archive]
Registry Discovery
joy registry <subcommand>joy search <query> [--registry <name>] [--limit <n>]joy info <package> [--registry <name>]
Dependency State / Integrity
joy fetchjoy vendor [--output <dir>]joy verify [--strict] [--sbom <path>]joy cache gc [--aggressive]joy recipe-check
Publishing + Ownership
joy package init <id> [--version <semver>] [--kind header-only|cmake] [--force]joy publish [--registry <name>] [--rev <rev>] [--source-package <id>]joy owner <subcommand>joy yank <package> --version <semver> [--undo] [--registry <name>]
Build and Execution
joy build [--release] [--target <name>] [--locked] [--update-lock]joy sync [--release] [--locked] [--update-lock]joy run [--release] [--target <name>] [--locked] [--update-lock] [-- <args...>]
Diagnostics and Metadata
joy metadatajoy doctorjoy version
Grouped Subcommands
joy registry
list [--project]add <name> <index> [--default] [--project]remove <name> [--project]set-default <name> [--project]
joy owner
list <package> [--registry <name>]add <package> <owner> [--registry <name>]remove <package> <owner> [--registry <name>]
joy package
init <id> [--version <semver>] [--kind header-only|cmake] [--force]
joy cache
gc [--aggressive]
Minimal Example Sweep
joy new demo
joy add nlohmann/json
joy tree
joy why nlohmann/json
joy registry list
joy search json
joy fetch
joy vendor
joy verify --strict
joy cache gc
joy package init acme/widgets
joy publish --registry internal --rev v0.1.0
joy owner list acme/widgets --registry internal
joy yank acme/widgets --version 0.1.0 --registry internal
joy metadata
joy doctor
joy build
joy sync
joy run -- --help
CLI UX Controls
Status: Shipped (human output controls)
joy has separate human and machine interfaces:
- human mode (default) for local developer experience
- machine mode (
--json/--machine) for automation
Human Output Controls
Global flags:
joy --color auto|always|never ...
joy --progress auto|always|never ...
joy --glyphs auto|unicode|ascii ...
Convenience aliases:
--no-progress(same as--progress=never)--ascii(same as--glyphs=ascii)
Environment Variables
joy also consults environment variables for human output behavior:
JOY_COLORJOY_PROGRESSJOY_GLYPHSNO_COLORCLICOLORCLICOLOR_FORCETERMCI
Compatibility Policy
Human output is allowed to improve over time (layout, colors, wording, progress rendering).
Automation should use --json, which remains the stable interface.
Manifest Schema
joy supports three joy.toml document shapes:
- project manifest (
[project]) - workspace manifest (
[workspace]) - reusable package manifest (
[package])
Source of truth: src/manifest.rs.
Project Manifest
[project]
name = "demo"
version = "0.1.0"
cpp_standard = "c++20"
entry = "src/main.cpp"
extra_sources = ["src/lib.cpp"]
include_dirs = ["include"]
[[project.targets]]
name = "tool"
entry = "src/tool.cpp"
extra_sources = []
include_dirs = []
[dependencies]
"nlohmann/json" = { source = "github", rev = "HEAD" }
Required project fields:
nameversioncpp_standardentry
Optional project fields:
extra_sources(string[])include_dirs(string[])[[project.targets]](named target list)
Workspace Manifest
[workspace]
members = ["apps/app", "tools/tooling"]
default_member = "apps/app"
profile = "release"
Required workspace fields:
members(string[], non-empty)
Optional workspace fields:
default_member(must be present inmembers)profile(dev|release)
Package Manifest
Used for reusable package publishing workflows.
[package]
id = "acme/widgets"
version = "0.1.0"
kind = "header_only"
[headers]
include_roots = ["include"]
[dependencies]
"fmtlib/fmt" = { source = "github", version = "^11" }
Required package fields:
id(canonical package id)versionkind(header_only|cmake)
Optional package fields:
[headers].include_roots- package-level
[dependencies]
Dependency Spec Contract
Each dependency entry is a DependencySpec:
source- optional
package - source-specific fields:
rev,version,registry,git,path,url,sha256
Source Rules
source = "github"
- supports
revorversion(mutually exclusive) - does not allow
registry,git,path,url,sha256
source = "registry"
- requires
version - disallows
rev - optional
registry - does not allow
git,path,url,sha256
source = "git"
- requires
gitandrev - does not support
version - does not allow
registry,path,url,sha256
source = "path"
- requires
path - disallows
revandversion - does not allow
registry,git,url,sha256
source = "archive"
- requires
urlandsha256 - disallows
revandversion - does not allow
registry,git,path
Dependency Prefix Parsing (CLI Input)
Input prefixes map to source backends:
registry:<id>->registrygithub:<id>->githubgit+<url-or-path>orgit:<url-or-path>->gitpath:<relative-or-absolute-path>->patharchive:<url>->archive- no prefix ->
github
Lockfile Schema
joy.lock is a TOML lockfile used for reproducibility and source provenance.
Source of truth: src/lockfile.rs and lockfile assembly logic in src/commands/build.rs.
Top-Level Fields
version = 1
manifest_hash = "<sha256>"
generated_by = "joy <version>"
[[packages]]
...
version: lockfile schema version (currently1)manifest_hash: hash used for stale-lock detectiongenerated_by: generator version stringpackages: resolved package entries
Package Entry Fields
Each [[packages]] entry includes:
- identity and resolution:
idsourcerequested_revrequested_requirement(optional)resolved_version(optional)resolved_commitresolved_ref(optional)
- source provenance:
registry(optional)source_package(optional)source_git(optional)source_path(optional)source_url(optional)source_checksum_sha256(optional, required for archive source)
- dependency/build metadata:
header_onlyheader_roots[]deps[]recipe(optional)metadata_source(optional)package_manifest_digest(optional)declared_deps_source(optional)abi_hashlibs[]linkage(optional)
Source Provenance Expectations
github: no extra provenance field requiredregistry: should includeregistrygit: should includesource_gitpath: should includesource_patharchive: should includesource_urlandsource_checksum_sha256
joy verify enforces source-specific provenance checks and checksum policy.
Lockfile Lifecycle
sync/build/runmay write or refresh lockfile based on lock mode flags.--lockedrejects drift.--update-lockforces refresh.--frozenimplies locked/offline behavior.
Workspace-routed commands use workspace lockfile semantics when invoked from workspace root with selected member routing.
Registry Configuration
joy merges registry config from user scope and optional project scope.
Source of truth: src/registry_config.rs and src/commands/registry_cmd.rs.
Scopes
- user scope (default):
$JOY_HOME/config/registries.toml - project scope (
--project):<project>/.joy/registries.toml
Effective config merge behavior:
- user config loaded first
- project config overlays user entries
- project default overrides user default
File Format
version = 1
default = "internal"
[registries.internal]
index = "file:///srv/joy-index.git"
[registries.default]
index = "https://github.com/harnesslabs/joy-registry.git"
Fields:
version(must be1)default(optional registry name)registries.<name>.index(URL/path)
CLI Management
joy registry list
joy registry add internal file:///srv/joy-index.git --default
joy registry remove internal
joy registry set-default internal
joy registry list --project
joy registry add internal file:///srv/joy-index.git --project --default
Validation Rules
- registry name must be non-empty and
[A-Za-z0-9_.-]only - registry index path/URL must be non-empty
- unsupported config versions fail with
registry_index_unsupported_versionin publishing/index flows or parse/config errors in config loading paths
Related Commands
- discovery:
joy search,joy info - dependency resolution:
joy add registry:<id> --version <range> - publish workflows:
joy publish,joy owner,joy yank
Machine Interface
joy supports machine-readable output for all commands via --json (alias --machine).
JSON output always uses one of two top-level envelopes:
{
"schema_version": "1",
"joy_version": "<semver>",
"ok": true,
"command": "<name>",
"data": { "...": "..." }
}
{
"schema_version": "1",
"joy_version": "<semver>",
"ok": false,
"command": "<name>",
"error": {
"code": "<stable_code>",
"message": "<human_text>"
}
}
Compatibility Policy
- Top-level envelope keys are stable:
schema_version,joy_version,ok,command, plusdataorerror. - Existing payload keys are additive within a fixed
schema_version. schema_versionchanges only for explicit contract revisions.error.codeis the automation key;error.messageis human-oriented and may evolve.- Human output is not a machine contract; automation should use
--json.
Workspace Routing Metadata
Project-scoped command payloads may include additive workspace fields when invoked from workspace root routing:
workspace_root(string | null)workspace_member(string | null)
Build/Run/Sync Target Metadata
build and run include target metadata:
targettarget_default
build, sync, and run include lockfile metadata:
lockfile_pathlockfile_updated
Machine Payload Catalog
See Machine Payload Matrix for command-specific key maps.
Error Code Catalog
See Error Codes for stable machine error keys.
Machine Payload Matrix
This chapter summarizes command-specific JSON payload keys emitted under the machine envelope.
For envelope compatibility policy, see Machine Interface.
Core Project Commands
new
project_rootmanifest_pathcreated_paths
init
project_rootmanifest_pathcreated_paths
add
project_root,manifest_pathdependency,source,registry,source_packagefetched(source fetch metadata when applicable)installed(header install metadata)sync(sync-lite result)
remove
project_root,manifest_pathdependencyheader_link_removedwarnings
update
project_root,manifest_pathupdated_count,manifest_changedupdated[]entries with source/resolve/install metadatawarnings
tree
project_root,manifest_pathroots[]packages[]with source/provenance/dependency edges
why
project_root,manifest_pathpackagelockedroots[],paths[]package_info
outdated
project_root,manifest_path,lockfile_pathroots[]sourcessummary(direct/transitive/source counts)packages[]outdated[]
Registry and Discovery
registry (all subcommands)
action(add|remove|set-default) for mutating subcommandsscopename,index,default_set,removed(as applicable)registries[]anddefaultforlist
search
queryregistrycountpackages[](id,latest_version)
info
registrypackagelatest_versionversions[]
Dependency State, Integrity, and Cache
fetch
project_root,manifest_pathfetched_count,skipped_countfetched[]with source/provenance/cache metadata
vendor
project_root,lockfile_path,output_dirvendored_count,skipped_countvendored[],skipped[]
verify
project_root,lockfile_pathstrictsummary(package_count,passed_count,warning_count,failed_count)results[]sbomsbom_path
cache (gc)
action(gc)aggressiveremoved_paths[]cache_root
recipe-check
recipes_rootrecipe_countpackages[]
Publishing and Ownership
package (init)
action(init)manifest_pathid,version,kind
publish
packageversionregistryindex_pathgit_committed
owner
action(list|add|remove)packageregistryowners[](forlist)changed(for mutation flows)
yank
packageversionregistryyankedchangedindex_path
Build, Run, and Sync
build
project_root,manifest_pathbuild_file,binary_path,source_file,compiled_sources[]target,target_default,profileinclude_dirs[],link_dirs[],link_libs[]compiled_dependencies_built[]toolchainninja_status,ninja_stdout,ninja_stderrlockfile_path,lockfile_updated
sync
project_root,manifest_pathprofileinclude_dirs[],link_dirs[],link_libs[]compiled_dependencies_built[]toolchain(optional)lockfile_path,lockfile_updated
run
project_root,binary_path,build_filetoolchain,profile,target,target_defaultargs[],exit_codestdout,stderrlockfile_path,lockfile_updated
Diagnostics and Metadata
metadata
project_root,manifest_pathroots[]artifacts(joy/state/build/compile-db paths + flags)lockfilegrapheditor_extension_gate
doctor
ok,cwdenv,tools,toolchain,cache,recipesproject,artifacts,lockfile,dependency_metadataeditor_extension_gateproject_warnings[],project_hints[]
version
joy_versionschema_versionbuild_targetbuild_profilegit_commit
Workspace Metadata Note
Project-scoped command payloads can include additive workspace_root and workspace_member keys when invoked from workspace-routed contexts.
Error Codes
joy command failures return machine-readable error codes via JSON envelopes.
{
"ok": false,
"command": "build",
"error": {
"code": "manifest_not_found",
"message": "..."
}
}
Stability Policy
error.codeis the stable automation key.error.messageis human text and may evolve.- New codes may be introduced additively.
Core / CLI
cli_parse_errorcwd_unavailableio_erroroutput_serialize_failednot_implemented
Manifest / Workspace / Package Identity
manifest_not_foundmanifest_parse_errormanifest_write_errormanifest_existsmanifest_hash_failednon_empty_directorypath_existsinvalid_package_idinvalid_package_versioninvalid_targetdependency_not_foundworkspace_member_invalidworkspace_member_requiredworkspace_member_not_found
Dependency Input / Source Validation
invalid_add_argsinvalid_update_argsinvalid_dependency_sourcesource_backend_unsupportedregistry_alias_unsupportedpackage_metadata_mismatchdependency_resolve_failed
Lockfile / Reproducibility
invalid_lock_flagslockfile_not_foundlockfile_missinglockfile_parse_errorlockfile_hash_failedlockfile_stalelockfile_incompletelockfile_mismatchlockfile_write_failedlockfile_package_assembly_failed
Fetch / Network / Registry
fetch_failedoffline_cache_missoffline_network_disabledinvalid_version_requirementversion_not_foundinvalid_checksumchecksum_mismatcharchive_format_unsupportedregistry_not_configuredregistry_load_failedregistry_package_not_foundregistry_config_errorregistry_index_parse_errorregistry_index_serialize_failedregistry_index_unsupported_version
Git / Registry Transport
git_failedregistry_transport_failedregistry_auth_failed
Toolchain / Build / Graph Materialization
toolchain_not_foundtoolchain_probe_failedenv_setup_failedcache_setup_failedrecipe_load_failedrecipe_validation_faileddependency_graph_invalidmissing_recipemissing_cmake_metadatamissing_link_metadatageneric_cmake_no_librariescmake_build_failedlibrary_install_failedheader_install_failedinclude_dir_not_foundentry_not_foundsource_not_foundbuild_failedninja_file_write_failedninja_spawn_failedcompile_db_write_failedstate_index_errorstate_cleanup_failedstate_graph_error
Command Policy / Lifecycle
frozen_disallows_addfrozen_disallows_removefrozen_disallows_updateadd_sync_failedrun_spawn_failedrun_failedpublish_version_existsinvalid_owner
Verify / SBOM / Vendor
verify_failedverify_scan_failedverify_hash_path_missingsbom_serialize_failedvendor_copy_failed
Releasing joy
This chapter documents the release process for joy binaries, GitHub Releases, and release-adjacent notes.
Versioning Policy
joyuses semantic versioning with pre-1.0 expectations (0.y.z).Cargo.tomlis the source of truth for the version.- Git tags use
vX.Y.Z(for examplev0.4.0).
Current Release Targets
The release workflow currently publishes:
x86_64-unknown-linux-gnuaarch64-apple-darwinx86_64-apple-darwinx86_64-pc-windows-msvcx86_64-pc-windows-gnu(compatibility artifact during the beta transition)
Release Workflow
- Release PR + tag automation:
.github/workflows/release-plz.yaml - Binary/release asset workflow:
.github/workflows/release.yaml - Packaging config for release-plz:
release-plz.toml
release-plz handles version/changelog PRs and tag creation.
Tag pushes (v*) trigger the binary release workflow.
Pre-Release Checklist
- Ensure milestone issues and notes are up to date.
- Confirm local environment health (
joy --json doctor). - Run CI-parity commands (
just ci-local; optionally compiled e2e checks). - Validate distribution metadata templates (
just dist-metadata-check). - Confirm PR checks (
gh pr checks <pr-number>). - Ensure
RELEASE_PLZ_PATsecret is configured withcontents+pull_requestswrite permission (RELEASE_PLZ_TOKENis also supported as a fallback name). - If default-branch protection blocks workflow pushes, set
JOY_RELEASE_PATso release metadata commits can updateFormula/joy.rb.
Automated Flow (Recommended)
- Merge regular changes into
main. release-plzopens/updates a release PR with version and changelog updates.- Merge the release PR.
release-plz releasecreatesvX.Y.Ztag..github/workflows/release.yamlbuilds artifacts, publishes GitHub Release assets, and updates package metadata.
Monitor Actions and verify the GitHub Release contains archives/checksums/signatures/SBOM.
Manual Backstop (If Needed)
git tag -a vX.Y.Z -m "joy vX.Y.Z"
git push origin vX.Y.Z
Packaging Outputs
The release workflow generates and publishes concrete metadata with release checksums:
Formula/joy.rb(single-repo Homebrew tap source of truth)packaging/scoop/joy.json
Users can install via Homebrew tap:
brew tap harnesslabs/joy
brew install harnesslabs/joy/joy
brew upgrade joy
Incident Response Runbook
This runbook covers high-priority operational incidents for joy release consumers.
Severity Guidelines
SEV-1: active supply-chain risk (malicious dependency, compromised release artifact)SEV-2: broken release affecting installs/builds broadlySEV-3: localized issue with workaround
Scenario A: Compromised Dependency
- Freeze releases immediately.
- Identify affected versions and package IDs.
- Remove/disable affected dependency source in registry metadata.
- Publish a patched release and changelog/security advisory.
- Notify users with explicit upgrade/rollback instructions.
Scenario B: Bad Release Artifact
- Mark the release as yanked in release notes.
- Repoint package-manager channels (Homebrew/Scoop metadata) to the prior safe release.
- Publish fixed artifacts under a new version tag.
- Verify checksums/signatures and smoke test install paths.
Rollback Drill (Per Release)
Perform a rollback drill once per release cycle:
- Simulate a bad release in a staging repository.
- Execute package-manager metadata rollback.
- Confirm install commands resolve to the prior known-good version.
- Record elapsed time and gaps in the release notes archive.
Communication Checklist
- Open internal incident tracker entry.
- Publish public status update within 24 hours for SEV-1/SEV-2.
- Update
SECURITY.mdif policy/process changes were required.
Project Status
This section tracks the current implementation boundary for joy and clearly separates shipped behavior from deferred/planned work.
Snapshot date for this status section: March 6, 2026.
How to Read This Section
Shipped: available onmainand expected to work todayPlanned: intended near-term work but not yet guaranteed shippedDeferred: intentionally out of current implementation scope
See Roadmap / Deferred Features for current non-shipped scope.
Roadmap / Deferred Features
Status entries below are intentionally explicit so users know what is not ready yet.
Snapshot date: March 6, 2026.
Planned (Near-Term, Not Fully Closed)
- Additional offline CI matrix hardening for cold/warm/vendored permutations and deterministic error-path coverage.
- Further hardening of self-hosted publishing auth/token policy and transport reliability for non-local registry deployments.
- Continued source/backend parity hardening in resolver/fetch edge-case paths beyond current shipped baseline.
Deferred (Known, Expected Future Work)
- Broader registry protocols beyond current git-backed index mode.
- Registry alias package support (registry name different from canonical source package id).
- Deeper package feature/variant support and additional non-binary target kinds.
- Full-screen TUI mode (current roadmap remains focused on line-oriented CLI and machine JSON interfaces).
- Editor extension productization remains gated behind objective CLI/compile-db criteria; CLI-first remains default.
Documentation Notes
Roadmap intent may appear in docs where relevant. Planned/deferred items are never implied as shipped behavior.
Contributing Docs
This chapter is for contributors touching user-facing documentation.
Source of Truth
README.mdis the project overview and entrypoint.book/is the in-depth user and reference documentation.docs/contains legacy entrypoints/stubs that should point to the mdBook.
Writing Guidelines
- Prefer task-oriented explanations first, then reference detail.
- Mark incomplete/deferred features explicitly.
- Keep command examples copy/paste ready.
- When human output examples are likely to change, avoid over-specifying exact formatting unless the formatting itself is the subject.
Validation
Use local docs commands (defined in justfile) before opening a PR:
just docs-buildjust docs-lint