Gallery › robotparts › robotparts sources
robotparts sources
Every source robotparts.dev holds an asset from, grouped by kind, with a stale badge where an asset or a link check
has aged past its kind's threshold: the freshness table, in a .base file.
The .base file and its data
Every tab above is one entry of this file; the views read these rows. ⋯ in the toolbar copies the current view as YAML.
# Sources: robotparts' /sources/ page (build/site_pages.py sources_page, site/static/site.js freshness) as a .base
# file. One row per source, grouped by kind, each with its freshness badge as of 2026-11-25 (source/make.py says why).
# Obsidian Bases grammar plus data-ui's keys (docs/CONTRACT.md §5).
data: sources.json
facets:
- kind
- freshness
- rule
- { property: assets, as: range }
views:
- type: table
name: By kind
order: [name, freshness, stale_kinds, rule, parts, assets, last_accessed, first_seen, links_checked, dead, moved, refresh]
groupBy: { property: kind, direction: ASC }
sort:
- { property: last_accessed, direction: ASC }
summaries: { parts: Sum, assets: Sum }
- type: table
name: Needs refresh
filters: 'freshness == "needs refresh"'
order: [name, stale_kinds, last_accessed, age_days, assets, refresh]
groupBy: { property: kind, direction: ASC }
sort:
- { property: last_accessed, direction: ASC }
- type: list
name: List
order: [name, freshness, last_accessed, assets, rule]
groupBy: { property: kind, direction: ASC }
sort:
- { property: last_accessed, direction: ASC }
separator: " · "
- type: record
name: Source page
record:
sections:
- { name: The source, properties: [kind, rule, hosts, parts, assets] }
- { name: Freshness, properties: [freshness, stale_kinds, last_accessed, via_atlas, age_days, first_seen, oldest] }
- { name: Links, properties: [links, links_checked, oldest_check, dead, moved] }
- { name: Refresh, properties: [refresh] }
// sources.json: 43 rows, 29 KB; the first 3
{
"id": "robotparts-sources",
"title": "Sources",
"titleProperty": "name",
"linkProperty": "page",
"source": "robotparts dist/site/v2/sources.json, release 2026.10.25.1; 43 of 196 sources, at most 8 per kind, oldest access first; freshness as of 2026-11-25",
"properties": {
"name": {
"type": "text",
"label": "Source"
},
"id": {
"type": "text",
"label": "Id",
"hidden": true
},
"kind": {
"type": "text",
"label": "Kind",
"display": "badge",
"note": "maker: a maker's own site (makers.toml); seller: a shop that sells the part; distributor: a distributor (an atlas labels its values distributor); atlas: an atlas: the repository that owns the records; registry/API: a package registry or an API a reading came from; code host: a code host: repositories, pinned files and evidence; robotparts: robotparts.dev itself; image host: a host that serves only images; web: any other web page"
},
"rule": {
"type": "text",
"label": "Rule",
"note": "may robotparts read it"
},
"hosts": {
"type": "list",
"label": "Other hosts"
},
"parts": {
"type": "number",
"label": "Parts"
},
"assets": {
"type": "number",
"label": "Assets"
},
"last_accessed": {
"type": "date",
"label": "Last accessed",
"note": "the newest date among its assets"
},
"via_atlas": {
"type": "boolean",
"label": "Dated by atlas commit"
},
"first_seen": {
"type": "date",
"label": "First seen"
},
"age_days": {
"type": "number",
"label": "Age",
"unitText": "days",
"note": "days from last access to 2026-11-25"
},
"links": {
"type": "number",
"label": "URLs"
},
"links_checked": {
"type": "number",
"label": "Checked"
},
"oldest_check": {
"type": "date",
"label": "Oldest link check"
},
"dead": {
"type": "number",
"label": "Dead"
},
"moved": {
"type": "number",
"label": "Moved"
},
"freshness": {
"type": "text",
"label": "Freshness",
"display": "badge",
"colors": {
"needs refresh": 8,
"fresh": 0,
"date not recorded": 0
},
"note": "as of 2026-11-25, by freshness.toml's thresholds"
},
"stale_kinds": {
"type": "list",
"label": "Stale",
"display": "badge",
"colors": {
"link": 8,
"spec value": 8,
"citation": 8,
"port": 8,
"photo": 8,
"CAD": 8,
"sim model": 8,
"document": 8,
"software": 8,
"software reading": 8,
"price observation": 8,
"measurement": 8,
"logo": 8,
"link checks": 8
},
"note": "the kinds whose oldest asset is past its threshold"
},
"oldest": {
"type": "text",
"label": "Oldest asset by kind",
"hidden": true
},
"refresh": {
"type": "text",
"label": "How it refreshes"
},
"page": {
"type": "text",
"label": "Page",
"hidden": true
}
},
"rows": [
{
"id": "cdn.shopify.com",
"name": "cdn.shopify.com",
"kind": "web",
"rule": "not reviewed",
"hosts": [],
"parts": 1145,
"assets": 1445,
"last_accessed": "2026-10-08",
"via_atlas": false,
"first_seen": "2026-10-08",
"age_days": 48,
"links": 1326,
"links_checked": 1326,
"oldest_check": "2026-10-26",
"dead": null,
"moved": null,
"freshness": "fresh",
"stale_kinds": [],
"oldest": "photo 2026-10-08, spec value 2026-10-09",
"refresh": "python3 ~/robotparts/tools/live.py ingest cdn.shopify.com",
"page": "https://robotparts.dev/sources/cdn.shopify.com/"
},
{
"id": "shop.smc-powers.com",
"name": "shop.smc-powers.com",
"kind": "seller",
"rule": "not reviewed",
"hosts": [],
"parts": 1,
"assets": 23,
"last_accessed": "2026-10-08",
"via_atlas": false,
"first_seen": "2026-10-08",
"age_days": 48,
"links": 2,
"links_checked": 0,
"oldest_check": null,
"dead": null,
"moved": null,
"freshness": "needs refresh",
"stale_kinds": [
"price observation"
],
"oldest": "link 2026-10-08, price observation 2026-10-08, spec value 2026-10-08",
"refresh": null,
"page": "https://robotparts.dev/sources/shop.smc-powers.com/"
},
{
"id": "actuator-atlas",
"name": "actuator-atlas",
"kind": "atlas",
"rule": "atlas",
"hosts": [],
"parts": 1146,
"assets": 21764,
"last_accessed": "2026-10-09",
"via_atlas": true,
"first_seen": "2026-10-09",
"age_days": 47,
"links": null,
"links_checked": null,
"oldest_check": null,
"dead": null,
"moved": null,
"freshness": "fresh",
"stale_kinds": [],
"oldest": "spec value 2026-10-09",
"refresh": null,
"page": "https://robotparts.dev/sources/actuator-atlas/"
}
]
}skin.css, README.md
/* robotparts' skin: its own tokens (site/static/site.css, release 2026.10.25), then the one block that maps them onto
data-ui's --data-* (docs/SPEC.md §10). The gallery scopes a skin to .data-ui-skin; on robotparts.dev the same
mapping sits at :root. */
.data-ui-skin {
--bg: #ffffff; --bg2: #f6f7f8; --hover: #f1f5fb; --ink: #15181c; --ink2: #545c66;
--rule: #d9dde2; --rule2: #e9ebee; --accent: #0a5bb5; --on-accent: #ffffff; --warn: #9a3412;
--sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Liberation Sans", sans-serif;
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", "DejaVu Sans Mono", monospace;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) .data-ui-skin {
--bg: #111317; --bg2: #181b20; --hover: #1a2433; --ink: #e6e8eb; --ink2: #a4abb4;
--rule: #30353c; --rule2: #252930; --accent: #6ea8ec; --on-accent: #0b1220; --warn: #f0a070;
}
}
:root[data-theme="dark"] .data-ui-skin {
--bg: #111317; --bg2: #181b20; --hover: #1a2433; --ink: #e6e8eb; --ink2: #a4abb4;
--rule: #30353c; --rule2: #252930; --accent: #6ea8ec; --on-accent: #0b1220; --warn: #f0a070;
}
/* the mapping: this is all a vanilla app writes */
.data-ui-skin {
--data-bg: var(--bg); --data-fg: var(--ink); --data-muted: var(--ink2); --data-subtle: var(--bg2);
--data-border: var(--rule); --data-rule: var(--rule2); --data-hover: var(--hover); --data-accent: var(--accent);
--data-on-accent: var(--on-accent); --data-warn: var(--warn); --data-font: var(--sans); --data-mono: var(--mono);
--data-radius: 6px;
}
# robotparts sources
Every source robotparts.dev holds an asset from, grouped by kind, with a stale badge where an asset or a link check
has aged past its kind's threshold: the freshness table, in a `.base` file.
- **App:** robotparts
- **Replaces:** robotparts' hand-rolled `/sources/` page: `sources_page()` in `build/site_pages.py` in `~/robotparts`
(the table, its facet form and its counts) and the freshness script in `site/static/site.js` that adds the
"needs refresh" badges in the browser. Here the table, the grouping, the rail and the badges are the kit's.
- **Shows:** the table grouped by kind with Sum summaries, a badge column whose colour is a slot (`colors`), a preset
that filters to what needs a refresh, the `list` view of the same rows, and the `record` view as a source page.
- **Data:** `sources.json`, 43 of the release's 196 sources (at most 8 per kind, oldest access first), written by
`source/make.py` from robotparts' `dist/site/v2/sources.json` (release 2026.10.25.1). The verdict is
computed once, there, with freshness.toml's thresholds, as of 2026-11-25: one month after the release, so prices
and software readings (stale after 30 days) have aged out. On the release day itself every source reads fresh.
- **Skin:** `skin.css`, robotparts' token mapping.
The original UI it replaces
robotparts' hand-rolled /sources/ page: sources_page() in build/site_pages.py in ~/robotparts (the table, its facet form and its counts) and the freshness script in site/static/site.js that adds the "needs refresh" badges in the browser. Here the table, the grouping, the rail and the badges are the kit's.
What it shows
the table grouped by kind with Sum summaries, a badge column whose colour is a slot (colors), a preset that filters to what needs a refresh, the list view of the same rows, and the record view as a source page.
Data
sources.json, 43 of the release's 196 sources (at most 8 per kind, oldest access first), written by source/make.py from robotparts' dist/site/v2/sources.json (release 2026.10.25.1). The verdict is computed once, there, with freshness.toml's thresholds, as of 2026-11-25: one month after the release, so prices and software readings (stale after 30 days) have aged out. On the release day itself every source reads fresh.
Skin
skin.css, robotparts' token mapping.