Skip to Content
Concepts

Concepts

This page defines the terms used throughout NavFlow: sources ingest events; events carry labels, one of which is the key; a label value is an entity; the catalog is the registry of configured objects; a view correlates sources for a key; a trigger watches a view.

Sources

A source is a configured connector instance. It has a name, a connector type, and a config object. Each source produces a single stream of events.

Sources have one of three modes:

  • Pollnavflowd fetches from the upstream on an interval (poll, e.g. 5s, 1m). Used by GitHub, Prometheus, Postgres, Docker logs.
  • Push — producers send events to navflowd over HTTP. Used by Vercel, OTLP, Alertmanager, and webhooks. A push source has a generated ingest_key; producers POST to /ingest/<ingest_key> (OTLP uses /v1/{logs,traces,metrics}).
  • Reference — declarative context, not a stream. The config is the data; it’s re-materialized on edit and always surfaced regardless of the read window. Used by reference.

Sources are added, edited, paused, and removed at runtime; no restart is required.

Events

Every event is stored with the same fields:

fieldtypedescription
sourcestringthe source that produced the event
event_timetimestampwhen the event occurred (source time if available, else ingest time)
event_typestringa coarse type, e.g. commit, 5xx_rate, error
textstringthe rendered line an agent reads
fieldsobjecttyped values extracted for filtering and triggers, e.g. { "status": 500 }
labelsobjectnamed correlation axes, e.g. { "service": "checkout" }
payloadobjectthe original event, unmodified (lossless)
key_valuestringthe value of the primary label (the key)

Labels, keys, and entities

A label is a named axis carried by an event. It is declared on the source as one of:

  • const — a fixed value applied to every event from the source, or
  • field — read per-event from a field in the connector’s normalized event.

Example label declarations on a source:

labels: - { name: service, field: service, primary: true } - { name: env, const: prod }

The label marked primary: true is the keykey_value is set from it. There is no separate key field to configure; the key is just the label you marked primary. If no label is marked primary, the connector’s default key is used.

An entity is a (label, value) pair, e.g. (service, checkout) or (repo, acme/api). The console’s Explore page lets you pick any entity and read its correlated timeline; it lists each label’s distinct values with event counts. Because labels are indexed, selecting events by { service: "checkout" } is a lookup, not a text scan.

A source’s Fields view (console, or GET /api/sources/<name>/fields) reports each label/field’s coverage — how many sampled events actually carry it — and its top values. Use it to choose a key that is reliably present.

Reading

The core read is read(selector, window): a correlated, time-ordered timeline of every event matching a { label: value } selector across all sources, in one response — no view required. The selector is a strict-AND conjunction, so { service: "checkout" } returns that service’s logs, metrics, and deploys merged on one clock, and adding a label narrows it. Each row carries the labels it matched on, so a read is self-describing.

A view (below) is an optional, saved refinement — a named, narrowed set of sources you reuse and attach triggers to. Reading through a view is query(view, key | where, window).

The reference source type

Most sources are time-series: a read applies the window, so old events age out. A reference source is different — it holds declarative context (documents attached to an entity by their labels), and its events are always included in an entity read, regardless of the window. A runbook or schema attached to service=checkout surfaces on every read of that entity, not just recent ones — so an agent correlating on an entity always has its reference material to hand.

The catalog

The catalog is the set of configured sources, views, and triggers. It is stored in the embedded database and is also expressible as YAML: GET /api/catalog/export returns it, and importing YAML (or seeding from a file on first boot) recreates it. The MCP catalog_describe tool (and, in the console, a source’s detail page) reports any object’s schema (event types and inferred typed fields), the entities it carries, freshness, lineage, and sample events.

Views

A view is a saved, narrowed read: a named set of sources (with optional filters) you reuse and attach triggers to. Where read spans every source, a view fixes the source set. A view is defined by:

  • sources — the sources to merge,
  • key_field — the label used to identify the entity across those sources,
  • filters — optional [{ field, op, value }] (ops: eq, neq, contains, gt, lt, gte, lte).

A view is virtual: it is evaluated at query time and stores no data. Reading a view for a key (or a { label: value } selector) over a time window returns the merged events in order. Views can be created over MCP with the derive tool; agent-created views are recorded with created_by set to the agent.

Triggers and subscriptions

A trigger evaluates a condition over a view as events arrive. A condition is an aggregate of a field, grouped by key, compared to a threshold over a window — for example max(rate_5xx) > 1.0 per key over 1m. When the condition holds, the trigger emits a dispatch.

A subscription wires an agent to a trigger. On a dispatch, NavFlow delivers the entity’s timeline to each subscriber. Two kinds subscribe the same way: an external agent (a webhook URL registered over MCP with subscribe, which POSTs the timeline) and a NavFlow agent (a prompt configured in NavFlow that runs in-process and writes a finding back). Firings and delivery status are on the console’s Activity → Trigger dispatches page.

Object graph

connector → source → event → labels → entity ├→ read · view → query (read; agents + console) └→ trigger → dispatch → subscription (push; agents woken)

See Connectors for what can be ingested, and Connecting agents for the read/watch surface.

Last updated on