Inspiration
Old apps keep running because switching them off could lose records or expose private files. Low traffic doesn't mean nobody needs the data. Keeping everything running forever costs money and upkeep. Owners need a safe way to say "this can go" and prove nothing important went with it.
What it does
The owner first fixes the requirements: which records must survive, who may see what, and how long to keep it. Then:
- GitLab Duo decides RETIRE, KEEP or SCALE DOWN for each app, against those requirements. Low traffic alone is never a reason to retire. Duo also lists the conditions that must be met before anything is deleted.
- Trusted code proves the data survives. It switches the app to read-only, archives it, restores it into a fresh PostgreSQL database, and checks the records, attachments and access rules.
- One person approves the exact plan: the archive, the snapshot and the resources to remove.
- The controller acts. It switches the front door to the preserved read-only service, checks access, removes only the approved old container and its volume, then checks access again. Running it a second time does nothing.
It's for teams that need to shut down old systems without losing records or breaking privacy rules.
Duo's conditions controlled the deletion
| Duo's condition before retiring | What the record shows |
|---|---|
| Archive reconciliation must pass | Met |
| Fresh restore must verify records and attachments | Met: 8 tables, 3 attachment hashes |
| Access checks for anonymous, reader and admin | Met: 18 of 18 |
| Writes fenced before cutover | Met |
| Owner approval of the exact plan | Met, before any effect |
| Environmental benefit | Not established. No claim. |
Duo also made the right calls on the other two apps: KEEP the one still taking enrolments, and SCALE DOWN the one needed live this quarter.
Try it yourself
- An evidence page with the access table and the cases where Lights Out refuses to delete: https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/43513500/lights-out/-/blob/main/docs/TRY-IT.md
- Or locally, with Python only, no Docker:
python3 -B -m demo.try_itstarts the preserved app and shows that a reader is refused a private file (403), an admin can read it (200), and writes are refused (409).
Live on Google Cloud
The preserved read-only app that replaced the retired one is live on Google Cloud Run: https://lights-out-preserved-918290555848.us-central1.run.app The page lists ready-made requests: a reader is refused a private file (403), an admin can read it (200), and writes are refused (409). It was deployed after the recorded local retirement, from the same verified archive. Fictional data; the demo tokens are public.
How we built it
- Python (standard library) and PostgreSQL 16.6 for the app, archive, restore and read-only replacement.
- GitLab Duo Agent Platform for the decisions and the preservation plan. Duo returned decisions only; it wrote no code.
- GitLab CI restores the exact archive in a fresh PostgreSQL and runs the access checks on the merge request (Draft MR !2).
- SQLite holds the controller's record, so a repeated run can't repeat its effects.
Challenges
The first attempt passed CI but stopped before approval, when GitLab refused a job-detail request. Nothing was deleted, and its temporary resources were cleaned up. After a reviewed fix, the recovery reused the same Duo response with a fresh archive, MR, CI and approval. It's on the record as a recovery, not a first-try success.
Accomplishments we're proud of
- Proof that the data and the access rules survive, checked before anything is deleted.
- Refusals that work: KEEP when writes are still needed, refusal if the plan changes after approval, and no repeat effects.
- One human decision, tied to an exact plan, instead of many small approvals.
What we learned
A backup file isn't preservation. Relationships, attachments, permissions, a fresh restore and an exact approval all matter. The useful line for an agent is between proposing and acting.
Limits (honest)
- A local, disposable fixture app. Not a production or cloud retirement.
- The approval was local operator consent tied to the exact plan, not a GitLab MR approval. The MR stays Draft and unmerged.
- The Duo session page needs a GitLab sign-in. Duo's response is copied publicly into the repo.
- Environmental measurements were mixed, so no energy or carbon saving is claimed.
What's next
Cloud adapters, approval inside GitLab (protected environments), and independent signing for the approval record.
Links
- Repository: https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/43513500/lights-out
- Judge index: https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/43513500/lights-out/-/blob/main/docs/JUDGE-INDEX.md
- Duo's decisions explained: https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/43513500/lights-out/-/blob/main/docs/DUO-DECISIONS.md
- Restore and access check in CI: https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/43513500/lights-out/-/jobs/17324439390
- Live on Google Cloud Run: https://lights-out-preserved-918290555848.us-central1.run.app
Built With
- docker
- gitlab-ci
- gitlab-duo-agent-platform
- google-cloud-run
- postgresql
- python
- sqlite
Log in or sign up for Devpost to join the conversation.