公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-24 16:29 UTC

marcus / td

A minimalist CLI for tracking tasks across AI coding sessions.

GoMIT★ 232 星标⑂ 27 复刻始于 2025年12月在 GitHub 上查看 ↗

marcus/td 的健康指数为 100 分中的 60 分,处于「中等」区间。 其得分最高的类别是Vitality(83/100),最低的是Security(33/100)。 最近一次更新在 5 天前。 近期的大部分工作由 1 位贡献者完成。

60
总分 / 100
中等

软件健康指数

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

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

评分画像

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

所有权

Marcus Vorwaller个人账户
217 关注者28 个公开仓库始于 2008年3月Avalara

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

软件包生态系统

注册表软件包版本月下载量版本数最近发布
Gogithub.com/marcus/tdv0.51.2-996 天前

按类别列示的指标

活力

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

83良好 · 占总体的 22%
评分方式
36/36推送新近度 — 最近一次推送于 5 天前
15.2/36提交节奏 — 52 周中有 22 周有提交
18/18提交量 — 最近一年 841 次提交
10/10OpenSSF Scorecard:Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
所用输入
commits_last_year841
human_commit_share1
days_since_last_push5
active_weeks_last_year22

发布纪律

90优秀
评分方式
27/27有发布版本 — 已发布 64 个发布版本
36/36发布时效 — 最近一次发布版本于 6 天前
27/27发布节奏 — 约每 3.4 天发布一次
0/10OpenSSF Scorecard:Signed-Releases — Project has not signed or included provenance with any releases.
所用输入
releases_count64
latest_release_tagv0.51.2
releases_from_tags
days_since_latest_release6
mean_days_between_releases3.4

社区与采用

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

50中等 · 占总体的 18%
评分方式
38.3/60星标 — 232 个星标
11.8/25复刻 — 27 个复刻
0/15关注者 — 2 位关注者
所用输入
forks27
stars232
watchers2
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
has_contributing
has_issue_template
has_code_of_conduct
has_pull_request_template

可持续性与治理

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

54中等 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0.8/22.5提交分布 — 头号贡献者编写了 97% 的提交
12.2/13.5贡献者广度 — 9 位贡献者
3/10OpenSSF Scorecard:Contributors — project has 1 contributing companies or organizations -- score normalized to 3
所用输入
bus_factor1
contributors_sampled9
top_contributor_share0.966
评分方式
15.1/46.8议题解决 — 32% 的议题已关闭
28.7/38.3PR 接受 — 已裁定的 PR 中 33/44 已合并
0/15OpenSSF Scorecard:Code-Review — Found 0/30 approved changesets -- score normalized to 0
所用输入
merged_prs33
open_issues23
closed_issues11
issue_closed_ratio0.324
closed_unmerged_prs11
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
16.8/25所有者影响力 — marcus 有 217 位关注者
22.6/25既往记录 — 28 个公开仓库,账户约 18 年
所用输入
followers217
owner_typeUser
is_verified
owner_loginmarcus
public_repos28
account_age_days6,706
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。
评分方式
25/25已发布且可解析 — go 上有 1 个软件包
35/35发布时效 — 最近一次发布于 6 天前
20/20版本历史 — 99 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagesgithub.com/marcus/td
ecosystemsgo
any_deprecated
min_days_since_publish6

工程质量

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

70良好 · 占总体的 20%

工程实践

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

文档

85优秀
评分方式
30/30README
25/25文档目录
0/15文档 / 主页站点
10/10仓库描述
10/10主题标签 — 2 个主题标签
10/10Wiki
所用输入
topicsagents, ai
has_wiki
homepage
has_readme
has_docs_dir
has_description

安全

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

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

安全态势

33存在风险
评分方式
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — 无数据
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no 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
1/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 2
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
0/7.5Vulnerabilities — 67 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate3.3
已排除计分(无数据或不适用):ci_tests。 其余权重已重新归一化。

AI 就绪度

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

82良好 · 占总体的 0%
评分方式
45/45代理指令 — AGENTS.md, CLAUDE.md
0/15机器可读文档(llms.txt)
40/40可读的提交历史 — 100 次人类提交中有 97 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.97
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes8,569
评分方式
18/18一条命令的引导启动 — Makefile
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — Go(静态类型)
10/10可复现环境 — Dockerfile, lockfile
10/10已体现的代理实践 — 最近 100 次提交中有 73 次由代理编写或署名代理
0/8自动化维护 — 未观察到自动依赖更新
2/10OpenSSF Scorecard:Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 2
所用输入
has_nix
has_tests
lockfilesgo.sum, package-lock.json
has_dockerfile
typed_language
bootstrap_filesMakefile
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0.73
toolchain_manifestsgo.mod
dependency_bot_commit_share0
评分方式
45/45可类型检查的代码 — Go(静态类型)
54.5/55可控的文件大小 — 采样的 480 个源文件中有 4 个超过 60KB
所用输入
primary_languageGo
largest_source_bytes134,501
source_files_sampled480
oversized_source_files4

关键数据

232GitHub 星标
9贡献者
841最近 12 个月提交数
5距最近推送天数
64发布版本数
1巴士系数(bus factor)
23开放议题
Go, npm软件包生态系统数

数据采集警告

  • 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

更多细节

Star 与 Fork 历史 0 ★ / 27 ⇿
0Star
27Fork
22发布

每颗 star 和每个 fork 的添加时间,来自 GitHub 并按天汇总。累计增长位于其构成来源——每日新增——的正上方,二者可相互对照:稳定的自然增长与短暂的突增形态截然不同。当这一差别可被衡量时,它会作为增长真实性予以报告。

0510152025302732026-022026-042026-06
主版本 0次版本 18修订 4
OpenSSF Scorecard 3.3 / 10
3.3综合

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

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
不适用CI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update 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
2Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 2
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities67 existing vulnerabilities detected
直接依赖 24
注册表软件包版本约束清单文件
Gocharm.land/bubbles/v2v2.1.0go.mod
Gocharm.land/bubbletea/v2v2.0.7go.mod
Gocharm.land/glamour/v2v2.0.0go.mod
Gocharm.land/huh/v2v2.0.3go.mod
Gocharm.land/lipgloss/v2v2.0.3go.mod
Gogithub.com/charmbracelet/x/ansiv0.11.7go.mod
Gogithub.com/charmbracelet/x/cellbufv0.0.15go.mod
Gogithub.com/mattn/go-sqlite3v1.14.33go.mod
Gogithub.com/sahilm/fuzzyv0.1.1go.mod
Gogithub.com/spf13/cobrav1.10.2go.mod
Gogithub.com/spf13/pflagv1.0.10go.mod
Gogolang.org/x/cryptov0.47.0go.mod
Gogolang.org/x/syncv0.20.0go.mod
Gogolang.org/x/sysv0.45.0go.mod
Gogolang.org/x/termv0.39.0go.mod
Gomodernc.org/sqlitev1.41.0go.mod
npm@docusaurus/core3.9.2website/package.json
npm@docusaurus/preset-classic3.9.2website/package.json
npm@mdx-js/react^3.0.0website/package.json
npmclsx^2.0.0website/package.json
npmlucide-react^0.563.0website/package.json
npmprism-react-renderer^2.3.0website/package.json
npmreact^19.0.0website/package.json
npmreact-dom^19.0.0website/package.json
全部依赖 未采集

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [
        "agents",
        "ai"
      ],
      "is_fork": false,
      "size_kb": 62944,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "Go": 5425574,
        "CSS": 35448,
        "HTML": 26477,
        "Shell": 424028,
        "Makefile": 2016,
        "Dockerfile": 721,
        "JavaScript": 24380
      },
      "pushed_at": "2026-07-18T19:48:34Z",
      "created_at": "2025-12-09T06:44:31Z",
      "owner_type": "User",
      "updated_at": "2026-07-18T19:48:38Z",
      "description": "A minimalist CLI for tracking tasks across AI coding sessions.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": "http://marcus.pictures",
      "name": "Marcus Vorwaller",
      "type": "User",
      "login": "marcus",
      "company": "Avalara",
      "location": "Seattle, Washington",
      "followers": 217,
      "avatar_url": "https://avatars.githubusercontent.com/u/3090?v=4",
      "created_at": "2008-03-14T14:33:29Z",
      "is_verified": null,
      "public_repos": 28,
      "account_age_days": 6706
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.51.2",
          "kind": "patch",
          "published_at": "2026-07-18T16:00:12Z"
        },
        {
          "tag": "v0.51.1",
          "kind": "patch",
          "published_at": "2026-07-18T15:02:33Z"
        },
        {
          "tag": "v0.51.0",
          "kind": "minor",
          "published_at": "2026-06-21T04:06:59Z"
        },
        {
          "tag": "v0.50.1",
          "kind": "patch",
          "published_at": "2026-06-20T22:09:47Z"
        },
        {
          "tag": "v0.50.0",
          "kind": "minor",
          "published_at": "2026-06-20T21:48:10Z"
        },
        {
          "tag": "v0.49.0",
          "kind": "minor",
          "published_at": "2026-06-19T16:13:15Z"
        },
        {
          "tag": "v0.48.0",
          "kind": "minor",
          "published_at": "2026-06-19T01:04:41Z"
        },
        {
          "tag": "v0.47.4",
          "kind": "patch",
          "published_at": "2026-06-18T17:50:45Z"
        },
        {
          "tag": "v0.47.3",
          "kind": "patch",
          "published_at": "2026-06-18T06:41:00Z"
        },
        {
          "tag": "v0.47.2",
          "kind": "patch",
          "published_at": "2026-06-17T19:22:37Z"
        },
        {
          "tag": "v0.47.1",
          "kind": "patch",
          "published_at": "2026-06-17T16:13:02Z"
        },
        {
          "tag": "v0.47.0",
          "kind": "minor",
          "published_at": "2026-06-15T23:35:20Z"
        },
        {
          "tag": "v0.46.0",
          "kind": "minor",
          "published_at": "2026-06-11T14:24:29Z"
        },
        {
          "tag": "v0.45.0",
          "kind": "minor",
          "published_at": "2026-06-09T03:29:09Z"
        },
        {
          "tag": "v0.44.0",
          "kind": "minor",
          "published_at": "2026-04-18T21:26:47Z"
        },
        {
          "tag": "v0.43.0",
          "kind": "minor",
          "published_at": "2026-03-24T04:16:07Z"
        },
        {
          "tag": "v0.42.2",
          "kind": "patch",
          "published_at": "2026-03-21T15:20:07Z"
        },
        {
          "tag": "v0.42.1",
          "kind": "patch",
          "published_at": "2026-03-21T03:30:57Z"
        },
        {
          "tag": "v0.42.0",
          "kind": "minor",
          "published_at": "2026-03-10T00:07:06Z"
        },
        {
          "tag": "v0.41.0",
          "kind": "minor",
          "published_at": "2026-03-01T02:01:26Z"
        },
        {
          "tag": "v0.40.0",
          "kind": "minor",
          "published_at": "2026-02-28T06:55:18Z"
        },
        {
          "tag": "v0.39.0",
          "kind": "minor",
          "published_at": "2026-02-27T07:07:24Z"
        },
        {
          "tag": "v0.38.0",
          "kind": "minor",
          "published_at": "2026-02-19T17:16:27Z"
        },
        {
          "tag": "v0.37.0",
          "kind": "minor",
          "published_at": "2026-02-15T20:54:50Z"
        },
        {
          "tag": "v0.36.0",
          "kind": "minor",
          "published_at": "2026-02-14T22:06:07Z"
        },
        {
          "tag": "v0.35.0",
          "kind": "minor",
          "published_at": "2026-02-14T19:10:45Z"
        },
        {
          "tag": "v0.34.0",
          "kind": "minor",
          "published_at": "2026-02-11T04:54:24Z"
        },
        {
          "tag": "v0.33.0",
          "kind": "minor",
          "published_at": "2026-02-10T02:36:43Z"
        },
        {
          "tag": "v0.32.0",
          "kind": "minor",
          "published_at": "2026-02-09T04:18:37Z"
        },
        {
          "tag": "v0.31.0",
          "kind": "minor",
          "published_at": "2026-02-07T23:57:11Z"
        },
        {
          "tag": "v0.30.0",
          "kind": "minor",
          "published_at": "2026-02-06T17:17:10Z"
        },
        {
          "tag": "v0.29.0",
          "kind": "minor",
          "published_at": "2026-02-03T00:31:37Z"
        },
        {
          "tag": "v0.28.1",
          "kind": "patch",
          "published_at": "2026-02-01T01:14:53Z"
        },
        {
          "tag": "v0.28.0",
          "kind": "minor",
          "published_at": "2026-01-30T20:06:39Z"
        },
        {
          "tag": "v0.27.0",
          "kind": "minor",
          "published_at": "2026-01-30T17:21:27Z"
        },
        {
          "tag": "v0.26.0",
          "kind": "minor",
          "published_at": "2026-01-30T00:08:17Z"
        },
        {
          "tag": "v0.25.0",
          "kind": "minor",
          "published_at": "2026-01-29T05:25:05Z"
        },
        {
          "tag": "v0.24.0",
          "kind": "minor",
          "published_at": "2026-01-28T21:20:24Z"
        },
        {
          "tag": "v0.23.0",
          "kind": "minor",
          "published_at": "2026-01-26T21:00:09Z"
        },
        {
          "tag": "v0.22.2",
          "kind": "patch",
          "published_at": "2026-01-26T19:00:39Z"
        },
        {
          "tag": "v0.22.1",
          "kind": "patch",
          "published_at": "2026-01-26T18:40:39Z"
        },
        {
          "tag": "v0.22.0",
          "kind": "minor",
          "published_at": "2026-01-25T21:09:47Z"
        },
        {
          "tag": "v0.21.0",
          "kind": "minor",
          "published_at": "2026-01-24T01:35:57Z"
        },
        {
          "tag": "v0.20.0",
          "kind": "minor",
          "published_at": "2026-01-21T21:34:59Z"
        },
        {
          "tag": "v0.19.0",
          "kind": "minor",
          "published_at": "2026-01-21T19:15:15Z"
        },
        {
          "tag": "v0.18.0",
          "kind": "minor",
          "published_at": "2026-01-20T22:48:34Z"
        },
        {
          "tag": "v0.17.0",
          "kind": "minor",
          "published_at": "2026-01-20T06:08:33Z"
        },
        {
          "tag": "v0.16.0",
          "kind": "minor",
          "published_at": "2026-01-20T05:41:44Z"
        },
        {
          "tag": "v0.15.1",
          "kind": "patch",
          "published_at": "2026-01-19T20:19:42Z"
        },
        {
          "tag": "v0.15.0",
          "kind": "minor",
          "published_at": "2026-01-18T04:18:22Z"
        },
        {
          "tag": "v0.14.0",
          "kind": "minor",
          "published_at": "2026-01-18T03:12:06Z"
        },
        {
          "tag": "v0.13.0",
          "kind": "minor",
          "published_at": "2026-01-17T22:38:38Z"
        },
        {
          "tag": "v0.12.3",
          "kind": "patch",
          "published_at": "2026-01-15T06:41:31Z"
        },
        {
          "tag": "v0.12.2",
          "kind": "patch",
          "published_at": "2026-01-15T01:46:10Z"
        },
        {
          "tag": "v0.12.1",
          "kind": "patch",
          "published_at": "2026-01-15T00:11:34Z"
        },
        {
          "tag": "v0.12.0",
          "kind": "minor",
          "published_at": "2026-01-14T20:56:45Z"
        },
        {
          "tag": "v0.11.0",
          "kind": "minor",
          "published_at": "2026-01-13T18:52:11Z"
        },
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2026-01-13T16:53:33Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-01-11T05:42:40Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2026-01-10T15:16:16Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2026-01-08T04:04:41Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2026-01-08T00:05:06Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-01-07T15:35:05Z"
        },
        {
          "tag": "v0.4.26",
          "kind": "patch",
          "published_at": "2026-01-06T23:15:45Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "b739b10255e71f39ef7490ef0177e556db5b285c",
          "body": "Detect damaged databases before explicit or automatic sync, roll back pull batches when any event fails, and harden snapshot replacement against stale WAL generations and concurrent connections. Add integrity, cursor-preservation, and bootstrap regression coverage.\\n\\nRefs td-98f8e4\\n\\n🤖 Generated with Codex\\n\\nCo-Authored-By: Codex <noreply@openai.com>",
          "is_bot": false,
          "headline": "fix(sync): fail closed on SQLite corruption",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T19:48:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2950043244beffba102cc21d6452b4b70239d23e",
          "body": "…c50)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: per-project sync enablement model + override precedence (td-7d6…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T19:24:23Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "31ec01b0f8234b1d216b7a0609c349b084122e1e",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: always-available 'td sync status' diagnostics (td-78b482)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T19:22:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2d5fab4c40e574135879f8530078c5332f66907d",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: avoid DB opens on hot path in stranded-sync warning (td-da622d)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T19:22:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bbc6b97dbc2e94d5d2271d73bf76be75b1293b5e",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: warn when a sync-configured project has autosync off (td-da622d)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T19:22:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b9567324f7070fda74902e52b195916b31c5ff40",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add global sync kill-switch in config.json (td-735875)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T19:22:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cea7f3761a486fb07c819ef44030b5af22efbe4f",
          "body": "…to override (td-a4c721)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: gate autosync on per-project sync config; demote sync_autosync …",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T19:22:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4e57e5e52b6136ed3b0491730cd49b16b5285df1",
          "body": "ListMembers now joins users.email and the user-facing GET\n/v1/projects/{id}/members response includes it, so clients can show a\nhuman-readable identity instead of the raw user_id.\n\nUpdateMemberRole now runs in a transaction and rejects demoting the last\nremaining owner (mirrors RemoveMember's existi\n[…]\nd) so a project can\nnever be left without an owner. The update/remove handlers map the\nlast-owner guard to 409 Conflict with code \"last_owner\".\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "members: expose email in list; block demoting the last owner",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T19:22:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f8d290ea2a0d54684c774934c67d08039aeb778b",
          "body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: ignore .nightshift-plan artifacts",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T16:27:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ba4f88dd9137eeb862705a0018b93dfd53903082",
          "body": "Root cause: the DB was opened without a modernc _time_format param, so its\ndefault writer serialized every time.Time with time.Time.String() -- emitting a\nmonotonic-clock suffix (m=+...) and a zone name (PDT) that the driver cannot\nparse back. This corrupted timestamps DB-wide but only surfaced on t\n[…]\nso a\n  developer's shell no longer breaks feature tests.\n\nIndependently reviewed. go test ./... green (33 packages), go vet clean.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: normalize SQLite timestamp serialization (td session lookup crash)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T15:57:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "51a7b0164f09b746282976d4305c10fe5972b14c",
          "body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: cut v0.51.1 changelog (handoff stdin fix)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-18T15:00:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a110ef95c98bdff3f9af65eb489fed5d08e2a86f",
          "body": null,
          "is_bot": false,
          "headline": "Fix handoff",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-07-17T23:28:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0f39dfebff89079b9fdb5d3bfd46944008ef07f2",
          "body": "Summarize the session/worktree state, sync hardening, and handoff autosync fixes included in the v0.51.0 release.\n\nGenerated with Codex\n\nCo-Authored-By: Codex <noreply@openai.com>",
          "is_bot": false,
          "headline": "docs: cut v0.51.0 changelog",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T04:04:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2a0c1734ae404dcd8f7ee90a1f159456137350fa",
          "body": "Skip startup auto-sync for handoff so progress capture does not wait on a pre-command pull. If the post-mutation push fails, leave events pending and warn without attempting an immediate pull against the same unhealthy endpoint.\n\nGenerated with Codex\n\nCo-Authored-By: Codex <noreply@openai.com>",
          "is_bot": false,
          "headline": "fix: reduce handoff autosync stalls",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T04:03:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "95251d30c2027e565039e40abc43d5a095dd5e4e",
          "body": null,
          "is_bot": false,
          "headline": "feat: use session_state for serve focus (td-dd7a11)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T03:30:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "666c80761a0c999325b6bccefe133a6ef279b68f",
          "body": null,
          "is_bot": false,
          "headline": "fix: call show RunE from resume (td-e2f1ab)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T03:20:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6c6feac9abf7e894544908f571fe6e2efa70e633",
          "body": null,
          "is_bot": false,
          "headline": "feat: use session_state for CLI current state (td-e2f1ab)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T03:13:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1577514f506e9b7b8ef599ad55c0fc2c376a58d2",
          "body": null,
          "is_bot": false,
          "headline": "feat: add local session state store (td-3d427b)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T02:58:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "856330cd35d01ff44c336d8f9819098818ac3079",
          "body": null,
          "is_bot": false,
          "headline": "fix: scrub local-only fields from sync conflicts (td-83cfc9)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T02:48:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d43f359671c1ec16eeb30266daec1ced60926a4a",
          "body": null,
          "is_bot": false,
          "headline": "fix: scrub local-only fields from server sync events (td-83cfc9)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T02:40:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fd18a34c30f937eab74be67fc32b7a7789c39d09",
          "body": null,
          "is_bot": false,
          "headline": "fix: keep worktree metadata local in work session sync (td-83cfc9)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T02:31:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ee5984d83e66d2bc1b9e857710b7dd0ab58279e6",
          "body": null,
          "is_bot": false,
          "headline": "feat: add worktree identity to sessions (td-83cfc9)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T02:23:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cc5dc646a22c748a2065b2b937d9e6e6d7417867",
          "body": null,
          "is_bot": false,
          "headline": "docs: plan session-scoped current state (td-af80e9)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T02:13:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fceccc7afa87fe30da52973caaa78d172af359a9",
          "body": "…anges\n\nPost-mutation auto-sync made a single push attempt with a 5s timeout and\nswallowed failures to slog.Debug, so a transient blip left the change\nunsynced until the next td command or the 5m monitor tick — the main source\nof \"it didn't show up in td-watch\" inconsistency.\n\n- pushBatchWithRetry: \n[…]\nt).\n\nTests cover retry recovery, budget cutoff, timeout restoration, no-retry on\nunauthorized, and events left pending when the server is down.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: retry auto-sync push with bounded backoff + surface stranded ch…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-21T01:39:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "52ef3fae6d7b34b8fab05e5c291ef5ac06deadca",
          "body": "…a616c2)\n\nThe reviewer examples used 'td approve <id> --record-only', but --record-only\nis hard-rejected in trusted mode (the project default; cmd/review.go:648-655).\nAn agent on a default/fresh project that copy-pasted those examples would hit a\nfatal error.\n\nDefault trusted-mode examples now use a\n[…]\n-record-only is shown only under an\nexplicit delegated-mode caveat, mirroring the CLAUDE.md review-model section.\n\n🤖 Generated with Claude Code\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: fix record-only examples to plain approve for trusted mode (td-…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T23:08:45Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ccd4a246e4ac4be53f8b59157b76bbeab39ae479",
          "body": "…T_ID) (td-a616c2)\n\nAdd docs/multi-agent-sessions.md documenting the three routes for giving\nsub-agent contexts independent td sessions so delegated reviews are recorded\nas genuinely independent (Failure Mode #6):\n\n1. TD_CONTEXT_ID (recommended, shipped in td-64dc09) - feeds the session\n   lookup ke\n[…]\n.\n3. Worktree isolation (forthcoming, not yet implemented).\n\nAdd a short pointer in CLAUDE.md's review-model section linking to the\nfuller doc.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: document orchestrator sub-agent session independence (TD_CONTEX…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T23:05:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b86cf159675f9d88aa1516ce3a08d8b04815338e",
          "body": "Canonical identity model: explicit implementer/reviewer role declaration\nreplacing inferred-from-session-identity independence. Defines command\nsurface, issue_role_delegations schema, reviewpolicy precedence guard\n(declared role wins, fall back to session inference), migration story\nfrom shipped con\n[…]\nwork.\nAdditive and precedence-based so the two identity paths are one layered\nsystem, not two half-supported ones. Stubs follow-up tasks D1-D7.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: design spec for td delegate explicit role declaration (td-d7fd80)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T22:54:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "66344fd54c8e089bb66cd0017a8bcd4aa64890ea",
          "body": "validateTitle now returns (warning, err): a too-short title produces a\nnon-fatal warning and creation proceeds, while generic titles and\nover-max titles remain hard errors. The warning is surfaced via the\nexisting emitWarn helper (human mode only; silent in --json so scripts\nget a clean success envelope). Updated cmd/create_test.go accordingly.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: downgrade title min-length from rejection to warning (td-e76379)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T22:47:45Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8e0ad64f2cd27e48142d7f8be829bafb42815449",
          "body": "When td review auto-creates a handoff because none exists, synthesize the\nDone/Decisions fields from the issue's substantive session logs instead of\nwriting an empty placeholder. Routine workflow logs (Started work, Submitted\nfor review, etc.) are filtered out via the existing isSubstantiveReviewCon\n[…]\no the minimal placeholder when there are no usable logs, and\nwaives the auto-handoff entirely for --minor issues (which already bypass\nreview).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: synthesize auto-review handoff from session logs (td-713b57)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T22:42:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "34252e7ebf0820f969586a520c7bf03d05ad25f3",
          "body": "Promote a context dimension into the session lookup key so distinct\nsub-agent contexts that share one process/branch/checkout no longer\ncollapse into a single session (Failure Mode #6).\n\nWhat changed:\n- New optional env var TD_CONTEXT_ID feeds a dedicated matching key.\n  session.matchContextID() ret\n[…]\netSessionByIdentity context keying (db); distinct sessions for\ndiffering TD_CONTEXT_ID, empty-context reuse, and same-context refind\n(session).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: key sessions by context_id for sub-agent independence (td-64dc09)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T22:37:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1032097899372a4b244a23de13d657c7ca099f65",
          "body": "Record planning decisions (lean scope, context_id-keying-as-mechanism +\ntd delegate as canonical successor, session_state local-only) and two\ncode-grounding corrections (handoff gate already auto-creates; title min\nalready configurable).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: scope session/worktree flow lean phase into epic (td-124499)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T22:25:51Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "250c30c8941a0892c65ca9a84afa04a1b493db6a",
          "body": "… (td-70916d)\n\nA sync re-pulls the client's own just-pushed events to keep server_seq\nconvergent. Replaying them in order can transiently overwrite newer local\nstate (identical-payload logs; an issue creation event landing on a later\nlocal close) before a subsequent event restores it. These self-rep\n[…]\n. Independently reviewed; full suite green.\n\n(Also picks up a pre-existing gofmt alignment fix in the same file.)\n\n🤖 Generated with Claude Code\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: suppress sync conflict false-positives from self-authored events…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T22:07:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0bbecff8d5224c56b27cd74ab3b500b9a36ea686",
          "body": "…scope enforcement)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: changelog for v0.50.0 (project slugs, invitations, web signup, …",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T21:45:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "82137dbeea8cb7c5fb0a4f40be03c6a619437957",
          "body": "…-2df74a)\n\nBackfill no longer consumes slug namespace for soft-deleted projects;\nadmin project API now returns slug for parity with the user API; document\nstable-slug-on-rename and the p_ unicode-fallback edge case.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: skip soft-deleted in slug backfill, expose slug on admin API (td…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T21:29:55Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6ece85d33ff7a1b6e232c542119313ee2a089601",
          "body": "Stored slug column + unique index on projects; slugify matching td-watch;\ngenerate on create, idempotent backfill for existing rows; expose slug on\nthe project API responses. Enables stable canonical /projects/<slug> URLs.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add first-class unique project slugs (td-2df74a)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T21:16:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c5a3f78fcae7b2c16701438ce9c8ec5e85358504",
          "body": null,
          "is_bot": false,
          "headline": "Clarify sync project access guidance",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T19:41:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7870ac9efdd54b0d25f7ec5d9f6b594e4dac9539",
          "body": "…ommendations\n\nCaptures the session issue hit during the --json epic orchestration: Task-tool\nsub-agents share the orchestrator's session (same branch + terminal fingerprint\n+ worktree), so independent review can't be recorded and every close is forced\nto --self-review.\n\n- Failure Mode #6: why sub-a\n[…]\noff, relax input-validation gates, plus a\n  what-not-to-loosen guardrail\n- New near-term tasks; recommendation sequenced to land Phase 2b first\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: add sub-agent session-collapse failure mode + aged-controls rec…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T19:40:20Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "57a1e245c66d9b5e218a3e62486443a89e6eef3f",
          "body": null,
          "is_bot": false,
          "headline": "docs: clarify direct member invite wording (td-8b0b31)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T19:33:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "69d33b03a12826ac5546cfbef3eca53e2dc6bd5f",
          "body": "…ts (td-b4f7cd)\n\nAdd a 'JSON output (--json)' section to docs/guides/cli-commands-guide.md\ndocumenting the global persistent flag, the two success envelopes\n(EmitIssue / EmitResult), the error envelope, NDJSON bulk output, the\nknown exceptions (query --output, the JSONL commands, show --format\njson)\n[…]\n--json\nmode and carries the expected action/id, plus the JSON error envelope\nshape (close) and RunE-returns-error on missing id (log, handoff).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: document --json contract; add cross-command JSON regression tes…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T19:28:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "327f21a637984da9e7635a875f8084c9dfd91294",
          "body": "…iew JSON; fix JSONError escaping (td-575c78)\n\nThree pieces of work, all under td-575c78:\n\n1. Fix output.JSONError escaping: replaced the hand-rolled fmt.Printf(\"%s\")\n   envelope with a json.Encoder (SetEscapeHTML(false)) over a small error\n   struct. The previous form produced invalid JSON when a m\n[…]\nnged.\n\nUpdated TestWsCurrentFlags and TestRejectJSONShapeUnchanged to reflect the\ninherited-flag wiring. go build ./... and go test ./... pass.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: collapse local --json onto persistent flag; add approve/rev…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T19:14:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9101aa36109799453d1a0b2872bc23b06f603732",
          "body": "closeCmd now honors the persistent --json flag via jsonMode(cmd). In JSON\nmode it re-fetches the closed issue and emits output.EmitIssue(\"closed\",\nissue, extra) where extra carries session plus any self_close_exception,\nadmin reason, cascaded_parents, and unblocked_dependents. All human\nCLOSED/casca\n[…]\nelope, unchanged human\noutput, JSON error on not-found, and a regression guard locking the\nreject --json key set to {id,status,action,session}.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add --json to close; preserve review-family JSON shape (td-6f9e0b)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:59:56Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "363b4cefed69b073f7d9d311599a1aea08421c68",
          "body": "Co-Authored-By: Codex <codex@openai.com>",
          "is_bot": false,
          "headline": "feat: allow invited users through web signup (td-ff9d4d)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:50:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "81d43a01795ce79d8a245f94ae4c9fc0a14bbf3a",
          "body": "…tions (td-862b42)\n\nWire the global --json persistent flag into the transition and relationship\ncommands, following the create.go (c0f967f) and update/start/log/handoff\n(edab30e) pattern:\n\n- unstart: emit output.EmitIssue(\"unstarted\", issue, nil) per id, re-fetching\n  the now-open record (NDJSON in \n[…]\n\nTests: cmd/transition_json_test.go asserts the json envelope keys plus a db\nround-trip and unchanged human output across all the new commands.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add --json to unstart/defer/block/reopen/unblock/link/note muta…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:48:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cbae9122ee4c1b7575f05850de3b34b6846e4eaa",
          "body": "Co-Authored-By: Codex <codex@openai.com>",
          "is_bot": false,
          "headline": "fix: close invitation backend edge cases (td-274e59)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:44:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "edab30e2ac0d7541a55878a3fc1bd8f380e4e3b7",
          "body": "Wire the global --json persistent flag into the core mutating commands,\nfollowing the create.go pattern (commit c0f967f):\n\n- update: in json mode emit output.EmitIssue(\"updated\", issue, nil),\n  re-fetching the post-update record. One JSON object per id (NDJSON) in\n  the bulk case.\n- start: single st\n[…]\nest.go covers json envelopes (expected keys + db\nround-trip), bulk start NDJSON shape, and unchanged human output for\nupdate/start/log/handoff.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add --json to update/start/log/handoff (td-7b9ddf)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:38:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e5f4125a7886e96d26426fb3c1c2cfbb6fd5c37a",
          "body": "Co-Authored-By: Codex <codex@openai.com>",
          "is_bot": false,
          "headline": "feat: add project invitation backend (td-274e59)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:37:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c0f967fac69412cb6ffe1ac50ec9152713e42c39",
          "body": "Wire the global --json persistent flag into create/add (and epic create,\nwhich delegates to create's RunE):\n\n- Success path: when jsonMode(cmd), emit output.EmitIssue(\"created\", issue,\n  nil) — the full created *models.Issue with the new id — instead of the\n  human \"CREATED <id>\" line. Human output \n[…]\nr\":{...}}` on stdout.\n\nTests: cmd/create_json_test.go covers json full-issue envelope, unchanged\nhuman output, and epic-create json delegation.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add --json to create/add returning full issue (td-0a8c33)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:28:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "98bb6144fef568e423a569b61797779007f84c27",
          "body": "Co-Authored-By: Codex <codex@openai.com>",
          "is_bot": false,
          "headline": "feat: allow web signup magic links (td-7b6135)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:24:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c7fdd88fc341bf154826f61e8fe9141f8ff855b2",
          "body": "…lpers (td-d0f2ac)\n\nAdds infrastructure for consistent JSON output across td commands without\nchanging any existing command's output behavior:\n\n- cmd/root.go: register persistent --json flag; in Execute() emit a JSON\n  error envelope (output.JSONError) to stdout before the unknown-flag /\n  workflow-\n[…]\nal/inherited/missing/nil), and the os.Args error-path fallback.\n\nWiring --json into individual commands is handled by separate follow-up tasks.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: JSON output foundation — persistent --json flag + emit/error he…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-20T18:17:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8ffe752fecd7fb47d3ba3fd8f9134482dc69f0e9",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: scope-enforcement matrix incl. admin proxy paths (td-336b32)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T17:00:16Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2fb5781246337529d63bb3e3704edd0aa1d1e158",
          "body": "…d-f0bf76)\n\nAdds projectScopeAllowed() helper and applies it at all three project-route\nenforcement sites: requireProjectAuth (middleware.go), requireProjectMembership\n(project_middleware.go), and the flat GET/POST /v1/projects routes via a new\nrequireProjectScope wrapper (server.go). Admin routes and requireAuth itself\nare untouched. go test ./internal/api/ passes.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: enforce sync scope on project routes, preserving admin proxy (t…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T16:53:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "37336760f714d356e9c411d96674f3ac5e32e140",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add HasAnyScope helper (td-250d27)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T16:48:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8d7e5706915aaab52bd49c95b7d05e4ad8960954",
          "body": "The auth rate-limit middleware applied the strict SYNC_RATE_LIMIT_AUTH (10/min)\nto every /v1/auth/* path, but the device flow advertises a 5s poll interval\n(~12/min). A real CLI login polls for the whole approval window, so it hit 429\nbefore the user could click the email. Poll endpoints now use a s\n[…]\nigher limit (RateLimitOther), keeping the strict limit on the\nstart/exchange/approve endpoints. Regression test added. Web login is unaffected.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: give device-login poll endpoints a separate, higher rate limit",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T16:30:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "304738d81e8bc6f0ae8ba3031edfec852d5af76b",
          "body": "…L (td-d5f5ef)\n\nCloudflareSender consumes EmailConfig.BaseURL as the Cloudflare REST API base\n(default api.cloudflare.com), but the server wiring fed it AuthEmailBaseURL\n(SYNC_EMAIL_BASE_URL=https://sync.haplab.com), so email sends POSTed to td-sync's\nown host -> 404 -> login emails failed in prod. \n[…]\nEmailConfig() that does not\nset it, and add a regression test. SYNC_EMAIL_BASE_URL remains used by the auth\nhandlers for magic-link generation.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: stop mapping SYNC_EMAIL_BASE_URL into the Cloudflare API base UR…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T15:55:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "325274e83a586bb9efdb661f13ca2302cf94544e",
          "body": "… was crash-looping\n\nThe prod override mounted litestream.prod.yml (S3 replica) over /etc/litestream.yml,\nbut with no S3 bucket (backups disabled) litestream exits with \"bucket required for\ns3 replica\" and the container crash-loops. Drop the mount so the image's default\nfile-replica config is used (starts cleanly). Re-add the mount only with a real\nLITESTREAM_S3_BUCKET to enable S3 backups.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(deploy): don't mount S3 litestream config in prod (backups off) —…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T15:41:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3838bd0cc06371975c6b77583c5718f9f9e4ed0d",
          "body": null,
          "is_bot": false,
          "headline": "docs: map td session worktree flow",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T15:29:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e44bf9f4a93c6632b9051dfbe04e53884cc1cfea",
          "body": null,
          "is_bot": false,
          "headline": "fix(deploy): fail secure auth cutover if legacy login remains live",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T15:29:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2cca4213514b957023ba268c4eb0e9ca558f6334",
          "body": "…th validation, health gate\n\n- backups optional (LITESTREAM_ENABLED gate) so a deliberate no-backups prod deploys\n- prod fails closed if email/auth config missing (SYNC_EMAIL_PROVIDER + CLOUDFLARE_* +\n  SYNC_AUTH_WEB_CALLBACK_URL) while legacy auth is off — prevents a login-locked deploy\n- health ch\n[…]\nalthz with timeout and exits non-zero on failure (no more\n  false \"success\" on a down server); post-deploy check asserts legacy auth is 410/404\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(deploy): harden prod deploy.sh — optional backups, fail-closed au…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T15:02:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fb1327a4056d9d9b3ea3f5242f52012b2914d576",
          "body": "Replace the disabled legacy /v1/auth/login/start + /auth/verify endpoints in\ntest/e2e/harness.go and scripts/e2e-sync-test.sh with the device PKCE flow:\ngenerate PKCE -> device/start -> read magic link via GET /internal/dev/last-email\n(memory provider) -> approve -> poll. Provision users up front vi\n[…]\nync_cli feature flag so the full convergence test passes end-to-end.\n\ngo test ./test/e2e/ (non -short) passes; scripts/e2e-sync-test.sh passes.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: migrate e2e harness to device PKCE login flow (td-b274ed)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T15:00:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "59215575a9e803bb7ab6f96b1e42adbad41d780b",
          "body": "…ner (td-d255db)\n\nThe prod compose override enumerated container env explicitly and omitted all\nPhase 1-4 email/auth vars, so --env-file values never reached the container —\nemail send + web/device auth would be dead in prod. Add the email/auth vars via\n${VAR} substitution. SYNC_DEV_EMAIL_INSPECT intentionally NOT passed (dev-only).\nVerified all 9 keys resolve via `docker compose ... config`.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(deploy): pass email + secure-auth env vars to prod td-sync contai…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T14:52:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ed892becf27cd694045ce1ea10ab94d6f00e2c0f",
          "body": "…td-d55391)\n\nDouble-gated (SYNC_DEV_EMAIL_INSPECT=true AND *email.MemorySender provider);\nreturns 404 otherwise. Inert in prod, which uses the cloudflare provider.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: dev-only GET /internal/dev/last-email to read last magic link (…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T14:49:18Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5d9b50fbc9c8d3e7070cdd758d35597f73873c61",
          "body": "Cloudflare's Email Sending API rejects reply_to as {\"address\": ...} with\nemail.sending.error.invalid_request_schema; it must be a plain email string.\nProven via live sends against the real API. The httptest unit test asserted\nthe wrong (object) shape, masking the bug — updated to assert a string.\nWithout this, no login email would send in production.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: send Cloudflare reply_to as a string, not an object (td-ed1ade)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T14:31:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "420c460225e6b1945ec49d25bc0f1785f62026f4",
          "body": "Replace the old \"verification URL + 6-character code\" description in\nsync-client-guide.md and sync-setup-guide.md with the new email-approval\nflow: a local PKCE verifier is generated, only the S256 challenge is sent,\nthe server emails a one-time approval link, and the login completes only\nafter the link is clicked. No code is shown in the terminal.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: describe CLI email-approval (PKCE) login flow (td-3966bb)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T14:31:43Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6f4b34d6047c0ebc70c4058505ec43e025b96a87",
          "body": "Drives the real syncclient + PKCE helper against a live in-process api\nserver (httptest.Server over srv.routes()) with a MemorySender:\n\n- FullFlow: GeneratePKCE -> DeviceStart -> read magic link from the\n  in-process MemorySender -> approve -> DevicePoll yields a ~365-day key;\n  the key authenticate\n[…]\n returns\n  401 invalid_verifier and no key (PKCE binds the login to this process).\n- UnknownEmailNoKey: non-enumerating start, never completes.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test: end-to-end CLI PKCE device-login integration tests (td-89e8b8)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T14:30:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a461dec894b26639b46b936603815f68f08bd3ff",
          "body": "`td auth login` now generates a local PKCE verifier, sends only the S256\nchallenge via DeviceStart, and prints \"Check your email and click the link\nto approve this login\" — no user code and no self-approval URL are shown.\nIt polls DevicePoll with device_code + verifier at the server interval until\nc\n[…]\nm the\nserver. The returned 365-day key is saved to auth.json in the unchanged\nformat. device_name is derived from the hostname (td-cli@<host>).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: td auth login uses PKCE email-approval device flow (td-1d9cfc)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T14:29:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f38cb43d14e8e6164d68d5394479c6bbd9691299",
          "body": "GeneratePKCE() produces a 32-byte crypto/rand verifier (base64url no-pad)\nand Challenge = base64.RawURLEncoding(SHA-256(verifier)), exactly matching\nthe S256 verification in handleDevicePoll. Unit tests assert the S256\nrelationship, uniqueness across calls, and RFC 7636 verifier length.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add PKCE helper for CLI device login (td-011205)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T14:27:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ef54ad863ee523654cd82b6c205855252c7c9d93",
          "body": "Add DeviceStart(email, codeChallenge, method, deviceName) and\nDevicePoll(deviceCode, codeVerifier) hitting the new non-enumerating\n/v1/auth/device/{start,poll} endpoints, plus DeviceStartResponse and\nDevicePollResponse types mirroring internal/api/auth.go. The legacy\nLoginStart/LoginPoll methods are left in place.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add syncclient DeviceStart/DevicePoll PKCE methods (td-df552e)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T14:27:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7b4f76663afe832e310d8776593bb2f8f53e2423",
          "body": "…49f)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: run CleanupExpiredChallenges in background cleanup loop (td-b78…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T06:11:07Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "217a97f4bb392eb6b8bdd1eb2971d990cc31a1ae",
          "body": "…H (td-8cade5)\n\nWhen SYNC_LEGACY_DEVICE_AUTH is unset or false (the default), POST\n/v1/auth/login/start and /v1/auth/login/poll return 410 Gone with an\nendpoint_disabled error code, and GET/POST /auth/verify return 404.\nSet SYNC_LEGACY_DEVICE_AUTH=true (or =1) to re-enable the old flow for\nlocal/dev use. Existing legacy-endpoint tests opt in via\nsrv.config.LegacyDeviceAuth = true.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: gate legacy device-auth endpoints behind SYNC_LEGACY_DEVICE_AUT…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T06:08:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b64eb0bb69f2faf83890b97f0578e699972b2be9",
          "body": "Implements D4 of the CLI device login flow:\n\n- GET /auth/device/approve: verifies selector.secret token via\n  VerifyAndMarkDeviceChallengeVerified (secret hash check + atomic\n  pending->verified transition), sets Referrer-Policy: no-referrer, logs\n  AuthEventDeviceVerified, serves HTML success/error\n[…]\ng full flow, poll-before-approve, wrong secret, wrong verifier,\n  double-issue prevention, link-reuse, and unknown-device-code non-enumeration.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add device approval page + poll endpoint with PKCE (td-765a96)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T06:01:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "36db2cb5e502a9e8fb1b2cdc2151d8067d797eca",
          "body": "Implements the first half of the CLI device login flow. Validates email,\ncode_challenge (required), and code_challenge_method (must be S256). For\nknown users, creates a device_login email challenge storing DeviceCodeHash,\nCodeChallenge, and CodeChallengeMethod, then sends an approval email to\nAuthEm\n[…]\n) with no challenge created and no email sent;\nAuthEventEmailSuppressed is recorded. Rate limit (1/min per email) also\nreturns the generic 200.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add POST /v1/auth/device/start with PKCE challenge (td-7501b9)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T05:54:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2bbc350288ee80d8251a59b3b83839b12406b89c",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add POST /v1/auth/web/exchange (30-day web key) (td-1205ff)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T05:48:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8c9c67e7a77791caa599a090b32074ca7848559b",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add POST /v1/auth/web/start email login endpoint (td-c40207)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T05:44:09Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0a1ff8aecf1a586b042b1bb72ebb3a68fff91ac4",
          "body": "…55a)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: wire EmailSender into server + add auth event constants (td-144…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T05:39:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b251c5c48447e8304a3c22840f13b209f8764522",
          "body": "…-54cf93)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: document email provider config in env templates + ops guide (td…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:37:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c33160e5a848f1f73a469343de93d79cd53ac403",
          "body": "CloudflareSender.SendLoginLink POSTs to the Cloudflare Email Sending\nREST API with Bearer auth and the CF envelope JSON shape. Validates\nrequired config fields at construction time. API token and magic link\nbody content are never logged or surfaced in errors.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: implement Cloudflare email REST sender (td-d36311)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:34:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b13a2c2fd74e4d6d1ccc96880fcbce415e58980b",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add EmailSender interface + memory/log providers (td-b74d04)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:31:51Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ac3bc124d71469c1c8d358302b69ca72d8705236",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add email provider config + startup validation (td-43904b)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:29:01Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b9b861fbc35e05648d31ab427414f44520e9a6a3",
          "body": "…td-054083)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: drop misleading no-op BEGIN IMMEDIATE in ConsumeChallenge (…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:26:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "197c0d971701f741d555314ec2ef9e8853eaf359",
          "body": "Implements CreateEmailChallenge, LookupChallenge, ConsumeChallenge,\nLookupChallengeByDeviceCodeHash, and CleanupExpiredChallenges for the\nauth_email_challenges table (migration v4). Only SHA-256(secret) is stored;\nplaintext token is never persisted. ConsumeChallenge is atomic and single-use.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add auth email challenge store methods (td-054083)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:23:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6743b7a6c9e8c905e3ab1c0ad23cc716f39ea4a9",
          "body": "Bump ServerSchemaVersion 3->4 and append migration v4 that creates the\nauth_email_challenges table with all columns, constraints (purpose CHECK\nincludes admin_login), and three indexes. Update TestMigrationV3_SchemaVersion\nto use a >= 3 assertion since a fresh DB now reaches v4.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add auth_email_challenges migration v4 (td-5531d1)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:19:18Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a7f9f0323b51dbfa6cc3bab9d29684f5e67615d5",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add admin revoke-key CLI subcommand (td-db323f)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:17:02Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b499610ceab17cd0a71558f6f8011f6157da7042",
          "body": "DELETE /v1/admin/users/{id}/keys/{keyID} gated on new admin:write:users scope.\nReturns 204 on success, 404 on missing user or key, 403 on auth failure.\nRecords key_revoked auth event with admin_user_id + key_id metadata (no key material).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add admin key revocation endpoint (td-d606a9)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:14:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "0ecf00bb8df75ba0a9d0cbf94728207f1ce07b86",
          "body": "Add AdminRevokeAPIKey(keyID string) error to internal/serverdb/apikeys.go\nthat deletes any api_keys row by ID with no user_id constraint. Returns\nErrNotFound (new package-level sentinel in serverdb.go) when RowsAffected==0\nso HTTP handlers can map to 404. Tests cover successful revoke, non-existent\nkey, and that VerifyAPIKey returns nil after admin revocation.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat: add AdminRevokeAPIKey to serverdb (td-787c8f)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T04:10:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "42961b02e161d3e5318e709c67fcc994a4b4d41f",
          "body": "Board and issue-list responses blanked the heavy text fields (description,\nacceptance) that those views never render off store-hydrated issues; the\ndetail endpoint refetches the full issue, so it's unchanged. ~42% smaller\nper issue (~1MB+ on the sidecar all-issues board), compounding with gzip.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(serve): slim board/list payload — omit description/acceptance",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T03:33:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5f8018c01bd2e4c6c717fbad7d7217db98355ed5",
          "body": "The server builds td-sync on deploy, accumulating build cache and\ndangling images; a full disk makes nginx truncate large proxied\nresponses (caused a prod incident). Prune every deploy and report disk.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ops(deploy): prune docker images + build cache after remote deploy",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T03:28:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2fcf72236513dd55640910f0544dd5270fa83bfc",
          "body": "Silent failures in the batched blocker queries now emit slog.Warn so a\ndegraded board (cards missing their blocked dot) is observable, instead\nof failing silently.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(serve): log DB errors when building dependency summaries",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T00:53:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "df40ec777ee0b711183169bbd9a03919810929eb",
          "body": "Board and issue-list responses now carry an optional dependency_summary\nwith the issue's non-closed blockers (depends_on direction), enriched\nwith title+status via two batched queries (no N+1). Detail endpoint\nunchanged. Powers the blocked-card indicator in td-watch.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(serve): include unresolved-blocker summary on board/list issues",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-19T00:37:12Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "12b000f06eb316f5716abf282cb27731cfdf4f8b",
          "body": null,
          "is_bot": false,
          "headline": "test(sync): tolerate fast monitor autosync in e2e",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-18T17:48:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "900d142e9d85fe624126a6243e22b407504ea298",
          "body": null,
          "is_bot": false,
          "headline": "fix(sync): cover wrapped issue update replay (td-9edf1b)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-18T17:27:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a9abb62a1001cfd9aacff6bcc2d4e252fd30e797",
          "body": null,
          "is_bot": false,
          "headline": "sync: unwrap ReviewUndoPayload when applying remote issue events",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-18T16:12:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cecc7a016162117b5b81ac4153b2db21afb40c3d",
          "body": "Add an `available_transitions` field to the issue-detail, transition, and\nPATCH responses, computed per issue+session by reusing the exact decision\nfunctions the transition endpoints enforce (validFrom + the in_review/\nnon-minor close rule + the approve review-policy decision, incl. delegated\nMode-C\n[…]\nr than a status-based guess that includes actions the endpoints reject\n(e.g. close on a non-minor in_review issue). Omitted from list payloads.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Expose per-issue available_transitions on issue responses",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-18T05:35:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "dc0c7e16b1754b308559ae89552dc2eaf0bc4508",
          "body": null,
          "is_bot": false,
          "headline": "sync: auto-create session during push if it does not exist",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-18T04:04:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "847d16efeba84649bd10f9781516e854d4b2f14f",
          "body": null,
          "is_bot": false,
          "headline": "docs: cut v0.47.2 changelog (bare-id FK 787 fix)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-17T19:19:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8af3f76490bcf1160c0c87577616235d88db093f",
          "body": "handoff, comment, git-snapshot and ws-tag write paths persisted the raw\nuser-supplied issue id. When a bare id (no td- prefix) was passed, the\nstored issue_id did not match the issues(id) PK, so the FOREIGN KEY\nconstraint failed (error 787) once migration 30 enabled foreign_keys=ON.\n\nThis was misrep\n[…]\nd forms.\n\nAdds a regression test asserting bare-id writes succeed under FK\nenforcement and persist canonical ids.\n\n🤖 Generated with Claude Code\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(db): normalize issue_id before FK-constrained writes (td-25a0ae)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-17T19:19:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f71909d4df14b97c3ece20cc984a449b98e82531",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: cut v0.47.1 changelog (capital-letter shortcut fix)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-17T16:10:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8088a516fe07fd12c3b24b95923649e1733e98f9",
          "body": null,
          "is_bot": false,
          "headline": "Merge: fix shifted capital-letter shortcuts in monitor (td-272d9b)",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-17T16:09:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ecf62b694a8f7ebfff91ad1c74a2726bcf2f5215",
          "body": "KeyToString used key.Key().Keystroke(), which in bubbletea v2 renders a\nshifted printable key (e.g. shift+y => Code 'y' + ModShift) as \"shift+y\"\nrather than \"Y\". Bindings are written in textual form (\"Y\", \"?\", \"G\"), so\nevery capital-letter shortcut in the monitor (Y copy-id, C, F, G, H, I, J,\nK, N, \n[…]\n in sidecar's own keymap.\n\nTests now use realistic shifted-key input (Code + ModShift + uppercase\nText) so the regression is caught.\n\ntd-272d9b\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(monitor): match shifted capital-letter shortcuts after charm v2",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-17T16:03:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "62400592e7d00f9c6c221232fee797489bc367ab",
          "body": "…-d31841)\n\nRewrite docs/guides/releasing-new-version.md to match the actual release\npipeline and to give automated agents a non-interactive runbook:\n\n- Correct the Homebrew story: the tap formula is bumped by the dedicated\n  update-homebrew-tap job in release.yml (build-from-source, rewriting the\n  \n[…]\n  interactive bare `gh run watch`.\n\nAlso add the v0.47.0 CHANGELOG entry (getting-started modal first-open-only).\n\n🤖 Generated with Claude Code\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: cut v0.47.0 changelog and make release guide agent-friendly (td…",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-15T23:31:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "21090ce3a152f47ef46e6f53f9e596c525f29465",
          "body": "The .todos/ directory holds the project's local td SQLite database and\nsession state, which should never be committed.\n\n🤖 Generated with Claude Code\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: ignore local .todos/ directory",
          "author_name": "Marcus Vorwaller",
          "author_login": "marcus",
          "committed_at": "2026-06-15T23:31:33Z",
          "body_truncated": false,
          "is_coding_agent": true
        }
      ],
      "releases_count": 64,
      "commits_last_year": 841,
      "latest_release_at": "2026-07-18T16:00:12Z",
      "latest_release_tag": "v0.51.2",
      "releases_from_tags": false,
      "days_since_last_push": 5,
      "active_weeks_last_year": 22,
      "days_since_latest_release": 6,
      "mean_days_between_releases": 3.4
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "github.com/marcus/td",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/marcus/td",
          "is_deprecated": false,
          "latest_version": "v0.51.2",
          "repository_url": "https://github.com/marcus/td",
          "versions_count": 99,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-18T15:57:50Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 6
        }
      ]
    },
    "popularity": {
      "forks": 27,
      "stars": 232,
      "watchers": 2,
      "fork_history": {
        "days": [
          {
            "date": "2026-02-05",
            "count": 1
          },
          {
            "date": "2026-02-10",
            "count": 3
          },
          {
            "date": "2026-02-12",
            "count": 2
          },
          {
            "date": "2026-02-15",
            "count": 1
          },
          {
            "date": "2026-02-17",
            "count": 1
          },
          {
            "date": "2026-02-18",
            "count": 1
          },
          {
            "date": "2026-02-23",
            "count": 1
          },
          {
            "date": "2026-02-26",
            "count": 1
          },
          {
            "date": "2026-03-03",
            "count": 1
          },
          {
            "date": "2026-03-07",
            "count": 1
          },
          {
            "date": "2026-03-09",
            "count": 1
          },
          {
            "date": "2026-03-10",
            "count": 1
          },
          {
            "date": "2026-03-21",
            "count": 1
          },
          {
            "date": "2026-03-23",
            "count": 1
          },
          {
            "date": "2026-03-26",
            "count": 1
          },
          {
            "date": "2026-03-31",
            "count": 1
          },
          {
            "date": "2026-04-02",
            "count": 1
          },
          {
            "date": "2026-04-04",
            "count": 1
          },
          {
            "date": "2026-04-17",
            "count": 1
          },
          {
            "date": "2026-04-30",
            "count": 1
          },
          {
            "date": "2026-05-12",
            "count": 1
          },
          {
            "date": "2026-05-19",
            "count": 1
          },
          {
            "date": "2026-06-16",
            "count": 1
          },
          {
            "date": "2026-06-18",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 27,
        "total_forks": 27
      },
      "star_history": null,
      "open_issues_and_prs": 146
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": false,
      "bootstrap_files": [
        "Makefile"
      ],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 134501,
      "source_files_sampled": 480,
      "oversized_source_files": 4,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 8569
    },
    "dependencies": {
      "manifests": [
        "go.mod",
        "website/package.json"
      ],
      "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": [
        "go",
        "npm"
      ],
      "dependencies": [
        {
          "name": "charm.land/bubbles/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.1.0"
        },
        {
          "name": "charm.land/bubbletea/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.7"
        },
        {
          "name": "charm.land/glamour/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.0"
        },
        {
          "name": "charm.land/huh/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.3"
        },
        {
          "name": "charm.land/lipgloss/v2",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v2.0.3"
        },
        {
          "name": "github.com/charmbracelet/x/ansi",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.11.7"
        },
        {
          "name": "github.com/charmbracelet/x/cellbuf",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.0.15"
        },
        {
          "name": "github.com/mattn/go-sqlite3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.14.33"
        },
        {
          "name": "github.com/sahilm/fuzzy",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.1.1"
        },
        {
          "name": "github.com/spf13/cobra",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.10.2"
        },
        {
          "name": "github.com/spf13/pflag",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.0.10"
        },
        {
          "name": "golang.org/x/crypto",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.47.0"
        },
        {
          "name": "golang.org/x/sync",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.20.0"
        },
        {
          "name": "golang.org/x/sys",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.45.0"
        },
        {
          "name": "golang.org/x/term",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v0.39.0"
        },
        {
          "name": "modernc.org/sqlite",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.41.0"
        },
        {
          "name": "@docusaurus/core",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "3.9.2"
        },
        {
          "name": "@docusaurus/preset-classic",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "3.9.2"
        },
        {
          "name": "@mdx-js/react",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^3.0.0"
        },
        {
          "name": "clsx",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.0.0"
        },
        {
          "name": "lucide-react",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^0.563.0"
        },
        {
          "name": "prism-react-renderer",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^2.3.0"
        },
        {
          "name": "react",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^19.0.0"
        },
        {
          "name": "react-dom",
          "manifest": "website/package.json",
          "ecosystem": "npm",
          "version_constraint": "^19.0.0"
        }
      ],
      "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": 123,
        "merged_prs": 33,
        "open_issues": 23,
        "closed_ratio": 0.324,
        "closed_issues": 11,
        "closed_unmerged_prs": 11
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "marcus",
          "commits": 787,
          "avatar_url": "https://avatars.githubusercontent.com/u/3090?v=4"
        },
        {
          "type": "User",
          "login": "yashas-salankimatt",
          "commits": 19,
          "avatar_url": "https://avatars.githubusercontent.com/u/54542393?v=4"
        },
        {
          "type": "User",
          "login": "claude",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/81847?v=4"
        },
        {
          "type": "User",
          "login": "viktorius007",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/38939817?v=4"
        },
        {
          "type": "User",
          "login": "boozedog",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/1410808?v=4"
        },
        {
          "type": "User",
          "login": "FredLackeyOfficial",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/6161622?v=4"
        },
        {
          "type": "User",
          "login": "ricktraveler",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/34584238?v=4"
        },
        {
          "type": "User",
          "login": "alpjor",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/61747?v=4"
        },
        {
          "type": "User",
          "login": "rjshrjndrn",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/2563385?v=4"
        }
      ],
      "contributors_sampled": 9,
      "top_contributor_share": 0.966
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "deploy-docs.yml",
        "release.yml",
        "test-docs.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum",
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 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": 2,
            "reason": "dependency not pinned by hash detected -- score normalized to 2",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 0,
            "reason": "67 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "b739b10255e71f39ef7490ef0177e556db5b285c",
        "ran_at": "2026-07-24T16:29:48Z",
        "aggregate_score": 3.3,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": null,
      "oldest_open_prs": [
        {
          "number": 61,
          "created_at": "2026-03-20T09:57:53Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 62,
          "created_at": "2026-03-20T10:06:01Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 63,
          "created_at": "2026-03-20T10:13:40Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 66,
          "created_at": "2026-03-21T09:49:28Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 67,
          "created_at": "2026-03-21T10:01:31Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 71,
          "created_at": "2026-03-22T10:30:32Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 72,
          "created_at": "2026-03-22T10:40:57Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 73,
          "created_at": "2026-03-22T10:51:56Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 74,
          "created_at": "2026-03-23T09:43:01Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 75,
          "created_at": "2026-03-23T09:52:03Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 76,
          "created_at": "2026-03-24T10:45:21Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 77,
          "created_at": "2026-03-25T09:32:08Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 78,
          "created_at": "2026-03-25T09:41:04Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 79,
          "created_at": "2026-03-26T07:52:11Z",
          "last_comment_at": "2026-03-26T09:13:19Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 80,
          "created_at": "2026-03-26T10:16:21Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 81,
          "created_at": "2026-03-26T10:26:19Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 82,
          "created_at": "2026-03-27T10:24:53Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 83,
          "created_at": "2026-03-27T10:32:59Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 84,
          "created_at": "2026-03-29T09:39:27Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 86,
          "created_at": "2026-03-29T09:56:53Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ],
      "last_merged_pr_at": "2026-03-31T02:47:30Z",
      "ci_last_conclusion": null,
      "oldest_open_issues": [
        {
          "number": 22,
          "created_at": "2026-02-10T17:59:19Z",
          "last_comment_at": "2026-02-10T20:44:40Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 24,
          "created_at": "2026-02-11T13:07:32Z",
          "last_comment_at": "2026-02-11T13:09:16Z",
          "last_comment_author": "rjshrjndrn"
        },
        {
          "number": 28,
          "created_at": "2026-02-12T21:56:32Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 31,
          "created_at": "2026-02-15T21:59:37Z",
          "last_comment_at": "2026-03-01T19:28:17Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 32,
          "created_at": "2026-02-15T22:00:38Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 33,
          "created_at": "2026-02-16T16:09:29Z",
          "last_comment_at": "2026-02-19T17:28:55Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 36,
          "created_at": "2026-02-17T18:05:58Z",
          "last_comment_at": "2026-02-17T18:28:06Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 37,
          "created_at": "2026-02-17T19:35:49Z",
          "last_comment_at": "2026-02-17T19:44:18Z",
          "last_comment_author": "Razkaroth"
        },
        {
          "number": 39,
          "created_at": "2026-02-17T23:35:28Z",
          "last_comment_at": "2026-02-20T04:20:45Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 41,
          "created_at": "2026-02-19T16:44:49Z",
          "last_comment_at": "2026-03-09T23:29:22Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 48,
          "created_at": "2026-02-24T04:04:48Z",
          "last_comment_at": "2026-04-12T22:56:53Z",
          "last_comment_author": "justin13888"
        },
        {
          "number": 51,
          "created_at": "2026-02-27T19:54:51Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 56,
          "created_at": "2026-03-09T20:47:30Z",
          "last_comment_at": "2026-05-11T19:37:25Z",
          "last_comment_author": "karmajunkie"
        },
        {
          "number": 57,
          "created_at": "2026-03-09T22:47:57Z",
          "last_comment_at": "2026-03-09T23:29:24Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 58,
          "created_at": "2026-03-11T15:16:42Z",
          "last_comment_at": "2026-03-11T15:28:54Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 59,
          "created_at": "2026-03-13T22:38:05Z",
          "last_comment_at": "2026-03-13T22:59:43Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 60,
          "created_at": "2026-03-15T07:31:52Z",
          "last_comment_at": "2026-03-15T08:57:53Z",
          "last_comment_author": "marcus"
        },
        {
          "number": 94,
          "created_at": "2026-03-31T18:55:39Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 184,
          "created_at": "2026-05-11T09:40:57Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 198,
          "created_at": "2026-06-01T08:07:53Z",
          "last_comment_at": "2026-06-18T13:18:37Z",
          "last_comment_author": "hyperverse"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/marcus/td",
    "host": "github.com",
    "name": "td",
    "owner": "marcus"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 60,
      "inputs": {
        "security": 33,
        "vitality": 83,
        "community": 50,
        "governance": 54,
        "engineering": 70
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 83,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 79,
            "inputs": {
              "commits_last_year": 841,
              "human_commit_share": 1,
              "days_since_last_push": 5,
              "active_weeks_last_year": 22
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "22/52 weeks with commits",
                "points": 15.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 22
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "841 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 841
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 64,
              "latest_release_tag": "v0.51.2",
              "releases_from_tags": false,
              "days_since_latest_release": 6,
              "mean_days_between_releases": 3.4
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "64 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 64
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 6 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~3.4 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 3.4
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 5,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 5 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "moderate",
        "name": "Community & Adoption",
        "value": 50,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "moderate",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "forks": 27,
              "stars": 232,
              "watchers": 2,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "232 stars",
                "points": 38.3,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 232
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "27 forks",
                "points": 11.8,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 27
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "2 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "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
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 54,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 25,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 9,
              "top_contributor_share": 0.966
            },
            "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 97% of commits",
                "points": 0.8,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 97
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "9 contributors",
                "points": 12.2,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 9
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "at_risk",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 44,
            "inputs": {
              "merged_prs": 33,
              "open_issues": 23,
              "closed_issues": 11,
              "issue_closed_ratio": 0.324,
              "closed_unmerged_prs": 11
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "32% of issues closed",
                "points": 15.1,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 32
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "33/44 decided PRs merged",
                "points": 28.7,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 33,
                      "decided": 44
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "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": 62,
            "inputs": {
              "followers": 217,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "marcus",
              "public_repos": 28,
              "account_age_days": 6706
            },
            "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": "217 followers of marcus",
                "points": 16.8,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 217,
                      "login": "marcus"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "28 public repos, account ~18 yr old",
                "points": 22.6,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 28
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 18
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/marcus/td"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 6
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on go",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "go"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 6 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "99 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 99
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "good",
        "name": "Engineering Quality",
        "value": 70,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "3 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "topics": [
                "agents",
                "ai"
              ],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": "2 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "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": "at_risk",
        "name": "Security",
        "value": 33,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 33,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 3.3
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file 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 2",
                "points": 1,
                "status": "partial",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "67 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 5
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 82,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.97,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 8569
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "97 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 97,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 73,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum",
                "package-lock.json"
              ],
              "has_dockerfile": true,
              "typed_language": true,
              "bootstrap_files": [
                "Makefile"
              ],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.73,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "Makefile",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Makefile"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Go (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "Dockerfile, lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Dockerfile, lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "73 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 73,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 2",
                "points": 2,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 134501,
              "source_files_sampled": 480,
              "oversized_source_files": 4
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Go (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "4/480 source files over 60KB",
                "points": 54.5,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 480,
                      "oversized": 4
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "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"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-24T16:29:59.861439Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/m/marcus/td.svg",
  "full_name": "marcus/td",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

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