Raspberry Pi Projects skill for Codex

Pi projects that boot, restart and survive power cuts. Codex writes Raspberry Pi code for current Raspberry Pi OS instead of 2019 tutorials: gpiozero rather than RPi.GPIO on the Pi 5, /boot/firmware paths, venvs that can still see apt hardware libraries, and a systemd unit that restarts the app without running it as root. It checks throttling and power before blaming the code.

  • Embedded & IoT
  • $raspberry-pi
  • 167 lines
  • 2 files
  • ~1,600 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- raspberry-pi

Installs to ~/.agents/skills/raspberry-pi/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $raspberry-pi, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Builds Raspberry Pi projects on Raspberry Pi OS Bookworm - GPIO with gpiozero and lgpio (Pi 5 safe), I2C/SPI enabled in /boot/firmware/config.txt, Python in a venv under PEP 668, systemd services that start on boot and restart on failure, and SD-card-friendly logging. Use when a Pi script fails on a Pi 5, RPi.GPIO errors, a sensor is missing on I2C, a program must run at boot, the Pi throttles or reboots, or the SD card keeps corrupting.

Use it when

  • Porting GPIO code to a Pi 5 or Raspberry Pi OS Bookworm
  • A Python program on the Pi needs to run at boot as a service
  • An I2C or SPI device is not detected on the Pi
  • The Pi throttles, reboots under load or corrupts its SD card

Use something else when

  • The board is a Raspberry Pi Pico microcontroller running MicroPython: use micropython
  • You are hardening a Pi as an internet-facing server: use linux-server-hardening

How to check the result

Reboot the Pi and confirm the service is active, kill the process to see systemd restart it, and check vcgencmd get_throttled returns 0x0 under load.

The mistake it prevents

Running the app with sudo to get GPIO access; add the service user to the gpio and i2c groups instead.

~/.agents/skills/raspberry-pi/SKILL.md

--- name: raspberry-pi description: Builds Raspberry Pi projects on Raspberry Pi OS Bookworm - GPIO with gpiozero and lgpio (Pi 5 safe), I2C/SPI enabled in /boot/firmware/config.txt,… license: MIT ---

Done well means: the project installs on a fresh Raspberry Pi OS image from a script, runs as a supervised systemd service under a non-root user, survives power loss without a corrupted card, and works on both Pi 4 and Pi 5 unless the user said otherwise.

Inspect first

Ask the user to run these on the Pi (Codex usually works on a laptop clone of the repo) and paste the output, or run them yourself if the session is on the Pi:

cat /proc/device-tree/model; echo
cat /etc/os-release | grep VERSION_CODENAME     # bookworm is the current baseline
uname -m                                         # aarch64 vs armv7l
vcgencmd get_throttled                           # 0x0 is healthy
ls /dev/i2c-* /dev/spidev* 2>/dev/null
groups                                           # needs gpio, i2c, spi for non-root access

Read AGENTS.md and any install script before changing dependencies.

Decisions that changed with Bookworm and the Pi 5

Old habitCurrent answer
import RPi.GPIODoes not work on Pi 5. Use gpiozero (default) or lgpio; rpi-lgpio is a drop-in shim for legacy code
/boot/config.txt/boot/firmware/config.txt
sudo pip installRefused (PEP 668). Use a venv; apt install python3-xyz for system packages
raspi-gpiopinctrl get 17, pinctrl set 17 op dh
libcamera-still, picamerarpicam-still, Picamera2
dhcpcd.conf static IPNetworkManager: nmcli connection modify ...
Hard-coded /dev/gpiochip0 or gpiochip4Let gpiozero pick; on the CLI find the chip with gpiodetect and gpioinfo

Python environment

sudo apt install -y python3-venv python3-lgpio python3-gpiozero   # network
python3 -m venv --system-site-packages ~/app/.venv   # sees apt-installed lgpio
~/app/.venv/bin/pip install -r requirements.txt

--system-site-packages lets the venv use the apt builds of hardware libraries, which are compiled for the Pi; installing those through pip often fails without build headers. Package installs need network access; in a Codex sandbox, request approval for that step.

GPIO with gpiozero

from signal import pause
from gpiozero import Button, LED, PWMLED

led = LED(17)                         # BCM numbering, physical pin 11
button = Button(27, pull_up=True, bounce_time=0.05)
fan = PWMLED(18, frequency=25000)

button.when_pressed = led.toggle      # callbacks run on a background thread
fan.value = 0.4
pause()
  • BCM numbers, not physical pins. Put a pin map comment next to each assignment.
  • 3.3 V logic only. A 5 V signal on a GPIO pin damages the SoC; use a divider or level shifter. GPIO pins source a few mA safely; drive relays and motors through a transistor or driver board with a flyback diode.
  • Callback code runs on another thread: guard shared state with a lock or hand events to a queue.Queue.
  • Tests on a laptop: GPIOZERO_PIN_FACTORY=mock with from gpiozero import Device; from gpiozero.pins.mock import MockFactory.

I2C and SPI

sudo raspi-config nonint do_i2c 0     # 0 means enable
sudo raspi-config nonint do_spi 0
sudo reboot
i2cdetect -y 1                        # from i2c-tools

Or add to /boot/firmware/config.txt: dtparam=i2c_arm=on, dtparam=spi=on; extra buses and devices come from overlays (dtoverlay=i2c-rtc,ds3231). Read /boot/firmware/overlays/README for the parameters of each overlay; do not guess them.

Run at boot with systemd

# /etc/systemd/system/plant-monitor.service
[Unit]
Description=Plant monitor
After=network-online.target
Wants=network-online.target

[Service]
User=pi
Group=pi
SupplementaryGroups=gpio i2c
WorkingDirectory=/home/pi/app
ExecStart=/home/pi/app/.venv/bin/python -u main.py
Restart=on-failure
RestartSec=5
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now plant-monitor
journalctl -u plant-monitor -f
  • Never run the app as root to “fix” GPIO permissions; add the user to the groups.
  • Replace the user name with the real account; recent images do not create pi by default.
  • Use a systemd timer instead of cron for periodic jobs, so logs land in the journal.
  • GUI apps that need the desktop session belong in a user service or autostart entry, not a system unit.

Power, heat and storage

  • vcgencmd get_throttled non-zero: bit 0 undervoltage now, bit 16 undervoltage has occurred, bits 2 and 18 throttling. Fix the supply (Pi 5 wants 5 V 5 A for full USB current) before debugging software.
  • vcgencmd measure_temp above about 80 C throttles; add a heatsink or the active cooler.
  • SD wear: reduce writes. Set Storage=volatile in /etc/systemd/journald.conf for appliances, write data to a database with batched commits, and consider the overlay file system (raspi-config, Performance Options) for read-only deployments.
  • For anything important, boot from an SSD (USB or the Pi 5 PCIe) instead of SD.

Exposing it on a network

Change the default password, keep SSH key-only, and do not port-forward the Pi. For remote access use a VPN or tunnel the user already runs. Server hardening detail lives in linux-server-hardening.

Gotchas

  • time.sleep polling loops for buttons miss presses; use gpiozero edge callbacks.
  • Two processes cannot own the same pin; a leftover service holds it. Check systemctl list-units --type=service before debugging “GPIO busy”.
  • The 1-Wire, UART and I2C overlays change pin functions; check pinctrl get when a pin “does nothing”.
  • The primary UART on Pi 3/4 is used by Bluetooth; use /dev/serial0 and enable the UART in raspi-config rather than hard-coding ttyAMA0.

Verification

  • Fresh-image install script runs end to end without manual steps
  • Service starts after sudo reboot and systemctl status shows active
  • Killing the process (sudo kill -9 <pid>) results in an automatic restart
  • vcgencmd get_throttled returns 0x0 under full load
  • Pulling power mid-run and rebooting leaves the app and data intact

Report

**Hardware:** Raspberry Pi 5 4 GB, Bookworm 64-bit, BME280 at 0x76 on I2C-1
**Change:** RPi.GPIO -> gpiozero; venv with system site packages; systemd unit with restart
**Verified:** survives reboot and kill -9; throttled=0x0; user log pasted from journalctl
**Risks:** still on SD card; journald set to volatile, data written once a minute

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Raspberry Pi Projects"
  short_description: "Pi projects that boot, restart and survive power cuts"
  default_prompt: "$raspberry-pi This script used RPi.GPIO and fails on my Pi 5, port it"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem