Skip to main content

First Steps

A tour from a fresh clone to running project tools, and then the three commands worth knowing.

How examples are written

Examples throughout this manual call tools by bare name, envy sync and cmake --version, which assumes the shell hook is installed. The hook puts the project's bin directory on PATH while you are inside the project.

Without the hook, every one of those commands still works with the bin directory in front: ./bin/envy sync and ./bin/cmake --version on macOS and Linux, bin\envy.bat sync and bin\cmake.bat --version on Windows. That is the form CI jobs use, since no interactive shell is involved.

Run a tool​

In a project that is already set up, there is nothing to do first:

$ git clone https://github.com/acme/firmware && cd firmware
$ cmake --version
[envy.cmake@r0] installed (8.2s)
cmake version 4.4.0

That one line of install output is the whole setup. bin/cmake is a committed wrapper, it asked bin/envy for cmake's path, bin/envy downloaded the pinned envy, and envy installed cmake. The second call prints only cmake's own output.

Only what that tool needed was installed, not the whole manifest. See Installation.

Install everything at once​

When on-demand is not what you want, install fills the cache and stops there:

$ envy install
[envy.cmake@r0] installed (8.2s)
[envy.ninja@r0] installed (1.1s)
[envy.python@r1] installed (31.4s)

One line per package. Reach for it before going offline, and in CI when you want the job to fail at install rather than mid-compile.

sync is the same thing plus the bin directory, so it adds a summary line when the bin directory changed:

$ envy sync
deploy: 12 product script(s) (1 created, 0 updated, 11 unchanged, 0 removed)

Run that one after editing the manifest, which is when a wrapper has to be written or pruned. Both are idempotent and incremental, and running either again installs nothing.

Run it a second time and it prints nothing:

$ envy sync
$

That means it succeeded. A package prints a line only if it did something, and the deploy summary appears only when a wrapper was written or pruned, so a project that is already correct has nothing to report. Redirect the output to a file and every package prints its outcome again, which is what keeps CI logs complete. See a run with no work is silent.

The three verbs​

They are not synonyms.

CommandPackagesBin directory
envy installinstallsuntouched
envy deployuntouchedwritten, refreshed, pruned
envy syncinstallswritten, refreshed, pruned

install is for warming a cache without touching the work tree, which is what you want in a Docker layer, a CI cache step, or anything you would rather not see in git status. deploy is for restoring a bin directory you cleaned, or picking up a product a spec just added, without reinstalling anything. sync is for a manifest edit, when both halves apply.

The bin directory is the whole distinction. A wrapper resolves its package at call time, so a version bump, a cache wipe, or a switch to a project-local cache changes nothing about the wrappers and needs no sync. Adding, removing, or renaming a product does.

Three ways to run project tools​

  1. The wrappers. cmake. Committed, zero setup, works in any shell and in CI. See Product Scripts.
  2. envy run. envy run make -j puts the bin directory on PATH for one command and sets ENVY_PROJECT_ROOT. Good for scripts, git hooks, and CI.
  3. Shell integration. cd into the project and its tools are on PATH until you leave.

All three reach the same packages. Pick by context rather than by preference: wrappers and envy run are deterministic anywhere, hooks are for interactive work.

Asking envy questions​

$ envy product # every product, and who provides it
cmake bin/cmake envy.cmake@r0{["version"]="4.4.0"}
ctest bin/ctest envy.cmake@r0{["version"]="4.4.0"}
python3 bin/python3 envy.python@r1{["version"]="3.13.14"}

$ envy product cmake # one product, resolved
/Users/you/Library/Caches/envy/packages/envy.cmake@r0/darwin-arm64-blake3-49a9b2620de8c380/pkg/bin/cmake

$ envy package envy.cmake@r0 # the package's whole tree
/Users/you/Library/Caches/envy/packages/envy.cmake@r0/darwin-arm64-blake3-49a9b2620de8c380/pkg

$ envy cache # what is on disk, largest first
Cache: /Users/you/Library/Caches/envy
...

envy product <name> installs the provider if it is missing, so it doubles as "install just this one thing".

Working on a subset​

Queries select manifest entries by identity:

envy install envy.cmake@r0 # this entry and its dependencies
envy install python # matches any namespace and revision

See query forms. Prefer install while iterating. A filtered sync prunes wrappers outside the filtered subgraph, so if you do use one, follow it with a bare sync when you are done.

What is safe​

  • Deleting the cache. Everything in it is reconstructible. rm -rf is the supported cleanup tool.
  • Running sync repeatedly. It is incremental, and a no-op when nothing changed.
  • Interrupting a run. A partial install is never marked complete, so the next run redoes it. Verified downloads survive, so the retry is cheaper.

Next​