Skip to main content

max / alloy

9.4 KB · 236 lines History Blame Raw
1 @{! variants = default, night }
2 # Alloy starship configuration
3 #
4 # Cross-shell prompt per docs/STACK.md#shell. Two lines: context on the first,
5 # the entry glyph alone on the second, so a typed command always starts at the
6 # same column no matter how long the branch name or the path is.
7 #
8 # Palette drawn from docs/TOKENS.md, mapped to starship's color slots by
9 # function rather than by name. Color is reserved for state per
10 # DESIGN-LANGUAGE.md, which is why almost everything here is muted: the only
11 # things that take a color are the ones saying something went wrong.
12 #
13 # THE RULE THIS FILE IS BUILT ON, stated 2026-08-14: every segment is a fact
14 # somebody acts on, written as words rather than as pictures.
15 #
16 # What that ruled out, and why:
17 #
18 # - Nerd-font icons. A branch glyph in front of a branch name is the same fact
19 # drawn twice, and it costs a font dependency to say it: shop has no font
20 # fallback, so a glyph the font lacks draws as tofu rather than as nothing.
21 # A prompt of words and ASCII cannot break that way.
22 # - Language versions (rust, python, nodejs). Information, not useful
23 # information. Inside a Rust repo it printed the toolchain version on every
24 # line for a question nobody asks at the prompt, and `rustc -V` answers it
25 # the moment they do.
26 #
27 # What it ruled in, all of them invisible until they are true:
28 #
29 # - The exit code as a number. A red glyph says a command failed; 1, 127, 130
30 # and 137 are four different next actions, and the glyph cannot tell them
31 # apart.
32 # - The container name. `alloy pkg` puts people inside distrobox, and a box
33 # prompt was indistinguishable from the host.
34 # - git_state. Mid-rebase is the most important thing on screen while it lasts.
35
36 format = """
37 $username\
38 $hostname\
39 $container\
40 $directory\
41 $git_branch\
42 $git_state\
43 $git_status\
44 $line_break\
45 $character"""
46
47 # The right prompt is a different subject from the left, and that is the whole
48 # grouping mechanism: the left says where you are, the right says what just
49 # happened. Exit code, duration and the time all belong to the command that
50 # finished, so they sit together at the far end and nothing on the left has to
51 # be separated from anything else by punctuation.
52 right_format = """$status$cmd_duration$time"""
53
54 # No blank line between prompts. The second line is already the separator, and
55 # a blank one on top of it spends a third of a three-line prompt on nothing.
56 add_newline = false
57
58 # -------------------------------------------------------------------
59 # Who and where
60 # -------------------------------------------------------------------
61 # Both were disabled here as "noise for Alloy's audience", on the reading that
62 # a laptop user knows which machine they are sitting at. That did not survive
63 # an installed test machine: two boxes gave the identical prompt and an ssh
64 # session was indistinguishable from a local one.
65 #
66 # ssh_only stays off deliberately. Showing the host only over ssh keeps the
67 # prompt silent in exactly the case where a machine is new and unfamiliar.
68 [hostname]
69 disabled = false
70 ssh_only = false
71 format = "[$hostname]($style) "
72 style = "@{content.secondary}"
73
74 [username]
75 disabled = false
76 show_always = true
77 format = "[$user]($style)[@](@{content.muted})"
78 # Not `style`. This module resolves `$style` to one of these two by who you
79 # are, and a plain `style` key is silently ignored: starship warns and falls
80 # back to its own bold yellow, which is off-palette and reads as a warning
81 # about nothing.
82 style_user = "@{content.muted}"
83 # Root gets the danger color rather than the muted one. This is the one time
84 # the prompt should be saying something about who you are.
85 style_root = "@{status.danger}"
86
87 # Which distrobox, blank on the host. No symbol: the name is the fact, and the
88 # brackets are what make it read as an enclosure rather than as a word in the
89 # path.
90 [container]
91 disabled = false
92 format = "[\\[$name\\]]($style) "
93 style = "@{status.warning}"
94
95 # -------------------------------------------------------------------
96 # Directory — the one bold thing on the line
97 # -------------------------------------------------------------------
98 [directory]
99 style = "bold @{content.primary}"
100 format = "[$path]($style)[$read_only]($read_only_style) "
101 truncation_length = 4
102 truncation_symbol = "…/"
103 truncate_to_repo = true
104 # Was a nerd-font padlock. Two letters that are always in the font say it as
105 # well and cannot arrive as tofu.
106 read_only = " [ro]"
107 read_only_style = "@{status.danger}"
108
109 # -------------------------------------------------------------------
110 # Git — branch, then any operation in flight, then the working tree
111 # -------------------------------------------------------------------
112 [git_branch]
113 symbol = ""
114 style = "@{content.secondary}"
115 format = "[$branch]($style) "
116
117 # Only ever on screen mid-operation, and then it is the thing that matters:
118 # what you are in the middle of, and how far through. The parenthesised
119 # progress is starship's optional syntax and collapses when there is none, so
120 # a merge reads `merge` and a rebase reads `rebase 3/7`.
121 [git_state]
122 style = "@{status.warning}"
123 format = "[$state( $progress_current/$progress_total)]($style) "
124
125 # Count first, then a letter for what was counted: `2m 1u 3s 3a`. Reads as a
126 # quantity with a unit, which is what it is.
127 #
128 # This replaced `!?+` with arrows, where the count was missing on the working
129 # tree markers and present on the remote ones, nothing separated one marker
130 # from the next, and `!` and `↑3` sat adjacent while being different kinds of
131 # fact: one is your working tree, the other is your relationship to the remote.
132 # `!↑3` was three characters that had to be learned rather than read.
133 #
134 # Each marker carries its own trailing space, because starship concatenates
135 # these with no separator and `2m1u3s` is the run-together problem again.
136 #
137 # `st` for stashed rather than a second `s`, which staged already has. It is
138 # the one marker here that is not about the working tree, and the extra letter
139 # is cheaper than the collision.
140 [git_status]
141 style = "@{status.warning}"
142 format = "[$all_status$ahead_behind]($style)"
143 conflicted = "${count}c "
144 ahead = "${count}a "
145 behind = "${count}b "
146 # Diverged needs no symbol of its own now: ahead and behind already have
147 # letters, so it is just both of them.
148 diverged = "${ahead_count}a ${behind_count}b "
149 untracked = "${count}u "
150 stashed = "${count}st "
151 modified = "${count}m "
152 staged = "${count}s "
153 renamed = "${count}r "
154 deleted = "${count}d "
155
156 # -------------------------------------------------------------------
157 # The exit code, as a number
158 # -------------------------------------------------------------------
159 # Disabled by default in starship, and the reason to turn it on is that the
160 # entry glyph already carries this state as a color and a color cannot count.
161 # 127 is a typo'd command, 130 is you pressing ctrl-c, 137 is the OOM killer.
162 # Same red glyph, three unrelated problems.
163 #
164 # Silent on success: a prompt that printed 0 after every command would be
165 # saying nothing, loudly.
166 [status]
167 disabled = false
168 # Labelled. On the right-hand side, away from anything that gives it context,
169 # a bare `130` is a number with no noun. `exit 130` costs five characters and
170 # needs nothing learned.
171 format = "[exit $status]($style) "
172 style = "@{status.danger}"
173 # The number, not a name for it. `map_symbol` would turn 130 into an interrupt
174 # glyph, which is the picture-for-a-word trade this file exists to refuse.
175 map_symbol = false
176 pipestatus = false
177
178 # -------------------------------------------------------------------
179 # Command duration — only for commands slow enough to have been noticed
180 # -------------------------------------------------------------------
181 [cmd_duration]
182 min_time = 2000
183 style = "@{content.secondary}"
184 format = "[$duration]($style) "
185 show_milliseconds = false
186
187 # -------------------------------------------------------------------
188 # Entry glyph — the prompt character itself
189 # -------------------------------------------------------------------
190 # Geometric shapes rather than nerd-font icons, so this survives a font with
191 # no icon coverage. It keeps its color state even though the exit code is now
192 # spelled out: the color is what you catch without reading.
193 [character]
194 success_symbol = "[▸](@{content.secondary})"
195 error_symbol = "[▸](@{status.danger})"
196 vimcmd_symbol = "[◂](@{status.success})"
197
198 # -------------------------------------------------------------------
199 # Right-aligned clock — when the command in front of it ran
200 # -------------------------------------------------------------------
201 # Kept even though the status bar is also a clock. The bar says what time it
202 # is now; this says what time each command in the scrollback happened, which
203 # is a different question and the only place it gets answered.
204 [time]
205 disabled = false
206 format = "[$time]($style)"
207 time_format = "%H:%M"
208 style = "@{content.muted}"
209
210 # -------------------------------------------------------------------
211 # Disabled modules — noise for Alloy's audience
212 # -------------------------------------------------------------------
213 # The language modules are not merely absent from `format`; they are off, so
214 # that adding a segment later is a deliberate act rather than something that
215 # starts rendering because a module's default changed.
216 [package]
217 disabled = true
218
219 [python]
220 disabled = true
221
222 [rust]
223 disabled = true
224
225 [nodejs]
226 disabled = true
227
228 [aws]
229 disabled = true
230
231 [gcloud]
232 disabled = true
233
234 [docker_context]
235 disabled = true
236