How Nodes, Verbs, and Sources Work
The mental model behind a Krill swarm — every node is independent, observes its sources, and acts on the verb it receives using only its own capabilities. No more "executing children"; nodes are invoked from a source.
Everything is a node
A Krill swarm is a collection of nodes. A timer is a node. A data point is a node. A calculation, a GPIO pin, an email sender, a webhook — all nodes. Each node has a type, some configuration, a current state, and a place in a parent/child hierarchy you arrange in the swarm view.
The interesting part isn’t the nodes themselves — it’s how they wake each other up and decide what to do. That’s what this post is about.
Sources: how a node knows it’s time to act
Every node can observe one or more sources. A source is just another node it’s watching. When a source changes — a timer fires, a sensor reading updates, a calculation produces a new value — every node that lists it as a source is invoked to re-evaluate itself.
The key word is invoked, not executed. Krill used to talk about a parent “executing its children.” That’s the wrong picture. A parent doesn’t reach into its children and run them. It simply announces that something changed, and any node observing it as a source wakes up and decides for itself what that means.
This is a pull model. When a node is invoked, it reads whatever it needs from its source at that moment — the current value, the verb that came with the change — and then acts. The source doesn’t push instructions; the invoked node pulls context and makes its own decision.
The default: a child uses its parent as a source
When you drop a new node under a parent in the swarm, Krill wires the parent as the new node’s source automatically. This is the “it just works” default: place an email node under a threshold trigger and, with no extra configuration, the email is invoked whenever the threshold fires.
It’s only a default. Every node’s sources are fully editable on its Sources tab — you can remove the parent, add other nodes from anywhere in the swarm (even on a different server), or wire a node to several sources at once. Parent/child is how you organize the swarm visually; sources are how data and activity actually flow. They start aligned and you’re free to diverge them.
Nodes are independent of their parent’s logic
A node never runs its parent’s logic, and it doesn’t need to understand what its source does. A calculation doesn’t care whether it was woken by a timer, a button, or a sensor — it just knows “a source I observe changed, so I should recompute.” A data point wired to that calculation doesn’t care how the number was produced — it reads the calculation’s latest value and stores it.
This independence is the whole point. Each node is a small, self-contained unit that does one job using only its own capabilities. You can rewire sources, insert a node in the middle of a chain, or move work between servers, and nothing else has to be rewritten — every node still just observes its sources and acts on its own terms.
Verbs: what kind of action is being asked for
When a source fires, it carries a verb — the kind of action flowing downstream. The two you’ll encounter are:
- Execute — run the node’s normal forward action. Send the email, set the pin, compute the value, store the reading.
- Reset — return the node to its cleared/idle state. Undo, stand down, go quiet.
The verb of the source that fired cascades down the chain. Receivers apply the source’s verb, not one of their own. That’s a deliberate, powerful property: a single reset upstream clears an entire downstream chain in one motion — every node it reaches stands down together, without you wiring a separate “reset” path.
Best effort across node types
Not every node type has a meaningful response to every verb from every other node type. A reset means something concrete for a GPIO pin or an alarm; it’s less obvious for a one-shot notification. Krill makes a best effort: a node does the most sensible thing its type supports for the verb it received, and if a particular verb genuinely has no sensible meaning for that node, the node simply does nothing rather than guessing or misbehaving.
So when you build a chain across mixed node types, expect every node to honor the verbs it can act on, and to safely ignore the ones it can’t. You don’t have to memorize a compatibility matrix — wire what makes sense for your automation and Krill degrades gracefully where a combination doesn’t have a natural behavior.
Putting it together
Picture a timer, a calculation, and a data point. The timer fires on a schedule. The calculation lists the timer as a source, so it’s invoked, reads what it needs, and produces a new value. The data point lists the calculation as a source, so it’s invoked in turn, reads the freshly computed value, and stores it.
Nobody “executed” anyone’s children. The timer announced a change; the calculation was invoked from its source and did its own job; the data point was invoked from its source and did its own job. Three independent nodes, one clean flow, each acting on the verb it received with only the capabilities it has.
That’s the model. Once it clicks, building automations is mostly a matter of asking two questions for each node: what is my source? and what should I do when it fires?