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 two modes:
- Poll —
navflowdfetches from the upstream on an interval (poll, e.g.5s,1m). Used by GitHub, Prometheus, Postgres, Docker logs. - Push — producers send events to
navflowdover HTTP. Used by Vercel, OTLP, and webhooks. A push source has a generatedingest_key; producers POST to/ingest/<ingest_key>(OTLP uses/v1/{logs,traces,metrics}).
Sources are added, edited, paused, and removed at runtime; no restart is required.
Events
Every event is stored with the same fields:
| field | type | description |
|---|---|---|
source | string | the source that produced the event |
event_time | timestamp | when the event occurred (source time if available, else ingest time) |
event_type | string | a coarse type, e.g. commit, 5xx_rate, error |
text | string | the rendered line an agent reads |
fields | object | typed values extracted for filtering and triggers, e.g. { "status": 500 } |
labels | object | named correlation axes, e.g. { "service": "checkout" } |
payload | object | the original event, unmodified (lossless) |
key_value | string | the 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, orfield— 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 key — key_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 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 is a webhook URL registered by an agent (over MCP, with subscribe). On a
dispatch, NavFlow POSTs to each subscriber, optionally attaching the entity’s timeline. Firings and
delivery status are listed on the console’s Agents → 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.