Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,20 @@ export default defineConfig({
collapsed: true,
items: grouped('cascade'),
},
{
label: 'HotLoop Transmitter',
collapsed: true,
items: [
{ slug: 'transmitter/overview', label: 'Overview' },
{ slug: 'transmitter/install', label: 'Install' },
{ slug: 'transmitter/api', label: 'API' },
{ slug: 'transmitter/wire-format', label: 'What goes on the wire' },
{ slug: 'transmitter/timing', label: 'What it adds to the task' },
{ slug: 'transmitter/proof', label: 'What was run' },
{ slug: 'transmitter/roadmap', label: 'Roadmap' },
{ slug: 'releases/transmitter-1-0-0', label: 'Release notes' },
],
},
{
label: 'Release notes',
collapsed: true,
Expand Down
3 changes: 0 additions & 3 deletions scripts/forbidden.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@
// own, so no customer is named, not even by a project code, and a product that has not shipped
// is not on the page. The build and the sync both fail on a match, in the generated pages, the
// built HTML, the search index, and the strings the social cards are drawn from.
//
// When HotLoop Transmitter ships, take it off this list in the same change that adds it to the site.
export const FORBIDDEN = [
[/\bUT3\b/i, 'UT3, a customer project code'],
[/\bTrane\b/i, 'Trane, a customer'],
[/tranetech/i, 'tranetech, a customer tenant'],
[/expert[ -]?lift/i, 'Expert Lift, a customer'],
[/a customer'?s? production (program|plc)/i, 'a customer program, described by whose it is'],
[/HotLoop Transmitter/, 'HotLoop Transmitter, which is not on the public lineup until it ships'],
];

// Returns one line per match, with a little of the text around it.
Expand Down
6 changes: 5 additions & 1 deletion scripts/sync-docs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ for (const [slug, p] of mainPages) {
.sort((a, b) => b.slug.localeCompare(a.slug, undefined, { numeric: true }))
.map((m) => `- [${m.title}](/${m.slug}/)${m.status === 'next' ? ' (on main, next release)' : ''}`)
.join('\n');
const fm = ['---', MARK, 'title: "Release notes"', 'description: "What shipped in every HotLoop core, HotLoop Flow and HotLoop Cascade release, and what is on main waiting for the next one, newest first."', 'editUrl: false', '---', ''].join('\n');
const fm = ['---', MARK, 'title: "Release notes"', 'description: "What shipped in every HotLoop core, Flow, Cascade and Transmitter release, and what is on main waiting for the next one, newest first."', 'editUrl: false', '---', ''].join('\n');
out.set('releases/index.md', `${fm}
Every release has its own page, written the day it shipped. A note marked "on main, next release" describes a release that is not out yet, so nothing in it is in what you have installed. The latest HotLoop core release is ${releases.hotloop.version}, the latest Flow release is ${releases.flow.version}, and the latest Cascade release is ${releases.cascade.version}.

Expand All @@ -484,6 +484,10 @@ ${rows('flow')}
## HotLoop Cascade

${rows('cascade')}

## HotLoop Transmitter

- [HotLoop Transmitter 1.0.0 release notes](/releases/transmitter-1-0-0/)
`);
}

Expand Down
15 changes: 9 additions & 6 deletions scripts/sync-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ export const REPOS = {
cascade: { slug: 'HotLoop-io/hotloop-cascade', private: true, releaseName: 'HotLoop Cascade' },
};

// The six sections of the site, in the order the product picker shows them.
// The seven sections of the site, in the order the product picker shows them.
export const PRODUCTS = [
{ id: 'iot', name: 'HotLoop IoT', repo: 'hotloop', tagline: 'The automation base, built in Go for OT.' },
{ id: 'edge', name: 'HotLoop Edge', repo: 'hotloop', tagline: 'IoT plus the machine layer.' },
{ id: 'gateway', name: 'HotLoop Gateway', repo: 'hotloop', tagline: 'Everything, for the whole site.' },
{ id: 'edge-relay', name: 'HotLoop Edge Relay', repo: 'hotloop', tagline: 'Poll, forward, survive.' },
{ id: 'flow', name: 'HotLoop Flow', repo: 'flow', tagline: 'Node-RED compatible flows on a Go runtime.' },
{ id: 'cascade', name: 'HotLoop Cascade', repo: 'cascade', tagline: 'The plant talking to everything else.' },
// Hand-written: the library's repo is private and its pages are plain files in src/content/docs/transmitter.
{ id: 'transmitter', name: 'HotLoop Transmitter', repo: null, tagline: 'OPC UA PubSub from inside the PLC.' },
];

const ws = (s) => new RegExp(s.trim().split(/\s+/).map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('\\s+'), 'g');
Expand Down Expand Up @@ -100,7 +102,7 @@ export const PAGES = [
{ product: 'shared', group: 'Install', slug: 'install/helm', repo: 'hotloop', file: 'docs/DEPLOYMENT.md', title: 'k3s and Helm', description: 'Deploy any HotLoop chart on k3s or any Kubernetes: the values worth setting, the database choice, upgrades, rollbacks and what a good install looks like.' },
{ product: 'shared', group: 'Install', slug: 'install/quadlet', repo: 'hotloop', file: 'deploy/quadlet/README.md', stopAt: 'Updates', title: 'Podman Quadlet', description: 'Run HotLoop as real systemd services on a Pi or small industrial PC with Podman Quadlet, with no Docker, no Compose and no cluster.' },
{ product: 'shared', group: 'Install', slug: 'install/auto-update', repo: 'hotloop', file: 'deploy/quadlet/README.md', sections: ['Updates'], title: 'The :stable auto-update', description: 'Every box follows the stable tag and Podman moves it. What an update does, what a rollback cannot undo, and how to hold updates until you say.' },
{ product: 'shared', group: 'Lineup', slug: 'products', repo: 'hotloop', file: 'docs/PRODUCTS.md', title: 'HotLoop products: six on three release lines', description: 'Six products on three release lines, what each of the four core products has, which database each runs, how to install them and how to move a site up a product.' },
{ product: 'shared', group: 'Lineup', slug: 'products', repo: 'hotloop', file: 'docs/PRODUCTS.md', title: 'HotLoop products: seven on four release lines', description: 'Seven products on four release lines, what each core product has, which database each runs, how to install them and how to move a site up.' },
{ product: 'shared', group: 'Lineup', slug: 'roadmap', repo: 'hotloop', file: 'docs/ROADMAP.md', title: 'HotLoop roadmap', description: "What HotLoop is, what is left to build and what is broken, in the order it gets done, for HotLoop core. Flow and Cascade link their own." },

// ---- HotLoop Flow ----
Expand Down Expand Up @@ -203,20 +205,21 @@ Object.assign(SLUG_RULES, {
roadmap: [
// The roadmap is the core's. Say so, and say where the other two lines keep theirs. Links are HTML because the link pass runs after the rules and would drop a site path.
[ws('HotLoop core ships as four products out of one codebase. See [Products](#products).'),
'HotLoop is six products for the plant floor: four that grow with a site (IoT, Edge, Gateway, and Edge Relay), plus Flow for wiring and Cascade for workflows. This roadmap is for HotLoop core, the four products that come out of one codebase. See [Products](#products). Flow and Cascade keep their own, in <a href="/flow/roadmap/">the Flow roadmap</a> and <a href="/cascade/roadmap/">the Cascade roadmap</a>.'],
'HotLoop is seven products for the plant floor: four that grow with a site (IoT, Edge, Gateway, and Edge Relay), plus Flow for wiring, Cascade for workflows, and Transmitter for putting a PLC\'s values on the wire. This roadmap is for HotLoop core, the four products that come out of one codebase. See [Products](#products). Flow, Cascade, and Transmitter keep their own, in <a href="/flow/roadmap/">the Flow roadmap</a>, <a href="/cascade/roadmap/">the Cascade roadmap</a>, and <a href="/transmitter/roadmap/">the Transmitter roadmap</a>.'],
],
'products': [
[ws('HotLoop core is four products, one codebase, one tag. Every core release ships all four in lockstep,'),
'HotLoop is six products for the plant floor: four that grow with a site (IoT, Edge, Gateway, and Edge Relay), plus Flow for wiring and Cascade for workflows.\n\nThey ship on three release lines. **HotLoop core** is IoT, Edge, Gateway, and Edge Relay: four products, one codebase, one tag. Every core release ships all four in lockstep,'],
'HotLoop is seven products for the plant floor: four that grow with a site (IoT, Edge, Gateway, and Edge Relay), plus Flow for wiring, Cascade for workflows, and Transmitter for putting a PLC\'s values on the wire.\n\nThey ship on four release lines. **HotLoop core** is IoT, Edge, Gateway, and Edge Relay: four products, one codebase, one tag. Every core release ships all four in lockstep,'],
[ws("PLC on your bench. Features split them. Protocols don't."),
"PLC on your bench. Features split them. Protocols don't.\n\n**Flow** and **Cascade** are their own lines with their own versions, so a Flow release never moves the core, and the other way around. Everything below the table is about the core. Here is where each of the six starts:\n\n"
"PLC on your bench. Features split them. Protocols don't.\n\n**Flow**, **Cascade**, and **Transmitter** are their own lines with their own versions, so a Flow release never moves the core, and the other way around. Everything below the table is about the core. Here is where each of the seven starts:\n\n"
+ '| Product | Release line | Docs | Install | Release notes | Roadmap |\n|---|---|---|---|---|---|\n'
+ [['IoT', 'HotLoop core', 'iot/overview', 'iot/install', 'releases/#hotloop-core', 'roadmap'],
['Edge', 'HotLoop core', 'edge/overview', 'edge/install', 'releases/#hotloop-core', 'roadmap'],
['Gateway', 'HotLoop core', 'gateway/overview', 'gateway/install', 'releases/#hotloop-core', 'roadmap'],
['Edge Relay', 'HotLoop core', 'edge-relay/overview', 'edge-relay/install', 'releases/#hotloop-core', 'roadmap'],
['Flow', 'Flow', 'flow/overview', 'flow/install', 'releases/#hotloop-flow', 'flow/roadmap'],
['Cascade', 'Cascade', 'cascade/overview', 'cascade/running', 'releases/#hotloop-cascade', 'cascade/roadmap']]
['Cascade', 'Cascade', 'cascade/overview', 'cascade/running', 'releases/#hotloop-cascade', 'cascade/roadmap'],
['Transmitter', 'Transmitter', 'transmitter/overview', 'transmitter/install', 'releases/transmitter-1-0-0', 'transmitter/roadmap']]
.map(([n, l, d, i, r, m]) => `| **HotLoop ${n}** | ${l} | <a href="/${d}/">Docs</a> | <a href="/${i}/">Install</a> | <a href="/${r}">Notes</a> | <a href="/${m}/">Roadmap</a> |`).join('\n')
+ '\n\nThe table that follows compares the four core products.'],
],
Expand Down
7 changes: 5 additions & 2 deletions src/components/ProductPicker.astro
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
---
// The family map: six products on three release lines, each with the same five things
// The family map: seven products on four release lines, each with the same five things
// (docs, install, release notes, roadmap, and its version). Versions and release state
// come from src/data/sync.json, which the sync writes, so this can't disagree with the pages.
import sync from '../data/sync.json';

const hot = sync.repos.hotloop.release;
const flow = sync.repos.flow.release;
const cascade = sync.repos.cascade.release;
// Transmitter 1.0.0 shipped 2026-11-04 (HotLoop-io/hotloop-transmitter v1.0.0). Change this when the next one does.
const transmitter = { version: '1.0.0' };

const latest = (prefix: string) =>
sync.pages.filter((p) => p.release && p.status !== 'next' && p.slug.startsWith(prefix)).map((p) => p.slug).sort((a, b) => b.localeCompare(a, undefined, { numeric: true }))[0];
Expand All @@ -15,8 +17,9 @@ const lines = [
{ id: 'core', label: 'HotLoop core', version: hot.version, note: 'One codebase, one version. IoT to Edge to Gateway is the path a site grows along, and Edge Relay is the headless forwarder beside them.', notes: `/${latest('releases/hotloop-')}/`, roadmap: '/roadmap/', ids: ['iot', 'edge', 'gateway', 'edge-relay'] },
{ id: 'flow', label: 'Flow', version: flow.version, note: 'Its own release line, running next to HotLoop.', notes: `/${latest('releases/flow-')}/`, roadmap: '/flow/roadmap/', ids: ['flow'] },
{ id: 'cascade', label: 'Cascade', version: cascade.version, note: cascade.prerelease ? 'Pre-release. Its own release line, running next to HotLoop.' : 'Its own release line, running next to HotLoop.', notes: `/${latest('releases/cascade-')}/`, roadmap: '/cascade/roadmap/', ids: ['cascade'] },
{ id: 'transmitter', label: 'Transmitter', version: transmitter.version, note: 'Its own release line, running next to HotLoop.', notes: `/releases/transmitter-${transmitter.version.replace(/\./g, '-')}/`, roadmap: '/transmitter/roadmap/', ids: ['transmitter'] },
];
const install: Record<string, string> = { iot: '/iot/install/', edge: '/edge/install/', gateway: '/gateway/install/', 'edge-relay': '/edge-relay/install/', flow: '/flow/install/', cascade: '/cascade/running/' };
const install: Record<string, string> = { iot: '/iot/install/', edge: '/edge/install/', gateway: '/gateway/install/', 'edge-relay': '/edge-relay/install/', flow: '/flow/install/', cascade: '/cascade/running/', transmitter: '/transmitter/install/' };
---

<div class="map">
Expand Down
1 change: 1 addition & 0 deletions src/components/SiteFooter.astro
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const hasTerms = existsSync(new URL('../content/docs/terms.md', import.meta.url)
<a href="/roadmap/">HotLoop roadmap</a>
<a href="/flow/roadmap/">Flow roadmap</a>
<a href="/cascade/roadmap/">Cascade roadmap</a>
<a href="/transmitter/roadmap/">Transmitter roadmap</a>
{hasLicense && <a href="/license/">License</a>}
{hasTerms && <a href="/terms/">Terms</a>}
</nav>
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/index.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: HotLoop documentation
description: "Docs for every HotLoop product: IoT, Edge, Gateway, Edge Relay, Flow, and Cascade, with each claim marked as proven on real equipment or not proven yet."
description: "Docs for every HotLoop product: IoT, Edge, Gateway, Edge Relay, Flow, Cascade, and Transmitter, with each claim marked as proven or not."
template: splash
editUrl: false
hero:
Expand All @@ -23,7 +23,7 @@ import LatestReleases from '../../components/LatestReleases.astro';

## The family

HotLoop is six products for the plant floor: four that grow with a site (IoT, Edge, Gateway, and Edge Relay), plus Flow for wiring and Cascade for workflows. They ship on three release lines, so each carries its own version. Each section in the sidebar shows only what that product ships, and a bigger product links back to the pages it carries from a smaller one.
HotLoop is seven products for the plant floor: four that grow with a site (IoT, Edge, Gateway, and Edge Relay), plus Flow for wiring, Cascade for workflows, and Transmitter for putting a PLC's values on the wire. They ship on four release lines, so each carries its own version. Each section in the sidebar shows only what that product ships, and a bigger product links back to the pages it carries from a smaller one.

<ProductPicker />

Expand Down
11 changes: 6 additions & 5 deletions src/content/docs/products.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
---
# generated by scripts/sync-docs.mjs
title: "HotLoop products: six on three release lines"
description: "Six products on three release lines, what each of the four core products has, which database each runs, how to install them and how to move a site up a product."
title: "HotLoop products: seven on four release lines"
description: "Seven products on four release lines, what each core product has, which database each runs, how to install them and how to move a site up."
editUrl: false
---

:::note[Written against main]
This page follows `main` at 4d5da2f, and it differs from the copy in HotLoop core 4.18.11, the latest release. Parts of it may be newer than what you have installed. The [release notes](/releases/) say what moved.
:::

HotLoop is six products for the plant floor: four that grow with a site (IoT, Edge, Gateway, and Edge Relay), plus Flow for wiring and Cascade for workflows.
HotLoop is seven products for the plant floor: four that grow with a site (IoT, Edge, Gateway, and Edge Relay), plus Flow for wiring, Cascade for workflows, and Transmitter for putting a PLC's values on the wire.

They ship on three release lines. **HotLoop core** is IoT, Edge, Gateway, and Edge Relay: four products, one codebase, one tag. Every core release ships all four in lockstep, same version, each with its own image, its own Helm chart and its own
They ship on four release lines. **HotLoop core** is IoT, Edge, Gateway, and Edge Relay: four products, one codebase, one tag. Every core release ships all four in lockstep, same version, each with its own image, its own Helm chart and its own
Podman Quadlet units. Pick the one that fits the box. Every product speaks
every protocol HotLoop has, so you never step up a product just to read the
PLC on your bench. Features split them. Protocols don't.

**Flow** and **Cascade** are their own lines with their own versions, so a Flow release never moves the core, and the other way around. Everything below the table is about the core. Here is where each of the six starts:
**Flow**, **Cascade**, and **Transmitter** are their own lines with their own versions, so a Flow release never moves the core, and the other way around. Everything below the table is about the core. Here is where each of the seven starts:

| Product | Release line | Docs | Install | Release notes | Roadmap |
|---|---|---|---|---|---|
Expand All @@ -26,6 +26,7 @@ PLC on your bench. Features split them. Protocols don't.
| **HotLoop Edge Relay** | HotLoop core | <a href="/edge-relay/overview/">Docs</a> | <a href="/edge-relay/install/">Install</a> | <a href="/releases/#hotloop-core">Notes</a> | <a href="/roadmap/">Roadmap</a> |
| **HotLoop Flow** | Flow | <a href="/flow/overview/">Docs</a> | <a href="/flow/install/">Install</a> | <a href="/releases/#hotloop-flow">Notes</a> | <a href="/flow/roadmap/">Roadmap</a> |
| **HotLoop Cascade** | Cascade | <a href="/cascade/overview/">Docs</a> | <a href="/cascade/running/">Install</a> | <a href="/releases/#hotloop-cascade">Notes</a> | <a href="/cascade/roadmap/">Roadmap</a> |
| **HotLoop Transmitter** | Transmitter | <a href="/transmitter/overview/">Docs</a> | <a href="/transmitter/install/">Install</a> | <a href="/releases/transmitter-1-0-0">Notes</a> | <a href="/transmitter/roadmap/">Roadmap</a> |

The table that follows compares the four core products.

Expand Down
6 changes: 5 additions & 1 deletion src/content/docs/releases/index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
# generated by scripts/sync-docs.mjs
title: "Release notes"
description: "What shipped in every HotLoop core, HotLoop Flow and HotLoop Cascade release, and what is on main waiting for the next one, newest first."
description: "What shipped in every HotLoop core, Flow, Cascade and Transmitter release, and what is on main waiting for the next one, newest first."
editUrl: false
---

Expand Down Expand Up @@ -37,3 +37,7 @@ IoT, Edge, Gateway and Edge Relay release together from one tag, so they share t
- [HotLoop Cascade 1.0.0 release notes](/releases/cascade-1-0-0/)
- [HotLoop Cascade 0.1.2 release notes](/releases/cascade-0-1-2/)
- [HotLoop Cascade 0.1.1 release notes](/releases/cascade-0-1-1/)

## HotLoop Transmitter

- [HotLoop Transmitter 1.0.0 release notes](/releases/transmitter-1-0-0/)
Loading
Loading