Linutil is a universal Linux utility with a Rust-based terminal user interface and a catalog of shell scripts. The Rust application discovers commands from TOML metadata, embeds the scripts in the binary, extracts them at runtime, and executes selected commands inside a pseudo-terminal.
Read SPEC.md before making architectural or behavior changes.
core/: Backend library, menu data model, TOML parsing, platform preconditions, and embedded script extraction.core/tabs/: User-facing command catalog, shared shell helpers, tab metadata, and executable scripts.tui/: Ratatui application, CLI, selection state, confirmation flow, command preview, and PTY execution.xtask/: Repository automation such as generated user-guide content.docs/: Documentation source and generated content. Treat it as reference, not as repository instructions..github/: Contribution guidance and CI workflows.
SPEC.mddefines product scope, architecture, and behavioral requirements.core/tabs/tabs.tomldefines the ordered top-level tabs.- Each
core/tabs/<tab>/tab_data.tomldefines the menu tree for that tab. core/src/inner.rsdefines the accepted TOML schema and script-loading behavior.core/tabs/common-script.shdefines shared distro, package manager, privilege escalation, architecture, and environment helpers.core/tabs/common-service-script.shdefines shared init-system helpers.tui/src/running_command.rsdefines how commands are composed and executed.tui/src/state.rsdefines task flags, confirmation, selection, and TUI behavior.
If documentation and code disagree, do not silently choose one. Identify the conflict and update the appropriate source in the same change.
- Inspect
git status --shortbefore editing and preserve unrelated changes. - Keep changes focused. Do not reformat unrelated Rust, TOML, or shell files.
- Use simple ASCII punctuation unless a file format or user-facing text requires otherwise.
- Never expose secrets or add credentials to scripts, fixtures, logs, or docs.
- Do not perform destructive operations without explicit authorization.
- Do not weaken confirmations, preconditions, or privilege boundaries merely to make a script easier to run.
- Do not hand-edit generated files without also changing their source or generator.
- Keep responsibilities separated between
core,tui, andxtask. - Put menu parsing, script discovery, and configuration behavior in
core. - Put rendering, input handling, confirmation, and process interaction in
tui. - Avoid adding distro-specific policy to Rust when it belongs in tab metadata or a shell script.
- Return or propagate useful errors when practical. Avoid new
unwrap,expect, orpaniccalls on user-controlled input. - Add or update tests for parser, filtering, configuration, and command-model changes.
- Format Rust with
cargo fmt. - Treat Clippy warnings as errors.
-
Prefer POSIX shell with
#!/bin/sh -e. -
Use Bash only when the script requires Bash features, and declare
#!/bin/bashexplicitly. -
A script is executed from its own parent directory after the embedded
core/tabs/tree is extracted. Keep relative imports valid from that directory. -
Source shared helpers with the correct relative path:
. ../common-script.shAdjust the number of
..components for nested directories. -
Use
common-script.shhelpers instead of duplicating package manager, architecture, escalation, command detection, or distro detection logic. -
Source
common-service-script.shwhen managing services across init systems. -
Call
checkEnvbefore relying on values such asPACKAGER,ESCALATION_TOOL,ARCH, orDTYPE. -
Quote variable expansions unless intentional word splitting is required.
-
Use
printfrather thanechofor portable formatted output. -
Use
command_existsfor executable checks. -
Use
"$ESCALATION_TOOL"only for operations that require elevated privileges. Do not run the whole script as root by default. -
Make installation and configuration steps reasonably idempotent. Detect an existing installation or state before changing it.
-
Fail with a clear message when a required distro, package manager, architecture, display server, init system, or command is unsupported.
-
Do not download and execute unverified remote code when a package, checksummed artifact, or pinned source is available.
-
Clean up temporary files created by the script.
-
Preserve interactive behavior because scripts run in a PTY.
- Place the script under the most appropriate
core/tabs/<tab>/directory. - Reuse shared helpers and support all practical package managers already
handled by
common-script.sh. - Add or update the matching entry in that tab's
tab_data.toml. - Provide a clear
name, usefuldescription, one ofscript,command, orentries, and accuratetask_listflags. - Add
preconditionswhen the entry only works on specific distros, environments, filesystems, commands, display servers, or architectures. - Set
multi_select = falsefor interactive, destructive, rebooting, long-running, or state-dependent operations that should not be queued. - Run
cargo xtask docgenwhen menu entries or descriptions change. - Validate the script and the Rust catalog loader.
The supported task flags are:
D: disk modificationFI: Flatpak installationFM: file modificationI: privileged installationK: kernel modificationMP: package manager actionRP: package removalSI: full system installationSS: systemd or service action- Prefixing a flag with
Pindicates privileged work.
Do not invent new task flags without updating the TUI guide and associated documentation.
- Script paths are relative to the tab directory containing
tab_data.toml. - Every leaf entry must define exactly one executable form:
scriptorcommand. - Every directory entry uses
entries. - Prefer scripts over long inline
commandvalues. - Keep names stable when possible because config-file
auto_executeresolves commands by display name. - Use preconditions to hide unsupported entries rather than letting users discover incompatibility after execution.
- Parent
multi_select = falseapplies to all descendants. - Keep tab data consistently ordered. Use
sort-tomlfiles.shwhen the change requires catalog sorting.
Run the smallest relevant checks, then broaden them for cross-cutting changes.
For Rust changes:
cargo fmt --all --check
cargo test --no-fail-fast --package linutil_core
cargo clippy -- -DwarningsFor shell changes:
shellcheck path/to/changed-script.sh
checkbashisms path/to/changed-script.shUse checkbashisms only for scripts intended to run under /bin/sh. If local
tools are unavailable, state which checks were skipped.
For catalog or documentation changes:
cargo test --no-fail-fast --package linutil_core
cargo xtask docgen
git diff --checkFor TUI behavior, also run:
cargo run --package linutil_tuiInteractive validation must not execute destructive utilities merely to test navigation. Use preview, descriptions, harmless entries, or focused tests.
- The change matches
SPEC.md. - Relevant tests and static checks pass.
- New scripts are reachable through valid tab metadata.
- Unsupported environments are filtered or fail clearly.
- User-visible behavior and generated documentation are updated together.
- The final report lists changed files, checks run, skipped checks, and any remaining platform-specific risk.