公开记录
软件健康报告模式 0.27.0 · 指标 1.13.0 · 2026-07-28 21:20 UTC

emmanuel-D / truthboard

Git-native tracker where status is derived from repo reality, never typed. Specs in markdown, boards from git, MCP for AI agents, drift auditing for any repo.

GoMIT★ 0 星标⑂ 0 复刻始于 2026年7月在 GitHub 上查看 ↗

emmanuel-D/truthboard 的健康指数为 100 分中的 48 分,处于「存在风险」区间。 其得分最高的类别是Engineering Quality(71/100),最低的是Community & Adoption(24/100)。 最近一次更新在今天。 近期的大部分工作由 1 位贡献者完成。

48
总分 / 100
存在风险

软件健康指数

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

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

评分画像

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

所有权

Emmanuel Dadem个人账户
2 关注者15 个公开仓库始于 2018年3月

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

软件包生态系统

注册表软件包版本月下载量版本数最近发布
Gogithub.com/emmanuel-D/truthboardv0.10.0-160 天前

按类别列示的指标

活力

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

69中等 · 占总体的 22%
评分方式
36/36推送新近度 — 最近一次推送于 0 天前
0.7/36提交节奏 — 52 周中有 1 周有提交
18/18提交量 — 最近一年 172 次提交
0/10OpenSSF Scorecard:Maintained — project was created within the last 90 days. Please review its contents carefully
所用输入
commits_last_year172
human_commit_share1
days_since_last_push0
active_weeks_last_year1

发布纪律

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

社区与采用

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

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

社区健康

50中等
评分方式
22.5/22.5README
22.5/22.5许可证 — 可识别的许可证(MIT)
0/18CONTRIBUTING 指南
0/13.5行为准则
0/7.2议题模板
0/6.3PR 模板
所用输入
has_readme
has_license
has_contributing
has_issue_template
has_code_of_conduct
has_pull_request_template

可持续性与治理

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

43存在风险 · 占总体的 24%
评分方式
9/54巴士系数 — 1 位贡献者贡献了半数提交
0/22.5提交分布 — 头号贡献者编写了 100% 的提交
1.4/13.5贡献者广度 — 1 位贡献者
0/10OpenSSF Scorecard:Contributors — project has 0 contributing companies or organizations -- score normalized to 0
所用输入
bus_factor1
contributors_sampled1
top_contributor_share1
评分方式
0/46.8议题解决 — 0% 的议题已关闭
38.2/38.3PR 接受 — 已裁定的 PR 中 1/1 已合并
0/15OpenSSF Scorecard:Code-Review — Found 0/30 approved changesets -- score normalized to 0
所用输入
merged_prs1
open_issues1
closed_issues0
issue_closed_ratio0
closed_unmerged_prs0
评分方式
10/30所有权背书 — 个人(用户)账户
0/20已验证域名 — 不适用于个人账户
3.4/25所有者影响力 — emmanuel-D 有 2 位关注者
20.8/25既往记录 — 15 个公开仓库,账户约 8 年
所用输入
followers2
owner_typeUser
is_verified
owner_loginemmanuel-D
public_repos15
account_age_days3,060
已排除计分(无数据或不适用):已验证域名。 其余权重已重新归一化。
评分方式
25/25已发布且可解析 — go 上有 1 个软件包
35/35发布时效 — 最近一次发布于 0 天前
20/20版本历史 — 16 个已发布版本
20/20未被弃用 — 活跃,未被弃用或撤回
所用输入
packagesgithub.com/emmanuel-D/truthboard
ecosystemsgo
any_deprecated
min_days_since_publish0

工程质量

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

71良好 · 占总体的 20%

工程实践

68中等
评分方式
24/24CI 工作流 — 3 个工作流
24/24存在测试
0/16Linter 配置
0/9.6Pre-commit 钩子
0/6.4.editorconfig
20/20OpenSSF Scorecard:CI-Tests — 1 out of 1 merged PRs checked by a CI test -- score normalized to 10
所用输入
has_ci
has_tests
has_editorconfig
has_linter_config
has_precommit_config

文档

75良好
评分方式
30/30README
25/25文档目录
0/15文档 / 主页站点
10/10仓库描述
10/10主题标签 — 7 个主题标签
0/10Wiki
所用输入
topicsai-agents, developer-tools, git, golang, kanban, mcp, project-management
has_wiki
homepage
has_readme
has_docs_dir
has_description

安全

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

28危急 · 占总体的 16%

安全态势

28危急
评分方式
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
2.5/2.5CI-Tests — 1 out of 1 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5许可证 — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
0/5Packaging — 无数据
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
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
6/7.5Vulnerabilities — 2 existing vulnerabilities detected
所用输入
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate2.9
已排除计分(无数据或不适用):packaging。 其余权重已重新归一化。

AI 就绪度

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

67中等 · 占总体的 0%
评分方式
45/45代理指令 — AGENTS.md, CLAUDE.md
0/15机器可读文档(llms.txt)
29.9/40可读的提交历史 — 100 次人类提交中有 56 次说明了意图(结构化标题或解释性正文)
所用输入
has_llms_txt
legible_history_share0.56
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes1,271
评分方式
12.6/18一条命令的引导启动 — go.mod(工具链约定,无任务运行器)
22/22自动化测试
0/11Lint / 格式化配置
11/11静态类型检查 — Go(静态类型)
10/10可复现环境 — Dockerfile, lockfile
10/10已体现的代理实践 — 最近 100 次提交中有 25 次由代理编写或署名代理
0/8自动化维护 — 未观察到自动依赖更新
0/10OpenSSF Scorecard:Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
所用输入
has_nix
has_tests
lockfilesgo.sum
has_dockerfile
typed_language
bootstrap_files
has_devcontainer
has_linter_config
typecheck_configs
agent_commit_share0.25
toolchain_manifestsgo.mod
dependency_bot_commit_share0
评分方式
45/45可类型检查的代码 — Go(静态类型)
55/55可控的文件大小 — 采样的 71 个源文件中有 0 个超过 60KB
所用输入
primary_languageGo
largest_source_bytes42,697
source_files_sampled71
oversized_source_files0
评分方式
0/40API 模式(OpenAPI/GraphQL/proto)
20/20MCP 服务器
0/40可运行示例
所用输入
example_dirs
has_mcp_signal
api_schema_files

关键数据

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

数据采集警告

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

更多细节

OpenSSF Scorecard 2.9 / 10
2.9综合

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

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
10CI-Tests1 out of 1 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
不适用Packagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
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
8Vulnerabilities2 existing vulnerabilities detected
直接依赖 3
注册表软件包版本约束清单文件
Gogithub.com/charmbracelet/bubbleteav1.3.10go.mod
Gogithub.com/charmbracelet/lipglossv1.1.0go.mod
Gogopkg.in/yaml.v3v3.0.1go.mod
全部依赖 未采集

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

原始 JSON 报告 机器可读
{
  "data": {
    "repo": {
      "topics": [
        "ai-agents",
        "developer-tools",
        "git",
        "golang",
        "kanban",
        "mcp",
        "project-management"
      ],
      "is_fork": false,
      "size_kb": 704,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "Go": 460634,
        "CSS": 18245,
        "HTML": 6616,
        "Shell": 4748,
        "Python": 11579,
        "Dockerfile": 1369,
        "JavaScript": 42697
      },
      "pushed_at": "2026-07-28T14:48:59Z",
      "created_at": "2026-07-15T19:26:57Z",
      "owner_type": "User",
      "updated_at": "2026-07-28T14:55:08Z",
      "description": "Git-native tracker where status is derived from repo reality, never typed. Specs in markdown, boards from git, MCP for AI agents, drift auditing for any repo.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": "https://www.linkedin.com/in/emmanuel-dadem-3b3096209/",
      "name": "Emmanuel Dadem",
      "type": "User",
      "login": "emmanuel-D",
      "company": null,
      "location": "Nuremberg",
      "followers": 2,
      "avatar_url": "https://avatars.githubusercontent.com/u/37305687?v=4",
      "created_at": "2018-03-12T16:52:12Z",
      "is_verified": null,
      "public_repos": 15,
      "account_age_days": 3060
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2026-07-28T04:40:23Z"
        },
        {
          "tag": "v0.9.1",
          "kind": "patch",
          "published_at": "2026-07-20T12:25:24Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-07-20T11:15:41Z"
        },
        {
          "tag": "v0.8.4",
          "kind": "patch",
          "published_at": "2026-07-20T10:12:20Z"
        },
        {
          "tag": "v0.8.3",
          "kind": "patch",
          "published_at": "2026-07-20T09:43:46Z"
        },
        {
          "tag": "v0.8.2",
          "kind": "patch",
          "published_at": "2026-07-20T09:05:43Z"
        },
        {
          "tag": "v0.8.1",
          "kind": "patch",
          "published_at": "2026-07-20T08:38:24Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2026-07-19T20:31:34Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2026-07-19T15:47:49Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2026-07-18T19:12:23Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2026-07-18T17:39:12Z"
        },
        {
          "tag": "v0.4.1",
          "kind": "patch",
          "published_at": "2026-07-17T14:36:35Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2026-07-17T13:36:23Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-07-17T12:52:38Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-07-16T14:37:50Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2026-07-16T08:11:55Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "2fa8249ceced93fb7425007889ad728fe2dcd845",
          "body": "The MCP server is the one command whose working directory the user does\nnot choose — the client spawns it. It is also the only one that ignores\na repo argument, so a hub whose .truthboard/ sits in a subdirectory can\nonly be served by a shell wrapper that cds first, with an absolute path\nbaked into an otherwise portable .mcp.json.\n\nFound wiring the LetTalk hub so agents launch from the workspace parent.\n\nNo trailers — this is intent.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Story: truthboard mcp serves the directory you point it at",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T14:44:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "64d90545d1bc1fdd5d1ea623174c3c884ca031f6",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'fix/tb-71c5-ci-identity'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T04:37:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3be7a46c41e594293e125c5f258749ba1d574e02",
          "body": "CI has been red since tb-71c5 merged, and I did not notice because I\nonly ran the suite on a machine that has a global git identity.\noriginAndClone configured user.name/user.email on the seed repo but not\non the clone, and the delete tests are the first to commit into the\nclone. A CI runner has no c\n[…]\nvisible — red CI flips a\ndone story to regressed — and it did not, because the local board runs\nwithout --forge and never asked GitHub. Worth remembering before\ntrusting a green column.\n\nSpec: tb-71c5",
          "is_bot": false,
          "headline": "Give the board clone a git identity in the test fixture",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T04:37:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "13760ece4407e0516ba9b44e3b92b8eccf2709c9",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-e8e3-repo-chips'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T04:28:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e41fb0d41cc6edd3dc0ae3fc3b6b89663981c3a6",
          "body": "The multi-select was the wrong control and measurably so. Clicked\nthrough in a browser with [hub, server] selected, one unmodified click\non a third option left [connect] alone — two repos dropped, silently, on\nthe field that decides what done requires. The safe gesture was\n⌘-click, the default gestu\n[…]\n\"dropdown\"; the goal was picking from what exists. Intent\nupdated to match what the click test showed, which is the tool working\nas intended — the promise is editable, the proof is not.\n\nSpec: tb-e8e3",
          "is_bot": false,
          "headline": "Repos are toggle chips, not a multi-select",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T04:28:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2efd8e1677e036b0571f56b4ae70eb0598a79fd3",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-5266-redact-credentials'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T04:04:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ce18b657f3f30dd1eda5b025d97e9a2b9d119ee0",
          "body": "A shared board publishes its sync errors — the page prints them as\n\"⚠ remote sync failing: …\" and the header carries them to anyone who can\nload the URL. A spoke clone takes its remote as a command argument, so a\nmanifest with a token in it (which the docs forbid and a hurried\noperator writes anyway\n[…]\ngit's own output —\ngit sanitizes most of what it prints, and \"most\" is not a property worth\nbetting a token on.\n\nHost and path survive redaction. An error naming no remote helps nobody.\n\nSpec: tb-5266",
          "is_bot": false,
          "headline": "Redact credentials where git output is born",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T04:03:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "68cbfdf4277ead4a4d067d62dee2e1cf79f92efb",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-28b0-hub-recipe'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T03:55:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9cfed87aa260dae57cd2f4ce228db708b725079b",
          "body": "The pieces were all documented and the way they compose was not. Arming\nthe edit token is what forces a second credential — the board only reads\na spoke but writes the hub, so the hub needs push and the spokes must\nnot have it, which turns one rewrite rule into two. Nothing said so, and\nfinding out \n[…]\nway to see which credential actually resolves.\n\nAlso covers the step people finish without: a shared board authenticates\nwrites, never reads, so the edit token does not keep anyone out.\n\nSpec: tb-28b0",
          "is_bot": false,
          "headline": "Write down the hub-with-editing deploy, end to end",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T03:52:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9c6ed7c1ff2cf728bcad1210f6e6da7f425f2779",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-c469-ui-feedback'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T03:27:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a279f95ccff934bb33038c4f47b95f6c92b85e52",
          "body": "The board did the right thing and said nothing about it. Creating and\nretiring a story both just closed the dialog, which is exactly what a\ncrash looks like. Sign-off confirmed nothing at all. What feedback did\nexist came in three shapes — a button label, a hint line, a note beside\na field — so ther\n[…]\nays it is reading the repository instead of showing\nempty columns, and says so with the reason if the first audit fails —\nuntil now an unreadable repo and an empty one looked identical.\n\nSpec: tb-c469",
          "is_bot": false,
          "headline": "Say what just happened, and show it straight away",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T03:27:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4515d161dc1ef34245296b3f3d3b5698ca27c9f0",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-e8e3-repos-dropdown'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T03:19:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4a5feb0c2eb6de6cf07f3893127087db2a3c8410",
          "body": "The Repos field was free text, so a typo produced a story that could\nnever be done — done with repos: declared means the trailer landed in\nevery one of them, and a repo that does not exist never lands anything.\nThe server rejected the typo on save, which is the right answer given\nfar too late. Offer\n[…]\norkspace — known repos: hub,\napi, web\"); deselecting it and picking hub saves and rewrites the file.\nOn a single-repo board the field is absent for both a new story and an\nexisting one.\n\nSpec: tb-e8e3",
          "is_bot": false,
          "headline": "Repos is a dropdown of repos that exist",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T03:19:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2195e3e073cfe99fabdadabe9665e1fd423a6eaf",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-71c5-delete-stories'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T03:11:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8294781c0d4e3d23ac042b5b38b136d83fa8b000",
          "body": "There was no delete route at all: the write guard admitted POST\n/api/specs and PUT /api/specs/ and nothing else, so clearing a story\ncreated by mistake meant deleting the file from a clone and pushing by\nhand. That is literally what a probe story on the live lettalk board\ntook to remove.\n\nDELETE /ap\n[…]\none sets to say where a story stands is a status, and statuses are\nderived. The deletion is a commit, so the undo is git revert — which the\nconfirm dialog and the API response both say.\n\nSpec: tb-71c5",
          "is_bot": false,
          "headline": "Retire a story from the board, not from a clone",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T03:11:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5e4d4b087492e5ebeb4420a7e2a57654a45b1136",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-fb2b-sync-latency'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T02:51:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b802badf6399fb1441b619e115554c3496aebd5b",
          "body": "Linking ran `git log --grep <trailer>` for every spec against every\nbranch. On this repo — 68 specs, 17 refs — that was 940 git processes\nfor a single audit, fifteen seconds during which boardCache.get holds\nits mutex while browsers poll every three seconds. That is the \"audit\nunavailable — retrying\n[…]\nfrom the forge unless --no-forge, and those\nAPI calls dominated the wall clock. The numbers above exclude it, which\nalso matches the board, since boardCache only enriches under --forge.\n\nSpec: tb-fb2b",
          "is_bot": false,
          "headline": "Ask git once per branch, not once per spec per branch",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T02:51:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "af420cfeb9ea2602182aed0312f36c9559fb3f32",
          "body": "Saving a story rebased on origin unconditionally before pushing, so\nevery save cost two round-trips to the forge — and the first one bought\nnothing almost every time, because the board is usually the only writer\nand the sync loop has already fetched within its interval. Push first\nand let the remote\n[…]\nis durability,\nnot visibility.\n\nAnd the save button says \"saving…\" and refuses a second press. A save\ntakes as long as the network does, and silence for that whole time\nreads as a hang.\n\nSpec: tb-fb2b",
          "is_bot": false,
          "headline": "Stop paying a forge round-trip for a rebase that does nothing",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T02:06:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a9922f5c869627be5d5fbcb879454a0dc4392ad9",
          "body": "Both were a title and a sentence. Traced the actual paths and wrote\ndown what each one turns on: for deletion, what it means when proof\nalready exists; for sync, which part is a bug and which is a deliberate\ntrade. No trailers — this is intent.",
          "is_bot": false,
          "headline": "Flesh out story deletion (tb-71c5) and sync latency (tb-fb2b)",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T01:36:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "45852b1feb78f2983f8ac0b5b1ff1fd27d9339ce",
          "body": "…, sync\n\nWritten through the shared board before it had push credentials, so\nthey never left the working tree. No trailers — this is intent.",
          "is_bot": false,
          "headline": "Stories drafted from the board: deletion, repos dropdown, UI feedback…",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T01:33:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "912e4ab1a9bb3cac4f1192fc07fa3bbd891c03c3",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-26f5-preflight'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T01:07:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "18e6cf84f4372b69d12ed1cf51832fcf8ebee325",
          "body": "A board on a platform that restarts crashed containers turned every\ncredential problem into the same git error printed once per restart,\nwith the cause buried in it. Five redeploys of a private multi-repo hub\nwent that way, and none of the failures were things git could explain:\na forge answers a mi\n[…]\n carries\non: a hub with an unreachable spoke still serves real truth about the\nrest, and refusing to boot would trade a degraded board for no board.\nSilent when everything is reachable.\n\nSpec: tb-26f5",
          "is_bot": false,
          "headline": "Prove the deploy can reach its remotes before serving",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T01:07:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8d8790be7ba07d68c66876a0359b24b7243eead3",
          "body": "Three stories from deploying a private multi-repo hub on Coolify:\npreflight reachability checks (tb-26f5), credential redaction in logs\n(tb-5266), and a complete private-hub-with-editing recipe (tb-28b0).\nNo trailers — this is intent, not proof.",
          "is_bot": false,
          "headline": "Deploy hardening backlog from the lettalk hub rollout",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T00:57:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "264700604b404aefa162ac8d4806ba13d6b91cc2",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-fd0b-build-git-config'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T00:23:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e26a4b6354fa65229a79321b93174beb3be0f5fa",
          "body": "Deploy platforms turn every configured environment variable into a\nbuild ARG, so a private hub's runtime credential is present during the\nimage build. Git validates the whole GIT_CONFIG_COUNT set on every\ninvocation, so a single missing VALUE_n failed `git config --system\nsafe.directory` in the runt\n[…]\nng at `apk add`, nowhere near the credential that caused it.\n\nPin that call to GIT_CONFIG_COUNT=0. A credential typo now fails the\nclone it belongs to, with a message about credentials.\n\nSpec: tb-fd0b",
          "is_bot": false,
          "headline": "Build-time git ignores injected GIT_CONFIG_*",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-28T00:23:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b7aa847178b99153674c97ba56d434ecddf373c2",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-0ac4-webhook-race'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T12:20:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0b9435502095ca47d84b5be3f8d4f93e0f727e96",
          "body": "A webhook kick ran `go trigger()` and nothing could observe it. The\ngoroutine runs git inside the repository, so a caller tearing that\nrepository down — a test's t.TempDir(), a server shutting down — raced a\nrefresh mid-write. CI caught it once as \"unlinkat .../.git: directory\nnot empty\".\n\nHandler n\n[…]\nitsWebhookRefresh asserts Wait\ndoes not return while a refresh is in flight, and fails when Wait is\nstubbed out. Under -race it also establishes the happens-before that a\ncleanup needs.\n\nSpec: tb-0ac4",
          "is_bot": false,
          "headline": "The webhook refresh can be awaited",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T12:20:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2ebf868b5838e47181557c24d9248c83665239a3",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-deploy-private-hubs'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T12:05:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2f26be712641f056bc368cdeb8fa24111d8363c2",
          "body": "Deploying a real private hub to Coolify hit two gaps the docs set the\nreader up for.\n\nREPO_URL with an embedded token is documented, so private repos look\nhandled. For a hub they are not: spokes are cloned from the remotes in\nthe committed workspace.yml, which must never carry a credential, so the\nh\n[…]\nnot buried later, with the mitigations named.\n\nAlso documents the first-boot window where spokes read as unreadable\nwhile their mirrors clone, so it is not mistaken for a failed deploy.\n\nSpec: tb-c847",
          "is_bot": false,
          "headline": "Deploy docs cover private multi-repo hubs and read exposure",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T12:05:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dbaf86914594c537bca4bfdca93509d7b2715d13",
          "body": "Verify the Docker image on a real engine",
          "is_bot": false,
          "headline": "Merge pull request #2 from emmanuel-D/feature/tb-c4c3-docker-verified",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T11:45:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "097909a65e5913996dbcde4784f226200623a5e6",
          "body": "Backlog intent only — no Spec: trailer, which on main would derive the\nstory done the moment it is written.",
          "is_bot": false,
          "headline": "Story: the webhook test races its own background refresh",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T11:43:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7b751f39b237e7b5072e7a10f81a12cfae408193",
          "body": "The smoke test failed exactly as intended with a wrong expected version,\nso its assertions are not vacuous. Restoring the real expectation.\n\nSpec: tb-c4c3",
          "is_bot": false,
          "headline": "Revert the negative control",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T11:41:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8ae0930368fadddd2f705eb4909d5a58941575eb",
          "body": "Spec: tb-c4c3",
          "is_bot": false,
          "headline": "TEMP negative control: prove the smoke test can fail",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T11:39:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c092123f392ba25bf47e05ddd336ac41adeb29a2",
          "body": "The Dockerfile and entrypoint shipped in tb-146e were checked by\ncross-compiling the build line and driving the entrypoint directly; no\ndocker build had ever run, because the author's machine has no Docker\nengine. That made \"the image works\" an assumption in the one place\nusers are told to deploy fr\n[…]\n case exiting\nnon-zero with its actionable message. It runs in CI and is the same\ncommand anyone with Docker can run by hand — which is the point, since\nthis repo cannot run it locally.\n\nSpec: tb-c4c3",
          "is_bot": false,
          "headline": "Verify the Docker image on a real engine",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T11:37:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3b4b3ecb2fe321ea700251bf1546e7b5132bc067",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-1eb5-spoke-identity'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T10:42:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f7ab38f8bf3fb5c05ddcd40f8bf0df49ba613885",
          "body": "Resolve accepted a declared path on the sole evidence that the directory\nexisted. A mistyped or stale path therefore made the board gather proof\nfrom the wrong repository and report it with full confidence — the only\nsilent wrong answer in a tool whose entire claim is that its findings are\ntrustwort\n[…]\n\nVerified end to end on a hub pointed at the wrong one of two similarly\nnamed checkouts: refused in the audit and carried to the board as\nworkspace health, naming both URLs and the fix.\n\nSpec: tb-1eb5",
          "is_bot": false,
          "headline": "A declared spoke path must prove it is the declared repo",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T10:42:22Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a82488deee072e8e76a6df1d55c9ecf71a1248ff",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-ad3f-status-version'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T10:30:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e74923275f6ce978a6bf82ff666940872bdb1c2b",
          "body": "A detached board keeps the binary it started with, so an install or a\nbrew upgrade silently leaves it serving old code — and the binary it\nstarted from is usually gone by then, so `ps` cannot tell you either.\nIt bit three times in one day; each time it was found by reading ps.\n\nstatus now asks the b\n[…]\ns both versions without implying a direction: a dev\nbuild asking about a release board is as common as the reverse, and the\nfirst wording claimed the board was behind when it was ahead.\n\nSpec: tb-ad3f",
          "is_bot": false,
          "headline": "truthboard status reports the serving version",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T10:30:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "259f7b3bb9907581a9ca7660d4f74a9a797d37e1",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-569e-version-from-buildinfo'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T10:05:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6b9f9eac23f0ebf20256fc58906c79ed836b5fd5",
          "body": "Release binaries are stamped by -ldflags; go install applies none, so the\ninstall path most likely to be used by Go developers produced a binary\ncalling itself \"dev\" — and selfupdate refuses to replace those, quietly\nopting those users out of updates.\n\nThe version now falls back to the module versio\n[…]\nunity.\n\nThe literal initialiser on `version` is load-bearing: -X only rewrites a\nvariable initialised to a constant, so the fallback runs in init() rather\nthan becoming a function call.\n\nSpec: tb-569e",
          "is_bot": false,
          "headline": "go install builds report their module version",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T10:03:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "439a3a04fae7a3e5769c6614459bc43d57bcaa82",
          "body": "Backlog intent only — no Spec: trailer, which on main would derive the\nstory done the moment it is written.",
          "is_bot": false,
          "headline": "Story: go install builds report their module version, not dev",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T09:58:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3e4f36cc80aee233f3d29186d556b1308c4baa00",
          "body": "Generalise the three specs that cited a client's private repo layout as\nevidence — the bugs they describe are unchanged, only the names go — and\ndrop the README caveat about unauthenticated install paths 404ing, which\nstops being true the moment the repo is public.\n\nSpec: tb-9693",
          "is_bot": false,
          "headline": "Prepare for the public flip",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T09:52:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4242902455266ce206ec95105ac7ed4ab8440eb7",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-d146-hook-upgrade'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T09:39:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1f95974b67830f45b0341809c7764b59a2163b32",
          "body": "installHook returned \"already installed\" on seeing hookMark and never\ntouched the text again, so a hook was frozen at whatever version wrote\nit — which meant tb-3d43's quieter nudge could not reach a single\nexisting adopter.\n\nThe nudge now closes with hookEndMark, so future versions can bound\ntheir \n[…]\nm's lines survived on both sides, a re-run left\nthe file untouched, and the upgraded nudge is silent on intent-only\ncommits.\n\nAlso gofmt internal/audit/audit_test.go, missed in tb-3d43.\n\nSpec: tb-d146",
          "is_bot": false,
          "headline": "Re-running init upgrades an existing commit-msg hook",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T09:39:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "48453b3b2741c32f08590c393734e86e67eb17f3",
          "body": "Backlog intent only — no Spec: trailer, which on main would derive the\nstory done the moment it is written.",
          "is_bot": false,
          "headline": "Story: re-running init upgrades an existing commit-msg hook",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T09:14:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7f03a5bc23c73fbac2f90b414c484ff68b504366",
          "body": "Backlog intent only — no Spec: trailer, which on main would derive the\nstory done the moment it is written.",
          "is_bot": false,
          "headline": "Story: truthboard status reports the serving version",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T09:12:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "35c77ac6028bb3bd6acb53997bdc747a21f9b460",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-3d43-hook-agrees'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T09:00:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bd80ff14c954e2b2dd3d8c040108d517d88121de",
          "body": "The commit-msg nudge warned \"this commit will show up as shadow work\"\non spec-only commits that the audit exempts — caught landing the tb-1eb5\nstory. A hook that cries wolf on the one commit shape it should ignore\nteaches you to ignore the hook.\n\nThe nudge now reads the staged fileset and applies the same governed rule\nas audit.governedFile. Silence is the exception, not the fallback: an\nempty or unreadable staged list falls through to the warning.\n\nSpec: tb-3d43",
          "is_bot": false,
          "headline": "The trailer hook agrees with the audit on intent commits",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T09:00:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "07163c3294d606b7fabc2157577c02cc9687cd80",
          "body": "Backlog intent only, no trailer — a Spec: trailer on main would derive\nthis story done the moment it is written.",
          "is_bot": false,
          "headline": "Story: a declared spoke path must prove it is the declared repo",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T08:57:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "623c7f9022d1345d633371ab0ab0c6bfd881c319",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-3d43-adoption-not-shadow'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T08:55:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ee387998a7f57202ddba82683ecf524b79449dc",
          "body": "Installing truthboard on the LetTalk hub for real showed the board's\nopening statement accusing its own setup of drift: the adoption commit\nlands directly on the integration branch by necessity — there is no\nboard to open an MR against yet — and tb-6e13's exemption only covered\n.truthboard/, so the \n[…]\nDE.md. Confined to those, a\ncommit changes how work is tracked and never the product. Mixed commits\nstay shadow work — code smuggled in beside intent is the case the\nfinding exists for.\n\nSpec: tb-3d43",
          "is_bot": false,
          "headline": "The adoption commit is not shadow work",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T08:55:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "042e5043d433a623de146b67d72d9293df0e35f5",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-a4ab-init-git-doctor'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T08:32:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8400299aaedb52516907346ec847df826d62762b",
          "body": "A clean-room run of the LetTalk hub setup on the released v0.8.0 binary\nfound the last onboarding hole. Single repos are already git repos when\nyou adopt them; a multi-repo hub is the one repo people create as an\nempty directory by hand, and init --workspace scaffolded it in silence,\nthen closed wit\n[…]\ninted the name of an internal for-each-ref invocation\n— so gitrepo.Run translates \"not a git repository\" into the directory\nand the fix, leaving every other failure its command context.\n\nSpec: tb-a4ab",
          "is_bot": false,
          "headline": "Init reports a hub that is not a git repository yet",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-20T08:32:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cf6878be560b6c2626002b9c2c36295d38adae21",
          "body": "Spec: tb-9693",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-9693-install-ergonomics'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T20:20:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f7ab68009b0b98b7e45070a4adc93c3d1aa83ee9",
          "body": "install.sh (repo root, POSIX sh, shellcheck-clean): resolves the current\ntag from the releases/latest redirect — the same never-stale pattern as\ndeploy.md — picks darwin/linux × amd64/arm64, verifies the tarball against\nchecksums.txt (sha256sum or shasum), and installs to /usr/local/bin when\nwritabl\n[…]\na shellcheck job over all shipped shell.\n\nREADME leads with curl|sh and brew, keeping tarballs and go install as\nalternatives, with a note that unauthenticated paths 404 until the flip.\n\nSpec: tb-9693",
          "is_bot": false,
          "headline": "Install ergonomics, staged for the public flip: install.sh + brew tap",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T20:20:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9c7d5b217f6defaf9ee61fe5aa12bf2e8d5c7155",
          "body": "Spec: tb-dcef",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-dcef-repo-filters'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T20:11:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "43639e3e311388cf1a31a927468a510ac638fffa",
          "body": "…cycle\n\nOne membership rule everywhere: a story belongs to a repo through declared\nrepos: intent, a per_repo landing entry, a linked branch living there\n(label prefix; unprefixed = hub), or the landing itself — so a repos:\nstory appears under every repo it declares and a plain story under the\nrepos \n[…]\nes → off, shown as repo= in the header like the\nother filters; the key and its footer hint exist only when a workspace\ndoes. Single-repo boards render byte-identically in both surfaces.\n\nSpec: tb-dcef",
          "is_bot": false,
          "headline": "Workspace board gets a repo dimension: filter chips, meta links, TUI …",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T20:11:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7d90920efa515a547bbff045e785e27adaa4d052",
          "body": "Spec: tb-9aa1",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-9aa1-init-workspace'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T19:59:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d801491c4917d108e8b797e8b2afb2ea3fd95269",
          "body": "init gains --workspace name=remote pairs (plus repeatable --path name=dir\nfor local spokes, alone or annotating a pair): workspace.Declare validates\nthe whole batch first — name grammar and the reserved hub name via the\nsame ValidName the loader enforces, duplicates, remote-or-path — and only\nthen w\n[…]\ned spoke and documents that\nspokes stay loud unreadable findings until a path exists or the board\nserver clones them. docs/multi-repo.md quick start now leads with the\none-command path.\n\nSpec: tb-9aa1",
          "is_bot": false,
          "headline": "truthboard init --workspace: scaffold a multi-repo hub in one command",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T19:59:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "909418d61461aa5d8e91e4fdc95f1a0633fe64c7",
          "body": "Spec: tb-711f",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-711f-forge-per-spoke'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T19:49:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1f18bdf850408a8813626f751c2ccba88f321c7",
          "body": "…repo\n\nThe hub-only guard falls: EnrichWithForges fetches forge data per repo —\nthe hub first, then every readable spoke, each repo's own remote deciding\nwhich forge (gh/glab) answers. A spoke branch with an open PR now derives\nin-review, claims-vs-proof runs against each spoke's own tracker with\nsu\n[…]\n\nevery forge that answered, not just the hub's — spoke-only claims were\notherwise computed but never rendered.\n\nSpec scope widened to the callers and renderers this necessarily touches.\n\nSpec: tb-711f",
          "is_bot": false,
          "headline": "Forge enrichment per spoke: PRs, claims, and CI from every workspace …",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T19:49:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2f9adc5327abae9be82894197c3b64c533ddbaef",
          "body": "Five stories for review, ids bare on purpose (a Spec: trailer on main\nwould derive them done): forge enrichment per spoke (tb-711f) and\nworkspace board repo filters (tb-dcef) extend the multi-repo epic;\ninit --workspace scaffolding (tb-9aa1) closes the hub-setup DX gap;\nDocker end-to-end verificatio\n[…]\nublic-flip install\nergonomics — install.sh + brew tap (tb-9693) — round out ship\nreadiness. Priorities are a proposal: reorder or delete freely.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Backlog: next phase after the multi-repo release",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T15:48:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7c677739fb6c18663100434dbfb47705399297e3",
          "body": "Spec: tb-9cf1\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-9cf1-docs-version-proof'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T15:42:47Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8d2c43db9d55057c61786dbcf2e2f65c787b1aee",
          "body": "deploy.md's install one-liner named the v0.5.0 tarball — stale since\nv0.6.0, and a staleness class, not an instance: any hardcoded tag dies\non the next release. The snippet now resolves the current tag from the\nreleases/latest redirect at run time (verified against a public repo's\nredirect; the gh r\n[…]\nts — extracted binary reports\ntruthboard v0.6.0). README Status: v0.6.0 with multi-repo workspaces\non main awaiting the next tag.\n\nSpec: tb-9cf1\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Docs catch up with reality: version-proof install line, README status",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T15:42:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "26baac21ebcbe8e274ad1793b77c2ac92a716a4a",
          "body": "Spec: tb-f515\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-f515-agent-decomposition'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T15:22:13Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8f470c218c81d90589da3eaaca174384e226312e",
          "body": "repos: (tb-c512) is the mechanism; per-repo decomposition is the\npractice, and the agent picking up a fat story is the one who should do\nit — never the PO on a phone. The adoption agreement gains a multi-repo\nsection when the hub carries a workspace manifest: split the story\n(narrow the original int\n[…]\n contract\nwith per-repo evidence, MCP flow test drives narrow + create-child +\nunknown-repo rejection + next ordering end to end.\n\nSpec: tb-f515\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Agents decompose cross-repo stories into per-repo children",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T15:22:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3028a9df590b9b7e692b5273cea6af8ce6e1a432",
          "body": "Spec: tb-c512\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-c512-cross-repo-done-semantics'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T15:10:22Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "eef92848a0eb3e4b6694addd4e16566d1a3d3363",
          "body": "Git cannot prove the absence of work it never knew was intended, so a\nstory that must land in several repos now declares it: repos: [api,\nweb] in frontmatter (\"hub\" is reserved for the repo carrying\n.truthboard/ — the manifest refuses a spoke by that name). With repos:\ndeclared, done requires the tr\n[…]\nond landing, 400 on unknown\nrepos over the API, detail-view Repos row and editor round-trip in\nChrome with no new console errors.\n\nSpec: tb-c512\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Cross-repo done semantics: repos as intent, per-repo evidence",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T15:10:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a1f1ed1d4ecfa07537b4d465ef59dd1acf78d252",
          "body": "Spec: tb-8a79\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-8a79-multi-repo-workspace'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T14:50:20Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8b75194c8898c3eeb104fb8879058c4ecda40b85",
          "body": "Hub-and-spokes: intent stays in the hub repo's .truthboard/, proof is\ngathered from every spoke declared in .truthboard/workspace.yml. The\naudit fans out over hub + resolvable spokes — units, digest, and shadow\nwork carry a repo tag; spec linking, landing, and revert detection run\nper repo with evid\n[…]\npath checkout +\nremote-only spoke), CLI audit, live board with self-healed mirror\nclone, browser render with zero console errors.\n\nSpec: tb-8a79\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Multi-repo workspace: one board over N repositories",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-19T14:50:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f71130bd5438597f7751aabaf10ee7ea5eb413fc",
          "body": "One board over N repositories, phased: workspace manifest with merged\naudit (tb-8a79), repos: frontmatter for cross-repo done semantics with\nper-repo evidence (tb-c512), agent-side decomposition of fat stories\ninto per-repo children (tb-f515). Intent lives in the hub repo; proof\nis gathered per spok\n[…]\nd, never typed.\n\nIds kept bare above on purpose: a Spec: trailer on main would derive\nthese stories done the moment this commit lands on origin.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Backlog: multi-repo epic — hub intent, workspace proof, cross-repo done",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T19:36:40Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d5a771b62d1a7e8720654e785441b52c33d14fe8",
          "body": "Spec: tb-6e13",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-6e13-remote-intent-editing'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T19:06:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "addd6f227a3ee36ef0257a63e7e626c24aa8e9b3",
          "body": "…k them up at home\n\nAn edit token (--edit-token / TRUTHBOARD_EDIT_TOKEN) arms intent writes\non a shared board. Reads stay open to anyone; writes carry the token\n(X-Truthboard-Token or bearer, constant-time compared like the webhook\nsecret) and land as real commits: the server adds the one spec file,\n[…]\nome — unlock, create from the browser, commit pushed to origin,\nand truthboard next in a second clone handing back the new story.\n\nSpec: tb-6e13\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Remote intent editing: create stories from a shared board, agents pic…",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T19:06:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bd7a3b1db23b9606f457b8c065795c1965cb58cb",
          "body": "Spec: tb-146e",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-146e-deploy-docs'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T18:49:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "588b834f1a0f9163effdd620016face208e1a87a",
          "body": "The board becomes a one-URL team service on any machine: a multi-stage\nDockerfile (alpine + git runtime, non-root, clone-on-first-start via\nREPO_URL or a mounted clone), and docs/deploy.md walking through the\nthree shapes — binary under systemd on EC2/VPS, Docker, and Coolify —\nplus poll-vs-webhook \n[…]\nd64, and the entrypoint was driven directly —\nREPO_URL clone path, env-driven flags, 200 on reads, 403 on writes\nbeyond loopback.\n\nSpec: tb-146e\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Shared board deploys anywhere: Dockerfile + server install docs",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T18:49:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bfde85d0ebec30f4b9143517e19adab38f6f4ec7",
          "body": "From a phone, create or edit a story on the shared board; the server\ncommits the intent to its clone and pushes to origin, and the agent at\nhome picks it up with truthboard next. Gated on an edit token — until\nthen shared boards stay read-only.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Backlog: remote intent editing from a shared board",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T18:34:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d58dfa91e873971656c843de5a90361a44db599e",
          "body": "Spec: tb-18df",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-18df-mcp-client-docs'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T18:13:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3a0f649940b2467945d48187ed17d2d1fcd5c1e6",
          "body": "The stdio MCP server has nothing Claude-specific in it, but the README\nonly showed the Claude Code registration command, so the question kept\ncoming up. The MCP section now says so outright and carries registration\nsnippets for Cursor, Codex CLI, and Gemini CLI, plus a note that\nAGENTS.md (not CLAUDE.md) is the cross-tool working agreement. The spec\ngets its real goal and acceptance in the same change.\n\nSpec: tb-18df\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Document that the MCP server works with any MCP client",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T18:13:04Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1b577d334a84015a59f59416764813c0e50006ec",
          "body": "Spec: tb-69d9",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-69d9-readme-v05'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T17:40:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5ac764f3d2b5022eeb61bb011d6b49ed39110288",
          "body": "Spec-mode section grows the intent vocabulary (type, points, needs with\nderived waiting, dated sprints); new sections for the terminal board and\nthe explicit LLM draft/review commands; the web board section documents\n--notify transitions and the webhook + SSE live mode, and stops claiming\na single embedded HTML file; MCP tool list completed; Status says v0.5.0\nand points readers at this repo's own live board.\n\nSpec: tb-69d9\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "README documents the v0.5 feature set",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T17:40:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "96b1d041caa09aae6e7c1aa1e44db3d9815cd74d",
          "body": "Spec: tb-c56b",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-c56b-dependencies'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T17:35:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ec5f5e65bbbc02b08b7020238d13c1cc7ba8c69e",
          "body": "needs: [tb-xxxx] frontmatter is pure intent, writable via spec new\n--needs, MCP create/update, and the web editor — every write path\nvalidates ids against the specs that exist (before creating the file,\nso a typo never leaves an orphan; the same latent orphan bug in the\ntype validation is fixed by t\n[…]\ned as\nthe chain, and cycle members are never handed out. A need referencing\na vanished id shows as tb-gone? — visible, not fatal.\n\nSpec: tb-c56b\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Spec dependencies: needs as intent, readiness derived",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-18T17:35:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c4b1deaff29c2ede12937372d6822ae8360894d3",
          "body": "Spec: tb-ad46",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-ad46-notifications'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T15:05:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "015f5aca7cedffffe5ae86ac0cd305b8e0941342",
          "body": "ui --notify <url> (env TRUTHBOARD_NOTIFY_URL; detach passes it through\nthe environment — Slack webhook URLs are secrets) arms a notifier on\nthe board process: once a minute, and immediately on a push webhook, it\nre-derives the board, diffs each spec's status against the last check\n(.git/truthboard/n\n[…]\ndence line. First sight is baseline, steady state is silent, and\nwithout --notify nothing changes and no state file ever appears.\n\nSpec: tb-ad46\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Stalled and regressed stories notify someone, not just the board",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T15:05:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c42c0ecdf74a3ae05d4ec9138d9e22a68974d0a1",
          "body": null,
          "is_bot": false,
          "headline": "Backlog: notifications and spec dependencies",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T14:55:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "80531bbd7b1fb5fb87abbd973f9f02123e2103f7",
          "body": "Spec: tb-a8a7",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-a8a7-readme-screenshots'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T14:34:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a6109472644ce23931832d481dd07367d24671db",
          "body": "Two captures from a realistic acme-shop demo (checkout + activation\nepics, sprint s12 mid-flight): the derived kanban with stat tiles,\nfilters, and the dated sprint rollup; and a story detail with signed-off\nGherkin acceptance above the derived-truth panel. Captions spell out\nwhat the pictures argue — statuses computed from branches and merges,\nintent editable, proof not. Images live in docs/screenshots, no\nexternal hosts.\n\nSpec: tb-a8a7\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "README shows the board: screenshots from a demo repo",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T14:34:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "21b8967be6f9e497c9b8a137925e3fbd2aceba68",
          "body": "Spec: tb-f82e",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-f82e-dialog-scroll-version'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T14:11:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9cad55a9053c9a00dd6d93c0629b26cf7f36e138",
          "body": "The dialog body capped its height with calc(86vh - 8rem) — a guess at\nheader/footer size that the detail view's chips and assign rows, and\nthe editor's grown field grid, had outgrown, clipping the footer\nbuttons out of reach. Dialogs are now flex columns: chrome keeps its\nsize, the body flexes and s\n[…]\ned. The serving version now also sits next to the page title,\nand source builds say 'dev build (source)' instead of a bare 'dev'.\n\nSpec: tb-f82e\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Board dialogs scroll properly and the serving version is always visible",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T14:11:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "22ddd159e4c2ba400b9ff5c8916a392a513b3664",
          "body": "Spec: tb-40c4",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-40c4-static-split'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T14:08:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "83678c5b608d8e51693d232369572dbd613b8a13",
          "body": "internal/web/static/{index.html,app.css,app.js} embedded as a directory\nand served same-origin under /static/ — organized, diffable, and\nsyntax-checkable, with go build still the entire pipeline. The\nself-containment test now proves the stronger property directly: every\nsrc/href on the page must be same-origin and actually served by the\nhandler, instead of banning asset tags outright.\n\nSpec: tb-40c4\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Split the web page into embedded static assets",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T14:08:58Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4b8aaf3e2fe7e91d4ef064c3299ac6327aa4557d",
          "body": null,
          "is_bot": false,
          "headline": "Backlog: static-asset split and the dialog/version UI bug",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:59:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "344175907eea63dcde4bb6c5ff684dda7236d897",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "CLAUDE.md: carry the Truthboard working agreement into Claude sessions",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:34:15Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ed696e87ffa4c9a3355e8eb8a4358959ff05536b",
          "body": "Spec: tb-f21c",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-f21c-live-shared-board'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:25:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "411da51ba012c65a02fbb815ff9247018022a20d",
          "body": "ui --webhook-secret (or TRUTHBOARD_WEBHOOK_SECRET, which detach passes\nthrough the environment, never argv) arms POST /webhook: a forge push\ncarrying the secret — GitLab's X-Gitlab-Token, GitHub's HMAC-SHA256\nbody signature, or ?token= — triggers an immediate coalesced fetch and\nre-derive instead of\n[…]\nard on\npurpose: it carries its own auth and can only make the board fresher —\nspec writes stay forbidden there, verified by test.\n\nSpec: tb-f21c\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Live shared board: webhook-triggered fetch and browser push",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:25:22Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7117e2487a90ffe4bcab71180e25cbafbff7490c",
          "body": "Spec: tb-1be0",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-1be0-embedded-llm'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:18:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3a9245ea46f53a4382c4110925f9f56a2805ebf3",
          "body": "internal/llm speaks Anthropic (ANTHROPIC_API_KEY) or a local Ollama\n(OLLAMA_HOST) over plain HTTP — no SDK. truthboard draft turns a\nconcept into an epic of fully-formed stories written through the same\nspec files a human would edit, refusing any story that arrives without\na Goal and Acceptance chec\n[…]\n derived facts — the LLM is a\nwriter, never a source. Nothing calls a model unless one of the two\ncommands is explicitly invoked.\n\nSpec: tb-1be0\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Embedded LLM: draft a backlog, narrate the sprint review",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:18:23Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b5caf08321cbe77560ee6e0de2675f8db029b6b8",
          "body": "Spec: tb-8dd7",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-8dd7-tui-board'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:15:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7845823a90f3fc0573b6672e4af1e0300dbf81df",
          "body": "truthboard board opens the derived board in the terminal: kanban\ncolumns (core four always, stalled/regressed only when occupied),\narrow/vim navigation, enter for a detail pane that reads the spec's\ngoal and acceptance from disk, e/s/a cycling filters for epic, sprint,\nand owner, and d/g views for t\n[…]\nrictly\na viewer — there is no keybinding that writes anything, because\nstatuses are derived from git and there is nothing to set.\n\nSpec: tb-8dd7\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Terminal board: a read-only Bubbletea TUI",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:15:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "893f389938b00efa637d03cbd4505f19de331778",
          "body": "Spec: tb-fa9b",
          "is_bot": false,
          "headline": "Merge branch 'feature/tb-fa9b-spec-types'",
          "author_name": "Emmanuel Dadem",
          "author_login": "emmanuel-D",
          "committed_at": "2026-07-17T13:06:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 16,
      "commits_last_year": 172,
      "latest_release_at": "2026-07-28T04:40:23Z",
      "latest_release_tag": "v0.10.0",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 1,
      "days_since_latest_release": 0,
      "mean_days_between_releases": 1
    },
    "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/emmanuel-D/truthboard",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/emmanuel-D/truthboard",
          "is_deprecated": false,
          "latest_version": "v0.10.0",
          "repository_url": "https://github.com/emmanuel-D/truthboard",
          "versions_count": 16,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-28T04:37:41Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 0,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_stars": 0,
        "collected_at": null
      },
      "open_issues_and_prs": 1
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": true,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "go.mod"
      ],
      "largest_source_bytes": 42697,
      "source_files_sampled": 71,
      "oversized_source_files": 0,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 1271
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "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"
      ],
      "dependencies": [
        {
          "name": "github.com/charmbracelet/bubbletea",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.3.10"
        },
        {
          "name": "github.com/charmbracelet/lipgloss",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v1.1.0"
        },
        {
          "name": "gopkg.in/yaml.v3",
          "manifest": "go.mod",
          "ecosystem": "go",
          "version_constraint": "v3.0.1"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 1,
        "open_issues": 1,
        "closed_ratio": 0,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "emmanuel-D",
          "commits": 197,
          "avatar_url": "https://avatars.githubusercontent.com/u/37305687?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "release.yml",
        "truthboard.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "go.sum"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "1 out of 1 merged PRs checked by a CI test -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 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": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 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": 8,
            "reason": "2 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "2fa8249ceced93fb7425007889ad728fe2dcd845",
        "ran_at": "2026-07-28T21:20:18Z",
        "aggregate_score": 2.9,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-28T14:49:47Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-20T11:45:32Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 1,
          "created_at": "2026-07-15T19:27:54Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/emmanuel-D/truthboard",
    "host": "github.com",
    "name": "truthboard",
    "owner": "emmanuel-D"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "at_risk",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 48,
      "inputs": {
        "security": 28,
        "vitality": 69,
        "community": 24,
        "governance": 43,
        "engineering": 71
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "moderate",
        "name": "Vitality",
        "value": 69,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "commits_last_year": 172,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 1
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "1/52 weeks with commits",
                "points": 0.7,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 1
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "172 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 172
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 16,
              "latest_release_tag": "v0.10.0",
              "releases_from_tags": false,
              "days_since_latest_release": 0,
              "mean_days_between_releases": 1
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "16 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 16
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~1 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 1
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 24,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 0,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "0 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "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": "at_risk",
        "name": "Sustainability & Governance",
        "value": 43,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "at_risk",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 38,
            "inputs": {
              "merged_prs": 1,
              "open_issues": 1,
              "closed_issues": 0,
              "issue_closed_ratio": 0,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "0% of issues closed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 0
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "1/1 decided PRs merged",
                "points": 38.2,
                "status": "met",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 1,
                      "decided": 1
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": "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": 43,
            "inputs": {
              "followers": 2,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "emmanuel-D",
              "public_repos": 15,
              "account_age_days": 3060
            },
            "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": "2 followers of emmanuel-D",
                "points": 3.4,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 2,
                      "login": "emmanuel-D"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "15 public repos, account ~8 yr old",
                "points": 20.8,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 15
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 8
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/emmanuel-D/truthboard"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "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 0 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "16 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 16
                    }
                  }
                ],
                "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": 71,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 68,
            "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": "1 out of 1 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [
                "ai-agents",
                "developer-tools",
                "git",
                "golang",
                "kanban",
                "mcp",
                "project-management"
              ],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": "7 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 7
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "critical",
        "name": "Security",
        "value": 28,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "critical",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 28,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 2.9
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "1 out of 1 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "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": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file 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": "2 existing vulnerabilities detected",
                "points": 6,
                "status": "partial",
                "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": 2
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 67,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "good",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.56,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 1271
            },
            "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": "56 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 29.9,
                "status": "partial",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 56,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 66,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "go.sum"
              ],
              "has_dockerfile": true,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.25,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "go.mod (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "go.mod"
                    }
                  }
                ],
                "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": "25 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 25,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 42697,
              "source_files_sampled": 71,
              "oversized_source_files": 0
            },
            "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": "0/71 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 71,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "critical",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 20,
            "inputs": {
              "example_dirs": [],
              "has_mcp_signal": true,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-28T21:20:24.215773Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/e/emmanuel-D/truthboard.svg",
  "full_name": "emmanuel-D/truthboard",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

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