Contributing to Relationships

Relationships follow a schema-defined structure. The Relationship schema (relationships.meshery.io/v1beta3) is the single source of truth for how relationships between components are expressed. The in-tree corpus under models/**/relationships/ is still mostly v1beta2. The version shapes are compatible - Meshery Server bridges registered definitions to the v1beta2 shape for its policy engine - but registration on current releases accepts only v1beta2/v1alpha3 documents (meshkit#1096 adds v1beta3), so a definition that must register today declares v1beta2. Refer to the schema when defining new relationship types or selectors. See Contributing to Schemas for details.

Coding agents: use the gen-relationship skill in .agents/skills/gen-relationship/ (one example of every canonical kind / type / subType).

Relationships within Models classify how Components relate and whether they affect each other.

Overview of Steps to Create Relationships

Prework:

  1. Relationship Identification
  2. Relationship Classification

Development:

  1. Relationship Definition
  2. Relationship Scopes

Postwork:

  1. Relationship Authoring Best Practices and Considerations
  2. Relationship Contribution

Prework

1. Characterize the relationship and any specific constraints

Using your domain expertise, define the qualities of this new relationship. Identify and qualify any specific constraints to be enforced between one or more specific components within the same or different models.

For example, a Kubernetes Service can have a network relationship with a Kubernetes Deployment. That is kind: edge, type: non-binding, subType: network.

Relationship Example

{
  "id": "00000000-0000-0000-0000-000000000000",
  "schemaVersion": "relationships.meshery.io/v1beta3",
  "version": "v1.0.0",
  "kind": "edge",
  "type": "non-binding",
  "subType": "network",
  "status": "enabled",
  "evaluationQuery": "",
  "metadata": {
    "description": "A Service selects Pods of a Deployment."
  },
  "model": {
    "id": "00000000-0000-0000-0000-000000000000",
    "name": "kubernetes",
    "version": "v1.0.0",
    "displayName": "kubernetes",
    "registrant": { "kind": "github" },
    "model": { "version": "" }
  },
  "selectors": [
    {
      "allow": {
        "from": [
          {
            "kind": "Service",
            "model": { "name": "kubernetes" }
          }
        ],
        "to": [
          {
            "kind": "Deployment",
            "model": { "name": "kubernetes" }
          }
        ]
      },
      "deny": {
        "from": [],
        "to": []
      }
    }
  ]
}

You might also know that this relationship should not form when the destination is not a workload the Service can select. Encode that with deny in the same selector-set item.

Codify relationships using your domain expertise. The kind, type, and subType together pick both the visual paradigm and the evaluation policy.

Kind, type, and subType

kind is a schema enum: hierarchical, edge, or sibling. type and subType are open strings. Use an established combination rather than inventing one.

kindtypesubTypeMeaning
hierarchicalparentinventoryParent contains/scopes children. Parent identity is patched onto the child: the Namespace’s name lands in each namespaced resource’s metadata.namespace.
hierarchicalparentaliasChild is a nested object inside the parent (Container inside Pod).
hierarchicalparentwalletChild configuration is held/patched into the parent (WASMFilter β†’ EnvoyFilter).
hierarchicalsiblingmatchlabelsIn-tree tagsets encoding. Components that share labels. Schema also allows kind: sibling; do not mix encodings in one model.
edgenon-bindingreferenceLogical name/id pointer (Deployment β†’ ConfigMap).
edgenon-bindingnetworkDocumented network selection without provisioning an attachment (Service β†’ Deployment).
edgebindingnetworkConnecting provisions or rewrites network identity. Rare.
edgenon-bindingfirewallPolicy that allows or denies traffic (NetworkPolicy β†’ Pod).
edgebindingpermissionAssigns identities (Role β†’ ServiceAccount).
edgenon-bindingpermissionMentions a role or identity without binding it.
edgebindingmountStorage or device is attached (PVC β†’ Pod).
edgenon-bindingannotationDesigner-only line. Set metadata.isAnnotation: true. No patch.
edgenon-bindingaliasNamed stand-in, not nested ownership.
edgenon-bindinginventoryRare peer index/list. Prefer hierarchical parent inventory for containment.

badge is a visual paradigm only; there is no in-tree encoding. Propose a visualization before introducing subType: badge.

Hierarchical from / to: from is the child, to is the parent.

  • Inventory: parent mutates the child.
  • Alias and wallet: child mutates the parent.

Binding vs non-binding: binding means forming the relationship assigns, mounts, or entitles. non-binding means the link is real (selector, name, policy match) but does not itself provision the attachment.

2. Classify relationship type and specify visual representation

Browse and pick the most appropriate visualization for this relationship by using one of the predefined relationship visualizations.

Example Visual Representations
Kind: Hierarchical
subType: Parent | Namespace (Parent) and ConfigMap (child), Role (Child) (open in playground)
Hierarchical - Parent: Namespace to other components
subType: Inventory | Namespace and ConfigMap (open in playground)
Hierarchical - Parent: Namespace to other components
Kind: Edge
Type: `Non-Binding`, subType: `Permission`: Cluster Role with Cluster Role Binding to Service Account (open in playground)
Binding
Type: `Binding`, subType: `Mount`: Pod to Persistent volume via Persistent volume claim (open in playground)
Edge - Mount
Type: `Non-Binding`, subType: `Network`: Ingress to Service (open in playground)
Edge - Network
Type: `Non-Binding`, subType: `Network`: Service to Pod (open in playground)
Edge - Network: Ingress to Service
Type: `Non-Binding`, subType: `Network`: Service to Service (open in playground)
Edge - Network
Type: `Non-Binding`, subType: `Network`: Service to Endpoint (open in playground)
Edge - Network
Type: `Non-Binding`, subType: `Network`: Service to Deployment (open in playground)
Edge - Network
type:non-binding, subType: `Network`: Network Policy (Pod to Pod) (open in playground)
Edge - Network Policy

Once selected, note the relationship’s kind, type, and subType. If an existing visualization does not seem appropriate, propose a new one. Use the whiteboard feature of Meshery’s extensions to sketch the relationship.

Development

3. Create a Relationship Definition as a JSON file

Create a relationship definition as a JSON file, placing this new definition file into its respective model folder (see Contributing to Models). A model may include any number of relationship definitions. Filename convention: {kind}-{type}-{subType}-<suffix>.json.

Include:

  • schemaVersion: relationships.meshery.io/v1beta3 is the authoring target, but declare v1beta2 for definitions that must register on current servers (see the note at the top of this page). Keep v1beta2 when refining an existing in-tree file unless you are deliberately migrating it.
  • kind: The genre of relationship (hierarchical, edge, sibling).
  • type: The augmentative category (parent, binding, non-binding, sibling, …).
  • subType: The specific visual paradigm (inventory, mount, network, wallet, reference, matchlabels, …).
  • selectors: The scope of the relationship. One selector-set item is an OR. Inside an item, every from entry relates to every to entry - a cross-product (AND).
  • evaluationQuery: Deprecated. Set it to "" as every in-tree definition does; the evaluation engine enters through the fixed data.relationship_evaluation_policy package and dispatches on kind/type/subType.
  • metadata.description: A characterization of the relationship, its purpose, and constraints.

4. Configuring the Scope of Relationships

The extent to which a relationship affects components within a model or beyond a model is defined and controlled using scopes.

Global Scope

Global scope is defined using the model attribute in the relationship definition.

Relationships can be confined to a specific model or allowed to affect all models. For example, if the model is specified as aws-ec2-controller, the relationship will work for those components that belong to the aws-ec2-controller model.

Local Scope

Local scope is defined and controlled via selectors in the relationship definition.

Relationship selectors refine applicability. Selector details determine whether there is a match: which models and components are involved, and any constraints. Selector items combine with AND. Selector sets (the selectors array) combine with OR.

Selectors are an array. Each entry has allow and optional deny, each with from and to. Only components inside the same selector-set item relate to each other: each object in from relates to each object in to.

When many from/to combinations would otherwise force a complicated deny, split them into additional selector-set items.

Note: When defining Hierarchical relationships, the from field represents the child component, while the to field represents the parent component.

Actions: mutatorRef and mutatedRef

Patches copy values from one component to another when the selector matches. Both fields are nested arrays of string path segments (string[][]). Sequence length must match: index i of mutatorRef is copied onto index i of mutatedRef.

"mutatorRef": [["config", "url"], ["config", "name"]],
"mutatedRef": [["configPatch", "value"], ["name"]]

[config, url] is patched onto [configPatch, value]; [config, name] onto [name].

FieldRole
mutatorRefSource. JSON path of the value to read.
mutatedRefSink. Path segments of the field to patch.
patchStrategyHow to apply. Schema enum: merge, strategic, add, remove, replace, copy, move, test. The in-tree corpus and the evaluation engine use replace exclusively; default to replace unless you need different semantics.

Paths are relative to the Meshery component document (configuration, displayName, component.kind, …), not the raw Kubernetes YAML root. _ may mark only the first array position in a path; later arrays need an explicit index. Omit patch when the relationship only matches (tagsets, annotation).

Relationship Selector Example

"selectors": [
  {
    "allow": {
      "from": [
        {
          "kind": "WASMFilter",
          "model": { "name": "meshery-core" },
          "patch": {
            "patchStrategy": "replace",
            "mutatorRef": [
              ["configuration", "config"]
            ]
          }
        }
      ],
      "to": [
        {
          "kind": "EnvoyFilter",
          "model": { "name": "istio-base" },
          "patch": {
            "patchStrategy": "replace",
            "mutatedRef": [
              ["configuration", "spec", "configPatches", "_", "patch", "value"]
            ]
          }
        }
      ]
    },
    "deny": {
      "from": [],
      "to": []
    }
  },
  {
    "allow": {
      "from": [
        {
          "kind": "ConfigMap",
          "model": { "name": "kubernetes" },
          "patch": {
            "patchStrategy": "replace",
            "mutatorRef": [
              ["configuration", "metadata", "name"]
            ]
          }
        }
      ],
      "to": [
        {
          "kind": "Deployment",
          "model": { "name": "kubernetes" },
          "patch": {
            "patchStrategy": "replace",
            "mutatedRef": [
              ["configuration", "spec", "template", "spec", "containers", "_", "envFrom", "0", "configMapRef", "name"]
            ]
          }
        }
      ]
    },
    "deny": {
      "from": [],
      "to": []
    }
  }
]

The first selector-set item (WASMFilter β†’ EnvoyFilter) is independent of the second (ConfigMap β†’ Deployment). Use separate items when the pairs should not cross-match.

The WASMFilter example is hierarchical parent wallet (child config patched into the parent). The ConfigMap example is edge reference (a name pointer), not hierarchical inventory.

Understanding Relationship Policies and their Evaluation

Meshery evaluates designs with Open Policy Agent. The engine enters through the fixed policy package data.relationship_evaluation_policy and dispatches on each definition’s kind, type, and subType. The policies live under models/meshery-core/<version>/<definition-version>/policies/.

What value should evaluationQuery carry?

An empty string. The property is deprecated (see the schema’s deprecation notice) and the current engine ignores it; every in-tree definition sets "". The historical per-relationship rule name was {kind}_{subType}_relationship β€” no {type} segment β€” and any value you do set must be a valid Rego identifier (letters, digits, underscores), so a hyphenated type such as non-binding can never appear in one.

Postwork

5. Relationship Authoring Best Practices and Considerations

General

  1. Use camelCase on the wire (subType, mutatorRef, schemaVersion).
  2. Author against relationships.meshery.io/v1beta3 (declare v1beta2 while current servers require it - see the top of this page). Do not use core.meshery.io/v1alpha2 or v1beta1.

Scoping

  1. To apply a relationship across models, set the selector model.name to *. To limit it to one model, specify that model name (case sensitive).
  2. Absence of a selector property is interpreted as the wildcard *.
  3. Values for kind, version, and model are case-sensitive.

Actions

  1. If a mutatedRef / mutatorRef path contains more than one array, only the first array position may be _; later arrays must be an explicit index (0, 1, …).
  2. mutatedRef currently does not support patching an array value itself.
  3. Pair every mutator path with a mutated path. Do not swap source and sink.
  4. Verify each path against the component schema in models/<model>/.../components/<Kind>.json.

Matching

  1. Targets of a Relationship can be specific Components or entire Models.
  2. Leave evaluationQuery empty (""); evaluation dispatches on kind, type, and subType.
  3. metadata.isAnnotation: true means Meshery must not evaluate or patch the relationship.

Conflicts

  1. Ensure deny selectors and allow selectors do not overlap for the same pair.
  2. In the event of conflicting Relationship Definitions, the union between them is taken.
    • If we have two Relationships, one from (Component A) to (Component B and Component F), and another from (Component A) to (Component B and Component C), then it is similar to having a Relationship from Component A to Component B, C and F.
  3. No relationship kind is inherently more important than another.

Schema Conformance

Every mutatorRef/mutatedRef path rooted at configuration. must resolve against the JSON schema of the component it addresses (models/<model>/<version>/v1.0.0/components/<Kind>.json). For a selector item belonging to the relationship’s own model, that is the schema shipped in the same model version directory as the definition; for a selector item that references a different model - as a cross-model edge does - it is the schema in that model’s newest version directory. A path that names a field the component schema does not define is written by the evaluation engine but never reaches the rendered resource - the defect behind #21482, where an Ingress relationship patched the pre-1.22 backend.serviceName shape into a networking.k8s.io/v1 component.

  • Exemptions. The configuration.metadata subtree and paths rooted at displayName or component are not checked: component schemas describe the resource’s spec, not its ObjectMeta or the Meshery component envelope.
  • Where it runs. server/policies/relationship_schema_conformance_test.go, executed by the policies test workflow on every change under models/**.
  • When it fails, fix the path. The knownUnresolvedMutationPaths allowlist exists only for known pre-existing defects, and cites the open follow-up issue tracking their repair (#21490). An allowlisted entry must keep failing, so repairing one of those definitions means deleting its line in the same pull request.

6. Contribute your relationship to the Meshery project

Submit a pull request to the Meshery repository with your new relationship definition, so that all users can benefit from the relationship(s) you have defined.

Keeping your relationship definition in a separate file allows for easier management and review of the relationship(s) you have defined.

For more information refer - Model - Construct Models in Meshery