A warning held on purpose and lost with the walk's message at a restart was turned into history and never told. Name the walk in the told line from its own item.
messenger
The holder of the operator-channel seat: the router (novox/hq to-be 45 §5, to-be 46, ADR 0227, ADR 0234,
ADR 0259). It decides what is said to the operator and on which channel, holds every ask a module makes of
the operator, judges each answer and issues the warrant its asker acts on. It performs nothing, holds no
channel's client and no channel's secret.
- Declares three seats:
operator-channel(held here:open,history,notify,asks; an ask and its cancel accepted under the asker's own name, the warrant emitted to that asker alone; the asks kept as a record each asker reads under its own name), and the two kinded benches its channels hold,channel(show,edit,send, each under the holder's kind) andintake(choice,link,failed,standing, and the proofcode, request and reply only). Onlychannelandintakemay be kinded. - Reads the controller's open conditions (
seat:mesh-controller.conditions) and consumes its condition events; the events are read in one place,cmd/messenger/condition.go. - The channels are modules of their own:
telegram(kindtelegram, reaches the operator away, proves its sender) anddesk-channel(kinddesktop, the machines' notifiers, proves nothing). Which kinds exist and what each promises is the controller's word, in this module's membership; whether each can send now is the channel's own, said onintake.standing. - Keeps its state on the bus (ADR 0201):
openandsent(the messages, and the restart passes made),asks(every ask, closed ones for 30 days),identities(the operator's linked accounts, one per kind, and a link asked for),walks(the delivery walks open now, each with what it holds). - Lost answers are said again from here, never from a channel's memory (issue 384,
cmd/messenger/restart.go): a channel whose messages' answers were lost — the desk's notifier started again — says when in its standing (answers-lost-at). The router says again on that kind, directly and not through the outbox, each message that is still open, asked there, never answered and last said before that time: one per problem, under its handle, with the words and answers of now, so it replaces the message in place. A restart says nothing it has said (novox/hq ADR 0308 §6, issue 531): a silenced message, one withheld for its content, one answered and one a walk holds are left as they are, and what ended never comes back. The standings of one restart (a notifier on each machine, seconds apart) are one pass: a loss is acted on once it stood 10 s, and the pass made is kept in the state (sent, keypasses), so a router that starts again does not make it again. A kind that cannot send waits; it never goes to another channel. Telegram's answers are never lost and it says no time.
Asks, answers and warrants (novox/hq ADR 0259)
- An ask arrives on
mesh.seat.operator-channel.accept.ask.<asker>; the asker is the subject's last token, which the bus grants that module alone. It is checked (the asks contract, the content rule, at most three open per asker) and recorded before its work is taken; a refusal is said to the asker on itsdecidedsubject, in words. - It is offered on every kind that can carry one of its answers: an acknowledgement wherever a choice can be made; an approval only where the kind proves its sender and an account is linked; nothing that destroys until an authenticator-app code exists. Each option has a one-time ticket per kind; the words say where an answer not offered here can be given ("Release or Stop: answer on Telegram, or from the mesh MCP server."). An ask about a condition is shown on that condition's message.
- An answer is judged in order, refused at the first failure and said where it was given: the ticket is known, unused and for this kind; the ask is open and unexpired; the sender is the linked account where the kind proves its sender; the kind's capabilities meet the level; an approval comes from an account linked an hour or more. The ask is then closed by compare-and-set — a second answer loses — and the warrant published to the asker alone. A warrant the bus did not take is published again every minute.
- What the operator sees when they answer (issue 372): first, in reply to the answer where it was given, that it was recorded and whether its asker was told ("You chose Approve: recorded, and claude-code was told.") — said only once the ask's end is recorded — or, refused, why; then the ask's message edited to how it ended, as its title ("You chose Approve at 13:30 on Telegram · "), with no answers left on it. What the asker then did is not said: the asks protocol carries no result back to the router, so the message says only that the asker was told and acts on it itself.
- An ask never defaults: at its expiry it ends
expiredand its asker does what it said it would. - Linking (
/startto the bot): a six-digit code is shown, with the account's name and number, on a channel whose words stay private (the desk) for ten minutes; the operator sends it to the bot, and the account is linked. It acknowledges at once and approves after an hour. The code is shown now or never: while the desk cannot show it (its notifications paused, nobody there), no link is begun and no code waits in a queue. At most three links an hour per account, and ten per kind, counted in the router's state. Every link and unlink is said on every channel. An account unlinked less than a day ago is not linked again by a code; one account per kind is checked again as a link is made. - Unlinking is asked of the account that is linked (
messenger_unlinkasks it): an approve question put to that account alone. Its approval unlinks it, told to it first, by name, then everywhere. A link within a day of an unlink waits for the replaced account's approval, asked of it by name. Each unlink or relink question binds the account it is about, so its approval never acts on another account linked meanwhile. An account still in its first hour, which cannot approve yet, is unlinked from the desk: when another account sends/start, the desk is asked whether to unlink it. - When that account is lost with its phone, root at the router's machine leaves a file in this module's
state directory —
unlink.<kind>, orallow-link.<kind>for a link that waits, a regular file owned by uid 0 — and the router does it within the minute, said on every channel with what was done, and every open question of the router's own ends. A file not made by root is refused and said. - A channel proving its sender says only to the linked account: none linked, it is not ready, and asks
for approval are not offered on it. An approval rests on the controller's positive word, asked of its
verb
root-freefor the router's machine and the channel's, live when an answer arrives (a word at most 30 s old renders the buttons): only a machine it says is free carries an approval. A router that does not know its machine, a controller that does not answer, a machine its answer leaves out, or a word on the channel kinds older than two minutes all fail closed. - An ask that offers an approval is answered only where it could be approved, whichever option is chosen: the desk, which proves nothing of who clicked, is not offered it, and an acknowledgement from a fresh link does not end it. An asker wanting an acknowledgement at the desk asks it alone.
- Each ask's message says who asks (as the bus names it), what each answer does, and what happens if nobody answers. A warrant is published under a message id nobody can foresee.
- The router runs as its own account
messenger, on a bus account of its own, never carried by the machine's runtime (ADR 0259 §8): its state and its bus credential are that account's.
What is sent, and when
History is never news (novox/hq issue 271). The events stream hands everything it holds to a consumer that is new, was made again, or whose holder was away — on 2026-10-06 a newly made consumer handed over three hours of raised-and-cleared conditions at once, and each was said as if new. So what is said is decided by the state now and by when a thing happened, never by when it arrived:
- The state first. On start, every 10 min, and at once when an old event arrives, the holder reads
what is open now from the controller (
mesh-controller.conditions). An event older than that reading is already in it and is not acted on. What is open here and not there ended meanwhile: it is forgotten quietly (Telegram's message is edited, which notifies nobody; the desktop is not woken). An urgent condition open and never said is said — all of them in one message. A warning raised in the last 10 min and not heard is said like any other; an older one is state. - Old is state. An event whose own time (
at) is more than 10 min old is recorded, never said. - A clearing of something never said says nothing, and a message still held when its condition clears is dropped.
- Start grace. Nothing is sent in the first minute after start but that one urgent message; what arrives meanwhile goes out, coalesced, when the minute ends.
A message reads in one glance (novox/hq ADR 0253). Its title is the condition's headline — a few
plain words such as "openrazer not working on g14" — prefixed "Urgent:", "Still open:" or "Now urgent:"
where that applies; its body is the condition's explanation (what happened, what it means, whether the
operator needs to act) and since when, in the operator's time zone. No key, id, commit, command or markup:
those stay in the controller's conditions and in this module's history. A clearance is one line, the
condition's resolved line and how long it was open: "Resolved: openrazer works again on g14, after 26 min".
A condition from a controller older than plain words, or a module's notice without a headline, is said from
its summary, with code spans taken out (cmd/messenger/words.go).
A condition's message says which issue tracks it (novox/hq ADR 0285, issue 400). Below the explanation,
one line from the issue tracker's tracking verb, asked outside the work at most once a minute and used for
ten minutes: "Tracked as issue 386: fix-386 on g14 is fixing it since 21:10.", "…: nobody is working on it.",
"…: its fix is merged and on its way.", "…: it waits for your answer.", up to three issues and then a count;
"No issue tracks this yet." when no issue links the condition's key; "Whether an issue tracks this could not
be checked." when the tracker gave no answer in ten minutes. "Nothing for you to do." becomes "Needs you:
answer issue N." while an issue tracking it waits for the operator, and is left out while nobody works on any
issue tracking it. The line changes words only, never when a message is sent (cmd/messenger/tracking.go).
Every explanation opens with a verdict: "Nothing for you to do." or "Needs you:" and one thing the operator can do themselves. A warning that needs nothing is not sent: it stays open here and in the controller's conditions, the history says it was kept quiet, and it is said the moment it needs the operator (urgent at its bound, or its words now say "Needs you:"). An urgent condition is always said.
A message offers the answers of the ask about it, and Details (cmd/messenger/answers.go). The router
calls no verb of a condition's: the controller asks for the answers a condition names, and performs the one
chosen on its warrant. Details is a ticket per kind, good for a day, used once, shown where it was chosen. A
warning kept quiet is also said once after a day.
| When | What |
|---|---|
condition-raised |
one message, deduplicated by the condition's key |
| still open after 1 h (urgent) or 12 h (warning) | once more, in place of its message — never sooner than that after it was last said |
condition-changed from warning to urgent |
once more, in place of its message, to both channels |
condition-cleared |
once it stays cleared 2 min (10 min once it came back): its message edited to say so; said inside a digest, a line in the next one |
| cleared and raised again before its clearing was said | nothing: to the operator it never ended — a unit failing again after each apply is one message, not one per apply; back as urgent, or with a reminder waiting when it cleared, that is said |
| cleared, said so, and raised again within 10 min | the same message, edited back to open — not a new one (urgent: said again in its place, so it rings) |
| silenced | its message, where shown, edited to "Silenced until : " with the reason, no answers and no urgency (the desk's popup times out); nothing more while it lasts; silence over and still open, the message is open again; resolved meanwhile, said only where an edit notifies nobody |
One message per problem (issue 373). A record keeps the id of its message on each channel; a reminder or an escalation is said in place of it — the channel takes the earlier one away and shows the new one as a new message is shown, so it rings once and no second message stands beside the first (the desk replaces the notification by its id; Telegram deletes the earlier message). A message said again goes alone, never as a line of a digest beside the message it follows; one first said inside a digest gets a message of its own the next time, and later words replace or edit that one. An ask's buttons live on that one message, so an ask that ends takes them away everywhere; its expiry is said with its day when it is not today.
- Routing: urgent to every kind that can send; a warning to the desk where it can send, otherwise to the channel that reaches the operator away; an ask to every kind that carries one of its answers.
- Bursts are one message. What is to be said on a channel is held 30 s from the first and goes
out together: alone, as itself; several, as one digest (
WARNING: 5 new warnings, a line each). An urgent message goes at once when nothing went out on its channel in the last 30 s. - The desktop is gentle: warnings reach it as at most one message every 15 min; urgent ones are not held to that.
- Cap: at most 20 messages an hour per channel — a last line of defence the above keeps far away. Reached, it is said once, in a message of its own, and the rest is held to go out as one digest when the hour allows.
- What may leave the mesh: roles and words. A message carrying an address (IP, host name, URL,
mail address), a path, or anything shaped like a secret (a token, a key block, a long random or
hexadecimal string,
password=…) is refused, logged, stated as therefusedevent, and sent in its place aschannel-refusedwith the words that carried it withheld. The rule iscmd/messenger/content.go. - Nothing silent: a channel that cannot send says so in
messenger_statusand in the log, and what it holds is tried again every minute while the condition is open.messenger_statusalso says when the open conditions were last read, why they could not be, and how many events were taken as history. An event that cannot be read is refused by name, counted, and told to the operator once an hour.
While a delivery walks (novox/hq ADR 0308)
The controller's plan-moved says each walk's start and end: walk, phase (started, ended), touches
([{machine, modules}]: what it moves and what a moved tool runner or node-engine carries), outcome
(delivered, failed, stopped), bound_seconds and budget_class (cmd/messenger/walks.go).
- Held: while a walk is open and within its bound, a message whose subject is a machine it touches, or a
module it touches (on a machine it touches, when the subject names one), is held: kept on the walk with when
and what, and the history says
held. A message several open walks touch is told when the last ends or passes its bound. At a walk's end, a later open walk that touches a message takes it over only as a first hold would: still open, not silenced, not said since, and not one that is never held. - Never held: an ask waiting for the operator (and a condition an open ask is about), a secret given or replaced, a subject no open walk touches, and a walk's own failure (a plan, walk, delivery or build).
- The end is one message: the outcome, the modules and machines reached, how long; each held message still
open, one line each; the ones that cleared counted. Delivered with nothing held and nothing open: one line —
and nothing on a kind listed in the setting
only-what-needs-me. What it carries is marked told on a kind only once the message was sent there. Until then each is kept owed in the state (owed): a message lost with a restart before it was sent leaves them untold and owed, and the restarted router says each on its own. - The bound: at its start plus
bound_seconds(900 when not given), what is held and still open is said, with "The walk … is still running, since HH:MM", and the cleared counted; the walk holds nothing more. A walk whose end never comes is forgotten a day after it started. A start heard after its end opens nothing: the controller's moments are compared on its own clock, never with one capped at the router's now. - Kept in the state (
walks): a router that starts again mid-walk holds and tells as before.
What the operator gives
- The time zone, as a setting:
{"time-zone": "<an IANA zone name>"}. Every time a message says is said in it; not given, the zone of the machine this runs on. The kinds that say only what needs the operator, as a setting:{"only-what-needs-me": ["<kind>"]}. A walk that delivered with nothing held and nothing open is not told on them (ADR 0308 §4); empty by default. - The channels: assign
telegramanddesk-channel(each says in its README what it needs). Linking an account as the operator is done on the channel, never by a setting.
Tools
| tool | does |
|---|---|
operator-channel.open |
what is open now, urgent first, with where it went, silenced, reminded, held, refused, unsent |
operator-channel.history |
what was said lately, and the refusals |
operator-channel.notify |
a message from a module using the seat: key, severity, summary, and best a plain headline, explanation and resolved line; clear to end it |
operator-channel.asks |
the asks held, open first: asker, state, where offered, the warrant, whether the asker was told |
messenger_status |
whether the operator can be reached and why not, per channel kind |
messenger_recent |
the recent sends, edits, digests, answers and failures |
messenger_test |
a test message now, to one kind or every one |
messenger_preview |
what a condition's message would say, tracking line and all, without sending it: the words a send would carry, reduced where the content rule refuses its own |
messenger_check |
whether some words may leave the mesh |
messenger_identities |
the accounts linked as the operator, and from when each approves |
messenger_unlink |
unlink a kind's account, said on every channel |
Where it runs
Held once for the mesh, on the control node: its settings are root's files at 0600 (as every runtime-carried module's are). It holds no secret.
Not yet
notifyis a served verb, not a work queue. The design has the seat acceptnotifyso a message waits for a holder; the node's tool runtime does not yet hand a bundle its seat's queue, and an accepted queue nobody takes would hold messages silently. It is answered request-and-reply until the runtime takes a seat's queue for a bundle (mesh-tools).- Channels are inside the holder, not modules contributing to the seat: a seat a module declares cannot receive contributions yet (ADR 0212 kinds are compiled for the mesh's own seats).