Here is the complete product specification:
justInferred from source review, documentation, tests, and CI configuration of casey/just. Statements reflect observed behavior and public documentation, not author claims.
Developers on any project accumulate a collection of commands they run repeatedly: building, testing, linting, deploying, seeding databases, resetting environments. These commands are long, easy to mistype, and differ between team members because they live in personal notes, shell history, or READMEs that quickly go stale.
make is the traditional solution, but it was designed as a build system, not a command runner. Using it for general task automation forces developers to work around its file-timestamp model, .PHONY declarations, tab-only indentation, and unintuitive variable scoping.
just solves this by providing a dedicated command runner: a single, portable tool that reads a justfile in the project directory, validates the task graph before running anything, and executes named recipes reliably from any subdirectory. It makes project-level commands first-class, reproducible, and discoverable.
Without just |
With just |
|---|---|
| Commands live in personal notes or READMEs and drift | Commands are versioned in the project repo alongside code |
| Developers must remember long, fragile shell invocations | Short recipe names invoke complex commands reliably |
| Errors discovered mid-execution after partial side effects | Recipe graph validated before any command runs |
| Onboarding requires reading prose docs to find commands | just --list reveals all available commands instantly |
| make workarounds required for non-build tasks | A purpose-built runner with no build-system impedance |
| Platform differences cause silent breakage | Cross-platform recipe syntax with explicit OS conditions |
The system allows a developer to define named recipes in a justfile and invoke them by name from the command line. A recipe is a named, ordered sequence of shell commands. Recipes may depend on other recipes. The system executes the full dependency graph in declaration order, deduplicating recipes that appear multiple times.
Recipes accept named parameters with optional defaults. Parameters may be required or variadic (accepting one or more, or zero or more values). Arguments are passed positionally on the command line after the recipe name. The system makes parameters available as interpolations within recipe commands and, optionally, as environment variables.
The justfile supports named variables whose values are string literals, shell command outputs (evaluated at load time via backtick expressions), or computed expressions using built-in functions. Variables may be exported to the shell environment of all recipe commands. Variable values can be overridden at invocation time via CLI flags or environment variables.
Before running any commands, the system validates the full recipe graph: it detects undefined recipes, circular dependencies, missing required parameters, and unknown identifiers. If validation fails, no commands run. This prevents partial execution side effects from misconfigured justfiles.
The system can list all available (non-private) recipes with their parameters and doc comments. Recipes can be grouped and filtered. The listing can be rendered as human-readable text or as structured JSON for tooling consumption. Private recipes (prefixed with _ or marked with an attribute) are hidden from listings by default.
A developer can invoke multiple recipes in a single just command. Each is executed in the order specified. Recipes are deduplicated across the full invocation: the same recipe with the same arguments runs only once.
The system operates on Linux, macOS, Windows, and BSD platforms. Recipes can be conditioned on the operating system via attributes, so a single justfile can encode platform-specific variants of a command. The path-join operator always uses forward slashes regardless of host platform.
A justfile can include other justfile modules by name. Each module has its own isolated namespace for variables and recipes. Recipes from modules are invoked using a module::recipe path syntax. Modules may be optional (no error if the file is absent).
The system supports configuring the shell used to execute recipes (interpreter and flags). It can automatically load a .env file and inject its contents as environment variables before recipe execution. The search path for the .env file is configurable.
The system provides an interactive recipe chooser (backed by a configurable fuzzy-finder) for exploratory use. Recipes can require confirmation before executing, with a customizable prompt. Dry-run mode prints all commands that would execute without running them.
The system can reformat a justfile to canonical style in place, or verify that an existing file is already canonically formatted (for use in CI). It can open the justfile in the user's configured editor. It can initialize a new justfile with a starter template.
The system can emit completion scripts for common shells, enabling tab-completion of recipe names and flags in the developer's terminal.
The system provides a library of pure functions available in justfile expressions, covering: string manipulation, path decomposition, environment inspection, hashing, UUID generation, date/time formatting, OS detection, filesystem queries, and terminal color/style sequences.
When invoked from a subdirectory, the system ascends the directory tree to find the nearest justfile, allowing recipes to be run from anywhere within a project. The search can be bounded to prevent ascending above a specified ceiling directory.
A developer can maintain a personal justfile at a fixed location and invoke it from anywhere using a flag, providing a personal command library independent of any project.
just <recipe> runs all dependencies of that recipe first, then the recipe itself.--set VAR VALUE or VAR=value before just take precedence over justfile variable defaults.just itself go to stderr.0 when all requested recipes complete successfully.just --dry-run <recipe> prints every command that would execute, including those in dependencies, without running any of them.just --list prints all non-private recipes, their parameters, and any doc comment. Output is alphabetically sorted by default.just --list --unsorted preserves source order.just --json produces a machine-readable JSON representation of the justfile structure.justfile, Justfile, or .justfile.--justfile is specified, that exact file is used and no search is performed.just with no recipe name runs the first recipe in the justfile, or the recipe explicitly marked as default.--yes is not passed), the recipe does not run..env file before executing any recipes..env values (configurable).module::recipe or just module recipe on the command line.just --fmt --check exits 0 if the justfile is already canonically formatted, 1 if it would be changed by formatting..env file: When dotenv loading is enabled without an explicit path, a missing .env is silently ignored. With an explicit path configured, a missing file is an error.+ variadic requires at least one argument; * allows zero. Passing zero arguments to a + variadic is an error reported before execution.{{ in recipe output, use {{{{. A single {{ always begins an interpolation.--working-directory without --justfile: The working directory flag requires an explicit justfile path and cannot be combined with automatic discovery.just do not need to install a language runtime or SDK. The tool ships as a self-contained executable.just does not track file modification times, perform incremental compilation, or implement pattern rules. It does not replace make, cmake, ninja, or similar tools for compiled artifacts.just does not download, install, or manage software packages. Recipes may invoke package managers, but just provides no dependency resolution.just maintains no run database, result cache, or artifact store. Each invocation is stateless with respect to prior runs.just does not monitor the filesystem for changes and re-run recipes automatically.just runs recipes and exits. It does not manage long-running services, provide restart semantics, or act as a daemon supervisor.just applies no capability restrictions or secret masking beyond what the configured shell provides.just has no SSH, container, or remote execution model. All commands run on the local machine.just does not parse or execute Makefiles and does not aim to be a drop-in replacement for make.The following observations describe internal mechanisms rather than product-level promises. They belong in a technical or interface spec, not a product spec:
src/ module decomposition (lexer, parser, compiler, evaluator, executor): Directory structure. Not a product capability.clap for CLI argument parsing: Library choice. The product promise is "the CLI accepts the documented flags and subcommands."fzf as the default chooser binary: A configurable default, not a product-level promise. The product promise is "an interactive recipe chooser is available and the backend program is configurable."mdbook for documentation generation: Operational/toolchain detail.setsid / process group management: Signal-handling mechanism. The product promise is "when interrupted, the tool exits cleanly and non-zero."strftime delegation in datetime(): That the format string follows strftime conventions is an interface contract (part of the function signature). That it delegates to a C library is implementation leakage.sha256 and blake3 as built-in function names: These algorithm names are part of the public API surface and belong in an interface spec. The choice to implement them in Rust (vs. shelling out) is implementation leakage.mdbook translations (EN/ZH): Operational toolchain detail for documentation, not a product capability of just itself.