公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-25 22:47 UTC

broberg-ai / ai-sdk

@broberg/ai-sdk — config-wrapper SDK

TypeScript未检测到许可证★ 0 星标⑂ 0 复刻始于 2026年6月在 GitHub 上查看 ↗

broberg-ai/ai-sdk 的健康指数为 100 分中的 52 分,处于「中等」区间。 其得分最高的类别是Vitality(71/100),最低的是Community & Adoption(24/100)。 最近一次更新在 6 天前。 近期的大部分工作由 1 位贡献者完成。

52
总分 / 100
中等

软件健康指数

指标归入加权类别,统一采用 1–100 量表。总体分先取类别加权平均;当公开证据触发高风险司法辖区政策时,评级会按政策调整,并设置 49(有风险)的上限。AI 就绪度不计入总体分。

52
优秀85-100堪称典范;基本满足所有检验标准
良好70-84健康;仅有轻微不足
中等50-69可接受,但存在明显不足;建议进行审查
存在风险30-49存在重大薄弱环节;采用时应保持审慎
危急1-29问题严重(项目被弃置、仅有单一维护者、缺乏基本工程规范)
活力社区与采用可持续性与治理工程质量安全AI 就绪度

评分画像

每条轴代表一个类别。形状比平均值更重要——健康的对象会填满整个图形,而“一峰一谷”式画像意味着某一维度的优势正掩盖另一维度的风险。

所有权

1 关注者10 个公开仓库始于 2026年4月

该仓库由组织支持——共同承担、可问责的托管责任,可延续于任何单一维护者之后。

软件包生态系统

注册表软件包版本月下载量版本数最近发布
npm@broberg/ai-sdk0.25.13,525406 天前

按类别列示的指标

活力

项目是否仍有生命——是否仍在编写代码,是否仍在发布版本?

71良好 · 占总体的 22%
评分方式
36/36推送新近度 — 最近一次推送于 6 天前
5.5/36提交节奏 — 52 周中有 8 周有提交
18/18提交量 — 最近一年 179 次提交
0/10OpenSSF Scorecard:Maintained — project was created within the last 90 days. Please review its contents carefully
所用输入
commits_last_year179
human_commit_share0.83
days_since_last_push6
active_weeks_last_year8

发布纪律

88优秀
评分方式
16.2/27有发布版本 — 39 个版本标签(无 GitHub 发布版本)
36/36发布时效 — 最近一次发布版本于 6 天前
27/27发布节奏 — 约每 2.9 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count39
latest_release_tagv0.25.1
releases_from_tags
days_since_latest_release6
mean_days_between_releases2.9
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

项目是否拥有用户、下载量与关注度,并具备欢迎贡献者参与的配置?

24危急 · 占总体的 18%
评分方式
0/60星标 — 0 个星标
0/25复刻 — 0 个复刻
0/15关注者 — 0 位关注者
所用输入
forks0
stars0
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

25危急
评分方式
22.5/22.5README
0/22.5许可证 — 未检测到许可证文件
0/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
has_contributing
has_issue_template
has_code_of_conduct
has_pull_request_template
评分方式
47.3/80月度下载量 — npm 合计每月 3,525 次下载
0/20注册表被依赖数 — 该生态系统不报告此项
所用输入
packages@broberg/ai-sdk
dependents
ecosystemsnpm
total_downloads
monthly_downloads3,525
已排除计分(无数据或不适用):注册表被依赖数。 其余权重已重新归一化。

可持续性与治理

项目能否在其成员之外延续——巴士系数、响应能力、由谁支持,以及软件包的维护状况?

53中等 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0/22.5提交分布 — 头号贡献者编写了 100% 的提交
1.4/13.5贡献者广度 — 1 位贡献者
6/10OpenSSF Scorecard:Contributors — project has 2 contributing companies or organizations -- score normalized to 6
所用输入
bus_factor1
contributors_sampled1
top_contributor_share1
评分方式
0/46.8议题解决 — 没有议题或无数据
38.2/38.3PR 接受 — 已裁定的 PR 中 1/1 已合并
0/15OpenSSF Scorecard:Code-Review — Found 0/30 approved changesets -- score normalized to 0
所用输入
merged_prs1
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
已排除计分(无数据或不适用):议题解决。 其余权重已重新归一化。
评分方式
30/30所有权背书 — 组织持有
0/20已验证域名
2.2/25所有者影响力 — broberg-ai 有 1 位关注者
8.1/25既往记录 — 10 个公开仓库,账户约 0 年
所用输入
followers1
owner_typeOrganization
is_verified
owner_loginbroberg-ai
public_repos10
account_age_days102
评分方式
25/25已发布且可解析 — npm 上有 1 个软件包
35/35发布时效 — 最近一次发布于 6 天前
20/20版本历史 — 40 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packages@broberg/ai-sdk
ecosystemsnpm
any_deprecated
min_days_since_publish6

工程质量

基础的工程与文档实践是否到位?

62中等 · 占总体的 20%

工程实践

60中等
评分方式
24/24CI 工作流 — 2 个工作流
24/24存在测试
0/16Linter 配置
0/9.6Pre-commit 钩子
0/6.4.editorconfig
0/20OpenSSF Scorecard:CI-Tests — 无数据
所用输入
has_ci
has_tests
has_editorconfig
has_linter_config
has_precommit_config
已排除计分(无数据或不适用):OpenSSF Scorecard:CI-Tests。 其余权重已重新归一化。

文档

65中等
评分方式
30/30README
25/25文档目录
0/15文档 / 主页站点
10/10仓库描述
0/10主题标签
0/10Wiki
所用输入
topics
has_wiki
homepage
has_readme
has_docs_dir
has_description

安全

可见的安全与供应链实践是否稳固,且不存在未解决的高风险司法辖区暴露?

46存在风险 · 占总体的 16%

安全态势

32存在风险
评分方式
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 — 无数据
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.5许可证 — 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 — 无数据
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
6.8/7.5Vulnerabilities — 1 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate3.2
已排除计分(无数据或不适用):ci_tests, signed_releases。 其余权重已重新归一化。
评分方式
35/35直接依赖不含已知公告 — 没有直接依赖携带已知公告
25/25间接依赖不含已知公告 — 没有间接依赖携带已知公告
0/40没有长期未处理的公告 — 没有公告带有发布日期
所用输入
sourceosv
advisories0
affected_packages0
assessed_packages1
unassessed_packages0
affected_by_severitynone
direct_affected_packages0
已排除计分(无数据或不适用):没有长期未处理的公告。 其余权重已重新归一化。 比对的是 npm:@broberg/ai-sdk@0.25.1 的运行时依赖闭包——安装已发布的软件包时真正被拉取进来的内容——共 1 个软件包。 未对可达性进行分析。

AI 就绪度

该仓库在多大程度上具备与 AI 编码代理协同开发与维护的条件?这是一枚独立的实验性徽章——权重为 0.0,因此单独呈现,不影响总体健康评分。

68中等 · 占总体的 0%
评分方式
45/45代理指令 — CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 83 次人类提交中有 83 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share1
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes38,283
评分方式
0/18一条命令的引导启动
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — tsconfig.json
0/10可复现环境
10/10已体现的代理实践 — 最近 100 次提交中有 67 次由代理编写或署名代理
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
所用输入
has_nix
has_tests
lockfiles
has_dockerfile
typed_language
bootstrap_files
has_devcontainer
has_linter_config
typecheck_configstsconfig.json
agent_commit_share0.67
toolchain_manifests
dependency_bot_commit_share0
评分方式
45/45可类型检查的代码 — TypeScript(静态类型)
55/55可控的文件大小 — 采样的 130 个源文件中有 0 个超过 60KB
所用输入
primary_languageTypeScript
largest_source_bytes29,347
source_files_sampled130
oversized_source_files0

关键数据

0GitHub 星标
1贡献者
179最近 12 个月提交数
6距最近推送天数
39发布版本数
1巴士系数(bus factor)
0开放议题
npm软件包生态系统数

数据采集警告

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

更多细节

OpenSSF Scorecard 3.2 / 10
3.2综合

来自开源项目 OpenSSF Scorecard 的独立、工具无关的安全评估。每项检查奖励的是安全实践本身,而非特定供应商的工具。Scorecard 无法判定的检查项标记为 不适用,并从安全评分中剔除(绝不按零分计)。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
不适用CI-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
不适用Signed-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
9Vulnerabilities1 existing vulnerabilities detected
直接依赖 1
注册表软件包版本约束清单文件
npmzod^3.23.8package.json
全部依赖 未采集

本报告未能采集到解析后的依赖集合:GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

依赖安全公告 0

安装 npm:@broberg/ai-sdk@0.25.1 会引入 1 个包(直接与传递):其中 0 个存在已知公告,0 个为直接依赖。

没有已知公告影响已评估的依赖。

公告表示依赖图中记录的版本落入某条公告的受影响范围。可达性未经分析,且依赖图包含开发与测试的版本固定——某项发现可能只涉及工具链而非交付的软件。

原始 JSON 报告 机器可读
{
  "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
}

评分是信号,而非担保。 评分反映的是 GitHub 上公开可见的实践——不是代码审计,也不是安全保证。

缺失数据将被剔除并重新归一化权重,绝不按零分计。方法论已版本化并公开:指标 v1.13.0、模式 v0.27.0—— 完整方法论 · 指标知识库.

单项结果在整体记录中的位置: 汇总统计npm.