Why I built Sunset
Writing new software has become faster than ever. Getting rid of old software is still surprisingly risky.
An endpoint can look unused in a repository and still be called by a scheduled job, an older service, or a client nobody remembered to check. You can leave it running forever, but that means more code to maintain, more things to secure, and more opportunities for something to break. Or you can remove it and hope for the best.
I wanted a better answer than either of those.
Sunset helps engineering teams retire old APIs with evidence, not guesswork. It brings together GitLab Duo, GitLab CI/CD, and live Google Cloud telemetry to figure out what depends on an API, help migrate those dependencies, and stop the retirement until it's safe enough for a human to approve.
What it does
For the working example, Sunset retires /v1/orders and moves its consumers to /v2/orders. There are three consumers: Checkout, Reporting, and a scheduled Legacy Worker. They live in a separate GitLab project, like a real application managed by Sunset rather than Sunset's own source code.
Here's how a retirement works:
- Start with an intention. Ask Sunset to retire an API. It creates or links a GitLab issue and starts building a picture of its dependencies.
- Find the consumers. Sunset checks consumer configuration, scheduled jobs, actual requests in Cloud Logging, and what's currently running on Cloud Run. It doesn't assume a search through source code tells the whole story.
- Help them move. A custom GitLab Duo flow investigates and prepares focused consumer migrations. Sunset restricts what those changes are allowed to touch and independently checks merge requests and successful pipelines.
- Wait for real evidence. Tests and security checks must pass. The replacement must be healthy, deployment identities must match the source and image that were tested, and the monitoring window must be complete with no deprecated traffic. If any evidence is missing, Sunset stays blocked.
- Ask a human for the final decision. When all checks pass, an operator reviews the evidence and approves the retirement. That approval is tied to the exact evidence and source commit. GitLab CI checks authorization again before deploying.
- Verify the outcome. Sunset retires the old route, checks that it returns 410 Gone, checks that v2 and the consumers still work, and saves an auditable receipt. It also has a traffic rollback path if final verification fails.
The important design choice is that the AI cannot approve its own work or override the safety rules. It can do the investigation and prepare changes. The decision to retire something is enforced by deterministic checks and a person. That's why I built Sunset as a supervised workflow rather than a hands-off deletion agent.
It's running, not just a mockup
Sunset has a live control application on Google Cloud Run, a separate Orders example project, actual GitLab CI pipelines, and recorded retirement outcomes.
On October 25, a live retirement completed with the old API returning 410 Gone, its replacement and registered consumers healthy, and a downloadable JSON receipt.
On October 27, another retirement change was merged in Orders example MR !7. The post-merge pipeline #2993012765 passed the Verify, Secure, Package, Authorize, and Release stages. The MR includes a live Sunset report recording 15 passed checks, from consumer inventory and telemetry coverage to deployment identity and final service verification.
You can inspect the work yourself:
- Live Sunset application
- Completed retirement and downloadable receipt
- Sunset source on GitLab
- Managed Orders example on GitLab
- Merged retirement MR !7, with its evidence report
- Successful release pipeline
The public app is available for judges to explore in read-only mode. Operator actions require authentication.
How I built it
The control plane is Python and FastAPI, with a durable workflow worker, PostgreSQL on Cloud SQL, saved evidence snapshots, and a policy engine. The interface is React and TypeScript, with a dependency view, traffic history, checklists, approvals, activity timeline, and receipts.
The GitLab side uses a native GitLab Duo Agent Platform custom flow, GitLab issues and merge requests, exact-diff checking, CI pipelines, and pinned commit evidence. The Cloud side uses Cloud Run, Cloud Logging, Cloud Scheduler, Artifact Registry, Secret Manager, and infrastructure managed with Terraform. The CI workflow includes tests, security and secret scanning, container checks, SBOM generation, deployment authorization, and release. There's also optional OpenTelemetry export.
I wanted the workflow to reach the whole DevSecOps lifecycle, rather than putting an agent in front of one isolated task:
- Plan: retirement issues, consumer inventory, and readiness conditions.
- Create: GitLab Duo investigation and bounded migration changes.
- Verify: unit and contract tests, plus final service checks.
- Package: container images, digests, and SBOMs.
- Secure: code, dependency, secret, and container checks.
- Release: gated deployment and rollback handling.
- Configure: version-controlled consumer routes and retirement settings.
- Monitor: request logs, heartbeats, scheduled consumers, deployment health, and optional OpenTelemetry.
- Govern: evidence-backed rules, operator approval, CI authorization, and an audit trail.
The hardest part
The most challenging thing wasn't making an agent generate a change. It was working out what would count as trustworthy evidence before a destructive change.
For example, a green pipeline doesn't prove the right code is running. A quiet log window doesn't help if logs are incomplete. And an AI agent shouldn't be able to change the rules used to approve its own output.
I had to account for source-to-deployment identity, stale or missing observations, scheduled consumers, exact changes in an MR, transient GitLab errors, and partial deployments. Those details are less flashy than the AI part, but they're what makes the idea worth using.
What I learned
The most useful thing an agent can do isn't always to take the final action. Sometimes it's to do the hard preparation and present enough evidence that someone can make a good decision.
That became the guiding principle for Sunset: automate the work, not the responsibility.
What's next
Right now this is a focused reference implementation: one Orders API, three registered consumers, one managed GitLab project, and one Google Cloud environment. Retiring v1 returns an intentional 410 Gone response; Sunset isn't claiming to remove every line of old code or delete a database.
The default five-minute observation window is for the hackathon demo, not a safe universal deprecation period. It cannot rule out unknown or rarely active external clients. A production version would need longer configurable windows, broader cross-repository discovery, stronger attribution of unknown callers, and team-level access controls.
I built the retirement orchestration, CI gates, Duo flow, example service, and cloud deployment for this hackathon. Some reusable interface components were adapted from my earlier MIT-licensed Vidicy design system, with attribution in the repository.
Sunset is about making space to build what's next without breaking what's already there.
Built With
- bandit
- docker
- fastapi
- gitlab
- gitlab-api
- gitlab-ci/cd
- gitlab-duo-agent-platform
- gitlab-graphql
- gitleaks
- google-artifact-registry
- google-cloud-logging
- google-cloud-run
- google-cloud-scheduler
- google-cloud-sql
- google-secret-manager
- oidc
- opentelemetry
- postgresql
- python
- react
- sbom
- terraform
- trivy
- typescript
- vite
Log in or sign up for Devpost to join the conversation.