Docs

The settings file

Every new workspace is a git worktree: Bloom creates a branch from the project's default branch, unless you pick another, and checks it out in a folder under ~/bloom. That checkout is clean, so it has nothing git ignores, such as .env, installed dependencies or a database. .bloom/settings.toml tells Bloom how to fill that gap, what to run while you work and what to clean up when you archive. Every key is optional, and committing the file gives your whole team the same setup.

TOML is a plain-text configuration format. It is made of key = value pairs grouped under [section] headers. The full syntax is on toml.io. In the example below, Bloom copies .env and auth.json before it runs the setup script.

.bloom/settings.toml
# Copies these files, which git ignores, into every new workspace.
file_include_globs = [".env", "auth.json"]

[scripts]
setup_file = ".bloom/setup.sh"

[scripts.run.vite]
name = "Vite"
command = "npm run dev"
autostart = true  # Bloom asks you to approve this once per project.

[browser]
url = "http://localhost:$BLOOM_PORT/admin"

You can also edit the file in File › Project Settings. When that window saves, it rewrites only the lines of the key you changed, so your comments and the order of your keys stay as you wrote them.

Where settings live#

Bloom reads the following files in this order, and a key in a later file overrides the same key in an earlier one.

~/.bloom/settings.toml
This file holds your own defaults and applies to every project on your Mac.
.bloom/settings.toml
This file holds the project's settings for your whole team, so commit it to the repository.
.bloom/settings.local.toml
This file holds your personal overrides for one project, so keep it out of git.

When Bloom saves project settings and the .bloom folder has no .gitignore yet, it adds one that ignores settings.local.toml and *.local.sh.

Bloom reads the two project files from the project folder you added, so a change you save there applies to the next workspace you create, whether or not you have committed it.

Bloom also reads .conductor/settings.toml, .conductor/settings.local.toml and ~/.conductor/settings.toml. Each one is read immediately before its .bloom counterpart, so the .bloom file wins when both set the same key. Bloom only ever writes to the .bloom files.

Scripts#

Setup script#

.bloom/settings.toml
[scripts]
setup_file = ".bloom/setup.sh"

Bloom runs this script in the new workspace's folder when it creates the workspace. The path is relative to the project folder.

If the file is executable and starts with a shebang such as #!/usr/bin/env bash, Bloom runs it directly. Otherwise Bloom runs the file's contents with zsh. In both cases the script runs without an interactive shell.

To put a short command in the settings file itself, use setup = "composer install" instead. If both keys are set, setup_file wins. When a setup fails, fix the script and choose Workspace › Run Setup Again. The Laravel answer in the FAQ contains a complete setup script.

Archive script#

.bloom/settings.toml
[scripts]
archive_file = ".bloom/archive.sh"

Bloom runs this script in the workspace's folder when you archive the workspace, before it removes the worktree. Use it to remove what the setup script created, such as the workspace's database.

If the script fails or runs for longer than ten minutes, the archive stops and the worktree stays where it is. As with setup, archive = "..." sets an inline command instead of a file.

Script variables#

Setup scripts, archive scripts and every terminal tab, including a run script's tab, get these environment variables.

BLOOM_ROOT_PATH
This is the path of the project folder you added to Bloom.
BLOOM_WORKSPACE_PATH
This is the path of the workspace's own folder.
BLOOM_WORKSPACE_NAME
This is the workspace's branch name with slashes turned into dashes. It is unique within one project, but two projects can have workspaces with the same name.
BLOOM_PROJECT_NAME
This is the project folder's name, with every character other than a letter or digit turned into an underscore, so you can use it in a database name.
BLOOM_WORKSPACE_ID
This is an ID that is unique to the workspace.
BLOOM_DEFAULT_BRANCH
This is the name of the project's default branch.
BLOOM_PORT
This is the first of a block of ten ports that Bloom reserves for the workspace.
BLOOM_URL_FILE
This is a file that a script can write an address to, as described under Browser address.
BLOOM_IS_LOCAL
This variable is always set to 1.

Each variable is also set with a CONDUCTOR_ prefix, so scripts written for Conductor keep working.

Files to copy#

.bloom/settings.toml
file_include_globs = [".env*", "auth.json"]

Bloom copies the files that match these patterns from the project folder into each new workspace. Git doesn't check out ignored files, so this is how a workspace gets its .env. The patterns are relative to the project folder, and the default is .env*.

Bloom skips folders and leaves files that already exist in the workspace alone, and an empty list copies nothing. Put this key above the first [section] line of the file, because TOML otherwise reads it as part of that section.

Run scripts#

.bloom/settings.toml
[scripts.run.vite]
name = "Vite"
command = "yarn dev"
icon = "bolt"        # Shows this SF Symbol in the menu and on the tab (optional).
autostart = true     # Starts the script when the workspace opens (optional).

[scripts.run.seed]
name = "Seed Database"
command = "php artisan migrate:fresh --seed"

Each table under scripts.run needs a name and a command. The scripts appear under Run Scripts in the tab strip's + menu, in the order they have in the file, and icon accepts any SF Symbol name.

The project's run scripts appear under Run Scripts in the + menu.

Running a script#

When you pick a script, Bloom opens a terminal tab named after it in the workspace's folder and types the command into your login shell. That is the same shell any terminal tab gets, with the script variables set. If the script is already running, Bloom switches to its tab instead of starting a second copy.

When the command stops, its tab stays open with the output, and a strip above the shell offers Run Again and Close Tab.

Vite and Horizon are still running, and Seed Database has stopped.

After a relaunch#

A tab whose script was running when Bloom quit shows Was running here and a Start button. Autostart scripts are the only ones that start again without a click.

After a relaunch, the Vite tab waits for you to click Start.

Autostart#

With autostart = true, the script starts when the workspace opens. The first time, Bloom lists the project's autostart commands and asks you to approve them, and it asks again whenever a pull changes any of those commands.

Entries Bloom can't read#

Bloom skips an entry that is missing its name or command, has a value of the wrong type, or repeats another script's name, and it shows a notice that names the entry. The rest of the file still loads.

Bloom asks before it autostarts scripts, and it names the entry it skipped.

Browser address#

.bloom/settings.toml
[browser]
url = "http://localhost:$BLOOM_PORT/admin"

A new browser tab in a workspace opens on this address, and the default is http://localhost:$BLOOM_PORT. Bloom expands script variables such as $BLOOM_PORT and ${BLOOM_WORKSPACE_NAME}, and it adds http:// when the address has no scheme.

The browser tab opens on the address from browser.url, with the port filled in.

Sometimes only the setup script knows the address, for example when it links a Valet site named after the workspace. In that case the script can write the address to $BLOOM_URL_FILE, and that address takes precedence over browser.url.

echo "https://$SITE.test" > "$BLOOM_URL_FILE"

Project quick prompts#

.bloom/settings.toml
[[quick_prompts]]
name = "Check for N+1 queries"
symbol = "doc.text.magnifyingglass"   # Uses a mark from the picker or an emoji (optional).
new_chat = false      # Opens the prompt in a new chat when true (optional).
prompt = """
Look through the controllers and Livewire components touched on this branch
for N+1 queries. Suggest eager loads, don't apply them.
"""

Each [[quick_prompts]] entry appears in the composer's quick prompt panel under a Project heading, below your own prompts. Every entry needs a name and a prompt.

Project prompts appear below your own prompts in the quick prompt panel.

Picking a project prompt puts its text in the composer without sending it. You can't edit project prompts in Bloom, but you can hover one and choose Copy to My Quick Prompts to get a copy of your own.

Symbols#

The symbol must be one of the marks in Bloom's quick prompt picker, such as checklist or doc.text.magnifyingglass, or a single emoji. Any other value shows the default mark along with a notice. A run script's icon works differently, because it accepts any SF Symbol name.

Git branches#

.bloom/settings.toml
[git]
branch_prefix = "freek"
delete_branch_on_archive = true

branch_prefix puts new workspace branches under a prefix, so freek gives branches such as freek/fix-invoice-totals, and you can leave off the trailing slash. branch_prefix_type = "github_username" uses your GitHub username, which Bloom reads from gh or from git config github.user, and "none" turns the prefix off. A prefix is a personal choice, so it belongs in ~/.bloom/settings.toml or settings.local.toml.

With delete_branch_on_archive = true, Bloom also deletes the workspace's local branch when you archive it. This setting is off by default.

Merge instructions#

.bloom/settings.toml
[instructions]
merge = """
Run composer test before merging, and stop if anything fails.
"""
fix_conflicts = """
For conflicts in composer.lock, take the incoming file and run composer update --lock.
"""

When you press Merge or Fix merge conflicts, Bloom adds this text after its own instructions to the agent, and your text wins where the two disagree. A change applies to every workspace in the project, including the ones that already exist.

A .bloom/merge-instructions.md or .bloom/conflict-instructions.md file in the workspace replaces the matching setting, which lets a branch carry its own instructions.

Models#

.bloom/settings.toml
[models]
default = "opus"

[models.claude]
default_thinking_level = "high"

New chats in this project start on this model and Claude Code thinking level, while existing chats keep the ones they have. The models include fable, opus, sonnet and haiku, and the thinking levels are low, medium, high, xhigh and max.

In the project's settings file, these keys override the defaults in Settings › Sessions. In ~/.bloom/settings.toml they rank below that screen, so what you pick in Settings wins.

Example: a Laravel project#

In this example the setup and archive scripts are separate files, and the Laravel answer in the FAQ has a setup script you can start from. The server runs on $BLOOM_PORT and Vite runs on the port after it.

.bloom/settings.toml
file_include_globs = [".env"]

[scripts]
setup_file = ".bloom/setup.sh"
archive_file = ".bloom/archive.sh"

[scripts.run.server]
name = "Server"
command = "php artisan serve --port=$BLOOM_PORT"
icon = "globe"
autostart = true

[scripts.run.vite]
name = "Vite"
command = "npm run dev -- --port=$((BLOOM_PORT + 1))"
icon = "bolt"
autostart = true

[scripts.run.horizon]
name = "Horizon"
command = "php artisan horizon"
icon = "tray.full"

[scripts.run.logs]
name = "Logs"
command = "tail -f storage/logs/laravel.log"
icon = "text.alignleft"

[scripts.run.seed]
name = "Seed Database"
command = "php artisan migrate:fresh --seed"
icon = "leaf"

[browser]
url = "http://localhost:$BLOOM_PORT/login"

[[quick_prompts]]
name = "Check for N+1 queries"
symbol = "doc.text.magnifyingglass"
prompt = """
Look through the controllers and Livewire components touched on this branch
for N+1 queries. Suggest eager loads, don't apply them.
"""

[[quick_prompts]]
name = "Write Pest tests"
symbol = "testtube.2"
prompt = """
Add Pest feature tests for the behaviour this branch changes. Use the existing
factories, and run the tests before you finish.
"""

If your setup script links a Valet or Herd site and writes its address to $BLOOM_URL_FILE, you can remove the Server script, because the written address takes precedence over browser.url.

    You can search section titles and text.

    Get Bloom

    Enter your email and we'll send you the download link. Bloom is free to use and checks for updates automatically.