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:
- 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, Alertmanager, and webhooks. A push source has a generatedingest_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:
| 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 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.