project-create-topology — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited project-create-topology (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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/sow/specs/topology-function-schema.md | Durable project spec for topology semantics |
.agents/sow/specs/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 rootsrc/go/pkg/topology payload model has been retired and MUST NOT be reintroduced for production topology payloads.
prove parity.
duplicated display strings to production payloads.
not in high-cardinality rows.
.local/ only.vSphere inventory, streaming parents, or another domain.
size on realistic data.
identity, merge_identity, and parent_identity in actor types.Kubernetes workload, SNMP device/interface, or vSphere object.
grouping: 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.
module. Do not scatter orchestrator/path special cases through topology emitters. Metric cgroup selection rules and topology actor-kind/icon/name rules are related but separate contracts.
v: 3; verify selector behavior with theactual POST payload shape (selections.group_by) and keep legacy function-string aliases only as compatibility paths.
correlation links, inferred links, and partial links when their meaning or layout behavior differs.
logical L3 adjacency in distinct L3 link/evidence types.
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 preservenested 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.
actor-owned processes and cgroups tables. Do not rely on the generic Labels tab for structured PID/cgroup inspection when the producer has typed rows.
correlation, grouping, sorting, filtering, and aggregation facts as typed canonical columns.
typed columns and apply any free-form label whitelist only at the Function output boundary. Do not rely on actor_labels for grouping keys.
topologyv1.NewActorOverlayRefsBuilder ortopologyv1.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 stringor string_ref; required selector-param row values must resolve to non-empty strings.
template, actor, or link as selector params; those namesare reserved refs-table convention columns.
netdata.metrics, node_id means node scope, collect_job maps tochart 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().
replacement, actor enrichment, or visible correlation actors.
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 actorswhen the input graph has them, and data.correlation.claims rows for real actors that can satisfy keys.
facts plus declared materialization policy over creating one actor per ephemeral endpoint.
absorb only for exact matches that should remove correlation actorsor loose-side placeholders from the aggregated output.
link for broader or partial matches that should keep the correlationactor or materialized partial actor visible.
replace_actor semantics for weaker placeholder actors that should bereplaced by stronger managed actors.
merge_enrich_actor semantics when multiple payloads providecomplementary facts for the same actor identity.
mutation of the original observation.
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 aproducer has a real mode difference. Do not expose a mode selector for mode-invariant topologies.
label_policy.columns with safe scalar display columns; never letcanonical identity arrays become actor names.
search.columns[] and/or search.label_keys[] for searchableactors. 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 visualemphasis, 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 linkmeaning, 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 autoderives 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 setsports.show_bullets: true.
ports.sources[].name_column; do not userefs, arrays, or JSON as graph bullet labels.
ports.sources[].value_column when one compact row representsmultiple 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 normaland 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.
capability-string icon inference; add a schema/UI icon token first. Runtime/container-family tokens include docker, kubernetes, lxc, nspawn, podman, systemd, user, and the existing container and vm tokens.
size.scale, layout.repulsion, and search use neutraldefaults. Do not expect the UI to preserve legacy self/device/SNMP/ endpoint heuristics for v1.
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 ofactor 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.
actor, formatted endpoint, selected-side endpoint, label lookup, coalesce, const, or explicit scalar JSON path.
selected_side_endpoint, include source/destination actor-refcolumns 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 whenthe 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.endpoint, array_count, or debug_json.
json is debug-only unless a schema-declared scalar projection givesthe UI/aggregator semantics.
info responses as metadata only. Validate full topologyresponses against FUNCTION_TOPOLOGY_SCHEMA.json; do not require metadata-only info responses to carry data.
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 helpersinstead of hand-building table JSON.
src/plugins.d/FUNCTION_TOPOLOGY_SCHEMA.json.max(actor rows, link rows) sovalid 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:
endpoint tuples.
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 unresolvedendpoint dependency links;
correlated_socket: solid, colored, thin, normal-strength, farthest aggregatoroutput links after exact endpoint absorption;
socket: gray, thin, normal-strength, normal-distance local process links, optionallyvariable 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 totype == ownership;
Dependencies where the selected actor is src_actorand 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 normalmodal tab;
visibility: "expanded" columns insteadof separate duplicate sections.
For socket correlation:
for outbound observations, server tuple for inbound observations;
materializes them;
socket_exact rule uses class: resolve_loose_side andaction: absorb;
endpoint_socket links are normal-strength/normal-distance visible links beforeaggregation;
correlated_socket is the farthest output link type after exact absorption.For topology:streaming actor modals:
retained_node_count metric, not fromgraph 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.
For graph-link sources this means 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 outboundas 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 bypath_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 byobserver_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 tablerepresents 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 modalcontract. 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:
Portsover actor_ports.
modal.labels.identification.fields[], backedby actor_labels. Typical keys are display name, management IP, vendor, model, port counts, and LLDP/CDP neighbor counts.
actor_ports columns: SNMP if_index asthe 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.
or any generated sequence; 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 whenthe 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, butmust not duplicate raw LLDP/CDP/FDB/ARP/STP evidence JSON.
actor_port_links. l3_subnet is not aphysical or L2 port-neighbor relationship.
l3_subnet relationship evidenceand an evidence-backed device modal section such as L3 Adjacencies.
l3_subnet links represent shared-subnet logical L3 adjacency betweenresolved 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-planelogical adjacency. It must not be presented as discovery, physical, L2, or port-neighbor evidence.
actor-owned detail tables, such as 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 adjacencybetween 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.
BGP identifiers, ASNs, and endpoint IPs as evidence/display fields, but do not make them the primary graph identity because vendor profiles expose those fields asymmetrically. Parallel sessions between the same managed actor pair in the same routing instance should remain actor-owned peer detail rows under one compact graph relationship unless a future producer contract explicitly adds a more detailed BGP graph mode.
Links sections only for endpoint, segment, orcustom 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.
correlation rules, layout tokens, and schema-token parity.
are documented and tested when cross-payload resolution applies.
actor_labels when the producer has labelsor actor metadata to show.
actor_labels.key, actor_labels.value, actor_labels.source, andactor_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 sourceFunction's access-control assumptions when forwarding, aggregating, testing, or documenting labels.
for null or empty grouping keys instead of merging every null row into one bucket.
high-cardinality evidence rows.
renders a scalar value.
selector-param columns, selector-param string types and values, reserved selector-param names, exactly one convention actor/link owner column, no extra actor/link ref owner columns, non-null owner row values, provider/merge enum membership, and link-type 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.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.