# How the Owner-Liveness-Sweep Detects Plugin Source Repo Ownership Changes

> Discover how the owner-liveness-sweep detects GitHub repository ownership changes by comparing current and baseline account IDs. Learn about identity_changed findings.

- Repository: [Anthropic/claude-plugins-community](https://github.com/anthropics/claude-plugins-community)
- Tags: internals
- Published: 2026-09-02

---

**The `owner-liveness-sweep` detects ownership changes by comparing each plugin owner's current GitHub account ID against a stored baseline, flagging any mismatch as an `identity_changed` finding.**

The `anthropics/claude-plugins-community` repository runs a daily security sweep to ensure that external plugin source repositories haven't changed hands unexpectedly. This sweep protects the marketplace from **name-squatting attacks**, where a GitHub username is abandoned and later claimed by a different account. The `owner-liveness-sweep` action automates this verification using GitHub's stable account identifiers and a version-controlled baseline.

## How the Ownership Detection Works

The sweep follows a five-step process to identify any ownership changes across all marketplace entries.

### Step 1: Extract Owners from Marketplace Entries

The script parses [`.claude-plugin/marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/marketplace.json) and extracts GitHub URLs from every plugin entry. For each URL, it isolates the owner login using a regex pattern in [`.github/actions/owner-liveness-sweep/scripts/sweep.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/owner-liveness-sweep/scripts/sweep.sh) at lines 60-102.

```bash

# From sweep.sh L60-L102: extracts unique GitHub owners from the marketplace

echo "$(jq -c '
  [.plugins[] | select(.source?.repository? | strings | test("^https://github.com/"; "i"))
  | .source.repository
  | capture("^https://github\\.com/(?<owner>[^/]+)"; "i").owner
  | ascii_downcase]
  | unique
' "$MARKETPLACE_PATH")"

```

### Step 2: Resolve Owners via GraphQL

The script queries GitHub's GraphQL API to resolve each login to its current **databaseId** (the immutable account identifier). The query template appears at lines 22-30 of [`sweep.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/sweep.sh):

```graphql
{#query}
  repositoryOwner(login:"$login") {
    __typename
    ...on User  { id databaseId }
    ...on Organization { id databaseId }
  }

```

This batched query runs for all discovered owners, returning both whether the login is still active (`live == true`) and the numeric `databaseId`.

### Step 3: Load the Stored Baseline

The baseline file [`.github/owner-baseline.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/owner-baseline.json) maps each owner login (lower-cased) to the `databaseId` recorded when that owner was first added to the marketplace. This JSON file serves as the **source of truth** for ownership verification.

### Step 4: Compare Live IDs Against Baseline

The core detection logic at lines 182-185 of [`sweep.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/sweep.sh) identifies ownership changes:

```bash

# From sweep.sh L182-185: identity change detection

if [[ "$live_id" -ne "$recorded_id" ]]; then
  finding_type="identity_changed"
  finding_payload=$(jq -n --arg o "$owner" --argjson rid "$recorded_id" --argjson lid "$live_id" '{owner:$o, recorded_id:$rid, live_id:$lid}')
fi

```

A mismatch between `live_id` and `recorded_id` indicates the login now belongs to a **different GitHub account**, even if the username appears identical.

### Step 5: Fail the Run on Identity Changes

Unless `FAIL_ON_IDENTITY_CHANGE` is set to `false`, the sweep exits with an error when any `identity_changed` finding exists (lines 84-87). This forces human review before automated actions like version bumps proceed.

```bash

# From sweep.sh L84-87: fail-on-change handling

if [[ "${FAIL_ON_IDENTITY_CHANGE:-true}" == "true" ]] && [[ "$(jq '.identity_changed | length' findings.json)" -gt 0 ]]; then
  echo "Error: Identity changes detected. Review findings.json" >&2
  exit 1
fi

```

## Running the Owner-Liveness-Sweep

The sweep supports two operational modes controlled by the `MODE` environment variable.

### Report Mode (Default)

Use this mode in CI to detect and block on ownership changes:

```bash
MARKETPLACE_PATH=.claude-plugin/marketplace.json \
BASELINE_PATH=.github/owner-baseline.json \
MODE=report \
bash .github/actions/owner-liveness-sweep/scripts/sweep.sh

```

### Refresh Mode

Use this mode after manually verifying ownership changes to update the baseline:

```bash
MARKETPLACE_PATH=.claude-plugin/marketplace.json \
BASELINE_PATH=.github/owner-baseline.json \
MODE=refresh \
bash .github/actions/owner-liveness-sweep/scripts/sweep.sh

```

## Understanding the Findings Output

Both modes generate a [`findings.json`](https://github.com/anthropics/claude-plugins-community/blob/main/findings.json) file with structured results. An `identity_changed` entry appears as follows:

```json
{
  "identity_changed": [
    {
      "owner": "exampleOwner",
      "recorded_id": 1234567,
      "live_id": 7654321,
      "entries": ["plugin-A", "plugin-B"]
    }
  ],
  "unresolved": [],
  "identity_intact": []
}

```

- **`recorded_id`**: The original GitHub account ID from the baseline
- **`live_id`**: The current GitHub account ID for that login
- **`entries`**: Plugin entries that reference this owner

## Key Components of the Detection System

| File | Purpose |
|------|---------|
| [`.github/workflows/owner-liveness-sweep.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/owner-liveness-sweep.yml) | Daily GitHub Actions workflow invoking the sweep |
| [`.github/actions/owner-liveness-sweep/scripts/sweep.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/owner-liveness-sweep/scripts/sweep.sh) | Core detection logic, GraphQL queries, and comparison |
| [`.github/actions/owner-liveness-sweep/README.md`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/owner-liveness-sweep/README.md) | Documentation of detection classes and baseline handling |
| [`.github/owner-baseline.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/owner-baseline.json) | Version-controlled mapping of owner logins to account IDs |

## Summary

- The **owner-liveness-sweep** protects against account takeovers by tracking immutable GitHub `databaseId` values, not just usernames.
- **Identity changes** are detected when a resolved `live_id` differs from the `recorded_id` in [`.github/owner-baseline.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/owner-baseline.json).
- The sweep **fails by default** on identity changes, requiring human review before any automated marketplace updates.
- Use **report mode** for CI detection and **refresh mode** to update the baseline after verified ownership changes.
- The entire system is implemented in the `anthropics/claude-plugins-community` repository as a Bash script with GitHub Actions integration.

## Frequently Asked Questions

### What triggers an `identity_changed` finding?

An `identity_changed` finding triggers when a GitHub login that exists in the baseline resolves to a different `databaseId` than previously recorded. This occurs when the original account deleted or renamed their account, and a new account claimed the same username.

### Why use `databaseId` instead of usernames for ownership tracking?

GitHub usernames are **mutable**—users can change them or delete their accounts. The `databaseId` is an immutable integer assigned at account creation. Comparing these stable identifiers prevents false negatives when a username gets recycled.

### How do I update the baseline after a legitimate ownership change?

Run the sweep in **refresh mode** after manually verifying the new owner is legitimate: set `MODE=refresh` and execute [`sweep.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/sweep.sh). This updates [`.github/owner-baseline.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/owner-baseline.json) with current `databaseId` values for all resolved owners.

### Can I disable the failure on identity changes?

Yes—set the environment variable `FAIL_ON_IDENTITY_CHANGE=false` before running the sweep. This allows the workflow to complete and report findings without blocking, useful for testing or transitional review workflows.