.agents/skills/project-create-topology/SKILL.md
This is a developer skill for assistants working in this repository. It is not an end-user/operator skill. Use it when changing topology producers, schema fixtures, validation, topology developer documentation, or Cloud/frontend handoff artifacts.
Read these before designing or changing topology payloads:
| File | Purpose |
|---|---|
src/plugins.d/FUNCTION_TOPOLOGY_SCHEMA.json | JSON Schema for production topology payloads |
src/plugins.d/FUNCTION_TOPOLOGY_DEVELOPER_GUIDE.md | Human-readable topology schema contract and producer guidance |
src/plugins.d/FUNCTION_TOPOLOGY_IMPLEMENTATION_SCOPE.md | Backend/frontend/aggregator migration scope |
.agents/skills/project-create-topology/topology-function-schema.md | Durable project spec for topology semantics |
.agents/skills/project-create-topology/topology-modes-correlation-aggregation.md | Mode, correlation, aggregation, and actor modal identification contract |
src/go/pkg/topology/v1 | Go production topology payload builders and compact-table helpers |
.agents/skills/project-writing-collectors/SKILL.md | Collector quality, Function, validation, and cardinality rules |
For transport-level Function behavior, also read:
src/plugins.d/FUNCTION_UI_REFERENCE.mdsrc/plugins.d/FUNCTION_UI_DEVELOPER_GUIDE.mdThe how-to catalog lives under how-tos/. These recipes are
developer-facing and must stay in this project skill, not under
docs/netdata-ai/skills/.
src/go/pkg/topology/v1. The non-v1 root
src/go/pkg/topology payload model has been retired and MUST NOT be
reintroduced for production topology payloads..local/ only.Define the topology purpose and scale target.
Pick actors.
identity, merge_identity, and parent_identity in actor types.group_by:process_name emits grouped process actors,
group_by:pid emits per-PID process actors with scalar per-PID details, and
group_by:container emits container actors grouped by canonical
container_name. In container grouping, producer-declared actor types may
be more specific than container (docker_container, systemd_service,
user, vm, etc.) as long as they share the container aggregation
scope. user.slice/user-UID.slice paths are grouped by resolved username,
or user${UID} when username resolution is unavailable; leaf scopes remain
cgroup/detail evidence, not graph actor identities. Grouped views must not
pretend variable per-PID fields are scalar actor identity; instead, expose
them through merged/set-valued actor labels or declared set aggregation
metadata so actor modals and Cloud aggregation preserve the contributing
process/container facts.v: 3; verify selector behavior with the
actual POST payload shape (selections.group_by) and keep legacy
function-string aliases only as compatibility paths.Pick graph links.
Pick evidence rows.
Classify detail tables.
actor_detail: custom actor state, not generally aggregatable.actor_inventory: actor-owned inventory data.relationship_evidence: exact relationship rows.relationship_summary: derived summaries.json columns only for custom actor/detail cells that must preserve
nested producer-owned values; avoid them for high-cardinality evidence.actor_labels table for modal labels:
actor, key, value, optional source, optional kind, and optional
value_index.processes and cgroups tables. Do not rely on the generic
Labels tab for structured PID/cgroup inspection when the producer has typed
rows.actor_labels for grouping keys.Define telemetry overlays.
topologyv1.NewActorOverlayRefsBuilder or
topologyv1.NewLinkOverlayRefsBuilder instead of hand-assembling compact
tables.template column, exactly one convention owner column
(actor with type actor_ref or link with type link_ref), and one
column for each selector param required by the referenced template. Do not
add any other actor_ref or link_ref columns to overlay refs. Every row
must have a non-null owner value.template column and required selector-param columns must be string
or string_ref; required selector-param row values must resolve to
non-empty strings.template, actor, or link as selector params; those names
are reserved refs-table convention columns.netdata.metrics, node_id means node scope, collect_job maps to
chart label _collect_job, and other selector params map to same-named
chart labels. In go.d producers, pass job.Name() for collect_job; do
not use job.FullName().Define correlation semantics when actors can be resolved across payloads.
data.correlation.rules with declarative key templates,
priorities, class, absorb or link actions, point actor types when
visible correlation actors exist, optional claim actor types, correlation
link types, and output link types.data.correlation.points rows for visible correlation actors
when the input graph has them, and data.correlation.claims rows for real
actors that can satisfy keys.absorb only for exact matches that should remove correlation actors
or loose-side placeholders from the aggregated output.link for broader or partial matches that should keep the correlation
actor or materialized partial actor visible.replace_actor semantics for weaker placeholder actors that should be
replaced by stronger managed actors.merge_enrich_actor semantics when multiple payloads provide
complementary facts for the same actor identity.Define graph presentation.
types.actor_types.<id>.presentation.types.link_types.<id>.presentation.types.port_types.<id>.presentation.data.presentation.__topology_mode for detailed vs aggregated topology requests when a
producer has a real mode difference. Do not expose a mode selector for
mode-invariant topologies.label_policy.columns with safe scalar display columns; never let
canonical identity arrays become actor names.search.columns[] and/or search.label_keys[] for searchable
actors. Set search.enabled: false for helper actors that should not
appear in graph search. Do not rely on UI hardcoded details, match, or
attributes paths.presentation.size.scale when an actor type needs fixed visual
emphasis, and presentation.layout.repulsion when an actor type needs
relative force-graph separation. Do not emit raw force numbers.link_types.<id>.semantic_role when behavior depends on link
meaning, such as discovery, ownership, traffic, correlation, or
control. Do not make the UI infer this from link type names or protocol
strings.presentation.arrow authoritative for arrows. Omitted or auto
derives no arrows for undirected, observed_bidirectional, none, or
observation; derives forward for directed flow/dependency and
hierarchical ownership. Use explicit reverse or both when needed.
direction_role is required; never rely on orientation: directed alone
to infer arrows.ports.sources[] whenever an actor type sets
ports.show_bullets: true.ports.sources[].name_column; do not use
refs, arrays, or JSON as graph bullet labels.ports.sources[].value_column when one compact row represents
multiple observations and the UI should size or count bullets by the sum.variable.scale_key and sourced from one raw numeric value_column.presentation.layout.strength tokens weakest, weaker, normal,
stronger, strongest, and presentation.layout.distance tokens
closest, closer, normal, farther, farthest; do not emit numeric
force values.presentation.layout.strength at normal
and varies only presentation.layout.distance where semantic separation is
needed. Do not emit non-normal strength tokens for graph polish unless a
later product decision explicitly re-enables force-strength tuning.docker, kubernetes, lxc,
nspawn, podman, systemd, user, and the existing container and
vm tokens.size.scale, layout.repulsion, and search use neutral
defaults. Do not expect the UI to preserve legacy self/device/SNMP/
endpoint heuristics for v1.Define modal/table composition.
types.actor_types.<id>.presentation.modal.types.link_types.<id>.presentation.modal.types.table_types.<id>.presentation.modal.labels.identification.fields[] to choose the small set of
actor labels that should appear in the actor modal identification/header
area. The full actor_labels table remains the Labels tab.actors, links, evidence,
actor_table, or relationship_table sources.selected_side_endpoint, include source/destination actor-ref
columns and both endpoint sides in the projection so the UI can choose the
side from the selected actor without hardcoded table knowledge.label_lookup, provide label_key; provide actor_column only when
the lookup should read labels for an actor referenced by the source row
instead of the selected modal actor.json_path, provide both the JSON column and scalar path.json is debug-only unless a schema-declared scalar projection gives
the UI/aggregator semantics.info responses as metadata only. Validate full topology
responses against FUNCTION_TOPOLOGY_SCHEMA.json; do not require
metadata-only info responses to carry data.Encode large sections as compact tables.
const for constant columns.dict for low/medium-cardinality repeated values.values only when values are high-cardinality.src/go/pkg/topology/v1 compact-table helpers
instead of hand-building table JSON.src/plugins.d/FUNCTION_TOPOLOGY_SCHEMA.json.max(actor rows, link rows) so
valid actor-only payloads are not rejected.directed + flow: sockets, traffic, request dependencies.directed + dependency: logical dependency direction.hierarchical + ownership: parent/child, host/VM, cluster/host.undirected + none: physical adjacency with no direction.observed_bidirectional + observation: discovery saw one or both sides,
but direction is not user-facing dependency.If direction is noise, mark it so the aggregator can merge independently of direction.
Network-connections uses three graph-link families:
Network-connections dependency direction is client-to-server. Use
direction_role: "dependency" for socket dependency link types. Emit
src_actor as the client/dependant and dst_actor as the server/dependency
target. Do not expose local as a topology socket direction; same-node sockets
still become inbound or outbound dependency rows based on which side is the
client.
Use distinct presentation for each family:
endpoint_socket: solid, colored, thin, normal-strength, normal-distance unresolved
endpoint dependency links;correlated_socket: solid, colored, thin, normal-strength, farthest aggregator
output links after exact endpoint absorption;socket: gray, thin, normal-strength, normal-distance local process links, optionally
variable by socket_count;ownership: dotted, faded/dim, thin, normal-strength, normal-distance graph-coherence links.In aggregated mode, do not enable process port bullets from detailed socket
evidence. Emit a compact actor inventory table such as socket_ports with
actor, port, and numeric socket_count, point the process actor
ports.sources[] at it with value_column: "socket_count", and size process
actors with size.mode: "metric" over actor row socket_count.
For network-connections actor modals:
Processes section from links filtered to
type == ownership;Dependencies where the selected actor is src_actor
and Dependants where the selected actor is dst_actor;tables.relationship.connections;evidence.socket;socket_ports stays an actor inventory for graph port bullets, not a normal
modal tab;visibility: "expanded" columns instead
of separate duplicate sections.For socket correlation:
socket_exact rule uses class: resolve_loose_side and
action: absorb;endpoint_socket links are normal-strength/normal-distance visible links before
aggregation;correlated_socket is the farthest output link type after exact absorption.For topology:streaming actor modals:
retained_node_count metric, not from
graph degree or direct child count. Emit presentation.size.mode: "metric"
and presentation.size.metric_column: "retained_node_count" for the parent
actor type. This count represents nodes for which the parent has retained
data, including self, virtual nodes, stale nodes, and transit descendants
when they have DB retention state.ports.sources[].actor_column: "dst_actor" and a scalar child/node display name_column, such as
port_name.actor_labels, stream_path, retention, inbound, and outbound
as the single source of truth. Do not duplicate rows only to populate modal
sections.modal.labels.identification.fields[], backed by actor_labels. Typical
host-like keys are hostname, node type, health, stream, ingest, OS, OS
version, kernel, architecture, CPU, cores, RAM, virtualization, container,
cloud placement, and Agent version. Parent actors also include retained-node
count and direct child count.
Vnode actors should use inventory/device labels such as vnode type, vendor,
model, address, location, sys object id, LLDP name, and status. Keep long
stable identifiers such as machine GUID and node id in the full Labels tab by
default.Stream path from stream_path filtered by actor, ordered by
path_index. This is only the selected actor's own path; child and virtual
node paths belong to their own actors. Do not emit blank since or
first_time values for synthetic path rows when those timestamps can be
derived from adjacent path, ingest, or DB status.Retained nodes from the retention table filtered by
observer_actor; this answers which nodes' data the selected actor
maintains. Include self, virtual nodes, direct children, transit descendants,
and stale/archived hosts when present in the Agent root index. Preserve
db_from and db_to whenever the DB status knows the range.Received nodes from inbound filtered by parent_actor; this table
represents children, virtual nodes, stale nodes, and descendants received or
transiting through the selected parent. Populate source_actor whenever the
immediate sending actor is known; for direct local receipt, use the child or
virtual-node actor instead of leaving the cell empty.Outbound streams from outbound filtered by the sending parent actor.
This table must list every node payload the selected parent streams upstream,
including self, virtual nodes, direct children, and transit descendants. Rows
need at least streamed node actor, destination actor when known, status, age,
hops, TLS, compression, and useful counts/replication metrics when available.Retention for node default section in the current modal
contract. Keep actor and observer_actor in the canonical retention table
so Cloud aggregation can preserve multiple retaining parents and a future
explicitly named Retained by section can be added without changing facts.For SNMP managed device actor modals:
Ports
over actor_ports.modal.labels.identification.fields[], backed
by actor_labels. Typical keys are display name, management IP, vendor,
model, port counts, and LLDP/CDP neighbor counts.actor_ports columns: SNMP if_index as
the visible numeric port ID when known, source port_id, display name,
if_name, if_descr, if_alias, MAC, speed, status, mode, role, VLAN, FDB,
link, and neighbor counts.if_index must come from device/SNMP facts.neighbor_actor and neighbor_port_name when graph-link facts can align the
port to a remote actor.actor_port_links modal index for Port Neighbors when
the device modal needs remote actor, remote port, link type, evidence count,
confidence, inference, attachment mode, or timestamps.actor_port_links may carry compact side-specific refs and scalar facts, but
must not duplicate raw LLDP/CDP/FDB/ARP/STP evidence JSON.actor_port_links. l3_subnet is not a
physical or L2 port-neighbor relationship.l3_subnet relationship evidence
and an evidence-backed device modal section such as L3 Adjacencies.l3_subnet links represent shared-subnet logical L3 adjacency between
resolved managed SNMP device actors. They must use explicit L3 link/evidence
types and must not be presented as discovery, physical, or L2 links.ospf_adjacency, is control-plane
logical adjacency. It must not be presented as discovery, physical, L2, or
port-neighbor evidence.actor_ospf_neighbors and
actor_bgp_peers. Non-full, non-established, or unresolved protocol
neighbors should remain visible there without creating loose router/IP
actors.bgp_adjacency links represent established BGP control-plane adjacency
between resolved managed SNMP device actors. They must use explicit BGP
link/evidence types, carry semantic_role: control, and must not be
presented as discovery, physical, L2, or port-neighbor links.Links sections only for endpoint, segment, or
custom actors that do not own port inventory.port_name,
if_name, if_descr, or source port_id. Never use actor labels such as
display_name or sys_name as port-name fallbacks.src/go/plugin/go.d/collector/snmp_topology. The suite starts from synthetic
SNMP-shaped ddsnmp inputs, runs the real cache, registry, and Function
rendering path, validates the final topology.v1 payload, and checks semantic
product expectations.netdata/testdata fixture repository under snmp/topology-scenarios/.
Local regeneration may point the test at that checkout with
NETDATA_SNMP_TOPOLOGY_SCENARIO_GOLDEN_DIR.actor_labels when the producer has labels
or actor metadata to show.actor_labels.key, actor_labels.value, actor_labels.source, and
actor_labels.kind are logical string fields. Accept string and
string_ref encodings as equivalent when validating, aggregating, or
rendering topology payloads.actor_labels as sensitive topology Function data. Preserve the source
Function's access-control assumptions when forwarding, aggregating, testing,
or documenting labels.overlay_templates references..local/.Before considering cloud-topology-service ready, verify service-level
fixtures for all topology kinds covered by the schema. network-connections is
the required high-cardinality benchmark, but it is not enough by itself.
The vSphere topology producer lives in a separate PR worktree. Do not edit that worktree before telling the user, because another agent may be working there.