add agent and spec sheets

This commit is contained in:
titus
2026-06-23 19:22:15 -05:00
parent c770e88764
commit f3946bf4a4
2 changed files with 581 additions and 0 deletions
+197
View File
@@ -0,0 +1,197 @@
# 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.md` defines product scope, architecture, and behavioral requirements.
- `core/tabs/tabs.toml` defines the ordered top-level tabs.
- Each `core/tabs/<tab>/tab_data.toml` defines the menu tree for that tab.
- `core/src/inner.rs` defines the accepted TOML schema and script-loading
behavior.
- `core/tabs/common-script.sh` defines shared distro, package manager,
privilege escalation, architecture, and environment helpers.
- `core/tabs/common-service-script.sh` defines shared init-system helpers.
- `tui/src/running_command.rs` defines how commands are composed and executed.
- `tui/src/state.rs` defines 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 --short` before 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`, and `xtask`.
- 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`, or `panic` calls 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/bash` explicitly.
- 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:
```sh
. ../common-script.sh
```
Adjust the number of `..` components for nested directories.
- Use `common-script.sh` helpers instead of duplicating package manager,
architecture, escalation, command detection, or distro detection logic.
- Source `common-service-script.sh` when managing services across init systems.
- Call `checkEnv` before relying on values such as `PACKAGER`,
`ESCALATION_TOOL`, `ARCH`, or `DTYPE`.
- Quote variable expansions unless intentional word splitting is required.
- Use `printf` rather than `echo` for portable formatted output.
- Use `command_exists` for 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
1. Place the script under the most appropriate `core/tabs/<tab>/` directory.
2. Reuse shared helpers and support all practical package managers already
handled by `common-script.sh`.
3. Add or update the matching entry in that tab's `tab_data.toml`.
4. Provide a clear `name`, useful `description`, one of `script`, `command`, or
`entries`, and accurate `task_list` flags.
5. Add `preconditions` when the entry only works on specific distros,
environments, filesystems, commands, display servers, or architectures.
6. Set `multi_select = false` for interactive, destructive, rebooting,
long-running, or state-dependent operations that should not be queued.
7. Run `cargo xtask docgen` when menu entries or descriptions change.
8. Validate the script and the Rust catalog loader.
The supported task flags are:
- `D`: disk modification
- `FI`: Flatpak installation
- `FM`: file modification
- `I`: privileged installation
- `K`: kernel modification
- `MP`: package manager action
- `RP`: package removal
- `SI`: full system installation
- `SS`: systemd or service action
- Prefixing a flag with `P` indicates 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: `script` or
`command`.
- Every directory entry uses `entries`.
- Prefer scripts over long inline `command` values.
- Keep names stable when possible because config-file `auto_execute` resolves
commands by display name.
- Use preconditions to hide unsupported entries rather than letting users
discover incompatibility after execution.
- Parent `multi_select = false` applies to all descendants.
- Keep tab data consistently ordered. Use `sort-tomlfiles.sh` when the change
requires catalog sorting.
## Validation
Run the smallest relevant checks, then broaden them for cross-cutting changes.
For Rust changes:
```bash
cargo fmt --all --check
cargo test --no-fail-fast --package linutil_core
cargo clippy -- -Dwarnings
```
For shell changes:
```bash
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:
```bash
cargo test --no-fail-fast --package linutil_core
cargo xtask docgen
git diff --check
```
For TUI behavior, also run:
```bash
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.
+384
View File
@@ -0,0 +1,384 @@
# Linutil Technical Specification
## 1. Product definition
Linutil is a terminal-based Linux utility that provides a searchable,
organized catalog of system setup, application installation, gaming, security,
and maintenance tasks.
The product consists of:
- A Rust TUI that presents commands, previews their contents, confirms
execution, and displays live terminal output.
- A Rust core library that loads command metadata, filters unsupported entries,
and embeds the complete script catalog in the application binary.
- Portable shell scripts that implement the operating-system changes.
- Shared shell libraries that centralize Linux distribution, package manager,
privilege escalation, architecture, and service-manager behavior.
"Universal" means the architecture supports multiple Linux distributions,
package managers, architectures, init systems, and desktop environments. It
does not mean every command must work on every Linux system. Unsupported
commands must be hidden by metadata or fail early with a useful explanation.
## 2. Goals
Linutil must:
1. Provide one discoverable TUI for common Linux administration and setup
tasks.
2. Ship as a self-contained binary with its command catalog and scripts
embedded at compile time.
3. Support distro-independent workflows where practical and explicit
distro-specific workflows where required.
4. Give users a preview and confirmation boundary before system-changing
commands run.
5. Preserve interactive terminal behavior for prompts, colors, progress, and
full-screen command-line tools.
6. Reuse shared shell behavior instead of duplicating package-manager and
privilege logic across scripts.
7. Make new utilities primarily data-and-script additions rather than Rust UI
changes.
8. Clearly communicate privileged, destructive, package-management, service,
kernel, disk, and file operations.
## 3. Non-goals
Linutil is not:
- A replacement for a distribution's package manager.
- A general-purpose shell or arbitrary command launcher.
- A daemon or background configuration-management system.
- A guarantee that every utility supports every Linux distribution.
- A mechanism for silently bypassing package signatures, privilege controls,
user confirmation, or platform compatibility checks.
- A substitute for backups before disk, bootloader, kernel, account, or
destructive filesystem operations.
## 4. System architecture
### 4.1 Workspace
The Cargo workspace contains:
| Component | Responsibility |
| --- | --- |
| `core` | Data model, TOML loading, precondition evaluation, embedded assets, temporary extraction, and user config |
| `tui` | CLI, rendering, navigation, search, preview, confirmation, selection, PTY execution, and output display |
| `xtask` | Repository maintenance and generated documentation |
| `core/tabs` | Tab definitions, utility metadata, shared shell libraries, and executable scripts |
### 4.2 Runtime flow
1. `linutil_core` embeds `core/tabs/` into the binary at compile time.
2. On startup, the embedded tree is extracted to a temporary directory.
3. `tabs.toml` determines the ordered list of tab directories.
4. Each tab's `tab_data.toml` is parsed into a tree of `ListNode` values.
5. Preconditions are evaluated against the current machine when validation is
enabled.
6. Unsupported leaves and empty parent categories are removed.
7. The TUI displays the resulting tabs and command tree.
8. The user may inspect descriptions and source previews before selection.
9. Selected commands pass through the confirmation flow.
10. The TUI composes the commands into a shell program and runs it in a PTY.
11. Output is rendered live until the process succeeds, fails, or is
interrupted.
12. The temporary script tree remains alive for the lifetime of the tab list
and is removed when it is dropped.
### 4.3 Data model
The core command model has three forms:
- `Command::Raw(String)`: A short inline shell command.
- `Command::LocalFile`: An extracted script, its shebang-derived executable,
and executable arguments.
- `Command::None`: A non-executable directory node.
A `Tab` owns a tree of `ListNode` values. Each node contains:
- Display name.
- User-facing description.
- Command form.
- Task flag string.
- Multi-select eligibility.
Display names should be unique among executable leaves because config-file
automation resolves entries by name.
## 5. Command catalog
### 5.1 Top-level tabs
`core/tabs/tabs.toml` contains an ordered `directories` array. Every listed
directory must contain a valid `tab_data.toml`.
Adding a top-level tab requires:
1. A new directory under `core/tabs/`.
2. A valid `tab_data.toml`.
3. An entry in `core/tabs/tabs.toml`.
4. At least one supported executable leaf at runtime.
### 5.2 Tab schema
Each tab data file contains:
```toml
name = "Tab Display Name"
[[data]]
name = "Category or Command"
```
An entry must define exactly one of:
- `entries`: Nested child entries.
- `script`: A script path relative to the tab directory.
- `command`: An inline shell command.
Optional entry fields are:
- `description`: User-facing explanation.
- `preconditions`: Conditions controlling visibility.
- `task_list`: Space-separated task flags shown in the TUI.
- `multi_select`: Whether the entry may participate in a queued command set.
The default is `true`.
Script paths may reference shared scripts elsewhere under `core/tabs/`, but
the resolved path must exist when the catalog is loaded.
### 5.3 Preconditions
All preconditions on an entry must pass for it to remain visible.
Supported data sources are:
| Type | Behavior |
| --- | --- |
| `environment` | Compare an environment variable with the provided values |
| `containing_file` | Check a file's contents for all provided strings |
| `command_exists` | Check all provided commands on `PATH` |
| `file_exists` | Check all provided paths as files |
`matches = true` requires a match. `matches = false` requires the inverse.
Preconditions should be used for objective platform capabilities such as a
package manager, distro marker, display-server session, required executable,
or required file. They are visibility filters, not a replacement for runtime
validation inside scripts.
### 5.4 Task flags
Task flags warn users about the important effects of a command:
| Flag | Meaning |
| --- | --- |
| `D` | Disk modification |
| `FI` | Flatpak installation |
| `FM` | File modification |
| `I` | Privileged installation |
| `K` | Kernel modification |
| `MP` | Package manager action |
| `RP` | Package removal |
| `SI` | Full system installation |
| `SS` | Service or systemd action |
| `P*` | The marked action requires privileges |
Flags are informational and do not grant privileges or replace confirmation.
## 6. Script contract
### 6.1 Interpreter
Scripts should use POSIX shell and `#!/bin/sh -e` by default. Scripts requiring
Bash syntax must declare Bash explicitly.
If no shebang is present, the core defaults to `/bin/sh -e`. When executable
validation is enabled, a script with an unavailable or non-executable shebang
interpreter is omitted.
### 6.2 Working directory and shared files
Before a local script runs, the TUI changes to the script's extracted parent
directory. Relative imports and sibling assets must be written for that
working directory.
General-purpose scripts should source `common-script.sh`. Scripts that manage
services should also source `common-service-script.sh`. More specialized
families may define an additional shared helper when it removes meaningful
duplication.
### 6.3 Environment initialization
Scripts using the general shared environment must call `checkEnv` before
depending on its results.
The shared environment is responsible for detecting or defining:
- CPU architecture.
- Supported privilege escalation tool.
- Required baseline commands.
- Supported package manager.
- Current Linux distribution identifier.
- Superuser group access.
- Current-directory writability.
- Arch User Repository helper where relevant.
Scripts must still validate feature-specific requirements and unsupported
states.
### 6.4 Distribution portability
For a generally available utility:
- Use the detected `PACKAGER`.
- Handle appropriate package names and flags per package manager.
- Prefer native distribution packages.
- Use Flatpak or another portable method as an intentional fallback, not an
accidental catch-all when the platform is unknown.
- Report unsupported distributions or architectures before making changes.
For a distro-specific utility:
- Place it in a clearly named distro category.
- Add metadata preconditions.
- Recheck critical assumptions in the script before changing the system.
### 6.5 Privilege and safety
Scripts must:
- Run unprivileged by default.
- Apply `ESCALATION_TOOL` only to commands that require elevated access.
- Explain destructive or irreversible choices before execution.
- Avoid overwriting user configuration without a backup, merge, or explicit
prompt.
- Check existing state so repeated execution is safe when practical.
- Stop on unsupported or ambiguous conditions.
- Avoid embedding credentials or collecting user secrets.
- Avoid logging sensitive input.
- Clean temporary files and partial downloads.
- Verify downloaded artifacts when upstream checksums or signatures exist.
Disk, bootloader, kernel, account-removal, and broad cleanup utilities should
set `multi_select = false`.
### 6.6 User interaction
Scripts run in a PTY and may prompt users. Prompts must:
- State the action and meaningful consequences.
- Accept predictable input.
- Provide a safe default for risky operations.
- Remain usable in the TUI's terminal viewport.
- Exit nonzero on failure or cancellation when no work was completed.
## 7. TUI requirements
The TUI must provide:
- Tab and hierarchical command navigation.
- Search and filtering.
- Command descriptions.
- Source preview for raw commands and local scripts.
- Multi-selection for compatible commands.
- Confirmation before execution unless an explicit, documented bypass applies.
- Live PTY output with terminal color support.
- Scrolling and process interruption.
- Clear success and failure status.
- A warning when Linutil itself is run as root unless explicitly bypassed.
- A minimum-size check with an explicit bypass option.
Raw and local commands selected together execute in selection order within one
shell program. A failure must be visible to the user and reflected in the final
command status.
## 8. Configuration and automation
Linutil accepts a TOML configuration file with:
- `auto_execute`: Display names of executable leaves.
- `skip_confirmation`: Whether confirmation is skipped.
- `size_bypass`: Whether terminal-size enforcement is bypassed.
Unknown configuration fields are errors.
Automation must not cause an unsupported catalog entry to appear. Missing or
filtered command names are ignored by the current loader and should be
reported more explicitly in a future compatibility-preserving improvement.
Command display names are therefore part of the user-facing automation
interface and should not be renamed casually.
## 9. Documentation
User-visible command additions and description changes must update generated
walkthrough content using:
```bash
cargo xtask docgen
```
Generated documentation must not be edited as the sole source of a change.
Architecture documentation should remain consistent with `SPEC.md` and the
code.
## 10. Quality requirements
### 10.1 Rust
Required checks for Rust changes:
```bash
cargo fmt --all --check
cargo test --no-fail-fast --package linutil_core
cargo clippy -- -Dwarnings
```
Parser and filtering changes require focused unit tests. TUI behavior changes
require either focused tests or documented interactive validation.
### 10.2 Shell
Changed shell scripts must pass ShellCheck. POSIX shell scripts should also
pass `checkbashisms`.
Scripts should be tested without performing unintended system changes. Use
syntax/static checks, controlled containers or virtual machines, mocked
commands, and representative supported distributions as appropriate.
### 10.3 Catalog
Catalog changes must prove that:
- TOML parses successfully.
- Every referenced script exists.
- Required interpreters are valid under normal validation.
- Preconditions retain intended entries and remove unsupported entries.
- Generated documentation is current.
The core test suite is the minimum automated validation for catalog changes.
## 11. Acceptance criteria for a new utility
A utility is complete when:
1. It has a focused script or appropriately short raw command.
2. It reuses shared environment and service helpers where applicable.
3. It supports the intended distributions and rejects unsupported ones.
4. Its metadata includes an accurate name, description, path, task flags,
preconditions, and multi-select policy.
5. It is previewable and executable from the TUI.
6. Privileged and destructive operations are explicit.
7. Re-running it does not cause avoidable damage or duplication.
8. Relevant Rust, TOML, shell, and generated-documentation checks pass.
9. Platform limitations and residual risks are documented.
## 12. Future compatibility
Architectural extensions should preserve the data-driven utility model.
Potential additions such as richer capability detection, structured command
results, dry-run support, per-command privilege declarations, or stronger
download verification should extend the catalog and core contracts rather
than hard-code individual utilities into the TUI.