7.7 KiB
AGENTS.md
Purpose
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.
Repository layout
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.
Sources of truth
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.
Working rules
- 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.
Rust conventions
- 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.
Shell script conventions
-
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.
Adding or changing a utility
- 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.
TOML catalog rules
- 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.
Validation
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 -- -Dwarnings
For shell changes:
shellcheck path/to/changed-script.sh
checkbashisms path/to/changed-script.sh
Use 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 --check
For TUI behavior, also run:
cargo run --package linutil_tui
Interactive validation must not execute destructive utilities merely to test navigation. Use preview, descriptions, harmless entries, or focused tests.
Completion criteria
- 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.