An estate only grows. Every quarter adds repositories; nothing removes them, because removing one requires somebody to decide and nobody is assigned to decide.
The result is predictable: after five years, a third or more of the repositories are dead, and they carry live credentials, unaddressed security alerts and no owner.
The short answer
Section titled “The short answer”This is a scheduled process, not a project. A monthly run that identifies candidates, notifies owners, waits, and archives. A one-off cleanup is undone within two years.
Archive, do not delete. Archiving preserves history, issues, pull requests and the review record while making the repository read-only. Deleting destroys all of it and leaves the forks behind.
Default the transition. Asking teams to volunteer repositories produces nothing. “These will be archived on the 30th unless you object” produces action.
Check for dependents first, always. A stable library with no commits and two hundred consumers must not be archived.
Expect a residue of repositories that resist classification, and have a plan for it.
The monthly run
Section titled “The monthly run”-
Identify candidates from the inventory: no commits in twelve months, no open or recently closed pull requests, no releases, and any additional criteria you have chosen.
-
Check for dependents. Dependency graph, fleet-wide code search for references, reusable workflow callers, package downloads, and recent traffic.
-
Exclude the protected categories. Anything with a lifecycle state of
activeormaintenanceset deliberately, anything in a compliance scope requiring retention in a live state, anything explicitly opted out. -
Notify the owner, or the organisation owner where there is none, with the reason, the evidence, and the date.
-
Post the candidate list somewhere engineers see it. Somebody always knows about a consumer no query found.
-
Wait thirty days.
-
Archive what remains uncontested.
-
Record what was archived, when, and on what basis.
Automate steps 1 through 4 and step 8. Steps 5 through 7 are human by design, and step 7 should require a person to confirm rather than running unattended.
Run it monthly. A small, familiar batch beats an annual sweep that is a project every time.
The decline signals
Section titled “The decline signals”No commits in twelve months. The headline criterion, and insufficient alone — a stable library legitimately has no commits.
No pull request activity. Combined with the above, much stronger.
Failing CI nobody has fixed. A red pipeline for three months means no active maintainer regardless of what the ownership record says.
Open dependency alerts, unaddressed. The clearest signal that nobody is watching, and the one with a direct security consequence.
No dependents. Nothing in the estate references it, no deployment consumes it, no package downloads.
An owning team that no longer exists. Definitive on its own.
No traffic. Clone and view counts near zero over a fortnight.
Combine at least three. A single signal produces false positives, and a false positive that archives a widely-used library is the failure that ends the programme.
Checking for dependents
Section titled “Checking for dependents”The dependency graph covers repositories declaring a dependency on a published package. It does not cover direct Git references, which in an enterprise are a substantial fraction.
Fleet-wide code search for the repository name, clone URL and package name. Catches workflow files, scripts and documentation.
Reusable workflow callers. A repository providing a workflow that others call — archiving it breaks every caller, and these references are easy to find and easy to forget.
Template usage. Archiving a template stops new repositories being created from it.
Traffic data. Clone and view counts tell you whether anything is still pulling it, including systems nobody remembers.
Package registry downloads, if it publishes.
None is complete alone, which is why the objection window exists — the checks narrow the risk and the window catches what they missed.
Starting from a large backlog
Section titled “Starting from a large backlog”The first run against an estate that has never done this is different from the steady state, and treating it the same way produces a mess.
The candidate list will be enormous. An estate of two thousand repositories that has never archived anything may produce six or seven hundred candidates. Notifying six hundred owners simultaneously produces a wave of objections and confusion.
Do not run the standard process at that volume. Stage it.
-
Publish the analysis first, without notifications. “Here is what we found: 680 repositories with no activity in a year.” This starts the conversation without an implied deadline.
-
Handle the unambiguous cases first. Repositories with no commits, no dependents, no releases and a dissolved owning team. These are uncontroversial and they are usually a large fraction.
-
Batch by organisation or by owning team, fifty at a time, so each owner deals with one manageable list.
-
Give the first batches a longer window. Sixty days rather than thirty, while people learn what the process is.
-
Learn from the objections. The first batches tell you which criteria produce false positives, and the criteria should be adjusted before the volume increases.
-
Then accelerate once the process is understood and the criteria are tuned.
-
Switch to the monthly steady state once the backlog is cleared. From then on the batches are small.
Expect the backlog to take a year. That is fine. The steady state afterwards is a few dozen a month and requires almost no effort.
And expect the first analysis to be the most valuable output. The number itself — how much of the estate is dead — is frequently the thing that gets the programme funded.
Automating it safely
Section titled “Automating it safely”Dry-run first, always. The candidate list should be produced, reviewed and published before anything is archived.
Bound the batch. A cap of, say, fifty per run means a bug affects fifty repositories rather than a thousand. Archiving is reversible, and a large mistake is still a large amount of explaining.
Require human confirmation for the archive step. Identification is automated; the action is approved.
Log per repository: why it was a candidate, what checks ran, what they found, who was notified, and what happened.
Make unarchiving quick and blameless. A team that needs a repository back should get it in minutes with no escalation. This single property is what makes the whole programme tolerable — the cost of a mistake is small.
And track how often unarchiving happens. A rate above a few percent means the criteria are too aggressive.
What archiving actually changes
Section titled “What archiving actually changes”Stating this precisely in the notification removes most objections, because the fear is that archiving destroys something.
Read-only. No pushes, no new issues or pull requests, no editing existing ones, no changing settings.
Everything remains visible. Code, full history, issues, pull requests, releases, and the review record. Nothing is hidden or deleted.
Cloning still works. Read access is unchanged.
Releases and packages remain available. A consumer downloading a release asset is unaffected.
Workflows stop. Scheduled workflows do not run on an archived repository, which is frequently a benefit — an unowned repository running a nightly job against production is a real thing that exists in most estates.
It can be unarchived at any time, restoring full function.
It still counts toward the organisation’s repository count and its content toward storage. Archiving is a governance action, not a cost-saving one.
The one genuine loss is that nobody can open a pull request to fix a bug. For a widely-consumed library that matters, which is exactly why the dependents check is not optional.
The security case
Section titled “The security case”Archiving is usually funded as tidiness, and the risk framing is both more accurate and more persuasive.
Dead repositories carry live credentials. Deploy keys, Actions secrets, app installations, tokens. None expire, none are rotated, and nobody is watching.
They run. Scheduled workflows on an unowned repository continue executing, with those credentials, indefinitely. Archiving stops them.
They carry unaddressed vulnerabilities. Dependency alerts open for years, on code that may still be deployed somewhere.
They are in scope. An auditor asking for the population subject to a control includes them, and nobody can answer for them.
They are a supply chain surface. An unowned repository with write access held by a former contractor, that something still builds from, is a path nobody is monitoring.
Reframe the ask accordingly. “We have 340 repositories with no owner, live credentials and open security alerts” gets attention that “the repository list is untidy” does not — and the number comes straight out of the inventory.
Archive first, then rotate. Archiving stops the workflows; the credentials attached to those repositories still need revoking, and that is a separate step people forget. See machine identities.
Deletion, and when it is right
Section titled “Deletion, and when it is right”Almost never.
What deletion destroys: history, issues, pull requests, review approvals — which may be the evidence for a change management control — and the ability to answer any question about the repository afterwards.
What it does not remove: forks. The fork network survives its parent, and the code continues to exist elsewhere.
The legitimate cases: a repository created by mistake with no meaningful content, a duplicate, or a repository whose contents must be removed for a legal or data protection reason.
For the last case, understand what deletion does not achieve. Existing clones and forks persist. Deleting is a step in a response, not the response.
Archiving is the default answer, and saying so clearly in the notification removes most of the resistance — teams object to deletion far more than to archiving, and frequently do not distinguish them.
Migration reduces the work
Section titled “Migration reduces the work”A specific and underappreciated case: the cheapest repositories to migrate are the ones you do not migrate.
Before any platform migration, run the lifecycle process. An estate of two thousand repositories where seven hundred are dead is a migration of thirteen hundred, and the seven hundred cost nothing to leave behind.
Archive rather than migrate. An archived repository on the old platform, retained read-only for a period, satisfies “we might need it” without any migration effort at all.
Which changes the migration’s size materially. A third fewer repositories is a third less migration work, a third fewer validation checks, and a third less of the long tail that dominates migration timelines. See migration planning.
Do the lifecycle pass first, not concurrently. Migrating repositories that are then archived is work performed for nothing, and it happens whenever the two activities run in parallel without coordination.
Set the retention for the old platform deliberately. How long the archived repositories remain accessible before the old system is decommissioned, and who decides. That is a decision, not a default.
And use the migration as the forcing function. Teams who would ignore an archival notice will respond to “this repository will not be migrated unless you claim it”, because the consequence is concrete and the date is real.
The residue
Section titled “The residue”Every lifecycle programme reaches a set of repositories that resist resolution.
Owned by a dissolved team, no successor. Escalate to the organisation owner, then to whoever owned that team’s budget. Somebody inherited the work.
Everybody uses it, nobody will claim it. The shared library predating the current structure. This needs an owner assigned, which is a management decision rather than a technical one.
Genuinely nobody’s and genuinely unused. Archive. The easy case and usually the largest.
Contains something nobody wants to be responsible for. Old credentials, personal data, an unclear licence. Investigate these first — they carry actual risk.
Somebody’s personal project in a company organisation. More common than expected. Ask, then archive or move.
Set a deadline with a default. “Unclaimed repositories will be archived on this date” resolves more of the residue than any amount of asking, and archiving’s reversibility is what makes the default defensible.
Consolidation, not just archival
Section titled “Consolidation, not just archival”Archiving removes dead repositories. Consolidation reduces the live ones, and it is the other half of keeping an estate tractable.
Duplicate implementations. Three teams’ HTTP client libraries. Consolidating them is a real engineering project and it removes two repositories permanently — plus their maintenance, their vulnerabilities and their divergence.
Fragments of one system. A service split across four repositories for reasons nobody remembers, with changes requiring coordinated releases across all four. Merging them removes coordination overhead as well as repository count.
Abandoned forks. A fork that diverged, was used for a while, and should either be merged back or archived.
Per-environment repositories. The same configuration in three repositories differing by a few values. Frequently a candidate for one repository with environment directories.
Consolidation is not a fleet operation. Each case is an engineering project with a design decision, and it cannot be automated. What fleet tooling contributes is finding the candidates — duplicate names, similar dependency sets, repositories that always change together.
Repositories that always change together are the strongest signal. A query over commit history across the estate, looking for repositories whose changes correlate, surfaces fragmented systems that nobody would have thought to look for. See monorepo versus polyrepo for the structural question.
Prioritise by maintenance burden, not by count. Consolidating four dormant repositories saves nothing; consolidating four that each need dependency updates every week saves real effort.
Running it as a programme
Section titled “Running it as a programme”Sustaining this past the first enthusiastic quarter.
Publish three numbers monthly: total repositories, archived this month, and unowned. The first is the trend, the second is whether the process runs, and the third is the governance gap.
Expect a lumpy archive rate. A reorganisation produces a wave; a quiet quarter produces almost nothing. Consistency of process matters more than consistency of output.
Report the security numbers alongside. Open alerts on unowned repositories, falling as the programme runs, is the outcome that justifies it.
Keep the notification friendly. The owner of a candidate repository is not doing anything wrong. A notice that reads as an accusation generates defensiveness and objections that are really about tone.
Handle objections without argument. A team saying “we still need this” gets it excluded, with a lifecycle property set so it is not a candidate next month. Do not litigate; the property records their decision and it is theirs to make.
Review the exclusions annually. A repository excluded three years ago on the basis that it was still needed may no longer be, and the exclusion list should not grow monotonically.
And accept a floor. There is a level of dead-but-unarchivable repositories below which you will not get. Reaching it and stopping is a success, not a failure to complete.
Common mistakes
Section titled “Common mistakes”A one-off cleanup project. Undone within two years.
Archiving on a single criterion. Stable libraries have no commits.
Skipping the dependents check. The failure that ends the programme.
No objection window. Somebody will be surprised, and they will be right.
Deleting instead of archiving. Destroys the record and leaves the forks.
Unbounded automated runs. A bug reaches the whole estate.
Unarchiving that requires an escalation. Makes the programme something people obstruct.
Asking teams to volunteer. Nobody volunteers.
Retrofitting standards onto the dead tail. Work that produces nothing; archive instead.
The lifecycle states as data
Section titled “The lifecycle states as data”Making the process queryable rather than procedural, using custom properties.
| State | Meaning | Effect on the process |
|---|---|---|
active | Maintained, changing | Excluded from candidacy |
maintenance | Stable, security fixes only | Excluded; low activity is expected |
deprecated | Replacement exists, migration underway | Candidate once consumers have moved |
pending-archive | Notified, objection window open | In the current run |
archived | Read-only | Done |
The maintenance state is the important one. It is what a team sets on a stable library so that “no commits in a year” stops being a signal for it. Without it, the process repeatedly proposes archiving things that are deliberately stable, and the team repeatedly objects — which trains them to ignore the notifications.
deprecated carries information consumers need. A repository marked deprecated, with the replacement named in its README, tells somebody discovering it that they should not build on it. That is worth more than the archival it eventually leads to.
The transitions have owners. A team declares maintenance or deprecated; the process proposes pending-archive; a person confirms archived.
Query on it. How many repositories are deprecated and how long they have been. A repository deprecated two years ago with consumers still on it is a migration that stalled, and that is a finding.
Set the state at creation where it is knowable — an experiment declared as an experiment can be archived on schedule without an argument, because the team said so at the start.
Mental model
Section titled “Mental model”Lifecycle is a continuous process with a default action and an objection window. Its safety comes from archiving rather than deleting, from checking dependents, and from making the reversal instant. Its effectiveness comes from the default — teams do not volunteer repositories, and they do respond to a date.
What you learned
Section titled “What you learned”- Lifecycle is a monthly scheduled process, not a cleanup project
- Archiving preserves history, issues and the review record while making the repository read-only
- Deleting destroys the record, may destroy control evidence, and leaves forks behind
- Combine at least three decline signals; no single criterion is safe
- The dependents check must cover packages, code references, reusable workflow callers, templates and traffic
- Automate identification and notification; keep the archive action human-confirmed and bounded
- Quick, blameless unarchiving is what makes the programme tolerable
- Default the transition with a date rather than asking teams to volunteer
- Every programme has a residue, and it needs escalation paths rather than more asking
Exercise
Section titled “Exercise”Use an organisation you administer.
-
Count repositories with no commits in twelve months. Predict: what fraction of the total?
-
For ten of them, check every dependents signal. How many have consumers?
-
Find one with no commits and many dependents. What would archiving it break?
-
Find repositories with open dependency alerts and no activity. Predict: how old is the oldest alert?
-
Draft the notification an owner would receive, including the evidence and the date.
-
Design your decline criteria: which signals, in what combination.
-
Determine how long unarchiving takes in your organisation, and who can do it.
-
Estimate how many repositories a first run would identify, and whether that batch size is safe.