Skip to main content
Blog

From Expired Flag to Merged PR: How We Built Vulture to Automate Code Cleanup

Author Abhishek Chaturvedi
Abhishek ChaturvediSenior Principal Engineer

Summary6 min read

Every mature codebase accumulates dead code: expired feature flags, unreachable branches, logic that shipped years ago and never got cleaned up. So we built Vulture to automate cleanup. It's already removed ~150,000 lines of dead code from our legacy eSignature codebase in one year. Here's how we built it.

Vulture featured image
    • Why is dead code a live problem?
    • What does Vulture do?
    • Year 1 results
    • A deterministic tool for a well-defined problem
    • What’s next

Jahnavi Katikitala, a Docusign software engineer, and Amit Sharma, a lead software engineer at Docusign, also contributed to this blog

Every quarter, a handful of Docusign engineers would manually clean up a few expired feature flags. The work was straightforward but tedious, and it never rose high enough on anyone's priority list to tackle at scale. 

Meanwhile, the backlog kept growing. By the time we decided to do something about it, our legacy eSignature codebase had accumulated over 15,000 feature flags, some expired for six years or more. While this isn't unusual for an enterprise software company with two decades of shipping history, the question is whether you address it systematically or let it compound.

The clutter wasn't just cosmetic. Dead code paths still needed to be accounted for in tests. Engineers debugging unfamiliar systems had to figure out which branches were actually live. Every conditional around an expired flag was a small tax on understanding, maintaining, and trusting the code.

So we built Vulture to automate our way out of this. Vulture is our internal code cleanup tool that takes a feature flag name, resolves its value, removes the dead code paths across the codebase, and submits a pull request (PR) for human review without an engineer having to touch the files directly. Vulture started as a 2024 hackathon project, the forcing function that finally turned years of “we should really clean this up” into working code. 

Why is dead code a live problem?

When a flag-controlled code path is never actually reached in production, it still needs to be accounted for in testing. Every new PR potentially touches code that branches around these dead paths. Engineers have to reason about conditions that will never be true, test scenarios that customers will never encounter, and maintain logic that exists purely as an artifact of shipping history. The surface area for bugs expands, and the confidence you can have in any given change shrinks.

Beyond testing overhead, there’s cognitive load. When an engineer is debugging a system they didn’t build, they have to figure out which branches are live. Expired flags can obscure that. 

Cleaner code means fewer unexpected interactions, faster onboarding for new engineers, and ultimately more reliable software for our customers.

What does Vulture do?

Vulture is an automated code cleanup tool that identifies expired feature flags and dead code in our codebase, removes them, and submits a PR for human review without requiring an engineer to touch the code directly. Here's how the workflow looks end-to-end:

Fig 1: Vulture feature flag cleanup flow

The workflow is intentionally simple. An engineer goes to a dedicated Slack channel, triggers the workflow, and specifies a Dynamic System Setting (DSS) — our internal mechanism for feature flags — along with its resolved value. From there, Vulture takes over.

Fig 2: Triggering the Vulture cleanup workflow in Slack

Under the hood, Vulture uses the .NET Roslyn compiler SDK to parse C# source files into abstract syntax trees, identify all references to the specified flag across the codebase, and apply the appropriate transformation. If a flag is enabled, Vulture simplifies the conditional to its true branch and removes the rest. If it’s disabled, it removes the entire dead path. After transformation, the code goes through multiple cleanup passes to handle nested blocks, unreachable code, and formatting. Vulture then runs a build and test suite to confirm nothing broke before creating a branch, committing the changes, opening a pull request on GitHub, and linking it to a Jira ticket automatically.

Fig. 3: Vulture cleaning dead code

The validation step is where Vulture earns trust. Rather than modify files and hand off immediately, it builds the project and runs tests before any PR is created. Docusign engineers can review the PR and merge with confidence that the automation has already done the verification work.

Year 1 results

In its first year focused on the core repository, Vulture has been immensely helpful cleaning up our code:

The scope is currently focused on Docusign’s legacy eSignature code, the part of the codebase that carries the most accumulated flag debt. Newer microservices built in the last year or two don’t have the same problem yet.

A deterministic tool for a well-defined problem

Vulture uses a compiler SDK rather than an AI model, and that’s a deliberate choice. For a tool that’s modifying production code at scale and relying on engineer trust to get PRs merged, predictable and auditable behavior matters. Given a flag name and a value, Vulture applies a well-defined set of rules. You can reason about exactly what it will do with any given input, which makes the output straightforward to review and approve.

The architecture is task-based by design. Beyond expired DSS flags, Vulture handles several other cleanup patterns: removing unused private methods and fields (at the file, project, or solution level) and enforcing consistent code formatting. Each task type plugs into the same pipeline — discovery, transformation, validation, PR creation — which means adding new cleanup patterns doesn't require touching core infrastructure. As the team identifies new categories of dead code worth targeting, the extension path is clear.

The main limitation is language scope. Vulture currently supports C# only. For our legacy eSignature codebase, that's the right fit. The deterministic approach also means we haven't had issues with false positives. Given a flag name and value, the transformation is predictable every time.

What’s next

The near-term goal is to implement automated cleanup PR generation, bypassing the current manual Slack workflow trigger. This year we aim to use Vulture to remove 50% of expired feature flags.

We're also exploring how to expand Vulture's language support. The deterministic Roslyn-based approach works well for C#, but extending to other languages would require rebuilding that logic from scratch. We're experimenting with AI-assisted transformation to make multi-language support more practical without sacrificing the review-and-merge workflow that engineers trust.

The deeper goal is making routine cleanup feel effortless.

Author Abhishek Chaturvedi
Abhishek ChaturvediSenior Principal Engineer

Abhishek is a senior principal engineer at Docusign with a career spanning nearly two decades. His deep technical expertise is anchored by over 15 years of combined experience at Microsoft and Meta, where he worked on various products including Microsoft Outlook, Exchange Server, and Facebook's Video Ads business.

More posts from this author

Related posts

  • Engineering

    How We Built an Autonomous Coding Agent for Repetitive Engineering Tasks

    Author Ahmed Jolani
    Ahmed Jolani
    Featured image for Dobby blog
  • How We Evaluate LLM Accuracy for Contract Review

    Author Allison Hegel
    Allison Hegel

Docusign IAM is the agreement platform your business needs

Start for FreeExplore Docusign IAM
Person smiling while presenting