Skip to content

Feature request: [preamble] attribute for injecting shared setup code into script recipes #3323

@jangel97

Description

@jangel97

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions