| name | add-system-action |
| description | Use when adding a new TUI button/action (system action) or a new package-manager backend to personal-os-setup — e.g. "add a button to do X", "support a new package manager", "add a new tab/section". Covers the factory.py section-builder pattern, the managers/_shared.py boilerplate pattern, and the required test additions. |
Adding a system action or package manager backend
This repo's TUI is entirely data-driven from src/personal_os_setup/tasks/factory.py::get_system_action_sections(). Never wire a button directly in frontend/app.py — add it to a section builder in factory.py instead. The frontend renders whatever sections/actions the factory returns generically (one TabPane per section, one Button per action), except for two special-cased sections it knows by name: "Sync dotfiles" (renders the chezmoi tree/toolbar) and "🚀 Start" (renders the onboarding markdown before the doc-link buttons).
For anything involving the chezmoi source tree itself (config/chezmoi/) — adding a run_* script, or explaining why a synced file's companion script didn't fire — see [[chezmoi-scripts]] first; the dotfiles tree's targeted-apply scoping is easy to get wrong.
⚠️ Every SystemAction.run you write or edit here is a real system-mutating command (installs a package, edits/overwrites a config file, changes the default shell, touches drivers, etc.) once a user clicks it in the running app. That's expected — it's the app's whole purpose — but when you (as the coding agent) are implementing/testing one of these, never invoke it against the real host yourself to "check it works." Read the code, run it through the unit-test mocks (see [[run-tests]]), and if you genuinely need to exercise the real command, confirm the exact command with the user first. See CLAUDE.md § "Safety: always confirm before system-mutating actions".
Adding a new action to an existing section