JSON-Rohbericht maschinenlesbar
{
"data": {
"repo": {
"topics": [
"blogging",
"cli",
"hugo",
"indieweb",
"local-first",
"markdown",
"posse",
"static-site",
"website"
],
"is_fork": false,
"size_kb": 1957,
"has_wiki": true,
"homepage": "https://crofty.site",
"languages": {
"Go": 705748,
"CSS": 19731,
"HTML": 18746,
"NSIS": 5680,
"Shell": 12874
},
"pushed_at": "2026-07-26T08:32:26Z",
"created_at": "2026-06-16T15:55:12Z",
"owner_type": "User",
"updated_at": "2026-07-26T08:32:27Z",
"description": "Own your site end to end: write Markdown, crofty builds it with Hugo and deploys to your own Cloudflare. No server of ours.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "AGPL-3.0",
"default_branch": "main",
"license_spdx_raw": "AGPL-3.0",
"primary_language": "Go",
"significant_languages": [
"Go"
]
},
"owner": {
"blog": "https://shiro-doro.site",
"name": "ShiroDoro",
"type": "User",
"login": "ShiroDoromoto",
"company": null,
"location": "Japan",
"followers": 4,
"avatar_url": "https://avatars.githubusercontent.com/u/8072360?v=4",
"created_at": "2014-07-05T02:34:32Z",
"is_verified": null,
"public_repos": 14,
"account_age_days": 4406
},
"license": {
"state": "standard",
"spdx_id": "AGPL-3.0",
"raw_spdx": "AGPL-3.0",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.23.0",
"kind": "minor",
"published_at": "2026-07-26T08:33:12Z"
},
{
"tag": "v0.22.0",
"kind": "minor",
"published_at": "2026-07-26T06:31:38Z"
},
{
"tag": "v0.21.0",
"kind": "minor",
"published_at": "2026-07-21T10:43:18Z"
},
{
"tag": "v0.20.0",
"kind": "minor",
"published_at": "2026-07-20T14:53:14Z"
},
{
"tag": "v0.19.0",
"kind": "minor",
"published_at": "2026-07-20T08:45:47Z"
},
{
"tag": "v0.18.0",
"kind": "minor",
"published_at": "2026-07-10T03:29:28Z"
},
{
"tag": "v0.17.2",
"kind": "patch",
"published_at": "2026-07-07T20:45:45Z"
},
{
"tag": "v0.17.1",
"kind": "patch",
"published_at": "2026-07-07T15:33:08Z"
},
{
"tag": "v0.17.0",
"kind": "minor",
"published_at": "2026-07-07T03:39:14Z"
},
{
"tag": "v0.16.1",
"kind": "patch",
"published_at": "2026-06-28T01:51:12Z"
},
{
"tag": "v0.16.0",
"kind": "minor",
"published_at": "2026-06-20T03:21:43Z"
},
{
"tag": "v0.15.0",
"kind": "minor",
"published_at": "2026-06-20T03:08:43Z"
},
{
"tag": "v0.14.0",
"kind": "minor",
"published_at": "2026-06-19T18:45:35Z"
},
{
"tag": "v0.13.0",
"kind": "minor",
"published_at": "2026-06-18T02:52:00Z"
},
{
"tag": "v0.12.0",
"kind": "minor",
"published_at": "2026-06-17T16:11:17Z"
},
{
"tag": "v0.11.0",
"kind": "minor",
"published_at": "2026-06-17T14:44:00Z"
},
{
"tag": "v0.10.2",
"kind": "patch",
"published_at": "2026-06-17T12:37:13Z"
},
{
"tag": "v0.10.1",
"kind": "patch",
"published_at": "2026-06-17T12:16:45Z"
},
{
"tag": "v0.10.0",
"kind": "minor",
"published_at": "2026-06-17T11:42:41Z"
},
{
"tag": "v0.9.0",
"kind": "minor",
"published_at": "2026-06-17T03:58:35Z"
},
{
"tag": "v0.8.1",
"kind": "patch",
"published_at": "2026-06-16T17:51:33Z"
},
{
"tag": "v0.8.0",
"kind": "minor",
"published_at": "2026-06-16T17:37:54Z"
},
{
"tag": "v0.7.1",
"kind": "patch",
"published_at": "2026-06-16T15:57:26Z"
}
],
"recent_commits": [
{
"oid": "31287d6636b571cc20c7f8ad392e278183670998",
"body": "Bumps the go-patch-minor group with 6 updates:\n\n| Package | From | To |\n| --- | --- | --- |\n| [github.com/fclairamb/ftpserverlib](https://github.com/fclairamb/ftpserverlib) | `0.32.0` | `0.32.1` |\n| [github.com/pkg/sftp](https://github.com/pkg/sftp) | `1.13.10` | `1.13.11` |\n| [golang.org/x/crypto](\n[…]\nsion-update:semver-minor\n dependency-group: go-patch-minor\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "chore(deps): Bump the go-patch-minor group with 6 updates (#28)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-26T08:32:19Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d509c87f5293d9f7619791b28b6565b231d2083c",
"body": "Only /doc/wip/ was ignored, so an internal note written to docs/ instead sat\nuntracked in a public repo with `git add -A` a step away — which is how the\nrelease routine starts. Two private request drafts were found there this way;\nthey were deleted before any commit, but nothing except the spelling \n[…]\nored directory does\nnot work on its own.\n\namenbo-task: #2194\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BLUAemzXDZ2XMctxpciFnP",
"is_bot": false,
"headline": "chore(repo): ignore doc/ and docs/ alike, so a typo can't publish a note",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T08:28:36Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "b1dcbea712f3b179335aede5e4b4c1b411d500f3",
"body": "…there\n\nThe installer wrote uninstall.exe to disk and then told nobody about it: no\nHKCU Uninstall key, so crofty never appeared in the Windows list of installed\napps. The one route that exists for people who don't open a terminal let\nthem install and not remove — they would have to find\n%LOCALAPPDA\n[…]\nkeep the install dir from being removed.\n\namenbo-task: #2193\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BLUAemzXDZ2XMctxpciFnP",
"is_bot": false,
"headline": "feat(windows): list crofty in \"Apps & features\" so it can be removed …",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T08:28:36Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "78f8bb749c632e4115b9cc2b1e176212ad2679d2",
"body": "The `low-risk` group named a line that no longer described anything: the\ndeps it left out — credential, network, crypto — were held for a review\nthat one maintainer never got to. A jlaffaye/ftp patch sat unmerged for a\nmonth with CI green since seven minutes in. Holding a known fix out of the\ntree i\n[…]\nd, so merging still\ndistributes nothing.\n\namenbo-task: #2191\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BLUAemzXDZ2XMctxpciFnP",
"is_bot": false,
"headline": "chore(ci): auto-merge every go patch/minor, not a hand-picked few",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T08:28:36Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1c05c314fbab8c5f4f17924a3f7305981a121adb",
"body": "…home\n\nThe macOS .pkg moved its body into the user's home (D-339), but the route\nclassifier still looked for it under /usr/local — the entry link's home,\nwhich crofty resolves away before classifying. Every .pkg install fell to\nrouteUnknown, so `crofty update` refused and doctor reported the install\n[…]\ned home path both with and without Hugo.\n\namenbo-task: #2192\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BLUAemzXDZ2XMctxpciFnP",
"is_bot": false,
"headline": "fix(update): recognize the .pkg body where it actually lives, in the …",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T08:28:36Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "b8e494246ff047007098fec0c84dc57e515508e6",
"body": "Bumps [github.com/jlaffaye/ftp](https://github.com/jlaffaye/ftp) from 0.2.0 to 0.2.1.\n- [Release notes](https://github.com/jlaffaye/ftp/releases)\n- [Commits](https://github.com/jlaffaye/ftp/compare/v0.2.0...v0.2.1)\n\n---\nupdated-dependencies:\n- dependency-name: github.com/jlaffaye/ftp\n dependency-ve\n[…]\nirect:production\n update-type: version-update:semver-patch\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "chore(deps): Bump github.com/jlaffaye/ftp from 0.2.0 to 0.2.1 (#22)",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-26T06:38:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "96498b9767e47fe055abf987449965c422a8efa0",
"body": "Reaching the OS keychain from a test was held off by a convention: every test\nthat touched a credential called keyring.MockInit() itself. A test that forgot\nwould read and write the real keychain — on a developer's machine, the one\nholding their own tokens. A rule each new test has to remember is th\n[…]\nrts what is or isn't saved, and\nbrokenKeychain(t, reason) stands in for a runner with no keychain and puts the\nworking mock back on its own, instead of a defer that can be dropped.\n\namenbo-task: #2188",
"is_bot": false,
"headline": "test(secret): mock the keychain for the whole package, not per test",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T06:14:57Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1243a5ad0be48a5c32dd525c8c887f61997164c4",
"body": "crofty doctor graded the built site and nothing around it, so \"will `crofty\ndeploy` publish from this runner?\" had only one way to be asked: deploy, and be\nstopped. The pieces are found one at a time that way — a token in the\nenvironment, then an account nobody pinned — each costing a push and a red\n[…]\nes to the network — so it can say a credential is there,\nnever that it still works. Like the install advisory it never gates; the output\ncontract keeps deciding doctor's exit code.\n\namenbo-task: #2186",
"is_bot": false,
"headline": "feat(doctor): answer whether a deploy would get through with no terminal",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T06:11:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7ae0e4713df7a705bbd76c3eef6f6315732878ad",
"body": "The non-interactive route exists now, but nothing an author or an AI reads said\nso: `crofty agent` still told an assistant a token can only be typed at a\nterminal, and the deploy that stopped for want of one named no way forward.\n\nName the four variables where they are looked for — `crofty agent`, `\n[…]\nat the author types.\n\nREADME also carries the account half of a CI deploy: pin deploy.accountId from\na terminal once, or pass --account, since a run with no terminal never guesses.\n\namenbo-task: #2184",
"is_bot": false,
"headline": "docs(deploy): say where a credential comes in when there is no terminal",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T05:48:46Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1ed24b86c9a4b5fede21484861e6a9e7930e4ac6",
"body": "Only Cloudflare could authenticate without a terminal, so \"the ways a secret\ngets in\" needed a different answer depending on where the site publishes.\n\nGive the plain-server backends the same three ways in: CROFTY_SFTP_PASSWORD,\nCROFTY_SFTP_KEY_PASSPHRASE and CROFTY_FTPS_PASSWORD, one name per crede\n[…]\ntial into the\nkeychain, so a variable that merely happens to be set must not answer for the\none the user came to type — otherwise connect reports a saved credential it\nnever saved.\n\namenbo-task: #2183",
"is_bot": false,
"headline": "feat(deploy): read SFTP / FTPS secrets from crofty's own variables too",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T05:44:33Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f60d603a91a4906a418ece535c2e2c4d67ccefa7",
"body": "With a token now arriving from the environment, `crofty deploy` reached account\nresolution on CI and asked a question nobody was there to answer: it printed the\naccount-id prompt and died on EOF, saying nothing about what to set.\n\nCheck for a terminal before every turn that needs one. Without one, a\n[…]\nnt.\n\nA move is never guessed off a terminal — nobody can confirm it, and guessing\nwould publish the site to an account its owner never named.\n\nBehaviour at a terminal is unchanged.\n\namenbo-task: #2182",
"is_bot": false,
"headline": "feat(deploy): stop with what is missing when there is no terminal to ask",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T05:38:42Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f486d7526a5f6428d060636709dcc4b15b60c721",
"body": "A CI runner has no terminal and no keychain, so `crofty deploy` always fell\ninto the hidden token prompt and died there — a site built with crofty had to\nleave crofty to be published.\n\nRead the token from CROFTY_CLOUDFLARE_API_TOKEN when it is set. It wins over\nthe keychain, and it lasts exactly one\n[…]\nOKEN is not read. It is usually set for another\ntool, and honouring it would quietly deploy to that tool's account.\n\nWith no variable set, the keychain and TTY paths are untouched.\n\namenbo-task: #2181",
"is_bot": false,
"headline": "feat(deploy): take the Cloudflare token from CROFTY_CLOUDFLARE_API_TOKEN",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-26T05:34:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c7095d359148266a1fae4d2aac55f00b08fed48b",
"body": "…ive path\n\nThe body zip line cd'd into $WINBODY inside a subshell and then wrote to\n\"$OUT/crofty-body-windows-amd64.zip\" — but $OUT is the relative dist/installers\nthe workflow passes in, so after the cd zip resolved it under $WINBODY and failed\nwith \"No such file or directory\". The macOS body above\n[…]\natching tar -czf's create-fresh above.\n\namenbo-task: #1941\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01MG3Ug4Cp6rL43dWAgnUiX4",
"is_bot": false,
"headline": "fix(release): build the Windows update-body zip without a stray relat…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-21T10:40:14Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ab6d9b5857540f8eb41ba29dd9b9c59298d842ce",
"body": "D-339's #1932 taught release-installers.sh to upload the bodies `crofty update`\nself-fetches (crofty-body-darwin-universal.tar.gz, crofty-body-windows-amd64.zip\nand their crofty-body-checksums.txt), but left release.yml attesting only the two\nclick installers. wharfy attests what it uploads itself a\n[…]\none that now carries build provenance.\n\namenbo-task: #1940\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01MG3Ug4Cp6rL43dWAgnUiX4",
"is_bot": false,
"headline": "fix(release): attest the update payloads release-installers.sh uploads",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-21T10:34:32Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "78100eba8d5ec20221b69a8fe2695b7a6b1850ba",
"body": "With `crofty update` in place, the surroundings still described the old\nmanual-only world (D-339 phase 4). Bring them in line:\n\n- The upgrade nudge (maybeNotifyUpdate) and the `crofty agent` line now say\n `crofty update` on the routes that can self-update, and keep the manual,\n route-back way (D-3\n[…]\n cover the route→self-update decision.\n\namenbo-task: #1935\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CXVFmvXRWX2j99Hj23No38",
"is_bot": false,
"headline": "feat(update): point the nudge, docs and doctor at `crofty update`",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-21T10:26:24Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "7ecd535296db47edec9bfe8d937ce7d62699b62e",
"body": "The Windows click-installer route (routeWindowsClick) could not self-update yet:\n3a handed it back the installer hint. Wire it into `crofty update` now. The body\nships as a flat zip (crofty.exe beside hugo.exe, as the NSIS installer lays it in\n%LOCALAPPDATA%\\crofty\\bin), so update fetches crofty-bod\n[…]\nase carrying the Windows body payload.\n\namenbo-task: #1934\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CXVFmvXRWX2j99Hj23No38",
"is_bot": false,
"headline": "feat(update): let `crofty update` swap a running Windows .exe",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-21T10:19:53Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "536ca94c439ce90ca88cfa89869cd2707da50bdc",
"body": "D-339 gives crofty a way to update itself so the AI driving it (or the author)\ncan run one command instead of re-downloading an installer. `crofty update`\nreads the install route from the classifier the upgrade nudge already uses —\nnow shared as classifyInstall — and self-updates the two routes that\n[…]\nording follow in the integration task.\n\namenbo-task: #1933\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CXVFmvXRWX2j99Hj23No38",
"is_bot": false,
"headline": "feat(update): add `crofty update`, which self-fetches and swaps the body",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-21T10:10:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8754278f306b1761a0371d8dc6f31f466952c265",
"body": "D-339 has `crofty update` swap only the body in the user's home, so it needs\nthat body to download — the same tree the installers drop, not the installer\nitself (re-running it would need root and re-trip Gatekeeper). release-\ninstallers.sh now emits, beside the .pkg and .exe, one payload per bundled\n[…]\ns binary archive — no body of its own.\n\namenbo-task: #1932\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_018nqcFNjDQogNgjNpXNZ6XR",
"is_bot": false,
"headline": "feat(release): publish the body crofty update self-fetches",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-21T09:40:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ff850cd83cb22a784a63f09c98395941d491be40",
"body": "The .pkg put crofty and its bundled Hugo under /usr/local — root-owned, so\nevery update needed root again and re-tripped Gatekeeper. Split the install\nin two (D-339): the postinstall stages the body under /usr/local/libexec,\nthen moves it into ~/Library/Application Support/crofty (crofty under bin/,\n[…]\nr,\nso its entry/body split is a no-op.\n\namenbo-task: #1931\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_018nqcFNjDQogNgjNpXNZ6XR",
"is_bot": false,
"headline": "feat(pkg): install the macOS body into the user's home, link it on PATH",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-21T09:34:28Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "264cdd69bdf263184ab611761df19e1b03737205",
"body": "…or Hugo\n\nA click install (D-339) keeps crofty's body in a user-writable place and\nleaves a link for it on PATH. os.Executable() on macOS reports that link,\nnot the file behind it, so crofty searched the shared system dir the link\nlives in and could pick up the wrong Hugo — or miss the bundled one.\n\n[…]\nough to PATH,\nso neither path changes.\n\namenbo-task: #1930\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_011HyatJ3h7iuC8fC6t1aaw2",
"is_bot": false,
"headline": "fix(hugobin): follow the entry link to the real body before looking f…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-21T09:08:41Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "137d4bd1148772df3ae041a90bd1b29f11290d12",
"body": "…ssing\n\nA worker whose environment variables were never set deploys perfectly and\nthen fails one route at a time. Nothing in the terminal said anything was\nwrong, so the failure surfaced far from the deploy that caused it — the\nhardest kind to trace back.\n\nThe author can now declare the names in dep\n[…]\nten into a file meant to be committed.\n\namenbo-task: #1902\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_018cmRK4yngLFc76WqWSeRyC",
"is_bot": false,
"headline": "feat(deploy): name the variables a worker needs, and say which are mi…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T14:35:36Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "54f394e5d58d369937d1b8049cf47756ca1d8f81",
"body": "…ource\n\nA top-level functions/ in the build was judged by name alone and skipped\nwhole. That is right for Pages Functions source, which reaches the build\nthrough static/ and must never be served. It is wrong for an ordinary\ncontent section named functions/ — a function reference, a feature list —\nwh\n[…]\nhere\"; they now ask the same\nquestion.\n\namenbo-task: #1907\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_018cmRK4yngLFc76WqWSeRyC",
"is_bot": false,
"headline": "fix(deploy): tell a functions/ content section apart from Functions s…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T14:01:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1692a9125e7d078bb0deea49d6a3a076b9de8942",
"body": "…g for them\n\nA worker runs against a Workers runtime, and until now crofty carried the\nworker without carrying that answer. Undeclared, Cloudflare falls back to the\nPages project's setting, and to the oldest runtime if there is none — so a\nworker written this year could quietly execute on a runtime \n[…]\ning else has already happened.\n\nThe config field is a nested `worker` object rather than a flat key, since\nthe next declaration to live there (required env names) is already known.\n\namenbo-task: #1901",
"is_bot": false,
"headline": "feat(deploy): let the author pin the worker's runtime, and pin nothin…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T13:43:09Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "845d00410e9924812326670cfde734efc3a79bb5",
"body": "… one\n\nA site with a `_worker.js` could not use `crofty deploy` at all: the gate\nstopped it rather than take the endpoint offline, which was right, and left\nthe author deploying their static site through a second toolchain, which was\nthe cost. Now a `_worker.js` at the project root travels — as the \n[…]\nps the deploy, and a root part\nfound in the build (via static/) now says where it belongs instead of being\nignored — a deploy that ignores the author's worker looks like it worked.\n\namenbo-task: #1900",
"is_bot": false,
"headline": "feat(deploy): carry a finished worker, instead of refusing to go near…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T13:37:07Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a1fc5377be23e19778da31d07ed631d274b07bad",
"body": "…name\n\nThe gate that keeps a deploy from taking live routes offline asked one\nquestion: does the project root hold a functions/ directory or a\n_worker.js. That answer was hard-coded in the common layer, so every new\nprovider or new artifact meant editing the gate and re-deciding the same\nthing.\n\nThe\n[…]\n a project with Functions still exits non-zero\nbefore it builds or authenticates, --static-only still goes through, and\n`crofty config --json` reports the same pagesFunctions list.\n\namenbo-task: #1898",
"is_bot": false,
"headline": "feat(deploy): stop on what the destination can't carry, not on a file…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T13:15:59Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c64e037d64dff1b2f031f2adb8833b87ca10dd04",
"body": "Deployer.Deploy took one directory, which fixed \"the site\" as \"whatever\nHugo wrote into dist/\". Anything a site needs that lives elsewhere had no\nway in, and the sorting of the special files was buried inside the\nCloudflare implementation.\n\nDeploy now takes a bundle: the assets plus the parts found \n[…]\nld leave behind instead of guessing.\n\nNothing observable changes: the same files go to Cloudflare, SFTP and\nFTPS, and the plain hosts warn about inert edge files exactly as before.\n\namenbo-task: #1897",
"is_bot": false,
"headline": "refactor(deploy): send a bundle, not a directory",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T13:08:31Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d42d7a7b49c0a4151649738f3f6ac788675825db",
"body": "crofty never updates itself, so every upgrade begins as a decision the\nauthor makes. \"A newer version is available\" gives them nothing to make it\non — least of all when the change is a distribution route going away.\n\nThe nudge now carries https://crofty.site/releases/: the human line on\nstderr, the \n[…]\n` text line, and a releaseNotesURL field in\n--json, so an AI driving crofty can tell the author what an upgrade brings.\nThe field is present only when there is an upgrade to weigh.\n\namenbo-task: #1872",
"is_bot": false,
"headline": "feat(update): say what changed, not just that something did",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T09:14:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2e2771d5cb7961172df1006349670519e889b00f",
"body": "wharfy.yaml explained the retired homebrew/scoop and apt/rpm channels by\nsaying `crofty update` walks the stragglers out. There is no such\nsubcommand — the work is done by the update notifier, which prints a\nroute-specific line at the end of a run. An AI reading this file would\nhave built on a command that does not exist.\n\namenbo-task: #1874",
"is_bot": false,
"headline": "docs(release): stop pointing at an `update` command crofty does not have",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T09:14:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "32dabcbcfd64748b65d07df103bc3f1f772b7874",
"body": "Both macOS install routes put crofty in /usr/local/bin, so the path alone\ncould not tell them apart and everyone got the install.sh hint. That asks\nsomeone who installed by double-clicking to open a terminal, and it strands\nthe Hugo the .pkg placed in /usr/local/libexec/crofty — install.sh replaces\n\n[…]\nne thing that separates the two routes, so\nhugobin.Bundled now answers that question and upgradeHintFor takes the\nanswer as an argument, leaving the classification a pure function.\n\namenbo-task: #1871",
"is_bot": false,
"headline": "fix(update): send .pkg users back to the .pkg, not to curl | sudo sh",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T09:14:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c93691d208c8ac6f3a15acdef49f666b2d5b9b07",
"body": "…#25)\n\nBumps the actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/setup-go](https://github.com/actions/setup-go) and [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).\n\n\nUpdates `actions/checkout` from 4 to 7\n-\n[…]\npe: version-update:semver-major\n dependency-group: actions\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
"is_bot": true,
"headline": "chore(ci): Bump the actions group across 1 directory with 3 updates (…",
"author_name": "dependabot[bot]",
"author_login": "dependabot[bot]",
"committed_at": "2026-07-20T09:13:48Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4fe47d6a790a30a7c0d265ef3e96f2a4e3cf7d23",
"body": "… block dropped it\n\nwharfy 0.23.1 writes a managed block that is only an entrance — deliberately no\npolicy, so a stale copy cannot mislead. Refreshing it took the\n\"merge is not distribution\" paragraph with it, and that rule is exactly what\nrelease.yml and promote.yml now implement, so it is restated\n[…]\nto a registry, and warned attest_unavailable without them.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01F6zrYT5JMC5x5zjjmV8LB6",
"is_bot": false,
"headline": "chore(release): keep the never-auto-distribute rule now that wharfy's…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T08:55:22Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d9c83b4321633f4d3532e67cb8098ae6b180fd57",
"body": "…hips\n\nWithout it wharfy prints the plan and exits 0, so the workflow reported a\nsuccessful promote while the release stayed a prerelease. publish caught it\none step later (prerelease_not_promoted) rather than writing the channels,\nwhich is the whole reason that guard exists — but the promote step should\nnot have looked green.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01F6zrYT5JMC5x5zjjmV8LB6",
"is_bot": false,
"headline": "fix(release): promote needs --yes, or the step is green and nothing s…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T08:52:35Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "001e300cfc94b4dab5108f7959eadd016f1b9f05",
"body": "…ipping\n\ncrofty is open source, so the bytes people install should be built where\nanyone can watch it happen. Releases were cut on a laptop, which also meant\nthey carried no build provenance at all: the attestation is signed with the\nOIDC identity GitHub Actions hands a workflow, so there is nothing\n[…]\npt now takes an outdir to hand CI the files it just built.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01F6zrYT5JMC5x5zjjmV8LB6",
"is_bot": false,
"headline": "feat(release): build what we distribute in public CI, and gate the sh…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T08:38:40Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d0c808db9f4fc5633d3c5be23c68be2a676c3ee4",
"body": "…is run\n\nThe gate that stops a deploy from taking live Functions offline was\ninvisible until you hit it: nothing in `crofty agent` mentioned Functions,\nso the AI driving crofty could only discover the rule by failing.\n\nPut it on all three surfaces an agent reads — the deploy workflow line, a\nnote ex\n[…]\nt breakage the gate exists to prevent.\n\namenbo-task: #1870\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NbkU4ztabxa6KD5BPMhVzm",
"is_bot": false,
"headline": "feat(agent): say that deploy stops on Pages Functions, before deploy …",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T08:22:27Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d40764ca8503b99b4cb30df3152ee11319efe4f8",
"body": null,
"is_bot": false,
"headline": "Merge branch 'main' into task/1869",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T08:19:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "635ec31feb0181ae50f8f1d55a3907fa7cebf048",
"body": "…ffline\n\ncrofty uploads static files only. Publishing over a site whose Pages\nFunctions are serving replaced them and still exited 0 — the breakage\nshowed up later, as enquiries that stopped arriving.\n\nThe old check looked in dist/, where Hugo never puts functions/, so real\nprojects were never warne\n[…]\ns the way to say the loss is intended.\n\namenbo-task: #1869\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NbkU4ztabxa6KD5BPMhVzm",
"is_bot": false,
"headline": "feat(deploy): stop a deploy that would silently take live Functions o…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T08:18:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f1a57d3f76e6c78c0a58faaa37b04cee8ec830ca",
"body": "…ssets\n\nA dist/ with a functions/ dir marked the scan as a Functions build but kept\nwalking into it, and the special-file check only looked at the root, so\nfunctions/api/contact.js sailed through as an ordinary asset. Skip the tree.\n\namenbo-task: #1868",
"is_bot": false,
"headline": "fix(deploy): stop publishing server-side Functions source as static a…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-20T08:16:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9cc1e42486cf1d7a605f66f88bff5d232a80e6f9",
"body": "The install section argued its way out of an apt/yum repo — that a hosted repo\nis only worth having if it is GPG-signed, that signing means handing a third\nparty our private key — for a reader who came here to install crofty. Whichever\nway that argument lands, it does not change what they type next.\n[…]\nnd `brew\nupgrade` will otherwise sit there finding nothing. Its reasoning does not: the\nroutes no longer update, leave, come back.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: stop explaining what crofty no longer ships",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-10T03:23:29Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "da9f32048239112093c5cdb94f82abcad5546551",
"body": "A Windows machine refused both `irm` and `curl`: its TLS stack would not supply\na credential (SEC_E_NO_CREDENTIALS), so the download died before crofty was ever\nreached. Downloading the same zip through a browser worked. What decides the\noutcome is the route, not the installer format — and the one r\n[…]\nre — shortcuts for when they work.\n\ninstall.sh and install.ps1 are generated by wharfy and are not touched here.\n\namenbo-task: #16\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: offer the archive before the one-liner",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-10T03:10:08Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4401ff513d1a7acf3db32246879bcef7642351b2",
"body": "Declining to host a signed repo (D-6) left the packages with no way to\ncarry an upgrade, and dropping hugo's recommends (D-8) left them with\nnothing to pull in. What remained was two artifacts CI never built and no\ndogfood box ever ran — a slower way to copy one binary onto PATH, which is\nall instal\n[…]\nt\n was falling into the .deb branch and being told to reinstall a package\n it never came from. It gets its own hint.\n- uninstalling was apt's job. README says how to do it by hand.\n\namenbo-task: #33",
"is_bot": false,
"headline": "feat: stop shipping a .deb and an .rpm",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:58:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2de69f9ebb0f33f16a67f48a2c0de694a5a00ebe",
"body": null,
"is_bot": false,
"headline": "Merge branch 'main' into task/20",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:52:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3eebbe14b8065e4a6d9ff1a768730f50962fc1a2",
"body": "…t failed\n\nThe update notice told anyone under %LOCALAPPDATA% to re-run\n`irm .../install.ps1 | iex`. On a real Windows box that pipeline died in\nschannel, so every notice sent the author back to the one route already\nknown to fail.\n\nThe click installer and install.ps1 both land in %LOCALAPPDATA%\\cro\n[…]\nl them apart. Name crofty-setup.exe: it overwrites the\nbinary in place whichever way it got there, and it works.\n\namenbo-task: #20\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(update): stop routing Windows updates back through a pipeline tha…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:52:13Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5b791a7a01e985ceb2ea69b9e272dccd735b3384",
"body": "Whether crofty pays Apple or a certificate authority is our arrangement, not\nthe reader's business. That the installers are unsigned, and what the OS will\ndo about it, is the whole of what they need.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: drop the backstage detail from the install warning",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:49:12Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "8b01a2b666d6ceea04308bf17ad3b65e95a13ebe",
"body": "# Conflicts:\n#\tREADME.md",
"is_bot": false,
"headline": "Merge branch 'main' into task/23",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:45:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f8c52b2bb6c783f040a32bc3016a005cf26bac4d",
"body": "apt and dnf both install recommends by default, so the .deb/.rpm pulled in\nwhatever Hugo the distro ships — frequently outdated, frequently the plain\nbuild. The theme's stylesheets are SCSS, and hugobin cannot tell a bad Hugo\non PATH from the one crofty was tested against. A Hugo that installs itsel\n[…]\nackaging now agrees with it.\n\nThe asymmetry the task described (deb recommends, rpm suggests) predates the\nmove to wharfy and was already gone — both channels listed both directives.\n\namenbo-task: #23",
"is_bot": false,
"headline": "fix(packaging): stop recommending a Hugo crofty cannot use",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:44:37Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e5a44cf0c8d45fdfe167513493fe5616f359e407",
"body": "Both channels existed to be the terminal user's route, and to drag Hugo in\nas a package dependency. install.sh / install.ps1 serve the first purpose;\nthe click installers now bundle Hugo, which retires the second. What was\nleft was two tap repos to keep.\n\nThe tap and the bucket freeze rather than di\n[…]\nis deliberate: wharfy has no caveats hook, so\nthe deprecation notice on the last formula has to be written by hand, and\na release with these channels still listed would overwrite it.\n\namenbo-task: #26",
"is_bot": false,
"headline": "feat: stop shipping to Homebrew and Scoop",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:43:05Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "891686a157dcfe97cbac650691028d5d5ac83cf5",
"body": null,
"is_bot": false,
"headline": "Merge branch 'main' into task/29",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:35:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "75246e3bb82e1b40875c22baf20218bc37092299",
"body": "…rocess dies\n\n--timeout was a promise kept in one process's memory: kill the wrapper and\nthe promise went with it, leaving hugo to serve until the machine went\ndown. The deadline itself is written in preview.json, so any later crofty\nrun in the project can enforce it.\n\nfindProject now sweeps an expi\n[…]\nes the wrapper as well. An\nunparseable deadline is treated as none — crofty does not kill on a guess.\nThe sweep reports itself on stderr, since stdout may be JSON someone is\nparsing.\n\namenbo-task: #29",
"is_bot": false,
"headline": "feat(preview): honour the auto-stop deadline even after the timer's p…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:35:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "16b1ac21f3f63a1b85b8a20e114f68b77a25993e",
"body": null,
"is_bot": false,
"headline": "Merge branch 'main' into task/22",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:32:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "57bbb6f6b24c69c370a0d303c3695cfd6104de1e",
"body": "…wed key\n\nThe repos were unsigned, so they made users write trusted=yes / gpgcheck=0 —\nhanding apt the one setting Linux distrusts most. Signing them meant uploading\nour private key to Gemfury, which is how their signing works. Both prices are\ntoo high for a repository whose only job is to save one \n[…]\nassets.\nREADME installs from the file, and the update nudge for a /usr/ binary now says\nto install the new package over the old rather than run apt upgrade, which\nwould never see it.\n\namenbo-task: #22",
"is_bot": false,
"headline": "feat: drop the hosted apt/yum repo instead of signing it with a borro…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:32:40Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b41139b9cbec865ad975d0b70cb692858355cd74",
"body": null,
"is_bot": false,
"headline": "Merge branch 'main' into task/28",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:29:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8852e74b2ab26fcbef44982dcaeab65ee113f3af",
"body": "Liveness asked only whether the `crofty preview` wrapper was alive. Kill\nthat wrapper and hugo keeps serving, while stop, status and the singleton\nreap all agreed nothing was running — and status deleted preview.json,\ndiscarding the one record of the pid that could have ended it. The port\nstayed bus\n[…]\napper\nexits by itself once its hugo is gone.\n\nThis is the orphan half. Nothing yet stops a preview whose wrapper died\nbefore its --timeout: that lands with the deferred sweep in #29.\n\namenbo-task: #28",
"is_bot": false,
"headline": "fix(preview): collect the hugo an abandoned wrapper leaves behind",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:29:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ca34c7832d22475c8904fbc8ed9962631dad6ff0",
"body": "Nothing answered that without writing: to learn the registry was behind a\nwall you had to run init and read the warning it printed afterwards. An\nagent wants to know before it acts.\n\n`crofty config` reports the state directory, who chose it, and whether\ncrofty may write there — probed, not read off \n[…]\nr because doctor grades a built ./dist,\nand the first thing an agent wants to know should not be behind a build.\n\namenbo-task: #25\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: say where crofty's state lives, and whether it may write there",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:26:26Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "09517bdb7f33ce50479eabbddf9823dbb589654b",
"body": null,
"is_bot": false,
"headline": "Merge branch 'main' into task/21",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:16:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a40cf767752e0b45f200cb3a12f3e7c6bcd8f9fc",
"body": "A person who does not open terminals had to read past brew, scoop and a\ncurl|sh pipe before reaching the thing they could actually use. The\ninstallers exist and carry Hugo; the README opened with everything else.\n\nInstall now starts with the .pkg and the .exe, and the terminal routes —\nscripts, Home\n[…]\nwho is not told that reads the refusal as the\nend of the road and turns back. Neither way past needs a terminal.\n\namenbo-task: #21\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: put the click installer first, and say the warning is coming",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:16:36Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8433a73bd0976c745b13afc6eca118f5cca73f23",
"body": null,
"is_bot": false,
"headline": "Merge branch 'main' into task/18",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:15:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "41d79faed96abfb1c620597674b4dcd75885b58a",
"body": "… them\n\ninit met its walls one at a time, in the middle of the work: it prompted for\na title, wrote a site, then failed to register it. The author who granted the\nfirst permission ran it again to find the second.\n\nproject.PreflightInit looks ahead at both — the folder the site goes in, and\nthe folde\n[…]\necond choice no longer claims the site \"is complete\" — the\npreflight offers it before there is a site. Registration never made a site a\nsite, which is the whole point of that choice.\n\namenbo-task: #18",
"is_bot": false,
"headline": "feat: init asks for every permission it needs, before it needs any of…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:15:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c950fba4b7d7bbb63ba506875d53349206edcaba",
"body": "…g shell tricks\n\npreview.json, `preview stop` and `preview status` were all built for a\npreview running in the background, yet the only way to start one was to\noccupy a terminal. Agents filled the gap with `Start-Process` and\n`cmd /c start`, which is where the flaky, platform-specific launches came\n\n[…]\nss probe while our own hugo died in the log, so it has to be ruled\nout where crofty can name it. Output goes to .crofty/preview.log, which\ninit now gitignores alongside preview.json.\n\namenbo-task: #15",
"is_bot": false,
"headline": "feat(preview): background the preview itself, so agents stop inventin…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:13:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "88de44e8997683de00a5d1874ad7826d64ea5d12",
"body": "`crofty init <name>` puts the site under ~/Documents/Crofty, a folder crofty\npicks and the author never named. Two things went wrong there.\n\nDocuments is not always ~/Documents. With OneDrive's Known Folder Move — on\nby default across consumer and managed Windows — it is under OneDrive, and\nthe assu\n[…]\nng, and a refusal is a fork the author picks\nfrom (D-1): grant access, or let crofty write where it may — `crofty init .`\ncosts no permission at all, which is the point of naming it.\n\namenbo-task: #14",
"is_bot": false,
"headline": "feat: ask the filesystem where the site goes, before asking the author",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T22:03:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3c467ae8f113d68654cf299ba1d9f33410b5c4b5",
"body": null,
"is_bot": false,
"headline": "Merge branch 'main' into task/24",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T21:58:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e1ffa9c0c9fb2ab7467829788a8713a2d64edc6d",
"body": "The click installers exist for authors who have no Hugo, so they now carry\none. A person double-clicks, and `crofty build` works — no prerequisite.\n\ncrofty runs the bundled Hugo ahead of anything on PATH. A `hugo` on PATH\nproves nothing: it can predate the frozen theme, it can be the plain build\n(th\n[…]\non and verifies the download against Hugo's published\nchecksums; Hugo ships macOS as a .pkg only, so it unwraps that for the\nuniversal binary. Apache-2.0, so the license rides along.\n\namenbo-task: #24",
"is_bot": false,
"headline": "feat: bundle Hugo in the click installers and prefer it over PATH",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T21:57:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6e89478b0b2f5415d247f2bb129342668b073e84",
"body": "crofty recorded every new project in a registry under the OS config dir, and\nreturned that write's error from init. On a locked-down Windows box the site\nwas written, then init exited with \"Access is denied.\" — so the agent driving\nit read a whole site as a failure and rewrote %APPDATA% to get past.\n[…]\nfolder, so the way past the wall is a door\ncrofty offers rather than one an agent has to invent — say so where the agent\nreads it (`crofty agent`) and where the author does (README).\n\namenbo-task: #13",
"is_bot": false,
"headline": "feat: a site crofty cannot register is still a site",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T21:54:22Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8d0954b56d36e1a017a2c78725f0119e31e68920",
"body": "crofty is usually driven by an AI. When a bare OS permission error came\nback, that agent read it as an obstacle to route around and started\nrewriting the author's environment instead of asking.\n\nAdd internal/access: a Denied error carrying what crofty tried to do, the\npath, the reason, and the choic\n[…]\ne\nfirst call site with real choices (grant access, or --print and paste).\n\nState the norm where an agent will read it: `crofty agent` and the AGENTS.md\ncrofty writes into a new site.\n\namenbo-task: #17",
"is_bot": false,
"headline": "feat: show a permission wall as a choice, not a bare \"Access is denied.\"",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T21:41:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d825f2ef7b28645ef2a890de93852dd12748c606",
"body": "A user who parked the binary at .crofty/bin/crofty.exe found that\n`crofty init .` reported success and wrote no site: the bare presence of\n.crofty/ made the folder look like an existing project, so init fell into\nthe configure path. \"It succeeded but there's nothing here\" is the worst\nanswer we can \n[…]\nf creating a site, and a .crofty/ without a\nconfig.json now reports the half-state — naming the directory and the one\ncommand that resolves it — rather than a bare \"no project here\".\n\namenbo-task: #12",
"is_bot": false,
"headline": "fix: mark a project by .crofty/config.json, not the .crofty/ directory",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T21:29:34Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9c6bac56d41609ec5a8f418ef10aa44f61e954a5",
"body": "The comment column drifted in c91dcfd, which fails the CI gofmt gate.",
"is_bot": false,
"headline": "style: gofmt update_test.go",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-09T21:26:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c91dcfd206022e7f9504c265fdb7f13ba02d02cd",
"body": "- update: upgradeHint recognizes per-user script installs (~/.local,\n %LOCALAPPDATA%) and suggests re-running install.sh / install.ps1\n- packaging: unsigned macOS .pkg (universal, /usr/local/bin) and Windows NSIS\n .exe (%LOCALAPPDATA%\\crofty\\bin + user PATH) — the double-click fallback for\n users\n[…]\ngent can't install over the shell; attached to the GitHub\n release as extra assets via release-installers.sh. Unsigned by choice.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: script-install update hint + unsigned click installers",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-07T20:25:42Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8069917e1aa87aa19a82dc1b1207fbcf0f52366c",
"body": null,
"is_bot": false,
"headline": "ローカルの設定をignore",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-07T03:37:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fd933555cc25310389365cd4a1a0399ceb2ac18d",
"body": "…er (#26)\n\n`crofty preview` wraps a blocking `hugo server`. When an AI backgrounds it to\nkeep working, it loses the chance to stop it, so the server runs forever. Give\npreview a lifecycle the agent (or anyone) can drive, without changing the\nforeground Control-C experience:\n\n- record .crofty/preview\n[…]\nworks too. `crofty agent` now teaches the stop/status/timeout lifecycle, and\ninit's .gitignore ignores the transient preview.json.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(preview): manage the preview server's lifecycle so it can't ling…",
"author_name": "ShiroDoro",
"author_login": "ShiroDoromoto",
"committed_at": "2026-07-07T03:34:50Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "fd0444361e8ddf507e917ba49041c07e115240b9",
"body": "wharfy 0.6.0's `init` adds a \"merge is not distribution\" note to the\nmanaged block: auto-merging dependency bumps is fine, but distribution\nstays an explicit human/AI-gated step (`wharfy release`/`publish`) and\nCI must not run release/publish unattended. This matches the gated\nauto-merge / no-auto-distribute setup landed this cycle (#20, #23).\n\nRegenerated via `wharfy init --yes`; only the managed block changed.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: refresh wharfy managed block (merge ≠ distribution) (#24)",
"author_name": "ShiroDoro",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-28T04:12:23Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "da92cfa926f7fc2cb8bb872d39ad34397132b5d2",
"body": "A solo maintainer who can't review every month would otherwise let\ndependency PRs rot. This enables GitHub's native auto-merge for the\n`low-risk` group (patch/minor only) so those bumps land after ci.yml\npasses — and only land on main, riding the next intentional wharfy\nrelease. Nothing auto-distrib\n[…]\nauto-merge\", set out of band. Uses pull_request_target for a writable\ntoken but never checks out PR code — metadata + gh API only.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "ci: auto-merge low-risk Dependabot bumps behind the gate (#23)",
"author_name": "ShiroDoro",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-28T02:16:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d9bb5d11dbf824526c62b467065bad99e191a16a",
"body": "* ci: add the build/test gate, Hugo-compat lane, and Dependabot\n\nStands up the safety net that dependency upkeep depends on (there was\nno CI before this).\n\n- ci.yml: a `check` job (build/vet/gofmt/test, no Hugo) and a `smoke`\n job that scaffolds a fresh site, builds it with the frozen theme on a\n \n[…]\n → `doctor` reports the output contract is clean.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "ci: add the build/test gate, Hugo-compat lane, and Dependabot (#20)",
"author_name": "ShiroDoro",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-28T02:08:59Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "b6d8d9973aedf874ec9e3b47fdf0f83d51e60bd5",
"body": "\"Support\" reads as donation/fundraising, which can slow a Stripe\nreview of the linked payment page. Use neutral tip wording and keep\ncore from editorializing: i18n label becomes Tip / チップ, and the\ndemo profile message drops 投げ銭 for チップ. No schema or behavior\nchange — the support: block and its providers are untouched.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(theme): label the support link \"Tip\" instead of \"Support\" (#19)",
"author_name": "ShiroDoro",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-28T01:49:51Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "816941942a047f8d482a29ad619ec75f6223dec2",
"body": "Add managed AGENTS.md / CLAUDE.md blocks that point release work at\n`wharfy agent` instead of guessed steps, so the next release goes through\nwharfy. Generated by `wharfy init`; no secrets or project-specific values.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: route releases through wharfy (wharfy init) (#18)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-20T03:59:09Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "6c31356d72e47e4a3daf1b9d4eea4467ee1a51b2",
"body": "The build's .gitignore hint keyed off whether a .gitignore file existed,\nso it missed a repo that has a .gitignore lacking the /.crofty/themes/\nrule — there the theme crofty rewrites every build gets committed and\nchurns history. It now asks git directly (check-ignore / ls-files) and\nclassifies the \n[…]\ns; it never edits .gitignore or touches the index.\n.crofty/config.json stays tracked — the build needs it and it holds no\nsecrets.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: detect when git would commit the regenerated theme cache (#17)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-20T03:21:09Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e656d4793504e8f1262ffc394ed54bb56f50fa18",
"body": "…(#16)\n\n`crofty init` now writes a minimal .gitignore for fresh sites so a `git\ninit` here never commits build output (dist/, public/, resources/) or the\nregenerated theme cache (.crofty/themes/), while keeping\n.crofty/config.json tracked — the build needs it and it holds no secrets.\nAn existing .gi\n[…]\nsting the two lines to\nadd. It only hints — it never writes the file itself, so the author's\nchoice of what to track stays theirs.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: scaffold a minimal .gitignore on init and nudge existing sites …",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-20T03:07:14Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "2f7e6a383a3f02cc1c231ba011416815fb8ea607",
"body": "Lead the Linux section with `curl -fsSL https://crofty.site/install.sh | sh`\n(quickest, installs the latest release), keeping the apt/rpm repos as the\nmanaged-update path. Mirrors the get-started page on crofty.site.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(readme): feature the curl|sh installer for Linux (#15)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-20T01:32:44Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d64466f2c9f1e902328eabe7e1da74c884b4281f",
"body": "wharfy publishes the release with GoReleaser's default checksum name, so the\nasset is `crofty_<version>_checksums.txt`, not a bare `checksums.txt`. Match the\nREADME to what the release actually ships.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(readme): name the versioned checksums file (#14)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-20T01:01:52Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "77a9967549a9d14f69e98351eb98d44ee181831a",
"body": "A crofty site looks like a plain Hugo project from the outside (hugo.yaml,\ncontent/, a theme), so an AI assistant dropped into the folder tends to edit\nlayouts and run `hugo` directly — exactly what crofty owns and overwrites.\nAGENTS.md is the funnel: it points the assistant at `crofty agent` (alway\n[…]\n CREATES the file. An author's own AGENTS.md is never touched —\n crofty advises adding the line instead of editing their content.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: write AGENTS.md so assistants run `crofty agent` first (#12)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-19T18:41:18Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "681064dd6c5f8fc02c65591eea78c6c79bc3a0d0",
"body": "…y (#13)\n\nReplace the hand-maintained .goreleaser.yaml with a small wharfy.yaml and let\nwharfy (which wraps GoReleaser) generate and publish every channel — homebrew,\nscoop, releases, script, goinstall, and apt/rpm via fury.io — at parity with\nthe old setup.\n\n- Version: wharfy builds with -ldflags \"\n[…]\nLinux .deb/.rpm — matching what crofty needs at runtime.\n- .wharfy/ (wharfy's generated config and build artifacts) is gitignored.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "build(release): migrate the release pipeline from GoReleaser to wharf…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-19T18:41:12Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c2961f596f97da50ba61823830aa44913986fd6e",
"body": "…n API (#11)\n\nThe previous approach called the GA4 Admin API (accountSummaries.list) on a 403\nto decide whether the configured property id was wrong, and only then changed the\nguidance. That made the good path depend on a second API being enabled in the\nproject, and had crofty guess the single cause\n[…]\nraw message carried through and the structured --json failure.\nRemoves the now-unused AccountSummaries/GA4Property and their test.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(analytics): name both 403 causes instead of probing the Admi…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-18T02:45:58Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d73635b16fc04e341e17627f3ceb7b9a544f141e",
"body": "…03 (#10)\n\nGA4 returns the same 403 PERMISSION_DENIED whether the configured property\nid doesn't exist and whether the service account simply isn't a member, so\nthe CLI collapsed both into \"add this email as a viewer\" — useless when the\nid is wrong.\n\nOn a 403, query the Admin API accountSummaries.li\n[…]\ngleError, configuredProperty, availableProperties, next } }\npayload (kind = disabled|wrongProperty|forbidden|apiError) for agents.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(analytics): tell a wrong GA4 property id from missing access on 4…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-18T02:35:58Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e2526b972ec84a7bf569c8cef76dafc91642fb97",
"body": "… (#9)\n\n`brew upgrade crofty` only compares against the locally cached tap, so a\njust-published release needs `brew update` first to be seen. Document the\nupdate step for macOS/Windows/Linux (the install section only covered\nfirst-time install).\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(readme): add an Updating section; brew needs `brew update` first…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-17T16:23:53Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "bb6195bb1abc412210c0ebc425dbf4215062d36d",
"body": "…tall at TOFU (#8)\n\nA user reported `crofty deploy` over SFTP stalling at the end on the\ntrust-on-first-use host-key prompt. Two gaps caused it:\n\n- crofty only consulted its own (initially empty) known_hosts store and\n ignored the host the user already trusts in ~/.ssh/known_hosts — so a\n server t\n[…]\nn host key on first use without\nthe prompt. A changed key is still a hard error; non-TTY without --yes\nstill errors with guidance.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(sftp): honor ~/.ssh/known_hosts and add --yes so deploy doesn't s…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-17T16:08:37Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "3c130ddc564c9b0eb884c0aaf48d36fcd777b48d",
"body": "Adds a hosted apt/yum repo (Gemfury, via publishers curl) so Linux gets managed updates, and an update notifier that nudges stale installs toward the right upgrade command. Verified end-to-end.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: hosted apt/yum repo (Gemfury) + update notifier (#7)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-17T14:35:04Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "cbecc7cd53b55994b282c2573137618631f0e8c6",
"body": "…tion (#6)\n\nThe footer credit label is `i18n \"built_with_crofty\"`, and the theme ships\nonly en + ja tables. Hugo's i18n returns \"\" for a missing key, so a site whose\ndefault content language is neither en nor ja (e.g. an fr-only site) rendered\nan empty credit link — <a ...></a>. Add a template fallback so the label is\nalways \"via crofty\" when no translation exists. en/ja sites are unaffected.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(credit): fall back to \"via crofty\" when a language has no transla…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-17T12:36:40Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "ddcbbb6b2bd246d7e17e56eb476e74ece040a180",
"body": "Footer credit (frozen theme + the CLI copy that quotes it):\n- shorten the label to \"via crofty\" (en + ja) — minimal footprint on the\n author's site, and not a copyright claim (© stays the site's own line)\n- open the credit link in a new tab (target=\"_blank\" rel=\"noopener\"); keep\n the referrer so t\n[…]\nolds in pending doc-string tweaks noting deploy supports SFTP/FTPS,\nnot just Cloudflare Pages (deploy/agent command descriptions).\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: refine footer credit label and no-project guidance (#5)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-17T12:16:05Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "451c03e359638a97bee13d3289307a5fa43d52d7",
"body": "…summaries (#4)\n\nThe default reading column was 34rem (~540px) — narrow enough on today's\ndisplays to feel cramped and to wrap the header (long title + nav + language\nswitch) onto several lines. Widen --measure to 46rem so the chrome, prose, and\nrich content (tables, code, diagrams, video) all get r\n[…]\nplaceholder avatar into a dark-mode-aware \"wren\" mark\n- fix raw ``` showing in the abc post intro (bare triple backticks in prose)\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(theme): widen the reading column to 46rem and add optional list …",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-17T11:41:42Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a18f2ca436220ac61b809aa4739949d4e3589d45",
"body": "Add the analytics command to the Commands list and a short paragraph: reads\nyour own GA4 / Search Console data from the CLI, using your own service-account\nkey in the keychain, talking to Google's APIs directly.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(readme): document `crofty analytics` (GA4 + Search Console)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-17T06:05:01Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "f9c8b6ea4ce165f3d8ebcf97d5a4eb020de8c29e",
"body": "…rch Console) (#3)\n\nFold the GA4/Search Console reporting that had been copied across several\nsite repos as byte-identical scripts (bar config) into one built-in\ncommand — removing the duplication and the per-repo Python venvs.\n\nMirrors crofty's no-SDK discipline (CF API direct-HTTP, PR#19): the new\n[…]\ns [] not null.\n\nRegistered in commands() and agentDetails() (agent_test enforces the latter).\ngo test ./... and go vet ./... pass.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(analytics): read your traffic with `crofty analytics` (GA4 + Sea…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-17T02:54:52Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e7345fcb8d6a28d9ba873f87e0cc35ce94042082",
"body": "…ta (#2)\n\nThe footer credit partial read site.Data.crofty, which Hugo deprecated in\nv0.156.0 — every `crofty build` printed a WARN. The rest of the theme already\nreads hugo.Data (profile/patronage/links); this aligns the credit partial with\nthat idiom and silences the warning. Output is unchanged (both resolve the same\ntheme-dir data file).\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(credit): read footer credit via hugo.Data, not deprecated site.Da…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T17:50:42Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "46ec9b7ad45c6bd5d370b74db60752566a8c7dd8",
"body": "…ine (#1)\n\nA free referral, never forced. crofty asks once — neutrally, with no\npreselect — on the first interactive deploy, right before the build that\nrenders the footer, so the very first published site already reflects the\nchoice. A non-interactive deploy (CI / an agent) is never asked and stays\n[…]\non` and `crofty agent` surface the state so an agent can\nread it and relay the choice to the author rather than deciding for them.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(credit): add the optional, removable \"Made with crofty\" footer l…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T17:37:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "bae02fe873d51b8028c0c3dee06baabd5788d9b0",
"body": "… (#81)\n\nUntil now the deploy backend (cloudflare/sftp/ftps) could only be chosen at\n`crofty init`; changing it afterward meant hand-editing\n.crofty/config.json. `crofty connect` now takes the same destination flags\nas init and reconfigures in place:\n\n crofty connect --provider sftp --host h --user\n[…]\nests for switch / field-update / no-op / unknown-provider.\n\nCo-authored-by: Shiro Doromoto <ShiroDoromoto@users.noreply.github.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(deploy): switch deploy backend from the CLI via `crofty connect`…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T14:46:56Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "74fbe290a28488708cdd5f9b23372e8ab64a5b79",
"body": "`crofty connect` (and deploy's reauth path) hard-failed when the freshly\nentered token couldn't manage Pages on the account the site was already\npinned to — printing only \"the token can't manage Pages on account <old\nid>\". The sole escape hatch was rerunning with `--account <id>`, a flag a\nregular u\n[…]\n-pin reuse, explicit-flag precedence, and\nthe menu parser.\n\nCo-authored-by: Shiro Doromoto <ShiroDoromoto@users.noreply.github.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(deploy): let connect switch accounts without --account (#80)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T14:00:47Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "04a8b5ed50b6a49d23e9cc50c5e714233677ba26",
"body": "…g in `crofty agent` (#79)\n\n* feat(agent): surface multilingual at onboarding in `crofty agent`\n\nThe agent brief framed language as singular, so an AI walking the author\nthrough `crofty init` would propose a single language and never mention\nthat crofty is multilingual. Reword the init workflow step\n[…]\ne Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Shiro Doromoto <ShiroDoromoto@users.noreply.github.com>\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(agent): surface multilingual + design customization at onboardin…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T12:53:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1bcbce8d830000d93bf8aed408861e65507fa833",
"body": "Repository ownership is moving to the ShiroDoromoto GitHub account.\nRewrite every in-repo reference accordingly:\n\n- go.mod module path + all internal imports\n- .goreleaser.yaml ldflags version path, scoop/brew tap owners, comments\n- README install commands (brew tap, scoop bucket, releases link)\n- examples blog profile + legal GitHub links\n\nBuilds and `go test ./...` pass after the rename.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: rename owner shirodoromoto -> ShiroDoromoto (#78)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T11:31:31Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "6a9abd1a231ccc510ba5f7066dc845fed1d13744",
"body": "* feat(deploy): add SFTP and FTPS deploy providers\n\nDeploy was hardcoded to Cloudflare Pages. crofty is a worldwide tool, and\nits users split in two: engineers on VPS/cloud (SFTP), and everyone else on\nshared hosting (FTPS). The deploy contract is just \"upload the verified\ndist/ somewhere\", so this \n[…]\nf\n printing success having saved no credentials.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(deploy): add SFTP and FTPS deploy providers (#77)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T07:22:54Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "829f83107f4743203f4573d7994e6235757daa0e",
"body": "Add an nfpms section so each release also produces .deb and .rpm\npackages (amd64/arm64) attached to GitHub Releases. hugo stays a soft\nrecommends/suggests since distro hugo is often outdated or non-extended;\nbuild/preview already error clearly when it is missing. Document the\nLinux install path in the README.\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(release): ship Linux .deb/.rpm packages (#76)",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T05:00:17Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "1a04918a7fbd07fc64763dca1a3268cbdab97033",
"body": "fix(deploy): build the current site before publishing",
"is_bot": false,
"headline": "Merge pull request #75 from shirodoromoto/fix/deploy-builds-first",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T04:32:27Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d27f85da5a425c248c5e6d30f10322a85cdff792",
"body": "`crofty deploy` uploaded whatever was already in ./dist and only errored\nif it was missing — so editing the source and deploying without a fresh\n`crofty build` shipped a STALE build (this actually bit a live site: an\nold CSS file went out after the fix was committed).\n\ndeploy now builds first, so it\n[…]\nd ./dist as-is\" behaviour for callers that built elsewhere\n(e.g. CI). buildSite() is extracted as the shared core of build/deploy.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(deploy): build the current site before publishing",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T04:32:21Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "cf5ed26c1900091a1170eac93ab3aa8b17b56abf",
"body": "…mples\n\nrefactor: fold demo into examples/blog (one gallery, not two concepts)",
"is_bot": false,
"headline": "Merge pull request #74 from shirodoromoto/refactor/fold-demo-into-exa…",
"author_name": "Shiro Doromoto",
"author_login": "ShiroDoromoto",
"committed_at": "2026-06-16T03:53:57Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 23,
"commits_last_year": 257,
"latest_release_at": "2026-07-26T08:33:12Z",
"latest_release_tag": "v0.23.0",
"releases_from_tags": false,
"days_since_last_push": 2,
"active_weeks_last_year": 6,
"days_since_latest_release": 2,
"mean_days_between_releases": 3.1
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 42,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/ShiroDoromoto/crofty",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/ShiroDoromoto/crofty",
"is_deprecated": false,
"latest_version": "v0.23.0",
"repository_url": "https://github.com/ShiroDoromoto/crofty",
"versions_count": 34,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-07-26T08:28:36Z",
"latest_version_yanked": null,
"days_since_latest_publish": 2
}
]
},
"popularity": {
"forks": 0,
"stars": 0,
"watchers": 0,
"fork_history": {
"days": [],
"complete": true,
"collected": 0,
"total_forks": 0
},
"star_history": {
"days": [],
"complete": true,
"collected": 0,
"total_stars": 0,
"collected_at": null
},
"open_issues_and_prs": 1
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [
"examples"
],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [],
"toolchain_manifests": [
"go.mod"
],
"largest_source_bytes": 33837,
"source_files_sampled": 105,
"oversized_source_files": 0,
"agent_instruction_files": [
"AGENTS.md",
"CLAUDE.md"
],
"agent_instruction_max_bytes": 1532
},
"dependencies": {
"manifests": [
"go.mod"
],
"advisories": {
"error": null,
"scope": null,
"source": null,
"findings": [],
"collected": false,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"go"
],
"dependencies": [
{
"name": "github.com/fclairamb/ftpserverlib",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.32.1"
},
{
"name": "github.com/jlaffaye/ftp",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.2.1"
},
{
"name": "github.com/pkg/sftp",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.13.11"
},
{
"name": "github.com/spf13/afero",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.15.0"
},
{
"name": "github.com/zalando/go-keyring",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.2.8"
},
{
"name": "golang.org/x/crypto",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.54.0"
},
{
"name": "golang.org/x/net",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.57.0"
},
{
"name": "golang.org/x/sys",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.47.0"
},
{
"name": "golang.org/x/term",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v0.45.0"
},
{
"name": "gopkg.in/yaml.v3",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v3.0.1"
},
{
"name": "lukechampine.com/blake3",
"manifest": "go.mod",
"ecosystem": "go",
"version_constraint": "v1.4.1"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 1,
"merged_prs": 26,
"open_issues": 0,
"closed_ratio": null,
"closed_issues": 0,
"closed_unmerged_prs": 1
},
"bus_factor": 1,
"bot_contributors": 1,
"top_contributors": [
{
"type": "User",
"login": "ShiroDoromoto",
"commits": 254,
"avatar_url": "https://avatars.githubusercontent.com/u/8072360?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml",
"dependabot-auto-merge.yml",
"hugo-compat.yml",
"promote.yml",
"release.yml"
],
"has_docs_dir": false,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"go.sum"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": null,
"reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": 10,
"reason": "3 out of 3 merged PRs checked by a CI test -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/27 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 0,
"reason": "project has 0 contributing companies or organizations -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 10,
"reason": "update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 0,
"reason": "project was created within the last 90 days. Please review its contents carefully",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "SAST tool is not run on all commits -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": 0,
"reason": "Project has not signed or included provenance with any releases.",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 9,
"reason": "1 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "31287d6636b571cc20c7f8ad392e278183670998",
"ran_at": "2026-07-28T16:32:53Z",
"aggregate_score": 4.3,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": true
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-27T09:34:36Z",
"oldest_open_prs": [
{
"number": 27,
"created_at": "2026-07-26T08:31:23Z",
"last_comment_at": null,
"last_comment_author": null
}
],
"last_merged_pr_at": "2026-07-26T08:32:19Z",
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/ShiroDoromoto/crofty",
"host": "github.com",
"name": "crofty",
"owner": "ShiroDoromoto"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 53,
"inputs": {
"security": 43,
"vitality": 71,
"community": 24,
"governance": 51,
"engineering": 71
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 71,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 58,
"inputs": {
"commits_last_year": 257,
"human_commit_share": 0.97,
"days_since_last_push": 2,
"active_weeks_last_year": 6
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 2 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 2
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "6/52 weeks with commits",
"points": 4.2,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 6
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "257 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 257
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"releases_count": 23,
"latest_release_tag": "v0.23.0",
"releases_from_tags": false,
"days_since_latest_release": 2,
"mean_days_between_releases": 3.1
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "23 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 23
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 2 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 2
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~3.1 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 3.1
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "unverified",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": "repository_too_young",
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": null,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "maintenance record not established from the collected data",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_unverified",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "critical",
"name": "Community & Adoption",
"value": 24,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 1,
"inputs": {
"forks": 0,
"stars": 0,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "0 stars",
"points": 0,
"status": "missed",
"details": [
{
"code": "stars",
"params": {
"count": 0
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "0 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 0
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (AGPL-3.0)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "AGPL-3.0"
}
}
],
"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": 51,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 10,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "moderate",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): Issue resolution. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"issue_resolution"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 69,
"inputs": {
"merged_prs": 26,
"open_issues": 0,
"closed_issues": 0,
"issue_closed_ratio": null,
"closed_unmerged_prs": 1
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "no issues or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_issues_or_data",
"params": {}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "26/27 decided PRs merged",
"points": 36.8,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 26,
"decided": 27
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/27 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 44,
"inputs": {
"followers": 4,
"owner_type": "User",
"is_verified": null,
"owner_login": "ShiroDoromoto",
"public_repos": 14,
"account_age_days": 4406
},
"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": "4 followers of ShiroDoromoto",
"points": 5,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 4,
"login": "ShiroDoromoto"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "14 public repos, account ~12 yr old",
"points": 20.6,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 14
}
},
{
"code": "account_age_years",
"params": {
"years": 12
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"github.com/ShiroDoromoto/crofty"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 2
},
"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 2 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 2
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "34 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 34
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "good",
"name": "Engineering Quality",
"value": 71,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "moderate",
"name": "Engineering practices",
"note": null,
"notes": [],
"value": 68,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "5 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 5
}
}
],
"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": "3 out of 3 merged PRs checked by a CI test -- score normalized to 10",
"points": 20,
"status": "met",
"details": [],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "good",
"name": "Documentation",
"note": null,
"notes": [],
"value": 75,
"inputs": {
"topics": [
"blogging",
"cli",
"hugo",
"indieweb",
"local-first",
"markdown",
"posse",
"static-site",
"website"
],
"has_wiki": true,
"homepage": "https://crofty.site",
"has_readme": true,
"has_docs_dir": false,
"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": 0,
"status": "missed",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": "https://crofty.site",
"points": 15,
"status": "met",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": "9 topics",
"points": 10,
"status": "met",
"details": [
{
"code": "topics_count",
"params": {
"count": 9
}
}
],
"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": 43,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "at_risk",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): Branch-Protection. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"branch_protection"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 43,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 17,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 1,
"scorecard_aggregate": 4.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": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "3 out of 3 merged PRs checked by a CI test -- score normalized to 10",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/27 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "update tool detected",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "SAST tool is not run on all commits -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "1 existing vulnerabilities detected",
"points": 6.8,
"status": "partial",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 2
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "good",
"name": "AI Readiness",
"value": 76,
"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.897,
"agent_instruction_files": [
"AGENTS.md",
"CLAUDE.md"
],
"agent_instruction_max_bytes": 1532
},
"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": "87 of 97 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 87,
"sampled": 97
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "good",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 74,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"go.sum"
],
"has_dockerfile": false,
"typed_language": true,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [],
"agent_commit_share": 0.57,
"toolchain_manifests": [
"go.mod"
],
"dependency_bot_commit_share": 0.03
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "go.mod (toolchain convention, no task runner)",
"points": 12.6,
"status": "partial",
"details": [
{
"code": "toolchain_convention",
"params": {
"files": "go.mod"
}
}
],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "Go (statically typed)",
"points": 11,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "57 of the last 100 commits agent-authored or agent-credited",
"points": 10,
"status": "met",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 57,
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "3 of the last 100 commits are automated dependency updates",
"points": 8,
"status": "met",
"details": [
{
"code": "dependency_bot_commits",
"params": {
"count": 3,
"sampled": 100
}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 33837,
"source_files_sampled": 105,
"oversized_source_files": 0
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Go (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "0/105 source files over 60KB",
"points": 55,
"status": "met",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 105,
"oversized": 0
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "at_risk",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"example_dirs": [
"examples"
],
"has_mcp_signal": false,
"api_schema_files": []
},
"components": [
{
"key": "api_schema_openapi_graphql_proto",
"name": "API schema (OpenAPI/GraphQL/proto)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 40
},
{
"key": "mcp_server",
"name": "MCP server",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "runnable_examples",
"name": "Runnable examples",
"detail": "examples",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "examples"
}
}
],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
],
"report_type": "repository",
"generated_at": "2026-07-28T16:33:03.195433Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/s/ShiroDoromoto/crofty.svg",
"full_name": "ShiroDoromoto/crofty",
"license_state": "standard",
"license_spdx": "AGPL-3.0"
}