Public record
Software health reportschema 0.27.0 · metrics 1.13.0 · 2026-07-24 16:29 UTC

marcus / td

A minimalist CLI for tracking tasks across AI coding sessions.

GoMIT★ 232 stars⑂ 27 forkssince Dec 2025View on GitHub ↗

marcus/td holds a health index of 60 out of 100, placing it in the Moderate band. It scores highest on Vitality (83/100) and lowest on Security (33/100). It was last updated 5 days ago. A single contributor accounts for most of its recent work.

60
overall / 100
Moderate

Software health index

Metrics are grouped into weighted categories on one standardized 1–100 scale. Overall starts as their weighted mean; when public evidence triggers the High-Risk Jurisdiction Policy, the rating is adjusted and receives an At risk ceiling of 49. AI Readiness sits outside the overall score.

60
Excellent85-100Exemplary; meets essentially all checked criteria
Good70-84Healthy; minor gaps
Moderate50-69Acceptable with notable gaps; review recommended
At risk30-49Significant weaknesses; adoption warrants caution
Critical1-29Severe problems (abandoned, single-maintainer, no hygiene)
VitalityCommunity &AdoptionSustainability &GovernanceEngineeringQualitySecurityAI Readiness

Score profile

Each axis is a category. The shape matters more than the average — a healthy subject fills the whole shape, while a spike-and-crater profile means strength in one dimension is masking risk in another.

Ownership

Marcus VorwallerPersonal account
217 followers28 public repossince Mar 2008Avalara

This repository is owned by a personal account. A single-owner project carries more continuity risk than an organization-backed one.

Package ecosystems

RegistryPackageVersionDownloads / moVersionsLast publish
Gogithub.com/marcus/tdv0.51.2-996 days ago

Metrics by category

Vitality

Is the project alive — is code being written and are releases shipping?

83Good · 22% of overall
How it's scored
36/36Push recency — last push 5 days ago
15.2/36Commit cadence — 22/52 weeks with commits
18/18Commit volume — 841 commits in the last year
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Inputs used
commits_last_year841
human_commit_share1
days_since_last_push5
active_weeks_last_year22
How it's scored
27/27Ships releases — 64 releases published
36/36Release recency — latest release 6 days ago
27/27Release cadence — a release every ~3.4 days
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Inputs used
releases_count64
latest_release_tagv0.51.2
releases_from_tagsno
days_since_latest_release6
mean_days_between_releases3.4

Community & Adoption

Does the project have users, downloads, attention, and a welcoming setup for contributors?

50Moderate · 18% of overall
How it's scored
38.3/60Stars — 232 stars
11.8/25Forks — 27 forks
0/15Watchers — 2 watchers
Inputs used
forks27
stars232
watchers2
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
How it's scored
22.5/22.5README
22.5/22.5License — recognized license (MIT)
0/18CONTRIBUTING guide
0/13.5Code of conduct
0/7.2Issue template
0/6.3PR template
Inputs used
has_readmeyes
has_licenseyes
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno

Sustainability & Governance

Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?

54Moderate · 24% of overall
How it's scored
9/54Bus factor — 1 contributor(s) cover half of all commits
0.8/22.5Commit distribution — top contributor authored 97% of commits
12.2/13.5Contributor breadth — 9 contributors
3/10OpenSSF Scorecard: Contributors — project has 1 contributing companies or organizations -- score normalized to 3
Inputs used
bus_factor1
contributors_sampled9
top_contributor_share0.966
How it's scored
15.1/46.8Issue resolution — 32% of issues closed
28.7/38.3PR acceptance — 33/44 decided PRs merged
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Inputs used
merged_prs33
open_issues23
closed_issues11
issue_closed_ratio0.324
closed_unmerged_prs11
How it's scored
10/30Ownership backing — personal (user) account
0/20Verified domain — not applicable to user accounts
16.8/25Owner reach — 217 followers of marcus
22.6/25Track record — 28 public repos, account ~18 yr old
Inputs used
followers217
owner_typeUser
is_verified
owner_loginmarcus
public_repos28
account_age_days6,706
Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.
How it's scored
25/25Published & resolvable — 1 package(s) on go
35/35Publish recency — latest publish 6 days ago
20/20Version history — 99 published versions
20/20Not deprecated — active, not deprecated or yanked
Inputs used
packagesgithub.com/marcus/td
ecosystemsgo
any_deprecatedno
min_days_since_publish6

Engineering Quality

Are baseline engineering and documentation practices in place?

70Good · 20% of overall
How it's scored
24/24CI workflows — 3 workflow(s)
24/24Tests present
0/16Linter config
0/9.6Pre-commit hooks
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — no data
Inputs used
has_ciyes
has_testsyes
has_editorconfigno
has_linter_configno
has_precommit_configno
Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.

Documentation

85Excellent
How it's scored
30/30README
25/25Documentation directory
0/15Documentation / homepage site
10/10Repository description
10/10Topics — 2 topics
10/10Wiki
Inputs used
topicsagents, ai
has_wikiyes
homepage
has_readmeyes
has_docs_diryes
has_descriptionyes

Security

Are visible security and supply-chain practices strong, without unresolved high-risk jurisdiction exposure?

33At risk · 16% of overall
How it's scored
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — no data
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5License — license file detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
1/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 2
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
0/7.5Vulnerabilities — 67 existing vulnerabilities detected
Inputs used
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate3.3
Excluded from scoring (no data or not applicable): ci_tests. Remaining weights renormalized.

AI Readiness

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.

82Good · 0% of overall
How it's scored
45/45Agent instructions — AGENTS.md, CLAUDE.md
0/15Machine-readable docs (llms.txt)
40/40Legible commit history — 97 of 100 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share0.97
agent_instruction_filesAGENTS.md, CLAUDE.md
agent_instruction_max_bytes8,569
How it's scored
18/18One-command bootstrap — Makefile
22/22Automated tests
0/11Lint / format config
11/11Static type checking — Go (statically typed)
10/10Reproducible environment — Dockerfile, lockfile
10/10Demonstrated agent practice — 73 of the last 100 commits agent-authored or agent-credited
0/8Automated maintenance — no automated dependency updates observed
2/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 2
Inputs used
has_nixno
has_testsyes
lockfilesgo.sum, package-lock.json
has_dockerfileyes
typed_languageyes
bootstrap_filesMakefile
has_devcontainerno
has_linter_configno
typecheck_configs
agent_commit_share0.73
toolchain_manifestsgo.mod
dependency_bot_commit_share0
How it's scored
45/45Type-checkable code — Go (statically typed)
54.5/55Manageable file sizes — 4/480 source files over 60KB
Inputs used
primary_languageGo
largest_source_bytes134,501
source_files_sampled480
oversized_source_files4

Key facts

232GitHub stars
9contributors
841commits, last 12 months
5days since last push
64releases
1bus factor
23open issues
Go, npmpackage ecosystems

Data collection warnings

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

More detail

Star and fork history 0 ★ / 27 ⇿
0Stars
27Forks
22Releases

When each star and fork was added, collected from GitHub and bucketed by day. Cumulative growth sits directly above the daily additions it is made of, so the two read against each other: steady organic accretion looks nothing like an abrupt, short-lived burst. Where that difference is measurable, it is reported as growth authenticity.

0510152025302732026-022026-042026-06
Major 0Minor 18Patch 4
OpenSSF Scorecard 3.3 / 10
3.3aggregate

Independent, tool-agnostic security assessment from the open-source OpenSSF Scorecard. Each check rewards a security practice, not a specific vendor's tool. Checks Scorecard could not determine are marked n/a and excluded from the security score (never counted as zero).Scorecard v5.5.0 · 2026-07-24 16:29 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
n/aCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
2Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 2
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities67 existing vulnerabilities detected
Direct dependencies 24
RegistryPackageVersion constraintManifest
Gocharm.land/bubbles/v2v2.1.0go.mod
Gocharm.land/bubbletea/v2v2.0.7go.mod
Gocharm.land/glamour/v2v2.0.0go.mod
Gocharm.land/huh/v2v2.0.3go.mod
Gocharm.land/lipgloss/v2v2.0.3go.mod
Gogithub.com/charmbracelet/x/ansiv0.11.7go.mod
Gogithub.com/charmbracelet/x/cellbufv0.0.15go.mod
Gogithub.com/mattn/go-sqlite3v1.14.33go.mod
Gogithub.com/sahilm/fuzzyv0.1.1go.mod
Gogithub.com/spf13/cobrav1.10.2go.mod
Gogithub.com/spf13/pflagv1.0.10go.mod
Gogolang.org/x/cryptov0.47.0go.mod
Gogolang.org/x/syncv0.20.0go.mod
Gogolang.org/x/sysv0.45.0go.mod
Gogolang.org/x/termv0.39.0go.mod
Gomodernc.org/sqlitev1.41.0go.mod
npm@docusaurus/core3.9.2website/package.json
npm@docusaurus/preset-classic3.9.2website/package.json
npm@mdx-js/react^3.0.0website/package.json
npmclsx^2.0.0website/package.json
npmlucide-react^0.563.0website/package.json
npmprism-react-renderer^2.3.0website/package.json
npmreact^19.0.0website/package.json
npmreact-dom^19.0.0website/package.json
All dependencies not collected

The resolved dependency set could not be collected for this report: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

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

Scores are signals, not warranties. They reflect publicly visible practices on GitHub — not a code audit, and not a security guarantee.

Missing data is excluded and weights renormalized, never scored as zero. Methodology is versioned and open: metrics v1.13.0, schema v0.27.0 — full methodology · metrics wiki.

How one result sits in the wider record: aggregate statisticsGo.