Repository navigation
Configuration
Rona is configured through TOML files. All settings are optional — Rona works without any configuration file.
| Priority | Path | Scope |
|---|---|---|
| 1 (highest) | .rona.toml |
Current project (searched from the current directory up to the repository root) |
| 2 | Extended file(s) declared via extends
|
Shared base config |
| 3 | File(s) pulled in by a matching [[overrides]] entry |
Every project under a given directory |
| 4 | ~/.config/rona.toml |
All projects for this user |
| 5 (lowest) | ~/.config/rona/config.toml |
Legacy global path (still supported) |
Project-level settings override global ones. Rona looks for .rona.toml in the directory you run it from and then in each parent directory, stopping at the repository root, so the project config still applies when you work in a subdirectory. The nearest file wins, and a config outside the repository is never used. You can also bypass this hierarchy entirely with the -f/--config-file <PATH> global flag, which loads only the specified file (and works before or after any subcommand).
TOML ordering constraint: In TOML, every key-value pair that appears after a [[extra_fields]] or [[branch_extra_fields]] header belongs to that array item, not the top-level table. Always declare editor, commit_types, template, field_order, and all branch-related top-level keys before any [[extra_fields]] or [[branch_extra_fields]] entry.
extends = "path/to/base-config.toml"Points to another TOML file whose settings are loaded as a base before the current file. Values in the current file override those in the extended file, so you only need to declare what differs.
The path is resolved relative to the file that declares extends. Absolute paths are also accepted. If the referenced file does not exist, Rona exits with an error.
A .rona.toml that contains only this key is valid and fully functional:
extends = "~/configs/rona-base.toml"You can also extend and override selectively:
extends = "~/configs/rona-base.toml"
editor = "vim" # overrides whatever editor is set in the baseWhere extends is declared by the project that wants a shared base, [[overrides]] works in the opposite direction: the global config declares that any repository under a given directory should pick up an extra config file. The repositories themselves need no .rona.toml at all.
# ~/.config/rona.toml
editor = "nano"
# When run anywhere under ~/Affluences, layer in the referenced config.
[[overrides]]
path = "~/Affluences/**"
config = "~/Affluences/afl-notes/selfnotes.config"
[[overrides]]
path = "~/oss"
config = "~/configs/rona-oss.toml"| Key | Meaning |
|---|---|
path |
Glob matched against the directory Rona runs from. A leading ~/ expands to your home directory. |
config |
The config file to layer in. Relative paths resolve against the file declaring the override; ~/ expands. |
Matching rules:
-
~/Affluences/**matches~/Affluencesitself and every directory beneath it. - A pattern with no wildcard (
~/oss) matches that directory and all of its descendants. - Matching is against the current working directory, not the repository root, so an override applies from any subdirectory of a covered repository.
- On Windows,
/and\are interchangeable in patterns, and matching is case-insensitive.
Windows paths in TOML: a backslash starts an escape sequence inside a double-quoted string, so path = "C:\Users\me\work\**" is invalid TOML (\U is not a valid escape) and Rona will report a parse error. Use forward slashes, or a TOML literal string:
[[overrides]]
path = 'C:\Users\me\work\**' # single quotes: backslashes are literal
config = 'C:\Users\me\work\shared-rona.toml'
# equivalent, and simpler
[[overrides]]
path = "C:/Users/me/work/**"
config = "C:/Users/me/work/shared-rona.toml"Behaviour:
- Overrides are read from the global configs only (
~/.config/rona.tomland the legacy~/.config/rona/config.toml), never from project configs. Resolution is therefore never recursive. - Every matching override applies, in declaration order, so a later entry wins over an earlier one.
- The referenced file may itself use
extends; its whole chain is layered in base-first. - If the referenced file does not exist, the override is skipped silently. Use
rona config -wto check what is actually being loaded.
Precedence, lowest to highest: legacy global config, global config, matching [[overrides]] targets, the project config's extends chain, then ./.rona.toml. So an override beats your global settings but a project .rona.toml still beats the override.
rona config -w lists each active override alongside the pattern that matched it:
✓ [priority 2] /Users/you/.config/rona.toml
└─ Global config (active)
✓ [priority 3] /Users/you/Affluences/afl-notes/selfnotes.config
└─ Override config (path = "~/Affluences/**") (active)
○ [priority 5] /Users/you/Affluences/some-repo/.rona.toml
└─ Project config (not found)
editor = "nano"The command used to open commit_message.md in non-interactive mode (rona -g without -i). Any editor launchable as <editor> <file> works.
Examples: "vim", "zed --wait", "code --wait", "emacs", "nano"
commit_types = ["feat", "fix", "docs", "refactor", "test", "chore"]The list shown in the commit-type selector. When absent, Rona uses the built-in default: ["feat", "fix", "docs", "test", "chore"].
template = "{?commit_number}[{commit_number}] {/commit_number}({commit_type} on {branch_name}) {message}"Controls how the final commit message is formatted in interactive mode (rona -g -i).
Built-in variables:
| Variable | Value |
|---|---|
{commit_number} |
Incremental commit count on the current branch |
{commit_type} |
The type selected at the prompt |
{branch_name} |
Current branch name (type prefix such as feat/ is stripped) |
{message} |
The message entered by the user |
{date} |
Today's date as YYYY-MM-DD
|
{time} |
Current time as HH:MM:SS
|
{author} |
Git author name (from git config) |
{email} |
Git author email (from git config) |
Any extra field defined under [[extra_fields]] is also available as {name}.
Conditional blocks — content is included only when the variable is non-empty:
{?variable}content{/variable}
This is mainly useful for commit_number, which is absent when using the -n flag:
# Renders "[42] feat: msg" normally, "feat: msg" with -n
template = "{?commit_number}[{commit_number}] {/commit_number}{commit_type}: {message}"field_order = ["scope", "message", "ticket"]Controls the sequence of prompts shown in interactive mode after the commit-type selector. The reserved name "message" positions the built-in message prompt. Extra fields not listed are appended after all listed items.
Default (empty or absent): extra fields in declaration order, then message.
These options configure the rona branch command, which generates branch names from a template in the same way that commit messages are generated in interactive mode.
branch_template = "{branch_type}/{description}"Controls how the branch name is assembled. Uses the same variable substitution and conditional block syntax as template. When absent, Rona defaults to {branch_type}/{description}.
Built-in variables available in branch templates:
| Variable | Value |
|---|---|
{branch_type} |
Selected branch type (from branch_types or commit_types) |
{description} |
Free-text description entered by the user |
{date} |
Today's date as YYYY-MM-DD
|
{time} |
Current time as HH:MM:SS
|
{author} |
Git author name (from git config) |
Any field defined under [[branch_extra_fields]] is also available as {name}.
Note: {branch_type} is distinct from {commit_type}, which is only available in commit templates.
Rona only prompts for {branch_type} and {description} when they actually appear in the template. A template like release/{version} skips both prompts entirely.
branch_types = ["feat", "fix", "release", "hotfix"]The list shown in the branch-type selector inside rona branch. When absent and merge_branch_and_commit_types is not set, the selector falls back to commit_types.
merge_branch_and_commit_types = trueWhen true, appends commit_types values not already present in branch_types to the branch-type selector. Requires branch_types to be set; omitting branch_types while setting this key to true produces an error.
branch_field_order = ["service", "description", "version"]Controls the sequence of prompts shown by rona branch after the branch-type selector. Works the same as field_order for commits: the reserved name "description" positions the built-in description prompt, and any branch_extra_fields entry not listed is appended at the end.
Default (empty or absent): extra fields in declaration order, then description.
[[branch_extra_fields]] entries add project-specific prompts to rona branch. Each field becomes a template variable using its name. The options are identical to [[extra_fields]].
[[branch_extra_fields]]
name = "service"
prompt = "Service name"
kind = "text"
required = true
[[branch_extra_fields]]
name = "version"
prompt = "Version"
kind = "select"
prefetch.source = "branches"
prefetch.extract_regex = "[0-9]+(?:-[0-9]+)+"
prefetch.deduplicate = trueprefetch.source = "branches" scans all local branch names and applies extract_regex to each, making it easy to populate selects with values (such as version strings) already present in the repository.
[[extra_fields]] entries add project-specific prompts to interactive mode. Each field becomes a template variable using its name.
[[extra_fields]]
name = "scope"
prompt = "Component scope" # label shown to the user; defaults to name
kind = "select" # "text" (default) or "select"
required = false # reject empty answers; default false
validation = "^[a-z]+" # regex the entered value must matchA prefetch block pre-populates the prompt from an external source.
[[extra_fields]]
name = "scope"
prefetch.source = "command" # "command", "branch", or "branches"
prefetch.command = "git log -20 --pretty=format:%s" # shell command (source = "command" only)
prefetch.extract_regex = "\\w+\\((?P<value>[^)]*)\\):" # regex applied to each line / branch name
prefetch.deduplicate = true # remove duplicates (command and branches sources)Prefetch sources:
| Source | Where values come from |
|---|---|
"command" |
Output lines of the shell command in prefetch.command
|
"branch" |
The current branch name (produces at most one value; used as a default) |
"branches" |
All local branch names (useful in [[branch_extra_fields]] to reuse version strings etc.) |
extract_regex extraction priority: named group value → capture group 1 → full match. A bare pattern like [A-Z]+-[0-9]+ works and returns the whole match.
Prompt behaviour by kind and prefetch result:
kind |
Prefetch result | Behaviour |
|---|---|---|
select |
non-empty list | Select list + (none) (if optional) + Other (enter manually)
|
select |
empty | Falls back to free-text |
text |
non-empty list from command or branches
|
Same as select with non-empty list |
text |
0–1 values from branch
|
Free-text with extracted value as default |
text |
nothing | Plain free-text |
When a field is skipped (optional + user chose (none)), the variable is absent. Use a conditional block to handle this: {?scope}({scope}){/scope}.
Pressing Enter on a pre-filled default always accepts it, regardless of the validation regex.
These options configure rona pr, which opens a pull request or a merge request for the current branch. Most options have a command line counterpart. The flag always wins.
pr_title_template = "{branch_type}: {commit_subject}"Seeds the heading Rona writes into a new pr_description.md. Uses the same variable substitution and conditional block syntax as template. When absent, Rona defaults to {commit_subject}.
Built-in variables available in PR title templates:
| Variable | Value |
|---|---|
{branch_name} |
Name of the current branch |
{branch_type} |
Type prefix of the current branch, such as feat in feat/login
|
{title} |
Free-text title entered by the user |
{target_branch} |
Branch the request targets |
{commit_subject} |
Subject of the last commit |
{date} |
Today's date as YYYY-MM-DD
|
{time} |
Current time as HH:MM:SS
|
{author} |
Git author name (from git config) |
{email} |
Git author email (from git config) |
Any field defined under [[pr_extra_fields]] is also available as {name}.
The default template needs no prompt at all. Reference {title} to add an interactive title prompt before the editor opens. You can always edit the heading in the editor afterwards.
pr_backend = "auto"Backend used to open the request: auto, gh, glab, push-options, or browser. Defaults to auto, which picks from the detected forge and the binaries you have. The Command Reference lists what each backend runs and what it cannot carry.
pr_target = "main"Branch a request targets by default. When absent, Rona reads the default branch of the remote from refs/remotes/<remote>/HEAD. Without that reference, it falls back to the first of main, master, or develop that exists on the remote.
pr_remote = "origin"Remote a request is opened against. Defaults to origin.
pr_forge = "gitlab"Forge behind the remote: github, gitlab, or bitbucket. Rona reads the forge from the remote URL. Set this key only for a self-hosted instance whose hostname does not name the product, such as git.company.com.
pr_draft = trueOpens every request from this project as a draft. Defaults to false.
pr_labels = ["needs-review"]
pr_reviewers = ["alice"]
pr_assignees = ["bob"]Applied to every request opened from this project. Values from the -l, -r, and -A flags are added to these lists. Rona keeps each value once.
pr_field_order = ["ticket", "title"]Controls the sequence of prompts shown by rona pr. Works the same as field_order for commits: the reserved name "title" positions the built-in title prompt, and any pr_extra_fields entry not listed is appended at the end.
[pr_title]
prompt = "Request title"
validation = "^\\S"
disabled = falseOverrides the built-in title prompt of rona pr. Same shape as the built-in overrides for commits. Set disabled = true to skip the prompt, which leaves {title} empty.
[[pr_extra_fields]] entries add project-specific prompts to rona pr. Each field becomes a template variable using its name. The options are identical to [[extra_fields]].
[[pr_extra_fields]]
name = "ticket"
prompt = "Ticket"
kind = "text"
prefetch.source = "branch"
prefetch.extract_regex = "[A-Z]+-[0-9]+"Rona prompts only for the fields that pr_title_template actually uses. It skips any other field and prints a note. A title template with no variables opens the editor with no prompt at all.
editor = "zed --wait"
commit_types = ["feat", "fix", "docs", "refactor", "test", "chore", "ci"]
template = "{?commit_number}[{commit_number}] {/commit_number}{commit_type}{?scope}({scope}){/scope}: {message}{?ticket} [{ticket}]{/ticket}"
field_order = ["scope", "message", "ticket"]
# Branch creation settings
branch_template = "{branch_type}/{service}/{version}"
branch_types = ["staging", "production"]
branch_field_order = ["service", "version"]
# Pull / merge request settings
pr_title_template = "{?ticket}[{ticket}] {/ticket}{commit_subject}"
pr_backend = "auto"
pr_target = "main"
pr_labels = ["needs-review"]
# --- commit: scope ---
# Suggested from the last 20 commit subjects.
[[extra_fields]]
name = "scope"
prompt = "Select scope"
kind = "select"
required = false
prefetch.source = "command"
prefetch.command = "git log -20 --pretty=format:%s"
prefetch.extract_regex = "\\w+\\((?P<value>[^)]*)\\):"
prefetch.deduplicate = true
# --- commit: ticket ---
# Default extracted from branch name, e.g. feat/PROJ-42_login -> PROJ-42.
[[extra_fields]]
name = "ticket"
prompt = "Ticket reference"
kind = "text"
required = false
validation = "^[A-Z]+-[0-9]+$"
prefetch.source = "branch"
prefetch.extract_regex = "[A-Z]+-[0-9]+"
# --- branch: service ---
[[branch_extra_fields]]
name = "service"
prompt = "Service name"
kind = "text"
required = true
# --- branch: version ---
# Values extracted from existing local branch names.
[[branch_extra_fields]]
name = "version"
prompt = "Version"
kind = "select"
prefetch.source = "branches"
prefetch.extract_regex = "[0-9]+(?:-[0-9]+)+"
prefetch.deduplicate = true
# --- pr: ticket ---
# Default extracted from branch name, e.g. feat/PROJ-42_login -> PROJ-42.
[[pr_extra_fields]]
name = "ticket"
prompt = "Ticket reference"
kind = "text"
prefetch.source = "branch"
prefetch.extract_regex = "[A-Z]+-[0-9]+"For a fully annotated starting point, see .rona.example.toml in the repository root.
- Features — overview of what each option enables
-
Command Reference —
-f/--config-fileflag and all commands - FAQ — common configuration questions