Informe JSON sin procesar legible por máquina
{
"data": {
"repo": {
"topics": [
"ruby",
"library",
"gem",
"gui",
"gui-toolkit",
"cpp",
"physics"
],
"is_fork": false,
"size_kb": 1712,
"has_wiki": true,
"homepage": null,
"languages": {
"C++": 636980,
"Ruby": 137234,
"Objective-C": 94737
},
"pushed_at": "2026-08-04T11:20:53Z",
"created_at": "2015-03-15T16:21:57Z",
"owner_type": "User",
"updated_at": "2026-08-04T11:20:44Z",
"description": "A Graphical User Interface Tool Kit.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "master",
"license_spdx_raw": "MIT",
"primary_language": "C++",
"significant_languages": [
"C++",
"Ruby",
"Objective-C"
]
},
"owner": {
"blog": "https://xord.org/",
"name": "xord.org",
"type": "User",
"login": "xord",
"company": null,
"location": null,
"followers": 11,
"avatar_url": "https://avatars.githubusercontent.com/u/776014?v=4",
"created_at": "2011-05-09T02:59:15Z",
"is_verified": null,
"public_repos": 27,
"account_age_days": 5566
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.6.0",
"kind": "minor",
"published_at": "2026-08-04T11:28:58Z"
},
{
"tag": "v0.5.3",
"kind": "patch",
"published_at": "2026-06-23T07:18:30Z"
},
{
"tag": "v0.5.2",
"kind": "patch",
"published_at": "2026-06-23T06:40:30Z"
},
{
"tag": "v0.5.1",
"kind": "patch",
"published_at": "2026-06-23T05:30:45Z"
},
{
"tag": "v0.5.0",
"kind": "minor",
"published_at": "2026-06-22T17:53:23Z"
},
{
"tag": "v0.4.2",
"kind": "patch",
"published_at": "2026-06-12T02:03:18Z"
},
{
"tag": "v0.4.1",
"kind": "patch",
"published_at": "2026-05-20T06:59:10Z"
},
{
"tag": "v0.4.0",
"kind": "minor",
"published_at": "2026-05-16T17:53:12Z"
},
{
"tag": "v0.3.15",
"kind": "patch",
"published_at": "2026-05-09T18:04:31Z"
},
{
"tag": "v0.3.14",
"kind": "patch",
"published_at": "2026-04-17T13:57:49Z"
},
{
"tag": "v0.3.13",
"kind": "patch",
"published_at": "2026-04-10T01:49:41Z"
},
{
"tag": "v0.3.12",
"kind": "patch",
"published_at": "2026-04-09T15:44:39Z"
},
{
"tag": "v0.3.11",
"kind": "patch",
"published_at": "2026-04-09T09:28:11Z"
},
{
"tag": "v0.3.10",
"kind": "patch",
"published_at": "2025-07-05T15:48:25Z"
},
{
"tag": "v0.3.9",
"kind": "patch",
"published_at": "2025-05-22T07:57:43Z"
},
{
"tag": "v0.3.8.1",
"kind": "other",
"published_at": "2025-05-12T17:18:02Z"
},
{
"tag": "v0.3.8",
"kind": "patch",
"published_at": "2025-05-11T18:11:30Z"
},
{
"tag": "v0.3.7",
"kind": "patch",
"published_at": "2025-05-10T17:54:11Z"
},
{
"tag": "v0.3.6",
"kind": "patch",
"published_at": "2025-04-08T15:12:51Z"
},
{
"tag": "v0.3.5",
"kind": "patch",
"published_at": "2025-03-23T18:04:20Z"
},
{
"tag": "v0.3.4",
"kind": "patch",
"published_at": "2025-03-06T17:00:48Z"
},
{
"tag": "v0.3.3",
"kind": "patch",
"published_at": "2025-01-22T18:20:23Z"
},
{
"tag": "v0.3.2",
"kind": "patch",
"published_at": "2025-01-13T18:08:54Z"
},
{
"tag": "v0.3.1",
"kind": "patch",
"published_at": "2025-01-12T18:56:28Z"
},
{
"tag": "v0.3",
"kind": "other",
"published_at": "2024-07-05T18:20:33Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2024-07-05T16:18:13Z"
},
{
"tag": "v0.2",
"kind": "other",
"published_at": "2024-03-13T17:05:44Z"
},
{
"tag": "v0.1.57",
"kind": "patch",
"published_at": "2024-02-06T17:22:14Z"
},
{
"tag": "v0.1.56",
"kind": "patch",
"published_at": "2024-01-07T16:03:01Z"
},
{
"tag": "v0.1.55",
"kind": "patch",
"published_at": "2023-12-09T15:06:12Z"
},
{
"tag": "v0.1.54",
"kind": "patch",
"published_at": "2023-11-08T15:59:09Z"
},
{
"tag": "v0.1.53",
"kind": "patch",
"published_at": "2023-10-28T17:31:04Z"
},
{
"tag": "v0.1.52",
"kind": "patch",
"published_at": "2023-10-24T15:50:39Z"
},
{
"tag": "v0.1.51",
"kind": "patch",
"published_at": "2023-07-30T04:43:42Z"
},
{
"tag": "v0.1.50",
"kind": "patch",
"published_at": "2023-07-30T04:18:03Z"
},
{
"tag": "v0.1.49",
"kind": "patch",
"published_at": "2023-07-10T17:38:58Z"
},
{
"tag": "v0.1.48",
"kind": "patch",
"published_at": "2023-07-10T04:45:08Z"
},
{
"tag": "v0.1.47",
"kind": "patch",
"published_at": "2023-06-26T15:49:47Z"
},
{
"tag": "v0.1.46",
"kind": "patch",
"published_at": "2023-06-22T06:50:16Z"
},
{
"tag": "v0.1.45",
"kind": "patch",
"published_at": "2023-06-11T10:00:31Z"
},
{
"tag": "v0.1.44",
"kind": "patch",
"published_at": "2023-06-08T16:41:51Z"
},
{
"tag": "v0.1.43",
"kind": "patch",
"published_at": "2023-06-07T01:51:50Z"
},
{
"tag": "v0.1.42",
"kind": "patch",
"published_at": "2023-06-02T07:27:51Z"
},
{
"tag": "v0.1.41",
"kind": "patch",
"published_at": "2023-05-29T07:42:25Z"
},
{
"tag": "v0.1.40",
"kind": "patch",
"published_at": "2023-05-27T14:31:36Z"
},
{
"tag": "v0.1.39",
"kind": "patch",
"published_at": "2023-05-17T17:07:24Z"
},
{
"tag": "v0.1.38",
"kind": "patch",
"published_at": "2023-05-12T18:03:42Z"
},
{
"tag": "v0.1.37",
"kind": "patch",
"published_at": "2023-05-11T13:32:04Z"
},
{
"tag": "v0.1.36",
"kind": "patch",
"published_at": "2023-05-08T04:18:55Z"
},
{
"tag": "v0.1.35",
"kind": "patch",
"published_at": "2023-04-30T05:38:45Z"
},
{
"tag": "v0.1.34",
"kind": "patch",
"published_at": "2023-04-24T15:59:14Z"
},
{
"tag": "v0.1.33",
"kind": "patch",
"published_at": "2023-04-21T18:01:36Z"
},
{
"tag": "v0.1.32",
"kind": "patch",
"published_at": "2023-03-01T12:49:17Z"
}
],
"recent_commits": [
{
"oid": "2bb778ac8a02ab48a86b1b7c1ea60d8551055a4d",
"body": "Highlights:\n- reflex-terminal: Initial release\n- reflex: Add Menu class backed by native OS menus\n- reflex: Add view constraints backed by Box2D joints\n (cascades to rubysketch)\n- reflex: Add Clipboard class\n- [BREAKING] reflex: Read modifiers as symbols from every event\n- [BREAKING] rays: Default \n[…]\n under them\non a bundle update.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[B1967D45-63AE-4117-A695-92D22FA40125]]",
"is_bot": false,
"headline": "Update changes for the menu, constraint and reflex-terminal release",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-08-04T10:47:53Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "3beb7341129f1afdd67e15264e6227cb6385aee1",
"body": "A view that owns something running -- a timer, an animation, a device -- had\nno way to stop it when its window stopped taking input. Window kept the state\ninternally and Window_get_active() read it, but nothing was exposed and\nnothing reached the views.\n\non_activate and on_deactivate are sent on att\n[…]\nvery other\nevent already works.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[9446AA56-E0AC-4D17-86FB-42F7120AE7A7]]",
"is_bot": false,
"headline": "reflex: Tell a view when its window becomes the active one",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-08-04T04:44:26Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4ba7ab31bb55e3ed027dd3c40345f267535e718d",
"body": "Each module keeps a Types namespace and imports the Types of every module\nit stands on. Before, a module wanting the vocabulary of the one below had\nto copy the whole list of using declarations.\n\nWhat belongs in Types is whatever the namespace needs declared for its\nvocabulary to read as its own, wh\n[…]\nants them says so.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[CCECA64E-F813-4130-9EB9-83D674A9F39A]]",
"is_bot": false,
"headline": "Let a module hand its types down to the one built on it",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-08-02T06:56:05Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a1d5513f7dc70d9781c9d4fa1cab4768e781ae0e",
"body": "Caps lock, num lock and scroll lock are states the keyboard is left in\nrather than keys held down for a stroke, and the platforms disagree on\nwhether to mention them at all: sdl reports all three, macos two of them,\nwin32 none. Anything matching a shortcut against modifiers therefore stops\nworking o\n[…]\nmodifiers\ntoday has to change.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[13C9D9A8-3509-4A68-8B18-962A742B237A]]",
"is_bot": false,
"headline": "reflex: Let modifiers be read without the locking states",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-08-01T07:44:31Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4e216976832781fead0931706c9a47a496af2ddb",
"body": "Menu kept its own list of the five it accepts, written out again beside the\none every event already reads from. Three copies of that table had just gone\nwrong once, losing MOD_SCROLL from all of them, so the subset now says only\nwhich of the whole it leaves out and takes the values from there.\n\nThe \n[…]\n other is what brought it out.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[53A6E1CE-8AA2-468A-BE18-FB5C6860D52F]]",
"is_bot": false,
"headline": "reflex: Derive the menu shortcut modifiers from the table the events use",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-31T18:29:31Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "93260b4cdaa4c3b21004110fd88ef9f2f732f06f",
"body": "…rries them\n\nKeyEvent had answered with symbols since it gained a bit flag reader, while\nPointer and WheelEvent still handed back the raw bits. The same idea reading\ntwo ways is a trap for anyone moving between them, and Pointer already spoke\nsymbols for its types, so it disagreed with itself.\n\nThe \n[…]\n has to ask the array instead.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[EC7F487E-97CB-466A-866B-29BBCC867D70]]",
"is_bot": false,
"headline": "reflex: [BREAKING] Read modifiers as symbols from every event that ca…",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-31T17:49:46Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "092e2aa85673936cddd93ca3a7ef16c760775da8",
"body": "lib depends on vendor, so building libghostty-vt from source was counted as\npart of reflex-terminal's own compile and there was no telling the two apart\nin the log. Running vendor first leaves lib measuring what it says it does.\n\nNo verbose on it: git clone and zig build report themselves, so there \n[…]\nfor it to unquiet.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[BD5C409F-A48E-4ECE-BDF2-5D2B8514B9C1]]",
"is_bot": false,
"headline": "Give the vendored libraries a CI step of their own",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-31T17:08:07Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e1508d4fb81653bd6cb90486db84878a15735974",
"body": "Define only singleton methods since the OS has a single clipboard, and\nmake Clipboard.new raise as Screen does.\n\nPass rb_utf8_encoding() explicitly when building the returned string.\nRucy defaults to rb_default_internal_encoding(), which is usually NULL\nand would hand back an ASCII-8BIT string for n\n[…]\not tell an empty clipboard\nfrom one holding an empty string.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01B5Jiy9Zx2rfGTSS9N5xJCA",
"is_bot": false,
"headline": "reflex: Expose Clipboard to Ruby",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-31T16:30:43Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ab12655dd6770ee3b6f363a067a16aa1f8b1f36c",
"body": "Hold the contents as a value object and get/set them all at once, since\nevery platform API works as a single transaction of \"clear everything,\nwrite every format, commit\". Setting one format at a time would either\nwipe the others or require a racy read-modify-write.\n\nKey the contents by MIME type in\n[…]\nnd normalize line\nendings on Windows so Ruby always sees LF.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01B5Jiy9Zx2rfGTSS9N5xJCA",
"is_bot": false,
"headline": "reflex: Add native Clipboard class",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-31T16:10:15Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c6265cef682f3da7130e4f9e963a8d115e327d79",
"body": "The module workflows are shared, so this names the one module that needs a\nzig outright rather than reaching for a mechanism that would keep the name\nout of them: the alternative hooked into the step every workflow runs, which\nwould have pulled a toolchain down for tag.yml too, where nothing is buil\n[…]\nersion it carries.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[E5754AE2-E5A5-4C6B-9359-4315538830B9]]",
"is_bot": false,
"headline": "Set up zig in the module workflows for reflex-terminal",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-30T18:58:04Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "bcf9d3b66c9e6296b31a417b5fd7eeaeb4779032",
"body": "A laptop keyboard has no keypad, so macos reports fn+return as 0x34, a code\nwith no kVK_* name of its own and no entry in KeyCode. It reached ruby as a\nkey of nil, where the enter on an external keyboard's keypad reaches it as\n:enter.\n\nNormalizing at the event boundary rather than adding a KeyCode o\n[…]\n for one scancode.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[9E55CF3C-0B43-4908-AC5E-8059754BB96F]]",
"is_bot": false,
"headline": "reflex: Report fn+return as the keypad enter on macos",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-30T16:33:56Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e76d7c4786597f1d43ded67048a7a3cb65aa2c8f",
"body": "…operators\n\nKeyCode's NATIVE_VK(darwin, win32, hid) macro left the whole OEM punctuation\nrow (MINUS through RBRACKET) and the numpad operator keys unassigned on\nwindows, falling back to unimplemented sentinels. Both are standard,\nunambiguous VK_OEM_* / VK_ADD-family codes per Microsoft's virtual-key\n[…]\n sequence from -2.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[A1D96E4E-E9A7-4352-9B3A-F6DA355810E1]]",
"is_bot": false,
"headline": "reflex: Fill in windows virtual-key codes for punctuation and numpad …",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-30T11:09:43Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "795c9cf4875cec29dd3f1f61a4318116d8a346b3",
"body": "An empty array reaches value_to() as argc == 0, since the macro-generated\noverload forwards value.size() straight through, and the conversions then\nread *argv anyway. Asserting is not enough for something ruby can trigger,\nand NDEBUG is defined for extension builds, so raise ArgumentError.\n\nThe arra\n[…]\nferencing NULL crashes loudly.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[570948DD-7633-4482-83E4-E6034F205665]]",
"is_bot": false,
"headline": "rays,reflex: Check conversion args instead of asserting",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-28T04:11:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "afd4f23f4c82f1150e6784b9c6b29d44986882b5",
"body": "?: binds looser than |, so the chain of ternaries parsed as one nested\nexpression instead of a bitwise or of eight: every modifier after the\nfirst match ended up in an else branch that was never reached.\n\nCtrl+Shift therefore arrived as shift alone, and holding caps lock hid\nevery other modifier, since caps is tested first.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[C615E272-4FB7-41ED-9535-CFF5A3014BAF]]",
"is_bot": false,
"headline": "reflex: Fix get_modifiers reporting only the first modifier held",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-27T17:40:10Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "a0aaea5c7002bcc113897397497919837befefd0",
"body": "The key was marked as unavailable on macOS, but Carbon does define it as\nkVK_ContextualMenu (0x6E), so it never fired there. Name it after what\nthe key does, matching the W3C UI Events code (\"ContextMenu\") and the\nmacOS name rather than the Windows VK_APPS spelling, which reads like a\nlauncher key.\n\n[…]\nand hid columns are untouched.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01XUpSquSBrAM2sWT7cmmJno\n\n[[AAEA5346-5D4C-4215-A0B5-0FA557E50EE3]]",
"is_bot": false,
"headline": "reflex: Rename KEY_APPS to KEY_CONTEXT_MENU and fix its macOS keycode",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-27T05:49:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5a40006b59ca8cc175831f26bbe6ebda40b0e833",
"body": "…en space\n\nThe clip rect was propagated in parent-local coordinates and handed to\nglScissor, which ignores the painter matrix. Under an ancestor zoom the\ncontent was drawn scaled while the scissor rect stayed unscaled, so only\nthe top-left fraction of each view was visible. Accumulate ancestor zooms\n[…]\nled from such a view on down.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FwftWFXxca9RhxULJEJx6E\n\n\n[[CA84377A-20F5-45B0-9D8F-A41B275B1310]]",
"is_bot": false,
"headline": "reflex: Fix view clipping to track ancestor zoom and position in scre…",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-24T11:51:04Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "86cda097cdd95884b3cb3b2d12ca89d76585d008",
"body": "Rucy::yield wraps rb_yield_values2 with protect(), so a block raising a\nRuby exception unwinds safely instead of longjmp-ing past C++ destructors.\nThis was the only remaining raw rb_yield in the monorepo; every other ext\nalready uses the wrapper.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\n\n[[10EDD7D2-E1DE-458E-9F0C-A4424D461791]]",
"is_bot": false,
"headline": "reflex: Use Rucy::yield instead of raw rb_yield in Menu#each",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-24T11:00:47Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "fdc3d02a4670baa93e81668aa786e799bdda3ee0",
"body": "The event fired when a submenu opens/closes was named on_open_child /\non_close_child, but \"child\" there refers to the submenu (the container),\nwhile add_child / remove_child use \"child\" for an individual item (an\nelement). The same word denoted two different levels, which read as\nconsistent but quie\n[…]\n (element) and \"submenu\"\n(container) stay distinct across the Menu API.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq",
"is_bot": false,
"headline": "reflex: Rename Menu's open/close_child event to open/close_submenu",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-23T05:49:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8f894718ccffd5ed8d79e978deb360930cfa97c3",
"body": "Demonstrate the menu bar, submenus, an item icon, a right-click popup and\nper-item click handlers in one runnable file. win.menu is set only on\nWindows, since macOS shares a single application-wide menu bar.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq",
"is_bot": false,
"headline": "reflex: Add menu sample",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-23T05:49:33Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "173806ae39151817111886d8d0a29a6ad25a8e16",
"body": "A menu item can now carry an icon: menu.image = Reflex::Image shows it\nnatively (NSImage on macOS, HBITMAP on Windows) at the image's own pixel\nsize -- the caller is responsible for sizing.\n\nrays gains Bitmap_get_nsimage / Bitmap_get_hbitmap. reflex only sees rays'\npublic headers, and re-implementin\n[…]\ntly drops\nits (empty) submenu instead of showing a dead title on macOS.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq",
"is_bot": false,
"headline": "reflex, rays: Add image (icon) to Menu items",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-23T05:49:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8135912d3d3000e0abf958e190794cda19dd206b",
"body": "Replace the NSMenu-built standard menu in the app delegate with a plain\nReflex::Menu tree owned by the application. Every standard item carries a\nselector name (about, quit, minimize, ...), so Ruby code can find and\nrearrange them through app.menu. Windows without a menu of their own now\nfall back t\n[…]\nd\n invalidated iterators and threw mid-terminate. It now closes a copy.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq",
"is_bot": false,
"headline": "reflex: Build the standard menu bar with Reflex::Menu on macOS",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-23T05:49:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "788d9b63bbbec2d05e862cbda2a5c9ae01533e4d",
"body": "Give Application a menu attribute as the home for an app-wide menu: the\nplan is to build the standard menu (About/Quit, Window, ...) as a plain\nReflex::Menu tree owned by the application, and to fall back to it when\nthe active window has no menu of its own -- so attaching a window menu no\nlonger cos\n[…]\nu bar lands together with the standard-menu build\nin a following commit.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq",
"is_bot": false,
"headline": "reflex: Add Application#menu",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-23T05:49:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "182eb3f212d3a8f1e0b7c278ba8e119804a88dd1",
"body": "Bring the win32 backend up to par with the macOS one: a menu can be\nattached to a window's menu bar, popup() works, and clicks and open/close\nevents are delivered.\n\nWin32 has no per-item object like NSMenuItem -- an item can only be\naddressed as (HMENU, position) or by command id -- so each node kee\n[…]\nritten and reviewed on macOS,\nwhere the win32 sources are not compiled.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq",
"is_bot": false,
"headline": "reflex: Implement Menu on Windows",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-23T05:49:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "906301b15fa629844483db1f89b48a0fa72fd842",
"body": "Expose Reflex::Menu to Ruby, on top of the C++ layer added in the previous\ncommit, and let Window#menu= attach a root menu to the window's menu bar.\n\nThe binding is deliberately split in two layers: ext exposes the raw calls\n(add_child!, enable!, check!, each!) and lib/reflex/menu.rb wraps them into\n[…]\n own class instead would\nre-enter Ruby and recurse until the stack dies.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq",
"is_bot": false,
"headline": "reflex: Add Ruby bindings for Menu",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-23T05:49:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ccd54191c005d82126c722c2ea53ddb08e9a58ca",
"body": "Reflex::Menu is a tree of native menu nodes: attach a root to a window to\ndrive its menu bar, or popup() one at a point for context menus. A single\nclass covers every role -- children make a submenu, a click handler makes an\nitem, and a dashes-only label ('----') is a separator. Nodes also carry\nena\n[…]\nry platform.\nRuby bindings, tests and samples follow in a later commit.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq",
"is_bot": false,
"headline": "reflex: Add Menu class backed by native OS menus (C++ layer)",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-23T05:49:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5d642abd2520e50cb6efadb621331e38f95eeca5",
"body": "Both now take an optional insertion index, so a child or a shape can be\nplaced at a specific position instead of only at the end. For shapes this\nis effectively draw order: draw_content() walks the shape list in order,\nso the index decides what overlaps what.\n\nThe ext layer exposes the raw add_child\n[…]\nlently inserting at the front.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01AyQ2jg1uXuUtBG38Mot6Qq\n\n[[6410D458-D15D-486E-874B-F2404548172F]]",
"is_bot": false,
"headline": "reflex: Add index argument to View#add_child and #add_shape",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-22T03:34:51Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8732d2f7d99686c15183de54ef1d23d050fb2910",
"body": "The motor always ran at the automatic strength (1000 * mass), so a weak\ndrive -- a car that stalls uphill, an arm that yields when pushed -- could\nnot be expressed.\n\nExpose the max motor force/torque as force, mirroring the chase\nconstraint: nil restores the automatic strength. The auto default is\nm\n[…]\n chase force already behaves.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[6F74D046-BA2D-4EE6-B034-36AC521F6428]]",
"is_bot": false,
"headline": "reflex: Let each motorized constraint cap its drive with force",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-18T16:44:52Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "46eb939ce345062a3aac5b9d420894d1f0791ccd",
"body": "RailConstraint bundled two joints behind a rotate flag, which silently\nswitched the unit of motor between px/sec and degree/sec, and the name\n\"rail\" never suggested the wheel behavior.\n\nGiving LinkConstraint an optional axis absorbs the prismatic side: the\naxis switches how the separation is measure\n[…]\nters from the bad mass ratio.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[DB46CCED-F50D-4CB7-88AB-B257D43B6D2C]]",
"is_bot": false,
"headline": "reflex: Fold the rail constraint into link and add a wheel constraint",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-18T16:44:52Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5c4d22ac15b8c1519a5c70f9b01d002eafe7c4ec",
"body": "View#constraints re-wraps each native constraint back into Ruby, but the\nC++ object carried no way to recover its Ruby VALUE, so every wrapper\ndegraded to the base Constraint instead of SnapConstraint/LinkConstraint/etc.\n\nGive each constraint family a ClassWrapper slot (RubyConstraint<T>) plus a\ncre\n[…]\nmily's\nprotected constructor.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[7A4F8458-70A1-4D0B-8FCA-6B8DB22047FC]]",
"is_bot": false,
"headline": "reflex: Preserve constraint subclass type across the Ruby boundary",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-18T16:44:52Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "9171c7ec8d4efe5c18c82bdfb1dee8004796f17d",
"body": "Constraint_get_id has no callers anywhere, and it was the only b2 type\nsrc/constraint.h referenced. Dropping both lets the header shed its\n<box2d/id.h> include, so it no longer drags box2d into files that include\nit (which matters once the ext starts pulling this header in).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[CBD10637-672C-4E29-9B84-CB6075ED12D5]]",
"is_bot": false,
"headline": "reflex: Remove the unused Constraint_get_id and its box2d include",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-18T16:44:52Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "3504d315f96d9092cd5489baf705856bb599cf26",
"body": "Map SDL_WINDOWEVENT_ENTER/LEAVE to ENTER/LEAVE pointers so hovered views\ndo not go stale when the cursor leaves the window; these window events\ncarry no coordinates, so the position is queried from SDL_GetMouseState.\nIn-window view enter/leave needs no native help.\n\nAlso reorder the NativePointerEve\n[…]\ners to lead with the window,\nmatching the other platforms.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_011UA1oAnvkyDf4esU7MguHY",
"is_bot": false,
"headline": "reflex: Support pointer enter/leave events on SDL",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-17T17:26:48Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "08b1d8eaf33793cc08409e5283e7cf12fcd8538c",
"body": "Arm TrackMouseEvent(TME_LEAVE) on the first mouse move and map the\nresulting WM_MOUSELEAVE to a LEAVE pointer, so hovered views do not go\nstale when the cursor leaves the window. Win32 has no mouse-enter\nmessage, so the first move after (re)arming — which is exactly when the\ncursor entered the windo\n[…]\nap onto the floatable\npointer model like the Apple Pencil.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_011UA1oAnvkyDf4esU7MguHY",
"is_bot": false,
"headline": "reflex: Support pointer enter/leave events on win32",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-17T17:26:31Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "48d91d445c10d4134ec6ee9cf97d73abd3195bfa",
"body": "Map the hover recognizer's states onto the pointer stream: Began becomes\nENTER, Changed stays MOVE, and Ended/Cancelled become LEAVE, so a window\nreports enter/leave when a pointer crosses it (Stage Manager) or an\nApple Pencil enters/leaves its hover range, symmetrically with macOS.\n\nA hover is type\n[…]\nd\nprev_pointers.clear() dropped the hover pointer with it.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_011UA1oAnvkyDf4esU7MguHY",
"is_bot": false,
"headline": "reflex: Support pointer enter/leave events on iOS",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-17T04:17:16Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "af7cf7202e92dd88359024a813405b2be3747956",
"body": "Window now tracks which views each pointer is over (hovered_views, keyed\nby pointer id with weak references) and synthesizes ENTER/LEAVE by\ndiffing that record against the frame-containment path on every pointer\nevent: enters fire root-to-leaf before the triggering down/move reaches\nthe views, leave\n[…]\nport it. iOS/win32/SDL signals follow in\nplatform commits.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_011UA1oAnvkyDf4esU7MguHY",
"is_bot": false,
"headline": "reflex: Synthesize pointer enter/leave events from hover tracking",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-16T07:30:16Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "9911166f0529efed5d85a1559f49961bd8929eb1",
"body": "Wire up the ENTER/LEAVE pointer actions and their on_pointer_enter/\non_pointer_leave handlers across the cross-platform layers: the action\nenum, C++ virtuals, Ruby overrides, ext bindings, and predicates. Reuse\nPointerEvent rather than introducing a new event class, since enter/leave\ncarry the same \n[…]\nd here because the action enum now\nexpresses these states.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_011UA1oAnvkyDf4esU7MguHY",
"is_bot": false,
"headline": "reflex: Add on_pointer_enter/leave event handlers to View and Window",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-14T15:54:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5c97d83fe0e77f1f71b6fcf9e6eb9c086f610592",
"body": "… are safe\n\nCopy the child/style/shape/constraint list before walking it, so a block\nthat removes an element (e.g. each_constraint { |c| c.remove }) can not\ninvalidate the iterator underneath us.\n\nThe snapshot is a local vector of Refs, so it relies on the Rucy::yield\nmigration: a Ruby exception rai\n[…]\npast the vector's destructor.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[753A8681-A066-41FE-804D-38B8C126B944]]",
"is_bot": false,
"headline": "reflex: Snapshot the list in View#each_* so removals during iteration…",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-10T17:03:44Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "cbedc3be479734d593b35c79a793a7c8d729011c",
"body": "rb_yield / rb_yield_values were called raw in every module's ext, which\nbypasses rucy's boundary handling: a Ruby exception raised in the yielded\nblock longjmps straight past C++ destructors instead of unwinding as a\nRubyJumpTag. Add Rucy::yield (0..12 args, via rb_protect) and adopt it in\nreflex, rays, rays-video and beeps.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[31F36404-6050-4710-AB94-B8EAD19CA6F6]]",
"is_bot": false,
"headline": "rucy: Add Rucy::yield and route ext block yields through it",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-10T16:49:28Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "b0843eb6d8514b1046855f03553edfd54617915d",
"body": "Mark the native timer primitive with the ! suffix like the each_*! ones,\nso a bang consistently flags \"raw native method, not the public API\". The\npublic entry point stays timeout; there is no non-bang start_timer wrapper\nbecause start_timer was already private and only timeout drives it.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[42592E27-B4CC-41DE-962C-8C5D431336A1]]",
"is_bot": false,
"headline": "reflex: Rename the private start_timer binding to start_timer!",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-10T07:28:39Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "541000adfd52c20a2735817f9b9f05ce09c1b9c9",
"body": "…l accessors\n\nFollow Ruby's each_line/lines convention: each_child/style/shape/constraint\nnow return an Enumerator when called without a block, and the plural\naccessors (children, styles, shapes, constraints) return a materialized\nArray instead of a lazy enumerator. The native iterators become priva\n[…]\nal-safe is a separate\nchange.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[5FD77BA9-6E19-4BC7-8FEF-5FF5394E0C55]]",
"is_bot": false,
"headline": "reflex: Give View#each_* an enumerator form and array-returning plura…",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-10T07:28:39Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a81000d78701aa5d50cdcca70f77afc492a92581",
"body": "…leaks\n\nChase's own \"can not chase itself\" check lives in set_target, which runs\nonly after the mouse joint is already attached to the view, so a rejected\nself-chase left a live orphan constraint. Move the check ahead of\nsetup_constraint so the rejection attaches nothing.\n\nAlso own each freshly-newe\n[…]\nysics errors and has no functional signature, so it is not unit-tested.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL",
"is_bot": false,
"headline": "reflex: Harden constraint creation against self-chase and error-path …",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-10T04:13:20Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "67a2872f9b844aaaa9390dd0d03ec8830b7facda",
"body": "Demonstrates all four constraint families (snap/link/rail/chase) in one\nscene. A couple of non-obvious points:\n\n- The car reverses its drive motors at each wall by watching contact_begin\n on the body *and* both wheels: depending on the tilt either a wheel or a\n body corner touches first, and a sid\n[…]\nhe same\n point list is stroked manually in the draw hook.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL",
"is_bot": false,
"headline": "reflex: Add constraint sample",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-07T15:55:04Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "174f14bf8ba47705af45c1d87e4aff15ef1a45d2",
"body": "Give Constraint a selector like the other things a view collects\n(children, shapes, styles), so a name or tags can identify a joint\nin a crowded rig (a ragdoll knee, a drawer's rail) and View can look\nthem up with find_constraints.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL",
"is_bot": false,
"headline": "reflex: Make constraints selectable",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-07T08:24:29Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "96e98e42a4b2f85c5fa49535562b0f70586becf8",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL",
"is_bot": false,
"headline": "reflex: Add tests for constraints",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-07T08:18:19Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "288fff957a4310b31bf7bc98cec471a556ee3e47",
"body": "Expose the pin algebra to Ruby: Pin.new goes through the C++ Pin\nconstructor via value_to<Pin>, so a single argument-parsing path\nhandles view / point / [view, x, y] / nil for every verb. The\nconstraint classes only bind the accessors that need Ruby-side\nshaping (angle/range map to a Range through p\n[…]\nocators that raise, since constraints are created only through\nview.pin.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL",
"is_bot": false,
"headline": "reflex: Add Ruby bindings for constraints",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-07T08:18:19Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "093e5656d88e249bc1a024fe2fce21e565bd4763",
"body": "Constraints are created through the pin algebra\n(Pin(view, x, y).snap/link/rail/chase(target)) and can not be added\ndirectly. A constraint is a persistent declaration while the b2 joint\nis a disposable cache: activated lazily when both views get attached\nto the same world, recreated on re-attach, an\n[…]\ng an axis\n- ChaseConstraint: mouse joint, tracks a target pin every step\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL",
"is_bot": false,
"headline": "reflex: Add view constraint mechanism based on Box2D joints",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-07T08:18:19Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "83dc0613970f249f3e2b8972d69d94798094a9ed",
"body": "The test was `query.contains(element)`, which only matched elements\nwhose tags are a subset of the query, so a shape or style carrying a\ntag beyond the queried ones was missed. Flip it to the direction\nfind_children already uses, `element.contains(query)`, so an element\nmatches when it has all the q\n[…]\n\nwent unnoticed.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[39BB2445-8931-4325-92BC-887606DB3FE3]]",
"is_bot": false,
"headline": "reflex: Fix reversed selector match in find_shapes and find_styles",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-07T08:17:51Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6a3be33ca1d60f7a5956709953efefdbf0a4d25a",
"body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[FF9AF318-F0D7-494B-BDB3-491346AB7742]]",
"is_bot": false,
"headline": "reflex: Add midi and gamepad to the umbrella header",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-07T02:17:16Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "e76a0910ae8018ae5dce4d12f937363c6ac6451d",
"body": "…ration argument\n\nupdate_world stepped the physics world but left the view frames stale,\nbecause the body-to-frame sync only ran in the normal update-tree loop.\nRoute it through the same update_child_world path so a debug or utility\ncaller sees the moved bodies reflected in the view frames. The dura\n[…]\n\na single frame.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DM4Zq1TLdHhxvG9tsR5bUL\n\n[[82026344-A490-492C-A575-EDB7BB102C88]]",
"is_bot": false,
"headline": "reflex: [BREAKING] Sync view frames on View#update_world, drop its du…",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-07-07T01:36:32Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "26603a1c5879830a11ff69ce658e64eb7e35ca1f",
"body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[05EE5F99-0102-4EB6-8222-82EC8B25D2DF]]",
"is_bot": false,
"headline": "Fix Extension.name to join all namespace segments except the last",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-24T10:24:07Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "866b21a87feee02556137b71114162fff9145ccf",
"body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[1CB910FB-F24D-426F-A67C-AC17AD6F0F90]]",
"is_bot": false,
"headline": "reflex rubysketch: Accept hyphenated gem names in pod.rake regex",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-24T03:54:57Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "13b7cd143256fea0f480c7d9e6f808957d2e0b47",
"body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[CFBF9963-EF0B-4019-B324-C7065993FA17]]",
"is_bot": false,
"headline": "Bump versions for pod.rake vendor fix",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-23T07:01:57Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "5525e508b50a0c277ac5709af5da25b8da7f54c2",
"body": "The per-repo clone approach only ran vendor/erb for dependencies.\nReflex's own vendor (Box2D, RtMidi) was not populated.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[4BF86AD2-EB0F-4A5B-B1DE-53A57ED63688]]",
"is_bot": false,
"headline": "reflex: Run vendor and erb for reflex itself in pod.rake setup",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-23T06:58:51Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "ac6ccceb13c24b1b03d26c82d94e0077e1d7ccb4",
"body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[F4AE299B-B9D2-497C-95A1-724850747BDC]]",
"is_bot": false,
"headline": "Bump versions for podspec preserve_paths fix",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-23T06:28:54Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "18c3d7573b2db026a0a00ad91f4d060971ba7755",
"body": "source_files only matches compiled sources (.cpp/.c), so header\nfiles in these directories were being removed by CocoaPods.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[92D5614F-8708-4B1C-BFB4-AAB05BA829F0]]",
"is_bot": false,
"headline": "reflex: Add include, ext, vendor to podspec preserve_paths",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-23T06:27:49Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "50d56a05025b91377d6acece75e1a83573af1889",
"body": "Highlights:\n- reflex: Replace monorepo-based pod.rake with per-repo clone approach\n- rubysketch: Fix podspec issues (RtMidi, Box2D, resource bundles)\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[31998424-B429-4AAD-9DB9-83A0AD923EC1]]",
"is_bot": false,
"headline": "Bump versions for podspec and pod.rake overhaul",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-23T05:18:03Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "bb570cb773a802933308ef9d045aa779cd272309",
"body": "CocoaPods strips .git from cached pod sources, so the previous\napproach — reading the [[UUID]] trailer from git log to find\nthe corresponding monorepo commit — failed in prepare_command.\n\nConsidered several alternatives:\n- Storing the UUID in a file (noisy if updated every commit,\n incomplete if on\n[…]\nm all/<module>/... to\nthe new flat layout, and adjusts check_dev_pods to verify\nxot/ instead of all/.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[101A460F-4D45-47C3-815D-34D24CCC49D2]]",
"is_bot": false,
"headline": "reflex: Replace monorepo-based pod.rake with per-repo clone approach",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-23T05:13:05Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c9c5aad3058fa123bbb431319bcfa6360944387b",
"body": "CocoaPods strips .git from cached pod sources, so git log is\nunavailable when prepare_command runs. Shallow-clone the source\nrepo at the version tag to read the [[UUID]] trailer instead.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[2004546B-B7C7-4C46-AD67-7A92ACB46521]]",
"is_bot": false,
"headline": "reflex: Fix pod.rake to work without .git directory",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-23T02:51:09Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d6c92717a9bc3aa6d20db396407537e31b178f24",
"body": "Highlights:\n- reflex-packager: New CLI tool to package Reflex apps as native macOS bundles\n- reflex: Upgrade Box2D from 2.4.1 to 3.1.1\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\n\n[[BE15D6F8-58BB-4795-935D-02F27B0D1D3E]]",
"is_bot": false,
"headline": "Bump versions for reflex-packager and Box2D 3.x release",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-22T17:33:17Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "e8be124b19e64c07973c6355b2089208c463339a",
"body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Add Reflex.podspec and pod.rake for CocoaPods distribution",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-22T08:38:33Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "ca2672d50683c7dd0109642987af3d3a037626fd",
"body": "A native object can be exposed through more than one Ruby wrapper, so\ncomparing wrappers by Ruby object identity is unreliable (e.g. a Timer\nobtained from View#timeout and the same timer read back from a\nTimerEvent could be unequal). Define ==, eql? and hash by the wrapped\nC++ pointer via Rucy::defi\n[…]\non, Device, MIDI, Filter,\nImageView, View, Window, Shape (and its subclasses) and Timer.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n[[47448B44-3F68-4153-98B7-5B446C07AE15]]",
"is_bot": false,
"headline": "reflex: Define ==/eql?/hash on RefCountable wrapper classes",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-17T16:55:39Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f6f8d9a0d3cb5ecfd310b5251292e95d9a80c983",
"body": "Timer kept its owner View as a raw pointer, so when the View was\ngarbage-collected while a Ruby Timer still referenced it (e.g. under\nGC pressure), reading the owner touched freed memory -- causing flaky\ntest_timer_event failures and crashes.\n\nMake Timer::Data::owner a Xot::WeakRef<View>: owner() returns null once\nthe View is gone, and fire() skips a timer whose owner was collected.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n[[33FED657-B069-4953-8648-39C69E372042]]",
"is_bot": false,
"headline": "reflex: Fix Timer owner use-after-free with WeakRef",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-17T13:27:47Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7a3c390bd871bb74f30e87c6adaee82a0333b990",
"body": "Bundled apps (.app) get an empty default main menu synthesized by\nAppKit before applicationDidFinishLaunching, which made setupMenu's\n'if ([NSApp mainMenu]) return NO' bail out and left the app with no\nQuit/Cmd+Q. Build the menu in applicationWillFinishLaunching while the\nmain menu is still nil.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n[[CEA48E5C-ADCA-4019-8D94-77E2C0CE699B]]",
"is_bot": false,
"headline": "reflex: Build the menu in applicationWillFinishLaunching",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-15T02:03:21Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "408b29cbfc14ba68baac79f058f970e2f428503f",
"body": "Box2D 3.x selects SSE2 SIMD on emscripten targets, but emscripten does\nnot enable SSE2 by default, breaking the wasm build. Fall back to the\nscalar path via BOX2D_DISABLE_SIMD for wasm.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n[[74E302F7-0CC1-49D4-8CBF-EE8D269FDE81]]",
"is_bot": false,
"headline": "reflex: Disable Box2D SIMD for wasm builds",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-14T06:36:10Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d72afe152a661c99e6f48f93ead11f9ab8423b37",
"body": "- Body: destroy the b2 body via Body::Data destructor (RAII) and guard\n body creation/mutation during a step via a World stepping flag\n- Fixture: keep density/friction/restitution/sensor as the source of\n truth, default to Box2D 3.x values (density 1, friction 0.6), and use\n b2*_IsValid before mu\n[…]\nnts after b2World_Step, track touching\n pairs to deliver contact-end events, and use the Box2D 3.x default\n maximum linear speed\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Refactor Box2D 3.x body, fixture, and world handling",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-14T02:24:09Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "9e4b293ef858cd7b035b6463e54ec31709d81730",
"body": "Port the physics layer (body, fixture, shape, world) to the Box2D 3.x\nC API: id handles instead of pointers, value-type collision shapes, and\ncontact/sensor events polled after b2World_Step instead of the\nb2ContactListener/b2ContactFilter callbacks.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Upgrade Box2D from 2.4.1 to 3.1.1",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-14T02:23:44Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "2b9985e6d82a89fc10ee0826a56e6d25b5652a0c",
"body": "- create_rect_fixture computed the bottom edge from frame.x instead of\n frame.y, producing a malformed rectangle\n- create_rect_fixture_without_division asserted on the first point's\n dimension instead of the point count, leaving b2points[8] unguarded\n- create_walls left the default rect shape on the wall view alongside\n the WallShape edges; clear it with set_shape(NULL)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\n\n\n[[C59CDD8F-07A4-4254-BF64-F09D92E12474]]",
"is_bot": false,
"headline": "reflex: Fix rect fixture bottom edge and wall shape setup",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-14T02:18:35Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7bfc3ebe7df8d54be66c58259e4b257e214f8a9f",
"body": "Highlights:\n- [BREAKING] processing: Drop redundant drawXxx aliases and make\n pixelDensity a keyword arg in createGraphics\n (cascades to rubysketch, reight)\n- processing: Per-window Context enables multi-window sketches\n- reflex,rays: Share single offscreen GL context across windows\n- processing: \n[…]\nng display * window scale\n- reight: Sharp editor text via AUTO pixel density, wasm build on\n Ruby 4.0\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n[[35C04FBD-B43A-4A13-B950-78B902B627AC]]",
"is_bot": false,
"headline": "Update changes for multi-window support release",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-12T01:49:00Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ae67c847f7a528419f665da290df5ebae5ad9145",
"body": "The close button on SDL called Window_close() directly, which skipped\nthe on_close event and did not detach views from the window. Go\nthrough Window::close() the same as other platforms.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n[[1B2E33CC-2707-41BC-91EC-DF6049A73DF1]]",
"is_bot": false,
"headline": "reflex: Fire on_close by the close button on SDL",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-11T16:07:30Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "899f8336c1f57db6106606082ff0aa0c68de64b3",
"body": "…ng on event handlers\n\nResetting the root view in close() destroyed the view tree that\nView_update_tree/View_draw_tree was still iterating over, so calling\nclose from event handlers such as on_update or on_draw raised\nArgumentError or crashed with use-after-free.\n\nDo not reset the root view in close\n[…]\nroy the view tree currently being\niterated; the root view is released together with the window itself.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\n\n[[4F50374F-6013-44D4-BA3E-EB7620634288]]",
"is_bot": false,
"headline": "reflex: Do not destroy the view tree in Window#close to survive closi…",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-11T16:06:03Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "26973b044ba3fd466e48cc4289960ba3b09ebd40",
"body": "The range-for over *children kept iterators that remove_child\ninvalidated by calling erase_child_from_children, leading to a\nuse-after-free during ~View() that crashed Ruby at finalizer time\nwith multi-window setups. Drain by popping back() each turn through\na const reference to the unique_ptr, which also follows the reset()\nthat happens when the list becomes empty.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[5CEC466B-0B4D-4993-8218-01518F685062]]",
"is_bot": false,
"headline": "reflex: Fix iterator invalidation in View::clear_children",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-08T15:29:49Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "947176c2df7f5c5f0be530eb0d9ab553ea006579",
"body": "…rior definition\n\nalias_snake_case_methods__ aliases each camelCase instance method to\nits snake_case form. When a snake_case method already exists on the\nclass (typically a manual deprecation wrapper like Sprite#gravity_scale\nor Shape#contact_end), Ruby emits a \"method redefined; discarding old\nfoo\n[…]\no only methods declared\non this class are removed; inherited methods are left untouched.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[9402D9BB-6BE0-4049-BFB7-57B400CA9049]]",
"is_bot": false,
"headline": "processing: Skip alias_snake_case_methods__ warning by removing the p…",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-03T08:20:34Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6fff9f430be77dd2b47d20562c7331f1dbadc36b",
"body": "Move setOpenGLContext: and the associated swap-interval setup out of\ninitWithFrame: into a new setupContext method, called from\nactivateContext on the first actual draw.\n\nThe shared offscreen context's setOpenGLContext: forces AppKit to\nallocate an NSCGLSurface immediately (via setView: -> update ->\n[…]\ne-bind so multi-window draws to the shared context continue\nto land on the correct view.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[D0C7AD61-6380-44E8-92AF-C2B78728B3AD]]",
"is_bot": false,
"headline": "reflex: Lazy-initialize OpenGL context until first drawRect:",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-02T17:51:56Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "790b2dec54b1ff95d0b5ee92b07fc95881fd5397",
"body": "The per-window context model (Strategy A) couldn't keep Painter FBO\nbindings consistent under multi-window — a Painter's begin_paint binds\non whatever context is current, and there was no clean Ruby-level way\nto keep that aligned with each window's draw cycle. Going back to a\nsingle shared context (\n[…]\nrent(hdc, ...) /\nSDL_GL_MakeCurrent(window, ...).\n\nReverts 17008a56, 8b9696e0, 9c64dfee.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[229D8D5B-8A79-4E5E-B3CB-074C88C8C40A]]",
"is_bot": false,
"headline": "reflex: Revert per-window GL context, restore single shared context",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-06-01T04:08:34Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "9ee5ab73694a38b633374479e5198cb244a0b949",
"body": "Switch from the single shared offscreen SDL_GLContext to per-window\ncontexts created with SDL_GL_SHARE_WITH_CURRENT_CONTEXT while the Rays\noffscreen context (the share-tree root) is current. This matches the\nindustry-standard \"per-window context + shared resources\" model and\ndecouples each window's \n[…]\ne window\ncontext is created standalone, as before. The is_active helper returns,\nnow accurately identifying this window's context.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Give each window its own GL context sharing resources (SDL)",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T09:01:58Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "dd54ed21295798a866c786836853a102b6449cc0",
"body": "Switch from the single shared offscreen HGLRC to per-window contexts\ncreated with wglCreateContext, sharing GL resources with the Rays\noffscreen context (the share-tree root) via wglShareLists. This\nmatches the industry-standard \"per-window context + shared resources\"\nmodel and decouples each window\n[…]\nurrent), and the\nis_active helper returns, now accurately identifying this window's\ncontext rather than the previously shared one.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Give each window its own GL context sharing resources (Win32)",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T08:06:50Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5f2725ba7721900edbe460d7750d9b117b44ee6a",
"body": "Switch from the single shared offscreen context to per-window\nNSOpenGLContexts that share GL resources with the Rays offscreen\ncontext via shareContext:. This matches the industry-standard\n\"per-window context + shared resources\" model and decouples each\nwindow's GL state.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Give each window its own GL context sharing resources (macOS)",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T07:49:04Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "4b487f7edf73181ca56cc2e38a4cfba6c850f7d8",
"body": "…haring\n\nSource window animates orbiting dots into a shared Rays::Image, and the\nmirror window samples the same image as a texture from a different\nwindow's draw context. The mirror tiles the image at varying aspect\nratios so the cross-window resource sharing is visually obvious.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Add multi_window sample to demonstrate cross-window texture s…",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T07:00:30Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "b8c99eff96cc3c139c1060bd58242a6f46025f41",
"body": "All Reflex windows now reuse the Rays offscreen SDL_GLContext when\navailable, so GL resources (shaders, textures, etc.) are usable across\nmultiple windows. A wasm fallback keeps the original per-window\ncontext path when Rays returns no offscreen context, tracked via the\nowner flag for proper cleanup.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex,rays: Share single offscreen GL context across windows (SDL)",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T07:00:24Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d1e2a52e8cf75bfaf0114a3177b0fa367b8ef9ec",
"body": "All Reflex windows now reuse the Rays offscreen HGLRC instead of\ncreating their own context, so GL resources (shaders, textures, VBOs)\nare usable across multiple windows. The offscreen PFD gains\nPFD_DOUBLEBUFFER so the same HRC can drive on-screen windows.\n\nThe PFD is defined once in Rays and obtain\n[…]\ndule\nforward declaration in Reflex (intentionally not exposed via\n<rays/rays.h> to keep windows.h types out of the public header).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex,rays: Share single offscreen GL context across windows (Win32)",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T06:07:52Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "05af31ea25db5c06e17169ad829870a00642c6da",
"body": "All NSOpenGLViews now reuse the Rays offscreen NSOpenGLContext via\nsetOpenGLContext: + setView:, so GL resources (shaders, textures,\nVBOs) are usable across multiple windows. The Rays offscreen pixel\nformat gains Accelerated, NoRecovery, and DoubleBuffer attributes\nso the same context can also serve as the render context for\non-screen views.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex,rays: Share single offscreen GL context across windows (macOS)",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T05:48:50Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "b3a055a74d7d7f9779b4c7cd8836f7cdfec9f475",
"body": "SDL had no ClassWrapper::retain at all, so Ruby could collect the\nwindow wrapper while the C++ Window was still alive. This caused\nmulti-window scripts to crash on Ubuntu in rb_id_table_lookup,\nmirroring the issue d8cadab7 fixed on Win32.\n\nApply the same pattern:\n\n- WindowData gains need_rebind. cre\n[…]\nchecks the GL state directly instead of also requiring\n the wrapper's object validity.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n\n[[B911C99F-F2FC-4361-A2D7-CF084513802A]]",
"is_bot": false,
"headline": "reflex: Apply GC-root rebind pattern to SDL window lifecycle",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T05:47:18Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a7ca0a5263f15970ebfc4e57e00ff22f189bbe4e",
"body": "Reorganize Win32 window teardown to mirror the macOS bind / rebind /\nunbind structure.\n\n- Window_register is moved into rebind() so a window only appears in\n Window_all() once its Ruby wrapper is GC-rooted. Closes the gap\n where iterating Window_all() during that window would touch a\n freed VALUE\n[…]\n\n- Rays::activate_offscreen_context surfaces wglMakeCurrent failures\n via system_error.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[71DBBB50-C865-4D57-8BD0-4B5C7DCC4AA3]]",
"is_bot": false,
"headline": "reflex,rays: Tighten Win32 window lifecycle around rebind / unbind",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-29T05:18:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "dd228ed84fd2b2cbdfaddbb92dfc86866e1bc83f",
"body": "Window_initialize on Win32 calls setup_window during the Window\nconstructor body (via CreateWindowEx -> wndproc WM_NCCREATE). At that\npoint the vtable is still Window's and ClassWrapper::value isn't built,\nso a virtual win->retain() dispatches to RefCountable::retain and\nmisses ClassWrapper::retain \n[…]\n::retain.\n\nAlso tidy the matching comment in the macOS native_window.mm for\nconsistency.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[F1EF9735-830A-4720-AF01-3A71118ABAD0]]",
"is_bot": false,
"headline": "reflex: Defer ClassWrapper::retain on Win32 to root Ruby wrapper for GC",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-28T17:48:46Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "53a259b10bc14f15a96f7f01c5a290882ed4e0a9",
"body": "Highlights:\n- reight: Add npm publish to WASM release workflow\n- reight: Add test server task for local WASM development\n- rays: Skip glGetError on WASM build for performance\n- reflex: Track actual key repeat count on macOS, add key repeat on iOS\n\nCo-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>\n\n[[0D8281DE-12BE-4FF7-9003-ABEBEF963634]]",
"is_bot": false,
"headline": "Bump versions for WASM npm publish",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-20T06:43:59Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "e99a32f122dbd503aa370c1ab9dd5200ebcd2c98",
"body": "iOS doesn't auto-repeat key events natively, so synthesize them with\nan NSTimer (0.4s initial delay, 0.1s interval) to match the macOS /\ncross-platform behavior. Modifier keys are excluded from repeat; only\nthe most recently pressed key repeats. Timer is invalidated in\nviewDidDisappear and cleanupReflexView to avoid retain cycles.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[63B2F401-5440-4C9F-A60B-2F99D7F55CEC]]",
"is_bot": false,
"headline": "reflex: Add key repeat on iOS",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-17T18:21:28Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "af827d92a5f67af494ce7c2d95d804c1290dc077",
"body": "NSEvent's isARepeat is boolean-only, so the previous implementation\nsent repeat=1 for every repeated event. Track the keyCode and count\nin the window so consecutive repeats of the same key report 1, 2, 3,\n... matching cross-platform expectations.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[F9B5ACC8-F893-48D1-B6AD-1E7CCF1E3B90]]",
"is_bot": false,
"headline": "reflex: Track actual key repeat count on macOS",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-17T16:59:32Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "619564ccac5291772a73b5183f5fcf2bb83c0d26",
"body": "Highlights:\n- [BREAKING] reflex: wheel Y delta normalized to top-left origin\n (cascades to processing, rubysketch, reight)\n- rays: Batch rendering deferred flush + text corruption fix\n- processing: Avoid painter.push overhead in image/blend draws\n- reflex: Keyboard and mouse event handling on iOS\n-\n[…]\nexample\n- All modules: README rewritten, release-gem.yml migrated to\n gh release create\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[25194EDC-92E6-48BB-A42F-B037CBA838A5]]",
"is_bot": false,
"headline": "Bump versions for batching and iOS event release",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-16T17:22:25Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e79bf7e7167edaa872e0f144621bd2683e2b7c32",
"body": "emscripten's SDL2 port shares the Linux scancode mappings, so\nKEY_LALT / KEY_LCOMMAND / KEY_LOPTION / KEY_NUM_CLEAR etc. collide\nwith their canonical names (KEY_ALT / KEY_LWIN / KEY_NUMLOCK) and\nbreak the WASM build with duplicate case errors. Exclude those\naliases on WASM the same way they are already excluded on LINUX.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[915D80E4-8404-4A82-8116-AA84100861B3]]",
"is_bot": false,
"headline": "reflex: Skip duplicate KEY_CODE aliases on WASM build",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-16T16:42:55Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "ff4c94d8a0d59a904eff7e21f13223eabb29a23d",
"body": "- Accept event arg in `on :update do |e|` to match current event API\n- Set explicit frame for the count TextView so it actually renders\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[A1E67CEF-26BC-4BCA-A3CE-3CA2B951CB0C]]",
"is_bot": false,
"headline": "reflex: Fix bats sample",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-16T16:24:03Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "ad89a5c6661646709ee25413ce654a4f2989f977",
"body": "[[C30462E6-27DF-4481-A558-16D5A50580B3]]",
"is_bot": false,
"headline": "Fix paths",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-16T16:24:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "181b7faf1adeb16f8a5e35146016779a6887eec8",
"body": "Replace the archived actions/create-release@v1 +\nactions/upload-release-asset@v1 pair with a single 'release(*ARGV)'\ncall from .workflows/utils.rb, which uses 'gh release create' (with\nfallback to 'gh release upload --clobber').\n\nThe deprecated actions were failing on newer repositories (notably\nxor\n[…]\nes under each module's .github/workflows are\nupdated via 'rake scripts:workflows:build'.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[BA59B07F-7B18-4F31-B393-7A4A53DB5B22]]",
"is_bot": false,
"headline": "ci: Switch release-gem.yml to gh release create via release() helper",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-16T07:16:18Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4adcd723676b99a2e94019a9c083d43f61b6bc2f",
"body": "Replace the prior AI-cleaned text with accurate, user-facing\ndocumentation for each gem. Every README now covers requirements,\ninstallation, what the gem provides (API surface), runnable usage\nexamples, and development tasks, in a consistent format.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[51109D14-7E6F-4709-83BC-25E4C9C4C6DD]]",
"is_bot": false,
"headline": "Rewrite README.md across all modules",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-15T18:37:05Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "9679c05c279837efee1a889d754fb54fa04c1e31",
"body": "Why: LALT, LCOMMAND/RCOMMAND, LOPTION/ROPTION, NUM_CLEAR are not\ndefined in the iOS key enum, so guard them alongside the existing\nLINUX exclusions.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[0D15DAF0-DBB6-4C4E-BC84-7CD17D6AC5B6]]",
"is_bot": false,
"headline": "reflex: Exclude unsupported key symbols on iOS",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-15T06:16:43Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "81a0f7871be1055b8171c8d64fb2528f3d39af95",
"body": "Update the macOS hello sample to build against the current sources\n(refresh the project file references and adopt the current event /\nview accessor APIs in main.cpp), and apply a corresponding cleanup\nto the iOS sample's project file.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[A6E0730C-750E-4FDD-8BF2-42935FBA46A4]]",
"is_bot": false,
"headline": "reflex: Refresh hello sample Xcode projects",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-15T04:33:31Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "300439dd0dec60995500af383bb775fc5208ebfa",
"body": "Translate UIPress events into KeyEvent via pressesBegan/Ended/Cancelled\non the view controller (iOS 13.4+). UIKey.characters that hold\nUIKeyInput* sentinel strings (Escape, arrow keys, etc.) are normalized\nto NULL chars so callers can rely on chars holding real typed text only.\n\nSwitch reflex KeyCod\n[…]\n/LANG2/LANG5 values. Rename the macro's\nthird argument from sdl to hid since SDL_Scancode is itself derived\nfrom HID Usage Tables.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Add keyboard event handling on iOS",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-15T03:44:50Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8633973cb8234a08cf0a6545ee0640065ce596a8",
"body": "Map UITouchTypeIndirectPointer to Pointer::MOUSE with button bits derived\nfrom UIEvent.buttonMask. Attach a UIHoverGestureRecognizer for cursor\nmovement and a UIPanGestureRecognizer with allowedScrollTypesMask for\nscroll-wheel deltas (using the hover recognizer's location to keep the\nreported cursor\n[…]\n\nare guarded for iOS 13.4+. Hover MOVEs are suppressed while any touch is\nactive so they don't interleave with button-drag events.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Add mouse event handling on iOS",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-15T03:44:50Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "317c149962a1ddfec875ddca3897e74533e1ba8a",
"body": "Refresh the Xcode project to match the current rays/reflex/Box2D file\nlayout (opengl/ subtree, view_controller.mm, vendored box2d/rtmidi),\nbump deployment target, and link required system frameworks. Update\nmain.cpp to use the current event/view accessor API.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "reflex: Update iOS hello sample to build with current sources",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-15T03:44:50Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "00959a4dc61b2c6898b07faf1e8b28b885a959c3",
"body": "Reflex already normalizes pointer positions to top-left origin (Y-down)\nacross platforms via osx/event.mm's get_pointer_position, but\nNativeWheelEvent passed NSEvent.deltaY through unchanged in its native\nY-up convention, leaving WheelEvent.dposition.y reversed relative to\npointer.position.y on macO\n[…]\n.y += event.dy` to\nscroll up on a 2-finger upward swipe) will move in the opposite\ndirection and must invert the sign or use `-=`.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "[BREAKING] reflex: Normalize wheel Y delta to top-left origin convention",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-15T03:37:09Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ff6999b4d2a7280c2bd0e5a34ce3a399c8576ef1",
"body": "Highlights:\n- WebAssembly runtime support landed across beeps, rays, reflex,\n processing, rubysketch, and reight\n- rays-video: VideoAudioIn for audio playback in Video class\n- rucy: TypedData migration for Ruby 4.x compatibility\n- xot/rucy: hint_memory_usage callback for external-memory GC\n- All modules: drop deprecated has_rdoc= from gemspecs\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>\n\n[[F010062D-2D91-4D5C-ADD5-39CBC743E5E1]]",
"is_bot": false,
"headline": "Bump versions for WebAssembly release",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-09T16:58:23Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "374ceb0c0b2329c7453b8ae4438424c02940e036",
"body": "Introduce release(*paths) and changelogs() in .workflows/utils.rb.\nrelease reads the tag from GITHUB_REF, looks up the corresponding\nsection in ChangeLog.md, escapes it via shellwords, and runs\n'gh release create' falling back to 'gh release upload --clobber'.\n\nThis will let workflows in each module\n[…]\nhs)' call. Distributed copies under\neach module's .github/workflows are updated by the shared\n'rake scripts:workflows:build' task.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "ci: Add release helper that uploads to GitHub Releases via gh CLI",
"author_name": "xordog",
"author_login": "xord",
"committed_at": "2026-05-09T09:13:11Z",
"body_truncated": true,
"is_coding_agent": true
}
],
"releases_count": 53,
"commits_last_year": 146,
"latest_release_at": "2026-08-04T11:28:58Z",
"latest_release_tag": "v0.6.0",
"releases_from_tags": false,
"days_since_last_push": 0,
"active_weeks_last_year": 22,
"days_since_latest_release": 0,
"mean_days_between_releases": 12.1
},
"artifacts": {
"collected": true,
"structure": [],
"declarations": [
{
"name": "#{name}ion",
"path": "reflex.gemspec",
"tokens": [
"gem.gemspec",
"gem.executables"
],
"ecosystem": "rubygems"
}
]
},
"community": {
"has_readme": true,
"has_license": true,
"readme_badges": {
"hosts": [
"badge.fury.io",
"github.com",
"shields.io"
],
"total": 3,
"header": 3,
"collected": true,
"has_inspect_badge": false
},
"has_description": true,
"has_contributing": true,
"health_percentage": 71,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": true
},
"ecosystem": {
"packages": []
},
"popularity": {
"forks": 0,
"stars": 0,
"watchers": 1,
"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": [
"samples"
],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [],
"toolchain_manifests": [],
"largest_source_bytes": 63311,
"source_files_sampled": 339,
"oversized_source_files": 1,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 695
},
"dependencies": {
"manifests": [
"Gemfile"
],
"advisories": {
"error": null,
"scope": "repository_graph",
"source": "osv",
"findings": [
{
"name": "yard",
"direct": true,
"version": "0.9.39",
"severity": "moderate",
"ecosystem": "rubygems",
"cvss_score": 5.3,
"advisory_ids": [
"GHSA-3jfp-46x4-xgfj",
"GHSA-pxcc-8665-phx8"
],
"fixed_version": "0.9.44",
"advisory_count": 2,
"oldest_advisory_days": 108
}
],
"collected": true,
"malicious": [],
"truncated": false,
"by_severity": {
"moderate": 1
},
"advisory_count": 2,
"affected_count": 1,
"assessed_count": 4,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 3,
"direct_affected_count": 1
},
"ecosystems": [
"rubygems"
],
"dependencies": [
{
"name": "rake",
"manifest": "Gemfile",
"ecosystem": "rubygems",
"version_constraint": null
},
{
"name": "test-unit",
"manifest": "Gemfile",
"ecosystem": "rubygems",
"version_constraint": null
},
{
"name": "yard",
"manifest": "Gemfile",
"ecosystem": "rubygems",
"version_constraint": null
}
],
"all_dependencies": {
"error": null,
"source": "github-sbom",
"packages": [
{
"name": "rake",
"direct": true,
"version": "13.3.1",
"ecosystem": "rubygems"
},
{
"name": "test-unit",
"direct": true,
"version": "3.7.7",
"ecosystem": "rubygems"
},
{
"name": "yard",
"direct": true,
"version": "0.9.39",
"ecosystem": "rubygems"
},
{
"name": "power_assert",
"direct": false,
"version": "3.0.1",
"ecosystem": "rubygems"
},
{
"name": "rays",
"direct": false,
"version": null,
"ecosystem": "rubygems"
},
{
"name": "rucy",
"direct": false,
"version": null,
"ecosystem": "rubygems"
},
{
"name": "xot",
"direct": false,
"version": null,
"ecosystem": "rubygems"
}
],
"collected": true,
"truncated": false,
"total_count": 7,
"direct_count": 3,
"indirect_count": 4
}
},
"maintainership": {
"issues": {
"open_prs": 1,
"merged_prs": 0,
"open_issues": 0,
"closed_ratio": null,
"closed_issues": 0,
"closed_unmerged_prs": 1
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "xord",
"commits": 629,
"avatar_url": "https://avatars.githubusercontent.com/u/776014?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"release-gem.yml",
"tag.yml",
"test.yml"
],
"has_docs_dir": false,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"Gemfile.lock"
],
"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": 3,
"reason": "branch protection is not maximal on development and all release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 0,
"reason": "project has 0 contributing companies or organizations -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 10,
"reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": null,
"reason": "packaging workflow not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": 0,
"reason": "Project has not signed or included provenance with any releases.",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 8,
"reason": "2 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "2bb778ac8a02ab48a86b1b7c1ea60d8551055a4d",
"ran_at": "2026-08-04T11:37:31Z",
"aggregate_score": 3.7,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"recent_prs": {
"merged_7d": 0,
"decided_7d": 0,
"merged_30d": 0,
"authors_30d": 0,
"decided_30d": 0,
"sample_size": 1,
"window_days": 30,
"sample_exhausted": false,
"authors_probed_30d": 0,
"newcomer_merged_30d": 0,
"bot_prs_excluded_30d": 0,
"newcomer_authors_30d": 0,
"newcomer_decided_30d": 0
},
"ci_last_run_at": "2026-08-04T11:29:07Z",
"oldest_open_prs": [
{
"number": 2,
"created_at": "2024-03-01T17:19:44Z",
"last_comment_at": null,
"last_comment_author": null
}
],
"last_merged_pr_at": null,
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/xord/reflex",
"host": "github.com",
"name": "reflex",
"owner": "xord"
},
"metrics": {
"overall": {
"key": "overall",
"band": "weak",
"name": "Overall health",
"note": "The weighted overall 49 is calibrated to 48 on the published index scale (record calibration 2026-08-02).",
"notes": [
{
"code": "overall_calibration",
"params": {
"raw": 49,
"calibrated": 48,
"calibration": "2026-08-02"
}
}
],
"value": 48,
"inputs": {
"security": 44,
"vitality": 83,
"community": 36,
"governance": 20,
"calibration": "2026-08-02",
"engineering": 60,
"ai_readiness": 68,
"weighted_overall_raw": 49
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "excellent",
"name": "Vitality",
"value": 83,
"weight": 0.21,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 79,
"inputs": {
"commits_last_year": 146,
"human_commit_share": 1,
"days_since_last_push": 0,
"active_weeks_last_year": 22
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 0 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 0
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "22/52 weeks with commits",
"points": 15.2,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 22
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "146 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 146
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"releases_count": 53,
"latest_release_tag": "v0.6.0",
"releases_from_tags": false,
"days_since_latest_release": 0,
"mean_days_between_releases": 12.1
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "53 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 53
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 0 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 0
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~12.1 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 12.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": "exceptional",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "maintained",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": null,
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": 0,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "last human commit 0 days ago",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_maintained",
"params": {
"days": 0
}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "weak",
"name": "Community & Adoption",
"value": 36,
"weight": 0.17,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 1,
"inputs": {
"forks": 0,
"stars": 0,
"watchers": 1,
"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": "1 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 1
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "good",
"name": "Community health",
"note": null,
"notes": [],
"value": 77,
"inputs": {
"has_readme": true,
"has_license": true,
"readme_badges": 3,
"has_contributing": true,
"has_issue_template": false,
"has_code_of_conduct": false,
"readme_badge_services": [
"badge.fury.io",
"github.com",
"shields.io"
],
"has_pull_request_template": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 18,
"status": "met",
"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": 6.3,
"status": "met",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "at_risk",
"name": "Sustainability & Governance",
"value": 20,
"weight": 0.23,
"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": "critical",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): Issue resolution, Newcomer PR acceptance. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"issue_resolution",
"newcomer_pr_acceptance"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 1,
"inputs": {
"merged_prs": 0,
"open_issues": 0,
"closed_issues": 0,
"prs_merged_7d": 0,
"prs_decided_7d": 0,
"prs_merged_30d": 0,
"prs_decided_30d": 0,
"issue_closed_ratio": null,
"closed_unmerged_prs": 1,
"first_time_authors_30d": 0,
"first_time_prs_merged_30d": 0,
"first_time_prs_decided_30d": 0
},
"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": 42
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "0/1 decided PRs merged",
"points": 0,
"status": "missed",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 0,
"decided": 1
}
}
],
"max_points": 30
},
{
"key": "newcomer_pr_acceptance",
"name": "Newcomer PR acceptance",
"detail": "no first-time contributor's PR decided in 30d",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_newcomer_prs",
"params": {
"days": 30
}
}
],
"max_points": 13
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "moderate",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 50,
"inputs": {
"followers": 11,
"owner_type": "User",
"is_verified": null,
"owner_login": "xord",
"public_repos": 27,
"account_age_days": 5566
},
"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": "11 followers of xord",
"points": 7.8,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 11,
"login": "xord"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "27 public repos, account ~15 yr old",
"points": 22.5,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 27
}
},
{
"code": "account_age_years",
"params": {
"years": 15
}
}
],
"max_points": 25
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "moderate",
"name": "Engineering Quality",
"value": 60,
"weight": 0.19,
"metrics": [
{
"key": "engineering_practices",
"band": "moderate",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 60,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "3 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 3
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "moderate",
"name": "Documentation",
"note": null,
"notes": [],
"value": 60,
"inputs": {
"topics": [
"ruby",
"library",
"gem",
"gui",
"gui-toolkit",
"cpp",
"physics"
],
"has_wiki": true,
"homepage": null,
"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": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": "7 topics",
"points": 10,
"status": "met",
"details": [
{
"code": "topics_count",
"params": {
"count": 7
}
}
],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "weak",
"name": "Security",
"value": 44,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "weak",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests, Packaging. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests",
"packaging"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 37,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 16,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 2,
"scorecard_aggregate": 3.7
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection is not maximal on development and all release branches",
"points": 2.2,
"status": "partial",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow not detected",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "Project has not signed or included provenance with any releases.",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "2 existing vulnerabilities detected",
"points": 6,
"status": "partial",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "dependency_advisories",
"band": "good",
"name": "Dependency advisories",
"note": "Excluded from scoring (no data or not applicable): Indirect dependencies free of known advisories. Remaining weights renormalized. Matched 4 resolved dependencies against OSV; 3 could not be assessed (no resolved version, an unsupported ecosystem, or beyond the reported package list). This repository publishes no package the index resolves, so the repository dependency graph was assessed instead. That graph mixes development and test pins with shipped dependencies, so only the declared runtime dependencies are scored; transitive findings are reported as context and excluded from the score. Reachability is not analyzed.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"indirect_dependencies_free_of_known_advisories"
]
}
},
{
"code": "weights_renormalized",
"params": {}
},
{
"code": "advisories_scope_repository",
"params": {
"assessed": 4
}
},
{
"code": "advisories_unassessed",
"params": {
"count": 3
}
},
{
"code": "advisories_repo_graph_caveat",
"params": {}
},
{
"code": "advisories_reachability",
"params": {}
}
],
"value": 74,
"inputs": {
"source": "osv",
"advisories": 2,
"affected_packages": 1,
"assessed_packages": 4,
"unassessed_packages": 3,
"affected_by_severity": "moderate 1",
"direct_affected_packages": 1
},
"components": [
{
"key": "direct_dependencies_free_of_known_advisories",
"name": "Direct dependencies free of known advisories",
"detail": "1 affected: yard 0.9.39 (moderate 5.3)",
"points": 20.2,
"status": "partial",
"details": [
{
"code": "advisories_affected",
"params": {
"count": 1,
"packages": "yard 0.9.39 (moderate 5.3)"
}
}
],
"max_points": 35
},
{
"key": "indirect_dependencies_free_of_known_advisories",
"name": "Indirect dependencies free of known advisories",
"detail": "transitive set not separable from development and test dependencies in this scope",
"points": 0,
"status": "excluded",
"details": [
{
"code": "advisories_scope_not_separable",
"params": {}
}
],
"max_points": 25
},
{
"key": "no_advisories_left_outstanding",
"name": "No advisories left outstanding",
"detail": "1 advisory-carrying package(s) unaddressed past 90 days; oldest published 108 days ago",
"points": 35.3,
"status": "partial",
"details": [
{
"code": "advisories_stale",
"params": {
"days": 90,
"count": 1,
"oldest": 108
}
}
],
"max_points": 40
}
]
},
{
"key": "malicious_dependencies",
"band": "exceptional",
"name": "Malicious dependencies",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"source": "osv",
"meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
"packages": [],
"red_flag": false,
"assessed_packages": 4,
"malicious_packages": 0,
"direct_malicious_packages": 0,
"withdrawn_malicious_packages": 0,
"installable_malicious_packages": 0
},
"components": [
{
"key": "no_dependency_reported_as_a_malicious_package",
"name": "No dependency reported as a malicious package",
"detail": "no dependency is reported as a malicious package",
"points": 100,
"status": "met",
"details": [
{
"code": "no_malicious_dependencies",
"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": 68,
"weight": 0.04,
"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.99,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 695
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "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": "99 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 99,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "moderate",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 53,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"Gemfile.lock"
],
"has_dockerfile": false,
"typed_language": true,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [],
"agent_commit_share": 0.99,
"toolchain_manifests": [],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"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": "C++ (statically typed)",
"points": 11,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "C++"
}
}
],
"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": "99 of the last 100 commits agent-authored or agent-credited",
"points": 10,
"status": "met",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 99,
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "exceptional",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "C++",
"largest_source_bytes": 63311,
"source_files_sampled": 339,
"oversized_source_files": 1
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "C++ (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "C++"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "1/339 source files over 60KB",
"points": 54.8,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 339,
"oversized": 1
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "weak",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"example_dirs": [
"samples"
],
"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": "samples",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "samples"
}
}
],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? Carries a deliberately small weight: agent tooling is a real maintenance signal, but its absence must never gate the top of the scale (calibration saturates at raw 91, so 100/100 remains reachable with AI Readiness at zero)."
}
],
"classification": {
"top": [
"library",
"application"
],
"labels": [
"cli",
"library"
],
"scores": {
"cli": 10,
"library": 10
},
"primary": "cli",
"evidence": [
{
"tier": "declared",
"label": "cli",
"source": "gem.executables",
"weight": 10
},
{
"tier": "declared",
"label": "library",
"source": "gem.gemspec",
"weight": 8
},
{
"tier": "tags",
"label": "library",
"source": "tag:library",
"weight": 2
}
],
"artifacts": [
{
"path": "reflex.gemspec",
"labels": [
"cli",
"library"
],
"ecosystem": "rubygems"
}
],
"confidence": "high",
"host_extension": false,
"runs_as_process": true,
"consumed_by_code": true
},
"metrics_version": "2.5.0"
},
"warnings": [
"Could not fetch rubygems package '#{name}ion' from its registry"
],
"report_type": "repository",
"generated_at": "2026-08-04T11:37:36.092865Z",
"schema_version": "0.30.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/x/xord/reflex.svg",
"full_name": "xord/reflex",
"license_state": "standard",
"license_spdx": "MIT"
}