Skip to content
Back to skills

Batocera Maintenance

BSecurity

Use when keeping a Batocera cabinet healthy over time: running scripts or scheduled jobs at boot and on an interval without cron, the custom_service boot-service pattern (which replaced custom.sh in v43), backing up /userdata to another machine over SSH, and upgrading between major Batocera versions (v42 to v43 and similar) including the ROM-directory renames and post-upgrade checklist. Covers why there is no crond, the backup-before-upgrade doctrine, and catch-up scheduling. Not for performa...

  • 4 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 5, 2026
ai-agentsgobashperformance

Security analysis

B88/100
  • criticalModifies startup scripts or system services for persistence

Pro scans all 3 files and shows the line behind each finding

Scanned September 5, 2026

npx -y skills add t3chnaztea/batocera-skills --skill batocera-maintenance --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Batocera Maintenance?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Batocera Maintenance
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/t3chnaztea-batocera-maintenance/badge)](https://www.skillsdirectory.com/skills/t3chnaztea-batocera-maintenance)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: batocera-maintenance
description: >-
  Use when keeping a Batocera cabinet healthy over time: running scripts or
  scheduled jobs at boot and on an interval without cron, the custom_service
  boot-service pattern (which replaced custom.sh in v43), backing up /userdata
  to another machine over SSH, and upgrading between major Batocera versions
  (v42 to v43 and similar) including the ROM-directory renames and post-upgrade
  checklist. Covers why there is no crond, the backup-before-upgrade doctrine,
  and catch-up scheduling. Not for performance tuning (batocera-tuning).
compatibility: Requires SSH access to a Batocera host (tested on v41-v43).
---

# Batocera Maintenance

Keeping the cabinet healthy: running things at boot and on a schedule, backing up
what matters, and surviving version upgrades. Assumes the connection pattern and
filesystem model from `batocera-ops`.

## There is no crond — use a boot service

Batocera does **not** run a general-purpose `crond`. Don't write a crontab and
assume it fires; it won't. The mechanism for "run this at boot / on a schedule"
is a **boot service**.

Since v43, the entry point is `/userdata/system/services/custom_service` (it
replaced `/userdata/system/custom.sh`; the upgrade auto-converts an existing
`custom.sh`). A service is a script Batocera runs at boot with a `start`
argument. Enable/inspect services:

```bash
SSHB "batocera-services list"
SSHB "cat /userdata/system/services/custom_service"
```

### Scheduling without cron: the boot-loop pattern

To run something periodically, the service launches a background loop that sleeps
and re-checks. This is how the cabinet does hourly/daily/monthly work with no
cron:

```bash
# inside custom_service, on the 'start' case:
(
  while true; do
    # hourly re-assert (e.g. CPU governor; see batocera-tuning)
    /etc/init.d/S18governor start 2>/dev/null

    # once-a-day / once-a-month gating: compare a stamp file to `date`
    stamp=/userdata/system/.last-monthly-backup
    if [ "$(cat "$stamp" 2>/dev/null)" != "$(date +%Y-%m)" ]; then
      /userdata/system/tools/backup-to-remote.sh && date +%Y-%m > "$stamp"
    fi

    sleep 3600
  done
) &
```

Key ideas:
- **Catch-up, not clock-exact.** Gate on "has this period's job run yet?"
  (compare a stamp to `date +%Y-%m` or `%Y-%m-%d`), not on "is it exactly 3 AM?".
  A cabinet that's powered off at 3 AM would never run a clock-exact job; the
  stamp approach runs it on the first boot of the new period instead.
- **Idempotent body.** The loop may re-enter; the gated job must be safe to skip
  when already done this period.
- **Don't park schedulable scripts in `/userdata/system/scripts/`** — ES invokes
  executables there as game event hooks (see `batocera-ops` → emulationstation).
  Put tools in `/userdata/system/tools/` or similar and call them from the
  service.

After editing `custom_service`, back it up first and test the loop logic before
relying on it (run the gated command by hand once).

## Backups

The doctrine: **push-only, dry-run-first, over SSH.** The cabinet pushes a copy
of the important parts of `/userdata` to another machine; you always dry-run an
rsync before letting it delete anything. Architecture, what to include/exclude,
and the catch-up schedule are in [references/backup.md](references/backup.md).

**Back up before every upgrade.** A major-version upgrade is the highest-risk
routine event; a fresh backup of saves/system/bios (and ideally decorations/
shaders/themes) is the difference between a 10-minute rollback and a rebuild.

## Version upgrades

Major Batocera upgrades rename ROM directories, change the boot-service model,
and swap emulators — each of which silently breaks things if you don't migrate.
The v42→v43 migration (representative of the class) with the full rename table
and a post-upgrade checklist is in
[references/v42-to-v43.md](references/v42-to-v43.md). The short doctrine:

1. Full backup first (above).
2. Upgrade.
3. Walk the post-upgrade checklist: move content out of renamed/stub dirs,
   migrate moved saves, confirm the boot service converted, and **re-check the
   CPU governor** (a v43 build can boot stuck in powersave — see
   `batocera-tuning`).
4. Verify a game from each major system actually launches before calling it done.

Files in this skill

  • SKILL.md4.2 KB
  • references/backup.md3.3 KB
  • references/v42-to-v43.md3.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.