September 27, 2025·6 min read·engineeringfishpromptsscriptingterminals

fish 4.1 gives prompts a final rendering phase

fish 4.1 can redraw a prompt before executing the command line. Its final-rendering argument separates the active editing prompt from the prompt retained in the terminal transcript.

A prompt useful while composing a command can occupy too much space after the command has run. Working-directory and repository information help during editing, but repeating the same large prompt throughout terminal scrollback makes earlier commands harder to scan. fish 4.1, released on September 27, adds native transient prompts. It gives the prompt function an explicit final-rendering phase before command execution.

I like fish for its interactive defaults and its programmable editing environment. Native support for this distinction fits that preference. The shell knows when editing is about to finish, so it can communicate that moment to the prompt without asking a custom binding to reconstruct the editor's execution sequence.

The prompt can distinguish two rendering contexts

The released prompt documentation describes the interface. When fish_transient_prompt is set to 1, fish calls fish_prompt --final-rendering before executing the command line. The function can inspect the argument and emit a shorter representation for that final redraw.

A small prompt can express both forms in one function. This example keeps the working-directory display during editing and retains a shorter prompt when the command is submitted.

set -g fish_transient_prompt 1

function fish_prompt
    if contains -- --final-rendering $argv
        printf '> '
    else
        printf '%s > ' (prompt_pwd)
    end
end

The opt-in variable and the function's behavior have different jobs. Setting the variable requests the additional phase. The function decides what to show in that phase. Enabling the variable without making the prompt respond to the argument does not inherently define a shorter prompt, because the shell cannot infer which part of an arbitrary function's output is dispensable.

The flag also gives the existing prompt a useful compatibility path. A function can retain its normal behavior when the argument is absent, while adding a branch for the new phase. There is no need for a second unrelated implementation to reproduce the normal prompt's shared decisions.

The prompt reference also states that commands inside fish_prompt do not change the outer value of status. This matters when a prompt displays the preceding command's outcome. Its own formatting commands should not become the outcome the user sees. The final-rendering phase adds another invocation of the prompt function, so keeping that status boundary explicit remains useful when extending an existing prompt.

The discussion separated the trigger from the output

The transient-prompt proposal initially considered dedicated transient prompt functions. Review identified that such functions would combine two responsibilities, requesting a final redraw and generating its contents. The discussion proposed a separate boolean setting and an argument to the existing prompt function.

That history explains the resulting interface better than describing the feature only as shorter scrollback. The shell supplies a rendering context, and the prompt supplies presentation for that context. The argument is information about when the function is running. It does not require the prompt to replace the command editor's execution binding.

The discussion also documents the difficulty of performing the final redraw indirectly through pre-execution behavior. Rendering has ordering requirements around the reader's own repaint sequence. A prompt customization that attempts to reproduce those requirements independently can miss cases that the editor already handles. Putting the phase in the reader gives the customization a defined place in that sequence.

The transcript and the editing display serve different purposes

The final-rendering interface permits a detailed active prompt while retaining compact command context afterward. That is a presentation change, not a modification to the command's text or its external effect. A shorter prompt should not be interpreted as a summarized execution result, because the redraw occurs before the command runs.

This distinction matters for prompt content. Information needed to understand a completed command's context may still belong in the final form. Removing all location information can save space while making a transcript harder to interpret across directory changes. The interface supplies a choice, but the prompt author still needs to decide which contextual information should remain visible.

The 4.1 reader source connects transient behavior to command-line rendering before execution. That places the final prompt at an editing boundary. It should not be used as evidence that a command succeeded or as a substitute for the command's eventual status. The useful guarantee is about when the display changes.

Braces provide another spelling for a compound command

The release also adds brace-delimited compound commands. The begin reference presents the brace form alongside begin and end. A block creates a local scope and allows redirection of a group of commands. It executes unconditionally.

{
    printf '%s\n' 'first line'
    printf '%s\n' 'second line'
} > output.txt

The example redirects both commands' output through the block. The shorter spelling is useful when grouping is the primary purpose and a full conditional structure would obscure that intention. It does not make fish a POSIX shell or turn the grouped commands into a separate shell language.

The version-pinned changelog records the corresponding syntax incompatibility. Forms such as {echo,echo} are no longer interpreted as brace expansion tokens. That means the new grammar has consequences for existing input at the same syntactic position. A familiar brace shape from another shell is insufficient evidence of equivalent parsing in fish.

Terminal behavior becomes less dependent on terminfo

The new terminal compatibility documentation lists the control sequences fish expects terminals to support. It includes a primary-device-attribute query and specifies the response the terminal must provide. A missing response produces a startup pause and warning, rather than silently proving that the terminal lacks every relevant capability.

This makes the protocol relationship more visible. Prompt rendering depends on moving the cursor and clearing parts of the display, as well as printing characters. A transient prompt redraw uses that same relationship between fish's model of the display and the terminal's actual state. Terminal behavior remains an input to the interactive experience, even when the prompt function itself is simple.

The release notes also describe moving away from reading the terminfo database and removing terminfo-style names from bind. This is a separate change from transient prompts, but it affects how the shell determines terminal behavior. Configuration relying on the old naming path needs to use the shell's supported key names rather than assuming that a terminfo identifier remains accepted.

Embedded builds change how supporting files are accessed

The 4.1 build documentation describes reading embedded supporting data directly from the executable. Some facilities extract temporary files on demand. This changes the self-installing approach introduced in 4.0, which required an extraction step on interactive startup.

The consequence is practical for functions that assume every built-in script has a stable installed path. An embedded build can provide the same function without a meaningful data directory containing a separate copy of that file. The documentation supplies status list-files and status get-file for inspecting embedded content when that is necessary.

The example illustrates inspection without assuming an installation directory. It asks fish for the embedded or available supporting file through its own interface.

status get-file functions/fish_prompt.fish

This is a useful distribution boundary to keep explicit. A package installed through the normal prefix-based route and an embedded executable can provide the same shell facilities through different storage layouts. Customization based on the public function behavior is less dependent on that layout than customization that reaches into an internal data path.

Argument parsing also exposes more intent

The 4.1 argparse reference documents separating parsed options from remaining arguments through argv_opts, alongside controls for unknown options and stricter long-option handling. These facilities matter to shell functions that wrap another command. A wrapper needs to distinguish its own options from the arguments it intends to pass onward.

That is another instance of making an implicit distinction explicit. The prompt receives a rendering phase, while an argument parser gives a wrapper structured information about what it consumed. Both reduce the amount of context a function must reconstruct from incidental behavior.

My preference is to keep custom shell functions small enough that their interaction with fish remains evident. The transient-prompt flag supports that by giving an existing function one additional context to handle. A detailed editing prompt and a compact final prompt can share the same implementation, with the reader responsible for calling it at the appropriate moment.