Skip to main content

max / mountaineer-sysop

Initialize mountaineer-sysop workspace Two-crate Cargo workspace: sysop (CLI binary) and sysop-tui (shared primitives library). Edition 2024, ratatui 0.29. docs/todo.md scaffolds the work in three phases: sysop-tui primitives first (per AESTHETICS.md, lands before any subcommand), then sysop info as the first read-only subcommand, then sysop motd as the first stateful one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-18 01:05 UTC
Commit: 3815bcbe52e91b3e8cfca4d5a92ca1394cc0ace0
8 files changed, +606 insertions, -0 deletions
A .gitignore +4
@@ -0,0 +1,4 @@
1 + /target
2 + **/*.rs.bk
3 + Cargo.lock.bak
4 + .DS_Store
A Cargo.lock +500
@@ -0,0 +1,617 @@
1 + # This file is automatically @generated by Cargo.
2 + # It is not intended for manual editing.
3 + version = 4
4 +
5 + [[package]]
6 + name = "allocator-api2"
7 + version = "0.2.21"
8 + source = "registry+https://github.com/rust-lang/crates.io-index"
9 + checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
10 +
11 + [[package]]
12 + name = "anyhow"
13 + version = "1.0.102"
14 + source = "registry+https://github.com/rust-lang/crates.io-index"
15 + checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
16 +
17 + [[package]]
18 + name = "bitflags"
19 + version = "2.11.1"
20 + source = "registry+https://github.com/rust-lang/crates.io-index"
21 + checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
22 +
23 + [[package]]
24 + name = "cassowary"
25 + version = "0.3.0"
26 + source = "registry+https://github.com/rust-lang/crates.io-index"
27 + checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
28 +
29 + [[package]]
30 + name = "castaway"
31 + version = "0.2.4"
32 + source = "registry+https://github.com/rust-lang/crates.io-index"
33 + checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
34 + dependencies = [
35 + "rustversion",
36 + ]
37 +
38 + [[package]]
39 + name = "cfg-if"
40 + version = "1.0.4"
41 + source = "registry+https://github.com/rust-lang/crates.io-index"
42 + checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
43 +
44 + [[package]]
45 + name = "compact_str"
46 + version = "0.8.1"
47 + source = "registry+https://github.com/rust-lang/crates.io-index"
48 + checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32"
49 + dependencies = [
50 + "castaway",
51 + "cfg-if",
52 + "itoa",
53 + "rustversion",
54 + "ryu",
55 + "static_assertions",
56 + ]
57 +
58 + [[package]]
59 + name = "crossterm"
60 + version = "0.28.1"
61 + source = "registry+https://github.com/rust-lang/crates.io-index"
62 + checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
63 + dependencies = [
64 + "bitflags",
65 + "crossterm_winapi",
66 + "mio",
67 + "parking_lot",
68 + "rustix",
69 + "signal-hook",
70 + "signal-hook-mio",
71 + "winapi",
72 + ]
73 +
74 + [[package]]
75 + name = "crossterm_winapi"
76 + version = "0.9.1"
77 + source = "registry+https://github.com/rust-lang/crates.io-index"
78 + checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
79 + dependencies = [
80 + "winapi",
81 + ]
82 +
83 + [[package]]
84 + name = "darling"
85 + version = "0.20.11"
86 + source = "registry+https://github.com/rust-lang/crates.io-index"
87 + checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
88 + dependencies = [
89 + "darling_core",
90 + "darling_macro",
91 + ]
92 +
93 + [[package]]
94 + name = "darling_core"
95 + version = "0.20.11"
96 + source = "registry+https://github.com/rust-lang/crates.io-index"
97 + checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
98 + dependencies = [
99 + "fnv",
100 + "ident_case",
101 + "proc-macro2",
102 + "quote",
103 + "strsim",
104 + "syn",
105 + ]
106 +
107 + [[package]]
108 + name = "darling_macro"
109 + version = "0.20.11"
110 + source = "registry+https://github.com/rust-lang/crates.io-index"
111 + checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
112 + dependencies = [
113 + "darling_core",
114 + "quote",
115 + "syn",
116 + ]
117 +
118 + [[package]]
119 + name = "either"
120 + version = "1.15.0"
121 + source = "registry+https://github.com/rust-lang/crates.io-index"
122 + checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
123 +
124 + [[package]]
125 + name = "equivalent"
126 + version = "1.0.2"
127 + source = "registry+https://github.com/rust-lang/crates.io-index"
128 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
129 +
130 + [[package]]
131 + name = "errno"
132 + version = "0.3.14"
133 + source = "registry+https://github.com/rust-lang/crates.io-index"
134 + checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
135 + dependencies = [
136 + "libc",
137 + "windows-sys 0.61.2",
138 + ]
139 +
140 + [[package]]
141 + name = "fnv"
142 + version = "1.0.7"
143 + source = "registry+https://github.com/rust-lang/crates.io-index"
144 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
145 +
146 + [[package]]
147 + name = "foldhash"
148 + version = "0.1.5"
149 + source = "registry+https://github.com/rust-lang/crates.io-index"
150 + checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
151 +
152 + [[package]]
153 + name = "hashbrown"
154 + version = "0.15.5"
155 + source = "registry+https://github.com/rust-lang/crates.io-index"
156 + checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
157 + dependencies = [
158 + "allocator-api2",
159 + "equivalent",
160 + "foldhash",
161 + ]
162 +
163 + [[package]]
164 + name = "heck"
165 + version = "0.5.0"
166 + source = "registry+https://github.com/rust-lang/crates.io-index"
167 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
168 +
169 + [[package]]
170 + name = "ident_case"
171 + version = "1.0.1"
172 + source = "registry+https://github.com/rust-lang/crates.io-index"
173 + checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
174 +
175 + [[package]]
176 + name = "indoc"
177 + version = "2.0.7"
178 + source = "registry+https://github.com/rust-lang/crates.io-index"
179 + checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
180 + dependencies = [
181 + "rustversion",
182 + ]
183 +
184 + [[package]]
185 + name = "instability"
186 + version = "0.3.10"
187 + source = "registry+https://github.com/rust-lang/crates.io-index"
188 + checksum = "6778b0196eefee7df739db78758e5cf9b37412268bfa5650bfeed028aed20d9c"
189 + dependencies = [
190 + "darling",
191 + "indoc",
192 + "proc-macro2",
193 + "quote",
194 + "syn",
195 + ]
196 +
197 + [[package]]
198 + name = "itertools"
199 + version = "0.13.0"
200 + source = "registry+https://github.com/rust-lang/crates.io-index"
201 + checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
202 + dependencies = [
203 + "either",
204 + ]
205 +
206 + [[package]]
207 + name = "itoa"
208 + version = "1.0.18"
209 + source = "registry+https://github.com/rust-lang/crates.io-index"
210 + checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
211 +
212 + [[package]]
213 + name = "libc"
214 + version = "0.2.186"
215 + source = "registry+https://github.com/rust-lang/crates.io-index"
216 + checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
217 +
218 + [[package]]
219 + name = "linux-raw-sys"
220 + version = "0.4.15"
221 + source = "registry+https://github.com/rust-lang/crates.io-index"
222 + checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
223 +
224 + [[package]]
225 + name = "lock_api"
226 + version = "0.4.14"
227 + source = "registry+https://github.com/rust-lang/crates.io-index"
228 + checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
229 + dependencies = [
230 + "scopeguard",
231 + ]
232 +
233 + [[package]]
234 + name = "log"
235 + version = "0.4.29"
236 + source = "registry+https://github.com/rust-lang/crates.io-index"
237 + checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
238 +
239 + [[package]]
240 + name = "lru"
241 + version = "0.12.5"
242 + source = "registry+https://github.com/rust-lang/crates.io-index"
243 + checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
244 + dependencies = [
245 + "hashbrown",
246 + ]
247 +
248 + [[package]]
249 + name = "mio"
250 + version = "1.2.0"
251 + source = "registry+https://github.com/rust-lang/crates.io-index"
252 + checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
253 + dependencies = [
254 + "libc",
255 + "log",
256 + "wasi",
257 + "windows-sys 0.61.2",
258 + ]
259 +
260 + [[package]]
261 + name = "parking_lot"
262 + version = "0.12.5"
263 + source = "registry+https://github.com/rust-lang/crates.io-index"
264 + checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
265 + dependencies = [
266 + "lock_api",
267 + "parking_lot_core",
268 + ]
269 +
270 + [[package]]
271 + name = "parking_lot_core"
272 + version = "0.9.12"
273 + source = "registry+https://github.com/rust-lang/crates.io-index"
274 + checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
275 + dependencies = [
276 + "cfg-if",
277 + "libc",
278 + "redox_syscall",
279 + "smallvec",
280 + "windows-link",
281 + ]
282 +
283 + [[package]]
284 + name = "paste"
285 + version = "1.0.15"
286 + source = "registry+https://github.com/rust-lang/crates.io-index"
287 + checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
288 +
289 + [[package]]
290 + name = "proc-macro2"
291 + version = "1.0.106"
292 + source = "registry+https://github.com/rust-lang/crates.io-index"
293 + checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
294 + dependencies = [
295 + "unicode-ident",
296 + ]
297 +
298 + [[package]]
299 + name = "quote"
300 + version = "1.0.45"
301 + source = "registry+https://github.com/rust-lang/crates.io-index"
302 + checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
303 + dependencies = [
304 + "proc-macro2",
305 + ]
306 +
307 + [[package]]
308 + name = "ratatui"
309 + version = "0.29.0"
310 + source = "registry+https://github.com/rust-lang/crates.io-index"
311 + checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
312 + dependencies = [
313 + "bitflags",
314 + "cassowary",
315 + "compact_str",
316 + "crossterm",
317 + "indoc",
318 + "instability",
319 + "itertools",
320 + "lru",
321 + "paste",
322 + "strum",
323 + "unicode-segmentation",
324 + "unicode-truncate",
325 + "unicode-width 0.2.0",
326 + ]
327 +
328 + [[package]]
329 + name = "redox_syscall"
330 + version = "0.5.18"
331 + source = "registry+https://github.com/rust-lang/crates.io-index"
332 + checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
333 + dependencies = [
334 + "bitflags",
335 + ]
336 +
337 + [[package]]
338 + name = "rustix"
339 + version = "0.38.44"
340 + source = "registry+https://github.com/rust-lang/crates.io-index"
341 + checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
342 + dependencies = [
343 + "bitflags",
344 + "errno",
345 + "libc",
346 + "linux-raw-sys",
347 + "windows-sys 0.59.0",
348 + ]
349 +
350 + [[package]]
351 + name = "rustversion"
352 + version = "1.0.22"
353 + source = "registry+https://github.com/rust-lang/crates.io-index"
354 + checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
355 +
356 + [[package]]
357 + name = "ryu"
358 + version = "1.0.23"
359 + source = "registry+https://github.com/rust-lang/crates.io-index"
360 + checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
361 +
362 + [[package]]
363 + name = "scopeguard"
364 + version = "1.2.0"
365 + source = "registry+https://github.com/rust-lang/crates.io-index"
366 + checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
367 +
368 + [[package]]
369 + name = "signal-hook"
370 + version = "0.3.18"
371 + source = "registry+https://github.com/rust-lang/crates.io-index"
372 + checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
373 + dependencies = [
374 + "libc",
375 + "signal-hook-registry",
376 + ]
377 +
378 + [[package]]
379 + name = "signal-hook-mio"
380 + version = "0.2.5"
381 + source = "registry+https://github.com/rust-lang/crates.io-index"
382 + checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc"
383 + dependencies = [
384 + "libc",
385 + "mio",
386 + "signal-hook",
387 + ]
388 +
389 + [[package]]
390 + name = "signal-hook-registry"
391 + version = "1.4.8"
392 + source = "registry+https://github.com/rust-lang/crates.io-index"
393 + checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
394 + dependencies = [
395 + "errno",
396 + "libc",
397 + ]
398 +
399 + [[package]]
400 + name = "smallvec"
401 + version = "1.15.1"
402 + source = "registry+https://github.com/rust-lang/crates.io-index"
403 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
404 +
405 + [[package]]
406 + name = "static_assertions"
407 + version = "1.1.0"
408 + source = "registry+https://github.com/rust-lang/crates.io-index"
409 + checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
410 +
411 + [[package]]
412 + name = "strsim"
413 + version = "0.11.1"
414 + source = "registry+https://github.com/rust-lang/crates.io-index"
415 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
416 +
417 + [[package]]
418 + name = "strum"
419 + version = "0.26.3"
420 + source = "registry+https://github.com/rust-lang/crates.io-index"
421 + checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
422 + dependencies = [
423 + "strum_macros",
424 + ]
425 +
426 + [[package]]
427 + name = "strum_macros"
428 + version = "0.26.4"
429 + source = "registry+https://github.com/rust-lang/crates.io-index"
430 + checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
431 + dependencies = [
432 + "heck",
433 + "proc-macro2",
434 + "quote",
435 + "rustversion",
436 + "syn",
437 + ]
438 +
439 + [[package]]
440 + name = "syn"
441 + version = "2.0.117"
442 + source = "registry+https://github.com/rust-lang/crates.io-index"
443 + checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
444 + dependencies = [
445 + "proc-macro2",
446 + "quote",
447 + "unicode-ident",
448 + ]
449 +
450 + [[package]]
451 + name = "sysop"
452 + version = "0.1.0"
453 + dependencies = [
454 + "anyhow",
455 + "crossterm",
456 + "ratatui",
457 + "sysop-tui",
458 + ]
459 +
460 + [[package]]
461 + name = "sysop-tui"
462 + version = "0.1.0"
463 + dependencies = [
464 + "crossterm",
465 + "ratatui",
466 + ]
467 +
468 + [[package]]
469 + name = "unicode-ident"
470 + version = "1.0.24"
471 + source = "registry+https://github.com/rust-lang/crates.io-index"
472 + checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
473 +
474 + [[package]]
475 + name = "unicode-segmentation"
476 + version = "1.13.2"
477 + source = "registry+https://github.com/rust-lang/crates.io-index"
478 + checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
479 +
480 + [[package]]
481 + name = "unicode-truncate"
482 + version = "1.1.0"
483 + source = "registry+https://github.com/rust-lang/crates.io-index"
484 + checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
485 + dependencies = [
486 + "itertools",
487 + "unicode-segmentation",
488 + "unicode-width 0.1.14",
489 + ]
490 +
491 + [[package]]
492 + name = "unicode-width"
493 + version = "0.1.14"
494 + source = "registry+https://github.com/rust-lang/crates.io-index"
495 + checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
496 +
497 + [[package]]
498 + name = "unicode-width"
499 + version = "0.2.0"
500 + source = "registry+https://github.com/rust-lang/crates.io-index"
Lines truncated
A Cargo.toml +14
@@ -0,0 +1,14 @@
1 + [workspace]
2 + resolver = "3"
3 + members = ["crates/sysop", "crates/sysop-tui"]
4 +
5 + [workspace.package]
6 + edition = "2024"
7 + rust-version = "1.85"
8 + license = "MIT OR Apache-2.0"
9 +
10 + [workspace.dependencies]
11 + sysop-tui = { path = "crates/sysop-tui" }
12 + ratatui = "0.29"
13 + crossterm = "0.28"
14 + anyhow = "1"
@@ -0,0 +1,10 @@
1 + [package]
2 + name = "sysop-tui"
3 + version = "0.1.0"
4 + edition.workspace = true
5 + rust-version.workspace = true
6 + license.workspace = true
7 +
8 + [dependencies]
9 + ratatui.workspace = true
10 + crossterm.workspace = true
@@ -0,0 +1,16 @@
1 + [package]
2 + name = "sysop"
3 + version = "0.1.0"
4 + edition.workspace = true
5 + rust-version.workspace = true
6 + license.workspace = true
7 +
8 + [[bin]]
9 + name = "sysop"
10 + path = "src/main.rs"
11 +
12 + [dependencies]
13 + sysop-tui.workspace = true
14 + ratatui.workspace = true
15 + crossterm.workspace = true
16 + anyhow.workspace = true
@@ -0,0 +1,3 @@
1 + fn main() -> anyhow::Result<()> {
2 + Ok(())
3 + }
A docs/todo.md +59
@@ -0,0 +1,59 @@
1 + # mountaineer-sysop — todo
2 +
3 + Status: Pre-v0. Repo just initialized. Active: sysop-tui primitives. Next: first subcommand (`sysop info <role>`) as the dogfood target.
4 +
5 + ## Phase 1 — sysop-tui primitives
6 +
7 + Per `AESTHETICS.md`, this lands before any subcommand code.
8 +
9 + - [ ] Color constants for flatwhite palette (fg, bg, dim, accent, state-ok, state-warn, state-fault)
10 + - [ ] Frame: footer-only chrome, no top title bar, no internal borders, whitespace separators
11 + - [ ] Footer keybind renderer (label/key pairs, right-aligned wrap)
12 + - [ ] Selection widget: leading `▶` + inverse, two-cue
13 + - [ ] Reserved global keys handler: `?` `q` `Esc` `/` `:`
14 + - [ ] Hue-is-state helpers (`ok()`, `warn()`, `fault()`, `inactive()`); no hue for hierarchy
15 + - [ ] Smoke test binary in `examples/` rendering one screen using every primitive
16 +
17 + ## Phase 2 — first subcommand: `sysop info <role>`
18 +
19 + The smallest useful subcommand. Resolves the role→tool mapping (principle 15). Read-only, single screen, exercises sysop-tui end-to-end.
20 +
21 + - [ ] Role→tool table source-of-truth (location TBD — `STACK.md`? embedded TOML? generated?)
22 + - [ ] CLI parsing (clap derive, single positional arg)
23 + - [ ] TUI screen: role name, current tool, config path, package name, version
24 + - [ ] `sysop info` (no arg) → list view of all roles, selectable, Enter → detail screen
25 + - [ ] Exit code 0 on found, 1 on unknown role
26 +
27 + ## Phase 3 — `sysop motd on/off`
28 +
29 + Smallest stateful subcommand. Writes the motd-enable flag (from installer or operator). Exercises config-write path.
30 +
31 + - [ ] Config file location decided (`/etc/mountaineer/sysop.toml`? `~/.config/mountaineer/`? both?)
32 + - [ ] `sysop motd on` / `sysop motd off` / `sysop motd` (status)
33 + - [ ] motd rotation script driven by this flag
34 +
35 + ## Deferred (post-MVP scaffolding)
36 +
37 + - [ ] `sysop wifi` — TUI front for iwctl
38 + - [ ] `sysop net status` — first-boot route dependency
39 + - [ ] `sysop services` — s6-rc health list + enable/disable
40 + - [ ] `sysop storage` — ZFS pool view
41 + - [ ] `sysop logs <service>` — lnav front
42 + - [ ] `sysop id` — identity subsystem (full design in `mountaineer/todo.md`)
43 + - [ ] `sysop upgrade`, `sysop wg`, `sysop notifications mute`, `sysop podman-s6`
44 + - [ ] Tool-agnostic backend pattern (principle 14): every TUI swappable when underlying tool changes
45 + - [ ] Tab completion (bash/zsh/nushell)
46 + - [ ] Man pages (mdoc; generated from clap?)
47 + - [ ] CI / reproducible builds story
48 + - [ ] Release artifact shape (static-linked musl binary in Alpine apk)
49 +
50 + ## Key Paths
51 +
52 + - `Cargo.toml` — workspace root
53 + - `crates/sysop/` — CLI binary
54 + - `crates/sysop-tui/` — shared TUI primitives (flatwhite, footer chrome, selection, reserved keys)
55 + - `../mountaineer/AESTHETICS.md` — committed aesthetic/UX picks the TUI must honor
56 + - `../mountaineer/MANIFESTO.md` — principles 1, 2, 14, 15 are the load-bearing ones for this repo
57 + - `../mountaineer/STACK.md` — role→tool mappings consumed by `sysop info`
58 + - `../mountaineer/todo.md` — wider Mountaineer state and the `sysop id` design
59 + - `/Users/max/Code/CONTRIBUTING.md` — cross-cutting rules