# Find where every Doppler secret lives and when it last changed

> One screen that groups every key in your Doppler workplace by name, shows how many projects hold it, and sorts by what has gone longest without a change.

- Workflow type: app
- Services: Doppler, GitHub, Linear
- Categories: Engineering, Operations
- Published: 2026-08-21

## What it does

- One row per key name instead of one row per project, so a secret sitting in seven projects shows up once with a sprawl count and the date it last changed, and never with its value
- Sorted most stale first, so the keys nobody has touched in months rise to the top instead of hiding behind a project list
- Click any key to see every project and environment holding it, plus the repositories and files in your code that actually read it
- Write a rotation note onto the key, file a rotation ticket, or press Draft rotation plan and have a background helper write an ordered runbook naming which environment to change first and what will break

## What you'll need

- A Doppler login that can see the projects you want to inventory, ideally all of them, on any plan that includes the built-in project and environment listings
- A GitHub login with read access to the repositories your code lives in
- A Linear workspace, if you want to file rotation tickets straight from the app
- A rough idea of how many days without a change you consider stale, so the list sorts the way you expect

## Prompt

I want an app that answers one question I currently cannot answer without clicking through every project in Doppler by hand: where does a given key actually live, and when was it last rotated. Build it over my whole Doppler workplace, with GitHub for code evidence and Linear for filing the rotation work.

Main screen. An inventory table keyed on the secret name rather than on the project. Build it by walking Doppler List Projects, then Doppler List Configs for each project, then Doppler List Secret Names for each config, and index everything by key name. One row per distinct key name across the entire workplace, so a key that appears in seven projects is a single row with a sprawl count of seven, not seven rows. Columns: key name, number of projects holding it, number of configs holding it, the environments it touches as small badges, the date it last changed, and its age in days. Paginate every Doppler list call until it returns an empty page, and skip projects my token cannot see rather than failing the whole load.

The last changed date comes from Doppler List Config Logs. For every config that holds the key, read that config's change history, find the most recent entry that touched the key name, and take the newest of those across all configs as the key's last changed date. Sort the table most stale first by default, oldest last change at the top, and let me re-sort by sprawl count or by name. Above the table put a summary strip: total distinct keys, how many live in more than one project, how many have not changed in longer than my staleness threshold, and the single most sprawling key. Filters: search by key name, only keys present in production configs, only keys with a sprawl count of at least N, filter by project, and a staleness threshold in days that defaults to 90.

Critical rule for the entire app, including the background agent: use Doppler List Secret Names and never Doppler List Secrets, Get Secret, or Download Secrets. The app must never fetch a secret value into a handler and must never render one in the browser. Everything on screen is names, counts, dates, notes, and links. Put a short line at the top of the inventory saying that values are never read, so anyone looking over my shoulder can see that too.

Detail panel. Clicking a row opens a panel for that key name. The first section, Where it lives, lists every project and config holding the key, one line each, showing the project, the config, the environment, that config's last change date for this key, and who made that change according to the config log. Sort it oldest first so the most neglected copy sits on top, and show the count at the head of the section, for example in 7 projects and 19 configs.

The second section, Where it is used, runs GitHub Search Code for the same key name across the organization or repositories I configure, and lists the repositories and files that reference it, grouped by repository, each linking out to the file on GitHub. This is the part that turns a key exists into this service reads it. GitHub code search is heavily rate limited, so cache each key's results with a timestamp, show when it was last searched, and give me a manual refresh rather than re-searching on every open.

Actions from the panel. I can write a rotation note onto the key with Doppler Update Secret Note. Important nuance to build for: that note is project-wide and applies across every environment in that project, and this key can live in several projects, so the dialog has to show a checkbox list of the projects holding the key, state plainly that the note will apply to every environment in each project I tick, and then call Update Secret Note once per selected project. I can also file a rotation ticket with Linear Create Issue: a dialog with a team picker filled from Linear List Teams, a title prefilled as Rotate KEY_NAME, and a description prefilled with the sprawl list, the per-config last change dates, and the repositories and files found in code, plus priority and an optional assignee. Store the created issue identifier and URL against the key and show it on the inventory row so I do not file the same rotation twice.

Draft rotation plan. Add a button on the detail panel that kicks off a background agent for that key name. The agent walks every project and config containing the key, reads each config's change history to see how often it changes and who changes it, searches GitHub for the consuming code paths, and writes an ordered rotation runbook back into the app. The runbook must be an ordered list of steps naming which config to change first and which to change last with production last, what will break at each step and which repository or service that belongs to, which configs look like they share the same value and therefore have to change in the same window, how to verify each step, and a rollback note. Open it with a one line blast radius summary. Land it in a Rotation plan panel on that key's detail with a run history and timestamps so I can compare against an earlier plan, show a pending state while the agent is working, and give me a button that files the finished runbook as a Linear issue through the same Create Issue action. The agent lives under the same rule as the app: names, change history, and code references only, never a secret value.

Persist per key name: the last rotation note I wrote and when, the linked Linear issue, a reviewed on date I can stamp manually, a snooze that drops the key out of the stale count until a date I pick, and the rotation plan history. In settings let me set the staleness threshold in days, the GitHub organization or list of repositories to search, and which config or environment names count as production. Crawling every project, config, and change history is a lot of calls, so build the inventory as a cached snapshot with a visible last refreshed time and a manual Refresh button, load the table from that cache on open, and back off when Doppler returns a rate limit response.

## How to customize

- Set how many days without a change counts as stale, which drives the sorting and the summary counts
- Choose which GitHub organization or list of repositories gets searched for the code that uses a key
- Name which environments count as production, so they stand out in the inventory and go last in every rotation plan

## FAQ

### Does this show my actual secret values?

No. The app only ever asks Doppler for the names of your secrets, never the values behind them. Everything you see is names, counts, dates, notes, and links. The background helper that drafts rotation plans works under the same restriction.

### How does it know when a key was last changed?

It reads the change history of every environment that holds the key, finds the most recent change that touched that key name, and shows the newest one across all of them as the last changed date. That date and its age in days are what the list sorts on.

### How does it know which repositories use a key?

When you open a key, it searches the repositories you have pointed it at for that key name and lists the repositories and files that reference it, with a link to each file. Results are cached so opening the same key twice does not re-run the search.

### If I write a rotation note, where does it show up?

Notes in Doppler are project-wide, so a note written on a key applies across every environment in that project. Because a key often lives in several projects, the app asks which projects to write the note into and spells out that each one covers all of that project's environments.

### What does the Draft rotation plan button actually do?

It starts a background helper that walks every environment holding the key, reads each one's change history, searches your code for the places that consume it, and writes an ordered runbook back into the app. The runbook says which environment to change first, which to change last, what will break at each step, and how to verify it.

Use this prompt in General Input: https://www.generalinput.com/prompts/find-where-every-doppler-secret-lives-and-when-it-last-changed