Skip to main content
Version: 0.5.0

Teams and identities

Every per-person panel rests on one small map in ~/.whodunit/config.json โ€” which addresses belong to the same person โ€” and every per-team panel on DevLake's team tables. Neither is collected; both are typed, and this page is how, including what the config teams map does and does not reach today.

Identities โ€” one person, several addressesโ€‹

A single developer picks up a second identity the moment one machine is configured with a GitHub noreply address and another with their real one. Nothing announces it: both are valid, both commit, and the dashboards show two contributors. Measured on one install, 153 of 985 commits sat under a second address, so filtering to either identity silently dropped a sixth of the work.

{
"identities": {
"12345+alice@users.noreply.github.com": "alice@example.com",
"alice@laptop.local": "alice@example.com"
}
}

Keyed by the address as git wrote it, valued by the canonical address. The literal committer email stays in the journal, the sidecar and every commit object; the map resolves at read time, so a wrong entry is fixed by editing one line rather than by re-syncing history.

An address with no entry is its own identity. Absent never means merged. dun will not merge two identities on its own โ€” merging is a claim about who somebody is โ€” so:

dun identities

lists every committer email found in your instrumented repositories, flags addresses that look like the same person, and prints the configuration lines. It never applies them. The decision stays with you.

Teams โ€” who is on which teamโ€‹

{
"teams": {
"platform": ["alice@example.com", "bob@example.com"],
"growth": ["carol@example.com"]
}
}

Keyed by team, valued by canonical addresses. Keyed this way because that is the shape someone maintains by hand: a team gains a member far more often than a person changes team, and this form makes the common edit one line in one place. Aliases resolve first, so a person's second machine lands in the same team as their first.

This is organisation metadata, not new personal data. The addresses are already in every commit object; which team someone is on is a fact about the org chart and adds no observation of a person. See Privacy.

Where the dashboards get teams from todayโ€‹

The dashboards read DevLake's teams and team_users tables, not the config map. Every team filter joins team_users.user_id against the committer email, after aliases resolve. Those tables are filled through DevLake's org plugin โ€” two CSVs, teams.csv and users.csv, with the committer email as each user's Id โ€” as described in Setting up the datalake.

The teams map in config.json is defined and validated, but nothing publishes or reads it yet โ€” not dun sync, not the dashboards. Until it is wired, populate DevLake's tables directly. The intended precedence when it lands โ€” a value typed in config wins over one that arrived on a connector sync โ€” is why the map exists, and this page will say so when it is true.

A contributor in no team is (unassigned), never dropped. The option is always offered in every team dropdown, even when nobody is currently unassigned โ€” someone will commit from an unmapped address, and a filter built from current membership would hide them the moment they appear. A person vanishing from a filter is the failure this whole area exists to prevent.

Editing the fileโ€‹

dun config set handles scalar settings. The two maps are edited in the file directly:

$EDITOR ~/.whodunit/config.json

Nothing needs re-syncing afterwards: both maps resolve when a dashboard runs its query, against the addresses already in the lake.

Where it showsโ€‹

Every dashboard with a Team or Contributor filter; Team Adoption and its rollout view; the per-team and per-person rows on the Delivery Forecast; the funnel per team. The DevLake deployment also reads the same maps when it seeds team tables for a demo database.