公开记录
软件健康报告模式 0.27.0 · 指标 2.5.0 · 2026-08-02 11:04 UTC

dinho149 / yeaboi.ai

yeaboi — AI Scrum Master in your terminal: sprint planning, daily standups, team retros, 1:1s & delivery reports, synced with Jira, Azure DevOps, GitHub, Confluence and Notion

PythonMIT★ 2 星标⑂ 0 复刻始于 2026年3月在 GitHub 上查看 ↗
类型MCP 服务器网页界面如何判定

dinho149/yeaboi.ai 的健康指数为 100 分中的 75 分,处于「良好」区间。 其得分最高的类别是Engineering Quality(100/100),最低的是Community & Adoption(33/100)。 最近一次更新在今天。 近期的大部分工作由 1 位贡献者完成。

75
总分 / 100
良好

软件健康指数

指标归入加权类别,统一采用 1–100 量表。总体分先取类别加权平均,再依据公开记录的分布进行校准,使各等级具有百分位含义;当公开证据触发高风险司法辖区政策时,评级会按政策调整,并设置 34(存在风险)的上限。

75
卓越93-100公开记录中的最高层级(约前 5%);基本满足所有检验标准
优秀80-92各方面均表现强劲;仅有少量不足
良好65-79健康;不足之处有限且可控
中等50-64可接受,但存在明显不足;建议进行审查
薄弱35-49多个领域存在实质性薄弱环节
存在风险20-34存在重大薄弱环节;采用时应保持审慎
危急1-19问题严重(项目被弃置、仅有单一维护者、缺乏基本工程规范)
活力社区与采用可持续性与治理工程质量安全AI 就绪度

评分画像

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

加权总体分 65 经校准后在公布的指数量表上为 75(记录校准 2026-08-02)。

所有权

Dinho个人账户
3 关注者38 个公开仓库始于 2020年5月

该仓库由个人账户拥有。相较于组织支持的项目,单一所有者项目的延续性风险更高。

软件包生态系统

按类别列示的指标

活力

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

81优秀 · 占总体的 21%
评分方式
36/36推送新近度 — 最近一次推送于 0 天前
4.8/36提交节奏 — 52 周中有 7 周有提交
18/18提交量 — 最近一年 442 次提交
10/10OpenSSF Scorecard:Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
所用输入
commits_last_year442
human_commit_share0.99
days_since_last_push0
active_weeks_last_year7

发布纪律

100卓越
评分方式
27/27有发布版本 — 已发布 66 个发布版本
36/36发布时效 — 最近一次发布版本于 0 天前
27/27发布节奏 — 约每 0.7 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — 无数据
所用输入
releases_count66
latest_release_tagv2.47.1
releases_from_tags
days_since_latest_release0
mean_days_between_releases0.7
已排除计分(无数据或不适用):OpenSSF Scorecard:Signed-Releases。 其余权重已重新归一化。

社区与采用

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

33存在风险 · 占总体的 17%
评分方式
0/60星标 — 2 个星标
0/25复刻 — 0 个复刻
0/15关注者 — 0 位关注者
所用输入
forks0
stars2
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history

社区健康

50中等
评分方式
22.5/22.5README
22.5/22.5许可证 — 可识别的许可证(MIT)
0/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
readme_badges
has_contributing
has_issue_template
has_code_of_conduct
readme_badge_services
has_pull_request_template
评分方式
49.7/80月度下载量 — pypi 合计每月 5,329 次下载
0/20注册表被依赖数 — 该生态系统不报告此项
所用输入
packagesyeaboi
dependents
ecosystemspypi
total_downloads
monthly_downloads5,329
已排除计分(无数据或不适用):注册表被依赖数。 其余权重已重新归一化。

可持续性与治理

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

46薄弱 · 占总体的 23%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
7.8/22.5提交分布 — 头号贡献者编写了 65% 的提交
4.1/13.5贡献者广度 — 3 位贡献者
0/10OpenSSF Scorecard:Contributors — project has 0 contributing companies or organizations -- score normalized to 0
所用输入
bus_factor1
contributors_sampled3
top_contributor_share0.653
评分方式
0/42议题解决 — 0% 的议题已关闭
26.7/30PR 接受 — 已裁定的 PR 中 114/128 已合并
0/13Newcomer PR acceptance — 30 天内没有首次贡献者的 PR 得到裁决
0/15OpenSSF Scorecard:Code-Review — Found 0/14 approved changesets -- score normalized to 0
所用输入
merged_prs114
open_issues1
closed_issues0
prs_merged_7d
prs_decided_7d
prs_merged_30d
prs_decided_30d
issue_closed_ratio0
closed_unmerged_prs14
first_time_authors_30d
first_time_prs_merged_30d
first_time_prs_decided_30d
已排除计分(无数据或不适用):newcomer_pr_acceptance。 其余权重已重新归一化。
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
4.3/25所有者影响力 — dinho149 有 3 位关注者
23.6/25既往记录 — 38 个公开仓库,账户约 6 年
所用输入
followers3
owner_typeUser
is_verified
owner_logindinho149
public_repos38
account_age_days2,282
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。
评分方式
25/25已发布且可解析 — pypi 上有 1 个软件包
35/35发布时效 — 最近一次发布于 0 天前
20/20版本历史 — 48 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagesyeaboi
ecosystemspypi
any_deprecated
min_days_since_publish0

工程质量

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

100卓越 · 占总体的 19%

工程实践

100卓越
评分方式
24/24CI 工作流 — 13 个工作流
24/24存在测试
16/16Linter 配置 — .eslintrc, .eslintrc.json
9.6/9.6Pre-commit 钩子
6.4/6.4.editorconfig
20/20OpenSSF Scorecard:CI-Tests — 15 out of 15 merged PRs checked by a CI test -- score normalized to 10
所用输入
has_ci
has_tests
has_editorconfig
has_linter_config
has_precommit_config

文档

100卓越
评分方式
30/30README
25/25文档目录
15/15文档 / 主页站点 — https://yeaboi.ai/
10/10仓库描述
10/10主题标签 — 20 个主题标签
10/10Wiki
所用输入
topicsagile, ai-agent, ai-scrum-master, azure-devops, claude, cli, jira, langgraph, llm, mcp, mcp-server, planning-poker, python, retrospective, scrum, scrum-master, sprint-planning, standup, terminal, tui
has_wiki
homepagehttps://yeaboi.ai/
has_readme
has_docs_dir
has_description

安全

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

59中等 · 占总体的 16%

安全态势

59中等
评分方式
7.5/7.5Binary-Artifacts — no binaries found in the repo
2.2/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 15 out of 15 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/14 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5许可证 — license file detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
4/5SAST — SAST tool detected but not run on all commits
5/5Security-Policy — security policy file detected
0/7.5Signed-Releases — 无数据
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
3.8/7.5Vulnerabilities — 5 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate5.9
已排除计分(无数据或不适用):signed_releases。 其余权重已重新归一化。

AI 就绪度

该仓库在多大程度上具备与 AI 编码代理协同开发与维护的条件?权重刻意设小(4%):代理工具链是一项真实的维护信号,但完全不具备的仓库仍可达到 100/100。

82优秀 · 占总体的 4%
评分方式
45/45代理指令 — CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 99 次人类提交中有 99 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share1
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes18,378
评分方式
18/18一条命令的引导启动 — Makefile, desktop-pet/node_modules/json-stringify-safe/Makefile, desktop-pet/node_modules/progress/Makefile
22/22自动化测试
11/11Lint / 格式化配置 — .eslintrc, .eslintrc.json
11/11静态类型检查 — desktop-pet/node_modules/boolean/tsconfig.json, desktop-pet/node_modules/define-data-property/tsconfig.json, desktop-pet/node_modules/es-define-property/tsconfig.json, desktop-pet/node_modules/es-errors/tsconfig.json, desktop-pet/node_modules/gopd/tsconfig.json, frontend/tsconfig.json
10/10可复现环境 — lockfile
10/10已体现的代理实践 — 最近 100 次提交中有 90 次由代理编写或署名代理
8/8自动化维护 — 最近 100 次提交中有 1 次为自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
所用输入
has_nix
has_tests
lockfilespackage-lock.json, uv.lock, yarn.lock
has_dockerfile
typed_language
bootstrap_filesMakefile, desktop-pet/node_modules/json-stringify-safe/Makefile, desktop-pet/node_modules/progress/Makefile
has_devcontainer
has_linter_config
typecheck_configsdesktop-pet/node_modules/boolean/tsconfig.json, desktop-pet/node_modules/define-data-property/tsconfig.json, desktop-pet/node_modules/es-define-property/tsconfig.json, desktop-pet/node_modules/es-errors/tsconfig.json, desktop-pet/node_modules/gopd/tsconfig.json, frontend/tsconfig.json
agent_commit_share0.9
toolchain_manifests
dependency_bot_commit_share0.01
评分方式
27/45可类型检查的代码 — Python,已配置类型检查(desktop-pet/node_modules/boolean/tsconfig.json, desktop-pet/node_modules/define-data-property/tsconfig.json, desktop-pet/node_modules/es-define-property/tsconfig.json, desktop-pet/node_modules/es-errors/tsconfig.json, desktop-pet/node_modules/gopd/tsconfig.json, frontend/tsconfig.json)
53/55可控的文件大小 — 采样的 688 个源文件中有 25 个超过 60KB
所用输入
primary_languagePython
largest_source_bytes584,773
source_files_sampled688
oversized_source_files25
评分方式
0/40API 模式(OpenAPI/GraphQL/proto)
20/20MCP 服务器
40/40可运行示例 — example
所用输入
example_dirsexample
has_mcp_signal
api_schema_files

关键数据

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

数据采集警告

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

更多细节

OpenSSF Scorecard 5.9 / 10
5.9综合

来自开源项目 OpenSSF Scorecard 的独立、工具无关的安全评估。每项检查奖励的是安全实践本身,而非特定供应商的工具。Scorecard 无法判定的检查项标记为 不适用,并从安全评分中剔除(绝不按零分计)。Scorecard v5.5.0 · 2026-08-02 11:04 UTC

10Binary-Artifactsno binaries found in the repo
3Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests15 out of 15 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/14 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
8SASTSAST tool detected but not run on all commits
10Security-Policysecurity policy file detected
不适用Signed-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
5Vulnerabilities5 existing vulnerabilities detected
直接依赖 15
注册表软件包版本约束清单文件
npmpreact^10.29.1frontend/package.json
PyPIlangchainpyproject.toml
PyPIlanggraphpyproject.toml
PyPIlangchain-anthropicpyproject.toml
PyPIrichpyproject.toml
PyPIprompt-toolkitpyproject.toml
PyPIpython-dotenvpyproject.toml
PyPIPyGithubpyproject.toml
PyPIazure-devopspyproject.toml
PyPIjirapyproject.toml
PyPIatlassian-python-apipyproject.toml
PyPInotion-clientpyproject.toml
PyPIlanggraph-checkpoint-sqlitepyproject.toml
PyPIholidayspyproject.toml
PyPIsegnopyproject.toml
全部依赖 未采集

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [
        "agile",
        "ai-agent",
        "ai-scrum-master",
        "azure-devops",
        "claude",
        "cli",
        "jira",
        "langgraph",
        "llm",
        "mcp",
        "mcp-server",
        "planning-poker",
        "python",
        "retrospective",
        "scrum",
        "scrum-master",
        "sprint-planning",
        "standup",
        "terminal",
        "tui"
      ],
      "is_fork": false,
      "size_kb": 38833,
      "has_wiki": true,
      "homepage": "https://yeaboi.ai/",
      "languages": {
        "CSS": 165125,
        "HTML": 209470,
        "Shell": 15318,
        "Python": 9173996,
        "Makefile": 9153,
        "JavaScript": 1699,
        "TypeScript": 848962
      },
      "pushed_at": "2026-08-02T11:01:10Z",
      "created_at": "2026-03-17T04:31:30Z",
      "owner_type": "User",
      "updated_at": "2026-08-02T10:58:39Z",
      "description": "yeaboi — AI Scrum Master in your terminal: sprint planning, daily standups, team retros, 1:1s & delivery reports, synced with Jira, Azure DevOps, GitHub, Confluence and Notion",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Python",
      "significant_languages": [
        "Python"
      ]
    },
    "owner": {
      "blog": "https://medium.com/@dinho149",
      "name": "Dinho",
      "type": "User",
      "login": "dinho149",
      "company": null,
      "location": "London",
      "followers": 3,
      "avatar_url": "https://avatars.githubusercontent.com/u/64692956?v=4",
      "created_at": "2020-05-02T13:26:36Z",
      "is_verified": null,
      "public_repos": 38,
      "account_age_days": 2282
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v2.47.1",
          "kind": "patch",
          "published_at": "2026-08-02T11:01:11Z"
        },
        {
          "tag": "v2.47.0",
          "kind": "minor",
          "published_at": "2026-08-01T10:04:54Z"
        },
        {
          "tag": "v2.46.0",
          "kind": "minor",
          "published_at": "2026-07-31T21:05:45Z"
        },
        {
          "tag": "v2.45.0",
          "kind": "minor",
          "published_at": "2026-07-31T18:57:46Z"
        },
        {
          "tag": "v2.44.0",
          "kind": "minor",
          "published_at": "2026-07-31T17:43:15Z"
        },
        {
          "tag": "v2.43.0",
          "kind": "minor",
          "published_at": "2026-07-31T13:36:50Z"
        },
        {
          "tag": "v2.42.0",
          "kind": "minor",
          "published_at": "2026-07-31T11:36:23Z"
        },
        {
          "tag": "v2.41.0",
          "kind": "minor",
          "published_at": "2026-07-28T11:07:51Z"
        },
        {
          "tag": "v2.40.0",
          "kind": "minor",
          "published_at": "2026-07-27T20:38:29Z"
        },
        {
          "tag": "v2.38.0",
          "kind": "minor",
          "published_at": "2026-07-27T06:57:04Z"
        },
        {
          "tag": "v2.37.0",
          "kind": "minor",
          "published_at": "2026-07-27T05:15:43Z"
        },
        {
          "tag": "v2.36.0",
          "kind": "minor",
          "published_at": "2026-07-25T05:21:38Z"
        },
        {
          "tag": "v2.35.0",
          "kind": "minor",
          "published_at": "2026-07-24T21:08:21Z"
        },
        {
          "tag": "v2.34.0",
          "kind": "minor",
          "published_at": "2026-07-24T12:29:21Z"
        },
        {
          "tag": "v2.33.0",
          "kind": "minor",
          "published_at": "2026-07-24T12:14:38Z"
        },
        {
          "tag": "v2.32.0",
          "kind": "minor",
          "published_at": "2026-07-24T12:02:03Z"
        },
        {
          "tag": "v2.31.1",
          "kind": "patch",
          "published_at": "2026-07-24T11:44:06Z"
        },
        {
          "tag": "v2.31.0",
          "kind": "minor",
          "published_at": "2026-07-23T06:37:55Z"
        },
        {
          "tag": "v2.30.0",
          "kind": "minor",
          "published_at": "2026-07-23T05:28:13Z"
        },
        {
          "tag": "v2.29.0",
          "kind": "minor",
          "published_at": "2026-07-22T19:05:26Z"
        },
        {
          "tag": "v2.28.0",
          "kind": "minor",
          "published_at": "2026-07-22T10:37:42Z"
        },
        {
          "tag": "v2.27.0",
          "kind": "minor",
          "published_at": "2026-07-22T07:49:27Z"
        },
        {
          "tag": "v2.26.0",
          "kind": "minor",
          "published_at": "2026-07-21T15:46:25Z"
        },
        {
          "tag": "v2.25.0",
          "kind": "minor",
          "published_at": "2026-07-21T14:52:11Z"
        },
        {
          "tag": "v2.24.0",
          "kind": "minor",
          "published_at": "2026-07-21T11:15:42Z"
        },
        {
          "tag": "v2.23.0",
          "kind": "minor",
          "published_at": "2026-07-20T21:12:12Z"
        },
        {
          "tag": "v2.22.0",
          "kind": "minor",
          "published_at": "2026-07-20T20:24:50Z"
        },
        {
          "tag": "v2.21.0",
          "kind": "minor",
          "published_at": "2026-07-20T13:36:28Z"
        },
        {
          "tag": "v2.20.0",
          "kind": "minor",
          "published_at": "2026-07-20T13:04:44Z"
        },
        {
          "tag": "v2.19.1",
          "kind": "patch",
          "published_at": "2026-07-20T11:14:19Z"
        },
        {
          "tag": "v2.19.0",
          "kind": "minor",
          "published_at": "2026-07-20T10:52:20Z"
        },
        {
          "tag": "v2.18.0",
          "kind": "minor",
          "published_at": "2026-07-19T15:59:49Z"
        },
        {
          "tag": "v2.17.0",
          "kind": "minor",
          "published_at": "2026-07-19T15:47:22Z"
        },
        {
          "tag": "v2.16.0",
          "kind": "minor",
          "published_at": "2026-07-19T15:19:52Z"
        },
        {
          "tag": "v2.15.0",
          "kind": "minor",
          "published_at": "2026-07-19T14:03:11Z"
        },
        {
          "tag": "v2.14.0",
          "kind": "minor",
          "published_at": "2026-07-18T10:51:55Z"
        },
        {
          "tag": "v2.13.0",
          "kind": "minor",
          "published_at": "2026-07-18T09:04:18Z"
        },
        {
          "tag": "v2.12.1",
          "kind": "patch",
          "published_at": "2026-07-18T08:28:18Z"
        },
        {
          "tag": "v2.12.0",
          "kind": "minor",
          "published_at": "2026-07-18T07:50:00Z"
        },
        {
          "tag": "v2.11.0",
          "kind": "minor",
          "published_at": "2026-07-18T06:41:28Z"
        },
        {
          "tag": "v2.10.1",
          "kind": "patch",
          "published_at": "2026-07-18T06:29:17Z"
        },
        {
          "tag": "v2.10.0",
          "kind": "minor",
          "published_at": "2026-07-18T03:57:07Z"
        },
        {
          "tag": "v2.9.1",
          "kind": "patch",
          "published_at": "2026-07-17T12:20:47Z"
        },
        {
          "tag": "v2.9.0",
          "kind": "minor",
          "published_at": "2026-07-17T11:47:02Z"
        },
        {
          "tag": "v2.8.3",
          "kind": "patch",
          "published_at": "2026-07-17T10:43:49Z"
        },
        {
          "tag": "v2.8.2",
          "kind": "patch",
          "published_at": "2026-07-17T09:24:14Z"
        },
        {
          "tag": "v2.8.1",
          "kind": "patch",
          "published_at": "2026-07-16T16:21:00Z"
        },
        {
          "tag": "v2.8.0",
          "kind": "minor",
          "published_at": "2026-07-16T13:02:34Z"
        },
        {
          "tag": "v2.7.0",
          "kind": "minor",
          "published_at": "2026-07-16T10:01:40Z"
        },
        {
          "tag": "v2.6.0",
          "kind": "minor",
          "published_at": "2026-07-16T06:11:14Z"
        },
        {
          "tag": "v2.5.0",
          "kind": "minor",
          "published_at": "2026-07-16T04:52:10Z"
        },
        {
          "tag": "v2.4.2",
          "kind": "patch",
          "published_at": "2026-07-16T03:52:58Z"
        },
        {
          "tag": "v2.4.1",
          "kind": "patch",
          "published_at": "2026-07-15T20:40:08Z"
        },
        {
          "tag": "v2.4.0",
          "kind": "minor",
          "published_at": "2026-07-15T11:59:21Z"
        },
        {
          "tag": "v2.3.0",
          "kind": "minor",
          "published_at": "2026-07-15T04:37:22Z"
        },
        {
          "tag": "v2.2.0",
          "kind": "minor",
          "published_at": "2026-07-14T05:40:45Z"
        },
        {
          "tag": "v2.1.0",
          "kind": "minor",
          "published_at": "2026-07-13T04:40:10Z"
        },
        {
          "tag": "v2.0.0",
          "kind": "major",
          "published_at": "2026-07-11T18:26:46Z"
        },
        {
          "tag": "v1.7.0",
          "kind": "minor",
          "published_at": "2026-07-10T21:48:06Z"
        },
        {
          "tag": "v1.6.0",
          "kind": "minor",
          "published_at": "2026-07-10T19:16:03Z"
        },
        {
          "tag": "v1.5.0",
          "kind": "minor",
          "published_at": "2026-07-10T14:55:44Z"
        },
        {
          "tag": "v1.4.0",
          "kind": "minor",
          "published_at": "2026-07-10T10:24:41Z"
        },
        {
          "tag": "v1.3.0",
          "kind": "minor",
          "published_at": "2026-04-01T06:01:10Z"
        },
        {
          "tag": "v1.2.0",
          "kind": "minor",
          "published_at": "2026-03-25T06:03:41Z"
        },
        {
          "tag": "v1.1.0",
          "kind": "minor",
          "published_at": "2026-03-22T07:49:37Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-03-20T07:59:23Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "8f4d56290f6118a5fc290628b8373ad44caf6bf5",
          "body": "Bumps the actions-all group with 2 updates: [actions/setup-node](https://github.com/actions/setup-node) and [github/codeql-action](https://github.com/github/codeql-action).\n\n\nUpdates `actions/setup-node` from 6 to 7\n- [Release notes](https://github.com/actions/setup-node/releases)\n- [Commits](https:\n[…]\nversion-update:semver-major\n  dependency-group: actions-all\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "chore(ci): bump the actions-all group with 2 updates (#126)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-08-02T10:58:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6b8716f945c0e2cab5488d247529e29915509587",
          "body": "* make the invite one link that carries its own code\n\nEvery Copy Invite path put two things on the clipboard as a two-line string —\nthe share URL, a newline, then \"Access code: XXXX-XXXX\". The URL always ends\nin \"/\", so any paste target that flattens a newline into a space produced\nhttps://host/%20A\n[…]\nhropic.com>\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 4.6 <noreply@anthropic.com>\nCo-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "make the invite one link that carries its own code (#132)",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-08-02T10:55:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7dc71f4c115ec3dd24f6a2e2d16fbc6ed266f131",
          "body": "…s (#129)\n\nEvery claude-code-action run in this repo failed with HTTP 401 from\n2026-07-30, and the outage was misdiagnosed twice — first as a stale\nHaiku alias, then as a token needing rotation — because the action\nhides SDK output, so the only symptom was a bare `is_error: true`.\n\nNothing about ver\n[…]\ner the wrong cause\n- record the incident and its signatures in the ci-and-release skill\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): preflight the claude credential and stop hiding auth failure…",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-08-01T20:19:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "53a0e30891c0064fb407c45ff4d6dee0e534ad65",
          "body": "`make wt-new NAME=x` created the branch with a bare `git worktree add -b x` —\nno fetch, no reference to the remote — so it started at whatever the main\ncheckout's HEAD happened to be. A stale main silently handed every new feature\nbranch an old base, and the first /sync-main turned into a surprise r\n[…]\nhere a host-key or\ncredential prompt would hang the orchestrating agent with no output.\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "branch new worktrees off latest origin/main (#124)",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-08-01T10:49:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "726448029419fb2360b7f1add3b444d65940b0d9",
          "body": "… breakdowns (#123)\n\n* make the standup export scannable: evidence rows, bulleted intros, pr breakdowns\n\nReplace the bare SHA-chip rows with structured evidence (kind chip, linked\nref, title, repo, glyphed status), add a member jump strip and blocker-first\ncards, fold overflow and PR commit breakdow\n[…]\no 2.47.0\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "make the standup export scannable: evidence rows, bulleted intros, pr…",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-08-01T09:59:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0f43af016f36e1564325b5110d8d05fe007305ba",
          "body": "* one place for the headers every served document carries\n\nThree servers hand HTML to a browser and each grew its own `_send`. They\ndiverged the way duplicated code always does: the share server accumulated a\nfull protective header set and a policy per surface, while the two live boards\nsent a bare \n[…]\nserted\nto be a pure insertion.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "unify every browser surface on one theme and one chrome (#122)",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-31T20:59:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "12ce96a0751fdfcc85aef87eb11d0eefc7cfd2c8",
          "body": "yeaboi.ai was not in Google's index at all: no robots.txt, no sitemap.xml, no\ncanonical tags, and — because the docs nav is built by JS into a display:none\ncontainer — not one crawlable link between docs pages.\n\nscripts/gen_site_seo.py now owns the SEO head block, a crawlable footer, the\n?v= cache-b\n[…]\n1M context) <noreply@anthropic.com>\n\n# Conflicts:\n#\tREADME.md\n#\tdocs/docs/modes/index.html\n#\tdocs/docs/modes/retro.html\n#\tdocs/index.html\n#\tpyproject.toml\n\nCo-authored-by: Dev Person <dev@example.com>",
          "is_bot": false,
          "headline": "make the docs site indexable, and measure it (#121)",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-31T20:02:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "51df4c3d4b5f2e9943ba8354b5d96a3eed6a2ff9",
          "body": "* mark performance mode as beta across every surface\n\nPerformance ships as a first-class mode — a welcome card, five MCP tools, a\nCLI subcommand, a plugin skill and its own docs pages — with nothing saying\nits output has never been validated against a real team's tracker. For a mode\nthat drafts mate\n[…]\nnv vars.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "mark performance mode as beta across every surface (#116)",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-31T18:51:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7db4fbe4da95c2a622f482dcd0761b88fd377ae8",
          "body": "…rors (#120)\n\n* ci: show claude sdk output in auto-version\n\nThe action prints only `Running Claude Code via SDK (full output hidden for\nsecurity)` and a bare `is_error: true`, so both Haiku outages so far have had\nto be diagnosed by elimination rather than by reading the error. The prompt and\ndiff a\n[…]\nfailure.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): unbreak the auto-version bump, and make it report its own er…",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-31T18:03:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "71e54b9c69e67868584cec4a295ec6f642d884d5",
          "body": "* remove LAN sharing — the live boards are tunnel-only\n\nThe retro and poker boards advertised two addresses for one server: a LAN URL\nbuilt from a UDP-probed local IP, and a Cloudflare tunnel URL only if the host\npressed \"Share Remotely\". The LAN link works for one room, exposes the port to\neveryone\n[…]\nend rewrite shipped as 2.43.0.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "remove LAN sharing — the live boards are tunnel-only (#115)",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-31T17:36:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6cc73afe0ff1c1ab59df462cde1d0f076ae0321a",
          "body": "The old banner was a neon-sign graphic reading \"Scrum AI\" — stale branding\nfrom before the rename. Replaced with a flat dark banner carrying the\nyeaboi.ai wordmark, the docs-site tagline, and the pixel duck mascot,\nusing the palette from docs/assets/landing.css.\n\nGenerated with the duck sprite (base\n[…]\n0x400 — the generator's widest ratio is 21:9 and cropping to 3:1\nclipped the duck's feet. README renders it at width=800 either way.\n\nCo-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "replace readme banner with duck mascot artwork (#117)",
          "author_name": "Nikolai Main",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T16:26:26Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4f0a416a149f717a43ba6f208324228fd412dc71",
          "body": "… (#114)\n\n* fix(ci): compute the auto-version diff locally, not through the API\n\n`gh pr diff --name-only` returns HTTP 406 on any diff over 20000 lines,\nand the call sat inside an `if` condition where `set -e` does not apply —\nso the failure was indistinguishable from \"no files matched\" and fell\nint\n[…]\nrebuild.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix the auto-version guard that swallowed PR #111, and release 2.43.0…",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-31T13:31:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d70f399b4fc59fc92d9d5b498b6cb5738c2eedb9",
          "body": "…vite on it (#111)\n\n* allowlist url schemes in every export\n\nA ticket whose `url` was `javascript:alert(1)` rendered as a live\nclick-to-execute link. `test_export_xss.py` could not catch it: its probe is\nmarkup-shaped, and html.escape() rewrites none of the characters in a scheme,\nso the value reach\n[…]\nnvite, and the retro\nboard's per-column composers and in-flow reaction tray.\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "migrate every browser surface to react + typescript, and build the in…",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-31T13:10:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5c3bc598454311d0077d45bd7f73b458d6040bdd",
          "body": "fix(ci): pin the dated haiku model id, and apply the version bump it missed",
          "is_bot": false,
          "headline": "Merge pull request #113 from dinho149/fix/auto-version-haiku-model",
          "author_name": "Nikolai Main",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T11:31:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c7c1a49c17fd114fc6ea5e73e44ebf4670e801ba",
          "body": "The bot can't write it from this PR. claude-code-action refuses to run at\nall when the workflow file differs from the default branch's copy\n(\"Workflow validation failed... must have identical content\"), and this PR\nedits auto-version.yml. It exits as a *skip*, so the job goes green without\nthe model ever being called — which also means the model pin can't be\nverified until after merge.\n\nRestores the hand-written 2.42.0 entry.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Revert \"chore: let the bot write the 2.42.0 changelog entry\"",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T11:26:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "871f3e896fb5ae3aa6107c08afdafe13acbaf39f",
          "body": "Keeps the manual version bump (the bot can't retroactively bump for an\nalready-merged PR — it only ever sees the current PR's diff) but drops the\nhand-written entry, so the guard routes to changelog-only mode instead of\nskipping. That actually exercises the pinned model, which the skip path\nnever did.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: let the bot write the 2.42.0 changelog entry",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T11:25:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d1ae297df06ae2bf3fb73d3d9ade74b3b4d0d1ef",
          "body": "The `claude-haiku-4-5` alias stopped resolving between 2026-07-29 and\n2026-07-30. Every Auto Version Bump run since died on turn 1 in ~2s with\ntotal_cost_usd 0, while every sibling workflow on claude-sonnet-5 kept\npassing with the same OAuth token — and neither workflow file had changed\nin that wind\n[…]\n1.0, which is already tagged and released, so publish.yml would not have\nshipped any of it. Applied the minor bump and changelog entry by hand.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ci): pin the dated haiku model, and apply the bump it missed",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T11:24:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fa70be815f9fdf4717f1ca8e1a17a3325f4c99a3",
          "body": "TUI mascot: duck companion, boxed settings with keyboard focus, app-wide clicking, feedback composer",
          "is_bot": false,
          "headline": "Merge pull request #112 from dinho149/feature/tui-mascot",
          "author_name": "Nikolai Main",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T11:14:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "879b5001e9a1f2367dfbbb48efb3a897beb6e03b",
          "body": "`make lint` only runs `ruff check`, so a long logger.info line and a\ntrailing blank line in the generated sprite module slipped past locally and\nfailed CI's separate `ruff format --check` step.\n\nThe sprite blank line came from the generator emitting a separator after\nevery block including the last, so it would have returned on the next\nregeneration — trimmed there rather than in the output.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "style: satisfy ruff format --check",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T11:09:57Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d9a47a2ebed222a7048538d1e1a3316ec71ac22e",
          "body": "The back/controls tabs ease their presence on every render, so rendering\nthe plain frame and then the composing frame left the pocket rows\ndiffering for reasons unrelated to the bubble — the test only failed when\nsomething earlier in the suite had left `_back_presence` non-zero.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(tui): pin tab presence in the composer overdraw test",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T10:56:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5c79dad4219c9c2a4469005fea4be3c078aed445",
          "body": "76 read as a slab across the screen. Still wide enough for all four types on one\nrow and a comfortable line of prose.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "style(tui): trim the composer to 64 columns",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T10:38:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f99b9735d1af9453461039a945b4980de1a9f562",
          "body": "…ng box\n\nThe bubble was laid out inside the companion lane, and that lane's width feeds\nthe mode list's — so making it wider reflowed every description and truncated the\nbottom-left hint row, and keeping it narrow left a 42-column box to write in.\nNeither is necessary: _WelcomeFrame already composit\n[…]\nimum size there is no lane to draw over, so `f` opens\nthe full form instead of a composer that would render nothing while swallowing\nevery key.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): draw the composer over the frame so it can be a real writi…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-31T08:27:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "624a049f8ebb95ecff16e20af7e4a8ee00fe42d2",
          "body": "Widening the companion lane for the composer was the single cause of both\nfaults. The split feeds the mode list's own width, so a wider lane reflowed every\ndescription — growing the left column, which pushed the bottom-anchored duck down\n— and truncated the bottom-left hint row, dropping \"tips\" from\n[…]\nnd its colours were still the fixed constants, so it didn't fade\nwith the rest of the bubble. Both fixed, and the now-unused constants dropped.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): the composer must not resize the mode list",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T21:00:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "605434594f4c5023e5eb54bd6dd1db135ef04e25",
          "body": "The lane is bottom-anchored, so a bubble taller than the space available cropped\nthe DUCK rather than itself — his neck disappeared under the music pocket. The\nmessage area is now budgeted against the lane height (minus the duck, the tail\nand the bubble's own chrome), so it shrinks instead of growin\n[…]\ndler asks for it, the animation finishes\nit. Esc used to drop the state between frames, which is what made the bubble\nvanish rather than leave.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): keep the composer clear of the duck, and animate it in and out",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T20:50:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cbff7d2e87f8516ccd17e746f2adf4b552e7aff7",
          "body": "Only the rows carrying text get it, so the typed message reads as a block of\nwriting rather than loose lines under the two selectors. The wrap width drops by\nthe gutter's own columns, so a long message still breaks inside the box.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): a gutter block down the composer's message rows",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T20:45:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "44f2e27cf3393684efe1bc8f8409589df7ecf50a",
          "body": "… bubble\n\nThe Type/Area rows were a carousel — the options rotated around a fixed marker,\nso the words moved and the selection didn't. They are a fixed list now: the\nmarker moves along them and the window only slides when the selection would fall\noff an end, marked with … rather than ‹ › (which read\n[…]\nngelog highlights follow the same rule against their version heading. This\nreplaces the previous commit's guess, which pushed them further out.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): static composer selectors, plus paste and dictation in the…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T20:35:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "44ab935fca17b7d7d6a83784d8f7ebf894172868",
          "body": "The `f` shortcut no longer leaves the welcome screen. The duck's tip bubble\nbecomes a composer in place: Type and Area selectors over a message box, ↑/↓\nbetween the three fields, ←/→ to cycle a selector or move the cursor, Enter to\nsend, Esc to cancel. Composing widens the right-hand lane from 44 to\n[…]\nt as a side\neffect of un-indenting something else; the tips gallery and the changelog\nhighlights are back on PAD, under their section headings.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): feedback comes out of the duck, and tips loses its chrome",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T20:27:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "efef57c505ab339b71a0c1c686b9d98b111ef2c8",
          "body": "Brings in #106 (filesystem sandbox, secret redaction, write-tool gating,\nCodeQL), #107 (standup intelligence + the shared export visual system), #108,\n#109 (reporting overhaul: threaded generate, themes, deck styles, pptx) and\n#110. Six files conflicted.\n\nOurs, in full — the settings screen and its \n[…]\nPAD while this branch had replaced that import. Both now exist,\ncommented — do not collapse them.\n\nuv.lock regenerated rather than hand-merged.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "merge origin/main into feature/tui-mascot",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T19:31:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4d00b3a1a91e1c76a930e90dce347431477b7bf1",
          "body": "…one click\n\nThe voice status was cropped mid-command. Its reason string appends a Linux\n`apt install libportaudio2` note, so no column width would ever hold it — a\nread-only status now flows onto continuation lines instead. The wrap happens at\nbuild time (_wrap_value), not at render: the whole layou\n[…]\n: the wrapped status left a\nfive-row shortfall across two boxes, which the old cap couldn't absorb, so the\ncolumns finished a line out of true.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): wrap long setting statuses, and make the back tab leave in …",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T16:41:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5438db3babb881d07a42e74d3c585ddfa93fd48f",
          "body": "The rows were indented two columns inside an already-indented box. That gutter\nexisted only to hold the focus marker — a leading glyph needs the gutter on\nEVERY row or the text jumps sideways when focus lands. Focus is a full-width\nbackground bar behind the row instead: it costs no columns, reads mo\n[…]\nbsurdly.\n\nThe focus bar is a background colour, so the tests covering it render styled\nsegments — there is nothing in the plain text to assert.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): flush setting rows and columns that end level",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T16:23:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2ff252834bbd8e7030740ad3643904f50fbb94e9",
          "body": "Clicking while editing did nothing: the edit branch routed every key to the\nbuffer, so a click was swallowed and you had to press Esc first. A click now\ncommits what was typed and falls through to the normal routing, so it lands on\nwhatever it hit — another row, or a tab. A click on empty space is l\n[…]\n) in _input — Settings is also the only page that shows the tab\n  AND types into fields, so it brackets each in-place edit and 'c' types a 'c'.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): click straight to another setting, and bind controls to 'c'",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T16:14:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f4f30ccdcace4399d0e26818e86447bceb1a6e86",
          "body": "The animation on these two was the full-screen ANSI-Shadow wordmark played\nbefore the page — reveal, diagonal shine sweep, exit — not the page title I\ntook the shimmer off last commit. Both pages open instantly (bundled JSON, an\nempty form), so a shine sweep in front of them reads as a loader for a wait that\nisn't happening. `c` and `f` now land straight on the page.\n\nThe All Tips gallery keeps its entrance, so play_wordmark_intro stays.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): open changelog and feedback without the wordmark intro",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T10:18:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e1dc4138b6834dcc758a86e3e392360979f5c526",
          "body": "Both loops fed shimmer_tick a monotonic clock, which sweeps a travelling\nhighlight across the ASCII title — it reads as a loader on a page that isn't\nloading anything. Both builders already default it to None (the solid look), so\nthey just stop passing a clock. The typewriter subtitle stays.\n\nChange\n[…]\ng_text stays in changelog.py: it's a public, separately tested\nexporter rather than UI, so dropping it would remove a module API, not a button.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): static titles on changelog and feedback, drop changelog copy",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T10:04:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "50b5fda8453253daf9be0334412a87499f121d10",
          "body": "…ata dir\n\nThree things the boxed layout still got wrong.\n\nLayout. A row-based grid padded every box in a row up to the tallest one, so a\ntwo-row section sat in a six-row box beside a full one. The sections are dealt\ninto the shortest column instead, and each box is exactly as tall as its own\ncontent\n[…]\nhe Esc chokepoint\narms the retract before the screen gets a say, so an edit that eats the key has\nto un-arm it — same as popping a focus level.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): balanced setting columns, storage under system, in-place d…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T09:32:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b7c3ab38b9851315b57b7a199aaa289ae57865b5",
          "body": "The marker now lands at ~30s locally — right on the deadline, so the test fails\nabout as often as it passes. It's a liveness check (does the TUI reach\nmode-select in a real pty at all), not a performance budget, so the tight bound\nbuys nothing.",
          "is_bot": false,
          "headline": "test: give the pty boot smoke test real headroom",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T09:11:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "018edd6fe2ccf8bc47985ee8c7ad3f1e5f702cdb",
          "body": "Boxing the sections left the mouse as the only way to reach a value. Settings\nnow has three focus levels, so every field is reachable with arrows alone:\n\n  (-1,-1)  the tab bar   — left/right switch tabs, down enters the grid\n  (b, -1)  a section box — arrows walk the grid, Enter opens it\n  (b,  f) \n[…]\n  chokepoint arms the retract before the screen decides whether it's keeping the\n  key. Added `cancel_back_retract()` for screens that keep it.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): navigate and edit settings from the keyboard",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T09:10:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "952f17ab2c11cd93b3d0e9cfd87873ced805c692",
          "body": "Each heading section becomes its own rounded box with the heading as the box\ntitle, laid out in an adaptive column grid (two columns when there's room, one\nwhen a column would fall below _SETTINGS_MIN_BOX_W) — the same treatment the\nUsage screen already uses, flattened through the shared _render_to_\n[…]\n box border lands on the tab-bar rule, which puts the row text inside it at\nexactly the column the unboxed rows used — no text shifts sideways.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): box the settings sections like the usage dashboard",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-30T08:10:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7a493cc38ff36bfc3fc4ceea6ce90a3d22429e3b",
          "body": "It sat over by the music pocket; anchor it to the left tab strip instead,\nimmediately after back (and copy). draw_back_pocket now publishes where that\nstrip ends so the tab lines up, and the tab unrolls and expands rightward from\nits left edge rather than leftward.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): move the controls tab next to the back tab",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T23:30:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6dea462c1554e014d0ec1b549ebbe99f057cfd30",
          "body": "Both hub delete messages now come from the companion duck instead of the\npage: the confirmation replaces the red centred overlay (that whole popup\nblock, its slide-up animation and the body-trimming it needed are gone), and\nthe follow-up toast moves out of the subtitle row.\n\nThe confirmation is stic\n[…]\nlds, since it has to wait\nfor an answer rather than dissolving like a transient status. The result toast\nuses the normal fade-in/hold/fade-out.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): the duck asks for delete confirmation and reports the result",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T23:26:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "02063978ba679524ca4d4952ed30bf83da2e1f0f",
          "body": "Clicking the companion duck lifted his shades on the welcome screen only.\nThe chrome duck (the one riding along on every sub-page) now publishes its\nrect and plays the same SHADES_LIFT_SEQUENCE when poked, so the gag is\navailable wherever he appears.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): the double-shades gag works on every page's duck",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T23:18:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2a39a3dcd382104fd67cf1038a249d47f3992791",
          "body": "With no page-specific hints the drawer just repeated the back/copy tabs\nbeside it (e.g. Usage), so a page now qualifies for the tab only when it\nhands over controls of its own.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): only show the controls tab on pages with their own controls",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T23:14:32Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e9b5499ac8ec47bfea0ce72e50c6355d9be2ebb1",
          "body": "The '⌃C controls' label is redundant once the list it describes is on screen,\nso once expanded that row carries a control instead.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): hide the tab label while the controls drawer is expanded",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T23:10:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7ec6ee230249f5c9cc3354136a842ca7e1f5992e",
          "body": "The drawer's keys were right-justified in their column; left-align them so\neach key starts flush at the edge with the descriptions still in a column.\nThe collapsed tab now eases in on pages that qualify (unrolling leftward out\nof its right edge, mirroring the back tab's corner peel) and eases back out\non pages that don't — it was popping in and vanishing before. It only\nbecomes clickable once settled.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): left-align the controls rows and animate the tab in",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T23:09:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "052332f40e089b67413610bf8edb432b141fea84",
          "body": "…s drawer\n\nThe page-hint tab duplicated what the drawer already lists (and was getting\ncut off behind it), and the ctrl+P / ctrl+O rows repeat the music pocket\nsitting right next to them. Page hints are now drawer content only.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): drop the redundant hint tab and music rows from the control…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T23:04:23Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "afda2e206e90cfcf7657a27a935af11a2bb75120",
          "body": "A \"⌃C controls\" tab now sits permanently between the page hints and the\nmusic pocket. Ctrl+C grows the tab itself upward into a panel listing every\ncontrol available on the current screen — the page's own hints plus the\nglobal chords — easing its height and width so it unfolds rather than\nsnapping, \n[…]\n\nthat. Esc closes the drawer instead of navigating back when it's open.\n\nNot shown on the welcome screen, which already lists its own controls.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): persistent controls tab that expands upward on Ctrl+C",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T23:00:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e69b2e312813440dd0fd3c3d81913429d1eca8d8",
          "body": "- Settings values didn't change in the UI until a restart: set_config_value\n  only writes ~/.yeaboi/.env, and the page re-reads os.environ. Added\n  config.apply_config_value (write + export, clearing on empty) — the pairing\n  every other setter in that module already did by hand — and used it from t\n[…]\ning the settings status.\n- Usage: drop the always-on scrollbar — the boxes normally fit, so the track\n  only shows when they actually overflow.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): settings edits apply live; duck status fades in and out",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T22:42:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f460b6e2b1da6e81af2d5786b1706d208dab1eaa",
          "body": "…ocket\n\n- Generalise the left pocket: sibling tabs beside back are now a list of\n  (label, key) pairs peeling out of the same corner, so the copy tab is just\n  one entry and a page can add its own. Clicks report the tab's key.\n- Settings hands its controls to the chrome via _hint_tab, freeing the bo\n[…]\nbubble beside his head (_duck_say) rather\n  than printed as a body line.\n- Usage: wide section boxes span two columns instead of the full grid.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): duck speaks settings status; controls ride in the bottom p…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T22:29:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9ac0c5139a9236874ec489ceac8f0d64b6d8d757",
          "body": "Their values (the last-session timestamp, the session DB path) don't fit a\nthird-width column and were ellipsizing. Sections can now be flagged wide,\nwhich lays them out as full-width boxes stacked below the column grid.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): give Session History and Environment full-width usage boxes",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T22:16:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "470cbca918b3cd46b5fabc195b6b3bbeafe8fdbf",
          "body": "Each Usage section (LLM Provider, Lifetime Token Usage, Current Session,\nLocal Model Performance, Session History, Environment, Team Profiles) is\nnow its own rounded box with the section name as its title, and the boxes\nsit side by side in a grid whose column count follows the terminal width\n(1 when\n[…]\nrender_to_lines — hoisted out of\n_build_retro_screen to module level and now shared by both — keeping the\nviewport math and scrollbar accurate.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): box the usage sections and lay them out in columns",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T22:12:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2ac4fe0b3a43b85ac0f9f8d855da4dc2763829f7",
          "body": "Generalise the left pocket into a peel helper so a sibling tab can share\nthe corner animation, and give copy-capable pages (flagged with _copy_tab)\na 'c copy' tab next to back. Clicking it presses 'c'. Usage drops its\ninline keyboard hint now that both affordances live in the chrome.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): add a 'c copy' chrome tab beside the back tab",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T21:53:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9ea4a618dcfd3255129965a4a5639b3edbcbbb20",
          "body": "The on-press retract snapped away the instant the key landed; hold the tab\nup for _BACK_RETRACT_DELAY (0.1s) after the press, then run the fast fold.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): hold the back tab a beat before folding it away",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T21:49:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ddfcac18c57aaae7711213e1b8ce6ed6ab0a3d0c",
          "body": "Three things kept the retract trailing into the next screen's entrance:\nthe latch only fired on a tab click (not Esc), the fold eased at the same\nrate as the glide-in, and the menu<->page transition frames still asked\nfor the tab. Now Esc and tab-clicks share one _esc() chokepoint that\nlatches the r\n[…]\n, the latched fold eases much faster, and the slide\nframes opt out via _no_back_hint. Measured: tab clears in ~0.1s from the\npress (was ~0.5s).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): fold the back tab away on press, not on arrival",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T21:46:07Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3ef1a1896ac786366dfdba3c223984b7f49bf658",
          "body": "… press\n\n- The companion duck was held off-screen for the whole return transition\n  (companion_intro=0) and only slid in afterwards, so it cleared and then\n  reappeared. _sweep_menu_in now takes companion_from and ramps the duck\n  in DURING the return wipe (from its sub-page corner), and the post-wi\n[…]\n a late animation. A retract latch set the instant the tab\n  is clicked overrides the current screen's target, so the fold triggers\n  on press.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): slide the duck back on menu return; retract the back tab on…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T21:39:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6273cc24d19c13fdd24c05584c5b7b8a9fcbe7ac",
          "body": "_settings_tab_bar takes a fractional tab position (pos) and interpolates\nthe bright underline span between adjacent tabs; the settings loop eases\n_tab_pos toward the active tab each frame, so switching tabs slides the\nunderline instead of jumping.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): slide the settings tab underline between tabs",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T19:38:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a25bc284f05135b4d0bf604310a4dcd8ce9da327",
          "body": "The config rows (and their create/scope sub-lines) sat 2 cols in from the\nsection headings; shift them left so the content aligns under each header.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): unindent settings rows to align with their section headings",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T19:33:51Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1bbac42e882723e03bcf6dfb944e90e8d5f43aca",
          "body": "Remove the explicit Back button from Performance (roster + detail) and\nthe 'Esc back' tail from the Usage, Changelog and Settings footer hints —\nthe app-wide back tab is the go-back affordance now. Tests updated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): drop redundant back affordances now the back tab covers them",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T19:32:07Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c947cc7a2fbe9891af731e3371f33fc1e33d9e85",
          "body": "The bottom-left back tab now shows the go-back affordance, so the\nboard-required screen no longer needs the inline hint.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): drop redundant 'Press any key to go back' hint",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T19:24:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "fba83cc468ccdf4f155fbd71be12402bc439da6e",
          "body": "Anchor the tab at the bottom-left corner and reveal it as a staggered\ndiagonal — the bottom border row opens first (corner ╯), then the text,\nthen the roof — so it reads as the corner peeling up. Retract reverses,\nfolding back down into the corner. Driven by the same eased presence.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): back tab peels up from the corner instead of sliding in",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T19:13:13Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ea39cc0fd430d8fd42cefc081d83a5dc58bf5d8d",
          "body": "Drive the tab from an eased presence (0..1) instead of a one-way slide:\ntarget 1 on back-capable screens glides it in, target 0 elsewhere glides\nit back out. The frame drives it every render (and the welcome frame\nretracts it), so leaving a back-capable screen slides the tab away rather\nthan vanishing it. Clickable only once mostly settled in.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): animate the back tab out (not just in)",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T19:06:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "58a75264a5cd602c066ed4df31ba3ab8b6304f0a",
          "body": "_build_run_hub_screen records the selected run card's Delete/Export\nbutton rects (panel._btn_regions); run_snapshot_hub hit-tests them (with\nx, before the y-only card regions) and reuses the existing focus==1/2\nEnter paths — delete-confirm popup / export picker. Covers retro, standup,\npoker, reporting, performance.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): make hub Delete/Export buttons clickable",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T19:02:24Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "531aeee616c90eb1c64506549120409b9064cc42",
          "body": "The back tab drew a closed floor under its text; mirror the music pocket\ninstead — the alcove hangs from the roof with corners rising at the walls\nand an open gap between, no bottom border.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): open bottom on the back tab to match the music pocket",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T18:57:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ab4168371d13e4dc78ca54b4cd74ae813a96633f",
          "body": "Attach _card_regions to _build_project_list_screen (absolute row spans per\ncard, tracked with real rendered heights) and hit-test clicks in the two\ninteractive project-list loops: a click selects the card and synthesises\nEnter to open it / start a new project or analysis. Mirrors the saved-runs\nhub. Card body only; edge Delete/Export buttons are not click targets.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): make project-list cards clickable (planning + analysis)",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T18:48:58Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1d7385f78b0135e84d19a60eeca35a133daaa198",
          "body": "A rounded 'go back' pocket mirroring the music bar, drawn on every\nback-capable screen (all but the main menu, which opts out via\n_no_back_hint). It slides in from the left on entry and is clickable:\nits rect is published from the render frame and read_key turns a click\nthere into Esc, so it works app-wide with no per-loop wiring.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): app-wide clickable 'go back' tab (bottom-left)",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T18:45:22Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "672a4325e3c373646dc738a5807e3544a8bb1006",
          "body": "'No engineers found' and the connect-a-tracker hint sat at _PAD while the\nsubtitle is at _PAD+2; align them under the subtitle.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): indent the performance empty-state to match its subtitle",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T18:32:31Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c057b9c10880f85b4595ccdc668363f8e4f5dfa4",
          "body": "The Board-required / export-status body sat at _PAD+4 while its heading\nand hint were at _PAD+2; align them all on the same column.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): un-indent the status-screen body to align with its heading",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-29T18:28:04Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "de7dfb638e4eaeceea9fe1999adfe9344b9db13d",
          "body": "… workflows (#110)\n\nClaude Review and Dependabot verify silently never ran on any PR that got an\nauto-version bump. auto-version pushed the bump with the default GITHUB_TOKEN,\nmaking the bump commit's CI run bot-actored; GitHub then emits no workflow_run\nevent for it. Combined with ci.yml's cancel-i\n[…]\n0 -> 2.41.0 to match pyproject.toml already on main —\npre-existing drift, not part of this change.\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "repair automation pipelines: restore dropped reviews, fix dead triage…",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-29T12:43:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5c42d6070b971c5387de60eddcea63da8edb550c",
          "body": "Wire mouse-click support into every button-row input loop across the\nmode-select flows and the session review pipeline: each loop keeps its\nlast-rendered panel, and a click is hit-tested via button_click() and\nrouted to the button under the cursor (synthesized as Enter). Covers the\nsnapshot detail v\n[…]\ner/reporting/performance pages, the analysis + roadmap\nresults, the preview/sprint-review flows, the confirm popups, and the\nphase review loop.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): make action-button rows clickable app-wide",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T17:51:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "918c8c33851d36f955f8a140d27a25dae28f2d7c",
          "body": "The standup/retro/poker/reporting/performance hubs couldn't be driven by mouse —\nyou couldn't click '+ New retro' (or a saved run) to open it. The builder now\nrecords each visible card's absolute row span on the panel (_card_regions), and\nthe shared hub loop hit-tests clicks against it: click a run \n[…]\nthe roster for\nPerformance). Regions use the real rendered heights (run cards 5 rows, the '+ New'\ncard 3), verified against the rendered frame.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): make the saved-runs hub cards clickable",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T17:11:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "773c17815166ccd1dfe058634847a4f9586d2e08",
          "body": "…unindented\n\nPer feedback: move the Join this retro block above the four-column grid table,\ntuck the 'Server ready — share the code' status note directly under its heading,\nand unindent the share code / LAN·remote·host URLs to align with the heading\n(dropping the extra level). Widen the grid slack so the four columns never wrap.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(retro): join info back on top (note under the heading), content …",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T14:55:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1203a72c627caa2514aad6cc232401d1322cd9a5",
          "body": "…lace\n\nRich's Live.start() unconditionally re-emits the enter-alt escape, which clears\nthe alternate buffer — a blank flash. When one full-screen page takes over from\nanother already in the alt-screen (notably the splash → menu handoff), that\nre-clear is the occasional flicker after the intro clears\n[…]\n) to skip the alt-enter when already in the alt-screen, while\nstill marking _alt_screen so the final stop() restores the normal screen on exit.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): don't re-clear the alt-screen when a screen takes over in-p…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T14:55:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a59facad1c8a61f240884a9d28b81f3cae8d74b1",
          "body": "… the bottom\n\nThe retro monitoring view stacked the four grids (What went well / didn't / Action\nitems / Demos) vertically with the join instructions on top. Put the four grid\ntitles + cards side by side in a 4-column table across the top, and move the join\ninstructions (share code, LAN/remote/host \n[…]\nndered\nto lines so it still scrolls line-by-line with the rest of the viewport; columns\nsize to the width and crop cleanly on narrow terminals.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(retro): lay the four grids out as a 4-column table, join info at…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T14:43:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "28eec95603e3bd8952406ef2ae4ec0049d7b7c99",
          "body": "… the terminal\n\nLive(screen=True).stop() unconditionally calls set_alt_screen(False) on the with\nexit — restoring the user's real terminal for an instant before the wizard/menu\nre-enters alt (the flash after the intro clears). Rich only calls it there to\nleave alt, and we own the alt-screen and hand\n[…]\nop\nset_alt_screen for the duration of stop(), then restore it. One continuous\nalt-screen: no flicker during the intro, no flash at the handoff.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(splash): keep the alt-screen on exit so the handoff doesn't flash…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T14:30:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "05f1c1c197a9039d48f34241adb5c1ad2e08ef06",
          "body": "Remove the '!' glyph from the exclaim phase; the duck's rear-back-then-snap\nrecoil carries the exclamation on its own.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(splash): drop the yellow exclamation mark",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T14:15:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3e54c733b1033def5d88f2e30eda5bb1b20fa84e",
          "body": "The scaler decoded to 1-bit, silently dropping the ░ light-shade that gives the\nmenu titles their pixel texture (the dots in counters/gaps — e.g. the Y in\nYEABOI). Decode to a 3-level grid (full/light/empty) so ░ survives the upscale;\nthe enlarged wordmark is now genuinely the menu letters, bigger, \n[…]\noved the checker/two-tone dithers (lego/cheese/carpet) — the glyphs\ncarry the texture themselves, so the compositor uses one flat brand colour.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(splash): preserve the ░ light-shade when scaling the menu font",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T14:11:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e2556e08681e2298e6f8237916c4fea0158180ed",
          "body": "The half-block dither punched holes in the strokes (cheese); the dark shade was\nlego. Neither matched the menu titles, which keep every cell full and just tint a\nfaint subset darker. Do the same: render the enlarged wordmark solid (crisp ▀▄\nedges from the scaler) and, in the compositor, tint a checker subset to 72%\nbrightness — a subtle two-tone weave, no holes, low contrast.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(splash): solid YEABOI with a subtle two-tone tint, matching the menu",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T13:50:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "06a979ac5a99f9835389911781cbf58f0dadaa8e",
          "body": "…re lego)\n\nThe ▓ dark-shade dither read as high-contrast lego studs. Switch the fill dither\nto a half-block (▄) — same colour, half-height cells — so the texture matches the\nmenu titles' own ▀▄ half-block pixelation instead of standing out as darker\nbricks. Only █ is dithered, so the letterforms are unchanged.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(splash): texture YEABOI with half-blocks, not a dark shade (no mo…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T13:45:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c8a981c90b64ea1960fe84dc526619da22a8ec7a",
          "body": "- Replace the quack (bob + ripples that read as a vibration) with a single\n  exclamation: after landing the duck rears back with a '!', then snaps forward\n  as YEABOI bursts out.\n- Dither the enlarged wordmark's solid fill on a fine █/▓ checker (texture=True)\n  so it keeps the menu titles' pixel texture instead of reading as flat blocks;\n  the ▀▄ edges stay crisp (only █ is dithered).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(splash): clean exclamation + textured YEABOI wordmark",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T13:36:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "232599ab871003d63a4eadf00235d53d295f8858",
          "body": "The redesigned duck traverses the whole screen (jump in → waddle across), so the\nnon-buffered inline Live (screen=False) diff-redrew a dozen scattered rows every\nframe and tore badly. Switch the splash Live to screen=True — Rich buffers the\nalternate screen and writes one atomic full frame per refre\n[…]\nenter the alt-screen after the Live exits to keep the seamless\nsplash → wizard/menu handoff (one continuous alt-screen, no clear-to-shell gap).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(splash): run the intro double-buffered so it doesn't flicker",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T13:21:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a51ef46c75df77387e5835534e6b60602ba017f2",
          "body": "… wordmark clean\n\nNew brand-splash choreography replacing the walk-in-and-paint intro:\n1. the duck jumps in on an arc from off the left edge,\n2. quacks — a couple of head-bobs each spitting a widening sound ripple,\n3. YEABOI bursts out to his right in the MAIN-MENU block font, scaled up\n   (render_a\n[…]\n _build_run_frame/_run_wordmark_animation\nstay for the per-mode wordmark intros. Layout recomputes per frame so a resize\nmid-intro never tears.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(splash): redesign the intro — duck jumps in, quacks, waddles the…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T13:04:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c4810dc244aace6ba4d382bfc4debe429ee7ab81",
          "body": "The return transition's second phase used a fade-up-from-black for the other\ntitles. Swap it for the same top-left→bottom-right diagonal wipe the fresh-load\nintro uses, so returning reads identically: the mode you came from slides home\nfirst, then the rest scroll in around it.\n\nAdd a sweep_skip para\n[…]\nreen that holds one title fully shown\nwhile the sweep reveals the others, and reuse _sweep_menu_in (with sweep_skip)\nfor the slide's phase two.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): the rest scroll in with the diagonal wipe on menu return",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T12:46:43Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cd435d56b8b588ebbfd49f6a0e8282158a01bd23",
          "body": "Returning to the mode menu used to snap in cold (except the project-list Esc,\nwhich slides). Now every return replays an intro:\n\n- Cold return from a mode/hub → the mode you came from slides back down from the\n  top (the inverse of the select→page lift), then the other titles fade up around\n  it — '\n[…]\nenu_in;\nthe project-list Esc keeps its own (card-dismiss + slide) reverse transition and\nflags _reverse_animated so the loop doesn't double up.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): animate the menu back in on every return",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T12:35:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d53aff364d4a1f1b46b425e84fa8ff7b65d97cdb",
          "body": "The bright bar under the active tab ended on a hard edge against the dim\nshoulders. Step the last char on either end down to the mid accent so it fades\nout — full brightness across all inner chars, one dim level at each end, then\nthe dimmer shoulder chars, then the neutral rule.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(settings): taper the active tab underline in three steps",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T12:14:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9884e965d3c9cdafe7910ea33e4e9f411d538aad",
          "body": "The section _heading helper always prepended a blank, so on the first heading\nit stacked on top of the subtitle's own trailing blank — two blank rows under\nthe subtitle. Skip the leading blank when the heading is the first body line;\na status message (when present) is still separated from the section by it.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): drop the doubled blank under the retro/poker subtitle",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T12:05:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "47019d83dc04bdbaf1c4386f4fcfe382e2602522",
          "body": "Mirror the Usage page: drop the Copy/Back action buttons for a lightweight\n'c copy · Esc back' keyboard hint aligned with the headings, and wire c/C to\ncopy and Esc/q to back in both run loops.\n\nPin each viewport line to a single row (no_wrap + crop) so a long changelog\nentry — its inline area tags \n[…]\nthe hint off the\nbottom where the crop and the music pocket swallow it. Update the stale\nbutton-assertion tests to check the hint text instead.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): replace Changelog/All-Tips button rows with keyboard hints",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T12:01:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5e6eafadd7f02dc08f889e51ff7c4826473d2747",
          "body": "…lide\n\nThe select→page slide eases every mode's title to end_offset=1 (one blank\nabove the title, matching the project-list layout). The saved-runs hub instead\nseated its title at selected_title_offset(0) — level with the menu's top row,\n~3 blanks down — so the instant the slide handed off to the hu\n[…]\npdate the stale Usage test: the Copy/Back button row became a keyboard\nhint, so assert the 'copy'/'back' hint text rather than a 'Back' button.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tui): stop the standup/retro/poker hub title dropping after the s…",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T11:37:52Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fb463d4af8ac6c3b65717928da8d9769af91cde2",
          "body": "Subtitle + hint were at _PAD (2), left of the title and their own body. Move\nthem to the title column (_PAD + 2) and the message body one level in.",
          "is_bot": false,
          "headline": "fix(tui): align the board-required/export-status subtitle with the title",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T11:18:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "26465fcdbc15a6b0d10d3553a728858b72ddc59e",
          "body": "- Indent every secondary screen's subtitle to the title column (was 2, now 4),\n  matching the headings.\n- Usage screen: drop the doubled blank under the subtitle, remove the Copy/Back\n  button row for a keyboard hint (c copy · Esc back); wire 'c' to copy and Esc\n  to back in the loop.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): indent secondary subtitles + strip the Usage button row",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T11:14:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "371a49485bc32f57d3cc65070e2c8f29ad22e227",
          "body": "…de packing, pptx (#109)\n\n* reporting overhaul: threaded generate, themes, deck styles, smart slide packing, pptx\n\nBring Reporting mode to parity with analysis/standup and make the exported\npresentations business-ready:\n\n- threaded generation behind the shared progress screen (on_progress /\n  cancel\n[…]\nthropic.com>\n\n---------\n\nCo-authored-by: Dev Person <dev@example.com>\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>\nCo-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "reporting overhaul: threaded generate, themes, deck styles, smart sli…",
          "author_name": "Dinho",
          "author_login": "dinho149",
          "committed_at": "2026-07-28T11:02:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7a68177e9ac997dc92710105fa9e3887f43bd9f7",
          "body": "Every secondary screen (usage, standup, retro, poker, performance, reporting,\nanalysis, changelog, all-tips, roadmap, project list…) indented content via a\nmix of PAD and its _PAD alias, both 4 spaces — deeper than the title. Point the\nwhole file at one 2-space _PAD so headings land at the title's c\n[…]\nmn and value\nrows one level in, matching Settings. All PAD refs in the file collapse to _PAD;\nlen(_PAD)-based width math stays self-consistent.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): unify secondary-screen indentation with the Settings scheme",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T10:59:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a7bb19c05ab87bb993678b99e925b6f5d429a8ae",
          "body": "Clicking a row now turns its value into an inline edit field (buffer + block\ncursor) right on the settings screen — the rest of the rows stay visible —\nrather than opening a full-screen input. Type/backspace/arrows/paste edit the\nbuffer; Enter saves to .env (applies log level live), Esc cancels. Hid\n[…]\n-aware flow. The full-screen _settings_edit_field is replaced by\n_settings_edit_keypress; the hint switches to edit instructions while editing.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(settings): edit config rows in place instead of a separate prompt",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T10:44:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cc570455701fe60e25a99eef21e340abb529e4f6",
          "body": "Each section heading already leads with a blank, so the extra blank after the\ntab bar doubled the gap before the first heading. Remove it and shift the\nviewport/​row-region math up one row to match.",
          "is_bot": false,
          "headline": "fix(settings): drop the doubled blank line under the tab bar",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T10:36:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "00f12351655bea9d446dcb01e6353445e2d0e5e1",
          "body": "Previously only the main menu showed the 'resize me' guard below the size\nfloor; settings, hubs, wizards and the rest rendered cramped/clipped. Add the\ncheck to MusicLive.get_renderable — the single chokepoint every screen renders\nthrough — so any screen under _MIN_WIDTH×_MIN_HEIGHT (84×40) shows the too-small\nduck instead. Test consoles bumped above the floor where they exercise other\nbehaviour.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): enforce the min terminal size on every screen",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T10:30:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3e4e89dfea5e50f33eb0bd79115584d53a48d925",
          "body": "Every env-backed row is now clickable: clicking opens an inline editor for that\nvariable, persists it to .env (set_config_value) and applies live where needed\n(log level). Rows carry their (env, label, masked) via an _EditableRow Text\nsubclass; the builder attaches per-row click regions (absolute ro\n[…]\n); Data Directory routes to the existing move-aware flow; read-only rows\n(Dictation status, Config File path) stay non-clickable. Hint updated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(settings): click any config row to edit its value",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T10:19:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6b0288ee832c240db35a37e2e7ec4311e343baf2",
          "body": "Extend the rule two chars past each end of the tab strip so the dimmer shoulder\nbeside the active tab stays visible when the first or last tab is selected.",
          "is_bot": false,
          "headline": "feat(settings): keep a 2-char margin on the tab underline",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T10:07:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cd71ac6f6349efce4ab652b2d266cd8519abfbd5",
          "body": "Start the rule at the first tab's left edge (no longer poking out left of\nCredentials) and end it at the last tab's right edge.",
          "is_bot": false,
          "headline": "feat(settings): span the tab underline exactly under the tab strip",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T10:05:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "484842a11583083ab52575bc183952c72e4a3e79",
          "body": "The rule ran nearly edge-to-edge; end it just past the last tab so it reads as\na compact tab underline rather than a full-width divider.",
          "is_bot": false,
          "headline": "feat(settings): shorten the tab-bar underline to the tab strip",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T10:02:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c16f13e4ed2cebb9a3c5a63db898abe993f4d5b2",
          "body": "Refine the tabbed Settings screen per feedback:\n- Underline-style tab bar: labels over one continuous horizontal rule, the\n  segment under the active tab accent-bright with dimmer flanking chars, no\n  vertical dividers. Clicks hit-test attached tab regions (labels + rule rows).\n- Group into 3 broad \n[…]\n Drop the 'Current configuration' subtitle; align content indent with the\n  SETTINGS title (headings at the title's column, rows one level in).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(settings): underline tab bar, 3 grouped tabs, aligned indent",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T09:58:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "409cfefa029dd7d6fae1dff96fab6391787523f6",
          "body": "Replace the long scrolling all-sections list + action-button row with a tabbed\nview: a top tab bar (Provider, Jira, Azure, GitHub, Notion, Storage, Standup,\nVoice, Bedrock, Advanced) switches which config section is shown. ←/→ (and Tab)\ncycle tabs; clicking a tab jumps to it (tab_click in _click.py \n[…]\none: Esc = Back, and\nEnter runs the section's context action — data-dir editor on Storage, log-level\ncycle on Advanced, setup wizard elsewhere.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(settings): tabbed section view with a clickable tab bar",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T09:33:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e52a8dcff307f7cd98340713fad2a89ad9cc0fe9",
          "body": "The formatter stripped button_click from the import while it was briefly\nunused mid-edit; clicking a destination would have raised NameError.",
          "is_bot": false,
          "headline": "fix(export-picker): restore dropped button_click import",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T09:33:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "81decc8f29156808705db10a48508ffd8d011592",
          "body": "First slice of app-wide click support. New src/yeaboi/ui/shared/_click.py:\nparse_click() decodes click events, button_click() maps a click to a\nbuild_action_buttons index by hit-testing the ACTUAL rendered frame (scans for\nthe ╭──╮ button runs), so it's robust to top-flowed vs bottom-anchored rows,\nvariable title heights, and popup shifts — no per-screen geometry. Wired into\nthe shared export-destination picker and the output-share screen.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tui): add shared click hit-testing + wire export/share buttons",
          "author_name": "neakoh",
          "author_login": "neakoh",
          "committed_at": "2026-07-28T09:01:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        }
      ],
      "releases_count": 66,
      "commits_last_year": 442,
      "latest_release_at": "2026-08-02T11:01:11Z",
      "latest_release_tag": "v2.47.1",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 7,
      "days_since_latest_release": 0,
      "mean_days_between_releases": 0.7
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 57,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "yeaboi",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "agile",
            "ai-agent",
            "ai-scrum-master",
            "azure-devops",
            "cli",
            "jira",
            "llm",
            "mcp",
            "planning-poker",
            "project-management",
            "retrospective",
            "scrum",
            "sprint-planning",
            "standup",
            "tui",
            "Development Status :: 4 - Beta",
            "Environment :: Console",
            "Intended Audience :: Developers",
            "License :: OSI Approved :: MIT License",
            "Programming Language :: Python :: 3.11",
            "Programming Language :: Python :: 3.12",
            "Programming Language :: Python :: 3.13",
            "Topic :: Software Development :: Libraries :: Application Frameworks"
          ],
          "ecosystem": "pypi",
          "matches_repo": true,
          "registry_url": "https://pypi.org/project/yeaboi/",
          "is_deprecated": false,
          "latest_version": "2.47.1",
          "repository_url": "https://github.com/dinho149/yeaboi.ai",
          "versions_count": 48,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 5329,
          "first_published_at": "2026-07-16T13:02:12.224821Z",
          "latest_published_at": "2026-08-02T11:00:51.613679Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 2,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 4
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "example"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": true,
      "bootstrap_files": [
        "Makefile",
        "desktop-pet/node_modules/json-stringify-safe/Makefile",
        "desktop-pet/node_modules/progress/Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "desktop-pet/node_modules/boolean/tsconfig.json",
        "desktop-pet/node_modules/define-data-property/tsconfig.json",
        "desktop-pet/node_modules/es-define-property/tsconfig.json",
        "desktop-pet/node_modules/es-errors/tsconfig.json",
        "desktop-pet/node_modules/gopd/tsconfig.json",
        "frontend/tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 584773,
      "source_files_sampled": 688,
      "oversized_source_files": 25,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 18378
    },
    "dependencies": {
      "manifests": [
        "frontend/package.json",
        "pyproject.toml"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm",
        "pypi"
      ],
      "dependencies": [
        {
          "name": "preact",
          "manifest": "frontend/package.json",
          "ecosystem": "npm",
          "version_constraint": "^10.29.1"
        },
        {
          "name": "langchain",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "langgraph",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "langchain-anthropic",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "rich",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "prompt-toolkit",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "python-dotenv",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "PyGithub",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "azure-devops",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "jira",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "atlassian-python-api",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "notion-client",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "langgraph-checkpoint-sqlite",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "holidays",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "segno",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        }
      ],
      "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": 3,
        "merged_prs": 114,
        "open_issues": 1,
        "closed_ratio": 0,
        "closed_issues": 0,
        "closed_unmerged_prs": 14
      },
      "bus_factor": 1,
      "bot_contributors": 2,
      "top_contributors": [
        {
          "type": "User",
          "login": "neakoh",
          "commits": 207,
          "avatar_url": "https://avatars.githubusercontent.com/u/114689967?v=4"
        },
        {
          "type": "User",
          "login": "dinho149",
          "commits": 108,
          "avatar_url": "https://avatars.githubusercontent.com/u/64692956?v=4"
        },
        {
          "type": "User",
          "login": "nikomain",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/208644664?v=4"
        }
      ],
      "contributors_sampled": 3,
      "top_contributor_share": 0.653
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "auto-version.yml",
        "backlog-groomer.yml",
        "ci-sentinel.yml",
        "ci.yml",
        "claude-review.yml",
        "claude.yml",
        "codeql.yml",
        "dependabot-auto.yml",
        "feedback-remediation.yml",
        "flaky-test-hunter.yml",
        "publish.yml",
        "security-scan.yml",
        "smoke.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [
        ".eslintrc",
        ".eslintrc.json"
      ],
      "has_editorconfig": true,
      "has_linter_config": true,
      "has_precommit_config": true
    },
    "security_signals": {
      "lockfiles": [
        "package-lock.json",
        "uv.lock",
        "yarn.lock"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 3,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "15 out of 15 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/14 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 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": 8,
            "reason": "SAST tool detected but not run on all commits",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 10,
            "reason": "security policy file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": 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": 5,
            "reason": "5 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "8f4d56290f6118a5fc290628b8373ad44caf6bf5",
        "ran_at": "2026-08-02T11:04:28Z",
        "aggregate_score": 5.9,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": true,
      "has_security_policy": true,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-08-02T11:03:46Z",
      "oldest_open_prs": [
        {
          "number": 125,
          "created_at": "2026-08-01T13:26:45Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 130,
          "created_at": "2026-08-01T20:31:36Z",
          "last_comment_at": "2026-08-01T20:39:53Z",
          "last_comment_author": "claude"
        },
        {
          "number": 131,
          "created_at": "2026-08-02T10:32:18Z",
          "last_comment_at": "2026-08-02T10:33:40Z",
          "last_comment_author": "claude"
        }
      ],
      "last_merged_pr_at": "2026-08-02T10:58:29Z",
      "ci_last_conclusion": "SKIPPED",
      "oldest_open_issues": [
        {
          "number": 105,
          "created_at": "2026-07-27T10:22:01Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/dinho149/yeaboi.ai",
    "host": "github.com",
    "name": "yeaboi.ai",
    "owner": "dinho149"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": "The weighted overall 65 is calibrated to 75 on the published index scale (record calibration 2026-08-02).",
      "notes": [
        {
          "code": "overall_calibration",
          "params": {
            "raw": 65,
            "calibrated": 75,
            "calibration": "2026-08-02"
          }
        }
      ],
      "value": 75,
      "inputs": {
        "security": 59,
        "vitality": 81,
        "community": 33,
        "governance": 46,
        "calibration": "2026-08-02",
        "engineering": 100,
        "ai_readiness": 82,
        "weighted_overall_raw": 65
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 81,
        "weight": 0.21,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 69,
            "inputs": {
              "commits_last_year": 442,
              "human_commit_share": 0.99,
              "days_since_last_push": 0,
              "active_weeks_last_year": 7
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "7/52 weeks with commits",
                "points": 4.8,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 7
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "442 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 442
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "exceptional",
            "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": 100,
            "inputs": {
              "releases_count": 66,
              "latest_release_tag": "v2.47.1",
              "releases_from_tags": false,
              "days_since_latest_release": 0,
              "mean_days_between_releases": 0.7
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "66 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 66
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~0.7 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 0.7
                    }
                  }
                ],
                "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": "exceptional",
            "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": "at_risk",
        "name": "Community & Adoption",
        "value": 33,
        "weight": 0.17,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 2,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "2 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "readme_badges": null,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "readme_badge_services": [],
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "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": 62,
            "inputs": {
              "packages": [
                "yeaboi"
              ],
              "dependents": null,
              "ecosystems": "pypi",
              "total_downloads": null,
              "monthly_downloads": 5329
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "5,329 downloads/month across pypi",
                "points": 49.7,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 5329,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "weak",
        "name": "Sustainability & Governance",
        "value": 46,
        "weight": 0.23,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "at_risk",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 21,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 3,
              "top_contributor_share": 0.653
            },
            "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 65% of commits",
                "points": 7.8,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 65
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "3 contributors",
                "points": 4.1,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "at_risk",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Newcomer PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "newcomer_pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 31,
            "inputs": {
              "merged_prs": 114,
              "open_issues": 1,
              "closed_issues": 0,
              "prs_merged_7d": null,
              "prs_decided_7d": null,
              "prs_merged_30d": null,
              "prs_decided_30d": null,
              "issue_closed_ratio": 0,
              "closed_unmerged_prs": 14,
              "first_time_authors_30d": null,
              "first_time_prs_merged_30d": null,
              "first_time_prs_decided_30d": null
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "0% of issues closed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 0
                    }
                  }
                ],
                "max_points": 42
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "114/128 decided PRs merged",
                "points": 26.7,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 114,
                      "decided": 128
                    }
                  }
                ],
                "max_points": 30
              },
              {
                "key": "newcomer_pr_acceptance",
                "name": "Newcomer PR acceptance",
                "detail": "no first-time contributor's PR decided in 30d",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_newcomer_prs",
                    "params": {
                      "days": 30
                    }
                  }
                ],
                "max_points": 13
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/14 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "weak",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 47,
            "inputs": {
              "followers": 3,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "dinho149",
              "public_repos": 38,
              "account_age_days": 2282
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "3 followers of dinho149",
                "points": 4.3,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 3,
                      "login": "dinho149"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "38 public repos, account ~6 yr old",
                "points": 23.6,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 38
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 6
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "exceptional",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "yeaboi"
              ],
              "ecosystems": "pypi",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on pypi",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 0 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "48 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 48
                    }
                  }
                ],
                "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": "exceptional",
        "name": "Engineering Quality",
        "value": 100,
        "weight": 0.19,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "exceptional",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": true,
              "has_linter_config": true,
              "has_precommit_config": true
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "13 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 13
                    }
                  }
                ],
                "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": ".eslintrc, .eslintrc.json",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".eslintrc, .eslintrc.json"
                    }
                  }
                ],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 9.6,
                "status": "met",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 6.4,
                "status": "met",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "15 out of 15 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "exceptional",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "topics": [
                "agile",
                "ai-agent",
                "ai-scrum-master",
                "azure-devops",
                "claude",
                "cli",
                "jira",
                "langgraph",
                "llm",
                "mcp",
                "mcp-server",
                "planning-poker",
                "python",
                "retrospective",
                "scrum",
                "scrum-master",
                "sprint-planning",
                "standup",
                "terminal",
                "tui"
              ],
              "has_wiki": true,
              "homepage": "https://yeaboi.ai/",
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://yeaboi.ai/",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": "20 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 20
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 59,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 59,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 5.9
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "15 out of 15 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/14 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool detected but not run on all commits",
                "points": 4,
                "status": "partial",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "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": "5 existing vulnerabilities detected",
                "points": 3.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "exceptional",
            "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"
              ],
              "commit_weight_rule": {
                "min_commits": 50,
                "min_commit_share": 0.1
              },
              "review_only_matches": 0,
              "below_threshold_exposures": [],
              "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": "excellent",
        "name": "AI Readiness",
        "value": 82,
        "weight": 0.04,
        "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": 18378
            },
            "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": "99 of 99 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 99,
                      "sampled": 99
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "excellent",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "package-lock.json",
                "uv.lock",
                "yarn.lock"
              ],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [
                "Makefile",
                "desktop-pet/node_modules/json-stringify-safe/Makefile",
                "desktop-pet/node_modules/progress/Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [
                "desktop-pet/node_modules/boolean/tsconfig.json",
                "desktop-pet/node_modules/define-data-property/tsconfig.json",
                "desktop-pet/node_modules/es-define-property/tsconfig.json",
                "desktop-pet/node_modules/es-errors/tsconfig.json",
                "desktop-pet/node_modules/gopd/tsconfig.json",
                "frontend/tsconfig.json"
              ],
              "agent_commit_share": 0.9,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0.01
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile, desktop-pet/node_modules/json-stringify-safe/Makefile, desktop-pet/node_modules/progress/Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile, desktop-pet/node_modules/json-stringify-safe/Makefile, desktop-pet/node_modules/progress/Makefile"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": ".eslintrc, .eslintrc.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".eslintrc, .eslintrc.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "desktop-pet/node_modules/boolean/tsconfig.json, desktop-pet/node_modules/define-data-property/tsconfig.json, desktop-pet/node_modules/es-define-property/tsconfig.json, desktop-pet/node_modules/es-errors/tsconfig.json, desktop-pet/node_modules/gopd/tsconfig.json, frontend/tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "desktop-pet/node_modules/boolean/tsconfig.json, desktop-pet/node_modules/define-data-property/tsconfig.json, desktop-pet/node_modules/es-define-property/tsconfig.json, desktop-pet/node_modules/es-errors/tsconfig.json, desktop-pet/node_modules/gopd/tsconfig.json, frontend/tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "90 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 90,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "1 of the last 100 commits are automated dependency updates",
                "points": 8,
                "status": "met",
                "details": [
                  {
                    "code": "dependency_bot_commits",
                    "params": {
                      "count": 1,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 80,
            "inputs": {
              "primary_language": "Python",
              "largest_source_bytes": 584773,
              "source_files_sampled": 688,
              "oversized_source_files": 25
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Python with type-check config (desktop-pet/node_modules/boolean/tsconfig.json, desktop-pet/node_modules/define-data-property/tsconfig.json, desktop-pet/node_modules/es-define-property/tsconfig.json, desktop-pet/node_modules/es-errors/tsconfig.json, desktop-pet/node_modules/gopd/tsconfig.json, frontend/tsconfig.json)",
                "points": 27,
                "status": "partial",
                "details": [
                  {
                    "code": "typecheck_config_language",
                    "params": {
                      "files": "desktop-pet/node_modules/boolean/tsconfig.json, desktop-pet/node_modules/define-data-property/tsconfig.json, desktop-pet/node_modules/es-define-property/tsconfig.json, desktop-pet/node_modules/es-errors/tsconfig.json, desktop-pet/node_modules/gopd/tsconfig.json, frontend/tsconfig.json",
                      "language": "Python"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "25/688 source files over 60KB",
                "points": 53,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 688,
                      "oversized": 25
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "moderate",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "example_dirs": [
                "example"
              ],
              "has_mcp_signal": true,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "example",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "example"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
      }
    ],
    "classification": {
      "top": [
        "library",
        "application"
      ],
      "labels": [
        "library",
        "mcp-server",
        "web-ui"
      ],
      "scores": {
        "cli": 2,
        "tui": 2,
        "web-ui": 4,
        "library": 6,
        "mcp-server": 5
      },
      "primary": "library",
      "evidence": [
        {
          "tier": "distribution",
          "label": "library",
          "source": "registry:pypi",
          "weight": 6
        },
        {
          "tier": "dependencies",
          "label": "web-ui",
          "source": "dep:preact",
          "weight": 4
        },
        {
          "tier": "structure",
          "label": "mcp-server",
          "source": "mcp_signal",
          "weight": 3
        },
        {
          "tier": "tags",
          "label": "cli",
          "source": "tag:cli",
          "weight": 2
        },
        {
          "tier": "tags",
          "label": "mcp-server",
          "source": "tag:mcp-server",
          "weight": 2
        },
        {
          "tier": "tags",
          "label": "tui",
          "source": "tag:tui",
          "weight": 2
        }
      ],
      "artifacts": [],
      "confidence": "medium",
      "host_extension": false,
      "runs_as_process": true,
      "consumed_by_code": true
    },
    "metrics_version": "2.5.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index pypi:yeaboi@2.47.1; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-08-02T11:04:47.299171Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/d/dinho149/yeaboi.ai.svg",
  "full_name": "dinho149/yeaboi.ai",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

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