原始 JSON 报告 机器可读
{
"data": {
"repo": {
"topics": [
"dashboard",
"e-ink",
"esp32",
"home-assistant",
"raspberry-pi",
"self-hosted",
"tesserae"
],
"is_fork": false,
"size_kb": 91970,
"has_wiki": false,
"homepage": "https://tesserae.ink",
"languages": {
"CSS": 1110061,
"HTML": 641071,
"Shell": 23495,
"Python": 4617797,
"Dockerfile": 5742,
"JavaScript": 795669,
"PowerShell": 5920
},
"pushed_at": "2026-07-27T05:52:03Z",
"created_at": "2026-05-25T07:37:15Z",
"owner_type": "User",
"updated_at": "2026-07-27T05:52:37Z",
"description": "E-ink dashboard companion. Compose dashboards in a browser, render server-side, and push to e-ink panels over REST or MQTT.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "AGPL-3.0",
"default_branch": "main",
"license_spdx_raw": "AGPL-3.0",
"primary_language": "Python",
"significant_languages": [
"Python",
"CSS",
"JavaScript"
]
},
"owner": {
"blog": "https://dmello.io",
"name": "Kayden D'Mello",
"type": "User",
"login": "dmellok",
"company": null,
"location": "Melbourne, Australia",
"followers": 9,
"avatar_url": "https://avatars.githubusercontent.com/u/180086677?v=4",
"created_at": "2024-09-01T10:49:42Z",
"is_verified": null,
"public_repos": 70,
"account_age_days": 693
},
"license": {
"state": "standard",
"spdx_id": "AGPL-3.0",
"raw_spdx": "AGPL-3.0",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.152.0",
"kind": "minor",
"published_at": "2026-07-19T11:03:22Z"
},
{
"tag": "v0.132.0",
"kind": "minor",
"published_at": "2026-07-16T18:07:25Z"
},
{
"tag": "v0.131.0",
"kind": "minor",
"published_at": "2026-07-16T18:00:13Z"
},
{
"tag": "v0.130.0",
"kind": "minor",
"published_at": "2026-07-16T11:08:03Z"
},
{
"tag": "v0.100.0",
"kind": "minor",
"published_at": "2026-07-11T08:22:18Z"
},
{
"tag": "v0.78.1",
"kind": "patch",
"published_at": "2026-07-10T10:48:11Z"
},
{
"tag": "v0.73.1",
"kind": "patch",
"published_at": "2026-07-10T03:55:55Z"
},
{
"tag": "v0.72.0",
"kind": "minor",
"published_at": "2026-07-08T05:55:17Z"
},
{
"tag": "v0.71.5",
"kind": "patch",
"published_at": "2026-07-07T11:05:44Z"
},
{
"tag": "v0.71.2",
"kind": "patch",
"published_at": "2026-07-07T03:21:46Z"
},
{
"tag": "v0.71.1",
"kind": "patch",
"published_at": "2026-07-07T01:29:14Z"
},
{
"tag": "v0.71.0",
"kind": "minor",
"published_at": "2026-07-07T00:47:10Z"
},
{
"tag": "v0.70.1",
"kind": "patch",
"published_at": "2026-07-07T00:00:12Z"
},
{
"tag": "v0.70.0",
"kind": "minor",
"published_at": "2026-07-06T23:46:48Z"
},
{
"tag": "v0.65.0",
"kind": "minor",
"published_at": "2026-07-03T06:39:01Z"
},
{
"tag": "v0.64.40",
"kind": "patch",
"published_at": "2026-06-29T00:32:37Z"
},
{
"tag": "v0.64.23",
"kind": "patch",
"published_at": "2026-06-24T13:21:41Z"
},
{
"tag": "v0.53.2",
"kind": "patch",
"published_at": "2026-06-20T09:32:48Z"
},
{
"tag": "v0.51.9",
"kind": "patch",
"published_at": "2026-06-20T01:43:54Z"
},
{
"tag": "v0.51.8",
"kind": "patch",
"published_at": "2026-06-20T00:43:25Z"
},
{
"tag": "v0.51.7",
"kind": "patch",
"published_at": "2026-06-19T05:59:04Z"
},
{
"tag": "v0.51.6",
"kind": "patch",
"published_at": "2026-06-18T13:08:44Z"
},
{
"tag": "v0.51.5",
"kind": "patch",
"published_at": "2026-06-18T09:31:12Z"
},
{
"tag": "v0.51.4",
"kind": "patch",
"published_at": "2026-06-18T09:19:36Z"
},
{
"tag": "v0.51.3",
"kind": "patch",
"published_at": "2026-06-18T04:27:04Z"
},
{
"tag": "v0.51.1",
"kind": "patch",
"published_at": "2026-06-18T03:15:52Z"
},
{
"tag": "v0.51.0",
"kind": "minor",
"published_at": "2026-06-18T03:01:59Z"
},
{
"tag": "v0.50.3",
"kind": "patch",
"published_at": "2026-06-18T00:30:09Z"
},
{
"tag": "v0.50.2",
"kind": "patch",
"published_at": "2026-06-17T11:30:17Z"
},
{
"tag": "v0.50.0",
"kind": "minor",
"published_at": "2026-06-17T05:04:29Z"
},
{
"tag": "v0.49.6",
"kind": "patch",
"published_at": "2026-06-17T04:13:23Z"
},
{
"tag": "v0.49.5",
"kind": "patch",
"published_at": "2026-06-16T23:30:23Z"
},
{
"tag": "v0.49.4",
"kind": "patch",
"published_at": "2026-06-16T23:05:14Z"
},
{
"tag": "v0.49.3",
"kind": "patch",
"published_at": "2026-06-16T22:36:52Z"
},
{
"tag": "v0.49.2",
"kind": "patch",
"published_at": "2026-06-16T12:35:24Z"
},
{
"tag": "v0.49.1",
"kind": "patch",
"published_at": "2026-06-16T11:00:28Z"
},
{
"tag": "v0.49.0",
"kind": "minor",
"published_at": "2026-06-16T08:36:02Z"
},
{
"tag": "v0.48.0",
"kind": "minor",
"published_at": "2026-06-16T02:08:11Z"
},
{
"tag": "v0.47.17",
"kind": "patch",
"published_at": "2026-06-16T01:04:05Z"
},
{
"tag": "v0.45.5",
"kind": "patch",
"published_at": "2026-06-10T21:43:51Z"
},
{
"tag": "v0.44.6",
"kind": "patch",
"published_at": "2026-06-10T02:02:01Z"
},
{
"tag": "v0.44.5",
"kind": "patch",
"published_at": "2026-06-09T22:07:33Z"
},
{
"tag": "v0.44.4",
"kind": "patch",
"published_at": "2026-06-09T06:37:12Z"
},
{
"tag": "v0.44.3",
"kind": "patch",
"published_at": "2026-06-09T04:05:49Z"
},
{
"tag": "v0.44.2",
"kind": "patch",
"published_at": "2026-06-09T03:35:27Z"
},
{
"tag": "v0.44.1",
"kind": "patch",
"published_at": "2026-06-09T03:14:54Z"
},
{
"tag": "v0.44.0",
"kind": "minor",
"published_at": "2026-06-09T03:01:07Z"
},
{
"tag": "v0.43.7",
"kind": "patch",
"published_at": "2026-06-09T02:42:05Z"
},
{
"tag": "v0.43.6",
"kind": "patch",
"published_at": "2026-06-09T02:34:09Z"
},
{
"tag": "v0.43.5",
"kind": "patch",
"published_at": "2026-06-09T02:19:35Z"
},
{
"tag": "v0.43.4",
"kind": "patch",
"published_at": "2026-06-09T00:02:39Z"
},
{
"tag": "v0.43.3",
"kind": "patch",
"published_at": "2026-06-08T21:49:40Z"
},
{
"tag": "v0.43.2",
"kind": "patch",
"published_at": "2026-06-08T20:58:22Z"
},
{
"tag": "v0.43.1",
"kind": "patch",
"published_at": "2026-06-08T20:21:59Z"
},
{
"tag": "v0.43.0",
"kind": "minor",
"published_at": "2026-06-08T10:18:39Z"
},
{
"tag": "v0.42.3",
"kind": "patch",
"published_at": "2026-06-08T09:16:56Z"
},
{
"tag": "v0.42.2",
"kind": "patch",
"published_at": "2026-06-08T03:35:45Z"
},
{
"tag": "v0.42.1",
"kind": "patch",
"published_at": "2026-06-08T03:03:16Z"
},
{
"tag": "v0.42.0",
"kind": "minor",
"published_at": "2026-06-08T02:57:09Z"
},
{
"tag": "v0.41.2",
"kind": "patch",
"published_at": "2026-06-07T22:59:47Z"
},
{
"tag": "v0.41.1",
"kind": "patch",
"published_at": "2026-06-07T22:37:49Z"
},
{
"tag": "v0.41.0",
"kind": "minor",
"published_at": "2026-06-07T22:16:09Z"
},
{
"tag": "v0.40.0",
"kind": "minor",
"published_at": "2026-06-07T21:54:32Z"
},
{
"tag": "v0.39.0",
"kind": "minor",
"published_at": "2026-06-07T21:46:29Z"
},
{
"tag": "v0.38.0",
"kind": "minor",
"published_at": "2026-06-07T21:36:26Z"
},
{
"tag": "v0.37.0",
"kind": "minor",
"published_at": "2026-06-07T21:15:34Z"
},
{
"tag": "v0.36.2",
"kind": "patch",
"published_at": "2026-06-07T10:54:53Z"
},
{
"tag": "v0.36.1",
"kind": "patch",
"published_at": "2026-06-07T10:02:22Z"
},
{
"tag": "v0.36.0",
"kind": "minor",
"published_at": "2026-06-07T09:31:44Z"
},
{
"tag": "v0.35.2",
"kind": "patch",
"published_at": "2026-06-07T08:59:36Z"
},
{
"tag": "v0.34.1",
"kind": "patch",
"published_at": "2026-06-07T01:18:31Z"
},
{
"tag": "v0.31.0",
"kind": "minor",
"published_at": "2026-06-06T13:03:56Z"
},
{
"tag": "v0.29.0",
"kind": "minor",
"published_at": "2026-06-05T22:19:35Z"
},
{
"tag": "v0.16.26",
"kind": "patch",
"published_at": "2026-06-04T07:53:18Z"
}
],
"recent_commits": [
{
"oid": "1e3d096a6b054869aeb9ee431035f8c2ef94860f",
"body": "Publishes the bridge with the device-owned-touch primitives section in its agent\ndocstring, so agents discover the button/switch/slider/stepper kinds.",
"is_bot": false,
"headline": "chore: tesserae-mcp 0.10.2",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T05:51:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "57398d9fd53dd68d275d08091fda20f6ff4a6287",
"body": "Advances edge for the device-owned touch (touch-v3) feature: typed primitives,\nthe frame-spec / interact / atlas / stream endpoints, canvas authoring, and the\nopt-in experiment gate.",
"is_bot": false,
"headline": "chore: bump version to 0.202.0",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T04:39:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "bf7673d9b335dad3212bfb396d6efe32d8caa3ed",
"body": "Firmware handoff summarising the finalized device contract now that the backend,\nauthoring, gating, and MCP paths have shipped: the atlas + SSE-values contracts\n(text and live state unblocked), framebuffer-space rects, the always_on config\nfield, and the touch_v3 opt-in behaviour (empty spec when off).",
"is_bot": false,
"headline": "docs: touch-v3 firmware sync (server complete through M4)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T04:39:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b1458216f6950d2a4929a2ebb907d4b63735baf9",
"body": "…he bridge\n\nConfirms an agent can create + round-trip button/switch/slider/stepper over the\nMCP element API (fields validate against the Element model, so no special-casing)\nand that a typo'd binding field surfaces as a 422. Adds a device-owned-touch\nprimitives section to the MCP bridge docstring so agents can discover the kinds\nand their bindings.",
"is_bot": false,
"headline": "test: touch-v3 primitives are authorable via MCP + document them in t…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T03:50:25Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c2cd32af4a8c8761de8dc876f7fd64e1aaa890c1",
"body": "One canvas of primitives drives the whole device flow in a single test:\n/frame/spec returns the switch in device-framebuffer coords with its label atlas\nattached, /interact fires the HA toggle with no reconcile scheduled, and the SSE\nstream pushes the bound entity's live state. Guards the pieces working together.",
"is_bot": false,
"headline": "test: touch-v3 end-to-end round-trip integration",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T03:46:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d1f382e91a389372dd989c6a07917b19b4eface9",
"body": "Adds a touch_v3 experiment (default off) so the new feature doesn't affect\nexisting installs. The palette hides the primitives and the device endpoints go\ninert until it's enabled: /frame/spec serves an empty spec, /interact returns\nno_target, /atlas 404s. The editor route passes the flag to the template; the\ncanvas filters the palette on it. Existing touch tests enable it in their\nfixtures; a new gating test covers the off/on behaviour.",
"is_bot": false,
"headline": "feat: touch_v3 experiment gate (opt-in for device-owned touch)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T03:45:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "87115fa574ce74b645bf3290d7a7e2795711aee4",
"body": "Layer list now names button/switch/slider/stepper (with label/binding) instead\nof \"Empty box\". The button inspector gains an icon field reusing the existing\nicon picker; the preview already renders the chosen icon. The chrome geometry\nstays hardcoded to match primitives.json (verified in the editor); serving\nprimitives.json as a shared source is deferred as low near-term value.",
"is_bot": false,
"headline": "feat: touch-v3 authoring polish (layer labels + button icon picker)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T03:37:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6c8d417df5e50cb0920f025456a9f65156f39537",
"body": "Selecting a button/switch/slider/stepper now shows a dedicated inspector: a\nlabel field (button/switch) and an interaction section with the entity binding\n(value_key), the slider/stepper numeric range, and the slider axis. A switch\nskips the tap/swipe/slide picker since its action is the bound entity's toggle;\na button keeps the action picker. No color/fill controls, since the firmware\ndraws the control. Touch is now authorable in the canvas editor without MCP.",
"is_bot": false,
"headline": "feat: touch-v3 primitive config in the canvas inspector",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T03:23:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f02a9ab3e72425a773ff926f2322abf93b1ba136",
"body": "Adds button/switch/slider/stepper to the canvas palette with sensible defaults\n(label, value binding, axis/range fields). Each renders an editor-only chrome\npreview matching primitives.json geometry (button outline+label, switch\npill+thumb, slider track+thumb, stepper -/value/+), mirroring the hotspot\naffordance: the real render stays blank and the firmware draws the control.\nPer-type binding config (entity/axis/range) follows.",
"is_bot": false,
"headline": "feat: touch-v3 primitives in the canvas editor (palette + preview)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T03:20:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fe2d53f1e694a7d4f2e8505bacf00c4456ca548d",
"body": "The device stream now resolves the current canvas page's touch-primitive\nbindings alongside the overlay value slots, so a switch/slider reflects HA\nchanging externally. Values arrive keyed by value_key (ha:light.desk), which the\nfirmware maps back to its primitives; reuses the existing values_document,\nfingerprint dedup, and ha_core resolution rather than adding a parallel event.",
"is_bot": false,
"headline": "feat: touch-v3 live state via the SSE values stream",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T03:12:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c910444e543196e8901bfd9a2631d02e7f3e8f95",
"body": "Builds label (20/400) and value (28/700) atlases over a wide charset (printable\nASCII + degree) by reusing build_atlas with its own cache namespace, and converts\nthe result to the firmware atlas descriptor. The packed glyph cell is advance-\nwide, so adv == w and text lays out by walking cells. /fram\n[…]\ns\nthe atlases its primitive text refs reference (label/value_text), each with a\ncontent-addressed url; GET /atlas/<digest> serves the immutable 4bpp-gray strip\nwith a path-traversal-safe digest check.",
"is_bot": false,
"headline": "feat: touch-v3 glyph atlas pipeline (build, attach, serve)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T02:46:44Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ad71a3a94756a6792c67d9591b43c4ddba1419b3",
"body": "Devices advertise can_stay_awake (they can run mains-powered without deep sleep)\non register/heartbeat; ingested sticky like proto/overlay and persisted to the\ndevice-facts store. This is the hardware fact that gates whether the server\noffers the always_on setting for a device; the setting itself is separate.",
"is_bot": false,
"headline": "feat: touch-v3 can_stay_awake capability ingest",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T02:36:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c365d1cac7dee3fb7200342e66134223f31e3103",
"body": "The button/switch/slider/stepper kinds previously fell through to the default\nshape and painted a solid box. In the device-owned model the firmware draws the\ncontrol on top of the served image, so the render now reserves a blank rect\nfilled with the canvas background (covering anything behind), mirroring the\nhotspot: paint nothing, let the device own the pixels. Editor chrome for these\ncomes with the authoring UI.",
"is_bot": false,
"headline": "feat: touch-v3 primitives render as a blank reserve in the composition",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T02:21:09Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "74f600c4beacdfe5d42d589f9b7c25a7e66fbbab",
"body": "Adds wire_transform: scales an authored canvas rect to the device's composition\ndims, then runs it through rect_to_wire (the .bin renderer's rotate/flip/scale/\nunderscan chain). /frame/spec now emits framebuffer-space rects per device, so\nthe firmware draws primitives at final coordinates and never scales or rotates.\nPrimitives that degenerate off-panel in wire space are dropped.",
"is_bot": false,
"headline": "feat: touch-v3 spec rects in device-framebuffer coordinates",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T02:06:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b3b825f434dd999cd54f9917f6275250636b6a41",
"body": "Delivers the per-device always_on setting in the /status config block alongside\nsleep_interval_s, defaulting false so firmware always sees the field; a stored\ntrue (set only for can_stay_awake devices) overrides. The device reads it each\npoll to decide deep-sleep vs stay-awake-and-hold-SSE.",
"is_bot": false,
"headline": "feat: touch-v3 always_on in the device config envelope",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T01:52:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "822b6be6d205f9dc9684d24b75bcdf77b8151913",
"body": "The firmware reports {primitive_id, interaction, value}; the server resolves the\nprimitive's action (button on_tap, switch entity toggle, slider/stepper slide\naction) and dispatches it through the existing machinery. The HA path passes a\nnew reconcile=False flag so the side-effect fires without the \n[…]\ner/frame-patch: in the device-owned model the device draws its own\nfeedback and dashboard data arrives via the values channel. Always 200 with an\noutcome; nav and webhook keep their existing dispatch.",
"is_bot": false,
"headline": "feat: touch-v3 POST /interact endpoint with reconcile-free dispatch",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T01:49:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a32ebb037adaf74d63ee595a434aa2ea47aa561e",
"body": "Serves the device-owned touch spec for a device's current frame: resolves the\nlatest render to its canvas page, builds the primitive spec from the page's\nelements, and anchors it to a layout digest derived from primitive structure\n(stable across data-only redraws, so a switch flip or clock tick doesn't\ninvalidate touch). Empty primitives is valid and served; the endpoint is\nauth-gated and 404s when the device has no current frame.",
"is_bot": false,
"headline": "feat: touch-v3 GET /frame/spec endpoint + derived layout digest",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T01:35:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "357d02ee653ccc269c0dbd02926085a9df5d9785",
"body": "Turns a canvas layout's placed primitives into the device-facing touch spec\n(schema/frame-spec.schema.json, graduated here with the atlas schema). Emits\nonly a {tier,type} action classification, never the payload; skips primitives\nthat can't form a valid entry (unbound switch, actionless button, off-panel\nrect), which is where the model's leniency is enforced. Not yet wired to an\nendpoint.",
"is_bot": false,
"headline": "feat: touch-v3 wire spec builder",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T01:24:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cd0ce36d82bab838613640aee0cb4470318fad58",
"body": "Adds button/switch/slider/stepper element kinds and their fields (value_key,\nstate, axis, value range) to the canvas Element, the storage foundation for\ndevice-owned touch. Left lenient at the model level: an in-progress primitive\nmay lack a binding, with required-field enforcement deferred to spec build.\nAdds the previously-missing panel_store test module.",
"is_bot": false,
"headline": "feat: touch-v3 typed primitives in the canvas element model",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T01:22:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8a950337fb893162d6e8e2ae652c5839cdca9a76",
"body": "Freezes the shared contract for the touch re-architecture: server ships an image\nwith blank control rects plus a declarative spec; the firmware draws typed\nprimitives, owns interaction with local partial-refresh feedback, and reports\nsemantic events. Includes primitives.json (shared geometry), the frame-spec and\natlas JSON schemas, the firmware build prompt + engineering spec, and the phase\nplan. Force-added into the gitignored notes/ tree. No app changes.",
"is_bot": false,
"headline": "docs: touch-v3 device-owned touch contract (Phase 0 handoff)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-27T01:18:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "aed40e71577b77018ad683f81a84b4b48b4f0c92",
"body": "…142)\n\nRaises pillow to <13 and cryptography to <50 so installs resolve to the versions\ncarrying the current fixes; the pillow-heif floor moves to 1.1 to match. Ignores\nthe pillow 12 Image.getdata deprecation, which only test assertions trigger.",
"is_bot": false,
"headline": "chore: lift pillow and cryptography pins to current security fixes (#…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-26T08:41:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "49b94489b835eafcc0749303ae95bbcdd001e16d",
"body": "Routes the two operator-supplied URL fetches through net_guard, which gains an\nallow_local mode: same-host loopback and LAN targets stay reachable for local\ndashboard capture while link-local and cloud-metadata addresses are refused.\nThe strict widget-fetch path keeps blocking all local ranges.",
"is_bot": false,
"headline": "fix: SSRF guard on the webpage-screenshot and remote-image fetch paths",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-26T08:41:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c2acdf7b8dbc38ebed48b5fa2f76d9e616f15148",
"body": "…ntend lint tooling\n\nAdds an 80% coverage floor (current baseline 82%), a bandit high-severity\ngate alongside advisory pip-audit, a uv.lock freshness check, a non-blocking\n3.12/3.13 matrix, and advisory ESLint/Stylelint/Prettier over static/. Indexes\nthe protocol-v2, OTA, and calibration docs into the mkdocs nav and repoints the\nplugin-authoring link in CONTRIBUTING. The pillow and cryptography advisories\nthat pip-audit surfaces are tracked in #142.",
"is_bot": false,
"headline": "chore: harden CI with coverage, security, and lockfile gates plus fro…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-26T07:50:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "50cdfce6674e45275f0d329733581c826426de46",
"body": "Removes two stray TRMNL X images (15.4 MB combined) that nothing in the\ndocs, README, or mkdocs config references, and resizes hero-rack.jpg\nfrom the 5624x3688 camera original to 1800 px wide (2.2 MB -> 302 KB),\nmatching its 900 px README display size.",
"is_bot": false,
"headline": "docs: drop unreferenced screenshots; downscale the README hero",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-26T02:54:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "43f2fc427d88599cc667615a57016719653e9bd4",
"body": null,
"is_bot": false,
"headline": "test: silence unused unpacked fixtures flagged by CI ruff",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T11:02:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ff397f4481b168190996f833a2494748c7a291a0",
"body": "…olerant patch diff\n\nRegion reports against a superseded frame digest now dispatch when that\nframe's untrimmed region-id set matches the live one, resolved through\na ~10-generation digest lineage per device, so a dashboard whose pixels\nre-render every 30 s no longer drops taps that race a render. An\n[…]\nen visually identical captures holds the frame digest and stages\nnothing instead of blowing the patch budget and minting a full-flash\nframe; a divert that still fails logs its reason at warning level.",
"is_bot": false,
"headline": "fix: layout-anchored /tap staleness, extraction-race guards, jitter-t…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T10:56:24Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f7149edd7f38daab21225d4d295c4005837e7f6a",
"body": "On protocol v2 panels the device hit-tests locally against a manifest\ntrimmed to max_targets, so interactive zones beyond the budget do not\nfire at all; the previous wording (overflow merely loses its instant\necho) described v1 behaviour. Both the bridge instructions and the MCP\ndevice-list description now state the hard cap, the trim priority, and\nthe advise-count-first / split-across-deck-pages guidance, and note the\ncurrent firmware budget of 64.",
"is_bot": false,
"headline": "docs: region budget is a hard cap on v2 panels (MCP surfaces)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T10:31:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "906550e12553bb2a9e225c0c39bd766045484a0a",
"body": "…tch; wire outcome vocabulary\n\nSidecar specs from code-element markup are raw JSON strings; the\nmanifest builder and region-id resolver classified and dispatched the\nunparsed string, so served manifests carried fragment garbage in\naction.type and every /tap region report failed. Specs now pass throu\n[…]\ndata answers 200 with an empty document for any known digest so\na linger poll can't latch data-off, and over-budget manifests trim nav\n> slide > tap > swipe with the dropped region ids logged by name.",
"is_bot": false,
"headline": "fix: coerce JSON-string action specs in v2 manifests and region dispa…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T10:12:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "73c7a644dd1b53e87fcc094b9acef2b50b902e08",
"body": "…seded digests; sticky envelope gating\n\nEvery /frame 200 for a proto-2 device now carries the manifest block: a\nnon-interactive frame gets a valid empty manifest instead of silence\n(which reads as a v1 server and latches the device out of region\ndispatch), a lost sidecar re-anchors the last built ma\n[…]\nw with the old artifacts\nprune-protected, /status value/patch envelopes gate on the sticky\ncapability instead of the beat body, and proto >= 2 counts as\npatch-capable everywhere overlay schema 2 does.",
"is_bot": false,
"headline": "fix: v2 manifest delivery survives re-renders; grace window for super…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T09:38:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6f3168a0d6990bf0a11b083e7ee1a48f60de8482",
"body": "…d guidance)\n\nThe MCP device list exposes the sticky proto capability next to\noverlay/deck_cache, the actions reference and bridge instructions\nexplain stable region ids and data-touch-id pinning for v2 panels, and\nrender_report documents the touch_id field on tap_regions.",
"is_bot": false,
"headline": "docs: protocol v2 on the MCP surfaces (proto capability, data-touch-i…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T09:11:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2695b5180b9cf34aa6ab373d748259cfac504aec",
"body": null,
"is_bot": false,
"headline": "docs: protocol v2 endpoints in the client contract; v0.197.0",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T07:13:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "edf9e841c96139ed40f9caf96f773bd1bd38ec30",
"body": "GET /<id>/bundle projects the deck pre-render cache into the v2 shape:\nevery warmed page as a digest-addressed frame state plus a links table\n(explicit buttons, gesture aliases, default neighbours), content-hash\nversioned so a device diffs and fetches only unknown digests;\nGET /<id>/bundle/frame/<di\n[…]\nc event now carries the bundle digest. Tile states stay contract-\nonly until element state declarations exist; cold pages are absent\nrather than blocking, so their navigation degrades to a round trip.",
"is_bot": false,
"headline": "feat: protocol v2 state bundles from the warmed deck cache",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T07:10:40Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8c35ac013b46c4077495174d741a5a50e4227e3b",
"body": "GET /<id>/stream serves values / patches / sync envelopes (identical\npayloads to the /status piggybacks and /frame/data) as Server-Sent\nEvents with 25 s comment keepalives, derived from a 2 s scan of the\nsame server state, so the channel is a latency optimisation over the\nlinger poll rather than a correctness surface. One waitress thread per\nconnected device; proxies must not buffer the route.",
"is_bot": false,
"headline": "feat: protocol v2 SSE device stream",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T07:08:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5aa3a5292fe1b1bd51f8807abbd600242fd9682a",
"body": "A v2 device that hit-tested locally reports {region_id, gesture, value,\ndigest, event_id}; the server re-mints the id from the digest's own\nsidecar (stale or forged ids resolve to no_target), applies the same\ndedup / stale / provenance guards as coordinate strokes, substitutes\nslider values, and dispatches through the existing action machinery.\nCoordinate strokes remain the v1 path on the same endpoint.",
"is_bot": false,
"headline": "feat: region-id action reports on POST /tap (protocol v2)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T07:05:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ad621070126f67ae9e83df15f60519fabdb42576",
"body": "New manifest builder turns a frame's region + slot sidecars into the\ndevice-owned hit-testing document: wire-space rects, stable ids\n(el:<id> pinned via data-touch-id / the canvas data-el-id, mk:<hash>\nfallback), tier + type classification, feedback modes, and text regions\nwith glyph atlases. Side-e\n[…]\nm\n/frame responses for devices advertising proto >= 2 (v1 responses stay\nbyte-identical); resolve_region_action re-mints ids deterministically\nso reports can be validated without persisting an id map.",
"is_bot": false,
"headline": "feat: protocol v2 interaction manifests",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T07:04:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f3f9fc86723f5769dd0d2c4067047faa133ca722",
"body": "{\"proto\": {\"v\": 2}} in register/status bodies is validated, carried\nforward across beats that omit it, persisted in the device-facts store,\nand re-seeded into the status cache at startup, mirroring the overlay\ncapability. Protocol v2 surfaces gate on it.",
"is_bot": false,
"headline": "feat: sticky proto capability handshake for protocol v2 devices",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T06:58:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1196393a3e06ce22fe400980fefa4aa325b8f8b8",
"body": "…ct and audit",
"is_bot": false,
"headline": "docs: record the schema-1 overlay spec removal in the protocol contra…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T06:33:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ee52d2b68a01622bfeb24314e018efdc32864349",
"body": "build_spec and the helpers only it used (nav-priority trimming, the\nper-spec target/slot/atlas caps, the 8 KB document guard) are deleted\nwith their unit tests; the endpoint that called it was removed in the\nprevious commit. rect_to_wire, the atlas pipeline, values_document, and\nthe capability parser are unchanged.",
"is_bot": false,
"headline": "refactor: remove the schema-1 overlay spec builder",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T06:31:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "59adedc39c55e33cd9be9bb6682b83fa0efd94ce",
"body": "GET /frame/overlay/<digest> is gone; old firmware probing it gets a 404,\nwhich the v1 client contract already defines as feature-off for the\nframe. The content-addressed atlas endpoint, /frame/data values + patch\ndelivery, and touch dispatch are unchanged; atlas serving gains direct\ntest coverage that previously rode the spec test.",
"is_bot": false,
"headline": "refactor!: remove the schema-1 overlay spec endpoint (protocol v2 audit)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T06:26:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "dfdbfe9f5f79e2639169c87e89b3bffb5616b879",
"body": null,
"is_bot": false,
"headline": "docs: protocol v2 touch design (audit + device-owned interaction model)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T06:18:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5446d18a73d1f10b7598025d4ce49f887ae16d9e",
"body": "…stable for small diffs\n\nThe patch diff moves to composition space (pre-dither) and maps rects\nthrough the tap-target transform chain: floyd-steinberg propagates a\none-tile change through the rest of the scan, so the wire-space byte\ndiff always blew the patch budget and every schema-2 reconcile fell\n[…]\nhe\ndevice-facts store and re-seeds the status cache at startup, overlay\nvalues seq is now milliseconds, and an end-to-end test drives the tap\nwake through the reconcile worker to /frame/data delivery.",
"is_bot": false,
"headline": "fix: engage frame patches under error-diffusion dither; hold digests …",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T04:19:49Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "72f070f584a2151a27a962b9f21dd36d06c867f2",
"body": "…rammar\n\nThe bridge's instruction blob and list_devices tool description now\ncover overlay.schema (post-action frame patches vs debounced re-push),\nattribute-path slot keys, data-overlay-map, and code-element slot\nextraction; the claim that the extractor skips code-element iframes is\nremoved.",
"is_bot": false,
"headline": "docs: teach the MCP bridge the schema-2 overlay capability and slot g…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T03:35:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "789d8178a669f0927afc86a5295430094c26afb3",
"body": "The device list now includes overlay.schema alongside max_targets, the\nrender_report docstring reflects that code-element slots extract via\nmirrors (with the attribute-path and data-overlay-map grammar), and the\nactions reference no longer claims the HA dispatch re-pushes on the\nsame wake.",
"is_bot": false,
"headline": "docs: surface overlay schema + patch behaviour on the MCP device list",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T02:52:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cf0bb9e3000abb21742ca73921af32965bfa643c",
"body": "…HA reconcile\n\nAfter a touch HA action, re-render headless, diff the wire framebuffer\nagainst the served frame, and stage only the changed rects as a patch\ndocument (patches on GET /frame/data, overlay_patches on /status, blob\nvia GET /frame/patch/<digest>), anchored to the served frame digest\nwith \n[…]\nconcile that also covers devices showing a deck\npage or a directly-pushed page (previously never repainted); value\nslots gain attribute paths, per-slot value maps, and code-element\nsandbox collection.",
"is_bot": false,
"headline": "feat: post-action frame patches (overlay schema 2) + async debounced …",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T02:17:56Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1338fbd7dc7fe00f19d3123b0598a58000d0bf8b",
"body": "Pages gain refresh_minutes ('Updates' on the Dashboards list): the\nscheduler re-renders on the page's own cadence and delivers only to\ndevices currently displaying it, resolved from deck nav, rotation\nposition (manual holds included), or single-page binding. Freshness\nbecomes a property of content instead of a side effect of rotation\ndwell; quiet hours respected; default 0 keeps existing behaviour.",
"is_bot": false,
"headline": "feat: per-page update cadence delivered only to showing panels (#140)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-25T00:43:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6d52f4291f2d95241b4909b85949cc2250cfd1a3",
"body": "The timer-driven return-to-home gated its push fallback but not the\npromote path, which could repaint a sleeping panel mid-quiet-window.\nBoth paths now defer until the window ends; user-initiated navigation\nand the Push button stay quiet-exempt.",
"is_bot": false,
"headline": "fix: deck home-return respects quiet hours on the promote fast path",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T12:54:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "94f29b06de150da6b8c0bd760bfd3c3af9f75c7e",
"body": "…turn\n\nDedicated create/edit surface: flip-order rail with page thumbnails,\nclick-to-append library with suggested clusters, per-card inspector\n(home toggle, return-after slider, refresh override, reposition and\nremove), inline settings bar with a live-derived graph view, and a\nsingle behavior line.\n[…]\np order; the\nform submits without JavaScript via membership checkboxes and numeric\norder fields. Home card + idle-return timeout ride the earlier\nbackend (scheduler return pass + manifest home block).",
"is_bot": false,
"headline": "feat: deck editor (dense rail + inspector) with home card and idle re…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T12:32:24Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f2dde2c7e23f7e8f0b597761fda175b645421b7c",
"body": "Decks gain a home page + idle-return timeout: the scheduler returns\nserver-navigated panels home once the timeout lapses (counted from\nthe last interaction), and the sync manifest ships a home block so\nSD-cache firmware enforces it offline. Manifest link tables now carry\nswipe triggers (authored dir\n[…]\ns mirrored, paging defaults where\nsilent), and pages beyond the device's advertised card capacity are\nmarked cache=false with ring-from-home priority instead of letting\nthe firmware overfill mid-sync.",
"is_bot": false,
"headline": "feat: deck home card, swipe triggers, capacity-aware manifests",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T12:21:25Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "18aa1c7456ac8751b61548aefa3a0beeaf249b29",
"body": "…selves\n\nA rotation previously rendered only on step transitions, freezing a\nstep's widget data for its whole dwell and rendering a single-step\nrotation exactly once ever. Fires now happen whenever a new dwell\nwindow begins even with the step unchanged, so a one-page rotation\nwith a 5-minute dwell m\n[…]\n and fires now exclude\npanels inside a manual button/touch hold (the rejoin pass restores\nthem when the hold lapses). Supersedes v0.190.0's refresh_minutes;\nrotations saved with that field still load.",
"is_bot": false,
"headline": "feat!: rotations re-fire at every dwell boundary, including onto them…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T09:13:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4283291dda606294cf29924bec8afc5a2596a792",
"body": "A device poll only fetches the already-rendered frame, so a rotation\nstep's widget data sat stale for its whole dwell. Rotations gain\nrefresh_minutes: the scheduler re-renders and re-pushes the current\nstep on that cadence between transitions, and refreshes manually-held\npages device-targeted on the same cadence. Default 0 preserves the\nrender-on-transition-only behaviour.",
"is_bot": false,
"headline": "feat: rotation content refresh cadence (#140)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T06:58:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9159a52329cea01b0ee3cbdb67b378e98e2375d4",
"body": "# Conflicts:\n#\tpyproject.toml",
"is_bot": false,
"headline": "Merge branch 'pr139'",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T06:43:32Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8a0f37004caff7d7bd4957a90ed6fead85208cd3",
"body": "The scheduler only pushed on step transitions, so a panel paged away\nby physical button or touch stayed on the manual page indefinitely on\nlong-dwell rotations: the override_until hold was recorded but nothing\nacted when it lapsed. A per-tick rejoin pass now pushes the rotation's\ncurrent page device-targeted once the hold expires and clears it;\nin-hold devices are untouched and failures retry next tick.",
"is_bot": false,
"headline": "fix: rejoin manually paged-away devices to their rotation (#140)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T06:11:54Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "254a78664e701afc25653266f33f38ab76714fdf",
"body": "Keep canary membership for fleet rollout state, but only present a device as queued while the imported release is still newer than its reported firmware. This prevents completed updates from remaining visibly queued and labels pending rows with the release actually on offer.",
"is_bot": false,
"headline": "fix: distinguish firmware queue from rollout membership",
"author_name": "Charm Xu",
"author_login": "charmmmz",
"committed_at": "2026-07-24T05:16:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8096b15b12b2b6f0eb4de5a8389eec4fb291b98a",
"body": "Graph-less decks now navigate: sync manifests synthesize left/right\nprev/next links (wrapping) plus half-panel tap zones on touch boards\nwhen a page has no zones or markup touch regions, and server-side\nbutton handling applies the same defaults for deck-bound devices.\nMCP create_deck derives the gra\n[…]\ndge 0.8.2). The Decks page gains a Push action that warms every\npage per device, sends the entry page, and seeds nav position. Deck\nversion churn from volatile page content documented in the protocol.",
"is_bot": false,
"headline": "feat: default deck navigation, MCP graph derivation, deck Push button",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T03:48:24Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a777a618ac2caf53f193787b2d1b7c7d280f4cf8",
"body": "v0.187.1's report promotion trusted the panel's on-glass page\nunconditionally, so a heartbeat between a push and the device's next\nfetch promoted the older deck frame over the pending one and the new\ndashboard never landed. Report and touch-reconcile promotions now only\nwin the live slot when the deck frame isn't older; stale-glass touches\nstill hit-test the frame the finger touched.",
"is_bot": false,
"headline": "fix: recency-guard deck promotions so reports can't revert fresh pushes",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T01:11:27Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "dbe683fb3037e348bf9aebcc46908ee0a02a5e59",
"body": "…cle)\n\nThe firmware counter is RTC_NOINIT and zeroes on any power-on reset\nwithout the device re-pairing, so the <= dedup rule swallowed every\nbutton and touch after a power cycle. A retry resends the same id, so\nequality is the only duplicate signal; lower ids (counter restart,\noffline-queue replay) dispatch and the high-water mark adopts them.",
"is_bot": false,
"headline": "fix: equality-only wake-event dedup (RTC counter restarts on power cy…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T00:48:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3667e0c0b8aaa27289db32c7ead51bed07110d6e",
"body": "The kind heal keeps a device's row (and its persisted dedup high-water\nmark) across reflashes, so a wiped-NVS firmware restarting its event\ncounter at 1 had every button and touch swallowed as a duplicate.\nRegister-on-existing-id and MAC-claim discover now clear the dedup\nstate, matching when a firmware counter legitimately restarts.",
"is_bot": false,
"headline": "fix: reset wake-event dedup counter on device re-pair",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-24T00:39:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8d6c57d32d4bbbbd40127c4948645fad34a35a45",
"body": "A frame painted from the SD deck cache was unknown to the live-render\nslot, so the touch stale-check dropped every stroke against it and a\nconditional poll could repaint the panel back to the pre-nav frame. A\ndigest matching a deck render now promotes that frame (ETag alignment,\nnav position, region hit-testing), deck_page_id reports promote the\nsame way, and report ingestion runs before button/touch dispatch on\n/frame and /status.",
"is_bot": false,
"headline": "fix: reconcile deck-painted frames so touches and polls track the glass",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T23:55:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6c495aa662a9d366536685e4dfb0764ae816e0ac",
"body": "Parses the additive overlay.max_targets capability field (v1.9\nfirmware, clamped 1-64, absent = 8), trims target lists to the\ndevice's advertised budget with navigation actions winning the echo\nslots, emits survivors in document order to match the firmware's own\noverflow rule, and guards spec size against the 8 KB parse buffer.\nMCP device entries report the budget.",
"is_bot": false,
"headline": "feat: per-device overlay target budgets with nav-priority trimming",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T22:07:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8e516a5083785adffa2651ca3071bc031adc1544",
"body": "/api/mcp/devices carries kind + overlay/deck_cache firmware flags,\nrender_report extracts overlay_slots alongside tap_regions, and the\ntesserae-mcp bridge (0.8.1) documents the live-value-slot vocabulary\nand its server-enforced caps in the handshake instructions.",
"is_bot": false,
"headline": "feat: map deck-cache + overlay capabilities into the MCP surface",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T21:22:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "064bfc757d6c3529c0c7d8b9b909d479f90b8a36",
"body": "data-overlay-key elements are extracted alongside touch regions\n(sidecar v3), glyph atlases rasterize through the composition browser\nand Inter faces and pack 4bpp to the firmware strip contract, and live\nvalues serve via GET /frame/data plus the overlay_values piggyback on\n/status. Firmware caps enforced server-side; every failure path\ndegrades the spec to rect-only.",
"is_bot": false,
"headline": "feat: overlay value slots + glyph atlases (hybrid render mode slice 2)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T21:14:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "72c86883f9cd4147baa3faa5edcff87606be8f73",
"body": "Serves GET /frame/overlay/<digest>: rect-only tap-echo targets derived\nfrom the frame's touch-region sidecar, transformed server-side into\nwire-framebuffer pixel space (rotate/flip/scale/underscan mirror the\n.bin renderer chain). Resolves live and deck-cached frames, ingests the\nsticky overlay capability, and documents the contract in\nclient-protocol.md. Value slots and glyph atlases are the next slice.",
"is_bot": false,
"headline": "feat: overlay specs for touch boards (hybrid render mode, schema 1)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T20:47:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3812b84c909e511a1fe514a30235aac61d2e8963",
"body": "Promotes bwr_3 to a canonical packer gamut sharing the BWRY 2-bpp path\n(wire values 0b00 black / 0b01 white / 0b10 red; reserved 0b11 never\nemitted) and adds the xiao_epaper_75_bwr catalog SKU on the same\nprotocol as the mono board so the kind heal migrates reflashes in both\ndirections without duplicating the device row.",
"is_bot": false,
"headline": "feat: bwr_3 native 2-bpp gamut + XIAO ePaper 7.5 BWR hardware SKU",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T13:02:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2bac42acae137bc7cdcab444426294c32d5d8f7c",
"body": "Adds the device-facing surface for on-device deck frame caching: a\ndeck_cache capability parsed per heartbeat (current-state, not sticky),\nGET /deck manifest with frame digests, sizes, TTLs and the link graph\n(cold pages warmed on demand), digest-addressed GET /deck/frame/<digest>,\na deck.version en\n[…]\nate the server nav position. Also adds the\nesp32_gray2_bin renderer (4-level gray, 2 bpp, 96000 bytes at 800x480)\nand the seeed_reterminal_e1001_gray hardware SKU on the same protocol as\nthe mono SKU.",
"is_bot": false,
"headline": "feat: deck cache sync for devices + 2-bpp grayscale E1001 variant",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T10:51:12Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "23823c6b01ec0fb1dd9b794920a795ce4d26f152",
"body": "… device facts\n\nThe Firmware page's manual queue no longer carries across release versions;\na new per-device Auto switch opts a device into every release instead,\nevaluated on heartbeat via app/ota/auto.py (paused releases are never\nauto-resumed, toggling off withdraws a pending offer). Last-known fw_version\nand OTA capability now persist in data/core/device_facts.json so a restart\ndoesn't mislabel sleeping devices as USB-only; devices with no heartbeat at\nall show 'awaiting first heartbeat'.",
"is_bot": false,
"headline": "feat: per-device auto-update switch, one-shot update queue, persisted…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T09:16:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "dfffb47fd435e2466305cf8b6470dde37140858b",
"body": "The page is now one device list: installed vs available firmware per row,\nwith queue / withdraw buttons that ride the release store's per-device offer\nset and auto-import the published descriptor when needed. The staged canary /\npromote / pause controls move to a collapsed Fleet rollout section; manual\ndescriptor import moves to a collapsed section too. No wire-contract changes.",
"is_bot": false,
"headline": "feat: flatten the Firmware page to a per-device update queue",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T03:48:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9c9fbd5f4fd2b8175d1553bcd0afa15450511b4c",
"body": "seeed_ee04_75 (7.5\" mono, 24-pin FPC, esp32_bw_client) and seeed_ee04_73e6\n(7.3\" Spectra 6, 50-pin FPC, esp32_client). Both reuse existing frame\nformats byte-for-byte; awaiting hardware verification. Regenerates the\ncompatibility matrix.",
"is_bot": false,
"headline": "feat: hardware-catalog kinds for the Seeed XIAO ePaper EE04 board",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T02:37:12Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "68b2d1d7b95d8372eccb262fb0abbbf5c278123e",
"body": "…tab next to Devices\n\nPOST /settings/firmware/check drops the hourly api.tesserae.ink cache and the\nredirect back re-fetches every kind; gated on online mode like the automatic\ncheck. The settings tab order becomes Server, Devices, Firmware, Widgets.",
"is_bot": false,
"headline": "feat: manual update-check button on the Firmware page; move Firmware …",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T02:37:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9a0908c20fbe5f35a3daedf3ef8ecfd45b7e2a35",
"body": "A device that paired under a generic protocol kind and later declares its\nhardware-catalog SKU is moved to the declared kind (same wire protocol\nonly), instead of staying pinned by the idempotent re-register path.\nKeeps per-kind OTA rollouts reaching devices whose firmware verifies\ndescriptors against the SKU kind.",
"is_bot": false,
"headline": "feat: auto-heal stale device kind on re-register and MAC-claim discover",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-23T01:06:21Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1b79d36a59d813ee732289bfbdf8a02569703c77",
"body": "…rmware page\n\nThe online update check now sends the reported firmware version as ?current= so\napi.tesserae.ink can aggregate version distribution (only on a cache-miss fetch;\nit never changes the response). When a newer release is published, the Firmware\npage offers a one-click \"Import from release\"\n[…]\nagainst the\ntrust anchor exactly like a file upload, and sets it as the kind's release, no\nmanual download. Both import paths share one accept-descriptor helper, and the\nfetch is gated on online mode.",
"is_bot": false,
"headline": "feat: firmware-version telemetry + one-click release import on the Fi…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-22T23:20:21Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6e2a20e5af7791b5f48297c75d26d1ffad8e5f61",
"body": "…n online mode\n\nWhen online mode is on, Settings -> Firmware shows per kind whether a newer\nfirmware has been published (the existing api.tesserae.ink per-kind check,\ncached hourly) with an \"available\" badge linking to the release. When online\nmode is off the check never runs and the page discloses \n[…]\nthe kind ids and reported firmware versions. Rollout\nitself (import, canary, promote, pause) stays fully offline; only this\navailability check reaches out, and the promote guardrail re-check skips it.",
"is_bot": false,
"headline": "feat: firmware update-availability check on the rollout page, gated o…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-22T22:28:35Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e3b22ab95568d23a6dfb3128e941292568df46e6",
"body": "A guard-railed page wrapping the same per-kind release state the CLI writes.\nPer device kind it shows the current release + verified manifest and the rollout\ncontrols: import + verify a descriptor (rejected with the verifier reason on a\nbad signature / unknown key / unknown kind), set a canary from \n[…]\ns shared with the stage CLI (app/ota/service.py) rather than\nreimplemented, and the advertised ota.schema is now captured on the heartbeat so\ncapability is known. New Firmware tab in the settings nav.",
"is_bot": false,
"headline": "feat: OTA rollout admin UI at Settings -> Firmware (#121)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-22T22:08:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "07596937d39adf7cfe44edfd7ae9402394ceadf3",
"body": "A device speaking OTA reports its update-lifecycle phase on the ota object\nof its heartbeat (phase/reason/target_fw/attempt_id/detail). The server now\nrecords the latest report on the device's live status, shows it as a chip on\nthe Devices card, and event-logs each lifecycle transition, deduping a\nt\n[…]\nParsing + change detection in app/ota/report.py,\nwired through the shared record_status_heartbeat so MQTT and REST both feed it.\nThe report is advisory; the device's first-boot checks remain the gate.",
"is_bot": false,
"headline": "feat: ingest device OTA state reports (#121)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-22T20:41:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f36a242f59571004ac5f9873179d5332aad70d8e",
"body": "…ip trusted keys in image (#121)\n\napp/ota/release.py imported packaging.version at module scope, but packaging\nwas never declared and is absent from the slim Docker image, so the release\nCLI and the /status release-delivery path both raised ModuleNotFoundError.\nVersion comparison now uses a small in\n[…]\n)\nshared with firmware_check, dropping the dependency. The Dockerfile also did\nnot copy ota/, leaving load_trusted_keys() with an empty registry at its\ndefault ota/keys dir; the image now includes it.",
"is_bot": false,
"headline": "fix: OTA release path no longer needs an undeclared packaging dep, sh…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-22T10:45:12Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "7b03496a7b5e35f76bcc4a9fec9e2174e786dade",
"body": "…#119)\n\nRepublish fanned the stored composition out unbound, and unbound pushes\nskip per-device clone renderers, so a resend to a bound device published\nnothing and its REST frame poll kept answering 304 on the old frame. The\npush history row already snapshots device_ids, so the resend now passes\nthem back as device_filters with panel dims resolved from the target.",
"is_bot": false,
"headline": "fix: resend from history replays the original push's device targets (…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-22T08:37:45Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "47b479e7f1df4ea3e01d9942f0e50321283a46a6",
"body": null,
"is_bot": false,
"headline": "Add fetch_latest button action (#135)",
"author_name": "Charm Xu",
"author_login": "charmmmz",
"committed_at": "2026-07-21T12:55:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0323cd28709c52cb18d60ff1a4108ddf60cf796f",
"body": "Reworks crop so it no longer stretches. Crop now separates a widget's render\nbox from its painted footprint: the widget keeps rendering at full size while\nthe element's on-canvas box shrinks to the kept rectangle and clips the rest.\nCropping the top drops a fixed title and the freed space is reclaim\n[…]\ne editor (footprint-aware node layout, move,\nresize, and live crop preview) and the compose render (reduced footprint cell\nplus an offset full-size cell-content). Scale (content density) is unchanged.",
"is_bot": false,
"headline": "feat: crop shrinks the widget box (undistorted), no stretch",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T12:42:22Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "75d9a19d75d712d0d6f172201aad0bcb6aeb3e8f",
"body": "Crossing 100% on the Scale slider made the content visibly jump: at exactly\n100% no root rule was emitted (natural render) but at 99/101% the fill rule\nforced the widget-root dimensions, so it snapped between \"natural\" and\n\"filled\". The root fill now stays engaged once a widget is scaled (the .w\nscale is kept even at 100 rather than removed), so dragging across 100 is\ncontinuous. Double-clicking the slider still resets to the natural render.",
"is_bot": false,
"headline": "fix: keep widget Scale continuous through 100%",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T12:21:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "09226dca8e2d866cf3615ce0314ef47e6906cad1",
"body": "A widget element gains crop insets (top/right/bottom/left, percent of the\nbox). The kept rectangle is scaled to fill the box, so cropping the top\ndrops a fixed title and cropping the bottom trims content to free room for\nanother element. Crop composes with the \"Scale\" content density into one\nroot t\n[…]\nble to the MCP agent via the element model.\n\nAlso fixes a repo-wide ruff lint slip (nested with-statements + a mutable\nclass default) in the URL-source and page-asset test files, which was\nfailing CI.",
"is_bot": false,
"headline": "feat: per-widget crop control (drop a title / reclaim space)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T11:51:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e7478484255dbc2367f8e485e5d72072757f7da7",
"body": "The zoom control lived inside the scrolling canvas area, so on a canvas\nlarger than the view it scrolled away with the content and could end up\nhovering over the component being edited. Split the workspace into a fixed\nframe plus an inner scroll area and mount the control on the frame, so it\nstays in the bottom-right of the view.",
"is_bot": false,
"headline": "fix: pin canvas zoom control to the viewport, not the scrolling canvas",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T11:38:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f73749d1f81c770fc2886c94cedd9dea1717505f",
"body": "Adds an Assets drawer to the canvas editor: cache a remote image by URL or\nupload one into the dashboard's own folder, then insert or copy its local\nURL for a code element to reference instead of hotlinking. Session-authed\npanels endpoints edit the same folder as the MCP ones and delete cascades\nwit\n[…]\n root scales by counter-sizing\nand reflowing to fill the box, rather than leaving a shrunken copy ringed by\nwhitespace when scaling down (discussion #131). Per-piece \"Zoom parts\"\nscaling is unchanged.",
"is_bot": false,
"headline": "feat: dashboard image assets drawer + fill-the-box content scaling",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T11:33:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c8a16b21b3f05e8b697b174d742b997cf1c3ff8e",
"body": "Each canvas dashboard gets a data/core/page_assets/<page_id>/ folder where\nimages can be cached, so a code element can reference a stable local copy\n(/page-assets/<id>/<name>) instead of hotlinking a remote URL every render.\nRemote fetches go through the SSRF guard and are stored content-addressed;\n\n[…]\nboard. Adds MCP endpoints to cache-by-URL / upload / list / delete assets\nand a loopback-reachable route to serve them during render. Remote images\nstay allowed, so existing dashboards are unaffected.",
"is_bot": false,
"headline": "feat: per-dashboard image asset catalog",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T11:18:34Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d513aa7b08d696ecd6c2eab3ed522c76ca45db51",
"body": "A code element's data source can now be a plain JSON HTTP(S) endpoint\ninstead of a widget or service plugin: set sources: [{url, headers?, name}]\nand the parsed body arrives at ctx.data[name]. Fetching goes through a\nshared SSRF guard (http(s) only, loopback/private/link-local hosts refused,\neach redirect hop re-validated, response size capped); rest_service reuses\nthe same guard. Adds an MCP /probe-url endpoint for field discovery and a\nURL option in the canvas editor's data-source picker.",
"is_bot": false,
"headline": "feat: code elements can source data from a raw API URL",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T11:11:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6730b0eec56c8565828f9ddbc0bb227245564d3f",
"body": "Registration and discovery rejections returned a JSON reason to the\ndevice but logged nothing, so a failed pair was only readable from a\npacket capture. Log each /register and /discover outcome: rejections at\nWARNING with the status, device id, client IP, and returned error;\nsuccesses at INFO. The pairing code is never logged.\n\nCloses #126",
"is_bot": false,
"headline": "feat: log REST pairing and registration outcomes server-side",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T10:40:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "84e81df7c3bfeabf190e103fad3854976de6dd68",
"body": "… restart\n\nREST /register wrote the instance manifest to the data root instead of\ndata/devices/, where the loader scans. The file was orphaned: it dropped\nout of the registry on restart (the device 404'd) and re-pairing failed\nwith \"instance file already exists\". Point create_instance,\nupdate_instance_renderer, and the token persist at data/devices/, and add\na startup migration that relocates any stray manifests already on disk.\n\nCloses #127",
"is_bot": false,
"headline": "fix: write REST instance files into data/devices/ so pairing survives…",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T10:36:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3d3d83b1c571c0724de267d107c691ddb517e610",
"body": "…frames\n\nRegistration stores ids lowercased, but frame/status lookup matched the\nURL id exactly, so a device that kept a mixed-case id paired but 404'd on\nevery frame fetch. Normalise the id on lookup the same way register\nnormalises it on write, and echo the canonical device_id in the register\nresponse (as /discover already does) so firmware adopts the stored id.\n\nCloses #128",
"is_bot": false,
"headline": "fix: resolve device ids case-insensitively so mixed-case pairs fetch …",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T10:25:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3410f0305cc68e7d00dfd35af662993644a5048b",
"body": "The Scale slider resized the element's bounding box around its centre,\nduplicating the drag handles. It now scales the widget's rendered content\nvia the root part while the box keeps its dimensions; box resizing stays\non the handles and the Size fields.",
"is_bot": false,
"headline": "fix: canvas Scale slider zooms content inside a fixed box",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T10:20:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "36494489d8f8777c121b00ef6de832ad07623675",
"body": "…editor (#130)\n\nThe canvas config drawer loads a widget's options form after page load,\nbut the canvas editor template is standalone and never pulled in the\nicon-picker / entity-overrides modules, and the multi-select filter\nwiring existed only in the grid editor. For the Home Assistant Entities\nwid\n[…]\nity\nlabel / icon / number-format overrides inert. Move the filter into the\nshared components module, load the two modules on the canvas page, and\ninitialise all three when the drawer injects the form.",
"is_bot": false,
"headline": "fix: wire HA entity filter, icon picker, and overrides in the canvas …",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T09:59:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b2febc8467d0a022d9926e0945091b89a63a7d88",
"body": "When the server is reached on a port that differs from its internal bind\n(reverse proxy, k8s Service, or Docker port map from external 4567 to the\ncontainer's 8765), render routes built the in-process loopback fetch from\nthe browser's port, so the headless renderer hit 127.0.0.1:<external>\nwhere nothing listens and the render was refused. The tesserae CLI now\nrecords its real bind port in TESSERAE_BIND_PORT, which the renderer\nalready prefers, so /compose is always fetched on the bound port.",
"is_bot": false,
"headline": "fix: canvas preview fails behind a non-default external port (#129)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T09:30:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3fb682ea1170a28f3897b200884bec2d647ac13c",
"body": "Specify the report fields devices add to the ota heartbeat object\n(phase, reason, target_fw, attempt_id, detail) and refresh the status\nline now that the signing Worker, R2 hosting, and per-kind rollout are\nlive.",
"is_bot": false,
"headline": "docs: OTA device state-reporting shape + rollout status (#121)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T09:19:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5837b651682f1e510cc0c2178e56a36b7887e546",
"body": "The per-device render fan-out decision read the plugin registry from\ncurrent_app, which is absent on the scheduler and rotation push threads.\nThose pushes silently fell back to a single render, so a grid panel kept\nshowing the min-across-all-devices battery even though a manual Send\nresolved the target correctly. The push manager now takes a registry\naccessor and threads it into the detection.",
"is_bot": false,
"headline": "fix: per-device status bar on scheduled + rotation pushes (#125)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T09:19:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ad6d84fd819bc488197abfdfb6c308477ab52891",
"body": "…(#125)\n\nThe status bar could still show a min-across-all-devices battery in two\ncases the grid-cell detection fix did not cover. Canvas renders dropped\nthe target device before the widget fetch, so a per-device push resolved\nthe aggregate on every panel; the target now threads through\n_render_canva\n[…]\n and the fetch. Editor previews\n(hover thumbnail, live iframe) carry no target, so grid and canvas\npreviews both showed the aggregate; a non-push preview now defaults to\nthe page's first bound device.",
"is_bot": false,
"headline": "fix: thread target device through canvas render + preview status bar …",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T01:20:27Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "16c216e2a940e9b68212f7e53d847c8201f1cae9",
"body": "The per-device render detection only scanned grid cells, so a canvas\ndashboard carrying the status bar rendered once per panel instead of per\ndevice. With no target device the status widget fell back to the lowest\nbattery across all devices, showing the wrong panel's battery / temperature\n/ humidity / Wi-Fi. Scan canvas elements too (a placed widget or a code\nelement's data source), so each panel's status bar reads its own telemetry.",
"is_bot": false,
"headline": "fix: per-device status bar on canvas dashboards (#125)",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T00:59:39Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "31e94cdf7d3535a3f58e7540bf472b195b5bfb8b",
"body": "Use the shared page-head + lede header markup (accent icon via the ph class)\ninstead of a custom flattened header, and drop the overriding page-head rules\nfrom dx-decks.css so the global styling applies.",
"is_bot": false,
"headline": "style: Decks header matches the Rotations page",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-21T00:13:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f9c7af203811e81477f211939b0bdd97139b5b89",
"body": "Add dx-decks.css (loaded in _base.html) styling the deck cards, meta chips,\nactions row, suggestions strip, per-page refresh table, device chips, and the\nadvanced graph fold, using the app's design tokens so it matches Rotations /\nSchedules instead of falling back to unstyled defaults.",
"is_bot": false,
"headline": "style: dedicated stylesheet for the Decks page",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-20T23:44:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "de00f07f1cd8f564c4d613832adb6a22a05d3658",
"body": "Make the Decks page a management surface rather than a graph editor. Navigation\nis authored in the canvas (tap/swipe page links) and suggested into a deck; the\nDecks page owns the deck-level concerns: refresh cadence (deck + per-page),\ndevices, entry, enable, delete. Add \"Sync from links\" to re-derive a deck's\ngraph + zones from the current page links, and demote the raw JSON graph editor\nto an Advanced fold. The management update preserves the graph and edits only\nmetadata + per-page refresh.",
"is_bot": false,
"headline": "feat: reshape the Decks page around the canvas editor",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-20T23:35:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "d27a0ffdb32b80c07da4b31c37cb1d851d2a1036",
"body": "Add an optional refresh_interval_minutes to a deck page, overriding the deck\ndefault: the scheduler now tracks last-warm per (deck, device, page) and warms\neach page on its own effective cadence, so a volatile tile can re-warm often\nwhile a static page refreshes rarely in the same deck. None inherits the deck\ncadence; 0 warms only on first navigation. Flows through the graph editor and\nthe MCP create_deck tool.",
"is_bot": false,
"headline": "feat: per-page refresh cadence in decks",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-20T23:18:42Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "94ae519caddcf46d5b0899d976058c5bea0c7131",
"body": "Add MCP endpoints and bridge tools for the three scheduling / navigation\nprimitives: list / create / delete for rotations and schedules, and list /\ncreate / delete / suggest for decks. Create validates the JSON against the\nmodel and returns 422 with field-level details. suggest_decks derives a\nready\n[…]\nid> links already on page elements, so an agent\nthat has wired inter-page navigation can offer a deck without hand-building\nthe graph. Handshake instructions gain a wire-up section covering the three.",
"is_bot": false,
"headline": "feat: expose rotations, schedules, and decks over the MCP",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-20T23:08:38Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a239d44124e10e04f4c92dc7ec402e12dfba69f3",
"body": "Derive suggested decks from the navigation links already authored in the\ncanvas editor: a cell's page:<id> tap becomes a zone link (the cell's rect\nnormalised to the panel) and a page:<id> swipe becomes a button link. The\nDecks page finds connected clusters of linked pages and offers a one-click\ncreate for each, with the graph and touch zones pre-filled, excluding pages\nalready in a deck. Also fixes the decks template block name and two component\nmacro calls.",
"is_bot": false,
"headline": "feat: suggest decks from page:<id> tap/swipe links between pages",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-20T22:56:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7cb6e7e0646656ec41a1518e2e7d90b54486f55c",
"body": "Complete the Decks feature: create the deck stores in the app factory and\npass them to the button service so button / touch navigation runs in-app; add\na scheduler pass that re-warms each deck's pages in the background on its\nrefresh cadence (off the tick thread, non-overlapping); and add a Decks admin\npage (create / edit / toggle / delete, with the page graph edited as validated\nJSON) plus a nav entry. Editing or deleting a deck clears the affected\ndevices' warmed frames and nav position.",
"is_bot": false,
"headline": "feat: wire Decks end-to-end with a Settings page and background refresh",
"author_name": "Kayden D'Mello",
"author_login": "dmellok",
"committed_at": "2026-07-20T22:41:12Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 74,
"commits_last_year": 1089,
"latest_release_at": "2026-07-19T11:03:22Z",
"latest_release_tag": "v0.152.0",
"releases_from_tags": false,
"days_since_last_push": 0,
"active_weeks_last_year": 9,
"days_since_latest_release": 7,
"mean_days_between_releases": 1.4
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": true,
"health_percentage": 100,
"has_issue_template": false,
"has_code_of_conduct": true,
"has_pull_request_template": true
},
"ecosystem": {
"packages": [
{
"name": "tesserae",
"exists": true,
"license": "MIT",
"keywords": [
"llm",
"wiki",
"knowledge-graph",
"mcp",
"obsidian",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12"
],
"ecosystem": "pypi",
"matches_repo": null,
"registry_url": "https://pypi.org/project/tesserae/",
"is_deprecated": false,
"latest_version": "0.28.2",
"repository_url": null,
"versions_count": 42,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": 3322,
"first_published_at": "2026-05-17T16:55:55.458536Z",
"latest_published_at": "2026-07-27T01:56:53.923164Z",
"latest_version_yanked": null,
"days_since_latest_publish": 0
}
]
},
"popularity": {
"forks": 17,
"stars": 296,
"watchers": 2,
"fork_history": {
"days": [
{
"date": "2026-06-15",
"count": 2
},
{
"date": "2026-06-16",
"count": 2
},
{
"date": "2026-06-25",
"count": 1
},
{
"date": "2026-06-27",
"count": 1
},
{
"date": "2026-06-29",
"count": 1
},
{
"date": "2026-07-02",
"count": 1
},
{
"date": "2026-07-08",
"count": 1
},
{
"date": "2026-07-09",
"count": 1
},
{
"date": "2026-07-13",
"count": 1
},
{
"date": "2026-07-17",
"count": 1
},
{
"date": "2026-07-19",
"count": 1
},
{
"date": "2026-07-21",
"count": 1
},
{
"date": "2026-07-22",
"count": 1
},
{
"date": "2026-07-23",
"count": 2
}
],
"complete": true,
"collected": 17,
"total_forks": 17
},
"star_history": null,
"open_issues_and_prs": 39
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": true,
"has_mcp_signal": true,
"bootstrap_files": [],
"api_schema_files": [
"schema/openapi.yaml"
],
"has_devcontainer": true,
"typecheck_configs": [],
"toolchain_manifests": [],
"largest_source_bytes": 162516,
"source_files_sampled": 471,
"oversized_source_files": 12,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"dependencies": {
"manifests": [
"package.json",
"pyproject.toml"
],
"advisories": {
"error": null,
"scope": null,
"source": null,
"findings": [],
"collected": false,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"npm",
"pypi"
],
"dependencies": [
{
"name": "flask",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=3.0,<4"
},
{
"name": "pydantic",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=2.6,<3"
},
{
"name": "jsonschema",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=4.21,<5"
},
{
"name": "pillow",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=10.2,<13"
},
{
"name": "pillow-heif",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=1.1,<2"
},
{
"name": "numpy",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=1.26,<3"
},
{
"name": "paho-mqtt",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=2.0,<3"
},
{
"name": "playwright",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=1.60,<1.61"
},
{
"name": "amqtt",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.11,<1"
},
{
"name": "icalendar",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=5.0,<7"
},
{
"name": "recurring-ical-events",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=2.1,<4"
},
{
"name": "defusedxml",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.7,<1"
},
{
"name": "waitress",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=3.0,<4"
},
{
"name": "tzdata",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": null
},
{
"name": "cryptography",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=42,<50"
},
{
"name": "zeroconf",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.130,<1"
},
{
"name": "segno",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=1.6,<2"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 18,
"open_issues": 39,
"closed_ratio": 0.567,
"closed_issues": 51,
"closed_unmerged_prs": 2
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "dmellok",
"commits": 1098,
"avatar_url": "https://avatars.githubusercontent.com/u/180086677?v=4"
},
{
"type": "User",
"login": "charmmmz",
"commits": 8,
"avatar_url": "https://avatars.githubusercontent.com/u/85142325?v=4"
},
{
"type": "User",
"login": "bablokb",
"commits": 2,
"avatar_url": "https://avatars.githubusercontent.com/u/9638355?v=4"
},
{
"type": "User",
"login": "mattlung",
"commits": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/3390750?v=4"
}
],
"contributors_sampled": 4,
"top_contributor_share": 0.99
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml",
"docker.yml",
"docs.yml",
"publish-tesserae-mcp.yml",
"release.yml",
"sync-addon.yml"
],
"has_docs_dir": true,
"linter_configs": [
"eslint.config.js"
],
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"package-lock.json",
"uv.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": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 0,
"reason": "project has 0 contributing companies or organizations -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 0,
"reason": "project was created within the last 90 days. Please review its contents carefully",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 10,
"reason": "security policy file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 0,
"reason": "25 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "1e3d096a6b054869aeb9ee431035f8c2ef94860f",
"ran_at": "2026-07-27T05:53:30Z",
"aggregate_score": 3.2,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": true,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-27T05:52:33Z",
"oldest_open_prs": [],
"last_merged_pr_at": "2026-07-24T06:45:46Z",
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": [
{
"number": 9,
"created_at": "2026-06-03T09:55:40Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 13,
"created_at": "2026-06-09T02:57:56Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 14,
"created_at": "2026-06-09T23:23:10Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 16,
"created_at": "2026-06-20T09:31:00Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 17,
"created_at": "2026-06-20T09:31:04Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 22,
"created_at": "2026-06-20T09:32:01Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 23,
"created_at": "2026-06-21T04:47:52Z",
"last_comment_at": "2026-06-23T06:38:42Z",
"last_comment_author": "dmellok"
},
{
"number": 33,
"created_at": "2026-06-28T23:21:16Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 36,
"created_at": "2026-06-30T07:16:18Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 37,
"created_at": "2026-06-30T07:18:32Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 41,
"created_at": "2026-07-01T23:42:14Z",
"last_comment_at": "2026-07-04T07:30:19Z",
"last_comment_author": "bablokb"
},
{
"number": 45,
"created_at": "2026-07-02T12:19:27Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 46,
"created_at": "2026-07-02T20:48:34Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 51,
"created_at": "2026-07-04T12:05:21Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 52,
"created_at": "2026-07-04T12:27:30Z",
"last_comment_at": "2026-07-07T11:39:29Z",
"last_comment_author": "dmellok"
},
{
"number": 55,
"created_at": "2026-07-04T22:18:31Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 56,
"created_at": "2026-07-04T22:18:37Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 57,
"created_at": "2026-07-04T22:18:45Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 58,
"created_at": "2026-07-05T00:55:51Z",
"last_comment_at": null,
"last_comment_author": null
},
{
"number": 59,
"created_at": "2026-07-05T00:59:46Z",
"last_comment_at": null,
"last_comment_author": null
}
]
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/dmellok/tesserae",
"host": "github.com",
"name": "tesserae",
"owner": "dmellok"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 63,
"inputs": {
"security": 32,
"vitality": 76,
"community": 67,
"governance": 50,
"engineering": 84
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 76,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 60,
"inputs": {
"commits_last_year": 1089,
"human_commit_share": 1,
"days_since_last_push": 0,
"active_weeks_last_year": 9
},
"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": "9/52 weeks with commits",
"points": 6.2,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 9
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "1089 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 1089
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 100,
"inputs": {
"releases_count": 74,
"latest_release_tag": "v0.152.0",
"releases_from_tags": false,
"days_since_latest_release": 7,
"mean_days_between_releases": 1.4
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "74 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 74
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 7 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 7
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~1.4 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 1.4
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "unverified",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": "repository_too_young",
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": null,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "maintenance record not established from the collected data",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_unverified",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "moderate",
"name": "Community & Adoption",
"value": 67,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "moderate",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"forks": 17,
"stars": 296,
"watchers": 2,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "296 stars",
"points": 40.1,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 296
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "17 forks",
"points": 10,
"status": "partial",
"details": [
{
"code": "forks",
"params": {
"count": 17
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "2 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 2
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "excellent",
"name": "Community health",
"note": null,
"notes": [],
"value": 92,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": true,
"has_issue_template": false,
"has_code_of_conduct": true,
"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 (AGPL-3.0)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "AGPL-3.0"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 18,
"status": "met",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 13.5,
"status": "met",
"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
}
]
},
{
"key": "ecosystem_adoption",
"band": "moderate",
"name": "Ecosystem adoption (downloads)",
"note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"registry_dependents"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 59,
"inputs": {
"packages": [
"tesserae"
],
"dependents": null,
"ecosystems": "pypi",
"total_downloads": null,
"monthly_downloads": 3322
},
"components": [
{
"key": "monthly_downloads",
"name": "Monthly downloads",
"detail": "3,322 downloads/month across pypi",
"points": 47,
"status": "partial",
"details": [
{
"code": "downloads_monthly",
"params": {
"count": 3322,
"ecosystems": "pypi"
}
}
],
"max_points": 80
},
{
"key": "registry_dependents",
"name": "Registry dependents",
"detail": "not reported by this ecosystem",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_reported_by_this_ecosystem",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "moderate",
"name": "Sustainability & Governance",
"value": 50,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 15,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 4,
"top_contributor_share": 0.99
},
"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 99% of commits",
"points": 0.2,
"status": "partial",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 99
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "4 contributors",
"points": 5.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 4
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "moderate",
"name": "Issue & PR responsiveness",
"note": null,
"notes": [],
"value": 61,
"inputs": {
"merged_prs": 18,
"open_issues": 39,
"closed_issues": 51,
"issue_closed_ratio": 0.567,
"closed_unmerged_prs": 2
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "57% of issues closed",
"points": 26.5,
"status": "partial",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 57
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "18/20 decided PRs merged",
"points": 34.4,
"status": "partial",
"details": [
{
"code": "decided_prs_merged",
"params": {
"merged": 18,
"decided": 20
}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 42,
"inputs": {
"followers": 9,
"owner_type": "User",
"is_verified": null,
"owner_login": "dmellok",
"public_repos": 70,
"account_age_days": 693
},
"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": "9 followers of dmellok",
"points": 7.2,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 9,
"login": "dmellok"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "70 public repos, account ~1 yr old",
"points": 16.8,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 70
}
},
{
"code": "account_age_years",
"params": {
"years": 1
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"tesserae"
],
"ecosystems": "pypi",
"any_deprecated": false,
"min_days_since_publish": 0
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on pypi",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "pypi"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 0 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 0
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "42 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 42
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "good",
"name": "Engineering Quality",
"value": 84,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "good",
"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": 80,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "6 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 6
}
}
],
"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": "eslint.config.js",
"points": 16,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "eslint.config.js"
}
}
],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "excellent",
"name": "Documentation",
"note": null,
"notes": [],
"value": 90,
"inputs": {
"topics": [
"dashboard",
"e-ink",
"esp32",
"home-assistant",
"raspberry-pi",
"self-hosted",
"tesserae"
],
"has_wiki": false,
"homepage": "https://tesserae.ink",
"has_readme": true,
"has_docs_dir": true,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": "https://tesserae.ink",
"points": 15,
"status": "met",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": "7 topics",
"points": 10,
"status": "met",
"details": [
{
"code": "topics_count",
"params": {
"count": 7
}
}
],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "at_risk",
"name": "Security",
"value": 32,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "at_risk",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests, Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests",
"signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 32,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 16,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 2,
"scorecard_aggregate": 3.2
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"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": "25 existing vulnerabilities detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 3
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "at_risk",
"name": "AI Readiness",
"value": 46,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "at_risk",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.99,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "no CLAUDE.md / AGENTS.md / editor rules",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_instructions",
"params": {}
}
],
"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": "at_risk",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 43,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"package-lock.json",
"uv.lock"
],
"has_dockerfile": true,
"typed_language": false,
"bootstrap_files": [],
"has_devcontainer": true,
"has_linter_config": true,
"typecheck_configs": [],
"agent_commit_share": 0,
"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": "eslint.config.js",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "eslint.config.js"
}
}
],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "devcontainer, Dockerfile, lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "devcontainer, Dockerfile, lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 100",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"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": "moderate",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 54,
"inputs": {
"primary_language": "Python",
"largest_source_bytes": 162516,
"source_files_sampled": 471,
"oversized_source_files": 12
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Python without a type-check config",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_typecheck_config_language",
"params": {
"language": "Python"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "12/471 source files over 60KB",
"points": 53.6,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 471,
"oversized": 12
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "moderate",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 60,
"inputs": {
"example_dirs": [],
"has_mcp_signal": true,
"api_schema_files": [
"schema/openapi.yaml"
]
},
"components": [
{
"key": "api_schema_openapi_graphql_proto",
"name": "API schema (OpenAPI/GraphQL/proto)",
"detail": "schema/openapi.yaml",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "schema/openapi.yaml"
}
}
],
"max_points": 40
},
{
"key": "mcp_server",
"name": "MCP server",
"detail": null,
"points": 20,
"status": "met",
"details": [],
"max_points": 20
},
{
"key": "runnable_examples",
"name": "Runnable examples",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"deps.dev does not index pypi:tesserae@0.28.2; advisories assessed against the repository dependency graph instead"
],
"report_type": "repository",
"generated_at": "2026-07-27T05:53:39.550179Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/d/dmellok/tesserae.svg",
"full_name": "dmellok/tesserae",
"license_state": "standard",
"license_spdx": "AGPL-3.0"
}