Facets describe what the system is at any moment, persistent, reactive and branchable. They’re named values in the FacetGraph that any service can read, any trigger can match, and any transport can stream. If you need to know something about the system, it’s a facet.

flowchart LR
    RT[[Runtimes]] -->|set facet| FG[FacetGraph]
    FG -->|trigger| FE[FlowEngine]
    FE -->|evaluate| IM[[Impulses]]

Facet as Concept

A facet answers “what is the current value of X?“.

Examples:

  • service:httpd_status"running"
  • network:eth0_address"192.168.1.10"
  • system:load0.45
  • session:makano"active"

If the system restarts, restored facets resume their last value.

Facet in Flow Items

A flow item watches a facet pattern:

[[facet]]
name = "temp"
payload = "json"
branch = ["id"]
after = [{ facet = "sensor:online" }]
FieldTypePurpose
namestringUnique facet name, group:entity convention
payloadstringPayload type: json (default), string, bytes, none
afterarrayFlowItem conditions that activate this facet (transcendence)
brancharrayJSON key specs for branching (e.g. ["id"], ["seat:tty"])
stop-onarrayConditions that deactivate this facet (inverse transcendence)
auto-payloadtableAutomatic payload generation
subscribersarrayTransport subscribers notified on change
broadcastarrayNamed broadcast targets
permissionsarrayPermission names required to set this facet

Branching

Facets can have multiple branch instances, keyed by JSON payload fields:

[[facet]]
name = "user_session"
payload = "json"
branch = ["tty"]          # one branch per unique tty value

When a payload {"tty": "tty1", "username": "makano"} is set, a branch tty1 is created. Another with {"tty": "tty2"} creates a separate branch. Existing branches are merged (JSON deep-merge); new branches are appended.

After: Transcendence

Facets can declare dependencies that activate them:

[[facet]]
name = "app_ready"
payload = "none"
after = [{ facet = "db:ready" }, { facet = "cache:ready" }]

When both db:ready and cache:ready are set, app:ready activates. When either is removed, app:ready deactivates. The FlowEngine maintains transcendence and inverse-transcendence indexes for efficient dependency resolution.

Stop-On: Inverse Transcendence

[[facet]]
name = "login_required"
payload = "json"
branch = ["tty"]
stop-on = ["rind:user_session"]

When rind:user_session has a branch for a given key, the corresponding login_required branch is automatically removed.

Subscribers

Facet changes can be published over transport:

[[facet]]
name = "transport_state"
payload = "string"
subscribers = [{ id = "uds", options = ["detached=true"], permissions = ["any"] }]

When the facet is set or removed, a TransportMessage is sent to each subscriber.

Auto Payload

Automatic payload generation:

[[facet]]
name = "generated"
payload = "string"
auto-payload = { eval = "/usr/bin/sensor-read" }

Setting Facets

Facets are set via runtime dispatch, IPC messages, or Trigger actions:

[[service]]
name = "reporter"
run.exec = "/usr/bin/reporter"
on-start = [{ facet = "status", payload = "running" }]

Facet Impermanence

Facets can be impersistent if their name ends with !, marking them as transient but not persistent. (e.g. net:configured!, rind:up!)

See also: Flow, Impulses, Persistence, Boot