Problem
Script recipes that share common setup — precondition checks, environment activation, shell options — must repeat those lines verbatim in every recipe. In projects with 10+ recipes this becomes a maintenance burden and a source of drift.
[script]
api:
set -euo pipefail
just require-env
just require-venv
. backend/api/.venv/bin/activate
fastapi dev backend/api/main.py
[script]
sync product:
set -euo pipefail
just require-env
just require-venv
. backend/api/.venv/bin/activate
python -m backend.collector.runner sync "$1"
Existing features don't solve this: dependencies run in separate shells (so source/export don't carry through), set script-interpreter can't inject arbitrary lines, and multi-line variable interpolation doesn't compose well and lacks editor support.
Proposal
A [preamble("recipe-name")] attribute that prepends a recipe's body to the current recipe's script before execution:
[private, script]
setup-python:
set -euo pipefail
just require-env
just require-venv
. backend/api/.venv/bin/activate
[preamble("setup-python")]
[script]
api:
fastapi dev backend/api/main.py
[preamble("setup-python")]
[script]
sync product:
python -m backend.collector.runner sync "{{ product }}"
When just api runs, the effective script is setup-python's body + api's body concatenated and executed as one script. Multiple preambles compose in order: [preamble("setup-python", "require-pyyaml")].
The mechanism is intentionally simple — textual prepend, no new shell semantics. Because it runs in the same shell, source, export, cd, and variable assignments carry through naturally.
Alternatives considered
- Multi-line variable interpolation (
{{ preamble }}) — works today but doesn't compose, no editor support inside strings, still repeated per recipe
- Wrapper recipe pattern (
_with-python *args) — splits every recipe into wrapper + inner, defeats just's simplicity
set script-interpreter with a wrapper script — moves complexity outside the justfile, loses visibility
wdyt
I'd love feedback before investing in an implementation. Happy to draft an implementation if there's interest.
Problem
Script recipes that share common setup — precondition checks, environment activation, shell options — must repeat those lines verbatim in every recipe. In projects with 10+ recipes this becomes a maintenance burden and a source of drift.
Existing features don't solve this: dependencies run in separate shells (so
source/exportdon't carry through),set script-interpretercan't inject arbitrary lines, and multi-line variable interpolation doesn't compose well and lacks editor support.Proposal
A
[preamble("recipe-name")]attribute that prepends a recipe's body to the current recipe's script before execution:When
just apiruns, the effective script issetup-python's body +api's body concatenated and executed as one script. Multiple preambles compose in order:[preamble("setup-python", "require-pyyaml")].The mechanism is intentionally simple — textual prepend, no new shell semantics. Because it runs in the same shell,
source,export,cd, and variable assignments carry through naturally.Alternatives considered
{{ preamble }}) — works today but doesn't compose, no editor support inside strings, still repeated per recipe_with-python *args) — splits every recipe into wrapper + inner, defeatsjust's simplicityset script-interpreterwith a wrapper script — moves complexity outside the justfile, loses visibilitywdyt
I'd love feedback before investing in an implementation. Happy to draft an implementation if there's interest.