Setup recipes
How the optional .bowlinesetup file prepares a freshly synced project to run when it becomes hot on a new machine or agent.
A Setup Recipe is an optional .bowlinesetup file that records the
project-owned commands needed to make a project runnable after it becomes hot on
a fresh machine or agent. Syncing the files is not enough on its own:
dependencies still need restoring. A Setup Recipe closes the gap between "the
code is here" and pnpm dev works.
A Setup Recipe is not sync policy. It never runs merely because files synced, and it does not decide which files travel with your workspace. That job belongs to path policy.
What a recipe looks like
A .bowlinesetup file is line-based and project-owned. Each non-empty line is a
command, blank lines and # comments are ignored, and Bowline never writes or
edits the file for you.
# .bowlinesetup: prepare this project after it becomes hot.
pnpm install --frozen-lockfile
pnpm db:migrate
pnpm buildCommands run sequentially from the directory that contains the recipe, and setup stops at the first failure. A recipe applies to its own directory subtree, so a monorepo can place recipes where they belong.
When setup runs
Setup is hot-triggered, not sync-triggered. A project becomes hot when you
explicitly prepare it with bowline setup <path>.
Bowline runs the recipe only then. It does not run setup during background sync, plain machine setup, or remote manifest import. Seeing the files arrive is never enough to execute commands.
Important
A setup recipe runs commands on your machine or agent host. Bowline confines execution to paths under the accepted workspace root and redacts command output, but the commands themselves are whatever the project author wrote. Approval gates protect you when a recipe arrives or changes through sync.
Inferred setup without a recipe
Most projects do not need a .bowlinesetup. When none exists for a subtree,
Bowline can infer a safe, lockfile-backed dependency restore for common
ecosystems.
| Ecosystem | Detected lockfile |
|---|---|
| pnpm | pnpm-lock.yaml |
| npm | package-lock.json |
| Bun | bun.lock and bun.lockb |
| uv | uv.lock |
| Cargo | Cargo.lock |
| Go modules | go.sum |
For each, Bowline runs a conservative, lockfile-pinned restore. Inference is deliberately narrow:
- It uses no-lifecycle-script install modes where the package manager supports them.
- A restore that would run package lifecycle hooks, for example
preinstallorpostinstall, requires your approval before it runs. - It never runs unknown project scripts. Anything beyond dependency restore
needs an explicit
.bowlinesetup.
A recipe beats inference: when a .bowlinesetup exists for a subtree, it is
authoritative there and Bowline does not infer.
Approving synced recipes
Because a recipe is just a project file, it can arrive or change through sync. Bowline does not run an unapproved recipe on the receiving machine.
The first time a machine or agent sees a recipe, or whenever its contents
change, Bowline records the new recipe hash and raises an approval-required
state instead of executing. You approve it once, locally, through the CLI, TUI,
or status surface, for example bowline setup --yes. Approval binds the recipe hash, the source
and approving devices, the working directory, and the trigger.
Setup receipts
Every setup run records a setup receipt so reruns are idempotent and explainable. A receipt captures enough identity to know whether setup is still valid: the recipe hash, relevant lockfile and toolchain hashes, the package-manager identity, the env profile, the OS and architecture, the trigger, command exit state, a timestamp, and a redacted output summary.
Bowline never stores raw env values or full secrets in a receipt; full logs are
kept outside the workspace with owner-only permissions. Because receipts are
hash-based, a second bowline setup on an unchanged project is a fast no-op.
Changing the recipe, a lockfile, the toolchain, the package manager, the OS, the
architecture, or the env profile invalidates the receipt, and setup runs again.
Generated output stays local
Setup creates dependency and build folders, and those stay on the machine that
made them. node_modules, .venv, target, .next, and caches are
local-regenerate or cache state. Setup can create them, but they never become
canonical workspace state, never sync across machines, and deleting one never
creates a conflict. See Path policy for how
Bowline classifies these paths.
Running setup
One command drives project setup under the accepted workspace root.
| Command | What it does |
|---|---|
bowline setup [path] [--yes] | Makes the project hot, runs its recipe or inferred restore, and reports the receipts. --yes approves a first-seen or changed recipe hash. |
Add --json for machine-readable output. Use
bowline status --root ~/Code --project <path> to inspect setup state — for
example, whether node_modules is in its expected local-regenerate state and
which receipt created it.
Zero-setup machines and agents
A Setup Recipe makes a project usable on a fresh machine or agent without manual work. Combined with env sync and materialize-by- default file sync, an approved recipe means a coding agent lands in a real project directory with dependencies restored and env in place, ready to run the project's commands with no manual materialization, secret grant, or config step.
Next steps
- Env sync: how
.envfiles follow your code. - Path policy: control which files sync, and keep generated folders local.
- Coding agents: how agents work in a prepared project.
- Working with agents: hand work to an agent in a ready-to-run project.
- CLI commands: full reference for
bowline setup.