Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-25 22:47 UTC

broberg-ai / ai-sdk

@broberg/ai-sdk — config-wrapper SDK

TypeScriptSin licencia detectada★ 0 estrellas⑂ 0 forksdesde jun 2026Ver en GitHub ↗

broberg-ai/ai-sdk tiene un índice de salud de 52 sobre 100, lo que lo sitúa en la banda Moderado. Su puntuación más alta es Vitality (71/100) y la más baja, Community & Adoption (24/100). Se actualizó por última vez hace 6 días. Una sola persona concentra la mayor parte del trabajo reciente.

52
global / 100
Moderado

Índice de salud del software

Las métricas se agrupan en categorías ponderadas sobre una escala de 1 a 100. El resultado global parte de su media; cuando la evidencia pública activa la Política de Jurisdicciones de Alto Riesgo, la calificación se ajusta y recibe el límite 49 (En riesgo). Preparación para IA queda fuera.

52
Excelente85-100Ejemplar; cumple prácticamente todos los criterios evaluados
Bueno70-84Saludable; carencias menores
Moderado50-69Aceptable con carencias notables; se recomienda revisión
En riesgo30-49Debilidades significativas; su adopción exige cautela
Crítico1-29Problemas graves (proyecto abandonado, un solo mantenedor, sin higiene)
VitalidadComunidad yAdopciónSostenibilidady GobernanzaCalidad deIngenieríaSeguridadPreparaciónpara IA

Perfil de puntuación

Cada eje es una categoría. La forma importa más que la media: un proyecto sano llena toda la figura, mientras que un perfil de picos y cráteres indica que la fortaleza en una dimensión enmascara el riesgo en otra.

Titularidad

broberg.aiOrganización
1 seguidor10 repositorios públicosdesde abr 2026

Este repositorio está respaldado por una organización: una custodia compartida y responsable que puede sobrevivir a cualquier mantenedor individual.

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicación
npm@broberg/ai-sdk0.25.1352540hace 6 días

Métricas por categoría

Vitalidad

¿Está vivo el proyecto: se escribe código y se publican versiones?

71Bueno · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 6 días
5.5/36Cadencia de commits — 8/52 semanas con commits
18/18Volumen de commits — 179 commits en el último año
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Datos de entrada utilizados
commits_last_year179
human_commit_share0,83
days_since_last_push6
active_weeks_last_year8
Cómo se puntúa
16.2/27Publica versiones — 39 etiquetas de versión (sin releases de GitHub)
36/36Recencia de las versiones — última versión hace 6 días
27/27Cadencia de publicación — una versión cada ~2,9 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count39
latest_release_tagv0.25.1
releases_from_tags
days_since_latest_release6
mean_days_between_releases2,9
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Signed-Releases. Los pesos restantes se han renormalizado.

Comunidad y Adopción

¿Tiene el proyecto usuarios, descargas, atención y unas condiciones acogedoras para quienes contribuyen?

24Crítico · 18% del índice global
Cómo se puntúa
0/60Estrellas — 0 estrellas
0/25Forks — 0 forks
0/15Observadores — 0 observadores
Datos de entrada utilizados
forks0
stars0
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
0/22.5Licencia — no se detectó ningún archivo de licencia
0/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_licenseno
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno
Cómo se puntúa
47.3/80Descargas mensuales — 3525 descargas/mes en npm
0/20Dependientes en el registro — no lo informa este ecosistema
Datos de entrada utilizados
packages@broberg/ai-sdk
dependents
ecosystemsnpm
total_downloads
monthly_downloads3525
Excluidos de la puntuación (sin datos o no aplicable): Dependientes en el registro. Los pesos restantes se han renormalizado.

Sostenibilidad y Gobernanza

¿Sobrevivirá el proyecto a sus personas: factor bus, capacidad de respuesta, quién lo respalda y mantenimiento del paquete?

53Moderado · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0/22.5Distribución de commits — el principal contribuyente firma el 100% de los commits
1.4/13.5Amplitud de contribuyentes — 1 contribuyentes
6/10OpenSSF Scorecard: Contributors — project has 2 contributing companies or organizations -- score normalized to 6
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
0/46.8Resolución de issues — sin issues o sin datos
38.2/38.3Aceptación de PR — 1/1 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs1
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
Excluidos de la puntuación (sin datos o no aplicable): Resolución de issues. Los pesos restantes se han renormalizado.
Cómo se puntúa
30/30Respaldo de la propiedad — propiedad de una organización
0/20Dominio verificado
2.2/25Alcance del propietario — 1 seguidores de broberg-ai
8.1/25Trayectoria — 10 repos públicos, cuenta de ~0 años
Datos de entrada utilizados
followers1
owner_typeOrganization
is_verified
owner_loginbroberg-ai
public_repos10
account_age_days102
Cómo se puntúa
25/25Publicado y resoluble — 1 paquete(s) en npm
35/35Recencia de publicación — última publicación hace 6 días
20/20Historial de versiones — 40 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packages@broberg/ai-sdk
ecosystemsnpm
any_deprecatedno
min_days_since_publish6

Calidad de Ingeniería

¿Existen unas prácticas mínimas de ingeniería y documentación?

62Moderado · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 2 flujo(s) de trabajo
24/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — sin datos
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_configno
has_precommit_configno
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: CI-Tests. Los pesos restantes se han renormalizado.

Documentación

65Moderado
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
10/10Descripción del repositorio
0/10Topics
0/10Wiki
Datos de entrada utilizados
topics
has_wikino
homepage
has_readme
has_docs_dir
has_description

Seguridad

¿Son sólidas las prácticas visibles de seguridad y de cadena de suministro, sin exposición jurisdiccional de alto riesgo sin resolver?

46En riesgo · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — sin datos
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
1.5/2.5Contributors — project has 2 contributing companies or organizations -- score normalized to 6
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
0/2.5Licencia — license file not detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
6.8/7.5Vulnerabilities — 1 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate3,2
Excluidos de la puntuación (sin datos o no aplicable): ci_tests, signed_releases. Los pesos restantes se han renormalizado.
Cómo se puntúa
35/35Dependencias directas libres de avisos conocidos — ninguna dependencia directa tiene un aviso conocido
25/25Dependencias indirectas libres de avisos conocidos — ninguna dependencia indirecta tiene un aviso conocido
0/40Sin avisos pendientes — ningún aviso tiene fecha de publicación
Datos de entrada utilizados
sourceosv
advisories0
affected_packages0
assessed_packages1
unassessed_packages0
affected_by_severitynone
direct_affected_packages0
Excluidos de la puntuación (sin datos o no aplicable): Sin avisos pendientes. Los pesos restantes se han renormalizado. Se cotejó el cierre de dependencias en tiempo de ejecución de npm:@broberg/ai-sdk@0.25.1 —lo que arrastra la instalación del paquete publicado—: 1 paquetes. No se analiza la alcanzabilidad.

Preparación para IA

¿Hasta qué punto está el repositorio preparado para desarrollarse y mantenerse con agentes de codificación de IA? Es una insignia independiente y experimental — peso 0,0, de modo que se presenta por separado y no afecta a la puntuación de salud global.

68Moderado · 0% del índice global
Cómo se puntúa
45/45Instrucciones para agentes — CLAUDE.md
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 83 de 83 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share1
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes38.283
Cómo se puntúa
0/18Arranque con un solo comando
22/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — tsconfig.json
0/10Entorno reproducible
10/10Práctica demostrada con agentes — 67 de los últimos 100 commits con autoría o crédito de agente
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Datos de entrada utilizados
has_nixno
has_tests
lockfiles
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configstsconfig.json
agent_commit_share0,67
toolchain_manifests
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — TypeScript (tipado estático)
55/55Tamaños de archivo manejables — 0/130 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageTypeScript
largest_source_bytes29.347
source_files_sampled130
oversized_source_files0

Datos clave

0estrellas de GitHub
1contribuidores
179commits en los últimos 12 meses
6días desde el último push
39versiones publicadas
1factor bus
0issues abiertas
npmecosistemas de paquetes

Advertencias de recopilación de datos

  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Más detalle

OpenSSF Scorecard 3.2 / 10
3.2agregado

Evaluación de seguridad independiente y agnóstica en cuanto a herramientas, procedente del proyecto de código abierto OpenSSF Scorecard. Cada comprobación premia una práctica de seguridad, no la herramienta de un proveedor concreto. Las comprobaciones que Scorecard no pudo determinar se marcan como n/d y se excluyen de la puntuación de seguridad (nunca se cuentan como cero).Scorecard v5.5.0 · 2026-07-25 22:47 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
n/dCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
6Contributorsproject has 2 contributing companies or organizations -- score normalized to 6
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
0Licenselicense file not detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
9Vulnerabilities1 existing vulnerabilities detected
Dependencias directas 1
RegistroPaqueteRestricción de versiónManifiesto
npmzod^3.23.8package.json
Todas las dependencias no recopilado

No fue posible recopilar el conjunto de dependencias resuelto para este informe: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Avisos de dependencias 0

Instalar npm:@broberg/ai-sdk@0.25.1 arrastra 1 paquetes, directos y transitivos: 0 tienen avisos conocidos, de los cuales 0 son dependencias directas.

Ningún aviso conocido afecta a las dependencias evaluadas.

Un aviso significa que la versión registrada en el grafo de dependencias cae dentro del rango afectado de un aviso. No se analiza la alcanzabilidad, y el grafo incluye fijaciones de desarrollo y prueba: un hallazgo puede referirse al utillaje y no al software distribuido.

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1261,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "Shell": 41197,
        "JavaScript": 10331,
        "TypeScript": 531706
      },
      "pushed_at": "2026-07-19T22:38:10Z",
      "created_at": "2026-06-01T21:44:59Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-19T12:56:04Z",
      "description": "@broberg/ai-sdk — config-wrapper SDK",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": null,
      "primary_language": "TypeScript",
      "significant_languages": [
        "TypeScript"
      ]
    },
    "owner": {
      "blog": "broberg.ai",
      "name": "broberg.ai",
      "type": "Organization",
      "login": "broberg-ai",
      "company": null,
      "location": "Denmark",
      "followers": 1,
      "avatar_url": "https://avatars.githubusercontent.com/u/276013563?v=4",
      "created_at": "2026-04-14T13:31:16Z",
      "is_verified": null,
      "public_repos": 10,
      "account_age_days": 102
    },
    "license": {
      "state": "absent",
      "spdx_id": null,
      "raw_spdx": null,
      "file_present": false,
      "scorecard_found": false,
      "profile_has_license": false
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.25.1",
          "kind": "patch",
          "published_at": "2026-07-19T12:55:52Z"
        },
        {
          "tag": "v0.25.0",
          "kind": "minor",
          "published_at": "2026-07-18T00:27:41Z"
        },
        {
          "tag": "v0.24.0",
          "kind": "minor",
          "published_at": "2026-07-17T16:31:32Z"
        },
        {
          "tag": "v0.23.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:53:33Z"
        },
        {
          "tag": "v0.22.0",
          "kind": "minor",
          "published_at": "2026-07-05T10:52:14Z"
        },
        {
          "tag": "v0.21.1",
          "kind": "patch",
          "published_at": "2026-07-02T12:38:54Z"
        },
        {
          "tag": "v0.21.0",
          "kind": "minor",
          "published_at": "2026-06-30T19:38:58Z"
        },
        {
          "tag": "v0.20.0",
          "kind": "minor",
          "published_at": "2026-06-30T13:32:52Z"
        },
        {
          "tag": "v0.19.0",
          "kind": "minor",
          "published_at": "2026-06-23T10:24:22Z"
        },
        {
          "tag": "v0.18.0",
          "kind": "minor",
          "published_at": "2026-06-23T10:13:49Z"
        },
        {
          "tag": "v0.17.1",
          "kind": "patch",
          "published_at": "2026-06-16T18:16:18Z"
        },
        {
          "tag": "v0.17.0",
          "kind": "minor",
          "published_at": "2026-06-16T18:02:47Z"
        },
        {
          "tag": "v0.16.0",
          "kind": "minor",
          "published_at": "2026-06-16T17:00:14Z"
        },
        {
          "tag": "v0.15.0",
          "kind": "minor",
          "published_at": "2026-06-16T16:27:19Z"
        },
        {
          "tag": "v0.14.0",
          "kind": "minor",
          "published_at": "2026-06-16T15:51:41Z"
        },
        {
          "tag": "v0.13.1",
          "kind": "patch",
          "published_at": "2026-06-15T19:48:07Z"
        },
        {
          "tag": "v0.13.0",
          "kind": "minor",
          "published_at": "2026-06-14T23:42:37Z"
        },
        {
          "tag": "v0.12.0",
          "kind": "minor",
          "published_at": "2026-06-13T10:40:52Z"
        },
        {
          "tag": "v0.11.0",
          "kind": "minor",
          "published_at": "2026-06-13T10:20:48Z"
        },
        {
          "tag": "v0.10.5",
          "kind": "patch",
          "published_at": "2026-06-11T07:18:10Z"
        },
        {
          "tag": "v0.10.4",
          "kind": "patch",
          "published_at": "2026-06-08T23:46:58Z"
        },
        {
          "tag": "v0.10.3",
          "kind": "patch",
          "published_at": "2026-06-07T18:55:17Z"
        },
        {
          "tag": "v0.10.2",
          "kind": "patch",
          "published_at": "2026-06-07T18:33:57Z"
        },
        {
          "tag": "v0.10.1",
          "kind": "patch",
          "published_at": "2026-06-07T18:17:40Z"
        },
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2026-06-07T17:59:37Z"
        },
        {
          "tag": "v0.9.1",
          "kind": "patch",
          "published_at": "2026-06-06T19:40:06Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-06-05T00:38:43Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2026-06-05T00:00:14Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2026-06-04T23:19:39Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2026-06-04T21:17:40Z"
        },
        {
          "tag": "v0.5.1",
          "kind": "patch",
          "published_at": "2026-06-04T14:33:09Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-06-03T11:19:15Z"
        },
        {
          "tag": "v0.4.1",
          "kind": "patch",
          "published_at": "2026-06-02T16:03:30Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-06-02T12:45:52Z"
        },
        {
          "tag": "v0.3.1",
          "kind": "patch",
          "published_at": "2026-06-02T11:54:50Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-06-02T11:42:19Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-06-02T10:12:17Z"
        },
        {
          "tag": "v0.1.2",
          "kind": "patch",
          "published_at": "2026-06-02T09:56:00Z"
        },
        {
          "tag": "v0.1.1",
          "kind": "patch",
          "published_at": "2026-06-02T08:25:27Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "54389c48e062f418d8b3e34688388d7cc6e7a61c",
          "body": "F036 shipped word/segment timestamps but only the Whisper (openai) adapter\nhonored them — Azure/Mistral silently returned { text }. A repo with only\nAZURE_SPEECH_KEY (e.g. contentpush) couldn't use the timestamps API \"as\nannounced\". Azure fast-transcription already returns phrases + per-word ms\noffs\n[…]\nft as a verified follow-up.\n- Seal: 3 azure tests (word+segment parsed ms→sec, single \"segment\" hides\n  words, no-timestamps stays plain text).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(F036.1): Azure adapter honors ai.transcribe timestamps too (v0.25.1)",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-19T12:55:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "619565a564f8c95f8bab15d4eb025fca1573afbc",
          "body": "contentpush F016.5 (time-synced captions) needs a timing source for TTS'd\nspeech. ai.transcribe returned only { text, usage }; Whisper natively supports\nword + segment timestamps via verbose_json. Additive, opt-in, backward-compat.\n\n- ai.transcribe({ audio, timestamps: \"word\" | \"segment\" | (\"word\"|\"\n[…]\n audio only; word boundaries need the Speech SDK over WebSocket (a\ntransport re-architecture) — transcribe covers the caption use-case cheaply.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F036): opt-in word/segment timestamps on ai.transcribe (v0.25.0)",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-18T00:27:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "aac792ccdd2341d7c60f8e63e4e860306416544b",
          "body": "…ice (backlog)\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F035): fal image extra/params passthrough + bless fal-recraft pr…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-07-17T20:39:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c670716e1be4dca15d89c8012f3392c430713ca6",
          "body": "A consumer (happy-little-place) read \"image (fal.ai)\" and assumed the recraft\nvector slug was a fal app-id → 404 + $0 cost detour. Recraft SVG routes via\nOpenRouter's Image API (F033.1): the \"-vector\" slug is an OpenRouter model and\nreturns image/svg+xml with ground-truth cost. Note the raster(fal)/vector(OR)\nsplit so the next reader doesn't take the same wrong turn.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(README): clarify image route — recraft SVG is OpenRouter, not fal",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-17T20:37:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "550f3ce5f03cc5535c31d6a78fddcb04f1640382",
          "body": "…om env\n\nRoot cause: createAI() reported to a cost sink ONLY when the caller passed\nconfig.costSink explicitly. Fleet-wide most call-sites don't (cardmem alone\nhad 4 createAI() on mistral-large with no sink) → ~91% of Mistral spend\n(125M input tokens = the €53 invoice) was invisible in upmetrics. Pe\n[…]\nd (which imports /registry).\n- Seal: 3 tests — no-sink+env auto-POSTs to /api/agent, ship-dark no-POST,\n  explicit-sink-wins skips auto-wiring.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F034): cost-tracking on by default — auto-wire upmetrics sink fr…",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-17T16:31:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "03ab0a89b61e3c56493fca0edc208639037b6878",
          "body": "…ery consumer\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F034): default env-based cost-sink in createAI() — auto-track ev…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-07-17T16:18:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b50ca2962a4600d225c10a6c8c85e3593b0210ca",
          "body": "… (v0.23.0)\n\nFAL_KEY-only consumers (contentpush F014 video spike) can now call\nai.animate({ image, override:{ provider:'fal',\nmodel:'fal-ai/kling-video/v2.5-turbo/pro/image-to-video' } }) with correct\ncost-tracking instead of a misleading $0 — no raw-provider hack.\n\n- FAL_VIDEO_PRICE_PER_SEC: bless\n[…]\no) — fal is override-only.\n- Seal cost-tracking: a test that fails if the blessed model bills $0, plus\n  a config.pricePerSecond override test.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F014): bless fal Kling 2.5 Turbo Pro i2v + $0.07/s cost-tracking…",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-17T13:53:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b5c5c37d2312c4a3be68bb824c60e95de2d80922",
          "body": "npm v12's `npm publish --provenance` fails with \"Cannot find module\n'sigstore'\" (fleet-wide, flagged 2026-07-10). Pin to 11.5.1 (OIDC trusted\npublishing needs >= 11.5.1) instead of @latest so provenance minting works.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): pin npm@11.5.1 in publish.yml — npm v12 breaks --provenance",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-17T13:53:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0ad5b00db927a96c3edaf63348dbefa93bc50387",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-16T10:27:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c15a5224471b90dad17414c28d42e6c2340b1528",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-13T13:50:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0e8c076e50da4b813d0635c943f8070b13205d57",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F149): sync canonical CLAUDE.md sections (scaffold v2 reuse-first)",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-13T11:55:32Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d28139fc17b9d7326eaf43cc3d433d6a9153a3dc",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-11T16:57:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c1b95175aee4f347b1ba0f1870d5a9ec5205fca4",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F149): sync canonical CLAUDE.md sections (scaffold v2 reuse-first)",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-10T22:16:15Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f66bb60a23e85d9091d3775d266c349780265a01",
          "body": "Applied canonical cardmem hooks/skills/settings via the daemon (F075.3).",
          "is_bot": false,
          "headline": "chore(cardmem): update .claude templates to 851e0f45",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-10T22:16:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7ef4869b9be3ca8545d131e78bf471491d77d504",
          "body": "…craft v4.1 image gen\n\nThree EU/provider capabilities land on the ai.image()/translate facade, all\nbuild+test green (335 tests):\n\n- F031 — Vertex AI Veo adapter: EU-resident image-to-video. Shared image-input\n  helper extracted to src/providers/media.ts (URL/bytes/data-URI → inline base64).\n- F032 —\n[…]\nngle-image\n  contract, ground-truth usage.cost with local price fallback. Unblocks Contentpush\n  F003.3 (on-brand logos + brand illustrations).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F031,F032,F033): Vertex Veo (EU i2v) + DeepL (EU translate) + Re…",
          "author_name": "Christian Broberg",
          "author_login": null,
          "committed_at": "2026-07-05T10:52:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "63c7622bd70c8682c67e7c9b0a9f0c24cc06b063",
          "body": "…cardmem_write_plan\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F033): write docs/features/F033-contentpush-image-models.md via …",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-07-03T20:37:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "97b16e5191c734d95d03af6828e0573b1aaa6470",
          "body": "… fixes)\n\nUpdate registry and wiring tests to verify fable-5 is now available and\nmythos-5 remains suspended (unverified).",
          "is_bot": false,
          "headline": "test: update availability tests for fable-5 re-enablement (additional…",
          "author_name": "Aidan Nielsen",
          "author_login": null,
          "committed_at": "2026-07-02T12:38:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fb277febecfd58b5f454698f21ee7f0b1852708b",
          "body": "Fable 5 is now available (re-enabled by Anthropic). Update resolve tests to\nverify fable-5 is available and use mythos (still suspended) for suspension-\nbehavior tests instead.",
          "is_bot": false,
          "headline": "test(F022): update availability tests for claude-fable-5 re-enablement",
          "author_name": "Aidan Nielsen",
          "author_login": null,
          "committed_at": "2026-07-02T12:37:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "59aeefd04a2683561e7749744768038fb19ad7a4",
          "body": null,
          "is_bot": false,
          "headline": "chore(release): v0.21.1 — re-enable claude-fable-5 (Anthropic restored)",
          "author_name": "Aidan Nielsen",
          "author_login": null,
          "committed_at": "2026-07-02T12:33:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "185208627610526722929e722b4c7d53da70e38c",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-07-01T11:51:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ca546feb6dc78c0f0e7d08a5d6ec660fe73baecd",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F149): sync canonical CLAUDE.md sections (scaffold v2 reuse-first)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-07-01T11:51:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b67fec69d5f7793d66c767ef4b34cebd4b7fe713",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F149): sync canonical CLAUDE.md sections (scaffold v2 reuse-first)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-07-01T11:51:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d9071dbce7f62b29daf046d3b7270c6b41b50427",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F149): sync canonical CLAUDE.md sections (scaffold v2 reuse-first)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-07-01T11:51:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9fee94dd39ab4c4f83b3e67b8b78b8b24bc29531",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F149): sync canonical CLAUDE.md sections (scaffold v2 reuse-first)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-07-01T11:51:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f392469a0fb3a5f0568f5958d14e5d99604f039d",
          "body": "Applied canonical cardmem hooks/skills/settings via the daemon (F075.3).",
          "is_bot": false,
          "headline": "chore(cardmem): update .claude templates to e73d8ab0",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-07-01T11:51:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e4955313311c527d3d6c043df5140151d0c89c90",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-07-01T11:51:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dbb1729a5be12e372135086a8d04e9b274061877",
          "body": "[skip ci]",
          "is_bot": true,
          "headline": "docs(F032): plan — DeepL translation adapter (EU, dedicated MT engine)",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-07-01T02:16:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8b1e06531645bbc2017d5d0cadd04daea308a8ab",
          "body": "[skip ci]",
          "is_bot": true,
          "headline": "docs(F031): plan — Vertex AI Veo adapter (EU-resident image-to-video)",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-07-01T01:02:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "35afc252ffc6298c1545e8133ed64429484ef0f6",
          "body": "…esolveModel fallback off Anthropic\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(F030): finish canonical ai-sdk CLAUDE.md block — env example + r…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-30T19:46:49Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a48d20f5e96d9e270ea73734a33da285338b4ccd",
          "body": "…ral EU\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): v0.21.0 — F030 phase out Anthropic API default → Mist…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-30T19:38:58Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9f7a836a94180ca8728d25bfe778be7d46a1cf63",
          "body": "…econdary\n\nDEFAULT_TIER_MAP: fast/smart/powerful/vision off Anthropic → Mistral EU (Schrems II).\nfast/vision/cheap=mistral-small-latest, smart/powerful=mistral-large-latest. No default\ntier hits Anthropic (ANTHROPIC_API_KEY removed). New deepseekAdapter (direct, OpenAI-\ncompatible, DEEPSEEK_API_KEY)\n[…]\npt-in non-PII secondary; anthropic kept for\noverride-only. PII always stays on Mistral EU. CLAUDE.md tier table + mistral stub +\ntests updated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F030): phase out Anthropic API default → Mistral EU + DeepSeek s…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-30T19:38:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9309be7a9f4db4560f34e25c7292fe1b651b5e2d",
          "body": "…to-Text\n\n- F028: requestyAdapter (OpenRouter-alternative AI gateway, EU endpoint)\n- F029: Azure Speech-to-Text (transcribe) on azureAdapter, EU da-DK + phraseList\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): v0.20.0 — F028 Requesty provider + F029 Azure Speech-…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-30T13:32:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0933e17c432c362305c3c466637c0e378e8e61e9",
          "body": "… primary + DeepSeek V4 Pro secondary\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F030): plan — phase out Anthropic API default route → Mistral EU…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-30T13:26:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5c6f5209ae27312f22184e5f87482fe5661f511a",
          "body": "…EU da-DK\n\nazureAdapter.transcribe() via fast transcription (regional EU host, da-DK forced —\nVoxtral can't), per-minute cost from the response's real duration, ship-dark. Generic\nphrases? on ai.transcribe → Azure definition.phraseList (api-version 2025-10-15;\n2024-11-15 rejects it). Live-verified Danish prose; phraseList wired but unproven on\nsynthetic audio (validate on real speech). Second EU STT next to Voxtral.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F029): Azure Speech-to-Text (transcribe) + phraseList biasing — …",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-29T21:12:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a63adba636358663b1352835d872bcc185c33b38",
          "body": "… EU da-DK\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F029): plan — Azure Speech-to-Text (transcribe) on azureAdapter,…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-29T16:55:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f899c15f7a3be236198358b4abd019afe0151fd0",
          "body": "… endpoint)\n\nrequestyAdapter on the OpenAI-compatible core: 400+ models via one REQUESTY_API_KEY,\nground-truth usage.cost, ship-dark. eu:true → router.eu.requesty.ai (gateway-in-EU;\nend-to-end EU still needs an EU-region model slug). Opt-in upstream like openrouter;\nai-sdk facade unchanged.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F028): Requesty provider — OpenRouter-alternative AI gateway (EU…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-29T14:57:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1287a5316b088ea4262d08713f9040424d32f91d",
          "body": "…ay, EU endpoint)\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F028): plan — Requesty provider (OpenRouter-alternative AI gatew…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-29T11:35:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a28debfbc342563dec829577ac1e0bfba1478411",
          "body": "…text\n\nThrowaway preview clips (cardmem F160 read-aloud use-case text) so Christian can\near-A/B the Azure neural Danish voices in cardmem's Chat→Artifacts. Generated live\nvia the F026 azureAdapter (swedencentral). Removable after the voice pick.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F026): Christel + Jeppe A/B samples of cardmem's daily-summary …",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-25T23:54:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "97717d179864e4c721d049dbd63ef3a37d874ae6",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): v0.19.0 — AI Pricing API (F027)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-23T10:24:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "07d71d9439da86e0293dae00172293be635ab6f2",
          "body": "getModelPrice/listModelPrices/findModelPrices/priceCall/pricingGeneratedAt over all\n~346 inventory models, browser/edge-clean (no fs/bun:sqlite). gen-pricing.mjs trims\ninventory.json into a bundled pricing-data module; curated PRICING overlaid as\nauthoritative. Lets Trail (edge) read exact prices without reaching the ai-sdk session.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F027): AI Pricing API — @broberg/ai-sdk/pricing subpath",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-23T10:24:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6ac564f2ebc84c57c5ec7d6e04cf933d0dad710f",
          "body": "…m package)\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F027): plan — AI Pricing API (model prices queryable from the np…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-23T10:18:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "99ef32408276fd31ee913ab89e47675d74182bfb",
          "body": "…ral TTS\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): v0.18.0 — F025 cost read-back client + F026 Azure Neu…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-23T10:13:49Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6ca38c44a7d1a235490b981895c0fa91c8e6bb16",
          "body": "azureAdapter (Azure Speech, region-pinned EU, SSML, ship-dark) reachable via\noverride:{provider:'azure'}. Curated da-DK roster (3F+3M: Christel/Jeppe native +\nseraphina/ava/florian/andrew multilingual) exposed via listAzureDanishVoices().\nSpeaking-rate control (ai.tts rate) + per-voice defaultRate (Christel 0.85).\nCost-tracked per-char. ElevenLabs stays the ai.tts default. 285/285 green.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F026): Azure Neural TTS provider (EU da-DK) behind ai.tts",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-23T10:11:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4841e7b381838edb0b793c4ba73dd2fa93e1ebb2",
          "body": "…rate control\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F026): Christel speed samples (rate 0.9 + 0.85) — SSML prosody …",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-23T10:04:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "56baecc9be6db9a554c6ca831b3e72ed6bcbcd97",
          "body": "3 female (christel native, seraphina/ava multilingual) + 3 male (jeppe native,\nflorian/andrew multilingual). Same Danish sentence for a fair A/B. Kept in-repo as testimonials.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F026): 6 Azure da-DK voice samples (3F + 3M) for selection",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-23T09:58:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ad4c53675c815615cd307c05fa54daace7c99df4",
          "body": "… listen\n\nThrowaway preview clips so Christian can ear-A/B the Azure neural Danish voices.\nGenerated live via the F026 azureAdapter (swedencentral). Can be removed after the voice pick.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F026): Azure da-DK TTS voice samples (Christel + Jeppe) for A/B…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-23T09:52:24Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "59d7e748571d280ec9d0cfa0a77f4095ad2a243b",
          "body": "[skip ci]",
          "is_bot": true,
          "headline": "docs(F026): plan — Azure Neural TTS provider (EU Danish) behind ai.tts",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-19T10:24:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c5932195717372c937473e8c8cc4baf7d47abd20",
          "body": "… docs\n\nupmetricsCostClient reads your own rolled-up cost (summary/timeseries,\nmicro-USD, per-tenant groupBy) from Upmetrics' COST-API — the read companion\nto upmetricsSink. Positions upmetrics as the canonical cost method (#1);\ndiscord/sqlite are extras. Browser-clean (pure fetch, no bun:sqlite).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F025): Upmetrics cost read-back client + canonical cost-delivery…",
          "author_name": "Aidan Nielsen",
          "author_login": null,
          "committed_at": "2026-06-19T10:14:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fd83497eac171f1da95958a841da5afc1bef3790",
          "body": "…ack client\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F025): plan — Upmetrics as canonical cost-delivery + cost read-b…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-18T16:59:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "09a274198c6d94e7a6c0e1c28e43714543a61c7d",
          "body": "…hed to scene (v0.17.1)\n\nChristian's preference: generated dialogue is the weak link (esp. non-English) and\nhe won't use it; environment-matched ambient sound IS wanted. So every ai.animate\nprompt now gets a default directive appended — \"No spoken dialogue, no talking, no\nvoiceover. Include natural \n[…]\nso it applies to both the Veo and fal routes. Just describe\nthe scene; the SDK adds the audio guidance. 270 tests green; .env-parked CI parity.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F024): ai.animate audio default — no speech, ambient sounds matc…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-16T18:16:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ffb9ad0d74fb291ca9dca229a1c9fc8cbb80b0a1",
          "body": "…-verified)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(F024): record Veo-direct-via-Gemini pivot (shipped v0.17.0, live…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-16T18:04:15Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4fd1bd21fdd3dbeebbb1a02b107c9db9998dac70",
          "body": "….17.0)\n\nLive-verified end-to-end: a still portrait → an 8s 1080p clip through createAI().\n\n- ai.animate({ image, prompt?, durationSec?, resolution? }) → { url, bytes?, mimeType?, usage }.\n  New ProviderAdapter.animate? + Capability:\"animate\" + AnimateRequest/Result + schema.\n- DEFAULT route = Veo 3\n[…]\nata); durationSeconds is a number (not string).\n- Consent-gated, US-hosted (EU route deferred, F024.4). 270 tests green; .env-parked CI parity.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F024): ai.animate image-to-video — Veo 3.1 direct via Gemini (v0…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-16T18:02:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d0ab90c55e60a6e1d1314cffcd40cc8cd8b483df",
          "body": "…ck, consent-gated\n\nInvestigation result: BFL does NOT do video (probed api.eu.bfl.ai /v1/{video,\nflux-video,i2v,...} → 404; /v1/video 403, image-only confirmed). Landscape:\nVeo/Grok/Runway/Luma = US, Kling/Seedance/Hailuo = CN, fal.ai aggregator = US.\n\nPolicy (Christian): EU-preferred when a route \n[…]\n chain. New ai.animate capability\n(ai.video is taken by F019 understanding). Interim plan with open Qs (first fal\nmodel, naming) for Christian.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(F024): plan — image-to-video (ai.animate), EU-first/US-CN-fallba…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-16T17:16:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "eac279a47a946e8d4151adc2990779d3631c3623",
          "body": "bflCredits({ apiKey?, baseUrl?, fetch? }) → { credits, usd } — standalone export\n(not on the AiClient facade; BFL-specific). Reads GET /v1/credits (EU-pinned),\n1 credit = $0.01. For budget-gating before a generate call.\n\nBFL has NO pre-flight pricing endpoint (probed /v1/pricing|cost|estimate|\ncalcu\n[…]\n014, per-MP) + the real per-call cost are the honest answer.\n\n- bfl.test.ts: bflCredits EU-pin + USD conversion + missing-key throw. 267 green.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F023.6): bflCredits() balance check + honest pricing docs (v0.16.0)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-16T17:00:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9787a4df5a2b9b331d4f1f78c71f00a6f4df7c37",
          "body": "…e({referenceImages}) via BFL FLUX 2 (v0.15.0)\n\nBFL flux-2-max/pro support multi-reference generation: 1–8 reference photos\nstraight into the generate call, no finetune/training step. Live-verified\nend-to-end on api.eu.bfl.ai (and on a real face through createAI()): EU-resident\nwhole chain (submit a\n[…]\n (table/section/changelog) updated; supersedes the manual\n  dashboard step for the common case (finetune stays for high-volume single subject).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F023.5): EU-resident person portraits with NO training — ai.imag…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-16T16:27:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "aac823cacc59af8058b4d5d6757f3cdbe50e0d1b",
          "body": "…({finetune}) (v0.14.0)\n\nDelt flow: BFL retired finetune-CREATE from its public API (live-verified —\nPOST /v1/finetune 404s on every region while inference paths 422; legacy\neu1/us1 hosts TCP-dead), so a subject is trained once manually in dashboard.bfl.ai\n(mode=character, EU region); the SDK automa\n[…]\nty run clean.\n- F023 plan-doc reshaped BLOCKED → SHIPPED(delt flow) + manual-training SOP; API.md\n  rows + v0.14.0 changelog + governance note.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(F023): EU-resident person/portrait generation via BFL — ai.image…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-16T15:51:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4b5c4de1ae85e097c454648c30d5f5ae55cc028e",
          "body": "… (all regions)\n\nLive-probed api.{eu,us,}.bfl.ai before building: the EU endpoint runs + manages\nfinetunes (inference flux-pro-*-finetuned, my_finetunes, finetune_details,\ndelete_finetune all present) but NO create/train endpoint exists on any region's\npublic OpenAPI (/v1/finetune 404s everywhere; e\n[…]\nfinetune can't be built; create is dashboard-only.\nF023 blocked pending Christian's re-decision (split dashboard+API / self-host EU / fal-DPA).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(F023): BLOCKER finding — BFL API has no finetune-create endpoint…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-16T15:19:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c591a82fb68f52993aaf9ac2c6bad22112419f4f",
          "body": "…PR-safe)\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F023): plan — Person/Portrait LoRA via Black Forest Labs (EU, GD…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-16T15:06:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c0e78b5e565747e8dd44955a5bee065cc03539b8",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F149): sync canonical CLAUDE.md sections (scaffold v2 reuse-first)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-15T21:00:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1ded1e76e3955642c675aae8683c3cd90127e0ae",
          "body": "…image (v0.13.1)\n\nVerified against Google's official ai.google.dev/gemini-api/docs/pricing (standard\npaid tier, 1K/1024px output):\n- ADD gemini-3.1-flash-image = $0.067/image (Google's recommended migration target\n  for the deprecated Imagen 4 endpoints; resolution-tiered $0.045/0.067/0.101/0.151\n  \n[…]\nNo 404 risk.\n\nTest switched to gemini-2.5-flash-image (the real $0.039 model) for the per-image\ncost assertion. 255 tests green; dist verified.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(gemini): correct gemini-3-pro image price + add gemini-3.1-flash-…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-15T19:48:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d66145f469070960f144cdc9879665b447cbf4bf",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(F149): sync canonical CLAUDE.md sections (scaffold v2 reuse-first)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-15T05:55:21Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7a900a88797f95ea46530a2819fe3fdd22ede8b1",
          "body": "…st (v0.13.0)\n\nChristian policy shift (relayed via cardmem #5174):\n- `claude -p` is retired fleet-wide (agent-CLI transport moved to Layer 1 /tmux\n  via buddycloud). The `cheap` tier no longer routes through it.\n- `cheap` now defaults to mistral-small-latest over HTTP — cheapest-that's-good-\n  enoug\n[…]\nmem F149.4\nbackfills into all 15 repos) + README + API.md changelog + tier-map test.\n255 tests green; dist verified cheap→mistral-small-latest.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(routing): retire claude -p as cheap default → mistral-small-late…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-14T23:42:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1c88fa97f7840089d5c1a33c9b61352f73ae2c17",
          "body": "…gle source for cardmem F149.3 scaffold)\n\ncardmem scaffolds a fixed '## @broberg/ai-sdk — the AI/LLM gateway (MUST)'\nsection into every new broberg.ai repo (F149). Per Christian's one-source rule,\nthe canonical text lives HERE; cardmem's scaffolder (F149.3) pulls this file\nverbatim instead of a pasted copy, so model IDs / tiers update in one place.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: canonical @broberg/ai-sdk AI/LLM-gateway CLAUDE.md section (sin…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-14T22:05:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "653635cbbf09b76187de39d28f8d1dcb0bb6034a",
          "body": "…stry (v0.12.0)\n\ncardmem build-verified that `import { listModels } from \"@broberg/ai-sdk\"`\nhard-fails in a Vite/Rollup browser build: the root barrel transitively pulls\nbun:sqlite (budget-store, sqlite-sink) + node:zlib (fal). That forced UI pickers\nthrough a per-repo server bridge — a fetch, defea\n[…]\nd. Subpath returns the Fable-suspended row byte-identical to the root\n(one source, no drift). 255 tests green; tsc clean. Root entry unchanged.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(availability): F022.5 browser-clean subpath @broberg/ai-sdk/regi…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-13T10:40:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5d589ba91d64a83f494efade0529558f909ed4e3",
          "body": "…try + refresh + listModels (v0.11.0)\n\nA runtime safety-net so a suspended/removed model never reaches a user as a raw\nprovider error (triggered by Anthropic's 2026-06-12 global Fable 5 / Mythos 5\nsuspension; requested via cardmem #4841, spawn-time contract refined #4842).\n\n- resolveModel(requested,\n[…]\n suspended\n  primary before dispatch; default off → existing call sites byte-identical.\n\n255 tests green; built dist smoke-verified end-to-end.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(availability): F022 Model Availability Harness — resolve + regis…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-13T10:20:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b6d3a94a9529e61b9ff0ebbee0849dacd3ad87d7",
          "body": "…lve) per cardmem #4842\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F022): bake in spawn-time hot-path contract (sync, zero-I/O reso…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-13T10:13:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d5f7319d3fc9fca9dd80c9511ee89e09c182ee1b",
          "body": "…efresh + listModels)\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F022): plan — Model Availability Harness (resolve + registry + r…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-13T10:12:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "48aee3c464dd1ebca05fd3c49fc7e4fb5ead8a38",
          "body": "…o ai.vision/video (v0.10.5)\n\nTwo real gaps caught by cms (#4423) building a Lens vision-critic:\n\n1) chat() did `text = msg.content ?? ''` — but reasoning/multimodal models\n   (magistral etc.) can return `content` as an ARRAY of blocks, which fell\n   through and crashed the consumer with 'text.repla\n[…]\nstem message before the image/video message.\n\n227 suite green (array-content coercion + null-content + vision system-prepend);\ntypecheck clean.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(vision/chat): coerce reasoning-model array content + add system t…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-11T07:18:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9072b0c51f0fd313751a6542c60d53d649e7b75d",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-10T15:29:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bca50f1e8b9ffc90f17c9b2197545db17f3ac5a3",
          "body": "Self-description in the canonical locked form (YAML header + 8 prose sections,\nmatching webhousecode/buddy/RESEARCHTARGET.md) so the Research Adapter worker can\nroute + pre-filter articles by interest before waking this session, and the\nreceiving cc can judge fit fast. Interests: LLM models/pricing, provider APIs,\ncost optimization, multimodal, GDPR/EU hosting, model routing.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: add RESEARCHTARGET.md (F125 Research Adapter fleet convention)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-09T16:17:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ccc8e029b954303fe0c7a45eb22c24edee117ca6",
          "body": "…v0.10.4)\n\ntoMessages early-returned input.messages and never reached the system-prepend\nbranch, so ai.chat({ system, messages }) silently DROPPED the system prompt — a\n'return ONLY JSON' instruction never reached the model. Affected every consumer\npassing both system + messages (caught by cms #4234\n[…]\ns).\n\n3 facade tests (system+messages preserved, no dup when caller leads with system,\nprompt-path unchanged); 224 suite green, typecheck clean.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(chat): keep top-level `system` when `messages` is also supplied (…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-08T23:46:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "38a0e2a798a5939112cf7f681e3cdbb6d922b923",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-08T21:46:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e48dcc334ce14fc130db1ee7e361b75f092a0aa5",
          "body": "Applied canonical cardmem hooks/skills/settings via the daemon (F075.3).",
          "is_bot": false,
          "headline": "chore(cardmem): update .claude templates to 325da84d",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-08T11:47:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "07ff78768cb98e2824b011df48720c7e5e3f7103",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-07T23:51:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c81c7d443935a88ddf35d7bc9b305808264244e1",
          "body": "…1.4, v0.10.3)\n\nfal's NSFW safety-checker occasionally false-positives on clean LoRA output and\nreturns a fully black image (has_nsfw_concepts[0]=true). sa's F021 pilot saw ~1/8.\nai.image({ retryOnBlack:true }) now detects the flag in the fal adapter and\nre-rolls ONCE with a fresh seed; both generat\n[…]\nmage behaviour unchanged.\n\n219→221 suite green (retry re-rolls + bills ×2; no-flag path untouched), typecheck\nclean. Plan-doc updated (F021.4).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(fal): ai.image retryOnBlack — re-roll fal NSFW black images (F02…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-07T18:55:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d70e99c6453c6e8eb88cdb53600cba7a18f9af80",
          "body": "…IFIED (F021, v0.10.2)\n\nRoot cause (found via a real run on Christian's test key): fal REJECTS a data:\nURI for images_data_url ('Invalid URL: URL too long'). The job reported COMPLETED\nbut the result was that 422 download error — which 0.10.0 mis-reported as 'no\ndiffusers_lora_file.url'. fal's real \n[…]\n$0.025\n219 suite green (storage initiate+PUT mocked; zip round-trip) + typecheck clean.\nscripts/verify-trainstyle.ts added for re-verification.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(fal): upload training zip to fal storage — ai.trainStyle LIVE-VER…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-07T18:33:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f2eee01e2a23d028084d623f76893aacec9ff824",
          "body": "….10.1)\n\nsa's live pilot hit 'no diffusers_lora_file.url in result' — fal's real training\nresponse shape didn't match the offline mock. fal's official OpenAPI confirms the\nfield IS diffusers_lora_file, so the real cause is a wrapper / non-OK result body,\nnot a rename. Fixes:\n\n- extractTrainedFiles()\n[…]\ned: 219 suite green (incl. extractTrainedFiles shape-variance + a\nraw-shape-error test); typecheck clean. Still no FAL key here → sa re-pilots.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(fal): robust ai.trainStyle output parsing + diagnostics (F021, v0…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-07T18:17:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b5f5dd6b952c5b73bc9fb11f2107022818fb0bbf",
          "body": "…v0.10.0)\n\nNew reusable capability: train a brand/style LoRA from a set of images, then\ngenerate in that style every time. Backed by fal flux-lora-fast-training (train)\n+ flux-lora (inference).\n\n- ai.trainStyle({ images, isStyle?, triggerWord?, steps? }) → { loraUrl, configUrl, usage }\n- ai.image({ \n[…]\nrity). NB no FAL_KEY in this session → sa runs the live $2\npilot train on the 8 illustrations. Plan: docs/features/F021-lora-style-training.md.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(fal): ai.trainStyle LoRA style-training + ai.image loras (F021, …",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-07T18:00:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "55c588efb96ffd77c24b34543673fcb8f7e5161d",
          "body": "…+ ai.image loras)\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F021): plan — fal LoRA style-training capability (ai.trainStyle …",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-07T17:52:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "846d3d1e763eb280e4e86f7cd557f93ad289620c",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-06T22:49:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "02c6e3d7d8997d2216e2ac39a6484f194eb1e9a8",
          "body": "… (v0.9.1)\n\nDeepSeek made the 75%-off promo permanent (2026-05-22): V4-Pro $0.435/$0.87,\nV4-Flash $0.098/$0.197 per 1M — matches OpenRouter /api/v1/models 1:1. Adds both\nto the pricing table (keyed openrouter:deepseek/deepseek-v4-*) so cost is never\nlogged $0, + a unit test and a live smoke script.\n\n[…]\nat goes API-billed on 15 Jun).\n\nInventory.json already carried both V4 entries, so the Model Advisor knew them;\nthis closes the cost-table gap.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(pricing): DeepSeek V4 via OpenRouter — official permanent prices…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-06T19:40:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "eb164b2c91e9ba0824ff40203c975e8a222807fc",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: gitignore *.bak backup artifacts",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:57:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1ae9d99ec3de2f4f9c90787ac90c7109bdcc814b",
          "body": "Close the F020.3/F020.4 doc-AC gap surfaced during board-sweep auto-review:\nai.tts had no capabilities-table row and neither capability had a usage\nsection. Adds ai.tts row, a Podcast & speech section, and the named Danish\nvoice registry (soren/jesper/mads/noam/camilla).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(F020): document ai.tts + ai.podcast usage + named Danish voices",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:47:23Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b69b680ef94b507d430a35affc79d19d10cd5e13",
          "body": "…rch automation\n\nai.embedding (mistral-embed) + ai.transcribe (Voxtral) + ai.batch.* (50% async,\nF016.1/.3/.5). Monthly model-research GHA workflow + inventory cheap-model enrichment\n(F014.4/.5, F017.5/.6). All live-verified where the test keys allow (batch needs\nMistral billing; Voxtral is non-Danish).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.9.0 — Mistral embeddings/transcribe/batch + monthly resea…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:38:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4af82fcc7d11786f99d12cdbd64589eb7115c5a0",
          "body": "ai.batch.submit({requests:[{customId,prompt}]}) → {jobId,status}; status(jobId);\nresults(jobId). Mistral: upload JSONL via /v1/files (purpose=batch) → POST /v1/batch/jobs\n→ poll /batch/jobs/{id} → download /files/{output}/content (JSONL → {customId,text}).\nProviderAdapter.batchSubmit/Status/Results.\n[…]\nistral Batch API requires account billing (402 'enable billing')\n— the test key lacks batch access; full round-trip is async (≤24h) regardless.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(mistral): ai.batch.* — async batch chat at 50% cost (F016.1)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:38:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "92972cac52f9b6c5a35939f16e9f11ee81d1e718",
          "body": "…f org blocks Actions PR-create\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci(research): resilient PR step — fall back to branch + compare URL i…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:19:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "de66987a79558d6cf7f52d20ee8fd6e1971e4c28",
          "body": "…lert (F014.4/.5 + F017.5/.6)\n\nF014.4 + F017.5 — .github/workflows/research-models.yml: monthly (cron) + manual\n(workflow_dispatch). Fetches the live catalogue (OpenRouter public, no key), runs\nthe drift report, rebuilds inventory.json, and opens a PR when the inventory changes\nSUBSTANTIVELY (timest\n[…]\ns the build).\n\nLIVE-VERIFIED: --enrich 3 → real tags+summaries (e.g. liquid/lfm-2 → reasoning,coding,\nedge,fast). typecheck clean, suite green.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(research): monthly GHA workflow + inventory enrichment + drift a…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:17:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3bf78845f454fc3dfccf44656e0ea76cc3c4e926",
          "body": "ai.embedding via mistral-embed/codestral-embed (POST /v1/embeddings, per-token).\nai.transcribe via Voxtral (POST /v1/audio/transcriptions multipart, voxtral-mini-latest,\nper-minute $0.002). Both optional ProviderAdapter methods on the mistral adapter.\n\nLIVE-VERIFIED: mistral-embed → 1024-dim vectors\n[…]\norrect text ($0.000167). NB Voxtral does NOT support\nDanish (ar/en/de/es/fr/hi/it/nl/pt/zh/ru/ko/ja only) — Danish transcription needs Whisper.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(mistral): embeddings (F016.5) + Voxtral transcribe (F016.3)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:14:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c447d0888d52afc14cfee5ad0e97cc35678652f4",
          "body": "…tions)",
          "is_bot": false,
          "headline": "chore(cardmem): commit scaffolded onboarding config (.claude + conven…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:09:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a18fb721289329b5abd99ecdcee165ba106078fe",
          "body": "Instant multi-voice podcasts: ai.podcast({script,voices}) → one episode MP3 via\nElevenLabs Text-to-Dialogue (eleven_v3). ai.tts({text,voice}) single voice. Named\nDanish voices (soren/jesper/mads/noam/camilla). Apps send a finished manuscript →\nfinished episode in one call. Live-verified (native Danish MP3s, per-char cost).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.8.0 — ai.podcast + ai.tts via ElevenLabs (F020)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-05T00:00:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b6540ee8ea3cb008d82dcbdb986c7a212290c951",
          "body": "…20.4)\n\nF020.3 — ELEVENLABS_DANISH_VOICES registry (soren/jesper/mads/noam/camilla → voiceId)\n+ resolveVoice(); ai.podcast voices map now accepts friendly names or raw IDs.\nF020.4 — ai.tts({text, voice}) single-voice capability over ElevenLabs\n(eleven_multilingual_v2, good Danish); ProviderAdapter.t\n[…]\nIFIED: ai.tts({voice:'soren'}) → real 81KB Danish MP3 ($0.012). Named-voice\nresolution + ai.tts unit-tested. Full suite green, typecheck clean.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(podcast): named Danish voices + ai.tts single-voice (F020.3 + F0…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-04T23:49:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "947ac5a7c1ac11a9b24fa747c3c5f6a608746c8c",
          "body": "…bs (F020.1 + F020.2)\n\nNew ai.podcast({script:[{speaker,text}], voices:{speaker->voiceId}}) → one\nmulti-voice MP3 episode via ElevenLabs Text-to-Dialogue (eleven_v3), per-character\ncost. ElevenLabs provider adapter (dialogue + tts + listVoices). 'podcast' capability,\ndefault route elevenlabs/eleven_\n[…]\nequire\na PAID ElevenLabs plan (free-tier 402 on library voices via API); the 25 default voices\nwork on free + eleven_v3 speaks the Danish text.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(podcast): ai.podcast() instant multi-voice podcasts via ElevenLa…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-04T23:42:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3a0c75749d3e0fa7d44084d116bb435242e8ac73",
          "body": "…abs)\n\n[skip ci]",
          "is_bot": true,
          "headline": "docs(F020): plan — instant podcast generation (ai.podcast via ElevenL…",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-04T23:31:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "31099c3cd61674dcfbd84e593dc8632a602da5e3",
          "body": "ai.ocr({document}) → {pages:[{index,markdown}], usage} (mistral-ocr, per-page) and\nai.moderate({input}) → {results:[{flagged,categories,categoryScores}], usage}\n(mistral-moderation, per-token). Both live-verified. FysioDK-launch-critical:\npatient-document OCR + moderate-client-notes-before-DB, EU/GDPR-hosted.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.7.0 — ai.ocr + ai.moderate via Mistral (F016.2 + F016.4)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-04T23:19:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f6d1b462ac5b4fcbbe83d56cd4cf1ec270ddc5bb",
          "body": "… F016.4\n\nai.ocr({document, mimeType?}) → {pages:[{index,markdown}], usage} via Mistral\n/ocr (mistral-ocr-latest), $0.002/page. ai.moderate({input}) → {results:[{flagged,\ncategories,categoryScores}], usage} via /moderations (mistral-moderation-latest),\nper-token ($0.10/M). Both optional ProviderAdap\n[…]\n Danish →\nflagged=false, threat → flagged=true (violence_and_threats 0.997), $0.0000117.\n200 tests green, typecheck clean. docs/API.md updated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(mistral): ai.ocr (per-page) + ai.moderate (per-token) — F016.2 +…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-04T22:40:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8c63cfb1f5250a31742d8a95b9469cba21aa6983",
          "body": "The 'sends inline + prices' + 'default tier' tests used createAI() with the\ndefault keyless gemini adapter — resolveKey() threw 'API key not set' in CI (no\n.env). Register geminiAdapter({apiKey:'test-key'}) instead; verified green with\n.env moved aside (195/195). Fixes the v0.6.0 publish-workflow failure.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(video): key the gemini adapter explicitly so CI (no .env) passes",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-04T21:17:40Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bafbd34391ae47326a2451bfe39ac036a42b4d6b",
          "body": "…der/prices\n\nai.video() ships: new video ContentPart + capability + 'video' tier\n(gemini-2.5-flash-lite). Live-verified on a real clip (gemini-flash-lite, gemma-4,\nnemotron). Also bundles the unreleased v0.5.x work: official Mistral provider +\nmistral.ai prices (F015), gemini-direct $0-cost fix + OpenRouter pricing drift fix.\ndocs/API.md documents ai.video.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: v0.6.0 — ai.video native video vision (F019) + Mistral provi…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-04T21:15:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6a1ac6f43f508476286ac1c7f5d81da09526c17b",
          "body": "…nemotron)\n\nai.video() proven end-to-end against the real OpenRouter API: both gemma-4\n($0.0003) and nvidia-nemotron ($0, free) described a real 2MB clip sent inline as\na base64 video_url data-URL. Confirms the openai-compatible video_url wire shape.\nAdds scripts/smoke-video.mjs for repeatability. Gemini-direct path (F019.2) works\nthe same once that key has credit.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(video): F019.3 OpenRouter video LIVE-verified (gemma-4 + nvidia-…",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-04T21:10:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cc5da12e89eca6f7ddeec64456fa4b1dfc30a2b6",
          "body": "New 'video' ContentPart + ai.video({video, prompt, override?}) capability,\nrouted through the vision message path. Default 'video' tier → gemini-2.5-flash-lite\n(priced 0.1/0.4). Gemini adapter sends video inline as base64 (video mime); >~20MB\nclips need the Files API (not yet handled). OpenAI-compat\n[…]\n-flash-lite on the real clip) PENDING — the Gemini key's prepay\ncredits are depleted (429). Test clip compressed to 2MB (inline-ready) at /tmp.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(video): ai.video() native video-vision capability (F019.1 + F019.2)",
          "author_name": "Christian Broberg",
          "author_login": "cbroberg",
          "committed_at": "2026-06-04T20:34:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7b6cfad3792bf50a87f0d8e59eea478619d5ccbc",
          "body": "[skip ci]",
          "is_bot": true,
          "headline": "docs(F016): add embeddings (F016.5) + classifier (F016.6) stories",
          "author_name": "projects[bot]",
          "author_login": null,
          "committed_at": "2026-06-04T20:24:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 39,
      "commits_last_year": 179,
      "latest_release_at": "2026-07-19T12:55:52Z",
      "latest_release_tag": "v0.25.1",
      "releases_from_tags": true,
      "days_since_last_push": 6,
      "active_weeks_last_year": 8,
      "days_since_latest_release": 6,
      "mean_days_between_releases": 2.9
    },
    "community": {
      "has_readme": true,
      "has_license": false,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 25,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "@broberg/ai-sdk",
          "exists": true,
          "license": "FSL-1.1-Apache-2.0",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@broberg/ai-sdk",
          "is_deprecated": false,
          "latest_version": "0.25.1",
          "repository_url": "https://github.com/broberg-ai/ai-sdk",
          "versions_count": 40,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 3525,
          "first_published_at": "2026-06-02T08:09:43.990000Z",
          "latest_published_at": "2026-07-19T22:38:34.392000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 6
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 0,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_stars": 0,
        "collected_at": null
      },
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 29347,
      "source_files_sampled": 130,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 38283
    },
    "dependencies": {
      "manifests": [
        "package.json"
      ],
      "advisories": {
        "error": null,
        "scope": "published_package",
        "source": "osv",
        "findings": [],
        "collected": true,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 1,
        "malicious_count": 0,
        "assessed_package": "npm:@broberg/ai-sdk@0.25.1",
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm"
      ],
      "dependencies": [
        {
          "name": "zod",
          "manifest": "package.json",
          "ecosystem": "npm",
          "version_constraint": "^3.23.8"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 1,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "cbroberg",
          "commits": 117,
          "avatar_url": "https://avatars.githubusercontent.com/u/486755?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "publish.yml",
        "research-models.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "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": null,
            "reason": "no pull request found",
            "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/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 6,
            "reason": "project has 2 contributing companies or organizations -- score normalized to 6",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 0,
            "reason": "license file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "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": 9,
            "reason": "1 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "54389c48e062f418d8b3e34688388d7cc6e7a61c",
        "ran_at": "2026-07-25T22:47:32Z",
        "aggregate_score": 3.2,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-19T22:38:38Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-06-04T16:03:24Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/broberg-ai/ai-sdk",
    "host": "github.com",
    "name": "ai-sdk",
    "owner": "broberg-ai"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 52,
      "inputs": {
        "security": 46,
        "vitality": 71,
        "community": 24,
        "governance": 53,
        "engineering": 62
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 71,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "commits_last_year": 179,
              "human_commit_share": 0.83,
              "days_since_last_push": 6,
              "active_weeks_last_year": 8
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 6 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "8/52 weeks with commits",
                "points": 5.5,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 8
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "179 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 179
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 88,
            "inputs": {
              "releases_count": 39,
              "latest_release_tag": "v0.25.1",
              "releases_from_tags": true,
              "days_since_latest_release": 6,
              "mean_days_between_releases": 2.9
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "39 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 39
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 6 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~2.9 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 2.9
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 24,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 0,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "0 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "critical",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "has_readme": true,
              "has_license": false,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "no license file detected",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "license_absent",
                    "params": {}
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "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": 59,
            "inputs": {
              "packages": [
                "@broberg/ai-sdk"
              ],
              "dependents": null,
              "ecosystems": "npm",
              "total_downloads": null,
              "monthly_downloads": 3525
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "3,525 downloads/month across npm",
                "points": 47.3,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 3525,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "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": "moderate",
        "name": "Sustainability & Governance",
        "value": 53,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 16,
            "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 2 contributing companies or organizations -- score normalized to 6",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "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": 72,
            "inputs": {
              "merged_prs": 1,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 0
            },
            "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": "1/1 decided PRs merged",
                "points": 38.2,
                "status": "met",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 1,
                      "decided": 1
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 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": 40,
            "inputs": {
              "followers": 1,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "broberg-ai",
              "public_repos": 10,
              "account_age_days": 102
            },
            "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": "1 followers of broberg-ai",
                "points": 2.2,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 1,
                      "login": "broberg-ai"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "10 public repos, account ~0 yr old",
                "points": 8.1,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 10
                    }
                  },
                  {
                    "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": [
                "@broberg/ai-sdk"
              ],
              "ecosystems": "npm",
              "any_deprecated": false,
              "min_days_since_publish": 6
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on npm",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "npm"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 6 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "40 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 40
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 62,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "2 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 46,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 32,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 3.2
            },
            "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": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "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/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 2 contributing companies or organizations -- score normalized to 6",
                "points": 1.5,
                "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": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "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": "1 existing vulnerabilities detected",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "dependency_advisories",
            "band": "excellent",
            "name": "Dependency advisories",
            "note": "Excluded from scoring (no data or not applicable): No advisories left outstanding. Remaining weights renormalized. Matched the npm:@broberg/ai-sdk@0.25.1 runtime dependency closure — what installing the published package pulls in — 1 packages. Reachability is not analyzed.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "no_advisories_left_outstanding"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              },
              {
                "code": "advisories_scope_published",
                "params": {
                  "package": "npm:@broberg/ai-sdk@0.25.1",
                  "assessed": 1
                }
              },
              {
                "code": "advisories_reachability",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "source": "osv",
              "advisories": 0,
              "affected_packages": 0,
              "assessed_packages": 1,
              "unassessed_packages": 0,
              "affected_by_severity": "none",
              "direct_affected_packages": 0
            },
            "components": [
              {
                "key": "direct_dependencies_free_of_known_advisories",
                "name": "Direct dependencies free of known advisories",
                "detail": "no direct dependency carries a known advisory",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "no_direct_advisories",
                    "params": {}
                  }
                ],
                "max_points": 35
              },
              {
                "key": "indirect_dependencies_free_of_known_advisories",
                "name": "Indirect dependencies free of known advisories",
                "detail": "no indirect dependency carries a known advisory",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "no_indirect_advisories",
                    "params": {}
                  }
                ],
                "max_points": 25
              },
              {
                "key": "no_advisories_left_outstanding",
                "name": "No advisories left outstanding",
                "detail": "no advisory carries a publication date",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_no_publication_date",
                    "params": {}
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "malicious_dependencies",
            "band": "excellent",
            "name": "Malicious dependencies",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "source": "osv",
              "meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
              "packages": [],
              "red_flag": false,
              "assessed_packages": 1,
              "malicious_packages": 0,
              "direct_malicious_packages": 0,
              "withdrawn_malicious_packages": 0,
              "installable_malicious_packages": 0
            },
            "components": [
              {
                "key": "no_dependency_reported_as_a_malicious_package",
                "name": "No dependency reported as a malicious package",
                "detail": "no dependency is reported as a malicious package",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "no_malicious_dependencies",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 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": "moderate",
        "name": "AI Readiness",
        "value": 68,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 38283
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "83 of 83 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 83,
                      "sampled": 83
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 43,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "tsconfig.json"
              ],
              "agent_commit_share": 0.67,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "67 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 67,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "TypeScript",
              "largest_source_bytes": 29347,
              "source_files_sampled": 130,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "TypeScript (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "TypeScript"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/130 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 130,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-25T22:47:37.985501Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/b/broberg-ai/ai-sdk.svg",
  "full_name": "broberg-ai/ai-sdk",
  "license_state": "absent",
  "license_spdx": null
}

Las puntuaciones son señales, no garantías. Reflejan prácticas públicamente visibles en GitHub; no son una auditoría de código ni una garantía de seguridad.

Los datos ausentes se excluyen y los pesos se renormalizan; nunca se puntúan como cero. La metodología es versionada y abierta: métricas v1.13.0, esquema v0.27.0 — metodología completa · wiki de métricas.

Cómo se sitúa un resultado dentro del registro general: estadísticas agregadasnpm.