cd /news/ai-agents/case-study-photoframe-3-0-0 · home › topics › ai-agents › article
[ARTICLE · art-146922] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Case study: photoframe 3.0.0

A developer forked the abandoned photoframe Raspberry Pi project in September 2025 and shipped v3.0.0 on October 6, 2026, its first stable release, adding Python 3 support, Immich as the primary photo source, current Raspberry Pi OS display handling, and a flashable SD card image. The fork, developed with AI agents under a strict rule that nothing is pushed, tagged, released, or sent upstream until it has run on Pi hardware, spans 65 files and 43 merged pull requests against the original project's master. QA on a Pi 4 and a second 32-bit board caught three release-candidate bugs that were fixed and re-verified the same day.

by read5 min views2 publishedOct 7, 2026

Thirteen months from forking an abandoned Raspberry Pi project to its first stable release, and why the release only counted once a real Pi had run it.

photoframe is Henric Andersson's Raspberry Pi project that shows random photos from Google Photos like a picture frame. In 2025 Google cut the Photos Library API down to photos an app uploaded itself, and the frame had nothing left to read. I self-host Immich, so I forked the project in September 2025 to teach it Immich.

On October 6, 2026, the fork shipped v3.0.0, its first stable release: Python 3, Immich as the main photo source, display handling for current Raspberry Pi OS, and a flashable SD card image. Against the original project's master that is 65 files, 4,686 lines added and 1,662 removed, across 43 merged pull requests.

The code was written with AI agents. The release discipline was not optional, and it came from one bad morning in April: nothing gets pushed, tagged, released, or sent upstream until it has run on Pi hardware. The worst bugs in this write-up were caught by that rule.

I covered the early part in The Photo Frame I Didn't Have Time to Fix. This is the whole arc, through 3.0.0. Three things were true at once:

tvservice, the tool photoframe used to find out what display it was plugged into.CLAUDE.md, in capitals: "NEVER modify existing routes for Immich features." Immich got its own /immichconfig route. September 2025. The first Immich commit landed on a Friday. By Monday the fork existed and a pull request offering the work upstream was open. The agents ran as roles: an architect wrote phased roadmaps, I approved them as the product manager, a developer built, and a QA agent tested. When the developer agent added handlers to server.py anyway, the next commit was titled "Revert unauthorized changes."

April 2026: the morning it went too far. I came back for a real release push. On April 11, inside about eight minutes, an automated session rebased the Python 3 branch onto master, pushed master, created a v3.0.0 tag and release, created a dev branch, forked the Raspberry Pi image builder, and closed my upstream pull request by deleting the branch behind it. None of it had run on a Pi.

The answer was a written rollout plan with an eight-row damage assessment and one gate:

Nothing gets pushed, tagged, released, or sent upstream until it's been tested on Pi hardware.

That gate stayed in force through every release after it.

The image. A fork of pi-gen builds a headless Lite image: flash it, put your wifi details in wifi-config.txt on the boot partition, and the frame comes up with no SSH. Before rc1, a Pi Zero W driving a Toshiba laptop panel at 1366x768 through an HDMI-to-LVDS board booted that image, joined wifi from the file, and ran an Immich slideshow with HEIC photos without running out of memory. CI builds the same image under QEMU in about 48 minutes. Every photoframe tag now needs a matching pi-gen tag.

rc1, April 18. Tested on a Pi 3B+ with Immich. The same week the Python 3 work went upstream again as a 30-commit pull request, which is still open.

rc2, October 1, and the next eight hours. rc2 went out a little after midnight Eastern. By that morning, QA on a Pi 4 flashed with an image built from the rc2 commit had filed three bugs, and a second 32-bit board confirmed all three:

/boot/firmware; photoframe looked in /boot. The rc1 and rc2 images both shipped an open settings page. All three were fixed and re-verified on the Pi 4 the same afternoon.

October 2 to 5: QA and review until it was boring. From rc2 to release, thirty issues and thirteen pull requests were opened. A few that stand out:

install.sh died at its pip step on Bookworm. The fix installs everything from apt, tested in an emulated Bullseye and on a Pi 5 running Trixie. Forcing pip with --break-system-packages was ruled out.config.txt, because the path had been relative since the Python 3 port. Fixing it led to the question of power loss mid-write. An fsck of the boot partition two seconds after a write found I made the scope calls: tvservice is deprecated but its code path stays where the command exists, and updater bugs move to 3.1.

October 6: 3.0.0. rc2 was recut on October 5 with the remediation merged. v3.0.0 was tagged the next day at the same commit. Between the last release candidate and the stable release, nothing changed but the image builder's branch and the release notes. The stable release is the candidate that survived.

/proc/meminfo and ImageMagick's limits allow it. HEIC works. A Browse button lists your albums, names match without regard to case, and the service retries with backoff when the server is unreachable./control/screenon and /control/screenoff over HTTP.

Measure Result
Fork to first stable release Sept 8, 2025 to Oct 6, 2026
Change against the original master 65 files, +4,686 / -1,662 lines
Merged pull requests at release 43
Issues and PRs opened between rc2 and 3.0.0 30 and 13
Bugs from the first Pi 4 rc2 test, found to fixed and re-verified about 2 hours, same day
Peak memory, Pi 3B+ at 800x480 about 1,061 MB down to about 494 MB
Supported OS Bullseye, Bookworm, Trixie; 32 and 64 bit
Supported Immich v2.x (v3 planned for 3.1)

The release notes list six known issues, all planned for 3.1. Two of them, rotation ignored under the KMS display driver and a cropped picture after an HDMI replug, were found on hardware and documented, with a workaround where one exists, instead of being guessed at.

Start with the hardware gate. It arrived in April because an agent shipped a release nobody had run; it belonged in the September roadmap next to the route rule. And write the final-release order into RELEASE.md before cutting the first final release. On release day the 3.0.0 branch was made before master was fast-forwarded. It came out right, but the order lived in a session, not in the doc.

── more in #ai-agents 4 stories · sorted by recency
── more on @henric andersson 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/case-study-photofram…] indexed:0 read:5min 2026-10-07 · —