Öffentliches Register
Software-GesundheitsberichtSchema 0.27.0 · Metriken 1.13.0 · 2026-07-23 19:03 UTC

jasonraimondi / plan-bender

Structured planning pipeline for AI coding agents — interview, PRD, issues, review, implement, archive

GoMIT★ 5 Sterne⑂ 0 Forksseit März 2026Auf GitHub ansehen ↗

jasonraimondi/plan-bender erreicht einen Gesundheitsindex von 56 von 100 und liegt damit im Bereich Mittel. Am stärksten schneidet es bei Vitality (79/100) ab, am schwächsten bei Community & Adoption (29/100). Zuletzt vor 5 Tagen aktualisiert. Ein einzelner Mitwirkender trägt den Großteil der jüngsten Arbeit.

56
gesamt / 100
Mittel

Software-Gesundheitsindex

Metriken werden auf einer Skala von 1–100 in gewichtete Kategorien gruppiert. Der Gesamtwert beginnt als ihr Mittel; sobald öffentliche Evidenz die Richtlinie für Hochrisikojurisdiktionen auslöst, wird die Bewertung angepasst und erhält die Obergrenze 49 (Gefährdet). AI Readiness liegt außerhalb.

56
Exzellent85-100Vorbildlich; erfüllt im Wesentlichen alle geprüften Kriterien
Gut70-84Gesund; geringfügige Lücken
Mittel50-69Akzeptabel mit deutlichen Lücken; Überprüfung empfohlen
Gefährdet30-49Erhebliche Schwächen; eine Übernahme erfordert Vorsicht
Kritisch1-29Schwerwiegende Probleme (aufgegeben, nur ein Maintainer, keine Hygiene)
VitalitätCommunity &VerbreitungNachhaltigkeit &GovernanceEngineering-QualitätSicherheitAI Readiness

Bewertungsprofil

Jede Achse ist eine Kategorie. Die Form zählt mehr als der Durchschnitt — ein gesundes Projekt füllt die gesamte Fläche, während ein Profil aus Spitzen und Kratern bedeutet, dass Stärke in einer Dimension Risiken in einer anderen verdeckt.

Eigentümerschaft

Jason RaimondiPersönliches Konto
101 Follower186 öffentliche Reposseit Okt. 2013@intelligems-io

Dieses Repository gehört einem persönlichen Konto. Ein Projekt mit nur einem Eigentümer trägt ein höheres Kontinuitätsrisiko als ein organisationsgetragenes.

Paket-Ökosysteme

RegistryPaketVersionDownloads / MonatVersionenZuletzt veröffentlicht
Gogithub.com/jasonraimondi/plan-benderv0.0.71-61vor 7 Tagen

Metriken nach Kategorie

Vitalität

Lebt das Projekt — wird Code geschrieben und werden Releases ausgeliefert?

79Gut · 22 % des Gesamtindex
Wie die Bewertung erfolgt
36/36Push-Aktualität — letzter Push vor 5 Tagen
8.3/36Commit-Rhythmus — 12/52 Wochen mit Commits
18/18Commit-Volumen — 388 Commits im letzten Jahr
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Verwendete Eingangsdaten
commits_last_year388
human_commit_share1
days_since_last_push5
active_weeks_last_year12
Wie die Bewertung erfolgt
27/27Liefert Releases aus — 58 Releases veröffentlicht
36/36Release-Aktualität — letztes Release vor 5 Tagen
27/27Release-Rhythmus — ein Release etwa alle 6 Tage
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Verwendete Eingangsdaten
releases_count58
latest_release_tagv0.0.71
releases_from_tagsnein
days_since_latest_release5
mean_days_between_releases6

Community & Verbreitung

Hat das Projekt Nutzer, Downloads, Aufmerksamkeit und ein einladendes Umfeld für Beitragende?

29Kritisch · 18 % des Gesamtindex
Wie die Bewertung erfolgt
9.8/60Stars — 5 Stars
0/25Forks — 0 Forks
0/15Watcher — 0 Watcher
Verwendete Eingangsdaten
forks0
stars5
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Wie die Bewertung erfolgt
22.5/22.5README
22.5/22.5Lizenz — anerkannte Lizenz (MIT)
0/18CONTRIBUTING-Leitfaden
0/13.5Verhaltenskodex
0/7.2Issue-Vorlage
0/6.3PR-Vorlage
Verwendete Eingangsdaten
has_readmeja
has_licenseja
has_contributingnein
has_issue_templatenein
has_code_of_conductnein
has_pull_request_templatenein

Nachhaltigkeit & Governance

Überdauert das Projekt die Menschen, die es tragen — Bus-Faktor, Reaktionsfähigkeit, Trägerschaft und Paketpflege?

56Mittel · 24 % des Gesamtindex
Wie die Bewertung erfolgt
9/54Bus-Faktor — 1 Beitragende decken die Hälfte aller Commits ab
0/22.5Commit-Verteilung — wichtigste beitragende Person verfasste 100 % der Commits
1.4/13.5Breite der Beitragenden — 1 Beitragende
10/10OpenSSF Scorecard: Contributors — project has 4 contributing companies or organizations
Verwendete Eingangsdaten
bus_factor1
contributors_sampled1
top_contributor_share1
Wie die Bewertung erfolgt
0/46.8Issue-Lösungsquote — keine Issues oder keine Daten
31.5/38.3PR-Annahme — 28/34 entschiedene PRs gemergt
0/15OpenSSF Scorecard: Code-Review — Found 0/18 approved changesets -- score normalized to 0
Verwendete Eingangsdaten
merged_prs28
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs6
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): Issue-Lösungsquote. Die verbleibenden Gewichte wurden renormalisiert.
Wie die Bewertung erfolgt
10/30Organisatorische Trägerschaft — persönliches (Nutzer-)Konto
0/20Verifizierte Domain — für Nutzerkonten nicht anwendbar
14.4/25Reichweite des Inhabers — 101 Follower von jasonraimondi
25/25Kontohistorie — 186 öffentliche Repos, Kontoalter ca. 12 Jahre
Verwendete Eingangsdaten
followers101
owner_typeUser
is_verified
owner_loginjasonraimondi
public_repos186
account_age_days4.652
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): Verifizierte Domain. Die verbleibenden Gewichte wurden renormalisiert.

Paketpflege

100Exzellent
Wie die Bewertung erfolgt
25/25Veröffentlicht & auflösbar — 1 Paket(e) auf go
35/35Veröffentlichungsaktualität — letzte Veröffentlichung vor 7 Tagen
20/20Versionshistorie — 61 veröffentlichte Versionen
20/20Nicht veraltet — aktiv, nicht veraltet oder zurückgezogen
Verwendete Eingangsdaten
packagesgithub.com/jasonraimondi/plan-bender
ecosystemsgo
any_deprecatednein
min_days_since_publish7

Engineering-Qualität

Sind grundlegende Engineering- und Dokumentationspraktiken vorhanden?

67Mittel · 20 % des Gesamtindex
Wie die Bewertung erfolgt
24/24CI-Workflows — 2 Workflow(s)
24/24Tests vorhanden
0/16Linter-Konfiguration
0/9.6Pre-Commit-Hooks
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 3 out of 3 merged PRs checked by a CI test -- score normalized to 10
Verwendete Eingangsdaten
has_cija
has_testsja
has_editorconfignein
has_linter_confignein
has_precommit_confignein
Wie die Bewertung erfolgt
30/30README
25/25Dokumentationsverzeichnis
0/15Dokumentations-/Homepage-Site
10/10Repository-Beschreibung
0/10Topics
0/10Wiki
Verwendete Eingangsdaten
topics
has_wikinein
homepage
has_readmeja
has_docs_dirja
has_descriptionja

Sicherheit

Sind die sichtbaren Sicherheits- und Lieferkettenpraktiken belastbar, ohne ungeklärte Exposition gegenüber Hochrisikojurisdiktionen?

44Gefährdet · 16 % des Gesamtindex

Sicherheitslage

44Gefährdet
Wie die Bewertung erfolgt
7.5/7.5Binary-Artifacts — no binaries found in the repo
2.2/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 3 out of 3 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/18 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 4 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Lizenz — license file detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
6/7.5Vulnerabilities — 2 existing vulnerabilities detected
Verwendete Eingangsdaten
sourceopenssf_scorecard
checks_evaluated18
scorecard_versionv5.5.0
checks_inconclusive0
scorecard_aggregate4,4

AI Readiness

Wie gut ist das Repository dafür ausgestattet, mit KI-Coding-Agenten entwickelt und gepflegt zu werden? Ein unabhängiges, experimentelles Badge — Gewicht 0,0, es wird eigenständig ausgewiesen und verändert den Gesamt-Gesundheitswert nicht.

76Gut · 0 % des Gesamtindex
Wie die Bewertung erfolgt
45/45Agentenanweisungen — CLAUDE.md
0/15Maschinenlesbare Doku (llms.txt)
40/40Lesbare Commit-Historie — 100 von 100 menschlichen Commits benennen ihre Absicht (strukturierter Betreff oder erläuternder Text)
Verwendete Eingangsdaten
has_llms_txtnein
legible_history_share1
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes707
Wie die Bewertung erfolgt
18/18Bootstrap mit einem Befehl — mise.toml
22/22Automatisierte Tests
0/11Lint-/Format-Konfiguration
11/11Statische Typprüfung — Go (statisch typisiert)
10/10Reproduzierbare Umgebung — lockfile
0/10Belegte Agentenpraxis — keine von Agenten verfassten Commits unter den letzten 100
0/8Automatisierte Wartung — keine automatisierten Abhängigkeits-Updates beobachtet
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Verwendete Eingangsdaten
has_nixnein
has_testsja
lockfilesgo.sum
has_dockerfilenein
typed_languageja
bootstrap_filesmise.toml
has_devcontainernein
has_linter_confignein
typecheck_configs
agent_commit_share0
toolchain_manifestsgo.mod
dependency_bot_commit_share0
Wie die Bewertung erfolgt
45/45Typprüfbarer Code — Go (statisch typisiert)
55/55Handhabbare Dateigrößen — 0/167 Quelldateien über 60 KB
Verwendete Eingangsdaten
primary_languageGo
largest_source_bytes25.732
source_files_sampled167
oversized_source_files0

Eckdaten

5GitHub-Sterne
1Mitwirkende
388Commits, letzte 12 Monate
5Tage seit letztem Push
58Releases
1Bus-Faktor
0offene Issues
GoPaket-Ökosysteme

Warnungen zur Datenerhebung

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Weitere Details

OpenSSF Scorecard 4.4 / 10
4.4Gesamtwert

Unabhängige, werkzeugneutrale Sicherheitsbewertung durch das quelloffene OpenSSF Scorecard. Jede Prüfung honoriert eine Sicherheits-Praxis, nicht das Werkzeug eines bestimmten Anbieters. Prüfungen, die Scorecard nicht ermitteln konnte, sind mit k. A. markiert und vom Sicherheitswert ausgeschlossen (nie als null gezählt).Scorecard v5.5.0 · 2026-07-23 19:03 UTC

10Binary-Artifactsno binaries found in the repo
3Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests3 out of 3 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/18 approved changesets -- score normalized to 0
10Contributorsproject has 4 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
8Vulnerabilities2 existing vulnerabilities detected
Direkte Abhängigkeiten 7
RegistryPaketVersionsvorgabeManifest
Gogithub.com/charmbracelet/huhv1.0.0go.mod
Gogithub.com/hasura/go-graphql-clientv0.15.1go.mod
Gogithub.com/spf13/cobrav1.10.2go.mod
Gogithub.com/stretchr/testifyv1.11.1go.mod
Gogolang.org/x/sysv0.41.0go.mod
Gogolang.org/x/toolsv0.42.0go.mod
Gogopkg.in/yaml.v3v3.0.1go.mod
Alle Abhängigkeiten nicht erhoben

Der aufgelöste Abhängigkeitssatz konnte für diesen Bericht nicht erhoben werden: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

JSON-Rohbericht maschinenlesbar
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1472,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "Go": 731458,
        "Shell": 2288,
        "Go Template": 64155
      },
      "pushed_at": "2026-07-17T21:38:03Z",
      "created_at": "2026-03-28T01:49:49Z",
      "owner_type": "User",
      "updated_at": "2026-07-17T21:38:07Z",
      "description": "Structured planning pipeline for AI coding agents — interview, PRD, issues, review, implement, archive",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": "jasonraimondi.com",
      "name": "Jason Raimondi",
      "type": "User",
      "login": "jasonraimondi",
      "company": "@intelligems-io ",
      "location": null,
      "followers": 101,
      "avatar_url": "https://avatars.githubusercontent.com/u/5787967?v=4",
      "created_at": "2013-10-27T17:20:27Z",
      "is_verified": null,
      "public_repos": 186,
      "account_age_days": 4652
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.0.71",
          "kind": "patch",
          "published_at": "2026-07-17T21:34:12Z"
        },
        {
          "tag": "v0.0.70",
          "kind": "patch",
          "published_at": "2026-06-08T02:45:11Z"
        },
        {
          "tag": "v0.0.62",
          "kind": "patch",
          "published_at": "2026-06-06T03:36:37Z"
        },
        {
          "tag": "v0.0.61",
          "kind": "patch",
          "published_at": "2026-06-03T13:50:25Z"
        },
        {
          "tag": "v0.0.60",
          "kind": "patch",
          "published_at": "2026-06-03T02:08:06Z"
        },
        {
          "tag": "v0.0.58",
          "kind": "patch",
          "published_at": "2026-05-29T18:42:00Z"
        },
        {
          "tag": "v0.0.57",
          "kind": "patch",
          "published_at": "2026-05-28T03:28:13Z"
        },
        {
          "tag": "v0.0.56",
          "kind": "patch",
          "published_at": "2026-05-28T02:29:13Z"
        },
        {
          "tag": "v0.0.55",
          "kind": "patch",
          "published_at": "2026-05-26T02:59:43Z"
        },
        {
          "tag": "v0.0.54",
          "kind": "patch",
          "published_at": "2026-05-25T01:37:24Z"
        },
        {
          "tag": "v0.0.53",
          "kind": "patch",
          "published_at": "2026-05-22T13:08:07Z"
        },
        {
          "tag": "v0.0.52",
          "kind": "patch",
          "published_at": "2026-05-21T02:41:04Z"
        },
        {
          "tag": "v0.0.51",
          "kind": "patch",
          "published_at": "2026-05-21T02:08:03Z"
        },
        {
          "tag": "v0.0.50",
          "kind": "patch",
          "published_at": "2026-05-20T20:19:45Z"
        },
        {
          "tag": "v0.0.49",
          "kind": "patch",
          "published_at": "2026-05-20T12:25:07Z"
        },
        {
          "tag": "v0.0.48",
          "kind": "patch",
          "published_at": "2026-05-15T21:49:39Z"
        },
        {
          "tag": "v0.0.47",
          "kind": "patch",
          "published_at": "2026-05-15T20:10:28Z"
        },
        {
          "tag": "v0.0.46",
          "kind": "patch",
          "published_at": "2026-05-15T03:07:32Z"
        },
        {
          "tag": "v0.0.45",
          "kind": "patch",
          "published_at": "2026-05-14T21:30:57Z"
        },
        {
          "tag": "v0.0.44",
          "kind": "patch",
          "published_at": "2026-05-14T02:40:47Z"
        },
        {
          "tag": "v0.0.43",
          "kind": "patch",
          "published_at": "2026-05-12T18:24:51Z"
        },
        {
          "tag": "v0.0.42",
          "kind": "patch",
          "published_at": "2026-05-12T13:38:56Z"
        },
        {
          "tag": "v0.0.41",
          "kind": "patch",
          "published_at": "2026-05-08T19:43:03Z"
        },
        {
          "tag": "v0.0.40",
          "kind": "patch",
          "published_at": "2026-05-05T20:33:32Z"
        },
        {
          "tag": "v0.0.39",
          "kind": "patch",
          "published_at": "2026-05-05T16:54:48Z"
        },
        {
          "tag": "v0.0.38",
          "kind": "patch",
          "published_at": "2026-05-25T01:38:08Z"
        },
        {
          "tag": "v0.0.37",
          "kind": "patch",
          "published_at": "2026-05-04T02:56:26Z"
        },
        {
          "tag": "v0.0.36",
          "kind": "patch",
          "published_at": "2026-05-03T03:08:39Z"
        },
        {
          "tag": "v0.0.35",
          "kind": "patch",
          "published_at": "2026-05-03T01:06:08Z"
        },
        {
          "tag": "v0.0.34",
          "kind": "patch",
          "published_at": "2026-05-02T18:06:34Z"
        },
        {
          "tag": "v0.0.33",
          "kind": "patch",
          "published_at": "2026-05-01T19:44:52Z"
        },
        {
          "tag": "v0.0.31",
          "kind": "patch",
          "published_at": "2026-04-30T19:48:18Z"
        },
        {
          "tag": "v0.0.30",
          "kind": "patch",
          "published_at": "2026-04-30T19:20:34Z"
        },
        {
          "tag": "v0.0.29",
          "kind": "patch",
          "published_at": "2026-04-24T14:53:21Z"
        },
        {
          "tag": "v0.0.28",
          "kind": "patch",
          "published_at": "2026-04-23T02:27:11Z"
        },
        {
          "tag": "v0.0.27",
          "kind": "patch",
          "published_at": "2026-04-23T02:21:15Z"
        },
        {
          "tag": "v0.0.26",
          "kind": "patch",
          "published_at": "2026-04-18T21:18:12Z"
        },
        {
          "tag": "v0.0.25",
          "kind": "patch",
          "published_at": "2026-04-17T15:28:27Z"
        },
        {
          "tag": "v0.0.24",
          "kind": "patch",
          "published_at": "2026-04-14T18:13:55Z"
        },
        {
          "tag": "v0.0.23",
          "kind": "patch",
          "published_at": "2026-04-09T18:18:47Z"
        },
        {
          "tag": "v0.0.22",
          "kind": "patch",
          "published_at": "2026-04-08T14:50:03Z"
        },
        {
          "tag": "v0.0.18",
          "kind": "patch",
          "published_at": "2026-04-02T04:03:56Z"
        },
        {
          "tag": "v0.0.17",
          "kind": "patch",
          "published_at": "2026-04-02T03:30:40Z"
        },
        {
          "tag": "v0.0.16",
          "kind": "patch",
          "published_at": "2026-04-01T15:17:27Z"
        },
        {
          "tag": "v0.0.15",
          "kind": "patch",
          "published_at": "2026-04-01T14:40:43Z"
        },
        {
          "tag": "v0.0.14",
          "kind": "patch",
          "published_at": "2026-04-01T13:53:13Z"
        },
        {
          "tag": "v0.0.13",
          "kind": "patch",
          "published_at": "2026-03-31T03:28:22Z"
        },
        {
          "tag": "v0.0.12",
          "kind": "patch",
          "published_at": "2026-03-30T19:28:06Z"
        },
        {
          "tag": "v0.0.11",
          "kind": "patch",
          "published_at": "2026-03-30T15:47:15Z"
        },
        {
          "tag": "v0.0.10",
          "kind": "patch",
          "published_at": "2026-03-29T03:48:36Z"
        },
        {
          "tag": "v0.0.9",
          "kind": "patch",
          "published_at": "2026-03-29T03:17:44Z"
        },
        {
          "tag": "v0.0.8",
          "kind": "patch",
          "published_at": "2026-03-29T01:26:39Z"
        },
        {
          "tag": "v0.0.7",
          "kind": "patch",
          "published_at": "2026-03-29T00:11:59Z"
        },
        {
          "tag": "v0.0.6",
          "kind": "patch",
          "published_at": "2026-03-29T00:09:22Z"
        },
        {
          "tag": "v0.0.5",
          "kind": "patch",
          "published_at": "2026-03-28T23:43:21Z"
        },
        {
          "tag": "v0.0.4",
          "kind": "patch",
          "published_at": "2026-03-28T23:40:10Z"
        },
        {
          "tag": "v0.0.3",
          "kind": "patch",
          "published_at": "2026-03-28T23:33:29Z"
        },
        {
          "tag": "v0.0.2",
          "kind": "patch",
          "published_at": "2026-03-28T22:17:12Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "744099fd2f3c926c93124083b6f3d3543c6e7984",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): stamp v0.0.70 and v0.0.71",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-07-17T21:38:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d6d6a9fb887dc995a2911c17839825302a968fb3",
          "body": null,
          "is_bot": false,
          "headline": "feat(template): disable model invocation on all bender skills",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-07-16T01:50:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ce20eedfde4a905d599710369b070400584cdc7",
          "body": "…spatcher (#34)\n\n* feat(status): add needs-input workflow status\n\n* feat(cli): add merge command for dependency-ordered merge-back\n\nExpose the merge-back step as a standalone `pb merge <slug>` / `pba merge`\nso it survives the upcoming removal of the dispatch loop. Purely additive:\nthe Run/RunBatch/r\n[…]\n still advertised `pb dispatch <slug>`, a command\nremoved in this branch, and setup_test pinned the stale string. Relocate the\nimplementation entry point to the agent section as /bender-implement-prd.",
          "is_bot": false,
          "headline": "feat(dispatch)!: replace cold-subprocess engine with live Workflow di…",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-08T02:38:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8eaee07b9cad30f1e622d7826590799b1539c880",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): stamp v0.0.61 and v0.0.62",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-06T12:56:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "40648264c29a47bd00f458edf108d7a967c4c9e8",
          "body": "When `no_implement: true` (default false), `pb setup`/`pb generate` skip\ngenerating the implementation skills (bender-implement-prd,\nbender-implement-hitl, bender-implement-issue) and drop them from the\norchestrator menu. Flipping the flag on removes any previously generated\ncopies and prunes their installed symlinks on the next run, reusing the\nexisting wipe-and-prune path.",
          "is_bot": false,
          "headline": "feat(config): add no_implement flag to skip implementation skills",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-06T03:34:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3eaed5a8f16311e57e0bf40cf02f14085142cd4a",
          "body": "…-issues skills\n\nBoth were superseded by bender-write-plan, which drafts the PRD and\ndecomposes issues in one pass. Slated for removal in >=0.0.60. pb setup\nno longer generates either skill and the pipeline menu no longer lists\nthem. The plan-bender-agent write-prd CLI command is retained —\nbender-write-plan still uses it to write prd.json.",
          "is_bot": false,
          "headline": "feat(template)!: remove deprecated bender-write-prd and bender-prd-to…",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-03T13:47:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4048d0783fcd868d32c7e7aaa937be9db0cbe0fe",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): stamp v0.0.53 through v0.0.60",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-03T02:15:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a841fff6ad54f3f1d9fc3ed62a82d43ed11c360b",
          "body": "The skill still described the pre-integration-worktree model: after_batch\nrunning in the repo root, dispatch refusing a dirty tree, and HEAD being\ncaptured/restored. Align with docs/cli.md + ADR-0003 — merge-back, status\nflips, and after_batch run in the per-slug integration worktree; the parent\nrepo's HEAD is never touched and a dirty parent is allowed.",
          "is_bot": false,
          "headline": "docs(cli): correct stale dispatch lifecycle in plan-bender-cli skill",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-03T01:52:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7079c271719b71d61aaa74075cf1316b6b6c0f35",
          "body": "- rename \"completion sentinel\" -> \"completion marker\" everywhere; the\n  <pba:complete/> line is a log marker, not dispatch's completion signal\n  (the in-review status flip is). pba complete JSON field sentinel->marker.\n  Glossary entries added to CONTEXT.md.\n- hide the `completion` command so it no \n[…]\ne line\n  (root SilenceUsage otherwise hid them)\n- plan-not-found: drop the leaked reading-prd/ENOENT chain\n- docs: open the browser on linux/windows too, not just macOS\n- setup: add -y short for --yes",
          "is_bot": false,
          "headline": "fix(cli): polish command surface from CLI review",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-03T01:37:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "903b0110d6de6ac13f9aecb3686fb4dd78859550",
          "body": "Regeneration only ever removed the per-skill dirs still present in the\ntemplate set, so renamed, removed, or filtered-out skills (e.g. backend\nskills with Linear disabled) were orphaned in .plan-bender/skills/ and\ntheir installed symlinks left dangling in each agent's skills dir.\n\nGenerateSkills now\n[…]\nngling symlinks that\npoint into that source dir. Real dirs and symlinks pointing elsewhere\nare left alone, so a user's own skills and links from other projects in\na shared user-scoped dir stay intact.",
          "is_bot": false,
          "headline": "fix(cli): prune stale skills on generate/setup",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-03T01:26:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "afc010ba18d20924a260393397998cbb7b2e6fc1",
          "body": "Add a §0 that makes a dispatched sub-agent detect INTEGRATION vs STANDALONE mode up front (cwd contains -wt/, branch contains --, or the prompt's issue is already in-progress with a branch it didn't create). In integration mode: skip §2/§8, never ask the operator (stdout is consumed by dispatch, not\n[…]\ners, so the sub-agent ran the standalone completion flow and stalled dispatch.\n\nAlso fix §9 prose claiming dispatch detects the completion sentinel on stdout; the trigger is the in-review status flip.",
          "is_bot": false,
          "headline": "feat(template): integration-mode preamble for bender-implement-issue",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-03T01:26:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9c1e67a9d751c2e9ba0835e0010c673ce8a835c0",
          "body": "A dispatched sub-agent runs from its worktree, where `pba complete` resolved plans_dir relative to the worktree's own checkout and flipped a copy the dispatcher never re-reads. With a git-tracked plans_dir the two diverge: the worktree shows in-review, the parent stays in-progress, and Verdict block\n[…]\nr defeats.\n\nAlso correct complete.go comments claiming dispatch detects the sentinel on stdout — the contract is the status-file re-read (Verdict); the <pba:complete/> line is a human-readable marker.",
          "is_bot": false,
          "headline": "fix(dispatch): route sub-agent pba complete to the parent plans store",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-06-03T01:26:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4c33afadb50dbdb1c84222f1346c60bd68f93536",
          "body": "\"merge issue #N\" auto-links to an unrelated GitHub issue and the\nplan-local number is meaningless on the remote. Derive the merge commit\nsubject from the issue name, falling back to the branch name.",
          "is_bot": false,
          "headline": "fix(dispatch): use issue name as merge subject instead of plan number",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-29T18:39:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d86ea297351045e417770e843fa118dbe857cb74",
          "body": null,
          "is_bot": false,
          "headline": "fix: stop referencing issue numbers in gh",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-29T18:31:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "643400f9786663d70cd6c2a6912e6a2db21acac3",
          "body": "…near op\n\nEvery Linear read/write now reads the project .plan-bender.json and refuses\nwith an error when it explicitly sets linear.enabled:false, making the flag a\nlive kill-switch. The file's explicit flag is read directly rather than the\nmerged config because mergeLinear only turns enabled on, so a project-level\nfalse could never override a global enable. Threads project root through\nbackend.New -> NewLinear.",
          "is_bot": false,
          "headline": "feat(backend): re-check linear.enabled in project file before each Li…",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-29T18:31:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef728c2af7dd698d9b141a224fd0350845cb7e63",
          "body": "* docs(adr): record dispatch completion-mode pre-flight prompt\n\nADR 0005 captures the decision to add a pre-flight three-mode prompt\n(merge/branch/pr) before dispatch runs, replacing the unconditional\nPR-at-end step. CONTEXT.md gains \"integration branch\" and \"landing\nbranch\" entries so the prompt UX\n[…]\nker.\n\nThe merge block uses `pba worktree gc <slug>` (which removes the worktree dir\nAND deletes the branch) rather than `git branch -d`, which would fail on a\nbranch still checked out in the worktree.",
          "is_bot": false,
          "headline": "feat(template): three-mode completion prompt for dispatch skills (#33)",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-28T03:26:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "20c2c48d979feb982b86c213ada49aa357ebc9e3",
          "body": "…-plan\n\nThe two skills always ran sequentially with a forced handoff between them.\nCombine them into one bender-write-plan skill that interviews, drafts the\nPRD, and decomposes it into issues in a single pass (honoring\nreview_with_user for the two review checkpoints). Mark the legacy skills\nas deprecated in their frontmatter + body; both still work and will be\nremoved in >=0.0.60.",
          "is_bot": false,
          "headline": "feat(template): combine write-prd and prd-to-issues into bender-write…",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-27T19:42:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "033ef27611d647d16268815c76a245f0ea891b64",
          "body": "feat: ship supporting files alongside SKILL.md in skill templates",
          "is_bot": false,
          "headline": "Merge pull request #32 from jasonraimondi/feat/skill-supporting-files",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-26T02:57:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6a4fef4e8716cc4e4066c91e361df295ccd69278",
          "body": "Drop assertions for the agent-conditional intro and issues URL that\nwere removed in f985c5c. Repoint the multi-agent generate check at\nbender-implement-hitl, which still carries the conditional.",
          "is_bot": false,
          "headline": "test: align interview-me tests with simplified template",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-26T02:56:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "70426f76f13434efa6a2ecea4736cd3e4c2a7df3",
          "body": "Two gaps in skill-template tests:\n\n- bender-sync-linear is filtered out by SkillRequiresBackend when Linear\n  is disabled, but no test asserted the directory was absent or present\n  based on cfg.Linear.Enabled. Now covered both ways.\n\n- The collision check would catch a verbatim SKILL.md silently shadowing\n  the rendered SKILL.md.tmpl body, but only by accident — no test pinned\n  it. Add the body-shadow case alongside the existing NOTE.md collision.",
          "is_bot": false,
          "headline": "test: cover Linear toggle and body-shadow collision cases",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-26T02:48:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "84cafbc8cd05289911b4c9d934c239f69513ba78",
          "body": "Skill.Name was written but never read in production; the map key already\ncarries it. Removing keeps the type minimal and the struct literal honest.\n\nIterate skills and files in sorted order in validate() so collision and\nmissing-body errors are deterministic across runs (map iteration order\notherwise leaks into error messages).",
          "is_bot": false,
          "headline": "refactor(template): drop dead Skill.Name, sort validate errors",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-26T02:48:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f985c5c12e4c4144450e48a0ca78906c6a874050",
          "body": null,
          "is_bot": false,
          "headline": "fix: simplify the interview me skill",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-26T02:43:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c6974cf06d4d2d60eb9607bf1033a7cb06fae9d2",
          "body": "A subdir under .plan-bender/templates/ whose name doesn't match a bundled\nskill was promoted to a phantom skill, then validate() hard-failed on the\nmissing SKILL.md.tmpl body — aborting LoadTemplates for every agent.\n\nAccept an override dir only when its name matches a bundled skill or it\nships its own SKILL.md.tmpl; silently skip the rest.",
          "is_bot": false,
          "headline": "fix(template): ignore stray override dirs instead of bricking the loader",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-26T02:11:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a807d8ac618118b1c645dce800b85fe63edb544e",
          "body": "`pb setup` called GenerateSkills + symlinkSkills directly without the\nwarnStaleTemplateOverrides hop, so a pre-existing flat `{name}.skill.tmpl`\noverride silently vanished through the documented entry point even though\ndocs/configuration.md and ADR 0004 promised a warning.",
          "is_bot": false,
          "headline": "fix(setup): emit stale-override warning from pb setup",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-26T02:11:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "90c2b54096c27333960e3669422abea81d99169b",
          "body": null,
          "is_bot": false,
          "headline": "docs: document skill directory layout and supporting files",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T16:59:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cfe3a93b566751c5673db404684fcdc21ed48ad9",
          "body": "RemoveAll the per-skill output dir before writing, then render .tmpl\nfiles (stripping the suffix) and copy all other files verbatim,\npreserving subdirectory structure via writeSkill helper.",
          "is_bot": false,
          "headline": "feat: emit skill supporting files into generated skills",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T16:52:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "88ed61e961c8c4d6e8425f7f41b637924c4cbdcf",
          "body": null,
          "is_bot": false,
          "headline": "feat: warn on stale flat overrides and dir-located forks",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T16:50:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5240e1d840bce512e19b4a4a17332c69ea8f5ca9",
          "body": null,
          "is_bot": false,
          "headline": "feat: validate skill templates have a body and no output collisions",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T16:42:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e87b6278f9c1fa6f8bc714524b1c2c377cc34eba",
          "body": "Move embedded *.skill.tmpl flat files into {name}/SKILL.md.tmpl directories.\nChange LoadTemplates to return map[string]Skill (with Main() accessor) instead\nof map[string]string. Update GenerateSkills and all tests accordingly.",
          "is_bot": false,
          "headline": "refactor: skill templates as per-skill directories",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T16:37:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3ddd4ffb78949cc81e5e657c756dac338d1e815e",
          "body": null,
          "is_bot": false,
          "headline": "docs: implementation plan for skill supporting files",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T16:28:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1a481630b00a2b8e1a91482a9b1be0353a3fbd5b",
          "body": "Skill templates become per-skill directories so they can ship supporting files (e.g. CONTEXT-FORMAT.md) alongside SKILL.md. Records the directory model, the breaking flat-override change, and the domain glossary.",
          "is_bot": false,
          "headline": "docs: design, ADR, glossary for skill supporting files",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T02:48:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c0e6d920970230ac2339f7e78094a241e8569dcc",
          "body": null,
          "is_bot": false,
          "headline": "chore(gitignore): ignore serena workspace",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T01:35:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e2e52e6046053c59fded3a77c373a67a1b4c1504",
          "body": "Wrap all-setup failures with a sentinel so report_bugs ignores stuck or lock-contention errors. Fold per-issue worktree paths when grouping setup causes.",
          "is_bot": false,
          "headline": "fix(dispatch): limit bug reports to setup failures",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-25T01:34:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "531b6b3cf64d758ea07f6c20dffb2bdf11d20ea3",
          "body": "…failures (#30)\n\n* fix(dispatch): provision worktree skills per-child, surface setup failures\n\nlinkPlansDir symlinked .claude/skills only when the dir was absent in the\nworktree. A repo that git-tracks even one skill makes git recreate\n.claude/skills in every fresh worktree, so the linker skipped an\n[…]\nrop redundant/nonlocal comments in linker tests\n\nRemove two section-label comments that restated the assertions beneath them\nand trim a nonlocal reference to the session retro from a test doc comment.",
          "is_bot": false,
          "headline": "fix(dispatch): provision worktree skills per-child and surface setup …",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-24T16:46:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fe8214e678e6380589a5b7b27f04902f2b1fdfb8",
          "body": "Status transitions (retry/complete/worktree create) committed through the\nwhole-plan validation path, so one rule-invalid issue anywhere blocked\nrecovery of every other issue -- exactly when the status->retry flow is\nneeded most.\n\nAdd CommitTouched, which validates only the mutated entities, skippin\n[…]\ntatus\nflip can't break. The status adapter's Save now uses it. Authoring/sync\ncommits keep whole-plan validation (their only consistency gate), and\n`agent validate` remains the strict whole-plan gate.",
          "is_bot": false,
          "headline": "fix(planrepo): scope status-commit validation to the touched issue (#31)",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-24T16:46:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ee073aa723578494d0961429d435c4f3c38898c5",
          "body": "pb setup now inserts a \"$schema\" key into existing .plan-bender.json /\n.plan-bender.local.json when missing, preserving formatting and unknown\nkeys. Drops the stale pi starter-config assertion.",
          "is_bot": false,
          "headline": "feat(setup): backfill $schema into existing config files",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-22T01:54:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "367efd7964aa93c6e6d6c21e065a84c319252aeb",
          "body": "dc3fbd1 dropped pi from scaffolded configs but left the test asserting\n'\"pi\": true'. Assert pi is absent instead.",
          "is_bot": false,
          "headline": "test(setup): assert pi absent from starter config defaults",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-21T21:52:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d31d1c464f251cd66a811fffafad2460b6f8f3c6",
          "body": "… missing issues/\n\nwrite-prd failed with 'reading prd {slug}/prd.json: no such file' whenever\nthe slug directory already existed without a prd.json (e.g. a leftover/empty\ndir from a prior partial run): OpenOrCreate treated any existing dir as\nloadable. Treat a slug with no prd.json and no issues/ tr\n[…]\nror.\n\nAlso: a missing issues/ dir now means zero issues (not a load error), so a\nfreshly written PRD validates before decomposition; and write-prd/write-issue\naccept '-' as the file arg to read stdin.",
          "is_bot": false,
          "headline": "fix(write-prd): create PRD into existing/empty slug dirs and tolerate…",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-21T21:52:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5248deff190dec94965d56ade86807864d1128d3",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): stamp v0.0.51 and v0.0.52",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-21T02:39:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "762d6c96349cff58a917fc35b51139839f5f2ba5",
          "body": null,
          "is_bot": false,
          "headline": "chore(config): enable interview_with_docs",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-21T02:35:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc3fbd1cc00d1b133619a9752585237eee267997",
          "body": null,
          "is_bot": false,
          "headline": "feat(config): drop pi from starter config defaults",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-21T02:35:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dd1c83d6c109a7b870131c8bc84c3c97ffe6d6a6",
          "body": "pb setup now writes a \"$schema\" key pointing at the published schema so\nnew .plan-bender.json files get editor validation out of the box.",
          "is_bot": false,
          "headline": "feat(config): scaffold new configs with $schema reference",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-21T02:32:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "000a4e570de652e665d597e93b1c60187b4b4f47",
          "body": "Hand-written draft 2020-12 schema modeling the full config (agents\nbool|object union, pipeline/linear/hooks, custom_fields enum rule).\nReference it via $schema for editor validation and autocomplete.",
          "is_bot": false,
          "headline": "feat(config): publish JSON Schema for .plan-bender.json",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-21T02:30:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f52ad3bd953d0fe38070d76ca2f2e69127d3511d",
          "body": "* feat(dispatch): per-slug lock rejects same-slug parallel runs\n\nTryFlock takes a non-blocking exclusive flock and returns ErrLocked on\ncontention so callers can distinguish lock-held from other I/O failures.\nDispatcher.Run acquires {plansDir}/{slug}/.dispatch.lock before any work\nand releases on ex\n[…]\ne the GC integration-branch inline block that duplicated the\nfunction doc, and drop two comments that restated the code (a git\nadd/commit/branch loop and a sleep already explained by the block above).",
          "is_bot": false,
          "headline": "Parallel dispatch + configurable worktree base (#29)",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-21T02:05:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b33a0f2b39bfff843b9bb2d0d4f0acda8903b579",
          "body": null,
          "is_bot": false,
          "headline": "docs(interview-me): default to new plan unless slug named",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-20T19:35:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2fb6625f8c7e8d3252fb2e022a386b4f44cef775",
          "body": "fix(dispatch): dispatch reliability hardening",
          "is_bot": false,
          "headline": "Merge pull request #28 from jasonraimondi/jason/dispatch-reliability",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-20T03:05:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f2f7e954a9161aa7e6dd8895f15dc1854dbceacf",
          "body": "The truncation-race tests used echo, which writes a trailing newline —\nlinePrefixWriter emitted the line through the normal Write path and the\npost-Wait Flush() was never exercised. Swap to printf so the partial-line\nbuffer is the only path that delivers the tail, matching the regression\nthe tests c\n[…]\nir) is asserted to clean up\nits leaked worktree — previously only Claim was covered. The\nlinkPlansDir variant commits .plan-bender to the integration branch to\ntrigger the narrowed real-dir rejection.",
          "is_bot": false,
          "headline": "test(dispatch): exercise flush path and remaining cleanup branches",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-20T03:03:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f2b2662cb4e416d03be242178148c79b5009cd25",
          "body": "A real .plan-bender in the worktree silently routes sub-agent writes away\nfrom the dispatch loop's parent state. Narrow linkPlansDir's real-dir\ntolerance to .claude/skills only (skills are legitimately committed),\nand reject a real .plan-bender so the failure surfaces loudly.\n\nAlso thread caller ctx\n[…]\nubprocess uses a fresh ctx because the subprocess ctx may be\ndeadline-exceeded — otherwise the read fails on lock contention and\nVerdict falls back to exit-code even when the sub-agent flipped status.",
          "is_bot": false,
          "headline": "fix(dispatch): narrow linkPlansDir tolerance and thread ctx into reads",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-20T03:03:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8f94057490ca4eacd3f48d29c2943e04b4e46962",
          "body": "A subprocess_timeout SIGKILL or Ctrl-C cancelling the dispatch loop\nwould otherwise drop the failure-path blocked-state transition and\nleave the issue in-progress for the next loop to re-pick. Route the\ntransition through a fresh ctx bounded by blockTransitionTimeout in\nboth RunSubprocess and markBlockedAndWarn.",
          "is_bot": false,
          "headline": "fix(dispatch): detach blocked-state write from parent ctx",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-20T02:45:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4ba4c41b899df4e686296215f6bee1e54b3d5dd1",
          "body": null,
          "is_bot": false,
          "headline": "style(dispatch): drop redundant comments and internal incident slug",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-20T02:44:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7acca6c04ce4d47d658dd1703eed9718017c7955",
          "body": "* jason/dispatch-reliability--2-restructure-subprocess-io:\n  fix(dispatch): kill StdoutPipe/Wait race with line-prefixing writer",
          "is_bot": false,
          "headline": "merge issue #2",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:22:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "78969bdc8469039511b23c2b303540853d16ddd7",
          "body": "Replace cmd.StdoutPipe + an explicit reader goroutine with a\nlinePrefixWriter set as cmd.Stdout in both RunSubprocess and RunHook.\nos/exec now owns the copy goroutine, so cmd.Wait (already bounded by\nWaitDelay from issue 1) is the single synchronization point — the\ndocumented hazard of calling Wait \n[…]\nlonger be\nlost when Wait closes the pipe.\n\nPartial lines buffer until the next newline and Flush emits any\ntrailing fragment after Wait, so a single huge stream-json event is\nnever split or truncated.",
          "is_bot": false,
          "headline": "fix(dispatch): kill StdoutPipe/Wait race with line-prefixing writer",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:21:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2239238abfeac75beeb83d006015be85930682ab",
          "body": "* jason/dispatch-reliability--9-cleanup-leaked-worktree-on-claim-failure:\n  fix(dispatch): clean up a leaked worktree on pre-subprocess failure",
          "is_bot": false,
          "headline": "merge issue #9",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7d7ade36b9a79a81911f274f7b558aabb964a422",
          "body": "* jason/dispatch-reliability--8-preserve-prior-dispatch-logs:\n  feat(dispatch): append to per-issue log across re-dispatch runs",
          "is_bot": false,
          "headline": "merge issue #8",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c25355ba0cc500d2f8c57e201f657b204eeaac3d",
          "body": "* jason/dispatch-reliability--7-route-loadissue-shared-planrepo-handle:\n  refactor(dispatch): route loadIssue through the shared planrepo handle",
          "is_bot": false,
          "headline": "merge issue #7",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6c5f3606f2ac47ac134fc010e6efde97ee18037a",
          "body": "* jason/dispatch-reliability--6-dedupe-block-status-label-helpers:\n  refactor(dispatch): dedupe block-status and label helpers",
          "is_bot": false,
          "headline": "merge issue #6",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7197fb373bffcb06fe0127a57de36ec71f1f2a45",
          "body": "* jason/dispatch-reliability--5-linkplansdir-tolerate-real-skills-dir:\n  fix(dispatch): tolerate a committed .claude/skills dir in the worktree",
          "is_bot": false,
          "headline": "merge issue #5",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2b13db3d38251c975e6b7f218c06d41ee5d7d0cc",
          "body": "* jason/dispatch-reliability--4-ctx-aware-plan-lock:\n  feat(planrepo): ctx-aware plan lock acquisition",
          "is_bot": false,
          "headline": "merge issue #4",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4611302760f959531b3b26df8e821d9ecf1146eb",
          "body": "* jason/dispatch-reliability--3-bound-batch-parallelism:\n  feat(dispatch): bound batch parallelism with pipeline.max_parallel",
          "is_bot": false,
          "headline": "merge issue #3",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6ac9e21e55c28947f35d06b91b7f79967f2ce340",
          "body": "* jason/dispatch-reliability--1-process-group-kill-waitdelay:\n  fix(dispatch): kill the process group and bound cmd.Wait on timeout",
          "is_bot": false,
          "headline": "merge issue #1",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6536fb70fdf49e5c527c05b4ea0674d7698fefca",
          "body": "RunBatch previously fanned out one goroutine per ready AFK issue, so a\nplan with 20 ready slices spawned 20 heavyweight `claude` subprocesses at\nonce (model API + MCP servers + a git worktree apiece). Add a worker\npool capped at pipeline.max_parallel (default 3) so the dispatcher\nmatches real machin\n[…]\ntinguishing the two with a plain int isn't possible.\n\nAlso drop RunBatch's always-nil error return (finding #9). The\ngoroutines route every failure through SubResult; the second return\nvalue was dead.",
          "is_bot": false,
          "headline": "feat(dispatch): bound batch parallelism with pipeline.max_parallel",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:12:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0e65743e5543a1997efad21ae70f38b42fa8d39c",
          "body": "Threads ctx through Store.OpenSession, Plans.OpenContext, and LockPlanDir\non Unix (flock LOCK_NB) and Windows (LockFileEx LOCKFILE_FAIL_IMMEDIATELY).\nA canceled or timed-out ctx unwinds a wait for a held plan lock instead of\nblocking unkillably. The uncontended path still acquires on the first\nattempt without consulting ctx. status.Owner.Transition and Claim stop\ndiscarding their ctx.",
          "is_bot": false,
          "headline": "feat(planrepo): ctx-aware plan lock acquisition",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:11:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e3b7e706288f375fbc327a205d37adc1c60eec3d",
          "body": "When runOne failed after worktree.Create but before RunSubprocess\n(Claim, linkPlansDir, before_issue hook, or BuildPrompt), the worktree\nwas left orphaned on disk. Add worktree.Remove and call it from each\nof those failure paths; a removal failure warns but does not mask the\noriginal error.",
          "is_bot": false,
          "headline": "fix(dispatch): clean up a leaked worktree on pre-subprocess failure",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:10:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dcd21cc8a1425dbcf96d54a7569ae87039847d14",
          "body": "Extract the [backlog, todo, in-progress, in-review] blocked-from set\ninto a package-level blockFromStatuses shared by RunSubprocess's block\nhelper and Dispatcher.markBlockedAndWarn.\n\nReplace the duplicated hasLabel helpers in internal/dispatch and\ninternal/plan with a single Issue.HasLabel method on schema.",
          "is_bot": false,
          "headline": "refactor(dispatch): dedupe block-status and label helpers",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:10:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "846c39e480e9fdb87ee775c28ae8c0d081a14b92",
          "body": "A timed-out claude or hook subprocess could hang for the natural\nlifetime of a grandchild process (MCP server, bash tool) that\ninherited the stdout/stderr pipe: the surviving write end keeps the\nI/O-copy goroutine alive so cmd.Wait never returns.\n\nconfigureProcessGroup puts the child in its own proc\n[…]\nhole group, reaping\ngrandchildren so the pipes close. cmd.WaitDelay (10s) backstops\ncmd.Wait regardless. Windows has no process groups, so the helper\nis a no-op there; WaitDelay still bounds the wait.",
          "is_bot": false,
          "headline": "fix(dispatch): kill the process group and bound cmd.Wait on timeout",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:09:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "83b5ec05d6e163630232d84a3eb82dcd113d2c69",
          "body": "RunSubprocess took a plansDir and loadIssue rebuilt a fresh\nplanrepo.NewProd from it on every post-run read. Pass the dispatcher's\nmemoized planrepo.Plans handle in instead, so every read in a Run flows\nthrough the same handle the plansOnce comment claims it does.\n\nCorrect the plansOnce/ownerOnce comments: the status.Owner wraps its own\nplanrepo handle, distinct from `plans`, so reads and status writes never\nshared a handle — only the on-disk plansDir.",
          "is_bot": false,
          "headline": "refactor(dispatch): route loadIssue through the shared planrepo handle",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:08:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "23e0f241ac54d551aab8f264e14ac650b323ef1f",
          "body": "linkPlansDir kept a real directory at the destination but then let\nos.Symlink fail with EEXIST, blocking the issue. Now a non-symlink at\ndst is logged and skipped so dispatch links what it can and proceeds.",
          "is_bot": false,
          "headline": "fix(dispatch): tolerate a committed .claude/skills dir in the worktree",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:07:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bdd955e1c1c74d07d75f68fe3093c9ab301b904a",
          "body": "writeLog truncated the log on every run, so re-dispatching an issue\ndiscarded the prior run's transcript. Open the log with O_APPEND and\nwrite a timestamped run-separator header before each run's output.",
          "is_bot": false,
          "headline": "feat(dispatch): append to per-issue log across re-dispatch runs",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T21:06:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a1439e5f18d709495d44fc7638f8e9432d714bdd",
          "body": "The stuck error reused plan.Resolve's BlockedCount, which counts only\ndependency-blocked issues. An issue blocked operationally (killed sub-agent,\nmerge conflict, failed hook) has no open deps and went uncounted, yielding\na misleading \"0 blocked\" on a run that had just blocked an issue. Count\nstatus==blocked directly and name the IDs so the operator knows what to fix.",
          "is_bot": false,
          "headline": "fix(dispatch): count blocked issues honestly in the stuck error",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T18:38:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "21d52b88530e29473a6a821fa858223380f920ce",
          "body": "A subprocess killed by exec.CommandContext's deadline was indistinguishable\nfrom an OS OOM-kill — both surfaced as \"code -1: signal: killed\". Detect\ncontext.DeadlineExceeded after Wait and name the subprocess_timeout knob in\nthe blocked-state reason.",
          "is_bot": false,
          "headline": "fix(dispatch): report a deadline SIGKILL as a subprocess_timeout",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T18:38:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "84a5bfcb237111792de1b66724a4c481c83d8a66",
          "body": "A sub-agent that ran pba complete (status -> in-review) and was then\nkilled during wrap-up had its finished work downgraded to blocked,\nbecause Verdict ranked exitErr above the post-run status. Make an\nin-review post-status outrank exitErr so completed work merges instead.",
          "is_bot": false,
          "headline": "fix(dispatch): trust in-review post-status over a wrap-up SIGKILL",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T18:38:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a91e216f5058a727d4c1f03b89ff5eb411cd4d86",
          "body": "…#25)\n\nWhen interview_with_docs is true, the bender-interview-me and\nbender-write-prd skills gain a grill-with-docs-style domain-awareness\nblock: glossary challenges, fuzzy-term sharpening, scenario stress-tests,\ncode cross-referencing, inline CONTEXT.md writes, and sparse ADRs.\nbender-interview-me \n[…]\ntioning.\n\nThe flag defaults to false; with it off both skills render byte-identical\nto today. Plumbed field-for-field after report_bugs across the config\nstruct, defaults, merge, and template context.",
          "is_bot": false,
          "headline": "feat(config): add interview_with_docs flag for grill-style planning (…",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-19T17:29:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7ae327781bbc29e17065849147cb7f7d5a97d6b0",
          "body": "feat(sync): publish full plan content to Linear",
          "is_bot": false,
          "headline": "Merge pull request #23 from jasonraimondi/jason/linear-sync-full-content",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T21:47:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b851aa4b6b199a39f055b39c8868a1ab4f9501c3",
          "body": "ADR 0002: push publishes full plan content one-way with plan JSON\ncanonical; pull mirrors back only status, priority, assignee.",
          "is_bot": false,
          "headline": "docs(adr): record one-way Linear sync publish decision",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T20:46:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "92a90a1c3bb402f77780466e2c8a9605548379f0",
          "body": "Add a plan-bender-cli reference skill and a PostToolUse hook that nudges\nupdating SKILL.md and docs/cli.md when CLI-defining Go files change.",
          "is_bot": false,
          "headline": "chore(skills): add plan-bender-cli skill and CLI doc-sync hook",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T20:46:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "db0a9604b2ba22c5542d0213fe4944640d3281f3",
          "body": "Test helpers, fixture constants, and test names referred to plan\nfiles as YAML (issueYAML, loadIssueYAML, *IssueYAML constants,\nTestX_MalformedYAML, Test*Yaml_RoundTrip). The files they produce\nand parse are JSON. Legacy-YAML detection tests and migrate_test.go\nkeep their YAML references intentionally.",
          "is_bot": false,
          "headline": "test: rename stale YAML identifiers to JSON",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T20:45:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "867e8c22c55f61a050e15b075078f9751f2f4bd3",
          "body": "Command help text, an error message, and comments referred to plan\nfiles as YAML; the format is JSON. The subprocess.go \"YAML\nfrontmatter\" comment is left intact — it accurately describes the\nskill body's markdown frontmatter.",
          "is_bot": false,
          "headline": "refactor: replace stale YAML terminology with JSON in source",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T20:45:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1201ff70fab3d541927469ff222932b69c829653",
          "body": "Skill templates described plan files as YAML; the on-disk format is\nJSON. Update the prose so generated skills are accurate.",
          "is_bot": false,
          "headline": "chore(skills): replace stale YAML terminology with JSON in templates",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T20:45:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f252676172a3ee37f34e2a44d119f608232baab4",
          "body": "Plan files migrated from YAML to JSON; scrub user-facing docs so the\ndescribed format matches what's on disk. The `pb migrate` reference\nkeeps `.yaml` since it describes the legacy-to-JSON conversion.",
          "is_bot": false,
          "headline": "docs: replace stale YAML terminology with JSON",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T20:44:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "28d3c2feacbb3ce6dce1adc764ad8e42004f674f",
          "body": "defaultSyncPlanFiles gated skill regeneration on the presence of\n.plan-bender.yaml/.plan-bender.local.yaml. After `pb migrate` those\nfiles no longer exist, so `pb self-update` silently stopped\nregenerating skills. Check the .json config files instead.",
          "is_bot": false,
          "headline": "fix(self-update): detect JSON config files, not legacy YAML",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T20:44:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2d156b6152d2251cd06e44b63ac9dbeeb9648298",
          "body": "…base-flag\n\nfeat(dispatch): add --base flag to pb dispatch",
          "is_bot": false,
          "headline": "Merge pull request #20 from jasonraimondi/jason/dispatch-base--1-add-…",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T18:16:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9621b4acb3df0137a811c6a9607e87c0607b5dae",
          "body": "Test names already describe what they cover; keeping only comments\nthat explain non-obvious setup or assertion intent.",
          "is_bot": false,
          "headline": "chore(tests): prune redundant test-doc comments",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T16:37:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "501659f527c0cd2cf560fc8f598bcc4310ac48f8",
          "body": "Opt-in --base <commit-ish> overrides the auto-detected default branch\nas the integration branch's fork point (or merge target under direct\nstrategy). Validated via git rev-parse before any worktree is created.\nWhen the integration branch already exists from a prior run, an explicit\n--base is ignored with a warning rather than re-forking — re-forking\nwould clobber merged work.\n\nDecision context in docs/adr/0001-dispatch-base-flag-not-default-change.md.",
          "is_bot": false,
          "headline": "feat(dispatch): add --base flag to pb dispatch",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-15T15:22:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bccd5326ea42761334917ed3c4d22e465470f3ca",
          "body": "End-of-session self-improvement pass on plan-bender itself. Scans\nconversation memory, the TodoWrite trail, pb-error-report-*.log files,\nand plan-state anomalies, then writes a structured log to\n.plan-bender/retros/<UTC-timestamp>.log.\n\nSwitched the conditional bug-report test marker from \"pb-error-report-\"\nto \"## Bug reports\" because the retro skill legitimately mentions the\nlog filename pattern in its body; the heading is a more semantic check\nfor whether the footer block rendered.",
          "is_bot": false,
          "headline": "feat(skills): add bender-retrospective skill",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-14T21:26:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "75b2fafa767c034032e4dd945dc0c6bb60ba5b20",
          "body": null,
          "is_bot": false,
          "headline": "chore: prune redundant doc comments",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-14T19:08:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d40b5b0e745d470a8004b4c909b8fd750c798c7b",
          "body": "Tab completion produces slugs like \"jason/plans/foo\" when plansDir\nis \"./jason/plans/\"; the loader joined them twice and reported the\nplan missing. Open/OpenOrCreate now normalize the slug so both bare\nand path-style forms resolve.",
          "is_bot": false,
          "headline": "fix(planrepo): strip plansDir prefix from slug args",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-14T18:40:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fb43e4c95569f62d35cfa9ad2b8a656b48d34222",
          "body": null,
          "is_bot": false,
          "headline": "fix(skills): harden HITL handoff flow",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-14T14:55:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d29ce08582b1bb04c27f723b8f0206485fd54bc9",
          "body": null,
          "is_bot": false,
          "headline": "feat(skills): add HITL implementation skill",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-13T02:30:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "965abec6c86b9815b40c07ee1a7deda4fe6ad0bb",
          "body": null,
          "is_bot": false,
          "headline": "chore: run pb migrate",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-13T02:28:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9b5309c023357b4d563c24a4b5cbc926f369da33",
          "body": "feat(locksafe): add plan session lock analyzer",
          "is_bot": false,
          "headline": "Merge pull request #18 from jasonraimondi/refactor/yaml-to-json",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T18:19:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "17a61ee0641f43daf97aabeffca0193217e411c7",
          "body": null,
          "is_bot": false,
          "headline": "test(cli): restore cwd in command tests",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T15:30:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "75945335af6e99d9cfe22f9bcf78aa6af54040e0",
          "body": null,
          "is_bot": false,
          "headline": "test(locksafe): cover subprocess lock checks",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T15:24:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8d6c1bbce2b41bb4061b9113583418c693d11da5",
          "body": null,
          "is_bot": false,
          "headline": "feat(locksafe): add plan session analyzer",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T13:11:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "73015ca8ad4a0eae96ba90c416678a1a97db4a14",
          "body": "* origin/refactor/internal-comments:\n  style(internal): gofmt struct field alignment in touched files\n  chore(internal): remove noise, redundant, and stale comments\n  fix(cli): strict-decode JSON at write-issue/write-prd boundary\n  fix(config): reject null agent entries\n  fix(skills): drop invalid-J\n[…]\nat(skills): rewrite embedded skill templates for JSON format\n  feat(cli): add pb migrate command for one-shot YAML->JSON conversion\n  refactor!: switch on-disk plan and config format from YAML to JSON",
          "is_bot": false,
          "headline": "Merge remote-tracking branch 'origin/refactor/internal-comments'",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T13:11:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d5660a9b89c8f9cb663251c9b91f84304cccbc0b",
          "body": null,
          "is_bot": false,
          "headline": "style(internal): gofmt struct field alignment in touched files",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T01:29:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aaca00e6108216e6bb2c7c5a33bb0873338cbf4c",
          "body": "Sub-agents run non-interactively so auto mode doesn't activate.\nAdd Write(*), Edit(*), and scoped Bash rules so worktree sub-agents\ncan implement issues without per-call permission prompts.",
          "is_bot": false,
          "headline": "feat(.claude): add scoped permissions for dispatch sub-agents",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T01:19:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "975b5695d5420c2397e457011d4ddebe7860e9ec",
          "body": "…on to worktrees\n\nDispatch sub-agents need Write/Edit/Bash permissions to implement issues.\nsettings.local.json is gitignored globally so new worktrees don't inherit it.\nThis hook copies it from the main repo into each newly created worktree.",
          "is_bot": false,
          "headline": "feat(.claude): add WorktreeCreate hook to propagate settings.local.js…",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T01:19:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3f8e544dd811eadc42d9e9061027eac72989da9a",
          "body": "Runs GenerateSkills + symlinkSkills at the end of every successful\nself-update path (already up to date, NPM notice, or direct binary\nreplace). Skips silently when not in a pb project directory.",
          "is_bot": false,
          "headline": "feat(cli): self-update re-generates and symlinks skills after updating",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-12T01:19:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "637b4cb02a9682ab614f51acf2a057112b5fdf3a",
          "body": "Audit of ./internal per best-practices-comments: drops godoc that merely\nrestates the identifier, \"// Verify X\"-style assertion narration in tests,\nsection-divider comments, numbered step labels, and a few stale references\n(YAML→JSON, shipped-follow-up hedges, gitignored-doc pointers). No behavior\nchanges; all internal tests pass.",
          "is_bot": false,
          "headline": "chore(internal): remove noise, redundant, and stale comments",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-11T22:56:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d6381960b743a42ca1301d3b859305305e291155",
          "body": "The planrepo loader uses DisallowUnknownFields so a typo'd field on\ndisk surfaces as a parse error. The CLI write entry points used plain\njson.Unmarshal, so the same typo at write time was silently dropped on\nthe way to disk — asymmetric. Export StrictUnmarshal and use it from\nboth write_issue.go and write_prd.go.",
          "is_bot": false,
          "headline": "fix(cli): strict-decode JSON at write-issue/write-prd boundary",
          "author_name": "Jason Raimondi",
          "author_login": "jasonraimondi",
          "committed_at": "2026-05-11T22:20:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 58,
      "commits_last_year": 388,
      "latest_release_at": "2026-07-17T21:34:12Z",
      "latest_release_tag": "v0.0.71",
      "releases_from_tags": false,
      "days_since_last_push": 5,
      "active_weeks_last_year": 12,
      "days_since_latest_release": 5,
      "mean_days_between_releases": 6
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/jasonraimondi/plan-bender",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/jasonraimondi/plan-bender",
          "is_deprecated": false,
          "latest_version": "v0.0.71",
          "repository_url": "https://github.com/jasonraimondi/plan-bender",
          "versions_count": 61,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-16T01:50:46Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 7
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 5,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "mise.toml"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 25732,
      "source_files_sampled": 167,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 707
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "go"
      ],
      "dependencies": [
        {
          "name": "github.com/charmbracelet/huh",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.0.0"
        },
        {
          "name": "github.com/hasura/go-graphql-client",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.15.1"
        },
        {
          "name": "github.com/spf13/cobra",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.10.2"
        },
        {
          "name": "github.com/stretchr/testify",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.11.1"
        },
        {
          "name": "golang.org/x/sys",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.41.0"
        },
        {
          "name": "golang.org/x/tools",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.42.0"
        },
        {
          "name": "gopkg.in/yaml.v3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.0.1"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 28,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 6
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "jasonraimondi",
          "commits": 386,
          "avatar_url": "https://avatars.githubusercontent.com/u/5787967?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "locksafe.yaml",
        "release.yaml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 3,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "3 out of 3 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/18 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 4 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 8,
            "reason": "2 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "744099fd2f3c926c93124083b6f3d3543c6e7984",
        "ran_at": "2026-07-23T19:03:29Z",
        "aggregate_score": 4.4,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-17T21:38:24Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-06-08T02:38:15Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/jasonraimondi/plan-bender",
    "host": "github.com",
    "name": "plan-bender",
    "owner": "jasonraimondi"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 56,
      "inputs": {
        "security": 44,
        "vitality": 79,
        "community": 29,
        "governance": 56,
        "engineering": 67
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 79,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 72,
            "inputs": {
              "commits_last_year": 388,
              "human_commit_share": 1,
              "days_since_last_push": 5,
              "active_weeks_last_year": 12
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "12/52 weeks with commits",
                "points": 8.3,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 12
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "388 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 388
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 58,
              "latest_release_tag": "v0.0.71",
              "releases_from_tags": false,
              "days_since_latest_release": 5,
              "mean_days_between_releases": 6
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "58 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 58
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~6 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 6
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 29,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "forks": 0,
              "stars": 5,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "5 stars",
                "points": 9.8,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 56,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 20,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 4 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "moderate",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 59,
            "inputs": {
              "merged_prs": 28,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 6
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "28/34 decided PRs merged",
                "points": 31.5,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 28,
                      "decided": 34
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/18 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 62,
            "inputs": {
              "followers": 101,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "jasonraimondi",
              "public_repos": 186,
              "account_age_days": 4652
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "101 followers of jasonraimondi",
                "points": 14.4,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 101,
                      "login": "jasonraimondi"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "186 public repos, account ~12 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 186
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 12
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/jasonraimondi/plan-bender"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 7
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on go",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "go"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 7 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 7
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "61 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 61
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 67,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 68,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "2 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "3 out of 3 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 44,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": null,
            "notes": [],
            "value": 44,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 18,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 0,
              "scorecard_aggregate": 4.4
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "3 out of 3 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/18 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 4 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "2 existing vulnerabilities detected",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 2
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 76,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 707
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "100 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 100,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 61,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [
                "mise.toml"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "mise.toml",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "mise.toml"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Go (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 25732,
              "source_files_sampled": 167,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Go (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/167 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 167,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-23T19:03:41.790365Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/j/jasonraimondi/plan-bender.svg",
  "full_name": "jasonraimondi/plan-bender",
  "license_state": "standard",
  "license_spdx": "MIT"
}

Bewertungen sind Signale, keine Garantien. Sie spiegeln öffentlich sichtbare Praxis auf GitHub wider — kein Code-Audit und keine Sicherheitsgarantie.

Fehlende Daten werden ausgeschlossen und die Gewichte neu normiert, nie als null bewertet. Die Methodik ist versioniert und offen: Metriken v1.13.0, Schema v0.27.0 — vollständige Methodik · Metriken-Wiki.

Wie ein einzelnes Ergebnis im Gesamtregister steht: aggregierte StatistikenGo.