Modulos de restauracion: - bootstrap: instala yq, age y dependencias base (curl, wget, git, nano, gpg) - ssh: descifra e instala claves SSH desde secrets/sshKeys.tar.gz.age - registry: aplica paquetes apt/snap/flatpak, dotfiles, servicios y configs Docker - thunderbird: instala Thunderbird snap y restaura perfil desde ZIP - claudeCode: configura repositorio apt de Anthropic e instala claude-code - easyEffects: restaura configuracion y presets desde ZIP - wireplumber: restaura dispositivo Bluetooth por defecto y perfiles de audio - cups: restaura impresoras y drivers PPD desde ZIP Scripts de captura (correr antes de push): - scripts/encryptSsh.sh: cifra ~/.ssh con age - scripts/thunderbird/capture.sh: captura perfil de Thunderbird snap - scripts/easyEffects/capture.sh: captura config de EasyEffects flatpak - scripts/wireplumber/capture.sh: captura estado de WirePlumber - scripts/cups/capture.sh: captura impresoras CUPS y PPDs (requiere sudo) Registro de aplicaciones (config/registry.yaml): - 9 paquetes apt, 1 snap (dbeaver-ce), 22 flatpaks incluyendo VSCodium, Bitwarden, Inkscape, LibreOffice, OBS Studio, Nextcloud Desktop, entre otros Secretos incluidos: - secrets/sshKeys.tar.gz.age: claves SSH cifradas con age - secrets/thunderbirdProfile.zip: perfil de Thunderbird sin emails ni cache - secrets/easyEffectsConfig.zip: ajustes y presets de salida de audio - secrets/wireplumberState.zip: estado de audio incluyendo auriculares Bluetooth - secrets/cupsConfig.zip: 5 impresoras configuradas con sus drivers Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
10 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this project is
STP (Sistema de Transferencia Personal) is a personal machine-setup automation tool. Running it on a fresh Ubuntu LTS install configures the machine to match the owner's environment: packages, PPAs, SSH keys, dotfiles, audio (PipeWire), video drivers, systemd services, and application configurations. Files (documents, media) are handled separately by Nextcloud and are out of scope.
Key commands
# First-time setup on a new machine
bash <(curl -fsSL https://gitea.mateosaldain.uy/mateo/stp/raw/branch/main/bootstrap.sh)
# Run all modules
bash stp.sh
# Run a single module
bash stp.sh --module registry
# Skip specific modules
bash stp.sh --skip ssh
# List modules in execution order
bash stp.sh --list
Architecture
Execution flow: bootstrap.sh → clone repo from Gitea → stp.sh → modules in the order defined by config/modules
stp.sh reads module order from config/modules (plain text, one name per line, # comments — no yq required at this level), then runs each modules/<name>.sh as a subprocess inheriting the exported stpRoot variable.
Modules (modules/<name>.sh) source lib/log.sh, lib/utils.sh, and optionally lib/yaml.sh. All modules are idempotent — they check current state before acting.
Current modules in execution order:
bootstrap— installsyqandage(required by all other modules)ssh— decryptssecrets/sshKeys.tar.gz.agewithageand installs keys into~/.sshregistry— readsconfig/registry.yamland applies every entry (packages, dotfiles, services, drivers, audio)thunderbird— installs Thunderbird (snap) and restores profile fromsecrets/thunderbirdProfile.zipclaudeCode— configures the Anthropic apt repository and installsclaude-codeeasyEffects— restores EasyEffects config and presets fromsecrets/easyEffectsConfig.zipwireplumber— restores WirePlumber state (default audio device, Bluetooth profiles) fromsecrets/wireplumberState.zipcups— restores CUPS printer definitions and PPD drivers fromsecrets/cupsConfig.zip
modules/registry.sh — the main workhorse. Reads all entries from config/registry.yaml and dispatches each one to a handler based on its type. Supported types: ppa, apt, snap, flatpak, dotfile, service, pipewire, video, docker.
config/registry.yaml — the single list of everything to configure on the machine. Adding a new entry is all that's needed to have STP apply it on the next run. Entries are idempotent — each handler checks current system state before acting.
config/settings.yaml — machine-independent settings: Gitea host/user/repo coordinates, user identity (name, email, username), and dotfiles backup flag.
lib/ — shared helpers sourced by modules:
log.sh—log::step,log::info,log::ok,log::warn,log::error; internal emit vialog::emitutils.sh—util::cmdExists,util::isAptInstalled,util::isSnapInstalled,util::isFlatpakInstalled,util::isYamlNull,util::confirm,util::requireSudo,util::keepSudoAlive,util::aptUpdateOnceyaml.sh— thin wrapper aroundyqv4:yaml::get,yaml::getArray,yaml::has
dotfiles/ — mirrors $HOME/ structure. Files referenced by type: dotfile entries in the registry become symlinks in the real home directory. If a real file already exists at the destination, it is renamed to ${destination}.stpbackup before the symlink is created.
docker/ — stores Docker configurations (Compose files, Dockerfiles, etc.) organized by service: docker/<id>/. Files are symlinked to the configured destination (default ~/docker/<id>). If autostart: true, docker compose up -d is run after deploying.
secrets/ — encrypted and configuration backups, all safe to commit:
sshKeys.tar.gz.age—age --passphrase-encrypted tar of~/.sshthunderbirdProfile.zip— Thunderbird profile (accounts, filters, extensions; excludes emails and cache)easyEffectsConfig.zip— EasyEffects settings and output presetswireplumberState.zip— WirePlumber state (default audio sink, Bluetooth device profiles, per-app volumes)cupsConfig.zip— CUPSprinters.confand PPD driver files for all configured printers
scripts/ — capture scripts to run on the current machine before pushing:
encryptSsh.sh— encrypts~/.sshintosecrets/sshKeys.tar.gz.agethunderbird/capture.sh— captures Thunderbird Snap profile intosecrets/thunderbirdProfile.zipeasyEffects/capture.sh— captures EasyEffects Flatpak config intosecrets/easyEffectsConfig.zipwireplumber/capture.sh— captures WirePlumber state intosecrets/wireplumberState.zipcups/capture.sh— captures CUPS printer config intosecrets/cupsConfig.zip(requires sudo)
config/keys/ — GPG public keys for third-party apt repositories:
claude-code.asc— Anthropic signing key for the Claude Code apt repository
.claude/ — Claude Code project configuration:
settings.json— allowed bash commands for this projectstyle.md— style guide (camelCase, Clean Code, no dry-run)commands/new-module.md→/new-module <name>— scaffolds a new modulecommands/addEntry.md→/addEntry <description>— adds an entry to the registrycommands/encrypt-ssh.md→/encrypt-ssh— guides SSH key encryption
Currently saved configurations
Packages (via registry)
| ID | Type | Package |
|---|---|---|
| curl, wget, git, vim, htop, tree, unzip | apt | same as ID |
| buildEssential | apt | build-essential |
| virtualbox | apt | virtualbox |
| dbeaverCe | snap | dbeaver-ce |
| vscodium | flatpak | com.vscodium.codium |
| filezilla | flatpak | org.filezillaproject.Filezilla |
| angryIpScanner | flatpak | org.angryip.ipscan |
| anydesk | flatpak | com.anydesk.Anydesk |
| bitwarden | flatpak | com.bitwarden.desktop |
| bottles | flatpak | com.usebottles.bottles |
| bruno | flatpak | com.usebruno.Bruno |
| nextcloudDesktop | flatpak | com.nextcloud.desktopclient.nextcloud |
| easyEffects | flatpak | com.github.wwmm.easyeffects |
| flatseal | flatpak | com.github.tchx84.Flatseal |
| warehouse | flatpak | io.github.flattool.Warehouse |
| freecad | flatpak | org.freecad.FreeCAD |
| hidamari | flatpak | io.github.jeffshee.Hidamari |
| inkscape | flatpak | org.inkscape.Inkscape |
| libreoffice | flatpak | org.libreoffice.LibreOffice |
| logseq | flatpak | com.logseq.Logseq |
| obsStudio | flatpak | com.obsproject.Studio |
| openshot | flatpak | org.openshot.OpenShot |
Application configurations (via modules)
| Module | Secret | What is restored |
|---|---|---|
ssh |
secrets/sshKeys.tar.gz.age |
SSH keys with correct permissions |
thunderbird |
secrets/thunderbirdProfile.zip |
Accounts, filters, extensions (Snap; excludes emails) |
claudeCode |
config/keys/claude-code.asc |
Anthropic apt repo + claude-code package |
easyEffects |
secrets/easyEffectsConfig.zip |
Settings DB and output presets (HB-Flat, HB-Lite, HB-Mid, Heavy Bass) |
wireplumber |
secrets/wireplumberState.zip |
Default audio sink (Bluetooth headphones), A2DP profile, per-app volumes |
cups |
secrets/cupsConfig.zip |
5 printers: Epson L8050 WiFi, Canon MP230, Samsung M2020, POS80, Cups PDF |
Adding a new package
Add an entry to config/registry.yaml. The registry handles: ppa, apt, snap, flatpak, dotfile, service, pipewire, video, docker.
Use /addEntry <description> for guided entry creation.
For complex setups that require steps beyond what the registry types support (GPG key import, profile restoration, custom installers), create a dedicated module with /new-module <name>.
Adding a new application configuration backup
- Create
scripts/<appName>/capture.sh— reads from the app's data directory and writes a ZIP tosecrets/ - Create
modules/<appName>.sh— checks if app is installed, checks if config already exists, restores from ZIP - Add
<appName>toconfig/modulesafterregistry - Run
bash scripts/<appName>/capture.shon the current machine - Commit the generated file in
secrets/
Restoration is automatic on the next stp.sh run. All modules are idempotent — if the config already exists on the target machine, the restore is skipped.
Updating a saved configuration
Re-run the corresponding capture script and commit the updated file:
bash scripts/thunderbird/capture.sh && git add secrets/thunderbirdProfile.zip
bash scripts/easyEffects/capture.sh && git add secrets/easyEffectsConfig.zip
bash scripts/wireplumber/capture.sh && git add secrets/wireplumberState.zip
bash scripts/cups/capture.sh && git add secrets/cupsConfig.zip
bash scripts/encryptSsh.sh && git add secrets/sshKeys.tar.gz.age
Restoring on a new machine
# 1. Bootstrap (clones repo and runs all modules)
bash <(curl -fsSL https://gitea.mateosaldain.uy/mateo/stp/raw/branch/main/bootstrap.sh)
The bootstrap runs all modules automatically. Each module skips gracefully if its secret is missing or if the configuration is already in place.
After WirePlumber restore, restart the session manager to apply the Bluetooth device as default:
systemctl --user restart wireplumber
Environment variables
| Variable | Default | Effect |
|---|---|---|
stpDir |
~/.stp |
Clone destination used by bootstrap.sh |
stpLogFile |
/tmp/stp-<timestamp>.log |
Path for the full execution log |
Style guide (enforced on all scripts)
See .claude/style.md for the full guide. Key rules:
- camelCase everywhere: variables, functions, file names — no underscores, no hyphens in identifiers
- No abbreviations:
packageNamenotpkg,serviceNamenotsvc,sourceFilenotsrc;temporaryDirectorynottempDir,sourceDirectorynotsourceDir - Small functions with one responsibility: extract any named block into a function
- Boolean functions named as questions:
printersAreConfigured(),wireplumberStateExists() - No
--dry-run: the system is idempotent — it checks state before acting - No
util::runwrapper: call commands directly - Comments only for WHY, never for WHAT
- Pre-increment
((++n))not post-increment((n++))— post-increment of 0 exits with code 1 underset -e