Payload
{
"action": "completed",
"workflow_run": {
"id": 29766818147,
"name": "Update Snapshots",
"node_id": "WFR_kwLOSB6EzM8AAAAG7j2ZYw",
"head_branch": "main",
"head_sha": "54b52a4d80cbfb34502b9fa372be24be74942149",
"path": ".github/workflows/update-snapshots.yaml",
"display_title": "fix: clear `rebuildStatus` on onboarding reset to prevent stale projection skipping build step",
"run_number": 344,
"event": "issue_comment",
"status": "completed",
"conclusion": "skipped",
"workflow_id": 295060443,
"check_suite_id": 80609837062,
"check_suite_node_id": "CS_kwDOSB6EzM8AAAASxLiABg",
"url": "https://api.github.com/repos/darkmatter/nixmac/actions/runs/29766818147",
"html_url": "https://github.com/darkmatter/nixmac/actions/runs/29766818147",
"pull_requests": [],
"created_at": "2026-07-20T18:13:16Z",
"updated_at": "2026-07-20T18:13:17Z",
"actor": {
"login": "darkmatter[bot]",
"id": 283346107,
"node_id": "BOT_kgDOEOOEuw",
"avatar_url": "https://avatars.githubusercontent.com/in/3663660?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter%5Bbot%5D",
"html_url": "https://github.com/apps/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter%5Bbot%5D/followers",
"following_url": "https://api.github.com/users/darkmatter%5Bbot%5D/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter%5Bbot%5D/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter%5Bbot%5D/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter%5Bbot%5D/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter%5Bbot%5D/orgs",
"repos_url": "https://api.github.com/users/darkmatter%5Bbot%5D/repos",
"events_url": "https://api.github.com/users/darkmatter%5Bbot%5D/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter%5Bbot%5D/received_events",
"type": "Bot",
"user_view_type": "public",
"site_admin": false
},
"run_attempt": 1,
"referenced_workflows": [],
"run_started_at": "2026-07-20T18:13:16Z",
"triggering_actor": {
"login": "darkmatter[bot]",
"id": 283346107,
"node_id": "BOT_kgDOEOOEuw",
"avatar_url": "https://avatars.githubusercontent.com/in/3663660?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter%5Bbot%5D",
"html_url": "https://github.com/apps/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter%5Bbot%5D/followers",
"following_url": "https://api.github.com/users/darkmatter%5Bbot%5D/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter%5Bbot%5D/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter%5Bbot%5D/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter%5Bbot%5D/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter%5Bbot%5D/orgs",
"repos_url": "https://api.github.com/users/darkmatter%5Bbot%5D/repos",
"events_url": "https://api.github.com/users/darkmatter%5Bbot%5D/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter%5Bbot%5D/received_events",
"type": "Bot",
"user_view_type": "public",
"site_admin": false
},
"jobs_url": "https://api.github.com/repos/darkmatter/nixmac/actions/runs/29766818147/jobs",
"logs_url": "https://api.github.com/repos/darkmatter/nixmac/actions/runs/29766818147/logs",
"check_suite_url": "https://api.github.com/repos/darkmatter/nixmac/check-suites/80609837062",
"artifacts_url": "https://api.github.com/repos/darkmatter/nixmac/actions/runs/29766818147/artifacts",
"cancel_url": "https://api.github.com/repos/darkmatter/nixmac/actions/runs/29766818147/cancel",
"rerun_url": "https://api.github.com/repos/darkmatter/nixmac/actions/runs/29766818147/rerun",
"previous_attempt_url": null,
"workflow_url": "https://api.github.com/repos/darkmatter/nixmac/actions/workflows/295060443",
"head_commit": {
"id": "54b52a4d80cbfb34502b9fa372be24be74942149",
"tree_id": "6967dcca39e2ded158a9f19a353e216912fac1a0",
"message": "Evolve view: stream responses and build output live (#561)\n\n* feat(evolve): stream dry-run build check output as events\n\ndry_run_build_check_streaming mirrors run_build_step's piped-stdio\nreader threads: lines from both streams are pumped into ~120ms batches\nand forwarded to a callback, and cancellation is polled between batches\nso a cancelled evolution kills the child instead of waiting minutes for\na doomed evaluation. The build_check tool uses it when the loop\nprovides an output sink (ToolCtx.on_build_output), emitting each batch\nas a buildCheck event carrying a BuildOutput { chunk } detail — raw\nholds the chunk, so the Console mirror and session transcripts capture\nthe log. The blocking variant stays for the rollback preflight.\n\nPart of the evolve view redesign (PR 6 of\ndocs/2026-07-15-evolve-view-implementation-plan.md).\n\n* feat(evolve): show streamed build output under the active row\n\nStreamed buildCheck chunks never render as timeline rows; instead the\nsticky active row expands with a monospace, tail-following log area\n(capped at 500 lines) under the 'Checking the configuration builds...'\nheadline while the check runs. Once any other event follows —\nbuildPass/buildFail — the log collapses and the outcome row takes over\nas usual.\n\nPart of the evolve view redesign (PR 6 of\ndocs/2026-07-15-evolve-view-implementation-plan.md).\n\n* fix(evolve): anchor oversized build_fail output on the error line\n\nraw and the Build detail head-truncated the captured output at 6000\nchars, so when nix prints pages of evaluation/progress chatter before\nthe failure the error itself got cut off — only the model-facing path\nwas tail-anchored. Keep from the last 'error:' line onward (tail\nfallback) before truncating, and prefer the colon-anchored match in\nfirst_error_line so file paths mentioning 'error' can't fake the\nsummary.\n\n* fix(evolve): run the streamed dry-run build check verbosely\n\nAt default verbosity 'nix build --dry-run' prints nothing until\nevaluation finishes, so the streamed build check had nothing to emit\nduring exactly the phase it was meant to make feel alive — the log\ntail only filled in at the end. Pass --verbose so nix emits\n'evaluating file/derivation ...' lines throughout evaluation. The\nblocking variant (rollback preflight) stays quiet; oversized failure\noutput stays readable because build_fail now anchors on the error\nline.\n\n* feat(evolve): streaming completion scaffold behind a dev flag\n\nAdds the plumbing for provider token streaming (design §4.2 Stage 3b)\nwithout changing behavior yet: an experimental_streaming_evolve\npreference with a Developer-tab switch, a StreamDelta event\ntype/detail for streamed assistant-text slices (raw carries the delta\nfor the Console and transcripts), a completion_streaming trait method\nwhose default delegates to the blocking call (the CLI provider can\nnever stream — its stdout is the parsed payload — and §7 gives it no\nfiller), and the loop wiring: a 120ms DeltaBatcher coalesces deltas\ninto StreamDelta events, flushed when the response lands, with the\nexisting 100ms cancellation race unchanged (dropping the future\ncancels mid-stream).\n\nPart of the evolve view redesign (PR 7 of\ndocs/2026-07-15-evolve-view-implementation-plan.md).\n\n* feat(evolve): stream completions from OpenAI-compatible providers\n\ncompletion_streaming uses create_stream with\nstream_options.include_usage: content deltas are forwarded to the\ncaller as they arrive and accumulated into the final message,\ntool-call argument fragments are assembled by chunk index (id/name\nfrom the first chunk, arguments appended across chunks), and token\nusage comes from the stream's final empty-choices chunk so accounting\nmatches the blocking path. Mid-stream errors normalize through the\nsame ProviderError mapping. Covers OpenAI, OpenRouter,\nOpenAI-compatible, and nixmac hosted inference, which all share this\nprovider.\n\nPart of the evolve view redesign (PR 7 of\ndocs/2026-07-15-evolve-view-implementation-plan.md).\n\n* feat(evolve): stream completions from Ollama\n\ncompletion_streaming posts with stream:true and reads the NDJSON\nresponse line by line: content deltas go to the caller as they\narrive, tool calls and the final done-chunk eval counters are\nassembled into the same response shape the blocking path returns. The\nblocking path's retry semantics carry over — HTTP 500 tool-call parse\nerrors and empty assistant responses retry once with guidance, and\nmid-stream {\"error\": ...} lines are recognized including the\nparse-error retry case.\n\nPart of the evolve view redesign (PR 7 of\ndocs/2026-07-15-evolve-view-implementation-plan.md).\n\n* feat(evolve): type the streamed response into the active row\n\nStreamed streamDelta slices never render as timeline rows; while a\nresponse streams, the active row becomes a 'Thinking...' row after the\nlast completed action (which keeps its own row), typing the\naccumulated text as quiet clamped detail — clipped to a ~4-line tail,\nsince the full text lands as a Narration row or the terminal summary\nwhen the response completes and supersedes the stream.\n\nPart of the evolve view redesign (PR 7 of\ndocs/2026-07-15-evolve-view-implementation-plan.md).\n\n* feat(evolve): stream tool-call reasoning, not just assistant prose\n\nLive runs showed why streaming looked dead: across 9 model calls a\nreal evolution produced only 2 assistant-content deltas — the model\nspends nearly all its tokens on tool-call arguments (its reasoning\ngoes through the think tool), which streamed invisibly. Surface them:\na ThoughtExtractor incrementally decodes the think tool's thought\nstring from streamed JSON argument fragments (escape- and\nboundary-safe, property-tested across every split point), and other\ntool calls announce themselves ('→ edit_nix_file') as their names\narrive. Ollama sends tool calls whole, so it emits the thought text\ndirectly. The active row's detail keeps line breaks\n(whitespace-pre-line) so announcements read as their own lines.\n\nPart of the evolve view redesign (PR 7 of\ndocs/2026-07-15-evolve-view-implementation-plan.md).\n\n* fix(evolve): announce streamed tool calls in the timeline's voice\n\nThe stream announced raw tool names ('→ edit_nix_file'), which reads\nas machinery. Translate them with the same copy the timeline's\ntool_call rows use, minus the object since the arguments carrying it\nare still streaming: '→ Editing configuration...', '→ Searching\npackages...', '→ Checking the configuration builds...'. Shared by\nboth streaming providers.\n\n* fix(evolve): collapse blank lines in the streamed thinking tail\n\nTool announcements carry surrounding newlines and thoughts end in\nwhatever the model wrote, so steps were separated by empty lines.\nNormalize the assembled tail for display — collapse blank lines and\ndrop a leading one — so it reads as a tight step list. The raw stream\nin the Console and transcripts is untouched.\n\n* fix(evolve): decode Ollama NDJSON from raw bytes\n\nThe streaming path decoded each HTTP body chunk independently with\nfrom_utf8_lossy, but transport chunk boundaries are arbitrary — a\nmultibyte character split across packets became two replacement\ncharacters, corrupting streamed prose and, worse, tool-call arguments\n(a path like café.nix could assemble wrong). Buffer raw bytes in an\nextracted NdjsonBuffer and decode only complete newline-terminated\nrecords, keeping the streaming cadence. Tested across every possible\nchunk boundary of a multibyte record, plus multi-record chunks,\nrecord-spanning chunks, unterminated tails, and blank lines.\n\nAddresses finding 1 of docs/2026-07-18-evolve-streaming-review.md.\n\n* fix(evolve): decode surrogate pairs in streamed thoughts\n\nNon-BMP characters arrive in JSON as UTF-16 surrogate pairs\n(\\uD83D\\uDE00); char::from_u32 rejects the halves individually, so\nemoji silently vanished from the streamed thought display. Combine a\nhigh surrogate with its following low escape, holding across fragment\nboundaries only while the buffered bytes could still be an escape\nprefix — a lone surrogate is dropped as before. Property-tested across\nevery split point plus the lone-surrogate case.\n\nAddresses finding 5 of docs/2026-07-18-evolve-streaming-review.md.\n\n* feat(evolve): reset the streamed tail when a provider retries\n\nWhen Ollama retried mid-stream, the abandoned attempt's deltas stayed\nin the visible tail and the retry concatenated onto them. The delta\ncallback now carries a StreamEvent (Delta or Reset): every Ollama\nretry path signals Reset — the batcher drops its pending buffer and\nemits a hidden streamReset marker the tail scanner stops at — followed\nby a visible '→ Response interrupted; retrying...' line so the pause\nand the cleared text read as intentional. Console and transcripts keep\nthe discarded attempt plus the labeled marker for diagnostics.\n\nAddresses finding 2 and the retry-visibility item of\ndocs/2026-07-18-evolve-streaming-review.md.\n\n* fix(evolve): anchor the active-step timer to semantic events\n\nThe step timer re-anchored on every event, and streamed chunks arrive\nevery ~120ms — so during exactly the long waits it exists to measure\n(model responses, build checks) it sat pinned at 0s. Anchor it to\nsemantic events only (everything except streamDelta/buildCheck chunks)\nwhile the header's elapsed clock keeps its per-event anchor, whose math\ndepends on the latest event's backend timestamp. Covered by a\nfake-timer test streaming a chunk mid-wait.\n\nAddresses finding 3 of docs/2026-07-18-evolve-streaming-review.md.\n\n* perf(evolve): coalesce stream chunks in the viewmodel\n\nEvery ~120ms chunk appended a new event to evolveEvents, so a long\nverbose build or multi-iteration stream retained thousands of hidden\nevents, each append copying the array and every render re-scanning it.\nConsecutive chunks of the same stream (streamDelta text, buildCheck\noutput) now merge into one event capped to a display-sized tail;\nsemantic events — including the streamReset markers that bound the\nvisible tail — still append as-is. The Console keeps receiving each\nraw chunk, and the backend-side transcript is unaffected.\n\nAddresses finding 4 (frontend half) of\ndocs/2026-07-18-evolve-streaming-review.md.\n\n* fix(evolve): serialize session transcript appends\n\nEach transcript line was written from its own spawned task, so\nhigh-frequency stream events could land out of order — and the final\n'result' line, written directly, could land before queued event lines\ndrained. All appends now flow through a single lazily-spawned writer\ntask that drains an ordered queue; the prompt/result writes in\nrun_evolve use the same queue so relative order holds end to end.\nCovered by a 50-line ordering test.\n\nAddresses finding 4 (transcript half) of\ndocs/2026-07-18-evolve-streaming-review.md.\n\n* refactor(evolve): single source for tool action labels\n\ntool_call_announcement duplicated the tool→label mapping inside\nEvolveEvent::tool_call, one list per file, kept aligned only by a\ntest. types::tool_action_label now owns the generic action label; the\ntool_call summary enriches it with the object argument when present\nand falls back to it otherwise, and the stream announcement wraps it\nin its arrow line.\n\nAddresses the tool-presentation item of\ndocs/2026-07-18-evolve-streaming-review.md.\n\n* feat(evolve): pause build-log tail-follow while scrolled up\n\nThe log scrolled to the bottom on every chunk, so scrolling up to\ninspect an earlier error was immediately undone. Tail-following now\npauses while the user is away from the bottom and resumes once they\nscroll back near it — the same near-bottom rule the outer timeline\nuses.\n\nAddresses the build-log interaction item of\ndocs/2026-07-18-evolve-streaming-review.md.\n\n* feat(evolve): fall back to blocking completion when streaming is rejected\n\nSome OpenAI-compatible endpoints reject stream requests or\nstream_options; that failed the whole evolution the moment the dev\nflag was on. When a streamed call errors before producing any output,\nretry the same call through the blocking path and disable streaming\nfor the rest of the run — a stream that already produced output failed\nfor real and keeps its error. Also warn when a streamed completion\nreturns no usage, since that silently weakens the session token budget\n(the iteration guard still applies).\n\nAddresses the unsupported-provider fallback item of\ndocs/2026-07-18-evolve-streaming-review.md.\n\n* docs(evolve): record resolutions in the streaming review\n\nEvery finding was verified and fixed (one commit per item, referenced\ninline); the reuse/UX suggestions are either addressed, deferred with\nreasons, or rejected with evidence.\n\n* fix(evolve): re-anchor the header clock on event identity\n\nEvent coalescing replaces the trailing stream event in place — same\narray length, newer backend timestamp — so the length-keyed arrival\nanchor missed the replacement and the header combined the newer\ntimestamp with the full wait since the first coalesced chunk, drifting\nfast during sustained streaming. Anchor on the last event's identity\ninstead: replacements re-arm it, untouched arrays don't. Regression\ntest replaces the last event at constant length and asserts no double\ncount.\n\nAddresses finding 1 of\ndocs/2026-07-18-evolve-streaming-post-review-assessment.md.\n\n* fix(evolve): gate the blocking fallback to genuine streaming rejections\n\nThe fallback retried every pre-delta failure: auth errors, rate\nlimits, transport failures — which the blocking path hits identically,\ndelaying the real error and potentially doubling a billable request —\nand even the CLI provider, whose default completion_streaming IS the\nblocking call, so a failed invocation ran twice. The loop now takes\nthe streaming path only for providers that declare supports_streaming\n(OpenAI-compatible and Ollama), and retries blocking only when the\nerror is rejection-shaped (400/404/405/415/422/501) — the statuses an\nendpoint that doesn't understand stream/stream_options produces. The\nmissing-usage warning is gated the same way.\n\nAddresses finding 2 of\ndocs/2026-07-18-evolve-streaming-post-review-assessment.md.\n\n* fix(evolve): show the retry notice immediately, not on the next flush\n\nThe 'Response interrupted; retrying...' delta went through the 120ms\nbatcher, so when the previous flush was recent it stayed buffered\nuntil the retry's first delta arrived — invisible during exactly the\npause it explains. Reset is now the whole semantic operation: the\nbatcher clears, emits the hidden boundary marker, and emits the\nvisible explanation directly, bypassing the throttle; providers just\nsignal Reset.\n\nAddresses finding 3 of\ndocs/2026-07-18-evolve-streaming-post-review-assessment.md.\n\n* fix(evolve): flush the transcript queue before run_evolve returns\n\nThe queued result line was fire-and-forget: run_evolve returned (and\nthe app could exit) before queued lines reached disk, losing the tail\nof the transcript. The writer queue now accepts a barrier item\nacknowledged after everything enqueued before it has been written, and\nrun_evolve awaits it at every exit — success, failure, and cancel —\nrestoring a durability point at the command boundary. The ordering\ntest now asserts against the barrier instead of polling.\n\nAddresses finding 4 of\ndocs/2026-07-18-evolve-streaming-post-review-assessment.md.\n\n* docs(evolve): record resolutions in the post-review assessment\n\nAll four findings verified and fixed, one commit per finding,\nreferenced inline with the reasoning where the fix deviates from the\nrecommendation.\n\n* fix(evolve): classify streaming rejections from structured provider errors\n\nThe status-based classification was wrong in both directions: 400/404\nalso mean context-window or model-not-found failures (which the\nblocking retry would just repeat, possibly billably), and\nclassify_openai_error maps unrecognized symbolic codes to 500, so a\ngenuine stream_options rejection could never match the 4xx list at\nall. Replace it with a dedicated ProviderError::StreamingUnsupported\nvariant produced at the provider boundary, only when the structured\nApiError names stream/stream_options (param or message) or says\nstreaming is unsupported — checked at both the request and the\nmid-stream error sites, since some proxies accept the request and\nreject streaming in an SSE error payload. Tests cover the rejection\nshapes, context-window/model-not-found/validation non-rejections,\ntransport errors, and the CLI provider staying off the streaming path.\n\nAddresses the reopened finding 2 of\ndocs/2026-07-18-evolve-streaming-post-review-assessment.md.\n\n* docs(evolve): record the second-pass resolution for finding 2\n\n* fix(evolve): classify streaming errors from SSE payloads\n\n* refactor(evolve): collapse the announcement wrapper into an emit helper\n\ntool_call_announcement had become a two-line wrapper over\ntool_action_label, leaving two near-identically-named label functions\nand Option-plumbing repeated at both provider call sites. Replace it\nwith announce_tool_call, which looks up the shared label, formats the\narrow line, and emits it — one function owns the copy\n(types::tool_action_label), one owns delivery, and the call sites\nbecome one-liners. The pinning test now exercises the emitted stream.\n\n* refactor(evolve): single-exit transcript teardown in run_evolve\n\nflush_ordered + set_session_path(None) were repeated at three exit\npaths, each of which had to remember them — a future early return\nwould silently drop the durability point. run_evolve is now a thin\nwrapper around run_evolve_session with a single exit: the body may\nreturn early freely, and the flush and session teardown happen exactly\nonce on the way out.",
"timestamp": "2026-07-20T17:25:56Z",
"author": {
"name": "Juanpe Bolívar",
"email": "raskolnikov@gnu.org"
},
"committer": {
"name": "GitHub",
"email": "noreply@github.com"
}
},
"repository": {
"id": 1209959628,
"node_id": "R_kgDOSB6EzA",
"name": "nixmac",
"full_name": "darkmatter/nixmac",
"private": false,
"owner": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter",
"html_url": "https://github.com/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter/followers",
"following_url": "https://api.github.com/users/darkmatter/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter/orgs",
"repos_url": "https://api.github.com/users/darkmatter/repos",
"events_url": "https://api.github.com/users/darkmatter/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/darkmatter/nixmac",
"description": "Home manager and nix-darwin that understands plain English",
"fork": false,
"url": "https://api.github.com/repos/darkmatter/nixmac",
"forks_url": "https://api.github.com/repos/darkmatter/nixmac/forks",
"keys_url": "https://api.github.com/repos/darkmatter/nixmac/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/darkmatter/nixmac/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/darkmatter/nixmac/teams",
"hooks_url": "https://api.github.com/repos/darkmatter/nixmac/hooks",
"issue_events_url": "https://api.github.com/repos/darkmatter/nixmac/issues/events{/number}",
"events_url": "https://api.github.com/repos/darkmatter/nixmac/events",
"assignees_url": "https://api.github.com/repos/darkmatter/nixmac/assignees{/user}",
"branches_url": "https://api.github.com/repos/darkmatter/nixmac/branches{/branch}",
"tags_url": "https://api.github.com/repos/darkmatter/nixmac/tags",
"blobs_url": "https://api.github.com/repos/darkmatter/nixmac/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/darkmatter/nixmac/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/darkmatter/nixmac/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/darkmatter/nixmac/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/darkmatter/nixmac/statuses/{sha}",
"languages_url": "https://api.github.com/repos/darkmatter/nixmac/languages",
"stargazers_url": "https://api.github.com/repos/darkmatter/nixmac/stargazers",
"contributors_url": "https://api.github.com/repos/darkmatter/nixmac/contributors",
"subscribers_url": "https://api.github.com/repos/darkmatter/nixmac/subscribers",
"subscription_url": "https://api.github.com/repos/darkmatter/nixmac/subscription",
"commits_url": "https://api.github.com/repos/darkmatter/nixmac/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/darkmatter/nixmac/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/darkmatter/nixmac/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/darkmatter/nixmac/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/darkmatter/nixmac/contents/{+path}",
"compare_url": "https://api.github.com/repos/darkmatter/nixmac/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/darkmatter/nixmac/merges",
"archive_url": "https://api.github.com/repos/darkmatter/nixmac/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/darkmatter/nixmac/downloads",
"issues_url": "https://api.github.com/repos/darkmatter/nixmac/issues{/number}",
"pulls_url": "https://api.github.com/repos/darkmatter/nixmac/pulls{/number}",
"milestones_url": "https://api.github.com/repos/darkmatter/nixmac/milestones{/number}",
"notifications_url": "https://api.github.com/repos/darkmatter/nixmac/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/darkmatter/nixmac/labels{/name}",
"releases_url": "https://api.github.com/repos/darkmatter/nixmac/releases{/id}",
"deployments_url": "https://api.github.com/repos/darkmatter/nixmac/deployments"
},
"head_repository": {
"id": 1209959628,
"node_id": "R_kgDOSB6EzA",
"name": "nixmac",
"full_name": "darkmatter/nixmac",
"private": false,
"owner": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter",
"html_url": "https://github.com/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter/followers",
"following_url": "https://api.github.com/users/darkmatter/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter/orgs",
"repos_url": "https://api.github.com/users/darkmatter/repos",
"events_url": "https://api.github.com/users/darkmatter/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/darkmatter/nixmac",
"description": "Home manager and nix-darwin that understands plain English",
"fork": false,
"url": "https://api.github.com/repos/darkmatter/nixmac",
"forks_url": "https://api.github.com/repos/darkmatter/nixmac/forks",
"keys_url": "https://api.github.com/repos/darkmatter/nixmac/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/darkmatter/nixmac/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/darkmatter/nixmac/teams",
"hooks_url": "https://api.github.com/repos/darkmatter/nixmac/hooks",
"issue_events_url": "https://api.github.com/repos/darkmatter/nixmac/issues/events{/number}",
"events_url": "https://api.github.com/repos/darkmatter/nixmac/events",
"assignees_url": "https://api.github.com/repos/darkmatter/nixmac/assignees{/user}",
"branches_url": "https://api.github.com/repos/darkmatter/nixmac/branches{/branch}",
"tags_url": "https://api.github.com/repos/darkmatter/nixmac/tags",
"blobs_url": "https://api.github.com/repos/darkmatter/nixmac/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/darkmatter/nixmac/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/darkmatter/nixmac/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/darkmatter/nixmac/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/darkmatter/nixmac/statuses/{sha}",
"languages_url": "https://api.github.com/repos/darkmatter/nixmac/languages",
"stargazers_url": "https://api.github.com/repos/darkmatter/nixmac/stargazers",
"contributors_url": "https://api.github.com/repos/darkmatter/nixmac/contributors",
"subscribers_url": "https://api.github.com/repos/darkmatter/nixmac/subscribers",
"subscription_url": "https://api.github.com/repos/darkmatter/nixmac/subscription",
"commits_url": "https://api.github.com/repos/darkmatter/nixmac/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/darkmatter/nixmac/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/darkmatter/nixmac/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/darkmatter/nixmac/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/darkmatter/nixmac/contents/{+path}",
"compare_url": "https://api.github.com/repos/darkmatter/nixmac/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/darkmatter/nixmac/merges",
"archive_url": "https://api.github.com/repos/darkmatter/nixmac/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/darkmatter/nixmac/downloads",
"issues_url": "https://api.github.com/repos/darkmatter/nixmac/issues{/number}",
"pulls_url": "https://api.github.com/repos/darkmatter/nixmac/pulls{/number}",
"milestones_url": "https://api.github.com/repos/darkmatter/nixmac/milestones{/number}",
"notifications_url": "https://api.github.com/repos/darkmatter/nixmac/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/darkmatter/nixmac/labels{/name}",
"releases_url": "https://api.github.com/repos/darkmatter/nixmac/releases{/id}",
"deployments_url": "https://api.github.com/repos/darkmatter/nixmac/deployments"
}
},
"workflow": {
"id": 295060443,
"node_id": "W_kwDOSB6EzM4RlkPb",
"name": "Update Snapshots",
"path": ".github/workflows/update-snapshots.yaml",
"state": "active",
"created_at": "2026-06-12T23:28:36.000Z",
"updated_at": "2026-06-12T23:28:36.000Z",
"url": "https://api.github.com/repos/darkmatter/nixmac/actions/workflows/295060443",
"html_url": "https://github.com/darkmatter/nixmac/blob/main/.github/workflows/update-snapshots.yaml",
"badge_url": "https://github.com/darkmatter/nixmac/workflows/Update%20Snapshots/badge.svg"
},
"repository": {
"id": 1209959628,
"node_id": "R_kgDOSB6EzA",
"name": "nixmac",
"full_name": "darkmatter/nixmac",
"private": false,
"owner": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter",
"html_url": "https://github.com/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter/followers",
"following_url": "https://api.github.com/users/darkmatter/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter/orgs",
"repos_url": "https://api.github.com/users/darkmatter/repos",
"events_url": "https://api.github.com/users/darkmatter/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/darkmatter/nixmac",
"description": "Home manager and nix-darwin that understands plain English",
"fork": false,
"url": "https://api.github.com/repos/darkmatter/nixmac",
"forks_url": "https://api.github.com/repos/darkmatter/nixmac/forks",
"keys_url": "https://api.github.com/repos/darkmatter/nixmac/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/darkmatter/nixmac/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/darkmatter/nixmac/teams",
"hooks_url": "https://api.github.com/repos/darkmatter/nixmac/hooks",
"issue_events_url": "https://api.github.com/repos/darkmatter/nixmac/issues/events{/number}",
"events_url": "https://api.github.com/repos/darkmatter/nixmac/events",
"assignees_url": "https://api.github.com/repos/darkmatter/nixmac/assignees{/user}",
"branches_url": "https://api.github.com/repos/darkmatter/nixmac/branches{/branch}",
"tags_url": "https://api.github.com/repos/darkmatter/nixmac/tags",
"blobs_url": "https://api.github.com/repos/darkmatter/nixmac/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/darkmatter/nixmac/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/darkmatter/nixmac/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/darkmatter/nixmac/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/darkmatter/nixmac/statuses/{sha}",
"languages_url": "https://api.github.com/repos/darkmatter/nixmac/languages",
"stargazers_url": "https://api.github.com/repos/darkmatter/nixmac/stargazers",
"contributors_url": "https://api.github.com/repos/darkmatter/nixmac/contributors",
"subscribers_url": "https://api.github.com/repos/darkmatter/nixmac/subscribers",
"subscription_url": "https://api.github.com/repos/darkmatter/nixmac/subscription",
"commits_url": "https://api.github.com/repos/darkmatter/nixmac/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/darkmatter/nixmac/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/darkmatter/nixmac/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/darkmatter/nixmac/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/darkmatter/nixmac/contents/{+path}",
"compare_url": "https://api.github.com/repos/darkmatter/nixmac/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/darkmatter/nixmac/merges",
"archive_url": "https://api.github.com/repos/darkmatter/nixmac/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/darkmatter/nixmac/downloads",
"issues_url": "https://api.github.com/repos/darkmatter/nixmac/issues{/number}",
"pulls_url": "https://api.github.com/repos/darkmatter/nixmac/pulls{/number}",
"milestones_url": "https://api.github.com/repos/darkmatter/nixmac/milestones{/number}",
"notifications_url": "https://api.github.com/repos/darkmatter/nixmac/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/darkmatter/nixmac/labels{/name}",
"releases_url": "https://api.github.com/repos/darkmatter/nixmac/releases{/id}",
"deployments_url": "https://api.github.com/repos/darkmatter/nixmac/deployments",
"created_at": "2026-04-14T00:37:13Z",
"updated_at": "2026-07-20T17:31:39Z",
"pushed_at": "2026-07-20T18:07:44Z",
"git_url": "git://github.com/darkmatter/nixmac.git",
"ssh_url": "org-17834193@github.com:darkmatter/nixmac.git",
"clone_url": "https://github.com/darkmatter/nixmac.git",
"svn_url": "https://github.com/darkmatter/nixmac",
"homepage": "https://nixmac.com",
"size": 689249,
"stargazers_count": 21,
"watchers_count": 21,
"language": "Rust",
"has_issues": true,
"has_projects": false,
"has_downloads": true,
"has_wiki": false,
"has_pages": true,
"has_discussions": true,
"forks_count": 2,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 98,
"license": {
"key": "mit",
"name": "MIT License",
"spdx_id": "MIT",
"url": "https://api.github.com/licenses/mit",
"node_id": "MDc6TGljZW5zZTEz"
},
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"has_pull_requests": true,
"pull_request_creation_policy": "all",
"topics": [
"home-manager",
"nix",
"nix-darwin",
"nix-flake",
"opencode"
],
"visibility": "public",
"forks": 2,
"open_issues": 98,
"watchers": 21,
"default_branch": "main",
"custom_properties": {}
},
"organization": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"url": "https://api.github.com/orgs/darkmatter",
"repos_url": "https://api.github.com/orgs/darkmatter/repos",
"events_url": "https://api.github.com/orgs/darkmatter/events",
"hooks_url": "https://api.github.com/orgs/darkmatter/hooks",
"issues_url": "https://api.github.com/orgs/darkmatter/issues",
"members_url": "https://api.github.com/orgs/darkmatter/members{/member}",
"public_members_url": "https://api.github.com/orgs/darkmatter/public_members{/member}",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"description": ""
},
"enterprise": {
"id": 469843,
"slug": "darkmatter",
"name": "darkmatter",
"node_id": "E_kgDOAAcrUw",
"avatar_url": "https://avatars.githubusercontent.com/b/469843?v=4",
"description": "",
"website_url": "darkmatter.io",
"html_url": "https://github.com/enterprises/darkmatter",
"created_at": "2025-09-07T16:01:00Z",
"updated_at": "2026-07-07T15:59:26Z"
},
"sender": {
"login": "darkmatter[bot]",
"id": 283346107,
"node_id": "BOT_kgDOEOOEuw",
"avatar_url": "https://avatars.githubusercontent.com/in/3663660?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter%5Bbot%5D",
"html_url": "https://github.com/apps/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter%5Bbot%5D/followers",
"following_url": "https://api.github.com/users/darkmatter%5Bbot%5D/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter%5Bbot%5D/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter%5Bbot%5D/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter%5Bbot%5D/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter%5Bbot%5D/orgs",
"repos_url": "https://api.github.com/users/darkmatter%5Bbot%5D/repos",
"events_url": "https://api.github.com/users/darkmatter%5Bbot%5D/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter%5Bbot%5D/received_events",
"type": "Bot",
"user_view_type": "public",
"site_admin": false
},
"installation": {
"id": 131074261,
"node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMTMxMDc0MjYx"
}
}