Öffentliches Register
Software-GesundheitsberichtSchema 0.27.0 · Metriken 1.13.0 · 2026-07-24 05:17 UTC

roomkit-live / roomkit

Pure async Python framework for multi-channel conversations

PythonMIT★ 30 Sterne⑂ 3 Forksseit Feb. 2026Auf GitHub ansehen ↗

roomkit-live/roomkit erreicht einen Gesundheitsindex von 64 von 100 und liegt damit im Bereich Mittel. Am stärksten schneidet es bei Engineering Quality (88/100) ab, am schwächsten bei Security (43/100). Zuletzt heute aktualisiert. Ein einzelner Mitwirkender trägt den Großteil der jüngsten Arbeit.

64
gesamt / 100
Mittel

Software-Gesundheitsindex

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

64
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

RoomkitOrganisation
10 Follower9 öffentliche Reposseit Feb. 2026

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

Paket-Ökosysteme

RegistryPaketVersionDownloads / MonatVersionenZuletzt veröffentlichtTags
PyPIroomkit0.37.08.36997vor 0 Tagenaiasyncchatmulti-channelrcsroomssmsvoicewhatsapp

Metriken nach Kategorie

Vitalität

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

84Gut · 22 % des Gesamtindex
Wie die Bewertung erfolgt
36/36Push-Aktualität — letzter Push vor 0 Tagen
15.9/36Commit-Rhythmus — 23/52 Wochen mit Commits
18/18Commit-Volumen — 1.212 Commits im letzten Jahr
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Verwendete Eingangsdaten
commits_last_year1.212
human_commit_share0,95
days_since_last_push0
active_weeks_last_year23
Wie die Bewertung erfolgt
27/27Liefert Releases aus — 86 Releases veröffentlicht
36/36Release-Aktualität — letztes Release vor 0 Tagen
27/27Release-Rhythmus — ein Release etwa alle 1,2 Tage
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Verwendete Eingangsdaten
releases_count86
latest_release_tagv0.37.1
releases_from_tagsnein
days_since_latest_release0
mean_days_between_releases1,2

Community & Verbreitung

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

56Mittel · 18 % des Gesamtindex
Wie die Bewertung erfolgt
23.7/60Stars — 30 Stars
2.5/25Forks — 3 Forks
0/15Watcher — 0 Watcher
Verwendete Eingangsdaten
forks3
stars30
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Wie die Bewertung erfolgt
22.5/22.5README
22.5/22.5Lizenz — anerkannte Lizenz (MIT)
18/18CONTRIBUTING-Leitfaden
13.5/13.5Verhaltenskodex
0/7.2Issue-Vorlage
0/6.3PR-Vorlage
Verwendete Eingangsdaten
has_readmeja
has_licenseja
has_contributingja
has_issue_templatenein
has_code_of_conductja
has_pull_request_templatenein
Wie die Bewertung erfolgt
52.3/80Downloads pro Monat — 8.369 Downloads/Monat über pypi
0/20Abhängige in der Registry — von diesem Ökosystem nicht ausgewiesen
Verwendete Eingangsdaten
packagesroomkit
dependents
ecosystemspypi
total_downloads
monthly_downloads8.369
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): Abhängige in der Registry. Die verbleibenden Gewichte wurden renormalisiert.

Nachhaltigkeit & Governance

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

47Gefährdet · 24 % des Gesamtindex
Wie die Bewertung erfolgt
9/54Bus-Faktor — 1 Beitragende decken die Hälfte aller Commits ab
0/22.5Commit-Verteilung — wichtigste beitragende Person verfasste 100 % der Commits
1.4/13.5Breite der Beitragenden — 1 Beitragende
3/10OpenSSF Scorecard: Contributors — project has 1 contributing companies or organizations -- score normalized to 3
Verwendete Eingangsdaten
bus_factor1
contributors_sampled1
top_contributor_share1
Wie die Bewertung erfolgt
0/46.8Issue-Lösungsquote — keine Issues oder keine Daten
25.5/38.3PR-Annahme — 8/12 entschiedene PRs gemergt
0/15OpenSSF Scorecard: Code-Review — Found 0/29 approved changesets -- score normalized to 0
Verwendete Eingangsdaten
merged_prs8
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs4
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): Issue-Lösungsquote. Die verbleibenden Gewichte wurden renormalisiert.
Wie die Bewertung erfolgt
30/30Organisatorische Trägerschaft — im Besitz einer Organisation
0/20Verifizierte Domain
7.5/25Reichweite des Inhabers — 10 Follower von roomkit-live
8.2/25Kontohistorie — 9 öffentliche Repos, Kontoalter ca. 0 Jahre
Verwendete Eingangsdaten
followers10
owner_typeOrganization
is_verified
owner_loginroomkit-live
public_repos9
account_age_days168

Paketpflege

100Exzellent
Wie die Bewertung erfolgt
25/25Veröffentlicht & auflösbar — 1 Paket(e) auf pypi
35/35Veröffentlichungsaktualität — letzte Veröffentlichung vor 0 Tagen
20/20Versionshistorie — 97 veröffentlichte Versionen
20/20Nicht veraltet — aktiv, nicht veraltet oder zurückgezogen
Verwendete Eingangsdaten
packagesroomkit
ecosystemspypi
any_deprecatednein
min_days_since_publish0

Engineering-Qualität

Sind grundlegende Engineering- und Dokumentationspraktiken vorhanden?

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

Sicherheit

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

43Gefährdet · 16 % des Gesamtindex

Sicherheitslage

43Gefährdet
Wie die Bewertung erfolgt
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
2.5/2.5CI-Tests — 1 out of 1 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/29 approved changesets -- score normalized to 0
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
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 0 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — keine Daten
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
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 — 71 existing vulnerabilities detected
Verwendete Eingangsdaten
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate4,3
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): packaging. Die verbleibenden Gewichte wurden renormalisiert.

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.

80Gut · 0 % des Gesamtindex
Wie die Bewertung erfolgt
45/45Agentenanweisungen — AGENTS.md, CLAUDE.md
15/15Maschinenlesbare Doku (llms.txt) — llms.txt vorhanden
39.9/40Lesbare Commit-Historie — 71 von 95 menschlichen Commits benennen ihre Absicht (strukturierter Betreff oder erläuternder Text)
Verwendete Eingangsdaten
has_llms_txtja
legible_history_share0,747
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes34.706
Wie die Bewertung erfolgt
18/18Bootstrap mit einem Befehl — Makefile
22/22Automatisierte Tests
11/11Lint-/Format-Konfiguration
11/11Statische Typprüfung — src/roomkit/py.typed
10/10Reproduzierbare Umgebung — lockfile
0/10Belegte Agentenpraxis — keine von Agenten verfassten Commits unter den letzten 100
8/8Automatisierte Wartung — 5 der letzten 100 Commits sind automatisierte Abhängigkeits-Updates
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Verwendete Eingangsdaten
has_nixnein
has_testsja
lockfilesuv.lock
has_dockerfilenein
typed_languagenein
bootstrap_filesMakefile
has_devcontainernein
has_linter_configja
typecheck_configssrc/roomkit/py.typed
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0,05
Wie die Bewertung erfolgt
27/45Typprüfbarer Code — Python mit Typprüfungs-Konfiguration (src/roomkit/py.typed)
54.8/55Handhabbare Dateigrößen — 3/1.060 Quelldateien über 60 KB
Verwendete Eingangsdaten
primary_languagePython
largest_source_bytes67.638
source_files_sampled1.060
oversized_source_files3
Wie die Bewertung erfolgt
0/40API-Schema (OpenAPI/GraphQL/proto)
0/20MCP-Server
40/40Lauffähige Beispiele — examples
Verwendete Eingangsdaten
example_dirsexamples
has_mcp_signalnein
api_schema_files

Eckdaten

30GitHub-Sterne
1Mitwirkende
1.212Commits, letzte 12 Monate
0Tage seit letztem Push
86Releases
1Bus-Faktor
0offene Issues
PyPIPaket-Ökosysteme

Warnungen zur Datenerhebung

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository
  • deps.dev does not index pypi:roomkit@0.37.0; advisories assessed against the repository dependency graph instead

Weitere Details

Stern- und Fork-Verlauf 0 ★ / 3 ⇿
0Sterne
3Forks
69Releases

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.

12233312026-022026-042026-07
Major 0Minor 16Patch 37
OpenSSF Scorecard 4.3 / 10
4.3Gesamtwert

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-24 05:17 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
10CI-Tests1 out of 1 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/29 approved changesets -- score normalized to 0
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
k. A.Packagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
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
0Vulnerabilities71 existing vulnerabilities detected
Direkte Abhängigkeiten 1
RegistryPaketVersionsvorgabeManifest
PyPIpydantic>=2.9pyproject.toml
Alle Abhängigkeiten nicht erhoben

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

JSON-Rohbericht maschinenlesbar
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 12260,
      "has_wiki": false,
      "homepage": "https://www.roomkit.live",
      "languages": {
        "Shell": 11282,
        "Python": 7479794,
        "Makefile": 1080
      },
      "pushed_at": "2026-07-24T05:16:54Z",
      "created_at": "2026-02-05T23:44:45Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-24T05:15:55Z",
      "description": "Pure async Python framework for multi-channel conversations",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Python",
      "significant_languages": [
        "Python"
      ]
    },
    "owner": {
      "blog": "https://www.roomkit.live",
      "name": "Roomkit",
      "type": "Organization",
      "login": "roomkit-live",
      "company": null,
      "location": "Canada",
      "followers": 10,
      "avatar_url": "https://avatars.githubusercontent.com/u/259731342?v=4",
      "created_at": "2026-02-05T22:52:24Z",
      "is_verified": null,
      "public_repos": 9,
      "account_age_days": 168
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.37.1",
          "kind": "patch",
          "published_at": "2026-07-24T05:15:44Z"
        },
        {
          "tag": "v0.37.0",
          "kind": "minor",
          "published_at": "2026-07-24T04:53:50Z"
        },
        {
          "tag": "v0.36.0",
          "kind": "minor",
          "published_at": "2026-07-21T04:39:21Z"
        },
        {
          "tag": "v0.35.0",
          "kind": "minor",
          "published_at": "2026-07-20T22:08:48Z"
        },
        {
          "tag": "v0.34.0",
          "kind": "minor",
          "published_at": "2026-07-20T16:16:15Z"
        },
        {
          "tag": "v0.33.0",
          "kind": "minor",
          "published_at": "2026-07-20T15:51:38Z"
        },
        {
          "tag": "v0.32.0",
          "kind": "minor",
          "published_at": "2026-07-19T14:24:53Z"
        },
        {
          "tag": "v0.31.0",
          "kind": "minor",
          "published_at": "2026-07-19T13:10:18Z"
        },
        {
          "tag": "v0.30.0",
          "kind": "minor",
          "published_at": "2026-07-16T20:24:21Z"
        },
        {
          "tag": "v0.29.0",
          "kind": "minor",
          "published_at": "2026-07-13T19:39:36Z"
        },
        {
          "tag": "v0.28.0",
          "kind": "minor",
          "published_at": "2026-07-11T21:41:53Z"
        },
        {
          "tag": "v0.26.0",
          "kind": "minor",
          "published_at": "2026-07-10T16:23:24Z"
        },
        {
          "tag": "v0.25.0",
          "kind": "minor",
          "published_at": "2026-07-10T02:01:18Z"
        },
        {
          "tag": "v0.24.0",
          "kind": "minor",
          "published_at": "2026-07-08T04:41:36Z"
        },
        {
          "tag": "v0.23.0",
          "kind": "minor",
          "published_at": "2026-07-07T03:11:48Z"
        },
        {
          "tag": "v0.22.0",
          "kind": "minor",
          "published_at": "2026-07-06T18:59:04Z"
        },
        {
          "tag": "v0.20.0",
          "kind": "minor",
          "published_at": "2026-07-03T15:23:02Z"
        },
        {
          "tag": "v0.19.0",
          "kind": "minor",
          "published_at": "2026-06-26T20:52:57Z"
        },
        {
          "tag": "v0.18.0",
          "kind": "minor",
          "published_at": "2026-06-21T20:19:07Z"
        },
        {
          "tag": "v0.17.2",
          "kind": "patch",
          "published_at": "2026-06-21T03:26:08Z"
        },
        {
          "tag": "v0.17.1",
          "kind": "patch",
          "published_at": "2026-06-21T01:50:25Z"
        },
        {
          "tag": "v0.17.0",
          "kind": "minor",
          "published_at": "2026-06-20T23:46:39Z"
        },
        {
          "tag": "v0.16.0",
          "kind": "minor",
          "published_at": "2026-06-20T03:12:04Z"
        },
        {
          "tag": "v0.15.0",
          "kind": "minor",
          "published_at": "2026-06-18T19:24:42Z"
        },
        {
          "tag": "v0.14.0",
          "kind": "minor",
          "published_at": "2026-06-18T14:38:21Z"
        },
        {
          "tag": "v0.13.0",
          "kind": "minor",
          "published_at": "2026-06-18T01:49:42Z"
        },
        {
          "tag": "v0.12.0",
          "kind": "minor",
          "published_at": "2026-06-17T11:54:19Z"
        },
        {
          "tag": "v0.11.0",
          "kind": "minor",
          "published_at": "2026-06-14T12:06:05Z"
        },
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2026-06-11T15:02:47Z"
        },
        {
          "tag": "v0.9.1",
          "kind": "patch",
          "published_at": "2026-06-11T11:43:31Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-06-10T20:53:08Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2026-06-09T22:33:06Z"
        },
        {
          "tag": "v0.7.2",
          "kind": "patch",
          "published_at": "2026-06-07T01:23:12Z"
        },
        {
          "tag": "v0.7.1",
          "kind": "patch",
          "published_at": "2026-05-22T12:52:08Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2026-05-15T15:48:18Z"
        },
        {
          "tag": "v0.7.0a17",
          "kind": "other",
          "published_at": "2026-04-30T21:28:10Z"
        },
        {
          "tag": "v0.7.0a16",
          "kind": "other",
          "published_at": "2026-04-23T14:06:32Z"
        },
        {
          "tag": "v0.7.0a15",
          "kind": "other",
          "published_at": "2026-04-23T11:35:56Z"
        },
        {
          "tag": "v0.7.0a14",
          "kind": "other",
          "published_at": "2026-04-17T21:43:41Z"
        },
        {
          "tag": "v0.7.0a13",
          "kind": "other",
          "published_at": "2026-04-17T01:31:05Z"
        },
        {
          "tag": "v0.7.0a12",
          "kind": "other",
          "published_at": "2026-04-08T18:09:05Z"
        },
        {
          "tag": "v0.7.0a11",
          "kind": "other",
          "published_at": "2026-04-04T20:58:01Z"
        },
        {
          "tag": "v0.7.0a10",
          "kind": "other",
          "published_at": "2026-04-03T20:35:13Z"
        },
        {
          "tag": "v0.7.0a8",
          "kind": "other",
          "published_at": "2026-04-01T20:26:47Z"
        },
        {
          "tag": "v0.7.0a7",
          "kind": "other",
          "published_at": "2026-03-28T02:25:56Z"
        },
        {
          "tag": "v0.7.0a6",
          "kind": "other",
          "published_at": "2026-03-28T01:51:37Z"
        },
        {
          "tag": "v0.7.0a5",
          "kind": "other",
          "published_at": "2026-03-27T00:56:42Z"
        },
        {
          "tag": "v0.7.0a4",
          "kind": "other",
          "published_at": "2026-03-26T00:58:29Z"
        },
        {
          "tag": "v0.7.0a3",
          "kind": "other",
          "published_at": "2026-03-25T03:00:07Z"
        },
        {
          "tag": "v0.7.0a2",
          "kind": "other",
          "published_at": "2026-03-24T20:56:17Z"
        },
        {
          "tag": "v0.7.0a1",
          "kind": "other",
          "published_at": "2026-03-24T19:08:15Z"
        },
        {
          "tag": "v0.6.13",
          "kind": "patch",
          "published_at": "2026-03-05T21:09:07Z"
        },
        {
          "tag": "v0.6.12",
          "kind": "patch",
          "published_at": "2026-03-05T20:03:38Z"
        },
        {
          "tag": "v0.6.11",
          "kind": "patch",
          "published_at": "2026-03-04T03:53:47Z"
        },
        {
          "tag": "v0.6.10",
          "kind": "patch",
          "published_at": "2026-03-03T17:54:23Z"
        },
        {
          "tag": "v0.6.9",
          "kind": "patch",
          "published_at": "2026-03-02T22:39:52Z"
        },
        {
          "tag": "v0.6.8",
          "kind": "patch",
          "published_at": "2026-03-02T18:07:19Z"
        },
        {
          "tag": "v0.6.7",
          "kind": "patch",
          "published_at": "2026-03-01T03:51:34Z"
        },
        {
          "tag": "v0.6.6",
          "kind": "patch",
          "published_at": "2026-02-28T19:52:35Z"
        },
        {
          "tag": "v0.6.5",
          "kind": "patch",
          "published_at": "2026-02-28T19:41:44Z"
        },
        {
          "tag": "v0.6.4",
          "kind": "patch",
          "published_at": "2026-02-28T16:29:02Z"
        },
        {
          "tag": "v0.6.3",
          "kind": "patch",
          "published_at": "2026-02-28T00:49:16Z"
        },
        {
          "tag": "v0.6.1",
          "kind": "patch",
          "published_at": "2026-02-26T14:38:47Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2026-02-25T04:37:28Z"
        },
        {
          "tag": "v0.5.3",
          "kind": "patch",
          "published_at": "2026-02-17T19:08:57Z"
        },
        {
          "tag": "v0.5.2",
          "kind": "patch",
          "published_at": "2026-02-17T04:31:17Z"
        },
        {
          "tag": "v0.5.1",
          "kind": "patch",
          "published_at": "2026-02-17T03:04:57Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-02-16T04:51:55Z"
        },
        {
          "tag": "v0.4.18",
          "kind": "patch",
          "published_at": "2026-02-14T01:05:22Z"
        },
        {
          "tag": "v0.4.17",
          "kind": "patch",
          "published_at": "2026-02-13T06:27:14Z"
        },
        {
          "tag": "v0.4.16",
          "kind": "patch",
          "published_at": "2026-02-13T04:25:50Z"
        },
        {
          "tag": "v0.4.15",
          "kind": "patch",
          "published_at": "2026-02-13T03:18:06Z"
        },
        {
          "tag": "v0.4.14",
          "kind": "patch",
          "published_at": "2026-02-12T03:23:02Z"
        },
        {
          "tag": "v0.4.13",
          "kind": "patch",
          "published_at": "2026-02-11T23:26:33Z"
        },
        {
          "tag": "v0.4.12",
          "kind": "patch",
          "published_at": "2026-02-11T18:06:16Z"
        },
        {
          "tag": "v0.4.11",
          "kind": "patch",
          "published_at": "2026-02-11T18:00:03Z"
        },
        {
          "tag": "v0.4.10",
          "kind": "patch",
          "published_at": "2026-02-11T17:23:18Z"
        },
        {
          "tag": "v0.4.9",
          "kind": "patch",
          "published_at": "2026-02-11T03:23:52Z"
        },
        {
          "tag": "v0.4.8",
          "kind": "patch",
          "published_at": "2026-02-10T20:58:31Z"
        },
        {
          "tag": "v0.4.7",
          "kind": "patch",
          "published_at": "2026-02-10T17:59:02Z"
        },
        {
          "tag": "v0.4.6",
          "kind": "patch",
          "published_at": "2026-02-10T15:57:17Z"
        },
        {
          "tag": "v0.4.5",
          "kind": "patch",
          "published_at": "2026-02-10T05:43:54Z"
        },
        {
          "tag": "v0.4.4",
          "kind": "patch",
          "published_at": "2026-02-09T06:37:40Z"
        },
        {
          "tag": "v0.4.3",
          "kind": "patch",
          "published_at": "2026-02-08T17:42:23Z"
        },
        {
          "tag": "v0.4.2",
          "kind": "patch",
          "published_at": "2026-02-08T17:04:50Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-02-07T19:10:39Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "b458ed19d628afc812c986f7c3fe41d4cee8bee5",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.38.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T05:15:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "32a0bd83de1100fdb5b27f35ec855fb230fa6222",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.37.1",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T05:15:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5bf3028eb0b3002bd54bdc560ef3f15891fdc40",
          "body": "The huddle backend drives HuddleClient with paced=False so RoomKit's\nOutboundAudioPacer owns the outbound clock; that argument only exists\nin buzzkit 0.1.4. With the 0.37.0 floor (>=0.1.3) a huddle session\nfails with a TypeError on connect. 0.1.4 also moves WebSocket I/O to\na dedicated thread and drops late frames instead of bursting them.\n\nSupersedes dependabot PR #12 (lockfile-only bump).",
          "is_bot": false,
          "headline": "fix(buzz): require buzzkit>=0.1.4 — BuzzHuddleBackend needs paced=False",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T05:11:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1a4e5081d90520ca06157bc755cf617d929728c3",
          "body": "…solvable\n\nav>=18 (aiortc requires av<18), opentelemetry-api/sdk>=1.40 (mistralai\npins semantic-conventions<0.61), and transformers (version dictated by\nthe TTS extras' exact pins). Attempting these fails every weekly run\nwith dependency_file_not_resolvable while the lockfile itself resolves\nfine.",
          "is_bot": false,
          "headline": "ci(dependabot): ignore update candidates that upstream pins make unre…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T05:00:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f8d9b3ea47513792085953f8255cbfc90ddd882d",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.38.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T04:53:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7aa023f4d05cdd8155ec35c52b9b94851a50f097",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.37.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T04:53:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5a42ebd27b14ec732a0bd0c4ee8615630b3681c0",
          "body": "…any workflow",
          "is_bot": false,
          "headline": "fix(release): CI guard checks the CI workflow, not the latest run of …",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T04:52:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "51f63720a51205a900058c46a9ace6d3c79eb566",
          "body": null,
          "is_bot": false,
          "headline": "docs: promote changelog for 0.37.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T04:36:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "05db5d0ea8140d7f8e4e229af6f6003302304b99",
          "body": "Update the grouped Python dependencies while keeping the WebRTC stack on a NumPy version supported by numba. Fix ACP prompt completion so trailing session updates are drained before the stream closes, and extend CI to install the real fastrtc dependency set.",
          "is_bot": true,
          "headline": "build(deps): update Python dependencies and harden ACP/WebRTC CI (#10)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-24T04:32:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "87f70a5e9763eb8dfc3255b7ed725bfc545cfa57",
          "body": null,
          "is_bot": false,
          "headline": "docs: prepare changelog for next release",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T03:57:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "21cf6568a52e79a9b53c47698026c848fe51aeb2",
          "body": null,
          "is_bot": false,
          "headline": "feat: add ACP channel and Claude CLI example",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T03:52:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d42eb4b95d41904d378c3fab573b1f8350adb85",
          "body": "BuzzHuddleWatcher owns watching/dialing/rejoin and PipelineDebugTaps\ncovers audio-stage capture, so the example drops its custom tap backend,\nparser, and bridge plumbing — what is left is the promise: env, voice\nchannel, watcher, run.",
          "is_bot": false,
          "headline": "refactor(examples): buzz voice agent shrinks to framework wiring",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T02:22:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "653a800704a721a5fbc16b76a9d162fe70471d2d",
          "body": "…n the framework\n\nAn application now only builds its voice channel; the watcher subscribes\nto huddle announcements (kind 48100) through a BuzzRelaySource attached\nwith auto_restart, dials each huddle (client_factory injectable, creates\nclients with paced=False), bridges it, rejoins on connection los\n[…]\nnever delivered outbound through the Buzz channel. Also:\nhuddle_announcement_parser + KIND_HUDDLE_STARTED in sources.buzz, and a\npublic transport property on RealtimeVoiceChannel (mirror of provider).",
          "is_bot": false,
          "headline": "feat(voice): BuzzHuddleWatcher — the announcement-to-call lifecycle i…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T02:22:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "711dbda71ff416629bd3bb05ad52695606a902ac",
          "body": "Replace the hand-rolled watch/reconnect/hangup plumbing with RoomKit\nidioms: a BuzzRelaySource subscribed to kind 48100 emits huddle\nannouncements as room events (auto_restart reconnects to the relay), an\nAFTER_BROADCAST hook dials the huddle, and the transport ends the\nsession itself (end_when_alone / socket drop). The example only reads\nbuzz_end_reason to choose between rejoining and waiting for the next\nhuddle.",
          "is_bot": false,
          "headline": "refactor(examples): buzz voice agent goes through the framework",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T01:35:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bc26e18bff13da9775836e1d251f1c58d915dcae",
          "body": "…zzRelaySource\n\nThe relay keeps a huddle alive while any member is connected — the agent\nincluded — so ending the call when the last remote peer leaves is\ntransport policy: the backend now watches the roster (second events()\nsubscriber) and fires the disconnect path with\nsession.metadata[\"buzz_end_r\n[…]\nactly once per session; deliberate disconnects fire no callback.\nBuzzRelaySource gains a kinds passthrough so a source can subscribe to\nmore than chat messages (e.g. huddle announcements, kind 48100).",
          "is_bot": false,
          "headline": "feat(voice): end_when_alone on BuzzHuddleBackend + kinds filter on Bu…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T01:35:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dcdd21a500466cecd5fdebe0d4645f46b76357ed",
          "body": "…ive relay restarts\n\nThe relay keeps a huddle alive while any member is connected, the agent\nincluded, so the agent must hang up itself when the last human leaves\n(with a grace period for huddles nobody joined yet) — otherwise the\nhuddle never ends and the watch loop never moves on. A dropped audio\n\n[…]\n same huddle with backoff, and a rejected rejoin means the huddle is\nreally over. The announcement subscription also ends silently when the\nrelay restarts, so watch mode reconnects instead of exiting.",
          "is_bot": false,
          "headline": "fix(examples): buzz agent — hang up when alone, rejoin on drops, surv…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T01:23:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5e06dd50119c4f7ccebffccbc50a1b4262fc45b3",
          "body": "…ahead\n\nWith fill_with_silence_when_idle, any >20ms provider lull mid-response\ninserted a silence frame even while the pacer still had jitter headroom,\npermanently displacing the rest of the response — heard as chopped\nspeech with bursty providers. Fill now only fires once the pacer has\nactually fallen behind wall-clock.",
          "is_bot": false,
          "headline": "fix(voice): pacer silence fill must not splice into a response while …",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T00:22:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1d74fa1e285afa6c6015638c8c4792a75a27e625",
          "body": "Bridge a connected buzzkit.HuddleClient to the realtime voice pipeline:\n48 kHz huddle wire resampled to/from the provider's rates with a shared\nsoxr streaming resampler (also adopted by the Twilio backend), outbound\ntiming owned by OutboundAudioPacer, silence fill toward the provider so\nserver VAD sees continuous audio. Ships a Gemini Live example with an\noptional BUZZ_TAP_DIR debug tap that records every hop of the outbound\naudio path. New extra: roomkit[buzz].",
          "is_bot": false,
          "headline": "feat(voice): BuzzHuddleBackend — Opus voice transport over Buzz huddles",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-24T00:21:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d7be03c47600680d0c4f2fd8f948c826b2206112",
          "body": "- BuzzConfig.announce_presence (default True): BuzzRelaySource publishes a\n  kind-20001 'online' presence on connect and heartbeats within its TTL, so the\n  agent shows online in Buzz while running\n- BuzzConfig.auth_tag: optional NIP-OA owner-attestation tag, passed to the\n  BuzzClient and injected into the NIP-42 AUTH event\n- Require buzzkit>=0.1.2",
          "is_bot": false,
          "headline": "feat(channels): Buzz presence heartbeat + NIP-OA auth_tag",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-23T03:46:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a150994a798e6293e7f39db4ae00f8f31f11f6f8",
          "body": "…und publish\n\nsend_event now accepts an optional idempotency_key and sets it on the RoomEvent.\nThe locked pipeline already de-duplicates on it (the in-lock check_idempotency +\nthe unique events(room_id, idempotency_key) index), and send_event traverses\nthat same pipeline — it just had no way to carr\n[…]\ncate, so no second row and no re-broadcast. Default None keeps\nthe prior behaviour, matching inbound events that carry no key.\n\nTest: TestIdempotency::test_send_event_idempotency_key_dedupes_a_resend.",
          "is_bot": false,
          "headline": "feat(framework): idempotency_key on send_event for at-most-once outbo…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-23T03:38:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "99f58677144de623ad870027a3cb99bcc3b5d134",
          "body": "- BuzzConfig.auto_join (default True); BuzzRelaySource self-joins the channel\n  (NIP-29 kind 9000, role=bot) on connect via buzzkit.join_channel, so the\n  agent's messages reach other members and it resolves in mention autocomplete\n- Require buzzkit>=0.1.1 (adds join_channel + the nostr self-tag fix)\n- Type the optional buzzkit import as Any via TYPE_CHECKING so type-checking is\n  stable whether or not the compiled dep is resolvable",
          "is_bot": false,
          "headline": "feat(channels): Buzz auto-join — agent self-joins its channel",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-23T03:05:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cc60bb83edb9943322b6c896653f3fdf826ade7e",
          "body": "Source + provider pair (mirrors Discord) bridging a Buzz/Nostr relay channel:\n- BuzzRelaySource wraps buzzkit.BuzzClient (NIP-42 auth + real-time subscribe)\n- BuzzProvider publishes outbound over the HTTP bridge, reusing the source client\n- ChannelType.BUZZ, BuzzChannel factory, config/base/relay/mo\n[…]\nt added as an isolated optional extra (roomkit[buzz]); core stays pure Python\n- Tests (parser + provider + inbound integration) and an echo-bot example\n\nLive-validated against a hosted Buzz community.",
          "is_bot": false,
          "headline": "feat(channels): add Buzz (Nostr relay) transport channel via buzzkit",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-23T02:30:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "725531033d36914446ecc7d7a4e7ab74708f0c0a",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.37.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-21T04:39:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8cfeb679fbb573b4e36227d0da56bc4aa7797ca7",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.36.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-21T04:39:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6c5e0e776c991e84a8219c69528681b75b0c2126",
          "body": "A muted channel's non-streaming response_events were suppressed in\nbroadcast(), but a streaming response was captured into\nresult.streaming_responses and returned *before* the mute check — so a\nmuted streaming intelligence channel still produced a reply.\n\nThis was latent while send_event dropped str\n[…]\n mirroring the response_events suppression and the RFC\n'muting silences the voice, not the brain'. Regression test covers the\nmuted (suppressed, generator never started) and unmuted (delivered)\ncases.",
          "is_bot": false,
          "headline": "fix(router): muting silences a channel's streaming voice too",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-21T03:50:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "22e148fd2b9751e81836f6560638b532ac1eaabc",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.36.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T22:08:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "463131cf1566931f8696fe1bc451b3bbfc7166ff",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.35.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T22:08:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "90e4cb25a74c206578c079e68a94bc7c60cc36f9",
          "body": "A directly-injected event that woke a streaming intelligence channel had\nits response generated and then silently dropped: send_event ran the\nlocked pipeline but omitted the post-lock streaming-response drain the\ninbound path performs, so broadcast_result.streaming_responses was\ncollected and never \n[…]\n lock, exactly like process_inbound. Non-streaming providers were\nunaffected; injections that don't wake an agent are a no-op.\n\nPromotes Unreleased (this + regenerate/voice error surfacing) to 0.35.0.",
          "is_bot": false,
          "headline": "fix(framework): send_event consumes streaming AI responses (0.35.0)",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T22:05:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "30709ee5eec52d82397c5a52be924647b2fed14d",
          "body": "- regenerate_response fires ON_ERROR for a non-streaming intelligence\n  failure (parity with the inbound path); the streaming path already\n  fires its own, so they never double up.\n- _voice_tts: a provider without synthesize_stream emits tts_error, not\n  only an ERROR log.\n- _voice_stt: a continuous\n[…]\nor like the\n  VAD twin.\n- deepgram: transcribe_stream raises on the SDK on_error callback so the\n  consumer marks the stream failed (state.error) and reconnects instead\n  of seeing a clean, empty end.",
          "is_bot": false,
          "headline": "fix(regenerate,voice): surface failures via ON_ERROR / error events",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T21:53:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "567392457b7fcadf8a024bb0d24a0041fc1f1198",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.35.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T16:16:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8d137c48e1c965bf24b6935da4d1b7aedb7c5f67",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.34.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T16:16:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e0fce5db921006f7c9de96464388e034f47e5949",
          "body": "When there is no streaming target, the failure is returned on\nInboundResult.error to a one-shot programmatic caller that logs it\nitself; the framework's own WARNING just duplicated the caller's line\nfor the same incident. A ProviderError on that headless path now logs at\nDEBUG. With a streaming target (interactive) the framework WARNING is\nunchanged, and unexpected errors keep their traceback.",
          "is_bot": false,
          "headline": "fix(inbound): log a headless turn failure at DEBUG, not WARNING",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T16:12:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0a7945b56a76c85dde1b087fb2938effa99fd56a",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.34.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T15:51:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "27ee837f4c102f3f7d8fd9b6fa2c55e874905b85",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.33.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T15:51:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b160c93ede7db0ad16b50e2a7b3ab2624d1b3437",
          "body": "…ndResult.error\n\nComplete the InboundResult.error contract symmetrically. The streaming\npath already returned the failure on the result; the non-streaming\ngeneration path and regenerate_response were left with the same hole\nthat caused the original symptom — ON_ERROR fired, but process_inbound /\nreg\n[…]\nng broadcast error too.\n- _ai_generation: log a transient ProviderError as WARNING, no stack.\n\nThe non-streaming ON_ERROR card was already correct; regenerate's\nnon-streaming card remains a follow-up.",
          "is_bot": false,
          "headline": "feat(broadcast): surface non-streaming + regenerate failures on Inbou…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T14:32:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fc3ba0207f3cc339141f641017e62df58217e582",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): promote Unreleased to 0.33.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T13:53:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0e3e6b0cc58b450d8300687e0e1b4ee175e8b2e1",
          "body": "A failure while consuming an intelligence channel's streaming response\n(provider/transport error, context overflow) fired ON_ERROR and then\nvanished: process_inbound returned a result with no signal, so a headless\none-shot caller with no streaming target saw an empty response instead of\nthe error.\n\n\n[…]\nrror-card behaviour is unchanged. A ProviderError — an\nexpected transient, now returned to the caller — is logged as one WARNING\nline without a traceback; any other exception keeps its full traceback.",
          "is_bot": false,
          "headline": "feat(inbound): return response-stream failures on InboundResult.error",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-20T13:50:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "697357dbe3daf30d9b3c309a8fc634e28bb3eddf",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.33.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-19T14:24:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aeba56e37c7854e987b0bf96e1e1ea812b900df6",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.32.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-19T14:24:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "67c30daefd358314d0f107657c4573ef7ecfae05",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): promote Unreleased to 0.32.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-19T14:20:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9f97141232d978f08f3e894c3b6c4ed9f206c8a3",
          "body": "update_room is a full-row read-modify-write: a caller holding a stale\nRoom silently clobbers concurrent metadata patches and regresses the\nevent_count/latest_index/timers counters maintained by commit_event.\npatch_room_metadata(room_id, patch, *, unset=()) touches only the keys\nit is given — documented non-atomic default on the ABC, single\n(metadata - unset) || patch JSONB update on the Postgres store.",
          "is_bot": false,
          "headline": "feat(store): atomic patch_room_metadata API",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-19T14:14:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "75b1df575b196a7004f9cc6a6ba684a38d1d4161",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.32.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-19T13:10:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bca627cf96769128c791f9df1f2df7218c131f0d",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.31.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-19T13:10:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e6af918acace9320565c22d5c53faf7fee68ca32",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): promote Unreleased to 0.31.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-19T05:33:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eab5641ae750d5734c84db4208f8d0378409e90c",
          "body": "…T_DELETED hooks\n\nNew EventOpsMixin exposes host-owned update_event()/delete_event() on\nRoomKit: mutations run under the room lock, authorization stays with the\ncaller, and the new HookTrigger.ON_EVENT_UPDATED / ON_EVENT_DELETED fire\nafter the lock is released. The store gains delete_event() (hard d\n[…]\ns it silently dropped.\nThe RFC §10.3 inbound EDIT/DELETE path fires the same triggers through\nthe generalized deferred async-hook sink, so observers see every\nstored-state change regardless of origin.",
          "is_bot": false,
          "headline": "feat(events): direct update/delete APIs with ON_EVENT_UPDATED/ON_EVEN…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-19T05:08:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "20076b7bd51968662693572dfaadaf753b376fdc",
          "body": "* build(deps): bump the python-deps group with 35 updates\n\n---\nupdated-dependencies:\n- dependency-name: pydantic\n  dependency-version: 2.13.4\n  dependency-type: direct:production\n  update-type: version-update:semver-minor\n  dependency-group: python-deps\n- dependency-name: anthropic\n  dependency-vers\n[…]\n---\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>\nCo-authored-by: Sylvain Boily <sylvainboilydroid@gmail.com>",
          "is_bot": true,
          "headline": "build(deps): bump the python-deps group with 35 updates (#7)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-17T13:03:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d66ffebc72bc5df8d6426b310341b068a2bda8b9",
          "body": "Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 4 to 7.\n- [Release notes](https://github.com/astral-sh/setup-uv/releases)\n- [Commits](https://github.com/astral-sh/setup-uv/compare/v4...v7)\n\n---\nupdated-dependencies:\n- dependency-name: astral-sh/setup-uv\n  dependency-version: '\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": "build(deps): bump astral-sh/setup-uv from 4 to 7 (#6)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-17T12:59:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2e77c14da2d815a6295c4ed8bc4281f64cefe09e",
          "body": "Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 7.\n- [Release notes](https://github.com/actions/checkout/releases)\n- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/actions/checkout/compare/v4...v7)\n\n---\nupdated-dependenc\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": "build(deps): bump actions/checkout from 4 to 7 (#4)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-17T12:59:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "51d90f10d6a56c8a715bb9f735679ab7a5c3d236",
          "body": "Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.\n- [Release notes](https://github.com/actions/upload-artifact/releases)\n- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)\n\n---\nupdated-dependencies:\n- dependency-name: actions/upload-artifac\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": "build(deps): bump actions/upload-artifact from 4 to 7 (#5)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-17T12:47:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "60e77050b50b4960a431737f27d9daee01358fa7",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.31.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-16T20:24:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f45391293182c862fec50c0cdb2fbe32e7844605",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.30.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-16T20:24:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bbd924bf87b2111b88d56e77948bea648a3122cf",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): promote Unreleased to 0.30.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-16T20:19:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f4eace66130b1b90bbabf7c148192ad764b7a803",
          "body": "Follow-up to the (parent_event_id, index) change: reusing the name\nidx_events_parent meant init()'s CREATE INDEX IF NOT EXISTS no-op'd against the\nold single-column index, so only fresh databases got the composite.\n\nShip the composite under a new name, idx_events_parent_index, so init() creates\nit a\n[…]\nhat predate it, since init() never drops.\n\nTests: schema pins the composite name/columns and that the single-column index\nis not re-created; the migration drops only when present and no-ops otherwise.",
          "is_bot": false,
          "headline": "fix(store): make the composite thread index reach existing databases",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-16T20:16:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a9e6a4d80a2fc98eacc8b7824629c3361a51ae81",
          "body": "Thread-reply pagination filters events by parent_event_id then reads forward\nORDER BY index. The single-column idx_events_parent forced a sort of the whole\nthread on every page; widening it to (parent_event_id, index) returns the page\nalready ordered. The leading column still serves plain parent_event_id lookups,\nso no existing query loses its index.",
          "is_bot": false,
          "headline": "perf(store): index thread replies on (parent_event_id, index)",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-16T18:50:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "49d948cd4f3228c8d1bd49566f72db67b991fbad",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.30.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T19:39:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2b57baa3a6f4a9cca0b0c5698ea0e2b0161712f7",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.29.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T19:39:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b455ace2ce9fa698a8dcda93d3b5c9aed15aa33b",
          "body": null,
          "is_bot": false,
          "headline": "docs(changelog): promote Unreleased to 0.29.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T19:37:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ea61d5e71853692a7376ba13ec680a885d6df2bc",
          "body": "… shortcut\n\nThe \"already released, just re-push\" shortcut read the version from the worktree\n_version.py. If the dev-cycle commit itself failed (the bump staged but not\ncommitted), the worktree already showed the .dev version, so a re-run matched\nthe shortcut, pushed, and exited — orphaning the staged bump. It now reads the\nversion from HEAD: when the dev-cycle commit failed, HEAD is still the release\ncommit (not .dev), so the run falls through and re-runs to finish the commit.",
          "is_bot": false,
          "headline": "chore(release): read HEAD, not the worktree, for the dev-cycle resume…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T19:26:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d98aa702b5772d86fe0d13304b15490dedfbabf9",
          "body": "Three residual issues from the commit_event unification: some events reached the\ntimeline PENDING, and a reentry's injection was ordered before its cause.\n\n- Injected events (_deliver_injected_events) were committed with their default\n  PENDING status; they are delivered timeline events and now comm\n[…]\nen its injections are\n  delivered — the cause takes the lower index, mirroring the main path where the\n  event commits before broadcast.\n\nAdds test_reentry_injection_commits_delivered_after_its_cause.",
          "is_bot": false,
          "headline": "fix(pipeline): commit injected/child events DELIVERED, in causal order",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T19:26:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a65b1357048f70b2cee14a9596aed7f4e299b927",
          "body": "The PyPI existence check aborted every re-run once the version was on PyPI,\nblocking two legitimate resumes: uploading the second artifact after the first\nlanded, and finishing the dev-cycle commit/push after a successful publish.\n\n- A local tag v${VERSION} now distinguishes a resume from a fresh re\n[…]\n\n- An early exit detects a fully released version whose next dev cycle was opened\n  (tree on a .dev version + tag present) and just re-pushes instead of aborting.\n- The dev-cycle commit is idempotent.",
          "is_bot": false,
          "headline": "chore(release): resume after a partial or complete PyPI publish",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T19:09:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3b77b1bf3b75617ca4959212dce3a595fc3bbbd3",
          "body": "The prior change made the inbound path atomic but left four writers still\nbypassing commit_event, so the timeline and the room counters could still\ndiverge (event_count / latest_index off, events stuck PENDING):\n\n- regenerate.py: the regenerated response was stored PENDING via\n  add_event_auto_index\n[…]\n declares _commit_event on the RegenerateMixin for the type\nchecker. Task tests that mocked/asserted add_event_auto_index now use\ncommit_event; adds regenerate + greeting consistency regression tests.",
          "is_bot": false,
          "headline": "fix(pipeline): route the last timeline writes through commit_event",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T19:09:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fdbd6ef9d39da7313f31788f7b2ad75b0a6002b0",
          "body": "Two resume hazards remained after moving the SBOM ahead of the Git mutations:\n\n- The version bump (sed on _version.py / test_public_api.py) runs before the\n  build, so a failure there left the tree dirty and a re-run aborted at the\n  clean-tree check. The check now tolerates uncommitted changes to e\n[…]\n already existed, so a re-run after a\n  failed PyPI upload (Release created, publish failed) could not reach the\n  retryable publish step. Creating the Release is now skipped when it already\n  exists.",
          "is_bot": false,
          "headline": "chore(release): make release.sh re-runnable end to end",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T18:43:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "92f512e74ebab5c650005ba5725faa596d29f86a",
          "body": "…est_index\n\nFollow-up to the atomic-commit work: the trigger message committed atomically,\nbut AI reentries and streamed segments did not — the review reproduced the\ndivergence (event_count=4, latest_index=2, a PENDING AI reply at index 3), which\nRFC §10.1 step 13 forbids.\n\nEvery path that adds to a\n[…]\n/test_commit_atomicity.py (reentry DELIVERED + counter consistency,\nchain-depth-blocked consistency, policy no-phantom, streaming DELIVERED) and a\nreal-Postgres end-to-end AI-reentry consistency test.",
          "is_bot": false,
          "headline": "fix(pipeline): commit every timeline write atomically; no phantom lat…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T18:43:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f47cd47ee5977477bb5babe1b28577938472dc96",
          "body": "…edx-bom\n\nThe SBOM was generated by fetching cyclonedx-bom over the network AFTER the\nversion commit and tag, so a flaky download left the release half-prepared and a\nre-run failed on \"nothing to commit\" / \"tag already exists\". Build and SBOM now\nrun before the commit/tag while the tree is still clean; the generator is pinned\n(cyclonedx-bom==7.3.0) for a reproducible SBOM; and the commit and tag steps are\nidempotent so a run that fails on the network is safe to re-run.",
          "is_bot": false,
          "headline": "chore(release): generate the SBOM before any Git mutation, pin cyclon…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T18:03:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b7d0b0e0c4cd3251b28f8872785da36bfc22ae76",
          "body": "The matrix presented itself as the single conformance gate while several\nassertions only checked for the presence of a field or class. Its docstring now\ndistinguishes behavioural checks from structural (API-surface) ones and points\nto the feature suites that own the end-to-end coverage (test_postgre\n[…]\ntest_ai_chain_depth for reentry depth, test_channel_abc for\ntranscoding). The timers auto-pause/close, chain-depth blocking, and\ntranscoder-fallback checks are upgraded from structural to behavioural.",
          "is_bot": false,
          "headline": "test: make the Level 0 conformance matrix honest and behavioural",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T18:03:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5f382adb1640eed098b4770c70bf3408bd398836",
          "body": "Per the project policy of exporting new public classes: roomkit.store now\nexports PostgresStore and PostgresAdvisoryLockManager, and the top-level\nroomkit package exports RoomLockManager and InMemoryLockManager (the documented\nlocking extension point, RFC §13.5). Importing the postgres submodules stays\nasyncpg-free (asyncpg is imported lazily on instantiation), so a base install\nis unaffected.",
          "is_bot": false,
          "headline": "feat(api): export lock managers and Postgres store/lock",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T18:03:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a1a206aa21100ed3d5a8a004489562a1d9d1ef1d",
          "body": "…the lock\n\nTwo RFC-conformance fixes from the pre-0.29.0 review.\n\nP1 (RFC §8.1 / §10.1 step 12 / §14.3) — the inbound commit was not atomic:\nthe index was assigned with get_event_count(), then the event and the room\ncounters were written in separate store calls. Two processes without an\nadvisory loc\n[…]\nw collected into a pending_error_hooks_out sink and run\nafter the lock is released, like AFTER_BROADCAST. A deterministic test proves\nthe hook fires with the room absent from the _held_rooms lock set.",
          "is_bot": false,
          "headline": "fix(pipeline): commit inbound events atomically; defer ON_ERROR past …",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-13T18:03:33Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "39f77becbee1a4186d7cf7665c741ea196e47c04",
          "body": "…lease\n\nEach release now ships a per-version Software Bill of Materials\n(roomkit-<version>.cdx.json): a CycloneDX inventory of the runtime dependency\ntree (core + the providers extra) generated from the frozen lockfile via\ncyclonedx-py, attached as a GitHub Release asset. Lets downstreams audit a\nspecific version for vulnerabilities and licenses long after release —\ncomplements the blocking pip-audit gate and Dependabot.",
          "is_bot": false,
          "headline": "ci(release): generate a CycloneDX SBOM and attach it to the GitHub Re…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T20:12:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "51f52e6c8f37acd6ff85b65a03b5c6f67dae568c",
          "body": "Adds tests/test_conformance_level0.py — one assertion per RFC §25.1 Core\n(REQUIRED) requirement, each mapped to its section: room lifecycle/timers,\nevent types & content, sequential indexing (§8.1), channel interface,\nbinding access/mute/visibility, permission enforcement (§7.5), SYNC/ASYNC\nhooks + \n[…]\ny. Behavioural where clean, structural where a full harness adds no\nsignal — the single 'is RoomKit Level 0 conformant?' gate and a regression net\nfor the spec invariants before higher-risk refactors.",
          "is_bot": false,
          "headline": "test: executable RFC Level 0 conformance matrix",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T19:41:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "48dc789523e576c2018b1253d503dfb3324ff942",
          "body": "A tested, opt-in repair for databases carrying duplicate (room_id, index) rows\nfrom a pre-fix release: in one transaction it renumbers each affected room's\nevents to a unique sequential 0..N-1 (by index, created_at, id), reconciles the\nroom counters, and (re)creates idx_events_room_index as UNIQUE. \n[…]\n SQL on production.\n\nVerified against postgres:16: dry-run reports without changing; repair yields\nunique sequential indices + a UNIQUE index that rejects further duplicates;\nnoop on a clean database.",
          "is_bot": false,
          "headline": "feat(store): PostgresStore.dedupe_event_indices() repair helper",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T19:12:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c37772f8e160d7f9a83ac215e1ff257c4700c960",
          "body": "The PL/pgSQL RAISE WARNING can be swallowed by asyncpg, so init() now checks\nidx_events_room_index after applying the schema and logs a roomkit-side warning\nwhen it is not UNIQUE — making the degraded (duplicate indices present,\nmulti-process safety off) state visible in the application logs.",
          "is_bot": false,
          "headline": "fix(store): log a visible warning when the events index stays non-unique",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T19:04:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e5da560436de771e5c4ee8652c2b086bdd3d7ee3",
          "body": "… UNIQUE\n\nH1b's UNIQUE(room_id, index) migration ran in init()'s SCHEMA and raised\nUniqueViolationError when the existing table already held duplicate\n(room_id, index) rows from a prior release's races — crashing app startup.\ninit() must never fail on existing data (same rule as the destructive-migr\n[…]\nunique index) and logs a WARNING telling\nthe operator to deduplicate; a clean database still upgrades to UNIQUE.\n\nVerified against postgres:16 with a seeded duplicate index=0.\nRegression from 8839130.",
          "is_bot": false,
          "headline": "fix(store): don't fail init() when upgrading idx_events_room_index to…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T19:00:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6735d6d8a4430288c232bb4c471293e74c510c80",
          "body": "'uv pip install fastapi' pulled a newer starlette whose TestClient requires\nhttpx2 and raised a StarletteDeprecationWarning that pytest (filterwarnings=\nerror) turned into a collection error. 'uv run --with fastapi' resolves fastapi\nagainst the locked deps, keeping a working starlette/httpx combination.",
          "is_bot": false,
          "headline": "ci: resolve fastapi via 'uv run --with' in the integration job",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T18:45:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0c6536380681f0bcdbcd1914a4727cf1562b6e5e",
          "body": "New 'integration' job with a postgres:16 service container (POSTGRES_DSN) and\nfastapi installed, running the tests that self-skip in the fast unit job:\nPostgres store CRUD/migration, the multiprocess index-safety proof (H1b), and\nthe WebRTC /webrtc/offer auth path (P0-2). The fast 'test' job stays mock-only\nfor quick feedback.",
          "is_bot": false,
          "headline": "ci: run real-Postgres + WebRTC integration tests",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T18:41:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7328f81c787d3a4965d5a35476e8b7a801c467c5",
          "body": "The UNIQUE(room_id, index) constraint surfaced pre-existing test setups that\ninserted several events at the default index 0 via add_event — the framework\nnever does this. _make_event now assigns a per-room monotonic index (reset per\ntest), mirroring the framework and the cursor tests that already us\n[…]\nte index and that two advisory-lock managers\n(separate pools = two processes) sharing one DB serialize concurrent index\nassignment into unique sequential indices. Verified locally against postgres:16.",
          "is_bot": false,
          "headline": "test(store): distinct indices in Postgres tests + multiprocess H1b proof",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T18:41:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a2b0fee79277b686191cba678e91134e577b514f",
          "body": "ruff format on the new file (missed in the H1b commit; CI's repo-wide\n`ruff format --check .` caught it).",
          "is_bot": false,
          "headline": "style: format postgres_lock.py",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T18:16:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "88391309ea6d67fec8d5d8853a9d2cd32d9713b0",
          "body": "A shared PostgresStore behind multiple processes could assign duplicate event\nindices: the index is computed as count(*) under a per-process in-memory lock\nthat does not coordinate across processes, and events(room_id, index) had no\nunique constraint — so duplicates persisted silently and broke pagi\n[…]\n-memory store is paired with InMemoryLockManager.\n- RoomLockManager gains close() (default no-op), called by RoomKit.close().\n\nReview: H1b. RFC §8.1 / §13.5 / §14.3 updated in roomkit-specs (a7fb3ef).",
          "is_bot": false,
          "headline": "feat(store): distributed room locking + UNIQUE(room_id, index)",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T18:13:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "102ebd3a498849627fe65d081f40fecb00e00c68",
          "body": "Only the streaming consumption path fired ON_ERROR on a provider/inference\nfailure. Three other paths swallowed the error into a log line, leaving the\nroom with no error event — so hosts (e.g. Luge's error card) rendered nothing:\n\n- an error raised in the AI channel's on_event before the stream begi\n[…]\nresponse now re-raises instead of swallowing, so a\nnon-streaming failure reaches the same path. One firing site covers every\nnon-streaming failure route.\n\nTests: tests/test_inbound_error_surfacing.py.",
          "is_bot": false,
          "headline": "fix(inbound): surface swallowed agent-turn failures to ON_ERROR",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-12T04:06:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "066025e8b9f02658f837e01d8bcd22f9925df4d9",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.29.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T21:41:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8c969357a26258a6736568e2d9ed95a0ee6b3feb",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.28.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T21:41:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "13bc0b511ce63477e6955af6ba880ae68398ad69",
          "body": "0.27.0 reached PyPI but not git (no tag, no GitHub Release) because the script\npublished to PyPI before pushing git state, and never checked the CHANGELOG.\nThree guardrails: abort if the version already exists on PyPI; abort if\nCHANGELOG.md has no entry for it; and publish to PyPI LAST, after the commit,\ntag, and GitHub Release are pushed, so a failed upload is retryable and PyPI is\nnever ahead of the repository.",
          "is_bot": false,
          "headline": "ci(release): harden release.sh against the 0.27.0-style partial release",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T21:38:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0edc4fb042d4e3836d278f3f83fa10f02de3ee75",
          "body": "0.27.0 was published to PyPI (2026-07-10) but never got a CHANGELOG entry or a\ngit tag; add it retroactively. 0.28.0 documents the production-readiness\nremediation (Postgres migration, WebRTC auth, inbound-timeout atomicity, tool\nauthorization, PII redaction, supply-chain gating).",
          "is_bot": false,
          "headline": "docs(changelog): document 0.27.0 (retro) and 0.28.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T21:38:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1f5bc05d9a9d338b6e3dcea5850bda6a926cea9",
          "body": "…ocstring\n\nMIN-1: validation._matches_type was a 7-arm if/elif keyed on json_type — the\nif-chain-for-dispatch that CLAUDE.md rule 5 forbids. Replaced with a\n_TYPE_CHECKS registry (type name -> predicate); behaviour identical, verified\nby test_tool_arg_validation.\n\nMIN-2: _webrtc_auth module docstring narrated the pre-fix state in past tense\n(\"that path was never authenticated\"). Reworded to present tense describing\ncurrent behaviour and the gate's role — comments describe state, not history.",
          "is_bot": false,
          "headline": "refactor(tools): dispatch table for JSON type checks; present-tense d…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T18:51:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc39f047f0ba4b08662e9e78d9303d6d4637a5e0",
          "body": "TEMP-1: inbound_locked.py comments pinned to RFC pipeline step numbers\n(\"RFC §10.1 step 12/15\", \"steps 3-12\"). Step numbers in the RFC's ASCII\npipeline can renumber; the section anchor cannot. Keep \"§10.1\", drop the\nvolatile step numbers.\n\nTEMP-2: postgres_schema.py / postgres.py said \"legacy v1 sch\n[…]\nma\". CLAUDE.md\nrule 1 bans \"legacy\" in comments, and \"v1\" already names the format\nprecisely without the temporal connotation.\n\nBoth violate the rule that comments describe current state, not history.",
          "is_bot": false,
          "headline": "style: drop temporal markers from code comments",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T18:50:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d3ee25bd5add669197c2e209bb0f2468cdf0155a",
          "body": "…t neonize)\n\nReview: 'le README propose roomkit[neonize], extra inexistant'.",
          "is_bot": false,
          "headline": "docs(readme): fix WhatsApp Personal extra name (whatsapp-personal, no…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T18:07:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "43c54f17ea57c09f0dcfeff037580ab75163c0ae",
          "body": "InMemoryStore returned shallow model_copy() objects, so mutating a nested\nfield (e.g. event.metadata['x']['y']) on a read object silently mutated the\nstored object. Reads now deep-copy. Adds ConversationStore.close() (default\nno-op, idempotent) and calls it from RoomKit.close() so a PostgresStore\nconnection pool no longer leaks on shutdown.\n\nReview: high-risks 'immutabilité fictive du store mémoire' + 'cycle de vie incomplet'.",
          "is_bot": false,
          "headline": "fix(store): deep-copy InMemoryStore reads; add ConversationStore.close()",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T18:07:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c1b108f59cd68751dd710ed9fd9711af317170a3",
          "body": "New 'Dependency audit (core)' CI job audits the core runtime dependency set\n(pip-audit on the exported non-dev lockfile) — blocking, and stays green\nbecause core is just pydantic + transitives. Optional extras (which pull the\nheavier, occasionally-vulnerable trees) are kept current by a new\ndependabot.yml (uv + github-actions ecosystems, weekly).\n\nReview: high-risk 'dépendances vulnérables' + 'la CI ne fait que Bandit'.",
          "is_bot": false,
          "headline": "ci: add blocking pip-audit for core deps + Dependabot",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T18:07:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3cf562a0cd438c76805fd95caee60e05e8f2fd70",
          "body": "…audio decode\n\nSTT transcripts, TTS/AI responses and screen-agent typed text were logged in\nclear at INFO level, and server WebSocket transports base64-decoded inbound\naudio with no size bound. Content log sites now go through a central redact()\ngate (telemetry/redaction.py) that emits a length-only\n[…]\ntly enabled (ROOMKIT_LOG_CONTENT / set_content_logging)\nand drop to DEBUG level. Inbound audio frames are capped before decode via\nvoice/_limits.py (Twilio + realtime WS paths).\n\nReview: H4 (partial).",
          "is_bot": false,
          "headline": "fix(privacy): redact message content in logs by default; cap inbound …",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T17:45:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b4409c1782c65fbedf0d2887d5e43485d32e451a",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump development version to 0.28.0.dev0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T16:46:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c1053d49dfaa53bd9da5ba3fef154ccd225b99ee",
          "body": "Three tool-authorization gaps: a failure building context for the\nBEFORE_TOOL_USE hook allowed the call by default (now denies, fail-closed);\nrealtime voice ran the tool handler before the blocking hook, so the side\neffect happened even when blocked (authorization now runs before the\nhandler, matchi\n[…]\ndency-free validate_tool_arguments\nenforces required fields and primitive types on both paths before\nexecution).\n\nReview: H1 (partial). Sandbox ToolPolicy exemption left as a separate\ndesign decision.",
          "is_bot": false,
          "headline": "fix(tools): fail closed on tool authorization; validate arguments",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T16:21:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e4c82523cc2415d17b8a06e65ea689e347b99c38",
          "body": "The whole locked pipeline (persist DELIVERED -> broadcast -> counters) was\nwrapped in one asyncio.wait_for, so a timeout during a slow broadcast left\nthe event stored as DELIVERED while the caller got blocked=process_timeout\nand the room counters were never updated. _process_locked now splits at the\n[…]\nroom-counter bump commit atomically via _commit_event, so the\ntimeline and counters can never diverge.\n\nReview: P0-3. Normative RFC updated in roomkit-specs (roomkit-rfc.md\nsections 10.1, 13.6, 14.3).",
          "is_bot": false,
          "headline": "fix(core)!: scope process_timeout to the pre-commit phase only",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T16:20:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9fbdda6d3e19659ed3001536a1a957c960a9163f",
          "body": "…Connection\n\nThe auth callback ran only when a WebSocket object was present, but WebRTC\nconnections arrive over an HTTP POST /webrtc/offer with no WebSocket, so\nthat path was never authenticated and an RTCPeerConnection was allocated\nfor any caller (auth bypass + DoS surface). A new shared helper,\nr\n[…]\nre delegation, and mount_fastrtc_voice/mount_fastrtc_av now require an\nexplicit allow_anonymous=True when no auth callback is supplied. Applied to\nboth the voice and audio+video mounts.\n\nReview: P0-2.",
          "is_bot": false,
          "headline": "fix(voice)!: authenticate WebRTC /webrtc/offer before creating a Peer…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T16:20:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7229449d560a6fec371a037bb7acf739ce4b159e",
          "body": "…migrate()\n\ninit() ran a SCHEMA that DROP...CASCADE'd every table when it detected a\nlegacy v1 (JSONB-blob) schema, so a routine connect after an upgrade could\nwipe rooms, events, participants and identities. init() now runs additive,\nidempotent DDL only and raises PostgresSchemaError when a v1 sche\n[…]\nation moves to an explicit, opt-in\nPostgresStore.migrate(dry_run=True, confirm=False), serialized by a\nPostgreSQL advisory lock.\n\nReview: P0-1. Docs updated in roomkit-docs (guides/postgres-store.md).",
          "is_bot": false,
          "headline": "fix(store)!: never DROP tables from PostgresStore.init(); add opt-in …",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T16:20:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "588bd3bb071d45f9138e6ffeb3573b4fb61f318c",
          "body": "Offset-based list_events / get_activity_timeline can now return the most\nrecent `limit` events (still ascending) instead of the room's opening\nevents — the right shape for a reconnect snapshot. Implemented across the\nConversationStore ABC, InMemoryStore, and PostgresStore.",
          "is_bot": false,
          "headline": "feat(store): add newest_first offset pagination to list_events",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T16:19:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cb28b6727de104d9a5354c3ec983d5532c80e586",
          "body": "Bump the PyPI Development Status classifier from '3 - Alpha' to\n'4 - Beta' to reflect that RoomKit is feature-complete and near\nproduction readiness.",
          "is_bot": false,
          "headline": "chore: promote development status to Beta (4)",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-11T13:38:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6f3f452f0dab9569e4a14ac13674d1a48ce5e60b",
          "body": "…stings\n\nThe hook-trigger count had drifted across docs (CLAUDE.md said 27, README\nsaid 35) while the HookTrigger enum has 65 members. Set both to 65. In\nAGENTS.md's quick-reference: add the membership triggers\n(ON_PARTICIPANT_JOINED/LEFT), list BEFORE_TOOL_USE / ON_USER_INPUT_REQUIRED,\ndrop the phantom ON_OBSERVATION (not a real trigger), and point to RFC §9.2\nas the authoritative complete set. Verified against len(HookTrigger) == 65.",
          "is_bot": false,
          "headline": "docs: correct hook-trigger count to 65 (was 27/35) and fix trigger li…",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-10T17:06:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c43e89b5bfa043df6681cba17d7414b3fce11ba3",
          "body": "The explicit-membership feature (0.26.0) shipped without an example.\nexamples/room_membership.py demonstrates add_member (idempotent join),\nlist_members/is_member, ON_PARTICIPANT_JOINED/LEFT hooks, remove_member\n(soft leave), and list_read_markers 'seen by' aggregation. Runs clean\nend-to-end; referenced by the Room Membership guide in roomkit-docs.",
          "is_bot": false,
          "headline": "docs(examples): add runnable room membership example",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-10T16:35:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6fff326f77d00a6b815ac769aad1f7bf5c83f2e2",
          "body": null,
          "is_bot": false,
          "headline": "Begin 0.27.0.dev0 development",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-10T16:23:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3b58cc0cced132d63e4462ba60eaf717204adf41",
          "body": null,
          "is_bot": false,
          "headline": "Bump version to 0.26.0",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-10T16:23:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9e478c33df861662f7ff52d4fabd3878c5016361",
          "body": "The membership feature pushed room_lifecycle.py to 462 LOC of code, ~40%\nover the 300-line target, and mixed two responsibilities (room CRUD +\nparticipant lifecycle vs. explicit join/leave). Move add_member /\nremove_member / list_members / is_member into a dedicated MembershipMixin\n(HelpersMixin bas\n[…]\net_room resolved cross-mixin via the same\nannotation-stub pattern used elsewhere). room_lifecycle.py drops to 329\nLOC; no public API or behaviour change (methods still resolve on RoomKit\nvia the MRO).",
          "is_bot": false,
          "headline": "refactor(core): extract MembershipMixin from RoomLifecycleMixin",
          "author_name": "Sylvain Boily",
          "author_login": "sboily",
          "committed_at": "2026-07-10T16:12:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        }
      ],
      "releases_count": 86,
      "commits_last_year": 1212,
      "latest_release_at": "2026-07-24T05:15:44Z",
      "latest_release_tag": "v0.37.1",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 23,
      "days_since_latest_release": 0,
      "mean_days_between_releases": 1.2
    },
    "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": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "roomkit",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "ai",
            "async",
            "chat",
            "multi-channel",
            "rcs",
            "rooms",
            "sms",
            "voice",
            "whatsapp",
            "Development Status :: 4 - Beta",
            "Framework :: AsyncIO",
            "Intended Audience :: Developers",
            "License :: OSI Approved :: MIT License",
            "Programming Language :: Python :: 3",
            "Programming Language :: Python :: 3.12",
            "Programming Language :: Python :: 3.13",
            "Topic :: Communications",
            "Topic :: Communications :: Chat",
            "Typing :: Typed"
          ],
          "ecosystem": "pypi",
          "matches_repo": true,
          "registry_url": "https://pypi.org/project/roomkit/",
          "is_deprecated": false,
          "latest_version": "0.37.0",
          "repository_url": "https://github.com/roomkit-live/roomkit",
          "versions_count": 97,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 8369,
          "first_published_at": "2026-02-02T23:14:31.916695Z",
          "latest_published_at": "2026-07-24T04:53:54.053993Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 3,
      "stars": 30,
      "watchers": 0,
      "fork_history": {
        "days": [
          {
            "date": "2026-02-07",
            "count": 1
          },
          {
            "date": "2026-02-17",
            "count": 1
          },
          {
            "date": "2026-07-02",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 3,
        "total_forks": 3
      },
      "star_history": null,
      "open_issues_and_prs": 1
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "examples"
      ],
      "has_llms_txt": true,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "src/roomkit/py.typed"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 67638,
      "source_files_sampled": 1060,
      "oversized_source_files": 3,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 34706
    },
    "dependencies": {
      "manifests": [
        "pyproject.toml"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "pypi"
      ],
      "dependencies": [
        {
          "name": "pydantic",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=2.9"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 1,
        "merged_prs": 8,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 4
      },
      "bus_factor": 1,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "sboily",
          "commits": 1221,
          "avatar_url": "https://avatars.githubusercontent.com/u/5470187?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": true
    },
    "security_signals": {
      "lockfiles": [
        "uv.lock"
      ],
      "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": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "1 out of 1 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/29 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "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 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 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": "71 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "b458ed19d628afc812c986f7c3fe41d4cee8bee5",
        "ran_at": "2026-07-24T05:17:18Z",
        "aggregate_score": 4.3,
        "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-24T05:16:01Z",
      "oldest_open_prs": [
        {
          "number": 13,
          "created_at": "2026-07-24T05:16:54Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ],
      "last_merged_pr_at": "2026-07-24T04:32:38Z",
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/roomkit-live/roomkit",
    "host": "github.com",
    "name": "roomkit",
    "owner": "roomkit-live"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 64,
      "inputs": {
        "security": 43,
        "vitality": 84,
        "community": 56,
        "governance": 47,
        "engineering": 88
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 84,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 80,
            "inputs": {
              "commits_last_year": 1212,
              "human_commit_share": 0.95,
              "days_since_last_push": 0,
              "active_weeks_last_year": 23
            },
            "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": "23/52 weeks with commits",
                "points": 15.9,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 23
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "1212 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 1212
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 86,
              "latest_release_tag": "v0.37.1",
              "releases_from_tags": false,
              "days_since_latest_release": 0,
              "mean_days_between_releases": 1.2
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "86 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 86
                    }
                  }
                ],
                "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.2 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 1.2
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "moderate",
        "name": "Community & Adoption",
        "value": 56,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 26,
            "inputs": {
              "forks": 3,
              "stars": 30,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "30 stars",
                "points": 23.7,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 30
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "3 forks",
                "points": 2.5,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "excellent",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": true,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 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": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 65,
            "inputs": {
              "packages": [
                "roomkit"
              ],
              "dependents": null,
              "ecosystems": "pypi",
              "total_downloads": null,
              "monthly_downloads": 8369
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "8,369 downloads/month across pypi",
                "points": 52.3,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 8369,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 47,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 13,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "at_risk",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 48,
            "inputs": {
              "merged_prs": 8,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 4
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "8/12 decided PRs merged",
                "points": 25.5,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 8,
                      "decided": 12
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/29 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 46,
            "inputs": {
              "followers": 10,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "roomkit-live",
              "public_repos": 9,
              "account_age_days": 168
            },
            "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": "10 followers of roomkit-live",
                "points": 7.5,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 10,
                      "login": "roomkit-live"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "9 public repos, account ~0 yr old",
                "points": 8.2,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 9
                    }
                  },
                  {
                    "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": [
                "roomkit"
              ],
              "ecosystems": "pypi",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on pypi",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "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": "97 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 97
                    }
                  }
                ],
                "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": "excellent",
        "name": "Engineering Quality",
        "value": 88,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "excellent",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 94,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": true
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "1 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "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": 16,
                "status": "met",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 9.6,
                "status": "met",
                "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": "1 out of 1 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 80,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": "https://www.roomkit.live",
              "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://www.roomkit.live",
                "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": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 43,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 43,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 4.3
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "1 out of 1 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/29 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "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 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow 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 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file 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": "71 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 3
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 80,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "has_llms_txt": true,
              "legible_history_share": 0.747,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 34706
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": "llms.txt present",
                "points": 15,
                "status": "met",
                "details": [
                  {
                    "code": "llms_txt_present",
                    "params": {}
                  }
                ],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "71 of 95 human commits state their intent (structured subject or explanatory body)",
                "points": 39.9,
                "status": "partial",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 71,
                      "sampled": 95
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 80,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "uv.lock"
              ],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [
                "src/roomkit/py.typed"
              ],
              "agent_commit_share": 0,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0.05
            },
            "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": 11,
                "status": "met",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "src/roomkit/py.typed",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "src/roomkit/py.typed"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "5 of the last 100 commits are automated dependency updates",
                "points": 8,
                "status": "met",
                "details": [
                  {
                    "code": "dependency_bot_commits",
                    "params": {
                      "count": 5,
                      "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 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "good",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 82,
            "inputs": {
              "primary_language": "Python",
              "largest_source_bytes": 67638,
              "source_files_sampled": 1060,
              "oversized_source_files": 3
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Python with type-check config (src/roomkit/py.typed)",
                "points": 27,
                "status": "partial",
                "details": [
                  {
                    "code": "typecheck_config_language",
                    "params": {
                      "files": "src/roomkit/py.typed",
                      "language": "Python"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "3/1060 source files over 60KB",
                "points": 54.8,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 1060,
                      "oversized": 3
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "at_risk",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "examples"
              ],
              "has_mcp_signal": false,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "examples",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "examples"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index pypi:roomkit@0.37.0; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-24T05:17:25.080458Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/r/roomkit-live/roomkit.svg",
  "full_name": "roomkit-live/roomkit",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

Wie ein einzelnes Ergebnis im Gesamtregister steht: aggregierte StatistikenPyPI.