Öffentliches Register
Software-GesundheitsberichtSchema 0.26.0 · Metriken 1.13.0 · 2026-07-22 09:31 UTC

genai-io / san

A minimal, fast agent harness for the terminal. One ~12 MB native binary that runs anywhere, with an open, extensible architecture.

GoApache-2.0★ 70 Sterne⑂ 32 Forksseit Sept. 2024Auf GitHub ansehen ↗

genai-io/san erreicht einen Gesundheitsindex von 73 von 100 und liegt damit im Bereich Gut. Am stärksten schneidet es bei Vitality (86/100) ab, am schwächsten bei Sustainability & Governance (63/100). Zuletzt heute aktualisiert. Ein einzelner Mitwirkender trägt den Großteil der jüngsten Arbeit.

73
gesamt / 100
Gut

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.

73
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

GenAI LabOrganisation
6 Follower13 öffentliche Reposseit Mai 2026

Dieses Repository wird von einer Organisation getragen — geteilte, rechenschaftspflichtige Trägerschaft, die jeden einzelnen Maintainer überdauern kann.

Paket-Ökosysteme

RegistryPaketVersionDownloads / MonatVersionenZuletzt veröffentlicht
Gogithub.com/genai-io/sanv1.21.11-123vor 0 Tagen

Metriken nach Kategorie

Vitalität

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

86Exzellent · 22 % des Gesamtindex
Wie die Bewertung erfolgt
36/36Push-Aktualität — letzter Push vor 0 Tagen
19.4/36Commit-Rhythmus — 28/52 Wochen mit Commits
18/18Commit-Volumen — 979 Commits im letzten Jahr
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 24 issue activity found in the last 90 days -- score normalized to 10
Verwendete Eingangsdaten
commits_last_year979
human_commit_share0,98
days_since_last_push0
active_weeks_last_year28
Wie die Bewertung erfolgt
27/27Liefert Releases aus — 100 Releases veröffentlicht
36/36Release-Aktualität — letztes Release vor 0 Tagen
27/27Release-Rhythmus — ein Release etwa alle 1,3 Tage
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Verwendete Eingangsdaten
releases_count100
latest_release_tagv1.21.11
releases_from_tagsnein
days_since_latest_release0
mean_days_between_releases1,3

Community & Verbreitung

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

66Mittel · 18 % des Gesamtindex
Wie die Bewertung erfolgt
29.8/60Stars — 70 Stars
12.4/25Forks — 32 Forks
1.7/15Watcher — 3 Watcher
Verwendete Eingangsdaten
forks32
stars70
watchers3
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonbelow_threshold
Wie die Bewertung erfolgt
22.5/22.5README
22.5/22.5Lizenz — anerkannte Lizenz (Apache-2.0)
18/18CONTRIBUTING-Leitfaden
13.5/13.5Verhaltenskodex
0/7.2Issue-Vorlage
6.3/6.3PR-Vorlage
Verwendete Eingangsdaten
has_readmeja
has_licenseja
has_contributingja
has_issue_templatenein
has_code_of_conductja
has_pull_request_templateja

Nachhaltigkeit & Governance

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

63Mittel · 24 % des Gesamtindex
Wie die Bewertung erfolgt
9/54Bus-Faktor — 1 Beitragende decken die Hälfte aller Commits ab
1.5/22.5Commit-Verteilung — wichtigste beitragende Person verfasste 93 % der Commits
13.5/13.5Breite der Beitragenden — 13 Beitragende
10/10OpenSSF Scorecard: Contributors — project has 5 contributing companies or organizations
Verwendete Eingangsdaten
bus_factor1
contributors_sampled13
top_contributor_share0,934
Wie die Bewertung erfolgt
38.1/46.8Issue-Lösungsquote — 81 % der Issues geschlossen
34.2/38.3PR-Annahme — 296/331 entschiedene PRs gemergt
15/15OpenSSF Scorecard: Code-Review — all changesets reviewed
Verwendete Eingangsdaten
merged_prs296
open_issues8
closed_issues35
issue_closed_ratio0,814
closed_unmerged_prs35
Wie die Bewertung erfolgt
30/30Organisatorische Trägerschaft — im Besitz einer Organisation
0/20Verifizierte Domain
6.1/25Reichweite des Inhabers — 6 Follower von genai-io
8.8/25Kontohistorie — 13 öffentliche Repos, Kontoalter ca. 0 Jahre
Verwendete Eingangsdaten
followers6
owner_typeOrganization
is_verified
owner_logingenai-io
public_repos13
account_age_days82

Paketpflege

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

Engineering-Qualität

Sind grundlegende Engineering- und Dokumentationspraktiken vorhanden?

81Gut · 20 % des Gesamtindex
Wie die Bewertung erfolgt
24/24CI-Workflows — 4 Workflow(s)
24/24Tests vorhanden
0/16Linter-Konfiguration
0/9.6Pre-Commit-Hooks
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 28 out of 28 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

Dokumentation

100Exzellent
Wie die Bewertung erfolgt
30/30README
25/25Dokumentationsverzeichnis
15/15Dokumentations-/Homepage-Site — https://genai-io.github.io/san/
10/10Repository-Beschreibung
10/10Topics — 11 Topics
10/10Wiki
Verwendete Eingangsdaten
topicsai-agents, provider-agnostic, llm, coding-agent, agent-harness, claude-code, cli, golang, mcp, terminal, tui
has_wikija
homepagehttps://genai-io.github.io/san/
has_readmeja
has_docs_dirja
has_descriptionja

Sicherheit

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

66Mittel · 16 % des Gesamtindex
Wie die Bewertung erfolgt
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — keine Daten
2.5/2.5CI-Tests — 28 out of 28 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
7.5/7.5Code-Review — all changesets reviewed
2.5/2.5Contributors — project has 5 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Lizenz — license file detected
7.5/7.5Maintained — 30 commit(s) and 24 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — keine Daten
1.5/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 3
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
5/5Security-Policy — security policy file 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
0/7.5Vulnerabilities — 31 existing vulnerabilities detected
Verwendete Eingangsdaten
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate5,8
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): branch_protection, packaging. Die verbleibenden Gewichte wurden renormalisiert.
Wie die Bewertung erfolgt
35/35Direkte Abhängigkeiten ohne bekannte Advisories — keine direkte Abhängigkeit trägt ein bekanntes Advisory
0/25Indirekte Abhängigkeiten ohne bekannte Advisories — transitive Menge in diesem Bereich nicht von Entwicklungs- und Test-Abhängigkeiten trennbar
0/40Keine offenen Advisories — kein Advisory trägt ein Veröffentlichungsdatum
Verwendete Eingangsdaten
sourceosv
advisories48
affected_packages5
assessed_packages78
unassessed_packages0
affected_by_severitycritical 2, moderate 1, unknown 2
direct_affected_packages0
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): Indirekte Abhängigkeiten ohne bekannte Advisories, Keine offenen Advisories. Die verbleibenden Gewichte wurden renormalisiert. 78 aufgelöste Abhängigkeiten wurden mit OSV abgeglichen. Dieses Repository veröffentlicht kein Paket, das der Index auflöst; bewertet wurde daher der Abhängigkeitsgraph des Repositorys. Dieser Graph vermischt Entwicklungs- und Test-Pins mit ausgelieferten Abhängigkeiten, daher werden nur die deklarierten Laufzeit-Abhängigkeiten bewertet; transitive Befunde werden als Kontext ausgewiesen und fließen nicht in die Bewertung ein. Erreichbarkeit wird nicht analysiert.

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.

86Exzellent · 0 % des Gesamtindex
Wie die Bewertung erfolgt
45/45Agentenanweisungen — AGENTS.md, docs/packages/2-feature/agent.md
0/15Maschinenlesbare Doku (llms.txt)
40/40Lesbare Commit-Historie — 98 von 98 menschlichen Commits benennen ihre Absicht (strukturierter Betreff oder erläuternder Text)
Verwendete Eingangsdaten
has_llms_txtnein
legible_history_share1
agent_instruction_filesAGENTS.md, docs/packages/2-feature/agent.md
agent_instruction_max_bytes3.518
Wie die Bewertung erfolgt
18/18Bootstrap mit einem Befehl — Makefile
22/22Automatisierte Tests
0/11Lint-/Format-Konfiguration
11/11Statische Typprüfung — Go (statisch typisiert)
10/10Reproduzierbare Umgebung — lockfile
10/10Belegte Agentenpraxis — 5 der letzten 100 Commits von Agenten verfasst oder ihnen zugeschrieben
8/8Automatisierte Wartung — 2 der letzten 100 Commits sind automatisierte Abhängigkeits-Updates
3/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 3
Verwendete Eingangsdaten
has_nixnein
has_testsja
lockfilesgo.sum
has_dockerfilenein
typed_languageja
bootstrap_filesMakefile
has_devcontainernein
has_linter_confignein
typecheck_configs
agent_commit_share0,05
toolchain_manifestsgo.mod
dependency_bot_commit_share0,02
Wie die Bewertung erfolgt
45/45Typprüfbarer Code — Go (statisch typisiert)
55/55Handhabbare Dateigrößen — 0/622 Quelldateien über 60 KB
Verwendete Eingangsdaten
primary_languageGo
largest_source_bytes49.529
source_files_sampled622
oversized_source_files0

Eckdaten

70GitHub-Sterne
13Mitwirkende
979Commits, letzte 12 Monate
0Tage seit letztem Push
100Releases
1Bus-Faktor
8offene Issues
GoPaket-Ökosysteme

Weitere Details

Stern- und Fork-Verlauf 70 ★ / 32 ⇿
70Sterne
32Forks
97Releases

Wann jeder Stern und Fork hinzugefügt wurde, von GitHub erfasst und nach Tagen gruppiert. Das kumulierte Wachstum steht direkt über den täglichen Zugängen, aus denen es besteht, sodass beide gegeneinander lesbar sind: stetiger organischer Zuwachs sieht ganz anders aus als ein abrupter, kurzlebiger Ausschlag. Wo dieser Unterschied messbar ist, wird er als Wachstumsauthentizität ausgewiesen.

01325385063757032142024-112025-092026-07
Major 0Minor 15Patch 82

Jeder Punkt umfasst 2 Tage.

OpenSSF Scorecard 5.8 / 10
5.8Gesamtwert

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-22 09:31 UTC

10Binary-Artifactsno binaries found in the repo
k. A.Branch-Protectioninternal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
10CI-Tests28 out of 28 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
10Code-Reviewall changesets reviewed
10Contributorsproject has 5 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 24 issue activity found in the last 90 days -- score normalized to 10
k. A.Packagingpackaging workflow not detected
3Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 3
0SASTSAST tool is not run on all commits -- score normalized to 0
10Security-Policysecurity policy file detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities31 existing vulnerabilities detected
Direkte Abhängigkeiten 21
RegistryPaketVersionsvorgabeManifest
Gocharm.land/bubbles/v2v2.1.0go.mod
Gocharm.land/bubbletea/v2v2.0.7go.mod
Gocharm.land/glamour/v2v2.0.1go.mod
Gocharm.land/lipgloss/v2v2.0.4go.mod
Gogithub.com/JohannesKaufmann/html-to-markdownv1.6.0go.mod
Gogithub.com/PuerkitoBio/goqueryv1.9.2go.mod
Gogithub.com/anthropics/anthropic-sdk-gov1.27.1go.mod
Gogithub.com/bmatcuk/doublestar/v4v4.9.2go.mod
Gogithub.com/charmbracelet/x/ansiv0.11.7go.mod
Gogithub.com/creack/ptyv1.1.24go.mod
Gogithub.com/hexops/gotextdiffv1.0.3go.mod
Gogithub.com/joho/godotenvv1.5.1go.mod
Gogithub.com/mattn/go-runewidthv0.0.23go.mod
Gogithub.com/openai/openai-go/v3v3.32.0go.mod
Gogithub.com/spf13/cobrav1.8.1go.mod
Gogo.uber.org/zapv1.27.0go.mod
Gogolang.org/x/termv0.40.0go.mod
Gogoogle.golang.org/genaiv1.58.0go.mod
Gogopkg.in/natefinch/lumberjack.v2v2.2.1go.mod
Gogopkg.in/yaml.v3v3.0.1go.mod
Gomvdan.cc/sh/v3v3.13.0go.mod
Alle Abhängigkeiten 78

Vollständig aufgelöster Abhängigkeitssatz aus dem GitHub-Abhängigkeitsgraphen: 21 direkte und 57 indirekte (transitive) Pakete. Die transitive Hülle ist vollständig, wenn das Repository eine Lockfile eincheckt.

RegistryPaketVersionBeziehung
Gocharm.land/bubbles/v2v2.1.0direkt
Gocharm.land/bubbletea/v2v2.0.7direkt
Gocharm.land/glamour/v2v2.0.1direkt
Gocharm.land/lipgloss/v2v2.0.4direkt
Gogithub.com/anthropics/anthropic-sdk-gov1.27.1direkt
Gogithub.com/bmatcuk/doublestar/v4v4.9.2direkt
Gogithub.com/charmbracelet/x/ansiv0.11.7direkt
Gogithub.com/creack/ptyv1.1.24direkt
Gogithub.com/hexops/gotextdiffv1.0.3direkt
Gogithub.com/johanneskaufmann/html-to-markdownv1.6.0direkt
Gogithub.com/joho/godotenvv1.5.1direkt
Gogithub.com/mattn/go-runewidthv0.0.23direkt
Gogithub.com/openai/openai-go/v3v3.32.0direkt
Gogithub.com/puerkitobio/goqueryv1.9.2direkt
Gogithub.com/spf13/cobrav1.8.1direkt
Gogo.uber.org/zapv1.27.0direkt
Gogolang.org/x/termv0.40.0direkt
Gogoogle.golang.org/genaiv1.58.0direkt
Gogopkg.in/natefinch/lumberjack.v2v2.2.1direkt
Gogopkg.in/yaml.v3v3.0.1direkt
Gomvdan.cc/sh/v3v3.13.0direkt
Gocloud.google.com/gov0.116.0indirekt
Gocloud.google.com/go/authv0.9.3indirekt
Gocloud.google.com/go/auth/oauth2adaptv0.2.4indirekt
Gocloud.google.com/go/compute/metadatav0.5.0indirekt
Gogithub.com/alecthomas/chroma/v2v2.20.0indirekt
Gogithub.com/andybalholm/cascadiav1.3.2indirekt
Gogithub.com/atotto/clipboardv0.1.4indirekt
Gogithub.com/aymerick/douceurv0.2.0indirekt
Gogithub.com/charmbracelet/colorprofilev0.4.3indirekt
Gogithub.com/charmbracelet/ultravioletv0.0.0-20260525132238-948f4557a654indirekt
Gogithub.com/charmbracelet/x/exp/slicev0.0.0-20250327172914-2fdc97757edfindirekt
Gogithub.com/charmbracelet/x/termv0.2.2indirekt
Gogithub.com/charmbracelet/x/termiosv0.1.1indirekt
Gogithub.com/charmbracelet/x/windowsv0.2.2indirekt
Gogithub.com/clipperhouse/displaywidthv0.11.0indirekt
Gogithub.com/clipperhouse/uax29/v2v2.7.0indirekt
Gogithub.com/dlclark/regexp2v1.11.5indirekt
Gogithub.com/felixge/httpsnoopv1.0.4indirekt
Gogithub.com/go-logr/logrv1.4.2indirekt
Gogithub.com/go-logr/stdrv1.2.2indirekt
Gogithub.com/golang/groupcachev0.0.0-20210331224755-41bb18bfe9daindirekt
Gogithub.com/google/go-cmpv0.7.0indirekt
Gogithub.com/google/s2a-gov0.1.8indirekt
Gogithub.com/googleapis/enterprise-certificate-proxyv0.3.4indirekt
Gogithub.com/gorilla/cssv1.0.1indirekt
Gogithub.com/gorilla/websocketv1.5.3indirekt
Gogithub.com/inconshreveable/mousetrapv1.1.0indirekt
Gogithub.com/lucasb-eyer/go-colorfulv1.4.0indirekt
Gogithub.com/microcosm-cc/bluemondayv1.0.27indirekt
Gogithub.com/muesli/cancelreaderv0.2.2indirekt
Gogithub.com/rivo/unisegv0.4.7indirekt
Gogithub.com/spf13/pflagv1.0.5indirekt
Gogithub.com/tidwall/gjsonv1.18.0indirekt
Gogithub.com/tidwall/matchv1.1.1indirekt
Gogithub.com/tidwall/prettyv1.2.1indirekt
Gogithub.com/tidwall/sjsonv1.2.5indirekt
Gogithub.com/xo/terminfov0.0.0-20220910002029-abceb7e1c41eindirekt
Gogithub.com/yuin/goldmarkv1.7.13indirekt
Gogithub.com/yuin/goldmark-emojiv1.0.6indirekt
Gogo.opencensus.iov0.24.0indirekt
Gogo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpcv0.54.0indirekt
Gogo.opentelemetry.io/contrib/instrumentation/net/http/otelhttpv0.54.0indirekt
Gogo.opentelemetry.io/otelv1.29.0indirekt
Gogo.opentelemetry.io/otel/metricv1.29.0indirekt
Gogo.opentelemetry.io/otel/tracev1.29.0indirekt
Gogo.uber.org/multierrv1.10.0indirekt
Gogolang.org/x/cryptov0.40.0indirekt
Gogolang.org/x/netv0.41.0indirekt
Gogolang.org/x/oauth2v0.30.0indirekt
Gogolang.org/x/syncv0.20.0indirekt
Gogolang.org/x/sysv0.45.0indirekt
Gogolang.org/x/textv0.30.0indirekt
Gogolang.org/x/timev0.6.0indirekt
Gogoogle.golang.org/apiv0.197.0indirekt
Gogoogle.golang.org/genproto/googleapis/rpcv0.0.0-20240903143218-8af14fe29dc1indirekt
Gogoogle.golang.org/grpcv1.66.2indirekt
Gogoogle.golang.org/protobufv1.34.2indirekt
Abhängigkeits-Advisories 5

Dieses Repository veröffentlicht kein vom Index auflösbares Paket, daher wurde sein eigener Abhängigkeitsgraph bewertet – 78 Pakete, darunter auch Entwicklungs- und Test-Pins, die nie ausgeliefert werden: 5 tragen bekannte Advisories, davon 0 direkte.

PaketVersionBeziehungSchweregradAdvisoriesBehoben in
golang.org/x/cryptov0.40.0indirektkritisch320.52.0
google.golang.org/grpcv1.66.2indirektkritisch31.82.1
golang.org/x/netv0.41.0indirektmittel111.26.3
github.com/yuin/goldmarkv1.7.13indirektunbekannt11.7.17
golang.org/x/textv0.30.0indirektunbekannt10.39.0

Ein Advisory bedeutet, dass die im Abhängigkeitsgraphen erfasste Version in den betroffenen Bereich eines Advisories fällt. Erreichbarkeit wird nicht analysiert, und der Graph enthält Entwicklungs- und Test-Pins — ein Fund kann das Werkzeug betreffen und nicht die ausgelieferte Software.

JSON-Rohbericht maschinenlesbar
{
  "data": {
    "repo": {
      "topics": [
        "ai-agents",
        "provider-agnostic",
        "llm",
        "coding-agent",
        "agent-harness",
        "claude-code",
        "cli",
        "golang",
        "mcp",
        "terminal",
        "tui"
      ],
      "is_fork": false,
      "size_kb": 30411,
      "has_wiki": true,
      "homepage": "https://genai-io.github.io/san/",
      "languages": {
        "Go": 3685554,
        "CSS": 55107,
        "HTML": 105807,
        "Shell": 5474,
        "Makefile": 5662,
        "JavaScript": 47772,
        "PowerShell": 5198
      },
      "pushed_at": "2026-07-22T09:22:24Z",
      "created_at": "2024-09-05T16:16:25Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-21T15:32:52Z",
      "description": "A minimal, fast agent harness for the terminal. One ~12 MB native binary that runs anywhere, with an open, extensible architecture.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "main",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": null,
      "name": "GenAI Lab",
      "type": "Organization",
      "login": "genai-io",
      "company": null,
      "location": null,
      "followers": 6,
      "avatar_url": "https://avatars.githubusercontent.com/u/280842444?v=4",
      "created_at": "2026-05-01T01:06:19Z",
      "is_verified": null,
      "public_repos": 13,
      "account_age_days": 82
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.21.11",
          "kind": "patch",
          "published_at": "2026-07-21T16:26:44Z"
        },
        {
          "tag": "v1.21.10",
          "kind": "patch",
          "published_at": "2026-07-20T11:03:08Z"
        },
        {
          "tag": "v1.21.9",
          "kind": "patch",
          "published_at": "2026-07-19T17:33:30Z"
        },
        {
          "tag": "v1.21.8",
          "kind": "patch",
          "published_at": "2026-07-18T17:12:52Z"
        },
        {
          "tag": "v1.21.6",
          "kind": "patch",
          "published_at": "2026-07-17T17:10:04Z"
        },
        {
          "tag": "v1.21.5",
          "kind": "patch",
          "published_at": "2026-07-17T09:54:42Z"
        },
        {
          "tag": "v1.21.4",
          "kind": "patch",
          "published_at": "2026-07-10T18:45:39Z"
        },
        {
          "tag": "v1.21.3",
          "kind": "patch",
          "published_at": "2026-07-10T14:33:44Z"
        },
        {
          "tag": "v1.21.2",
          "kind": "patch",
          "published_at": "2026-07-10T00:30:07Z"
        },
        {
          "tag": "v1.21.1",
          "kind": "patch",
          "published_at": "2026-07-09T18:10:03Z"
        },
        {
          "tag": "v1.21.0",
          "kind": "minor",
          "published_at": "2026-07-09T05:08:46Z"
        },
        {
          "tag": "v1.20.11",
          "kind": "patch",
          "published_at": "2026-07-05T12:20:42Z"
        },
        {
          "tag": "v1.20.10",
          "kind": "patch",
          "published_at": "2026-07-05T03:13:49Z"
        },
        {
          "tag": "v1.20.9",
          "kind": "patch",
          "published_at": "2026-07-03T10:38:10Z"
        },
        {
          "tag": "v1.20.8",
          "kind": "patch",
          "published_at": "2026-07-02T16:33:10Z"
        },
        {
          "tag": "v1.20.7",
          "kind": "patch",
          "published_at": "2026-06-27T16:10:10Z"
        },
        {
          "tag": "v1.20.6",
          "kind": "patch",
          "published_at": "2026-06-18T14:42:01Z"
        },
        {
          "tag": "v1.20.5",
          "kind": "patch",
          "published_at": "2026-06-16T12:39:58Z"
        },
        {
          "tag": "v1.20.4",
          "kind": "patch",
          "published_at": "2026-06-16T11:52:39Z"
        },
        {
          "tag": "v1.20.3",
          "kind": "patch",
          "published_at": "2026-06-15T05:27:59Z"
        },
        {
          "tag": "v1.20.2",
          "kind": "patch",
          "published_at": "2026-06-13T07:54:37Z"
        },
        {
          "tag": "v1.20.1",
          "kind": "patch",
          "published_at": "2026-06-11T15:06:31Z"
        },
        {
          "tag": "v1.20.0",
          "kind": "minor",
          "published_at": "2026-06-05T23:52:34Z"
        },
        {
          "tag": "v1.19.3",
          "kind": "patch",
          "published_at": "2026-06-03T04:53:23Z"
        },
        {
          "tag": "v1.19.2",
          "kind": "patch",
          "published_at": "2026-06-03T03:06:04Z"
        },
        {
          "tag": "v1.19.1",
          "kind": "patch",
          "published_at": "2026-05-23T00:46:46Z"
        },
        {
          "tag": "v1.19.0",
          "kind": "minor",
          "published_at": "2026-05-22T16:58:53Z"
        },
        {
          "tag": "v1.18.0",
          "kind": "minor",
          "published_at": "2026-05-17T14:38:25Z"
        },
        {
          "tag": "v1.17.4",
          "kind": "patch",
          "published_at": "2026-05-06T10:06:27Z"
        },
        {
          "tag": "v1.17.3",
          "kind": "patch",
          "published_at": "2026-05-06T09:11:05Z"
        },
        {
          "tag": "v1.17.2",
          "kind": "patch",
          "published_at": "2026-05-06T08:35:35Z"
        },
        {
          "tag": "v1.17.1",
          "kind": "patch",
          "published_at": "2026-05-05T03:19:03Z"
        },
        {
          "tag": "v1.17.0",
          "kind": "minor",
          "published_at": "2026-05-04T15:01:18Z"
        },
        {
          "tag": "v1.16.0",
          "kind": "minor",
          "published_at": "2026-05-04T08:07:48Z"
        },
        {
          "tag": "v1.15.14",
          "kind": "patch",
          "published_at": "2026-05-02T13:35:26Z"
        },
        {
          "tag": "v0.0.2",
          "kind": "patch",
          "published_at": "2026-05-02T10:35:38Z"
        },
        {
          "tag": "v0.0.1",
          "kind": "patch",
          "published_at": "2026-05-02T10:33:00Z"
        },
        {
          "tag": "v1.15.13",
          "kind": "patch",
          "published_at": "2026-05-02T02:57:20Z"
        },
        {
          "tag": "v1.15.12",
          "kind": "patch",
          "published_at": "2026-05-02T02:02:41Z"
        },
        {
          "tag": "v1.15.11",
          "kind": "patch",
          "published_at": "2026-05-01T06:11:32Z"
        },
        {
          "tag": "v1.15.10",
          "kind": "patch",
          "published_at": "2026-05-01T00:03:50Z"
        },
        {
          "tag": "v1.15.9",
          "kind": "patch",
          "published_at": "2026-04-30T23:49:22Z"
        },
        {
          "tag": "v1.15.8",
          "kind": "patch",
          "published_at": "2026-04-30T16:37:10Z"
        },
        {
          "tag": "v1.15.7",
          "kind": "patch",
          "published_at": "2026-04-30T12:01:28Z"
        },
        {
          "tag": "v1.15.6",
          "kind": "patch",
          "published_at": "2026-04-29T13:52:32Z"
        },
        {
          "tag": "v1.15.5",
          "kind": "patch",
          "published_at": "2026-04-25T23:13:08Z"
        },
        {
          "tag": "v1.15.4",
          "kind": "patch",
          "published_at": "2026-04-25T14:21:37Z"
        },
        {
          "tag": "v1.15.3",
          "kind": "patch",
          "published_at": "2026-04-25T09:37:07Z"
        },
        {
          "tag": "v1.15.2",
          "kind": "patch",
          "published_at": "2026-04-24T02:35:36Z"
        },
        {
          "tag": "v1.15.1",
          "kind": "patch",
          "published_at": "2026-04-24T02:14:28Z"
        },
        {
          "tag": "v1.15.0",
          "kind": "minor",
          "published_at": "2026-04-24T01:45:25Z"
        },
        {
          "tag": "v1.14.9",
          "kind": "patch",
          "published_at": "2026-04-23T15:11:31Z"
        },
        {
          "tag": "v1.14.8",
          "kind": "patch",
          "published_at": "2026-04-23T14:06:48Z"
        },
        {
          "tag": "v1.14.7",
          "kind": "patch",
          "published_at": "2026-04-23T04:52:33Z"
        },
        {
          "tag": "v1.14.6",
          "kind": "patch",
          "published_at": "2026-04-23T04:19:22Z"
        },
        {
          "tag": "v1.14.5",
          "kind": "patch",
          "published_at": "2026-04-22T06:04:44Z"
        },
        {
          "tag": "v1.14.4",
          "kind": "patch",
          "published_at": "2026-04-22T01:30:23Z"
        },
        {
          "tag": "v1.14.3",
          "kind": "patch",
          "published_at": "2026-04-21T12:45:30Z"
        },
        {
          "tag": "v1.14.2",
          "kind": "patch",
          "published_at": "2026-04-21T11:42:19Z"
        },
        {
          "tag": "v1.14.1",
          "kind": "patch",
          "published_at": "2026-04-21T09:04:24Z"
        },
        {
          "tag": "v1.14.0",
          "kind": "minor",
          "published_at": "2026-04-21T08:41:48Z"
        },
        {
          "tag": "v1.13.2",
          "kind": "patch",
          "published_at": "2026-04-14T16:55:39Z"
        },
        {
          "tag": "v1.13.1",
          "kind": "patch",
          "published_at": "2026-04-14T16:37:01Z"
        },
        {
          "tag": "v1.13.0",
          "kind": "minor",
          "published_at": "2026-04-14T15:40:15Z"
        },
        {
          "tag": "v1.12.2",
          "kind": "patch",
          "published_at": "2026-04-14T16:36:57Z"
        },
        {
          "tag": "v1.12.1",
          "kind": "patch",
          "published_at": "2026-04-13T10:14:23Z"
        },
        {
          "tag": "v1.12.0",
          "kind": "minor",
          "published_at": "2026-04-09T14:59:07Z"
        },
        {
          "tag": "v1.11.7",
          "kind": "patch",
          "published_at": "2026-04-08T05:50:36Z"
        },
        {
          "tag": "v1.11.6",
          "kind": "patch",
          "published_at": "2026-04-07T10:47:25Z"
        },
        {
          "tag": "v1.11.5",
          "kind": "patch",
          "published_at": "2026-04-07T05:09:32Z"
        },
        {
          "tag": "v1.11.4",
          "kind": "patch",
          "published_at": "2026-04-07T04:55:04Z"
        },
        {
          "tag": "v1.11.3",
          "kind": "patch",
          "published_at": "2026-04-07T04:01:44Z"
        },
        {
          "tag": "v1.11.2",
          "kind": "patch",
          "published_at": "2026-04-06T15:04:46Z"
        },
        {
          "tag": "v1.11.1",
          "kind": "patch",
          "published_at": "2026-04-06T12:03:44Z"
        },
        {
          "tag": "v1.11.0",
          "kind": "minor",
          "published_at": "2026-04-06T11:39:17Z"
        },
        {
          "tag": "v1.10.3",
          "kind": "patch",
          "published_at": "2026-03-30T10:33:19Z"
        },
        {
          "tag": "v1.10.2",
          "kind": "patch",
          "published_at": "2026-03-25T00:49:17Z"
        },
        {
          "tag": "v1.10.1",
          "kind": "patch",
          "published_at": "2026-03-24T01:42:07Z"
        },
        {
          "tag": "v1.10.0",
          "kind": "minor",
          "published_at": "2026-03-23T11:37:13Z"
        },
        {
          "tag": "v1.9.10",
          "kind": "patch",
          "published_at": "2026-03-16T09:40:32Z"
        },
        {
          "tag": "v1.9.9",
          "kind": "patch",
          "published_at": "2026-03-16T05:44:33Z"
        },
        {
          "tag": "v1.9.8",
          "kind": "patch",
          "published_at": "2026-03-15T18:37:08Z"
        },
        {
          "tag": "v1.9.7",
          "kind": "patch",
          "published_at": "2026-03-15T03:21:26Z"
        },
        {
          "tag": "v1.9.6",
          "kind": "patch",
          "published_at": "2026-03-11T08:04:28Z"
        },
        {
          "tag": "v1.9.5",
          "kind": "patch",
          "published_at": "2026-03-11T04:25:20Z"
        },
        {
          "tag": "v1.9.4",
          "kind": "patch",
          "published_at": "2026-03-11T02:36:16Z"
        },
        {
          "tag": "v1.9.3",
          "kind": "patch",
          "published_at": "2026-03-08T14:03:29Z"
        },
        {
          "tag": "v1.9.2",
          "kind": "patch",
          "published_at": "2026-03-08T14:03:23Z"
        },
        {
          "tag": "v1.9.1",
          "kind": "patch",
          "published_at": "2026-03-08T11:02:08Z"
        },
        {
          "tag": "v1.9.0",
          "kind": "minor",
          "published_at": "2026-03-08T04:56:17Z"
        },
        {
          "tag": "v1.8.2",
          "kind": "patch",
          "published_at": "2026-03-07T15:40:45Z"
        },
        {
          "tag": "v1.8.1",
          "kind": "patch",
          "published_at": "2026-03-07T12:31:57Z"
        },
        {
          "tag": "v1.8.0",
          "kind": "minor",
          "published_at": "2026-03-07T06:25:45Z"
        },
        {
          "tag": "v1.7.6",
          "kind": "patch",
          "published_at": "2026-03-05T01:55:07Z"
        },
        {
          "tag": "v1.7.5",
          "kind": "patch",
          "published_at": "2026-03-05T01:26:06Z"
        },
        {
          "tag": "v1.7.4",
          "kind": "patch",
          "published_at": "2026-02-25T02:57:38Z"
        },
        {
          "tag": "v1.7.3",
          "kind": "patch",
          "published_at": "2026-02-24T02:36:09Z"
        },
        {
          "tag": "v1.7.2",
          "kind": "patch",
          "published_at": "2026-02-24T02:31:00Z"
        },
        {
          "tag": "v1.7.1",
          "kind": "patch",
          "published_at": "2026-02-23T13:55:17Z"
        },
        {
          "tag": "v1.7.0",
          "kind": "minor",
          "published_at": "2026-02-18T17:07:45Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "445f0c7a6a4ff2c716a2e508d4364ab000ac06c4",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.21.11",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T15:28:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "093765a231d0e7ec1628bfdd5949b9bd87a14b68",
          "body": "Follow-up to #375, which swapped the \"▌\" caret for a reverse-video-space\none — that still trails a block caret after the live streaming text. Drop\nit altogether: the leading spinner already marks the turn as live, and a\nlone space covers the momentary gap right after a block commits so the\nspinner stays on screen. Nothing now trails the streamed text.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(conv): remove the streaming caret entirely",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T14:16:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7f5931a9a6594a07b2db11f3303374de2501f0fa",
          "body": "The live streaming tail appended a \"▌\" caret (U+258C) after the text. It is\nan East-Asian ambiguous-width glyph — measured as one cell by\nlipgloss/bubbletea but painted two cells wide by CJK terminals — so redrawn\nevery frame at the growing edge, the half-cell the cell differ never\nreclaims stranded\n[…]\nthe momentary gap right after a block commits (empty remainder) a lone space\nkeeps that spinner on screen, so nothing trails the streamed text.\n\nCloses #374\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(conv): drop the streaming caret that stranded a vertical line",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T14:05:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bab0439153324700baf549dd428e06f86955ef26",
          "body": "* refactor: write files atomically through one helper\n\nThe temp-file-then-rename dance was hand-copied into 19 call sites across\n14 packages, and the copies had drifted apart.\n\nThree of the differences mattered:\n\n- internal/secret/store.go, the file holding API keys and tokens, was the\n  only copy t\n[…]\npackage-map.md.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* refactor(atomicfile): unexport dirPerm\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor: write files atomically through one helper (#354)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:33:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "70edf68b2868039bae104662d46601077a038ba3",
          "body": "…ting (#357)\n\nMoney.Add panicked when the two amounts named different currencies, and\nthat input is reachable: providers do not agree on a currency — MiniMax\nprices in CNY, DeepSeek/MiMo/Ollama in USD — and switching provider\nmid-session does not reset env.ConversationCost. Only /clear and /new do.\n\n[…]\noney keeps its single-amount meaning and loses Add entirely — it had one\ncaller, and leaving a panicking helper behind is an invitation to\nreintroduce this.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(llm): stop a provider switch from crashing the TUI on cost accoun…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:30:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "57318f1c98c84d1f296a4e212b8ea617d489c153",
          "body": "* fix(mcp): keep servers connected across a cwd change\n\nmcp.Initialize replaces the package registry, and reloadProjectServices\ncalls it on every cwd change and plugin reload. The replacement started\nwith no clients, and nothing reconnected them: AutoConnect runs once, from\nmodel.Init at startup.\n\nT\n[…]\n-off-by: Meng Yan <yanmxa@gmail.com>\n\n* docs(mcp): remove the stale duplicate defaultRegistry comment\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(mcp): keep servers connected across a cwd change (#361)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:28:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5a7d0409107eab0846c3a90fbc8f525d6d44bd11",
          "body": "Both reload paths merged plugin hooks into a throwaway snapshot:\n\n\tplugin.MergePluginHooksIntoSettings(m.services.Setting.Snapshot())\n\tm.syncSettingsToHookEngine()   // SetSettings(Snapshot()) — a second clone\n\nSettings.Snapshot() returns data.Clone(), a fresh deep copy on every call,\nso the merge l\n[…]\ninside syncSettingsToHookEngine, on the\nsnapshot it actually hands over. A caller can no longer get it wrong,\nand the two now-redundant merge calls go away.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(hook): stop losing plugin hooks on every reload (#362)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:25:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7a6cc33a2eb5adf6428de517a98388338028c5e1",
          "body": "Two hook calls run synchronously on the bubbletea goroutine with\ncontext.Background():\n\n\tupdate_submit.go:94    checkPromptHook  (UserPromptSubmit)\n\tmodel_lifecycle.go:264 FireSessionEnd   (SessionEnd)\n\nThe engine's default timeout is 600 seconds. That default suits a detached\nhook; applied to a gat\n[…]\nwait — complexity in the most-used path in the app, to support a\nslow hook nobody has asked for. Bounding the wait fixes what the user actually\nexperiences.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(app): bound the hooks the UI goroutine waits on (#370)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:21:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e471fa9bcdb4d4dddf54b461c236083098a4a3e4",
          "body": "…ion (#363)\n\nLosing transcripts-index.json made every prior session permanently\ninvisible in /resume, while the .jsonl transcripts sat on disk untouched.\n\nlistIndexEntries already recovers: when loadIndexLocked fails it calls\nrebuildIndexLocked, which reconstructs the index from the transcripts\ndire\n[…]\ndex remains the right answer — loadIndexLocked's own doc already\nnamed both branches (\"rebuild, or start a fresh index\"); this path just\ntook the wrong one.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(transcript): rebuild a damaged index instead of hiding every sess…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:15:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b8aebf355fd45936345149ccdf28ae6d8bfa7364",
          "body": "…ssion (#364)\n\nloadRecordsLocked rejected the whole transcript when any line failed to\ndecode, so one interrupted turn made a session permanently unresumable\neven though every record before the tear was intact.\n\nThe transcript is append-only and appendRecord fsyncs only on turn\nboundaries (inference\n[…]\nnd skipping it silently would leave a hole in the\nreplayed conversation with nothing to show for it, so that still fails\nloudly. The dropped line is logged.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(transcript): survive a torn final record instead of losing the se…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:12:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4bcae47f4864e9f6ed04bdd55cfa925de29a16f6",
          "body": "…#366)\n\nEnable and Disable write p.Enabled under r.mu, but Get, List, GetEnabled\nand GetByScope returned the live *Plugin and released the lock. Callers\ndereferenced it outside — refreshInstalledPlugins reads p.Enabled on the\nUI goroutine (on_plugin.go:483).\n\nThe writer is not on the UI goroutine. /\n[…]\nEnabledState reads it under r.mu.\nplugin.Install builds an Installer inside a tea.Cmd goroutine, so a\nconcurrent cd raced it. Replaced with a locked SetCwd.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(plugin): stop handing out live pointers to lock-protected state (…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:08:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "039d42297bd055964ac2e6c76d128094b81e7764",
          "body": "Registry.Disconnect called Client.Disconnect while holding the registry\nwrite lock:\n\n\tr.mu.Lock()\n\terr := client.Disconnect()      // blocks\n\tdelete(r.clients, name)\n\tr.mu.Unlock()\n\nSTDIOTransport.Close waits up to 2s for the read loop and then up to 5s\nfor cmd.Wait — seven seconds for a wedged serv\n[…]\n waiting for it is precisely the freeze. It is\nlogged instead. One caller reported it (/mcp disconnect) and now reports\nthe removal, which is what happened.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(mcp): stop a server teardown freezing the TUI and the agent (#367)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:04:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3f15eb2aa20d358d95530da43e176a61f064cf87",
          "body": "* fix(cron): stop one san window deleting another's scheduled jobs\n\nThe durable-job file is per-project, not per-process: two san windows open\non the same repo write scheduled_tasks.json. LoadDurable runs once, at\nstartup, and saveDurableLocked rewrote the file from the in-memory view —\nso a job cre\n[…]\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* docs(cron): merge the stacked saveDurableLocked comment\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(cron): stop one san window deleting another's scheduled jobs (#371)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T12:01:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4b303c34736fb4480457514c883eecc05923d7f4",
          "body": "SessionPermissions is shared by two goroutines with no synchronisation.\nThe UI goroutine rewrites the posture whenever the user cycles the\noperation mode (Shift+Tab → env.ApplyModePermissions), and the agent\ngoroutine reads the same struct on every tool call through\nHasPermissionToUseTool. The race \n[…]\nly while it is parked. That still holds, and is not the\npath at fault: mode cycling is not covered by it, since the agent is\nrunning when Shift+Tab arrives.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(setting): stop the permission check racing the mode switch",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:46:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e16adfd3197ea92855196fdd28a415bc97821c90",
          "body": "A CJK character is one rune, three bytes, and two terminal columns. Twelve\nsites across the selectors mixed those up, so every panel misrenders as\nsoon as a name, path or prompt contains Chinese.\n\nByte-slicing against a column budget (mojibake, and a cut third of the\nrow):\n\n  on_session.go     the /\n[…]\nhose end\nidentifies them — a path's filename. suggest.go's rune-based\ntruncateFromLeft is the same idea but measured wrong; this is the\nwidth-aware version.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(tui): measure panel layout in display columns, not bytes or runes",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:42:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f7d346ba1e2332000d027e44396a9a60e2afd2a1",
          "body": "A background bash task runs in its own process group, and Stop/Kill signalled\nthe raw PGID. Once cmd.Wait reaps the child the kernel may reissue that PGID, so\na signal racing the reap could land on an unrelated group of the user's.\n\nThe cancel-driven path is the only fully race-free one — os/exec in\n[…]\nhat may already\nbe reissued — an inherent limit of raw-PGID signalling, where the common outcome\nis a harmless ESRCH. The stale \"safe against PID reuse\" claim on TerminateGroup\nis corrected to say so.",
          "is_bot": false,
          "headline": "fix(task): stop signalling a process group that may have been reissued",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:39:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "970576f4c9db39e59b76bd279fcd28e24a0045d3",
          "body": "executeCommand returned a clean outcome for any non-zero exit other than\n2, leaving Error nil and discarding stderr:\n\n\tif exitCode != 0 {\n\t\treturn outcome\n\t}\n\nEngine.Execute keys everything off result.Error, so the run took neither\nthe warn branch nor the audit-error branch and was recorded as \"ran\"\n[…]\ne turn carries on exactly as\nbefore — the only change is that the failure is now visible.\n\nExit 2 keeps its own blocking path, and a zero exit is untouched.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(hook): stop swallowing a hook that exited non-zero",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:37:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dc64c01271d9f6dbde1ec59008544277a9a549ae",
          "body": "forkSession re-pointed the session id but left the agent running. The\nagent holds an onEvent closure over the Recorder it was built with\n(app/agent.go:96), and a Recorder's session is fixed at construction\n(session/recorder.go:78) — so every message, inference, permission and\nhook record after the f\n[…]\n keeps OmitMessageWrites true\ninstead of re-chaining the fork's messages with synthetic timestamps), and\nthe hook engine's transcript path follows the fork.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(session): stop /fork writing the fork's history into the parent",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:34:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "39794fd2c23383a3ab886d63dd2e87827ff9942b",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(core): do not emit TurnEvent for a failed turn",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:32:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "81a2ef62f74e713341af8c9c67e82de4b85005e6",
          "body": "ThinkAct dropped the turn entirely when the retry budget ran out or the\nerror was not retryable — `return nil, err`. The steps already taken were\nbilled, their messages were already appended, and all of it went nowhere.\n\nsubagent is where that costs the most. Run falls through to the bare-error\npath\n[…]\nirst signal on this path: Run's\nerror is discarded at agent/session.go:45 and StopEvent has no consumer,\nso a turn that died this way was previously silent.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(core): return a Result when a turn dies on inference failure",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:32:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bd3c5dd18292f5f7c100c7501a83ea40e5a152a3",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "docs(skill): trim the registryMu comment, deduped with the test",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:28:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4daeec4958166acce12e23e4247591aad846a113",
          "body": "skill.Initialize swapped the package-level *Registry with no\nsynchronisation, and Default()/DefaultIfInit() read it the same way.\n\nBoth goroutines are live at once. Initialize runs on the bubbletea\ngoroutine via reloadProjectServices, which is reached whenever the working\ndirectory changes — and the\n[…]\ngoes through Default() and Count() rather than touching\ndefaultRegistry.skills directly, so the read is covered by both locks\ninstead of reaching past them.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(skill): guard the package-level registry against concurrent reinit",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T11:28:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "26a96c91fd57112c0c0ece103dff28d9ffa521e9",
          "body": "* fix(subagent): keep the task tracker parent-only\n\nEvery conversation shares one process-global todo store, and subagents get\nthe tracker tools by default. A background subagent that calls TaskCreate to\nplan its own work leaks that item into the main session's task panel — it\nshows up as an extra r\n[…]\ned tracker\nregardless of their allow list; their progress is still surfaced by the worker\nitem the main conversation creates for them.\n\n* test(subagent): assert tracker tools have no subagent executor",
          "is_bot": false,
          "headline": "fix(subagent): keep the task tracker parent-only (#373)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T09:47:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a61597625e5fc1ad64e15ed075987d93dc63204b",
          "body": "Tint each tracker row owned by a background agent (icon + text) with that\nagent's color, mirroring the agent's launch line in the conversation flow.\nPlain user todos keep the status palette; aborted rows stay error-red and\nstalled rows stay muted, since those states carry more meaning than whose\nage\n[…]\nws stay in ID order and the active/pending tail — the work the\npanel exists to surface — is never hidden behind the fold. A failed/killed\nitem breaks the run so a failure is never folded out of sight.",
          "is_bot": false,
          "headline": "feat(tracker): tint agent-owned rows and fold finished overflow (#372)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-21T09:35:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b6a44f39ca35eecc8859c8266a4c949d396942ac",
          "body": "…utput (#350)\n\n* fix(task): make a bash task's graceful stop actually graceful\n\nStop cancelled the task context before sending SIGTERM. bash.go overrides\ncmd.Cancel to SIGKILL the whole process group, and exec runs that the instant\nthe context is done — so the kill always landed first and the SIGTER\n[…]\n, so \"Stop must not\ncancel the run\" is checked by handing it a cancel func that records being\ncalled.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(task): make the graceful stop graceful, and bound a bash task's o…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T17:16:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "616efb6967048b38d71c0edc9301f37b47051440",
          "body": "ThinkAct built Result.Content from a per-return-site argument while Steps\nand the token counts came from closure capture. Four of the six exits got\nit wrong: the step cap passed the literal \"max steps reached\" and all\nthree cancellation paths passed \"\".\n\nTwo consequences, both reachable:\n\n- A subage\n[…]\nn the wrong text or none.\n\nThe detail parameter is dropped for the same reason: all six sites passed\n\"\". The StopDetail field stays, since it has consumers.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(core): report the model's own output at every turn exit (#351)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T17:06:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4395ddcd6df478cf04160834fe4a5dbd48a95d25",
          "body": "* feat(autopilot): add /goal to hand over the wheel in one line\n\nDriving a goal hands-free meant opening /autopilot, writing a mission,\ntoggling four steers, and clearing the continuation cap — enough setup that\nthe autonomy was there but rarely reached for.\n\n/goal <what to achieve> does all of it: \n[…]\nly what happened the first time it was tried.\nSay so where the reader picks the directory, not after.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat(autopilot): add /goal, and fix two defects from #347 (#349)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T16:33:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0eef967471c775b58091c15758d1c9d489112c5a",
          "body": "…esult (#348)\n\n* fix(tracker): create worker entries from the task lifecycle, not the tool result\n\nA background task's tracker entry was built from the launching tool's\nHookResponse, which reaches the UI goroutine long after the task is already\nrunning. Its completion is announced from the task's ow\n[…]\nthe\n\"Tasks\" panel header. The translation now happens at those edges instead of\ninside every package.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(tracker): join worker items to the task lifecycle, not the tool r…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T16:28:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ae9dc8918d5c258e0366be49c9258592d3b54480",
          "body": "Closes #343.\n\nAllDone read Status and drove UI, the shape #342 removed elsewhere. It is\nnot a liveness query, though: it asks whether the model closed out every item\nit wrote down, and Status is the only record of that. Deriving it would be\nwrong, not merely unnecessary — a task left in_progress wit\n[…]\nnd give renderTrackerList a pointer receiver —\nit passes a *model method value, so a value receiver moved the whole ~68 KB\nmodel to the heap on every frame.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(tracker): window the task list on the newest items (#346)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T15:31:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4dbeb11634330d4a250b9f31a181ed84cf599094",
          "body": "* feat(autopilot): keep an unattended run alive\n\nAutopilot handed control back at every point a session normally stalls, so\na run left alone ended at the first thing that wasn't a clean turn.\n\n- Continue through a turn that stopped mid-work (step limit, unrecoverable\n  truncation), telling the copil\n[…]\n will not fix itself (bad credentials,\n  unknown model) returns instead of spending the retry budget.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat(autopilot): raise the autonomy level (#347)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T15:26:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b5635373f6fe63d3cfdc54378d4c9f1ebd7bfa8b",
          "body": "Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6 to 7.\n- [Release notes](https://github.com/actions/setup-go/releases)\n- [Commits](https://github.com/actions/setup-go/compare/v6...v7)\n\n---\nupdated-dependencies:\n- dependency-name: actions/setup-go\n  dependency-version: '7'\n  depen\n[…]\nirect:production\n  update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "ci(deps): bump actions/setup-go from 6 to 7 (#341)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-20T12:30:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d04e1d6040b55df1369b3f5d97203c57cc04fb4c",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.21.10 (#345)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T10:58:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4426109c3f799ad16415d6cebfad04d6090e6fc9",
          "body": "The tracker's ●/◌ pulse kept animating after a turn ended. needsSpinner\nkeyed off todo.Task.Status == in_progress, but that status records what\nthe model intended and outlives whatever was executing it — a task can be\nleft open by a kill, a crash, a cancel, or the model simply never closing\nit out. \n[…]\niveness\n  query and had no remaining consumer.\n\nAlso removes a TaskUpdate prompt line referencing a <task-reminder> that\nnothing in the codebase ever emits.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(tracker): derive in-progress state from live executors (#342)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T10:36:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "088933ab048af3155c896897b92211396a15ff84",
          "body": "… (#339)\n\n* fix: base auto-compaction on the full prompt, including cached tokens\n\nThe proactive compaction check used resp.InputTokens as its input. With\nprompt caching active a provider reports the cached prefix under\nCacheRead/CacheCreation and leaves only the uncached delta in InputTokens —\na fe\n[…]\nllm.DefaultInputLimit, removed earlier.\n- Delete a doc comment left duplicated above isPromptTooLong.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix: base auto-compaction on the full prompt, including cached tokens…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T10:04:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fa64b9724f7b76cc98849fbcff5b8929dddaeb40",
          "body": "…wrapping (#340)\n\n* fix(input): bind shift+enter, place the real cursor, size the box by wrapping\n\nThree composer defects, each independent.\n\nThe terminal cursor never moved to the input box. The textarea painted a\nreverse-video block and tea.View.Cursor was left nil, so the real cursor\nstayed where\n[…]\nouching the filesystem through history.Load to exercise a widget, and the\nplain-enter case folds into the newline table. go mod tidy demotes uniseg,\nwhose last use went with the old height arithmetic.",
          "is_bot": false,
          "headline": "fix(input): bind shift+enter, place the real cursor, size the box by …",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-20T08:18:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "49e00da4086f6f327ea5189c41381d5879e74ddd",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.21.9",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:27:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6be4704f5b0abaa7e3748e5a97c1e2e9a7d32e96",
          "body": "The editResult submap in the Edit HookResponse duplicated the typed\nEditDetails and was read nowhere; drop it. Fold renderEditResultInline's\nerror branch into renderGenericToolResultInline (it differed only by\nstripping a redundant \"Error: \" prefix), and use strings.CutPrefix for\nthe BOM check.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor: drop dead Edit hook map and dedupe error render",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7e3c14f8d4cb7dd4fb937d73c4918d09c971d292",
          "body": "Deferring the \"❭\" display to the agent's ingest echo left a released\nmessage invisible between the queue and the conversation: it was\ndequeued instantly but only shown once the agent ingested it, which\nmid-turn lags a full inference step (drainInbox is non-blocking, so the\nmessage sits in the inbox \n[…]\nsses it (live is one step\nahead of where a resumed transcript places it) — a cosmetic ordering\ndifference in exchange for no gap and a uniform display path.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix: show released queued message at release time, not on ingest echo",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6e2e3862d1518edf869acc4fdd93f1c365a1a2a0",
          "body": "The step-boundary and turn-boundary drains both popped the same user\nqueue with duplicated edit-hold guards and image-block handling, and\ndiverged only in how they displayed the released message. Extract the\nshared release into releaseHeadQueued and route both through it, so a\nreleased queue message\n[…]\nrain (persistence is unaffected —\n  it rides the agent's OnAppend, not conv display)\n- rename stepDrainPending -> awaitingIngestEcho now that it serves both\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor: unify step and turn queue drains into releaseHeadQueued",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d18b10908f092f9ea168239f4990271c987bffe5",
          "body": "The agent-side wait (a UI-semantics atomic.Bool + a 200ms timer in\ncore.drainInbox) only bought one inference step of steer latency: a\nmid-turn queued message still arrives mid-turn without it, just at the\nnext drainInbox rather than the immediate one. Remove it so the core\nloop stays UI-agnostic an\n[…]\n message ID (minted at\n  release, threaded through the new Session.SendMessage) instead of by\n  payload equality, so identical queued text can't cross-match\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor: drop pendingInput step-boundary wait, correlate by ID",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3d1d9b297eda74f7876f98506b840e3c07dc0cda",
          "body": "- add setting.filePathArg as the single source of truth for the Edit\n  (\"path\") vs Read/Write/NotebookEdit (\"file_path\") argument, replacing\n  four inline copies across the permission and suggestion rules\n- gate the per-step conversation walk on InputLimit() > 0, so a model\n  with no input limit skips work that can never trigger compaction\n- add CompactState.Clear() to dedupe the in-progress-indicator reset\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor: consolidate Edit path-key mapping and trim compaction waste",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ff6229e94377acbb6bbe5cacc26548355d00fd0d",
          "body": "- remove the computed-but-unread FirstChangedLine from EditDetails, the\n  HookResponse editResult map, and applyEdits' return signature\n- restore the ToolResult doc comment displaced onto EditDetails\n- render \"<Tool> → failed\" instead of repeating the error's first line,\n  which the always-shown expanded body already displays\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor: drop unused Edit metadata and dedupe error summary",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "26110b35e6d6d5236066d3183d775772ae191eea",
          "body": "A message typed while the agent is mid-turn now reaches it at the next\nstep — its drainInbox waits a brief bounded window (pendingInput) for the\nUI to release the head queued message — instead of waiting for the whole\nturn to end. So the message steers the run as its own step and stays\neditable in the queue right up to that boundary. Subagents never set\nPendingInput, so their drainInbox stays non-blocking.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat: release queued user messages at step boundaries",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1fdcd3c027d64fbfb449702e147369577e9c7a4a",
          "body": "- Task-completion notices inline the full result (up to 20000 bytes) or,\n  when larger, point to the output file instead of a truncated preview,\n  so the reader gets the whole report in one read.\n- Relayed background-agent messages (completions, interim reports) render\n  as a distinct accent-toned n\n[…]\nthan a plain system line.\n- On resume, injected <task-notification>/<agent-message> envelopes\n  collapse to that one-line notice instead of dumping raw XML.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat: clearer background-agent output in the conversation",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "edf10a81a69f01cf8121addc90a29aab997cd9ea",
          "body": "The Edit tool now sends \"path\" instead of \"file_path\", but\nGenerateSuggestions still read \"file_path\" for Edit, so allow-rule\nsuggestions on an Edit permission prompt came back empty. Split Edit\n(path) from Write (file_path), matching permission.BuildRule, and feed\neach tool its real arg key in the test so the mismatch can't recur.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix: read Edit path arg for permission-rule suggestions",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ae1ca0cbb8c12b86460513d6a940b9d1d445741a",
          "body": "The reasoning summary streams as discrete parts with no separator between\nthem. Each part is a bold \"**headline**\" section, so concatenating them\ndirectly collided adjacent parts (…truncation****Updating…). Insert a blank\nline between parts in both the live stream and the round-tripped reasoning\nitem.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix: separate OpenAI reasoning summary parts",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8debc61e1b558b1567fc67186a15a8437d0ff653",
          "body": "Auto-compaction ran a multi-second blocking summarization call with no UI\nfeedback, so it looked frozen. Emit a CompactStart event before the call\nso the UI shows the same \"Compacting N messages…\" line and spinner as\nmanual /compact, and clear it on completion or when the next inference\nstarts (covering the compaction-failure retry path).\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix: show progress during auto-compaction",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d482fce8d676a0bd1e78c41905302492ba2f354d",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat: align Edit tool with Pi format",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "48280642e4d98e2b8eb07a58f8368f25506189d0",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat: support batched file edits",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "92691f336fd548790ec8c3b1bb6a08d3ee949dda",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "docs: clarify README and tool feedback",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c6bed49dbb650d2cf3f286a54fed0b234da40c95",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "docs: simplify subagent model override description",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3f500460161a5abc9a6e777bd72a463ff7280767",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix: inherit subagent model when override unavailable",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a496104eb4e168926f3ce45dbf469a5d7746de42",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "perf: avoid repeated conversation and agent rendering work",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T17:14:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e8eb64af98ab1156fd5c37f900042899c4cd034d",
          "body": "The transcript index is re-serialized and rewritten in full at every turn\nboundary. Two things made that write larger than necessary: it was\npretty-printed (MarshalIndent), and Title/LastPrompt stored the full user\ntext, so a long paste bloated an entry that gets rewritten every turn.\n\nStore a bound\n[…]\nal compact. On a real\n328-session project this shrank the per-turn index write from 811 KB to\n160 KB, and the entry size no longer grows with prompt length.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "perf(session): cap index preview text and compact the index write",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T10:11:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a31792e1df825669df2aab8f16fe94612ff0ac2b",
          "body": "The index flush was hand-placed in QuitWithCancel, so the /exit and\n/quit slash commands — which run the same shutdown sequence but never\nreach that handler — quit without persisting their staged index\nmutations, defeating the deferral for those paths. Move the flush to\nthe single post-Run teardown \n[…]\n Setup.FlushIndex facade instead of reaching through\nGetStore, so all exit paths flush exactly once. Also drop an\nunreachable nil check in flushIndexLocked.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "perf(session): flush the transcript index on every quit path",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T09:56:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eb80a38f8c974d250b6398127299d6838012a3ec",
          "body": "The active tail is re-rendered on every frame — every 360ms spinner tick,\nfor the whole duration a tool runs — and any assistant message carrying tool\ncalls falls out of the plain-wrap fast path into the full glamour + chroma\npipeline. That re-ran on byte-identical content several times a second.\n\nM\n[…]\nhe map is bounded so a long session's\none-shot renders can't grow it without limit. A cache hit is ~10ns / 0 allocs\nversus ~640µs / 418KB for a full render.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "perf(conv): memoize markdown rendering across frames",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T09:56:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "360503397025c315a0069318d3af7a83ddf5bea4",
          "body": "The read-side index cache (5071c2aa) left the write side untouched: every\nmessage append and state patch still re-serialized and rewrote the whole\ntranscripts-index.json — O(sessions) work, ~7-12 full-file writes per turn,\nall under the store-global lock (and amplified by subagent message dumps).\n\nH\n[…]\n after a crash mid-first-turn. The\nindex is a pure derived cache, so an unflushed update is recovered by the\nrebuild-from-transcripts path on the next List.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "perf(session): defer transcript-index writes to turn boundaries",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T09:56:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eb706d1c5bc47e6df7f0c97a459cac91b89b7e54",
          "body": "Now that the Entry layer is gone, give the message-conversion helpers and files\na deliberate, parallel scheme:\n\n- MessageBlocks -> MessageToBlocks, matching its sibling *ToBlocks converters\n  (userContentToBlocks / assistantContentToBlocks / toolResultToBlocks) and\n  stating the action.\n- FileStore.\n[…]\nso collided with the\n  transcript package's own Project() concept.\n\nAlso drops a stale doc reference to the deleted messageToTranscript. No behavior\nchange.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor(session): sharpen conversion-layer names",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T09:56:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "42872462ea5e3d5c8d5ca96df26eb5343203cb6f",
          "body": "Session content was modeled four times end to end — core.Message,\nsession.Entry, transcript.Node, transcript.Record — with Entry carrying the\nlegacy Claude-Code on-disk schema in json tags that were never serialized. It\nsurvived only as an in-memory intermediate, forcing two near-identity converter\n\n[…]\n (verified by a golden node diff over\nreminder / command / image / thinking / tool-call / tool-result messages); full\ntest suite and the race detector pass.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor(session): drop the vestigial Entry layer",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T09:56:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0c0f99b72e4b9c571626ae70f23e240a481fcdc9",
          "body": "Every message append and state patch ran through upsertIndexEntryLocked, which\nre-read and re-parsed the entire transcripts-index.json (loadIndexLocked) before\nrewriting it — an O(sessions) unmarshal on every append. Cache the parsed index\non the FileStore: saveIndexLocked (the sole writer of the fi\n[…]\ny saveIndexLocked does, under the\nwrite lock), keeping it a pure read that is safe under the read lock in\nlistIndexEntries. Verified with the race detector.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "perf(session): cache the transcript index in memory",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T09:56:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3d4419203048509767c04bc5851ee319412e4c5e",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(llm): sync provider model metadata",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T06:03:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "71a14074e31e7ef0d73d4e18419b7703578d76c1",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(app): align bash prompt with result marker",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T06:03:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aa5750729827c6160098116a905bceec7e031c67",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(app): inset bash prompt marker",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T06:03:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b6bc6ed1f3ea5745c39e7b5c648ed934096012c4",
          "body": "Add a reverse invariant test so registering a built-in but forgetting to\nadd it to builtinToolOrder — a tool that executes yet stays invisible to\nthe model — fails in CI instead of shipping silently. It resolves each\nregistry entry to its canonical Schema().Name so deprecated aliases fold\nonto the t\n[…]\nat runtime; document the defensive !ok skip.\n- Clean up the leaked TestPermissionAwareTool registration that polluted\n  the global registry for later tests.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "test(tool): guard builtinToolOrder covers every registered tool",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T03:46:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6b117459da32c83ffc8d016eb3a5feb10d92d3a5",
          "body": "Each built-in tool's LLM schema lived as a package-level var in the tool\npackage (schema_base/schema_task/schema_agent), divorced from its\nimplementation and joined to it by a name string in AdaptToolRegistry.\nThis let the two drift (every tool carried two divergent descriptions) and\nleft core.Tool.\n[…]\nma (the tool is intentionally\nunregistered) and the unused filterSchemas. Schema output is byte-identical\nto before, verified by a golden diff against main.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor(tool): make built-in tools self-describing via Schema()",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T03:46:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c7285565929f129ca26f25cc32c9a6a94c1118fe",
          "body": "llm.CompletionResponse was a field-for-field twin of core.InferResponse,\nbridged by toInferResponse on every inference. Alias it to core.InferResponse\nso the provider streaming layer and the agent loop share one response type\nwith no conversion and no way to drift; the logging accessors move onto\nco\n[…]\nelds.\n\nNo behavior change: StopReason values and response fields are identical and the\nremoved chunks had no consumer. Full build, vet, and test suite pass.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor(llm): unify the provider response type onto core.InferResponse",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-19T03:36:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9d82666199819e89a9974082e51218fe50ec524c",
          "body": "* fix(app): inset bash prompt marker\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* fix(app): align bash prompt with result marker\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* chore: bump version to 1.21.8\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.21.8 (#330)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T17:07:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d5edcc1480c0d115495208da77f553296c317c41",
          "body": "…#329)\n\n* fix(app): snapshot permission audit input before releasing the gate\n\nAgent tools decorate their shared input map with runtime callbacks as\nsoon as the permission response wakes them. Serializing that map after\nreleasing the gate could race the write and crash the process with a\nconcurrent \n[…]\nwo, and rename the helper and\nlocal to the file's perm* convention (permDecisionRecord / permRecord).\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(app): snapshot permission audit input before releasing the gate (…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T16:57:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d9af0e10006973fb3eea96a2d99e61de6a556105",
          "body": "* chore: bump version to 1.21.7\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* fix(app): align bash command and result columns\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* fix(app): inset bash prompt marker\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* fix(app): align bash prompt with result mark\n[…]\ne().\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* fix(app): sync hooks with restored operation mode\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore(release): v1.21.7 (#328)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T16:40:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b40d63e1049f784ea5531f95854f5a6f6b0fe400",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "fix(app): preserve live context across agent restarts",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T14:26:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8047dc05b96b4428c6d61e2182320b0977723335",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "style(agent): format session test",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T14:26:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "952276c996edac5dd7060c609c576ae0a99996b1",
          "body": "A mid-conversation agent rebuild (self-learn capability drift, /evolve save,\nagent toggle) reseeded the replacement agent from m.conv — the UI conversation\nmodel. When that model and the agent's live chain diverge, the reseed comes back\nempty, so the rebuilt agent starts with no history: the model s\n[…]\nes() surfaces the seeded chain with ids; nil when inactive\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_014Myxco9T1v4JbPsuKqa8kc",
          "is_bot": false,
          "headline": "fix(app): carry the agent's own chain into a rebuilt session",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T14:26:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "31db935d90f42bd931e9b74d8fff0f37d1454c5d",
          "body": "Review follow-ups on the flat spawn→result subagent work:\n\n- Project instructions now reach any worker that can edit the workspace,\n  not just edit/bypass modes: a default-mode worker whose allow_tools\n  grants an edit-class tool (Edit/Write/NotebookEdit) gets them too, so its\n  edits follow project\n[…]\ntMessages — its only caller\n  was the removed resume path.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015fRqq5ZarHvEMng7EGoQdS",
          "is_bot": false,
          "headline": "fix(subagent): give allow_tools edit workers project instructions",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T14:26:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d4fe2db4aa034db756f0c75997a5f761398cecbd",
          "body": "… activity naming\n\n- broker: introduce the Deliver type and have it return bool, so Send\n  reports whether a message was actually accepted; a full recipient inbox\n  is now distinguishable from a silent drop. Threaded through the main,\n  task-completion, and subagent delivery callbacks.\n- tool: extra\n[…]\nand comments.\n- docs + system testdata refreshed to match.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_014Myxco9T1v4JbPsuKqa8kc",
          "is_bot": false,
          "headline": "refactor(subagent): broker delivery reporting + shared XML escaping +…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T14:26:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "63142c30be4788023fed9ad3a16a1ec0b99c04a9",
          "body": "Subagent worktree isolation created a git worktree under\n.git/agent-worktrees/<slug> for each isolated run. That hard-fails when\nSan itself runs inside a linked worktree (where .git is a file, not a\ndirectory): `git worktree add` errors with \"Not a directory\", so every\nisolated subagent died before \n[…]\nrentOnlyTools excludes Agent from every subagent tool set.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_014Myxco9T1v4JbPsuKqa8kc",
          "is_bot": false,
          "headline": "refactor(subagent): drop worktree isolation; run in session cwd",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T14:26:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b5e1b84a89500ec8e9bd1647b34d9bebd35f7e6f",
          "body": "… reuse notifyMain\n\nFollow-up cleanups on the spawn→result / broker rework:\n\n- Extract finalizeResult() shared by buildAgentResult and\n  buildCancelledAgentResult. They differed only in Success/Error but\n  duplicated the whole settle/persist/hook flow and a 15-field AgentResult\n  literal that had to\n[…]\nve the now-redundant concepts/agent-communication.md and align\ndata-flow / permission-model / writing-a-subagent / broker / subagent with the\nshipped model.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor(subagent): dedup result builders, drop double worktree note,…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T14:26:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bbde76461edb5156608e31846baff27de3def7a1",
          "body": "Rework subagent communication down to the essentials and route all\ninter-agent messages through one small broker.\n\nSubagents:\n- spawn → result: foreground returns the tool result; background runs in\n  parallel and sends a completion when done. One-shot (no resume).\n- flat: only the main conversation\n[…]\np/hub\nreferences scrubbed across architecture/app/data-flow/package-map.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_015fRqq5ZarHvEMng7EGoQdS",
          "is_bot": false,
          "headline": "feat(subagent): flat spawn→result model + broker message routing",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T14:26:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7ef9f39ea11b05e9a341e342c8fa969c2d50e445",
          "body": "Signed-off-by: hchenxa <hchenxa1986@qq.com>",
          "is_bot": false,
          "headline": "feat: add json version output (#324)",
          "author_name": "Hui Chen",
          "author_login": "hchenxa",
          "committed_at": "2026-07-18T09:55:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "021569b4701cb56fae2eb9c4c0255747cf460149",
          "body": "InputLimit and the output-token cap resolve from the provider's ListModels,\nwhich is a live /v1/models round-trip for OpenAI-compatible providers\n(Anthropic/Google cache internally). They were called on every inference step\n— the pre-infer compaction check and every Infer/Stream — so a 20-step turn\n\n[…]\n resolved input/output\nlimits per model on the Client. Only a successful (non-zero) lookup is cached;\na transient failure retries rather than sticking at 0.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "perf(llm): memoize model token limits per client (#322)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-18T00:41:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5068221a5bbf56ed062a7899599e8105de69c893",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.21.6 (#321)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-17T17:03:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "120e9bb72263db751a238ad9d9e23b87b1b941e6",
          "body": "A disciplined senior-engineer persona for developing San: think before coding,\nask instead of assuming, write the minimum that solves the problem, change only\nwhat the task requires, and verify before claiming done.\n\nShips project-scoped — .gitignore gains `!.san/personas/` alongside the existing\n`!\n[…]\n from\nSan's own Apache-2.0 simplify skill. NOTICE records the provenance. Canonical\ncopy lives in genai-io/personas.\n\nSigned-off-by: Meng Yan <ben@stark.fund>\nCo-authored-by: Meng Yan <ben@stark.fund>",
          "is_bot": false,
          "headline": "feat: add project-scoped software-engineer persona (#318)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-17T16:58:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9925789a3730613ce955db75cac9b019b10f0c03",
          "body": "…#319)\n\nRender a multi-line Bash tool call — or a single line too long for the\ncompact Bash(cmd) label — as a terminal-style block below the \"● Bash\"\nheader: a dim shell \"$\" prompt sitting in the same column as the \"⎿\"\nresult trailer, with wrapped and continued lines hanging under the command\ntext s\n[…]\n up in one column. Short single-line commands\nkeep the compact label, and commands soft-wrap in full rather than\ntruncate, so the command is always visible.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat(bash): render multi-line commands as a $-prompt terminal block (…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-17T16:20:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "11e5100dcbd62633cd77d1d7a1da4e37d7d4c403",
          "body": "…lt (#317)\n\nallowBypass now defaults to enabled: Bypass Permissions is reachable via\nShift+Tab (and as a settings defaultMode) unless the user explicitly sets\n\"allowBypass\": false to lock it out. Previously it required opting in.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat(setting): make Bypass Permissions opt-out, in the cycle by defau…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-17T12:14:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "041f4998ecd2aea9c8dd1ec579fe17e8786acd37",
          "body": "…#316)\n\nThe status line already shows real context-window occupancy as\n\"ctx used/limit\". A second per-turn \"↑… ↓…\" token summary above the\ninput area used a different scope (turn accumulation), so the two\nfigures conflicted and confused readers. Remove the top summary and\neverything that fed only it\n[…]\nts: cached-token split for the Responses stream, latest-call-only\nctx accounting across two OnTokenUsage calls, status line shows ctx\nwithout the \"↑…↓…\" arrows, and unit coverage for SplitInputTokens.",
          "is_bot": false,
          "headline": "fix(app,llm): drop turn-usage line, fix OpenAI cached-token mapping (…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-17T11:41:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6399682f001db604ef142e546ba26401ca0d1b5a",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.21.5",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-17T09:49:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b40660705a659d376dec0e3638f2f6fa4222a5c2",
          "body": "…#311)\n\nGive self-learning its own /evolve overlay (skills + memory), split out of\n/config, and drive it entirely by the model rather than by cadence/rules.\n\nTrigger: when self-learning is active the main agent gets one safe Evolve\ntool. Calling it queues a background review at turn end — no cadence\n[…]\nllowed; memory opt-in). The\nskills JSON keeps an explicit `enabled` marker so legacy opt-outs stay off.\n\ngo build / vet / test ./... / layercheck all green.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat(selflearn): dedicated /evolve panel with model-decided trigger (…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-17T09:18:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3d4998cef769e4cbf0174dbf43832ea42f387d95",
          "body": "Queued messages now read as part of the conversation instead of a\nstatus-bar footnote:\n\n- Render each queued item as a dim \"❭\" shadow prompt above the input\n  separator, mirroring the live prompt below — no more \"1. 2. 3.\"\n  numbering.\n- Drop the \"[N queued]\" status-bar badge; the queue block is the\n[…]\nng it when a dequeued\n  item carries images the active model can't accept.\n- Preserve an unrelated textarea draft across an idle drain, and restore\n  the pre-edit stash before ctrl+u clears the queue.",
          "is_bot": false,
          "headline": "feat(queue): redesign queued-message interaction (#312) (#313)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-17T06:43:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fb445181b5fdd9eea504c6642c4d3600e6d0882e",
          "body": "Add CONTRIBUTOR_LADDER.md defining the Contributor -> Reviewer ->\nApprover -> Maintainer roles mapped to the OWNERS file, following the\nCNCF contributor-ladder conventions, and link it from CONTRIBUTING.md.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "docs: add contributor ladder (#301)",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-13T16:24:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a96f9bf0513ad8deee3c28c59832044e728d530d",
          "body": "Bumps [actions/stale](https://github.com/actions/stale) from 10.3.0 to 10.4.0.\n- [Release notes](https://github.com/actions/stale/releases)\n- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/actions/stale/compare/eb5cf3af3ac0a1aa4c9c45633dd1ae542a27\n[…]\nirect:production\n  update-type: version-update:semver-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "ci(deps): bump actions/stale from 10.3.0 to 10.4.0 (#306)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-13T15:44:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3438c2c6d24364d776844b7e7157b0e801d0c479",
          "body": "Signed-off-by: hchenxa <hchenxa1986@qq.com>",
          "is_bot": false,
          "headline": "feat: add session naming features",
          "author_name": "hchenxa",
          "author_login": "hchenxa",
          "committed_at": "2026-07-13T15:24:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "66102d0b187ff772efaa6b043b98f538827d73c1",
          "body": "Signed-off-by: hchenxa <hchenxa1986@qq.com>",
          "is_bot": false,
          "headline": "fix: agent time out issue",
          "author_name": "hchenxa",
          "author_login": "hchenxa",
          "committed_at": "2026-07-13T15:12:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1c879ae861ba5092f20f824cda2ecb69a764329c",
          "body": "Signed-off-by: hchenxa <hchenxa1986@qq.com>",
          "is_bot": false,
          "headline": "fix: fix the instllation issues when ratelimit reached",
          "author_name": "hchenxa",
          "author_login": "hchenxa",
          "committed_at": "2026-07-13T06:41:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8a7dd0135980279fa8acfea34fdbe02fb2c32bf0",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.21.4",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-10T18:40:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0f6af4ef825eb37372b004ef55c5fb2a5ad56a97",
          "body": "- extract Store.ResolveAuthMethod: the model-auth fallback (use the stored\n  connection's auth when the model carries none) was copy-pasted in both\n  reasoningCapabilityForModel and kit.GetModelTokenLimits; both now call it.\n- CachedModelReasoningForProvider returns the cached *ReasoningCapability\n \n[…]\nf rebuilding it with NewReasoningCapability on every lookup;\n  the value was already normalized at write time and this runs on the\n  status-bar render path.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor(llm): dedup auth resolution and drop redundant re-normalization",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-10T18:27:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5e7d6b5612000493d3c3a5d8404fe8431d402836",
          "body": "Carry ModelInfo.Description through to the model picker and trail the model\nname with a dimmed, width-truncated blurb when present. Populate it from the\nChatGPT Codex catalog's top-level per-model \"description\" (verified against\nthe codex ModelInfo wire struct); it stays blank for catalogs that omit it,\nso the row is unchanged for those.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat(provider): show the model description dimmed in the picker",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-10T18:27:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3732886b9e4964f7ab3af491a256da4440097189",
          "body": "- rename ReasoningCapability.Efforts -> SupportedEfforts (json supportedEfforts)\n  so it reads as a pair with DefaultEffort and mirrors the codex wire field\n  supported_reasoning_levels; the field is new in this branch, so no released\n  cache carries the old key.\n- inline the vestigial openAIDefaultThinkingEffort helper back into the\n  DefaultThinkingEffort method now that openAIModelInfo no longer calls it.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor(llm): name the reasoning-capability field SupportedEfforts",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-10T18:27:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f2557f1e3818b356b8fb43c3706ad728dfd8144b",
          "body": "…d guesses\n\n- openAIModelInfo no longer sets ModelInfo.Reasoning; only live catalogs\n  (the ChatGPT subscription /models response) attach it. /v1/models entries\n  fall back to the provider's static ThinkingEffortProvider rules at\n  resolution time, so a binary's updated static rules are no longer ma\n[…]\n by the TTL-ignoring reasoning cache read.\n- drop the now-unused ResolveThinkingEffort / NextThinkingEffort helpers,\n  superseded by the *ForModel variants.\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "refactor(openai): resolve reasoning capabilities live, not from cache…",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-10T18:27:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f67f5bac15b47251031457021d6f4fe435c6df34",
          "body": "Signed-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "feat(openai): discover model reasoning capabilities",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-10T18:27:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "55e607b6a3537ef04a55ca72292d0b936c719b4f",
          "body": "Adds hchenxa to OWNERS as reviewer/approver (see #285).\n\nSigned-off-by: hchenxa <hchenxa1986@qq.com>",
          "is_bot": false,
          "headline": "feat: add hchenxa as reviewers (#295)",
          "author_name": "Hui Chen",
          "author_login": "hchenxa",
          "committed_at": "2026-07-10T15:40:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1ae0167cd755e00bf12671df89d6cccb4516bb9",
          "body": "* fix: handle paste in autopilot overlay\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n* chore: bump version to 1.21.3\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>\n\n---------\n\nSigned-off-by: Meng Yan <yanmxa@gmail.com>",
          "is_bot": false,
          "headline": "chore: bump version to 1.21.3",
          "author_name": "Meng Yan",
          "author_login": "yanmxa",
          "committed_at": "2026-07-10T14:25:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 100,
      "commits_last_year": 979,
      "latest_release_at": "2026-07-21T16:26:44Z",
      "latest_release_tag": "v1.21.11",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 28,
      "days_since_latest_release": 0,
      "mean_days_between_releases": 1.3
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 87,
      "has_issue_template": false,
      "has_code_of_conduct": true,
      "has_pull_request_template": true
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/genai-io/san",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/genai-io/san",
          "is_deprecated": false,
          "latest_version": "v1.21.11",
          "repository_url": "https://github.com/genai-io/san",
          "versions_count": 123,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-21T15:28:52Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 32,
      "stars": 70,
      "watchers": 3,
      "fork_history": {
        "days": [
          {
            "date": "2025-04-03",
            "count": 1
          },
          {
            "date": "2026-02-09",
            "count": 1
          },
          {
            "date": "2026-03-05",
            "count": 1
          },
          {
            "date": "2026-05-13",
            "count": 1
          },
          {
            "date": "2026-05-14",
            "count": 1
          },
          {
            "date": "2026-05-23",
            "count": 1
          },
          {
            "date": "2026-05-26",
            "count": 1
          },
          {
            "date": "2026-05-27",
            "count": 1
          },
          {
            "date": "2026-05-28",
            "count": 1
          },
          {
            "date": "2026-06-01",
            "count": 1
          },
          {
            "date": "2026-06-04",
            "count": 1
          },
          {
            "date": "2026-06-05",
            "count": 9
          },
          {
            "date": "2026-06-06",
            "count": 2
          },
          {
            "date": "2026-06-08",
            "count": 1
          },
          {
            "date": "2026-06-11",
            "count": 1
          },
          {
            "date": "2026-06-12",
            "count": 3
          },
          {
            "date": "2026-06-13",
            "count": 1
          },
          {
            "date": "2026-06-17",
            "count": 1
          },
          {
            "date": "2026-06-21",
            "count": 1
          },
          {
            "date": "2026-07-07",
            "count": 1
          },
          {
            "date": "2026-07-16",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 32,
        "total_forks": 32
      },
      "star_history": {
        "days": [
          {
            "date": "2024-11-04",
            "count": 1
          },
          {
            "date": "2024-11-06",
            "count": 1
          },
          {
            "date": "2025-02-28",
            "count": 1
          },
          {
            "date": "2025-04-14",
            "count": 1
          },
          {
            "date": "2025-05-20",
            "count": 1
          },
          {
            "date": "2026-01-16",
            "count": 1
          },
          {
            "date": "2026-02-03",
            "count": 1
          },
          {
            "date": "2026-02-09",
            "count": 1
          },
          {
            "date": "2026-04-10",
            "count": 1
          },
          {
            "date": "2026-04-22",
            "count": 1
          },
          {
            "date": "2026-04-28",
            "count": 1
          },
          {
            "date": "2026-05-01",
            "count": 1
          },
          {
            "date": "2026-05-13",
            "count": 7
          },
          {
            "date": "2026-05-14",
            "count": 8
          },
          {
            "date": "2026-05-15",
            "count": 6
          },
          {
            "date": "2026-05-19",
            "count": 1
          },
          {
            "date": "2026-05-28",
            "count": 1
          },
          {
            "date": "2026-06-01",
            "count": 1
          },
          {
            "date": "2026-06-03",
            "count": 1
          },
          {
            "date": "2026-06-04",
            "count": 1
          },
          {
            "date": "2026-06-05",
            "count": 7
          },
          {
            "date": "2026-06-06",
            "count": 1
          },
          {
            "date": "2026-06-07",
            "count": 2
          },
          {
            "date": "2026-06-08",
            "count": 1
          },
          {
            "date": "2026-06-09",
            "count": 1
          },
          {
            "date": "2026-06-10",
            "count": 3
          },
          {
            "date": "2026-06-11",
            "count": 2
          },
          {
            "date": "2026-06-12",
            "count": 3
          },
          {
            "date": "2026-06-13",
            "count": 2
          },
          {
            "date": "2026-06-14",
            "count": 1
          },
          {
            "date": "2026-06-17",
            "count": 1
          },
          {
            "date": "2026-06-24",
            "count": 1
          },
          {
            "date": "2026-06-26",
            "count": 1
          },
          {
            "date": "2026-06-28",
            "count": 1
          },
          {
            "date": "2026-07-07",
            "count": 1
          },
          {
            "date": "2026-07-13",
            "count": 1
          },
          {
            "date": "2026-07-14",
            "count": 1
          },
          {
            "date": "2026-07-16",
            "count": 1
          },
          {
            "date": "2026-07-19",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 70,
        "total_stars": 70
      },
      "open_issues_and_prs": 11
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 49529,
      "source_files_sampled": 622,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        "AGENTS.md",
        "docs/packages/2-feature/agent.md"
      ],
      "agent_instruction_max_bytes": 3518
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "advisories": {
        "error": null,
        "scope": "repository_graph",
        "source": "osv",
        "findings": [
          {
            "name": "golang.org/x/crypto",
            "direct": false,
            "version": "v0.40.0",
            "severity": "critical",
            "ecosystem": "go",
            "cvss_score": 10,
            "advisory_ids": [
              "GHSA-45gg-vh54-h5m9",
              "GHSA-5cgq-3rg8-m6cv",
              "GHSA-78mq-xcr3-xm33",
              "GHSA-89gr-r52h-f8rx",
              "GHSA-9m57-25v3-79x9",
              "GHSA-f5wc-c3c7-36mc",
              "GHSA-f6x5-jh6r-wrfv",
              "GHSA-j5w8-q4qc-rx2x",
              "GHSA-jppx-rxg9-jmrx",
              "GHSA-q4h4-gmj2-qvw2"
            ],
            "fixed_version": "0.52.0",
            "advisory_count": 32,
            "oldest_advisory_days": 250
          },
          {
            "name": "google.golang.org/grpc",
            "direct": false,
            "version": "v1.66.2",
            "severity": "critical",
            "ecosystem": "go",
            "cvss_score": 9.1,
            "advisory_ids": [
              "GHSA-hrxh-6v49-42gf",
              "GHSA-p77j-4mvh-x3m3",
              "GO-2026-4762"
            ],
            "fixed_version": "1.82.1",
            "advisory_count": 3,
            "oldest_advisory_days": 125
          },
          {
            "name": "golang.org/x/net",
            "direct": false,
            "version": "v0.41.0",
            "severity": "moderate",
            "ecosystem": "go",
            "cvss_score": 6.5,
            "advisory_ids": [
              "GHSA-5cv4-jp36-h3mw",
              "GO-2026-4440",
              "GO-2026-4441",
              "GO-2026-4918",
              "GO-2026-5025",
              "GO-2026-5026",
              "GO-2026-5027",
              "GO-2026-5028",
              "GO-2026-5029",
              "GO-2026-5030"
            ],
            "fixed_version": "1.26.3",
            "advisory_count": 11,
            "oldest_advisory_days": 166
          },
          {
            "name": "github.com/yuin/goldmark",
            "direct": false,
            "version": "v1.7.13",
            "severity": "unknown",
            "ecosystem": "go",
            "cvss_score": null,
            "advisory_ids": [
              "GO-2026-5320"
            ],
            "fixed_version": "1.7.17",
            "advisory_count": 1,
            "oldest_advisory_days": 14
          },
          {
            "name": "golang.org/x/text",
            "direct": false,
            "version": "v0.30.0",
            "severity": "unknown",
            "ecosystem": "go",
            "cvss_score": null,
            "advisory_ids": [
              "GO-2026-5970"
            ],
            "fixed_version": "0.39.0",
            "advisory_count": 1,
            "oldest_advisory_days": 7
          }
        ],
        "collected": true,
        "malicious": [],
        "truncated": false,
        "by_severity": {
          "unknown": 2,
          "critical": 2,
          "moderate": 1
        },
        "advisory_count": 48,
        "affected_count": 5,
        "assessed_count": 78,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "go"
      ],
      "dependencies": [
        {
          "name": "charm.land/bubbles/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.1.0"
        },
        {
          "name": "charm.land/bubbletea/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.7"
        },
        {
          "name": "charm.land/glamour/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.1"
        },
        {
          "name": "charm.land/lipgloss/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.4"
        },
        {
          "name": "github.com/JohannesKaufmann/html-to-markdown",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.6.0"
        },
        {
          "name": "github.com/PuerkitoBio/goquery",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.9.2"
        },
        {
          "name": "github.com/anthropics/anthropic-sdk-go",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.27.1"
        },
        {
          "name": "github.com/bmatcuk/doublestar/v4",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v4.9.2"
        },
        {
          "name": "github.com/charmbracelet/x/ansi",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.11.7"
        },
        {
          "name": "github.com/creack/pty",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.1.24"
        },
        {
          "name": "github.com/hexops/gotextdiff",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.0.3"
        },
        {
          "name": "github.com/joho/godotenv",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.5.1"
        },
        {
          "name": "github.com/mattn/go-runewidth",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.23"
        },
        {
          "name": "github.com/openai/openai-go/v3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.32.0"
        },
        {
          "name": "github.com/spf13/cobra",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.8.1"
        },
        {
          "name": "go.uber.org/zap",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.27.0"
        },
        {
          "name": "golang.org/x/term",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.40.0"
        },
        {
          "name": "google.golang.org/genai",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.58.0"
        },
        {
          "name": "gopkg.in/natefinch/lumberjack.v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.2.1"
        },
        {
          "name": "gopkg.in/yaml.v3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.0.1"
        },
        {
          "name": "mvdan.cc/sh/v3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.13.0"
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "charm.land/bubbles/v2",
            "direct": true,
            "version": "v2.1.0",
            "ecosystem": "go"
          },
          {
            "name": "charm.land/bubbletea/v2",
            "direct": true,
            "version": "v2.0.7",
            "ecosystem": "go"
          },
          {
            "name": "charm.land/glamour/v2",
            "direct": true,
            "version": "v2.0.1",
            "ecosystem": "go"
          },
          {
            "name": "charm.land/lipgloss/v2",
            "direct": true,
            "version": "v2.0.4",
            "ecosystem": "go"
          },
          {
            "name": "github.com/anthropics/anthropic-sdk-go",
            "direct": true,
            "version": "v1.27.1",
            "ecosystem": "go"
          },
          {
            "name": "github.com/bmatcuk/doublestar/v4",
            "direct": true,
            "version": "v4.9.2",
            "ecosystem": "go"
          },
          {
            "name": "github.com/charmbracelet/x/ansi",
            "direct": true,
            "version": "v0.11.7",
            "ecosystem": "go"
          },
          {
            "name": "github.com/creack/pty",
            "direct": true,
            "version": "v1.1.24",
            "ecosystem": "go"
          },
          {
            "name": "github.com/hexops/gotextdiff",
            "direct": true,
            "version": "v1.0.3",
            "ecosystem": "go"
          },
          {
            "name": "github.com/johanneskaufmann/html-to-markdown",
            "direct": true,
            "version": "v1.6.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/joho/godotenv",
            "direct": true,
            "version": "v1.5.1",
            "ecosystem": "go"
          },
          {
            "name": "github.com/mattn/go-runewidth",
            "direct": true,
            "version": "v0.0.23",
            "ecosystem": "go"
          },
          {
            "name": "github.com/openai/openai-go/v3",
            "direct": true,
            "version": "v3.32.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/puerkitobio/goquery",
            "direct": true,
            "version": "v1.9.2",
            "ecosystem": "go"
          },
          {
            "name": "github.com/spf13/cobra",
            "direct": true,
            "version": "v1.8.1",
            "ecosystem": "go"
          },
          {
            "name": "go.uber.org/zap",
            "direct": true,
            "version": "v1.27.0",
            "ecosystem": "go"
          },
          {
            "name": "golang.org/x/term",
            "direct": true,
            "version": "v0.40.0",
            "ecosystem": "go"
          },
          {
            "name": "google.golang.org/genai",
            "direct": true,
            "version": "v1.58.0",
            "ecosystem": "go"
          },
          {
            "name": "gopkg.in/natefinch/lumberjack.v2",
            "direct": true,
            "version": "v2.2.1",
            "ecosystem": "go"
          },
          {
            "name": "gopkg.in/yaml.v3",
            "direct": true,
            "version": "v3.0.1",
            "ecosystem": "go"
          },
          {
            "name": "mvdan.cc/sh/v3",
            "direct": true,
            "version": "v3.13.0",
            "ecosystem": "go"
          },
          {
            "name": "cloud.google.com/go",
            "direct": false,
            "version": "v0.116.0",
            "ecosystem": "go"
          },
          {
            "name": "cloud.google.com/go/auth",
            "direct": false,
            "version": "v0.9.3",
            "ecosystem": "go"
          },
          {
            "name": "cloud.google.com/go/auth/oauth2adapt",
            "direct": false,
            "version": "v0.2.4",
            "ecosystem": "go"
          },
          {
            "name": "cloud.google.com/go/compute/metadata",
            "direct": false,
            "version": "v0.5.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/alecthomas/chroma/v2",
            "direct": false,
            "version": "v2.20.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/andybalholm/cascadia",
            "direct": false,
            "version": "v1.3.2",
            "ecosystem": "go"
          },
          {
            "name": "github.com/atotto/clipboard",
            "direct": false,
            "version": "v0.1.4",
            "ecosystem": "go"
          },
          {
            "name": "github.com/aymerick/douceur",
            "direct": false,
            "version": "v0.2.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/charmbracelet/colorprofile",
            "direct": false,
            "version": "v0.4.3",
            "ecosystem": "go"
          },
          {
            "name": "github.com/charmbracelet/ultraviolet",
            "direct": false,
            "version": "v0.0.0-20260525132238-948f4557a654",
            "ecosystem": "go"
          },
          {
            "name": "github.com/charmbracelet/x/exp/slice",
            "direct": false,
            "version": "v0.0.0-20250327172914-2fdc97757edf",
            "ecosystem": "go"
          },
          {
            "name": "github.com/charmbracelet/x/term",
            "direct": false,
            "version": "v0.2.2",
            "ecosystem": "go"
          },
          {
            "name": "github.com/charmbracelet/x/termios",
            "direct": false,
            "version": "v0.1.1",
            "ecosystem": "go"
          },
          {
            "name": "github.com/charmbracelet/x/windows",
            "direct": false,
            "version": "v0.2.2",
            "ecosystem": "go"
          },
          {
            "name": "github.com/clipperhouse/displaywidth",
            "direct": false,
            "version": "v0.11.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/clipperhouse/uax29/v2",
            "direct": false,
            "version": "v2.7.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/dlclark/regexp2",
            "direct": false,
            "version": "v1.11.5",
            "ecosystem": "go"
          },
          {
            "name": "github.com/felixge/httpsnoop",
            "direct": false,
            "version": "v1.0.4",
            "ecosystem": "go"
          },
          {
            "name": "github.com/go-logr/logr",
            "direct": false,
            "version": "v1.4.2",
            "ecosystem": "go"
          },
          {
            "name": "github.com/go-logr/stdr",
            "direct": false,
            "version": "v1.2.2",
            "ecosystem": "go"
          },
          {
            "name": "github.com/golang/groupcache",
            "direct": false,
            "version": "v0.0.0-20210331224755-41bb18bfe9da",
            "ecosystem": "go"
          },
          {
            "name": "github.com/google/go-cmp",
            "direct": false,
            "version": "v0.7.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/google/s2a-go",
            "direct": false,
            "version": "v0.1.8",
            "ecosystem": "go"
          },
          {
            "name": "github.com/googleapis/enterprise-certificate-proxy",
            "direct": false,
            "version": "v0.3.4",
            "ecosystem": "go"
          },
          {
            "name": "github.com/gorilla/css",
            "direct": false,
            "version": "v1.0.1",
            "ecosystem": "go"
          },
          {
            "name": "github.com/gorilla/websocket",
            "direct": false,
            "version": "v1.5.3",
            "ecosystem": "go"
          },
          {
            "name": "github.com/inconshreveable/mousetrap",
            "direct": false,
            "version": "v1.1.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/lucasb-eyer/go-colorful",
            "direct": false,
            "version": "v1.4.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/microcosm-cc/bluemonday",
            "direct": false,
            "version": "v1.0.27",
            "ecosystem": "go"
          },
          {
            "name": "github.com/muesli/cancelreader",
            "direct": false,
            "version": "v0.2.2",
            "ecosystem": "go"
          },
          {
            "name": "github.com/rivo/uniseg",
            "direct": false,
            "version": "v0.4.7",
            "ecosystem": "go"
          },
          {
            "name": "github.com/spf13/pflag",
            "direct": false,
            "version": "v1.0.5",
            "ecosystem": "go"
          },
          {
            "name": "github.com/tidwall/gjson",
            "direct": false,
            "version": "v1.18.0",
            "ecosystem": "go"
          },
          {
            "name": "github.com/tidwall/match",
            "direct": false,
            "version": "v1.1.1",
            "ecosystem": "go"
          },
          {
            "name": "github.com/tidwall/pretty",
            "direct": false,
            "version": "v1.2.1",
            "ecosystem": "go"
          },
          {
            "name": "github.com/tidwall/sjson",
            "direct": false,
            "version": "v1.2.5",
            "ecosystem": "go"
          },
          {
            "name": "github.com/xo/terminfo",
            "direct": false,
            "version": "v0.0.0-20220910002029-abceb7e1c41e",
            "ecosystem": "go"
          },
          {
            "name": "github.com/yuin/goldmark",
            "direct": false,
            "version": "v1.7.13",
            "ecosystem": "go"
          },
          {
            "name": "github.com/yuin/goldmark-emoji",
            "direct": false,
            "version": "v1.0.6",
            "ecosystem": "go"
          },
          {
            "name": "go.opencensus.io",
            "direct": false,
            "version": "v0.24.0",
            "ecosystem": "go"
          },
          {
            "name": "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc",
            "direct": false,
            "version": "v0.54.0",
            "ecosystem": "go"
          },
          {
            "name": "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",
            "direct": false,
            "version": "v0.54.0",
            "ecosystem": "go"
          },
          {
            "name": "go.opentelemetry.io/otel",
            "direct": false,
            "version": "v1.29.0",
            "ecosystem": "go"
          },
          {
            "name": "go.opentelemetry.io/otel/metric",
            "direct": false,
            "version": "v1.29.0",
            "ecosystem": "go"
          },
          {
            "name": "go.opentelemetry.io/otel/trace",
            "direct": false,
            "version": "v1.29.0",
            "ecosystem": "go"
          },
          {
            "name": "go.uber.org/multierr",
            "direct": false,
            "version": "v1.10.0",
            "ecosystem": "go"
          },
          {
            "name": "golang.org/x/crypto",
            "direct": false,
            "version": "v0.40.0",
            "ecosystem": "go"
          },
          {
            "name": "golang.org/x/net",
            "direct": false,
            "version": "v0.41.0",
            "ecosystem": "go"
          },
          {
            "name": "golang.org/x/oauth2",
            "direct": false,
            "version": "v0.30.0",
            "ecosystem": "go"
          },
          {
            "name": "golang.org/x/sync",
            "direct": false,
            "version": "v0.20.0",
            "ecosystem": "go"
          },
          {
            "name": "golang.org/x/sys",
            "direct": false,
            "version": "v0.45.0",
            "ecosystem": "go"
          },
          {
            "name": "golang.org/x/text",
            "direct": false,
            "version": "v0.30.0",
            "ecosystem": "go"
          },
          {
            "name": "golang.org/x/time",
            "direct": false,
            "version": "v0.6.0",
            "ecosystem": "go"
          },
          {
            "name": "google.golang.org/api",
            "direct": false,
            "version": "v0.197.0",
            "ecosystem": "go"
          },
          {
            "name": "google.golang.org/genproto/googleapis/rpc",
            "direct": false,
            "version": "v0.0.0-20240903143218-8af14fe29dc1",
            "ecosystem": "go"
          },
          {
            "name": "google.golang.org/grpc",
            "direct": false,
            "version": "v1.66.2",
            "ecosystem": "go"
          },
          {
            "name": "google.golang.org/protobuf",
            "direct": false,
            "version": "v1.34.2",
            "ecosystem": "go"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 78,
        "direct_count": 21,
        "indirect_count": 57
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 3,
        "merged_prs": 296,
        "open_issues": 8,
        "closed_ratio": 0.814,
        "closed_issues": 35,
        "closed_unmerged_prs": 35
      },
      "bus_factor": 1,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "yanmxa",
          "commits": 902,
          "avatar_url": "https://avatars.githubusercontent.com/u/19286664?v=4"
        },
        {
          "type": "User",
          "login": "hchenxa",
          "commits": 15,
          "avatar_url": "https://avatars.githubusercontent.com/u/10266685?v=4"
        },
        {
          "type": "User",
          "login": "ldpliu",
          "commits": 13,
          "avatar_url": "https://avatars.githubusercontent.com/u/56991288?v=4"
        },
        {
          "type": "User",
          "login": "zhfeng",
          "commits": 10,
          "avatar_url": "https://avatars.githubusercontent.com/u/1246139?v=4"
        },
        {
          "type": "User",
          "login": "zhujian7",
          "commits": 9,
          "avatar_url": "https://avatars.githubusercontent.com/u/36154065?v=4"
        },
        {
          "type": "User",
          "login": "wangke19",
          "commits": 7,
          "avatar_url": "https://avatars.githubusercontent.com/u/58931801?v=4"
        },
        {
          "type": "User",
          "login": "lonicerae",
          "commits": 3,
          "avatar_url": "https://avatars.githubusercontent.com/u/322491?v=4"
        },
        {
          "type": "User",
          "login": "onyx679",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/126763931?v=4"
        },
        {
          "type": "User",
          "login": "Karry2019web",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/51736839?v=4"
        },
        {
          "type": "User",
          "login": "Shaw529",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/39801161?v=4"
        }
      ],
      "contributors_sampled": 13,
      "top_contributor_share": 0.934
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "pages.yml",
        "release.yml",
        "stale.yml"
      ],
      "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": null,
            "reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "28 out of 28 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": 10,
            "reason": "all changesets reviewed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 5 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": 10,
            "reason": "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 24 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": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 3,
            "reason": "dependency not pinned by hash detected -- score normalized to 3",
            "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": 10,
            "reason": "security policy file 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": 0,
            "reason": "31 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "445f0c7a6a4ff2c716a2e508d4364ab000ac06c4",
        "ran_at": "2026-07-22T09:31:15Z",
        "aggregate_score": 5.8,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": true,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-22T06:07:11Z",
      "oldest_open_prs": [
        {
          "number": 266,
          "created_at": "2026-07-02T15:22:11Z",
          "last_comment_at": "2026-07-21T11:29:35Z",
          "last_comment_author": "san-ci"
        },
        {
          "number": 378,
          "created_at": "2026-07-22T05:12:36Z",
          "last_comment_at": "2026-07-22T05:12:54Z",
          "last_comment_author": "san-ci"
        },
        {
          "number": 380,
          "created_at": "2026-07-22T09:22:55Z",
          "last_comment_at": "2026-07-22T09:23:11Z",
          "last_comment_author": "san-ci"
        }
      ],
      "last_merged_pr_at": "2026-07-21T15:28:53Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 46,
          "created_at": "2026-05-23T00:48:01Z",
          "last_comment_at": "2026-05-24T15:53:17Z",
          "last_comment_author": "yanmxa"
        },
        {
          "number": 88,
          "created_at": "2026-06-03T10:23:47Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 156,
          "created_at": "2026-06-07T14:33:30Z",
          "last_comment_at": "2026-06-22T10:58:39Z",
          "last_comment_author": "yanmxa"
        },
        {
          "number": 209,
          "created_at": "2026-06-14T07:36:24Z",
          "last_comment_at": "2026-06-14T07:49:52Z",
          "last_comment_author": "yanmxa"
        },
        {
          "number": 297,
          "created_at": "2026-07-10T15:33:32Z",
          "last_comment_at": "2026-07-13T14:10:09Z",
          "last_comment_author": "hchenxa"
        },
        {
          "number": 309,
          "created_at": "2026-07-13T14:08:26Z",
          "last_comment_at": "2026-07-20T07:57:02Z",
          "last_comment_author": "hchenxa"
        },
        {
          "number": 310,
          "created_at": "2026-07-14T18:55:06Z",
          "last_comment_at": "2026-07-16T05:34:07Z",
          "last_comment_author": "yanmxa"
        },
        {
          "number": 314,
          "created_at": "2026-07-17T06:46:24Z",
          "last_comment_at": "2026-07-22T02:39:22Z",
          "last_comment_author": "yanmxa"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/genai-io/san",
    "host": "github.com",
    "name": "san",
    "owner": "genai-io"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 73,
      "inputs": {
        "security": 66,
        "vitality": 86,
        "community": 66,
        "governance": 63,
        "engineering": 81
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 86,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 83,
            "inputs": {
              "commits_last_year": 979,
              "human_commit_share": 0.98,
              "days_since_last_push": 0,
              "active_weeks_last_year": 28
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "28/52 weeks with commits",
                "points": 19.4,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 28
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "979 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 979
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 24 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": 100,
              "latest_release_tag": "v1.21.11",
              "releases_from_tags": false,
              "days_since_latest_release": 0,
              "mean_days_between_releases": 1.3
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "100 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 100
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~1.3 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 1.3
                    }
                  }
                ],
                "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": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 0,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 0 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "moderate",
        "name": "Community & Adoption",
        "value": 66,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 44,
            "inputs": {
              "forks": 32,
              "stars": 70,
              "watchers": 3,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "below_threshold"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "70 stars",
                "points": 29.8,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 70
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "32 forks",
                "points": 12.4,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 32
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "3 watchers",
                "points": 1.7,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "excellent",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 92,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": true,
              "has_pull_request_template": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 18,
                "status": "met",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 13.5,
                "status": "met",
                "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": 6.3,
                "status": "met",
                "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": 63,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "at_risk",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 34,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 13,
              "top_contributor_share": 0.934
            },
            "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 93% of commits",
                "points": 1.5,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 93
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "13 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 13
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 5 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "excellent",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 87,
            "inputs": {
              "merged_prs": 296,
              "open_issues": 8,
              "closed_issues": 35,
              "issue_closed_ratio": 0.814,
              "closed_unmerged_prs": 35
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "81% of issues closed",
                "points": 38.1,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 81
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "296/331 decided PRs merged",
                "points": 34.2,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 296,
                      "decided": 331
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "all changesets reviewed",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 45,
            "inputs": {
              "followers": 6,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "genai-io",
              "public_repos": 13,
              "account_age_days": 82
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "6 followers of genai-io",
                "points": 6.1,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 6,
                      "login": "genai-io"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "13 public repos, account ~0 yr old",
                "points": 8.8,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 13
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 0
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/genai-io/san"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "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 0 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "123 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 123
                    }
                  }
                ],
                "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": "good",
        "name": "Engineering Quality",
        "value": 81,
        "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": "4 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "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": "28 out of 28 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "topics": [
                "ai-agents",
                "provider-agnostic",
                "llm",
                "coding-agent",
                "agent-harness",
                "claude-code",
                "cli",
                "golang",
                "mcp",
                "terminal",
                "tui"
              ],
              "has_wiki": true,
              "homepage": "https://genai-io.github.io/san/",
              "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": "https://genai-io.github.io/san/",
                "points": 15,
                "status": "met",
                "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": "11 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 11
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 66,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Branch-Protection, Packaging. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "branch_protection",
                    "packaging"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 58,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 5.8
            },
            "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": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "28 out of 28 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": "all changesets reviewed",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 5 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": "update tool detected",
                "points": 7.5,
                "status": "met",
                "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 24 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 not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 3",
                "points": 1.5,
                "status": "partial",
                "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 detected",
                "points": 5,
                "status": "met",
                "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": "31 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "dependency_advisories",
            "band": "excellent",
            "name": "Dependency advisories",
            "note": "Excluded from scoring (no data or not applicable): Indirect dependencies free of known advisories, No advisories left outstanding. Remaining weights renormalized. Matched 78 resolved dependencies against OSV. This repository publishes no package the index resolves, so the repository dependency graph was assessed instead. That graph mixes development and test pins with shipped dependencies, so only the declared runtime dependencies are scored; transitive findings are reported as context and excluded from the score. Reachability is not analyzed.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "indirect_dependencies_free_of_known_advisories",
                    "no_advisories_left_outstanding"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              },
              {
                "code": "advisories_scope_repository",
                "params": {
                  "assessed": 78
                }
              },
              {
                "code": "advisories_repo_graph_caveat",
                "params": {}
              },
              {
                "code": "advisories_reachability",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "source": "osv",
              "advisories": 48,
              "affected_packages": 5,
              "assessed_packages": 78,
              "unassessed_packages": 0,
              "affected_by_severity": "critical 2, moderate 1, unknown 2",
              "direct_affected_packages": 0
            },
            "components": [
              {
                "key": "direct_dependencies_free_of_known_advisories",
                "name": "Direct dependencies free of known advisories",
                "detail": "no direct dependency carries a known advisory",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "no_direct_advisories",
                    "params": {}
                  }
                ],
                "max_points": 35
              },
              {
                "key": "indirect_dependencies_free_of_known_advisories",
                "name": "Indirect dependencies free of known advisories",
                "detail": "transitive set not separable from development and test dependencies in this scope",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_scope_not_separable",
                    "params": {}
                  }
                ],
                "max_points": 25
              },
              {
                "key": "no_advisories_left_outstanding",
                "name": "No advisories left outstanding",
                "detail": "no advisory carries a publication date",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_no_publication_date",
                    "params": {}
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "malicious_dependencies",
            "band": "excellent",
            "name": "Malicious dependencies",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "source": "osv",
              "meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
              "packages": [],
              "red_flag": false,
              "assessed_packages": 78,
              "malicious_packages": 0,
              "direct_malicious_packages": 0,
              "withdrawn_malicious_packages": 0,
              "installable_malicious_packages": 0
            },
            "components": [
              {
                "key": "no_dependency_reported_as_a_malicious_package",
                "name": "No dependency reported as a malicious package",
                "detail": "no dependency is reported as a malicious package",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "no_malicious_dependencies",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          },
          {
            "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": 6
            },
            "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": "excellent",
        "name": "AI Readiness",
        "value": 86,
        "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": [
                "AGENTS.md",
                "docs/packages/2-feature/agent.md"
              ],
              "agent_instruction_max_bytes": 3518
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, docs/packages/2-feature/agent.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, docs/packages/2-feature/agent.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": "98 of 98 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 98,
                      "sampled": 98
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 82,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.05,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0.02
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile"
                    }
                  }
                ],
                "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": "5 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 5,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "2 of the last 100 commits are automated dependency updates",
                "points": 8,
                "status": "met",
                "details": [
                  {
                    "code": "dependency_bot_commits",
                    "params": {
                      "count": 2,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "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": 49529,
              "source_files_sampled": 622,
              "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/622 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 622,
                      "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": [],
  "report_type": "repository",
  "generated_at": "2026-07-22T09:31:37.439685Z",
  "schema_version": "0.26.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/g/genai-io/san.svg",
  "full_name": "genai-io/san",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

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.26.0 — vollständige Methodik · Metriken-Wiki.

Wie ein einzelnes Ergebnis im Gesamtregister steht: aggregierte StatistikenGo.