-
-
Graveyard dashboard, live on Cloud Run: 2 features retired, 98 lines and 3 CVEs removed, 0.0204 gCO2e saved per pipeline run
-
Sunset MR pipeline: tests, SAST, secret detection and dependency audit, then verdict check, coma and vigil. Every gate is plain code
-
Live timeline: every stage is a real GitLab job. embed_widget was resurrected when a partner knocked during its vigil
-
Undertaker agent's Sunset MR !2 deletes the Goodreads importer, its tests and the vulnerable requests pin (3 CVEs)
-
Coroner agent's death certificates: DEAD, HIBERNATING (seasonal), INSUFFICIENT_EVIDENCE or PROTECTED, each backed by evidence
-
Reviewer agent checks the diff against the verdict: AFTERLIFE-REVIEW: PASS. GitLab Duo Code Review adds a second opinion
Inspiration
Code generation made writing code cheap, so codebases grow faster than ever. Nothing removes code. Features stop being used, but their routes, tests and dependencies stay. Every pipeline keeps testing, scanning and shipping them, and their old dependencies keep collecting CVEs. Deleting code is scary because nobody can prove it's unused, so nobody does it. The hackathon asks what happens after code. We think the honest answer is that code dies, and nobody automates that part.
What it does
AFTERLIFE retires dead features end to end, from production evidence to a smaller app in production:
- Census: every route counts its calls; a scheduled job joins a year of usage with static analysis.
- Coroner (Duo agent): writes a death certificate for each candidate, with evidence and a machine-readable verdict. It refuses to kill seasonal or protected code ("hibernating, not dead").
- Undertaker (Duo agent): deletes the feature, its tests and now-unused dependencies, and opens a Sunset MR.
- Reviewer (Duo agent): checks the diff against the verdict.
- Gates: tests, SAST, secret detection, CVEs before and after, and a verdict check against policy read from the target branch.
- Coma and vigil: the feature flag goes off in production; any request gets
410 Goneand is logged as a knock. - Resurrection: one knock and the flag comes back, the MR closes, and the Medium (Duo agent) explains who still needs the feature.
- Merge, release, canary, obituary: a deterministic gate merges, Cloud Run canaries then promotes or rolls back, and the measured savings go on the issue and the live Graveyard page.
A human opens one issue. Nothing else is manual.
How we built it
- GitLab Duo Agent Platform: two custom flows (Flow Registry v1). The retire flow chains Coroner, Undertaker and Reviewer, with a conditional router so the Undertaker runs only when something is DEAD. The resurrect flow runs the Medium. Agents use GitLab tools (issue and MR notes, diffs) plus
gitandglab. - GitLab CI/CD: census, Sunset MR and main pipelines. Every decision that matters is a plain script with tests: verdict check, vigil, merge gate pinned to the tested commit, canary judgement, rollback, measurement.
- GitLab features: feature flags (Unleash protocol) for coma and resurrection, protected branches, CODEOWNERS, container registry, Releases, SAST and secret detection templates.
- Google Cloud: Cloud Run (scale to zero), Firestore, Artifact Registry, keyless auth from GitLab OIDC through Workload Identity Federation, all in Terraform, in
europe-north1. - The app: Shelf, a small FastAPI reading-list app with five planted situations: a legacy API, a dead importer holding a vulnerable dependency, a December-only feature, a forgotten partner widget, and a protected admin path.
Lifecycle stages covered
Plan, Create, Verify, Package, Secure, Release, Configure, Monitor, Govern: all nine. The README maps each stage to the file that implements it.
Challenges we ran into
- Flows can only be started by a person. We made the single human action, opening the census issue, the statement of intent, and put everything after it in one flow plus CI.
- Agents can't merge. GitLab's flow token doesn't allow it, which is right. A deterministic CI gate merges instead, only after every check passes, pinned to the commit the pipeline tested.
- Agents could loosen their own rules. The gates read policy from the target branch, never from the MR under review.
- Proving something is unused is hard. Seasonal features look dead in a 30-day window, so the census looks back 400 days, and the vigil gives real traffic the final say.
- Identity verification without a credit card. We run CI on a self-hosted runner.
Accomplishments that we're proud of
- It ran for real, end to end. Two features retired with no human step after the census issue:
books_v1(!1) andimport_goodreads(!2), each merged by CI, canaried on Cloud Run, released and given an obituary. A third,embed_widget(!3), was switched off, a partner knocked during its vigil, and it came back automatically. - Measured across the two retirements: 98 lines removed, the vulnerable
requests==2.31.0pin and its 3 CVEs removed, and 0.0204 gCO2e saved per pipeline run. The image did not shrink (70.5 → 70.6 MB): Google's client libraries still needrequests, at a patched version, and we report that as measured. - The agents decide, and plain code with tests checks every decision before anything changes. 109 tests cover the gates, the app and the agents' contract with CI.
- The system says when it's wrong. A resurrection is a first-class outcome, not a failure. Duo Code Review, a second reviewer on every Sunset MR, caught a deleted general test on the first run, and we fixed the Undertaker.
- Nothing is invented: every number on the Graveyard page links to the CI job that measured it, and simulated demo traffic is labelled as simulated.
What we learned
The interesting part of agentic DevOps is not what the agent can do but what it's allowed to do and how you prove it was right. Splitting judgement (agents) from enforcement (deterministic gates) made the system both more autonomous and safer.
What's next
- Longer vigils for real services (policy already supports days instead of minutes).
- Cross-repo callers through GitLab Orbit before calling anything dead.
- Dead branches inside live functions, using runtime coverage.
- Per-request SCI for serving, not just per pipeline run.
Repository and pipelines: https://gitlab.com/afterlife-transcend/AFTERLIFE