Skip to content
GitmoapdocsBeta
Guide· How do I…?

Pipeline components

Overview

A pipeline component is a reusable fragment of a pipeline — a few nodes, the edges between them, the ports it exposes at its edge and the parameters it takes — published as a numbered version and referenced by as many pipelines as you like. Forty repositories that build the same way stop holding forty copies of the same three steps: you publish rust-build once on the group that owns them all, each repository references it, and improving the shared part is one edit and one publish instead of forty merge requests.

The version number is the contract. Publishing checks the change you made against the last version you published and refuses a number that understates it, so a pipeline tracking v1.* can pick up your patch releases without you promising by hand that nothing broke. When something does need to break, you deprecate the old version, see exactly which pipelines are still on it, and move them across in one sweep.

Quick start

Quick start3 steps

Share part of a pipeline as a component

You’ll need Maintainer on the group or the repository that will own it.
  1. Choose Pipelines, then the Components tab, then New component.

  2. Build it the way you build a pipeline: its stage slots, the steps inside them, and the inputs a consumer wires.

  3. Choose Create component, then publish a version from its page. Every pipeline beneath this scope can drop it onto its canvas.

Before you start

  • A group or a repository to own the component.A component belongs to one scope and is usable by that scope and everything beneath it. A component on your root group is available to every repository in the namespace; a component on one repository is available only to that repository's own pipelines.
  • Reporter to read, Maintainer to write.Every call is authorized against the group or repository named in the path, not against the scope that owns the component: a public one answers anyone, signed in or not; an internal one answers anyone signed in; a private one answers only its members, Reporter and above. A component owned by a parent group is therefore readable through any repository beneath it that you can read. Creating, editing, publishing, deprecating, sunsetting, re-pinning and deleting all need Maintainer, and access inherits downwards — Maintainer on a parent group is Maintainer on its repositories' components.
  • Maintainer on each consuming repository, if you plan to re-pin.Owning a component is not authority over the pipelines that use it. A sweep rewrites the pipelines you can manage and names the ones you cannot, rather than failing whole.
  • A token with the right scope, if you are calling the API or the CLI: pipeline:read for every read, pipeline:manage for every write. Scopes are fixed when a token is minted, so a script that only reports on usage should carry pipeline:read alone.
  • The providers your component needs, installed where it is used.A component records the capabilities its nodes call. A repository whose group has not installed those providers still sees the component in its list, marked with what is missing, so the fix is visible rather than the component being hidden.

How it works

Three things, not one

ThingMutable?What it is
The componentyesThe identity: a name unique within its scope, a description, an owner, and a working draft of the body
A versionneverOne publication of that draft, numbered v{major}.{minor}.{patch}. Its contents never change and a number is never reused
A usagederivedOne row per pipeline that references the component, recording the reference the author wrote and the version it last resolved to

Editing the draft cannot break anything, because nothing references a draft. Only a published version is referenceable, and only publishing makes an edit visible to a consumer.

A component has no stages of its own

A pipeline has stages. A component has stage slots — a short, ordered list of positions with names that mean something inside the component — and the pipeline that uses it decides which of its own stages each slot lands in.

component body the pipeline that uses it
stage_slots: [prepare, run] stages: [build, test, deploy]
node "fetch" in slot "prepare" ──► stage_map: { prepare: "build", run: "test" }
node "cargo" in slot "run" fetch lands in "build", cargo lands in "test"

Every slot the body declares must be mapped, and the stages you map them to have to run in the same order the slots are declared in. Several slots may share one stage; an inversion is refused with a message naming both slots, which is a much better error than the one you would get after the fragment had been flattened into nodes you never wrote.

Parameters replace whole values

A component declares typed parameters, and the body refers to one by putting {"$param": "name"} where the value belongs:

json
{
"capability_id": "docker:build",
"config": {
"context": ".",
"tag": { "$param": "image_tag" }
}
}

The instance that uses the component supplies image_tag, and expansion writes the value in whole. There is no string interpolation and no expression language: a reference occupies an entire value slot or it is not a reference. To build a string out of parts, use $join, whose arguments may themselves be references:

json
{ "tag": { "$join": [{ "$param": "registry" }, "/app:", { "$context": "short_sha" }] } }

Two escapes are worth knowing. {"$literal": <value>} emits its value verbatim, which is how a configuration object that genuinely needs a key called $param gets one. And an object carrying $param alongside other keys is not a reference at all and passes through untouched — the rule is one key, or nothing.

A parameter may declare allowed_values, a closed set the supplied value must belong to. Adding a member to that set is a minor change; introducing the set, or removing a member from it, is a major one, because a consumer whose value has just left the set stops validating.

Ten node settings are scalars rather than JSON documents and so cannot hold a reference object: the connection a node authenticates with, its CPU, its memory, its timeout, the environment it deploys to, the environment whose variables it reads, the service it acts on, whether its failure is tolerated, and how many times and how long apart it retries. A component node names the parameter for each of those in a param_slots block instead. It is the same substitution at the same moment, which is what lets one deploy component ship to staging in one place and production in another rather than being published twice. A component that builds and then deploys names the same parameter in its build's variables_from and its deploy's environment, so each instance builds with the settings of the environment it deploys to. The capability a node calls and the provider version it pins are never parameterised, because those two decide which code runs and a version whose requirements are unknowable cannot be checked at all.

A value that fits the parameter's declared type can still be one the setting cannot hold — production! is a string, and it is not a valid environment name. That is refused when the pipeline is saved, naming the setting and the value. The platform never quietly declines to apply one: a deploy node silently left without its environment would lose that environment's protection and its approval step, and would look deliberate.

Read the consuming pipeline's variables

A body's configuration may read a variable with {"$var": "NAME"}, exactly as a pipeline step's can (see Read a variable in a step's configuration). Expansion leaves it untouched, so it reads the variables of the step it becomes in the pipeline that uses the component — that step's environment, its repository and its groups — not anything of the component's own.

That is what keeps a deploy component small. Rather than a parameter for every bucket, distribution and endpoint, it takes one parameter for the environment, spends it on the node's environment setting, and reads the values the environment already holds:

json
{
"stage_slot": "deploy",
"node": {
"id": "sync",
"name": "Sync to S3",
"capability_id": "aws:s3-sync",
"config": {
"bucket": { "$var": "WEB_S3_BUCKET" },
"delete": true
}
},
"param_slots": { "environment": "target" }
}

A pipeline that sets target to production syncs to production's bucket, and a second instance set to staging syncs to staging's, from one published version.

Every version lists the names its body reads as variable_requirements — what a consuming step has to be able to see. Each is checked against the consuming pipeline when one of its runs starts, and a missing one refuses the run naming your instance and the variable. Publishing a version that reads a name the previous version did not is a major change; reading fewer is a minor one.

A pipeline using a component may also hand a variable to a parameter, by writing {"$var": "NAME"} as the parameter's value in the instance's params. The variable is read from the consuming step, like any other, and it is that pipeline's choice rather than part of the component's variable_requirements. The parameter has to be able to receive one, and is refused with the violation component_param_var_refused otherwise:

  • It is declared string. A variable is always a string, and nothing converts one into a number or a true-or-false value.
  • It declares no allowed_values. A fixed set cannot be checked against a value nobody knows until the run starts.
  • The component does not spend it on a node setting in param_slots, such as environment or connection. Those settings decide how the run is put together, which happens before any variable is read.

A parameter's default cannot read a variable. A default is the component author's choice, so write the {"$var": …} in the body where the value is used instead.

Version references, and which ones float

An instance names the version it wants in one of four forms:

ReferenceSelects
v1.2.0exactly that version, whatever else is published
v1.2.*the newest active version with major 1 and minor 2
v1.*the newest active version with major 1
latestthe newest active version of any major

The last three float: they re-resolve every time the pipeline is written or run, so a publish reaches them without anybody editing anything. A floating reference only ever selects an active version — never a deprecated or sunset one — which is what makes deprecating a safe way to retire something. An exact reference is immune to a publish and is the right choice when you need the same bytes every time.

The compatibility gate

Publishing computes what moved between the draft and the newest version you have not sunset, works out the lowest number that change permits, and refuses anything lower. The contract it compares is exactly the parameter declarations, the boundary ports and the variables the body reads — not behaviour.

What changedLowest permitted bump
A parameter removed, retyped, or added as required with no default; a value set introduced or narrowed; a boundary port removed, renamed or retyped; an optional boundary input made required; a variable read that the previous version did not readmajor
A parameter added as optional or with a default; a required parameter relaxed to optional; a value set widened or dropped; a boundary output added; an optional boundary input added; a variable no longer readminor
Anything else — internal nodes, internal edges, configuration that reads no new variable, display names, the provider versions the nodes pinpatch

Note

The gate sees the contract, not what the component does. A node's configuration can change inside a patch release and still break a consumer, and no diff catches that. Three things bound it: an exact reference is always available, deprecating removes a version from every floating track without disturbing anyone pinned to it, and a dry-run publish counts the consumers that move on their own and re-checks a sample of them against the draft first.

Retirement has three states

active ──deprecate──► deprecated ──sunset──► sunset
▲ │
└──────── undeprecate ───────┘
active every reference reaches it
deprecated still runs; an exact reference still reaches it; no floating reference selects it
sunset nothing reaches it, exact references included

A version is never deleted. Sunsetting is the only state that breaks a pipeline still pinned to the version, and it does so loudly: publishing that pipeline is refused, and a run triggered from it fails to start, both with a message naming the instance, the component and the version. A draft of it still saves, carrying the violation.

What happens when a pipeline uses one

Referencing a component adds no new mechanism to a pipeline. Before anything else runs, each instance is replaced by the nodes and edges of the version it resolves to, and everything downstream — structural checks, port wiring, configuration validation, environment and service binding — runs on a flat graph that no longer mentions components at all.

Two visible consequences. Node identifiers inside the component are prefixed with the instance's, so a node called build inside an instance called checkout becomes checkout--build, displayed as Checkout / Build and badged with the component and the version it resolved to. And a component's boundary outputs become candidates for automatic wiring in the pipeline around it, so adding an instance can make a previously unambiguous connection ambiguous. That is the rule working; the remedy is an explicit edge.

How to

Every task below exists twice — once for a component a group owns and once for a component a repository owns. The steps, the fields and the refusals are identical; only the owner in the path changes. Each task shows one scope, and the Reference section lists both.

Find the components you can use here

The listing for a scope answers what that scope may reference: its own components plus every parent group's, with the nearest declaration of a name winning. search narrows by name and description, and own_scope_only drops the inherited ones when you want to see only what you own.

One thing the listing does not show you: a component owned by a group you cannot read is dropped from it. That filter is on the picker alone — a pipeline in the subtree can still reference the component, and you can still open it by its id through this scope's own path. If somebody points you at a component you cannot find in the list, ask them for its id, or ask for read access to the group that owns it.

Open the repository, choose Settings → Pipelines → Components. The list shows every component this repository may reference. A component owned by a parent group is marked Inherited with the group it comes from; a component that needs a provider nobody has installed here is marked with the missing capability rather than hidden, because the fix is an install. Use the filter box to search names and descriptions, and the Owned here only toggle to hide the inherited ones.

Terminalbash
gitmoap pipeline-components list-repo-pipeline-components --repo-id <id>
curlbash
curl -X GET https://api.gitmoap.example/repositories/{repo_id}/pipeline-components \
-H "Authorization: Bearer $GITMOAP_TOKEN"

At group scope the same listing walks up from that group, so a root group sees only its own.

Open the group, choose Settings → Pipelines → Components. The list works exactly as a repository's, with the walk starting at this group.

Terminalbash
gitmoap pipeline-components list-group-pipeline-components --group-id <id>
curlbash
curl -X GET https://api.gitmoap.example/groups/{group_id}/pipeline-components \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Create a component

A component is created with its name, an optional description, and a draft body. The name is lowercase letters, digits and hyphens, up to 100 characters, may not start or end with a hyphen, and is unique within the scope that owns it. The body has to be complete enough to stand on its own — at least one stage slot and at least one node — and is validated as you save it, not only when you publish. Nothing can reference the component until you publish a version, so creating one is safe in every sense.

Put it on the group that owns the repositories that will use it. A component on a repository is only ever usable by that repository, which is right for a fragment that encodes something local and wrong for anything you expect to share.

Open the group, choose Settings → Pipelines → Components → New component. Name it, describe what it does, then build the body in the editor: declare the stage slots in the order the work happens, add the nodes and wire them, declare the parameters the consumer supplies, and expose the inputs and outputs you want the consumer to be able to wire. Create saves it as a draft.

Terminalbash
gitmoap pipeline-components create-group-pipeline-component \
--group-id <id> \
--name <name>
curlbash
curl -X POST https://api.gitmoap.example/groups/{group_id}/pipeline-components \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "body.component_instances[].component_id": "<uuid>", "body.component_instances[].id": "<string>", "body.component_instances[].name": "<string>", "body.component_instances[].version": "<string>", "body.edges[].id": "<string>", "body.edges[].source_node_id": "<string>", "body.edges[].target_node_id": "<string>", "body.inputs[].name": "<string>", "body.nodes[].stage_slot": "<string>", "body.outputs[].name": "<string>", "body.parameters[].name": "<string>", "body.parameters[].param_type": "<one of array | boolean | number | object | string>", "name": "<string>" }'

For something genuinely local to one repository, create it there instead.

Open the repository, choose Settings → Pipelines → Components → New component, and fill in the same form. The component is visible only to this repository's pipelines.

Terminalbash
gitmoap pipeline-components create-repo-pipeline-component \
--repo-id <id> \
--name <name>
curlbash
curl -X POST https://api.gitmoap.example/repositories/{repo_id}/pipeline-components \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "body.component_instances[].component_id": "<uuid>", "body.component_instances[].id": "<string>", "body.component_instances[].name": "<string>", "body.component_instances[].version": "<string>", "body.edges[].id": "<string>", "body.edges[].source_node_id": "<string>", "body.edges[].target_node_id": "<string>", "body.inputs[].name": "<string>", "body.nodes[].stage_slot": "<string>", "body.outputs[].name": "<string>", "body.parameters[].name": "<string>", "body.parameters[].param_type": "<one of array | boolean | number | object | string>", "name": "<string>" }'

Three node settings are refused inside a component body, and the refusal happens when you save the body so the person who wrote the field sees the error:

  • Path filters (changes) — the paths would be matched against a repository the component author does not own, and a skipped internal node propagates its skip outward through the boundary into nodes that have nothing to do with the component.
  • Approvals (approval) — naming an approver needs standing on it — Maintainer on a group whose role you name, authority over a team you name — so a team using your component would fail its own pipeline save on an approver it has never heard of. A cross-team gate belongs on an environment.
  • Resource groups (resource_group) — a resource-group key is a lock shared across the namespace. One component used forty times would quietly serialise forty pipelines against a key none of their authors chose.

An environment and a service are allowed, and are re-resolved and re-authorized against the consuming repository after expansion, so a repository that may not deploy to production still cannot.

Edit the draft

The draft is a full replacement: send the name, the description and the body you want, not a patch. Published versions are untouched, so an edit here changes only what your next publish would capture and cannot break a running pipeline — and that holds for a rename too, because an instance stores the component's id and never its name.

A draft still has to be a well-formed body. A save that names a stage slot the body does not declare, repeats an identifier, refers to a parameter nothing declares or carries a field a component may not hold is refused with 400 PIPELINE_VALIDATION_FAILED and every violation listed, so a stored draft is always one a publish would accept.

Open the component and stay on the Draft tab. Edit the body in the editor and choose Save draft. Anything wrong with the body is reported against the element that carries it, and the save does not go through until you have fixed it.

Terminalbash
gitmoap pipeline-components update-group-pipeline-component \
--group-id <id> \
--component-id <id> \
--name <name>
curlbash
curl -X PUT https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "body.component_instances[].component_id": "<uuid>", "body.component_instances[].id": "<string>", "body.component_instances[].name": "<string>", "body.component_instances[].version": "<string>", "body.edges[].id": "<string>", "body.edges[].source_node_id": "<string>", "body.edges[].target_node_id": "<string>", "body.inputs[].name": "<string>", "body.nodes[].stage_slot": "<string>", "body.outputs[].name": "<string>", "body.parameters[].name": "<string>", "body.parameters[].param_type": "<one of array | boolean | number | object | string>", "name": "<string>" }'

Review a component before you use it

Reading a component gives you its draft body and its published versions, newest first. This is what to read before writing an instance: the parameters you have to supply, the ports you can wire, the variables each version reads — its variable_requirements, which the step it becomes must be able to see — and which versions are still active.

Open the component from the components list. Draft shows the working body, Versions lists what has been published, and Used by lists the pipelines referencing it.

Terminalbash
gitmoap pipeline-components get-group-pipeline-component \
--group-id <id> \
--component-id <id>
curlbash
curl -X GET https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Check what a publish would do

Publishing takes a dry_run that validates the draft, checks the number you propose against the compatibility gate, and reports the blast radius — how many consumers wrote a floating reference rather than an exact one, and whether a sample of those still expands and validates against the draft. Nothing is written.

A dry run still needs the number you mean to publish, and it is judged exactly as the real publish would judge it. Propose one that understates the change and you get the refusal rather than a report — naming the step the contract moved by and the lowest number the gate permits. Propose one that is high enough and the report comes back carrying minimum_version, the lowest you could have used.

Read the floating count as how many consumers can move without being asked, not as how many will land on this number: a consumer tracking v1.* is counted whether you are publishing v1.4.3 or v2.0.0. Once the version exists, upgrade impact answers the narrower question.

Run it before every publish that is more than a typo. The sample covers up to 10 consuming pipelines; a failure in the sample is a strong signal, and a clean sample is not a proof for the other thirty.

Tip

You never have to guess the number: propose one, and either the report or the refusal names the lowest the gate permits. If you asked for v1.3.0 and the answer is v2.0.0, you removed something from the contract — check the parameter list and the boundary ports against the previous version before deciding whether the removal was intended.

Publish a version

A publish freezes the current draft under a version number. The number must be at or above what the compatibility gate permits, and the same number is never published twice: a retried publish that already succeeded answers 409, deliberately, because a silent success would mean a version's contents had changed.

Open the component, choose Versions → Publish. The dialog proposes the lowest number this change permits and explains why — the contract moved by a patch, minor or major step. Write a changelog, use Check without publishing to see the blast radius first, then Publish. The version appears at the top of the list as Active.

Terminalbash
gitmoap pipeline-components publish-group-pipeline-component-version \
--group-id <id> \
--component-id <id> \
--version <version>
curlbash
curl -X POST https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/versions \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "version": "<string>" }'

List and read published versions

Versions come back newest first, ordered by version number rather than alphabetically, so v0.10.0 sits above v0.3.0. Filter by lifecycle_state to see only the active versions, only the deprecated ones or only the sunset ones; leave it off and you get all three.

Open the component and choose Versions. Each row shows the number, the state, who published it and when, the changelog, the node count and the capabilities it needs. The State filter narrows to active, deprecated or sunset.

Terminalbash
gitmoap pipeline-components list-group-pipeline-component-versions \
--group-id <id> \
--component-id <id>
curlbash
curl -X GET https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/versions \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Reading one version gives you the body it froze — the definitive answer to what does v1.2.0 actually do, which the draft cannot answer once it has moved on.

Open the component, choose Versions, and click the version number. The frozen body renders as a graph beside its parameters and boundary ports.

Terminalbash
gitmoap pipeline-components get-group-pipeline-component-version \
--group-id <id> \
--component-id <id> \
--version <id>
curlbash
curl -X GET https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/versions/{version} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Reference a component from a pipeline

A component instance is a node in your pipeline. It carries the component's id, an instance identifier of up to 20 characters that is unique among the pipeline's nodes, the version reference you want, a map from every stage slot to one of your stages, and the parameters the body declares:

json
{
"id": "rustbuild",
"name": "Rust build",
"component_id": "3f1c0a52-0f2f-4a0a-9d1f-0b4b5a7c8d90",
"version": "v1.*",
"stage_map": { "prepare": "build", "run": "build" },
"params": { "toolchain": "1.83", "features": ["tls-vendored"] }
}

Wire into it with ordinary edges: the target is the instance and the port is one the component exposes as a boundary input. Wire out of it the same way, from a boundary output. A component is a node with ports, and there is no second wiring mechanism to learn.

A string parameter may take one of your variables instead of a written value — "params": { "bucket": { "$var": "WEB_S3_BUCKET" } } — which is read from your step when the run starts. Read the consuming pipeline's variables says which parameters can.

You may only reference a component whose owner is your repository or one of its parent groups. A component elsewhere is refused even if you have its identifier: publishing the pipeline comes back 400 PIPELINE_VALIDATION_FAILED with a violation naming your instance and saying the component does not exist here, and a draft save keeps the violation on the draft rather than blocking it. It reads the same whether the component is missing or merely out of your chain, because a scope you cannot see must not become discoverable by guessing.

Saving and publishing pipelines is covered in Pipelines; the only thing components add to it is that expansion runs first, so a violation inside a component is reported against your instance with the inner node named in the message.

See which pipelines use a component

The consumer list is the answer to what will this break. Each row is one reference: the pipeline, the repository, the instance identifier, the reference its author wrote, and the version that reference resolved to at the last write.

Open the component and choose Used by. Filter by version to see only the pipelines sitting on one release. Rows are ordered by resolved version, so everything still on an old release groups together.

Terminalbash
gitmoap pipeline-components list-group-pipeline-component-usages \
--group-id <id> \
--component-id <id>
curlbash
curl -X GET https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/usages \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Rows for repositories you cannot read are dropped after the page has been fetched, so a page can come back shorter than the size you asked for while a next page is still waiting. A group-owned component consumed across a subtree you only partly administer therefore shows you fewer consumers than exist, which is deliberate.

For a repository-owned component, open it from the repository's components list and choose Used by. Its consumers are the pipelines of that repository.

Terminalbash
gitmoap pipeline-components list-repo-pipeline-component-usages \
--repo-id <id> \
--component-id <id>
curlbash
curl -X GET https://api.gitmoap.example/repositories/{repo_id}/pipeline-components/{component_id}/usages \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Measure how far consumers are from a version

Upgrade impact answers the question that comes after a publish: who has still not moved. It measures every consumer against one version — the newest published one by default — and sorts them into three dispositions, because there are three different things to do about them.

DispositionWhat it meansWhat to do
on_targetThe reference already selects the targetNothing
needs_repinThe reference cannot reach the target from where it is, and waiting will not change thatRe-pin it, or ask the repository's Maintainer to
unresolvableThe reference selects no published version at all right nowFix this first — that pipeline cannot run

Every reference is re-resolved as the report is built rather than read from what the last pipeline write saw, because a floating reference moves without its pipeline being written and that drift is exactly what the report exists to surface. Up to 10 consumers are also re-expanded against the target and re-validated, so you learn about a break before you cause it.

The report covers up to 500 consumers and says truncated when there are more, and its counts describe what it covered and what you are allowed to read rather than the whole population. Read the consumer list, which pages, when you need every one of them.

Open the component, choose Used by → Upgrade impact, and pick the version to measure against. The summary counts the three dispositions and the table lists each pipeline with the reference it wrote and the version that selects today. Re-pin these carries the needs_repin set straight into a sweep.

Terminalbash
gitmoap pipeline-components get-group-component-upgrade-impact \
--group-id <id> \
--component-id <id>
curlbash
curl -X GET https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/upgrade-impact \
-H "Authorization: Bearer $GITMOAP_TOKEN"

The same report exists on a repository-owned component, over that repository's own pipelines.

Terminalbash
gitmoap pipeline-components get-repo-component-upgrade-impact \
--repo-id <id> \
--component-id <id>
curlbash
curl -X GET https://api.gitmoap.example/repositories/{repo_id}/pipeline-components/{component_id}/upgrade-impact \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Move consumers onto a different reference

A re-pin rewrites the version reference in consuming pipelines. Give the reference to move everyone to; optionally give the reference to move from, so only instances written exactly that way are touched, and a list of pipelines to restrict the sweep to.

Run it with dry_run first. A dry run performs every read, every rewrite and every validation and writes nothing, so its report is an honest answer to would this break anything.

Three things about the result are worth expecting rather than discovering:

  • Skips are normal and every one is named. A pipeline is left alone when you cannot manage its repository (forbidden), when you cannot read it at all (unreadable), when it already uses the target reference (already_pinned), when the rewritten definition would stop validating (validation_failed, carrying the message), or when it has been deleted since the list was built (pipeline_missing).
  • Nothing is written for a pipeline that would not validate. Each pipeline is validated exactly as an ordinary save validates it, and a refusal becomes a row rather than a broken pipeline.
  • A sweep covers up to 500 consumers. Past that the report says truncated. Every pass reads from the beginning of the consumer list, and a source reference or an explicit list of pipelines narrows what the sweep rewrites rather than which rows it reads — so after a truncated pass, run the sweep again and read the consumer list, which pages properly, to see what is still outstanding.

There is no transaction across pipelines, on purpose: they live in different repositories, and a partial sweep that reports exactly what it did beats one that rolls back thirty-nine successful writes because the fortieth failed.

Open the component, choose Used by → Re-pin consumers. Pick the target reference, optionally restrict to one source reference or to a selection of pipelines, and choose Preview. The preview lists what would be rewritten and what would be skipped with the reason for each. Apply performs the writes.

Terminalbash
gitmoap pipeline-components repin-group-component-usages \
--group-id <id> \
--component-id <id> \
--to <to>
curlbash
curl -X POST https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/repin \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "to": "<string>" }'

The same sweep exists on a repository-owned component, over that repository's own pipelines.

Terminalbash
gitmoap pipeline-components repin-repo-component-usages \
--repo-id <id> \
--component-id <id> \
--to <to>
curlbash
curl -X POST https://api.gitmoap.example/repositories/{repo_id}/pipeline-components/{component_id}/repin \
-H "Authorization: Bearer $GITMOAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "to": "<string>" }'

Retire a version safely

Deprecating a version removes it from every floating track without disturbing anyone pinned to it exactly. It still runs. Consumers tracking v1.* move off it at their next resolution; consumers pinned to v1.4.2 stay where they are until somebody moves them. This is the way to retire a version.

Open the component, choose Versions, and pick Deprecate from the version's row menu. The row moves to Deprecated, and nothing else changes until each consumer next resolves its reference.

Terminalbash
gitmoap pipeline-components deprecate-group-pipeline-component-version \
--group-id <id> \
--component-id <id> \
--version <id>
curlbash
curl -X POST https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/versions/{version}/deprecate \
-H "Authorization: Bearer $GITMOAP_TOKEN"

A floating reference only ever selects an active version, so deprecating the newest one leaves latest reaching the next active version rather than resolving to nothing.

A pipeline pinned exactly to a version you have deprecated still saves and still runs. Saving it reports a warning naming the instance, the component and the version — which is the signal to move it, not a refusal.

If you deprecated something in error, put it back:

Choose Restore from the version's row menu. It returns to Active and to every floating track it belongs to.

Terminalbash
gitmoap pipeline-components undeprecate-group-pipeline-component-version \
--group-id <id> \
--component-id <id> \
--version <id>
curlbash
curl -X POST https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/versions/{version}/undeprecate \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Stop a version from running at all

Warning

Sunsetting is the one lifecycle change that breaks pipelines. Nothing resolves a sunset version any more — an exact reference included — so a pipeline still pinned to it cannot be published and cannot start a run, and says so naming the instance, the component and the version. Read the consumer list and the upgrade impact first, and deprecate instead unless the version is genuinely unsafe to run.

Sunset the version you need gone. The version is never deleted, so its body stays readable for anyone auditing what ran — but every pipeline pinned to it is refused from that moment, and nothing about that resolves itself: each one has to be edited onto a version that still resolves. Sunset is final: restoring or deprecating a sunset version is refused with 409, so the way back is to publish a new version.

Open the component, choose Versions, and pick Sunset from the version's row menu. The confirmation names the version and the number of pipelines still referencing it; Sunset applies immediately.

Terminalbash
gitmoap pipeline-components sunset-group-pipeline-component-version \
--group-id <id> \
--component-id <id> \
--version <id>
curlbash
curl -X POST https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id}/versions/{version}/sunset \
-H "Authorization: Bearer $GITMOAP_TOKEN"

The same action exists on a repository-owned component's version list.

Terminalbash
gitmoap pipeline-components sunset-repo-pipeline-component-version \
--repo-id <id> \
--component-id <id> \
--version <id>
curlbash
curl -X POST https://api.gitmoap.example/repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}/sunset \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Delete a component

Warning

Deleting a component destroys the component, its draft and every version it ever published, and none of it can be recovered. Runs that already happened keep the flattened graph they ran and the version each step came from, so history stays readable — but the version bodies are gone and nothing can resolve them again. Recreating the component gives you a new, empty identity rather than the one you deleted, so every pipeline that referenced the old one has to be pointed at the new one by hand. Deleting is refused while any pipeline still references it, and that guard is the only thing standing between you and this.

A delete answers 409 while any pipeline still references the component, at any version. Read the consumer list, remove the instances from those pipelines, then delete. The guard is a live constraint rather than a check the request performs first, so a pipeline that starts referencing the component while you are deleting it still wins.

Open the component and choose Settings → Delete component. The confirmation names the component, its version count and the number of pipelines referencing it, and refuses while that last number is above zero. Type the component's name to confirm.

Terminalbash
gitmoap pipeline-components delete-group-pipeline-component \
--group-id <id> \
--component-id <id>
curlbash
curl -X DELETE https://api.gitmoap.example/groups/{group_id}/pipeline-components/{component_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

The same action exists on a repository-owned component.

Terminalbash
gitmoap pipeline-components delete-repo-pipeline-component \
--repo-id <id> \
--component-id <id>
curlbash
curl -X DELETE https://api.gitmoap.example/repositories/{repo_id}/pipeline-components/{component_id} \
-H "Authorization: Bearer $GITMOAP_TOKEN"

Reference

Components

10 endpoints

GET/groups/{group_id}/pipeline-componentspipeline:read

List the components a group's pipelines may reference

list_group_pipeline_componentsGET /groups/{group_id}/pipeline-componentsOpen in the API reference

Token scope

pipeline:read

Send

Path
  • group_iduuidThe group's id
Query
  • searchstringoptionalMatch on name and description
  • own_scope_onlybooleanoptionalExclude components inherited from parent groups
  • limitint32optionalPage size (1-100, default 20)
  • next_tokenstringoptionalOpaque pagination cursor

Refuses

  • 400Malformed cursor or page size
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such group, or it is not visible to the caller

Receive

  • next_tokenobjectoptional
GET/repositories/{repo_id}/pipeline-componentspipeline:read

List the components a repository's pipelines may reference

list_repo_pipeline_componentsGET /repositories/{repo_id}/pipeline-componentsOpen in the API reference

Token scope

pipeline:read

Send

Path
  • repo_iduuidThe repository's id
Query
  • searchstringoptionalMatch on name and description
  • own_scope_onlybooleanoptionalExclude components inherited from parent groups
  • limitint32optionalPage size (1-100, default 20)
  • next_tokenstringoptionalOpaque pagination cursor

Refuses

  • 400Malformed cursor or page size
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such repository, or it is not visible to the caller

Receive

The same shape list_group_pipeline_components returns — 1 field. Go to it

Show it here
  • next_tokenobjectoptional
POST/groups/{group_id}/pipeline-componentspipeline:manage

Create a reusable pipeline component

create_group_pipeline_componentPOST /groups/{group_id}/pipeline-componentsOpen in the API reference

Token scope

pipeline:manage

Counts against

pipeline_components_per_scope

Send

Path
  • group_iduuidThe group's id
Body
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • descriptionobjectoptional
  • namestring

Refuses

  • 400The body is malformed — an unknown stage slot, a duplicate identifier, a parameter reference nothing declares, or a node field a component may not carry
  • 401
  • 403Maintainer is required to create a component
  • 404No such group, or it is not visible to the caller
  • 409A component with this name already exists here
  • 429The scope's component quota is exhausted

Receive

  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • created_atstring
  • created_byobject1 field
    • avatar_urlobjectoptional
POST/repositories/{repo_id}/pipeline-componentspipeline:manage

Create a reusable pipeline component

create_repo_pipeline_componentPOST /repositories/{repo_id}/pipeline-componentsOpen in the API reference

Token scope

pipeline:manage

Counts against

pipeline_components_per_scope

Send

Path
  • repo_iduuidThe repository's id
Body
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • descriptionobjectoptional
  • namestring

Refuses

  • 400The body is malformed — an unknown stage slot, a duplicate identifier, a parameter reference nothing declares, or a node field a component may not carry
  • 401
  • 403Maintainer is required to create a component
  • 404No such repository, or it is not visible to the caller
  • 409A component with this name already exists here
  • 429The scope's component quota is exhausted

Receive

The same shape create_group_pipeline_component returns — 3 fields. Go to it

Show it here
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • created_atstring
  • created_byobject1 field
    • avatar_urlobjectoptional
GET/groups/{group_id}/pipeline-components/{component_id}pipeline:read

Read one component, its draft body and its published versions

get_group_pipeline_componentGET /groups/{group_id}/pipeline-components/{component_id}Open in the API reference

Token scope

pipeline:read

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component here — a component belongs to a scope, and only that scope and the scopes beneath it can see it

Receive

The same shape create_group_pipeline_component returns — 3 fields. Go to it

Show it here
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • created_atstring
  • created_byobject1 field
    • avatar_urlobjectoptional
GET/repositories/{repo_id}/pipeline-components/{component_id}pipeline:read

Read one component, its draft body and its published versions

get_repo_pipeline_componentGET /repositories/{repo_id}/pipeline-components/{component_id}Open in the API reference

Token scope

pipeline:read

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component here — a component belongs to a scope, and only that scope and the scopes beneath it can see it

Receive

The same shape create_group_pipeline_component returns — 3 fields. Go to it

Show it here
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • created_atstring
  • created_byobject1 field
    • avatar_urlobjectoptional
PUT/groups/{group_id}/pipeline-components/{component_id}pipeline:manage

Replace a component's draft body

update_group_pipeline_componentPUT /groups/{group_id}/pipeline-components/{component_id}Open in the API reference

Token scope

pipeline:manage

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
Body
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • descriptionobjectoptional
  • namestring

Refuses

  • 400The body is malformed
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to edit a component
  • 404No such component here
  • 409A component with this name already exists here

Receive

The same shape create_group_pipeline_component returns — 3 fields. Go to it

Show it here
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • created_atstring
  • created_byobject1 field
    • avatar_urlobjectoptional
PUT/repositories/{repo_id}/pipeline-components/{component_id}pipeline:manage

Replace a component's draft body

update_repo_pipeline_componentPUT /repositories/{repo_id}/pipeline-components/{component_id}Open in the API reference

Token scope

pipeline:manage

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
Body
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • descriptionobjectoptional
  • namestring

Refuses

  • 400The body is malformed
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to edit a component
  • 404No such component here
  • 409A component with this name already exists here

Receive

The same shape create_group_pipeline_component returns — 3 fields. Go to it

Show it here
  • bodyobject22 fields
    • component_instances[]object7 fields
      • component_iduuid
      • component_refobjectoptional
      • idstring
      • namestring
      • paramsobjectoptional
      • stage_mapobjectoptionalBinds every slot the referenced component declares to a slot of the containing body.
      • versionstring
    • edges[]object5 fields
      • idstring
      • source_node_idstring
      • source_portobjectoptional
      • target_node_idstring
      • target_portobjectoptional
    • inputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • nodes[]object1 field
      • stage_slotstring
    • outputs[]object2 fields
      • descriptionobjectoptional
      • namestring
    • parameters[]object5 fields
      • defaultobjectoptional
      • descriptionobjectoptional
      • namestring
      • param_typearraybooleannumberobjectstringThe JSON shape a parameter's value must have.
      • requiredbooleanoptionalWhether a pipeline using the component must supply a value. A required parameter cannot have a default.
  • created_atstring
  • created_byobject1 field
    • avatar_urlobjectoptional
DELETE/groups/{group_id}/pipeline-components/{component_id}pipeline:manage

Delete a component and all of its versions

delete_group_pipeline_componentDELETE /groups/{group_id}/pipeline-components/{component_id}Open in the API reference

Token scope

pipeline:manage

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to delete a component
  • 404No such component here
  • 409One or more pipelines still reference this component. Remove those references first

Receive

No body.

DELETE/repositories/{repo_id}/pipeline-components/{component_id}pipeline:manage

Delete a component and all of its versions

delete_repo_pipeline_componentDELETE /repositories/{repo_id}/pipeline-components/{component_id}Open in the API reference

Token scope

pipeline:manage

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id

Refuses

  • 400Bad request — a path parameter is not a well-formed value of its type
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to delete a component
  • 404No such component here
  • 409One or more pipelines still reference this component. Remove those references first

Receive

No body.

Versions

12 endpoints

POST/groups/{group_id}/pipeline-components/{component_id}/versionspipeline:manage

Publish the current draft as an immutable version

publish_group_pipeline_component_versionPOST /groups/{group_id}/pipeline-components/{component_id}/versionsOpen in the API reference

Token scope

pipeline:manage

Counts against

versions_per_pipeline_component

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
Query
  • dry_runbooleanoptionalReport the lowest permissible version and what would change downstream, and write nothing
Body
  • changelogobjectoptional
  • versionstring

Refuses

  • 400The draft does not validate, or the requested version is below what this change permits. Removing a parameter or a boundary port needs a major version; adding an optional one needs a minor
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to publish a version
  • 404No such component here
  • 409This version is already published. A version's contents never change, so it is never reused
  • 429The component's version quota is exhausted

Receive

  • blast_radiusobject5 fields
    • floating_pipelinesint32Pipelines whose reference would resolve to this version.
    • sample_failures[]object3 fields
      • pipeline_iduuid
      • pipeline_namestring
      • repository_iduuid
    • sampledint32How many of them were re-expanded and re-validated.
  • contract_changemajorminorpatchHow far the contract moved between the last published version and the draft.
  • depthint32
  • expanded_node_countint32
  • minimum_versionstring
  • versionstring
POST/repositories/{repo_id}/pipeline-components/{component_id}/versionspipeline:manage

Publish the current draft as an immutable version

publish_repo_pipeline_component_versionPOST /repositories/{repo_id}/pipeline-components/{component_id}/versionsOpen in the API reference

Token scope

pipeline:manage

Counts against

versions_per_pipeline_component

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
Query
  • dry_runbooleanoptionalReport the lowest permissible version and what would change downstream, and write nothing
Body
  • changelogobjectoptional
  • versionstring

Refuses

  • 400The draft does not validate, or the requested version is below what this change permits. Removing a parameter or a boundary port needs a major version; adding an optional one needs a minor
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to publish a version
  • 404No such component here
  • 409This version is already published. A version's contents never change, so it is never reused
  • 429The component's version quota is exhausted

Receive

The same shape publish_group_pipeline_component_version returns — 6 fields. Go to it

Show it here
  • blast_radiusobject5 fields
    • floating_pipelinesint32Pipelines whose reference would resolve to this version.
    • sample_failures[]object3 fields
      • pipeline_iduuid
      • pipeline_namestring
      • repository_iduuid
    • sampledint32How many of them were re-expanded and re-validated.
  • contract_changemajorminorpatchHow far the contract moved between the last published version and the draft.
  • depthint32
  • expanded_node_countint32
  • minimum_versionstring
  • versionstring
GET/groups/{group_id}/pipeline-components/{component_id}/versionspipeline:read

List a component's published versions, newest first

list_group_pipeline_component_versionsGET /groups/{group_id}/pipeline-components/{component_id}/versionsOpen in the API reference

Token scope

pipeline:read

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
Query
  • lifecycle_statestringoptionalactive, deprecated, sunset or all (default all)
  • limitint32optionalPage size (1-100, default 20)
  • next_tokenstringoptionalOpaque pagination cursor

Refuses

  • 400Malformed cursor, page size or lifecycle filter
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component here

Receive

  • items[]object11 fields
    • changelogobjectoptional
    • contract_digeststringA SHA-256 fingerprint, in hex, of what a pipeline using the version must satisfy: its parameters, its ports and the variables it reads. It changes only when that contract does.
    • depthint32How many levels of components the version spans: 1 when it uses no other component.
    • expanded_node_countint32How many steps the version expands into.
    • lifecycle_stateactivedeprecatedsunsetWhere a published version sits in its retirement. A deprecated version still resolves for an exact reference and still runs, but no floating reference selects it — which is what makes deprecating the safe way to retire one. A sunset version refuses to resolve at all, exact reference included.
    • published_atstring
    • published_byobject4 fields
      • avatar_urlobjectoptional
      • emailstring
      • idstring
      • usernamestring
    • versionstring
  • next_tokenobjectoptional
GET/repositories/{repo_id}/pipeline-components/{component_id}/versionspipeline:read

List a component's published versions, newest first

list_repo_pipeline_component_versionsGET /repositories/{repo_id}/pipeline-components/{component_id}/versionsOpen in the API reference

Token scope

pipeline:read

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
Query
  • lifecycle_statestringoptionalactive, deprecated, sunset or all (default all)
  • limitint32optionalPage size (1-100, default 20)
  • next_tokenstringoptionalOpaque pagination cursor

Refuses

  • 400Malformed cursor, page size or lifecycle filter
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component here

Receive

The same shape list_group_pipeline_component_versions returns — 2 fields. Go to it

Show it here
  • items[]object11 fields
    • changelogobjectoptional
    • contract_digeststringA SHA-256 fingerprint, in hex, of what a pipeline using the version must satisfy: its parameters, its ports and the variables it reads. It changes only when that contract does.
    • depthint32How many levels of components the version spans: 1 when it uses no other component.
    • expanded_node_countint32How many steps the version expands into.
    • lifecycle_stateactivedeprecatedsunsetWhere a published version sits in its retirement. A deprecated version still resolves for an exact reference and still runs, but no floating reference selects it — which is what makes deprecating the safe way to retire one. A sunset version refuses to resolve at all, exact reference included.
    • published_atstring
    • published_byobject4 fields
      • avatar_urlobjectoptional
      • emailstring
      • idstring
      • usernamestring
    • versionstring
  • next_tokenobjectoptional
GET/groups/{group_id}/pipeline-components/{component_id}/versions/{version}pipeline:read

Read one published version, including the body it froze

get_group_pipeline_component_versionGET /groups/{group_id}/pipeline-components/{component_id}/versions/{version}Open in the API reference

Token scope

pipeline:read

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
  • versionstringAn exact version, such as v1.2.0

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component or version here

Receive

No body.

GET/repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}pipeline:read

Read one published version, including the body it froze

get_repo_pipeline_component_versionGET /repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}Open in the API reference

Token scope

pipeline:read

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
  • versionstringAn exact version, such as v1.2.0

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component or version here

Receive

No body.

POST/groups/{group_id}/pipeline-components/{component_id}/versions/{version}/deprecatepipeline:manage

Deprecate a published version

deprecate_group_pipeline_component_versionPOST /groups/{group_id}/pipeline-components/{component_id}/versions/{version}/deprecateOpen in the API reference

Token scope

pipeline:manage

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
  • versionstringAn exact version, such as v1.2.0

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to change a version's lifecycle
  • 404No such component or version here
  • 409The version is sunset, which is final

Receive

  • changelogobjectoptional
  • contract_digeststringA SHA-256 fingerprint, in hex, of what a pipeline using the version must satisfy: its parameters, its ports and the variables it reads. It changes only when that contract does.
  • depthint32How many levels of components the version spans: 1 when it uses no other component.
  • expanded_node_countint32How many steps the version expands into.
  • lifecycle_stateactivedeprecatedsunsetWhere a published version sits in its retirement. A deprecated version still resolves for an exact reference and still runs, but no floating reference selects it — which is what makes deprecating the safe way to retire one. A sunset version refuses to resolve at all, exact reference included.
  • published_atstring
  • published_byobject4 fields
    • avatar_urlobjectoptional
    • emailstring
    • idstring
    • usernamestring
  • versionstring
POST/repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}/deprecatepipeline:manage

Deprecate a published version

deprecate_repo_pipeline_component_versionPOST /repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}/deprecateOpen in the API reference

Token scope

pipeline:manage

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
  • versionstringAn exact version, such as v1.2.0

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to change a version's lifecycle
  • 404No such component or version here
  • 409The version is sunset, which is final

Receive

The same shape deprecate_group_pipeline_component_version returns — 8 fields. Go to it

Show it here
  • changelogobjectoptional
  • contract_digeststringA SHA-256 fingerprint, in hex, of what a pipeline using the version must satisfy: its parameters, its ports and the variables it reads. It changes only when that contract does.
  • depthint32How many levels of components the version spans: 1 when it uses no other component.
  • expanded_node_countint32How many steps the version expands into.
  • lifecycle_stateactivedeprecatedsunsetWhere a published version sits in its retirement. A deprecated version still resolves for an exact reference and still runs, but no floating reference selects it — which is what makes deprecating the safe way to retire one. A sunset version refuses to resolve at all, exact reference included.
  • published_atstring
  • published_byobject4 fields
    • avatar_urlobjectoptional
    • emailstring
    • idstring
    • usernamestring
  • versionstring
POST/groups/{group_id}/pipeline-components/{component_id}/versions/{version}/undeprecatepipeline:manage

Return a deprecated version to active

undeprecate_group_pipeline_component_versionPOST /groups/{group_id}/pipeline-components/{component_id}/versions/{version}/undeprecateOpen in the API reference

Token scope

pipeline:manage

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
  • versionstringAn exact version, such as v1.2.0

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to change a version's lifecycle
  • 404No such component or version here
  • 409The version is sunset, which is final

Receive

The same shape deprecate_group_pipeline_component_version returns — 8 fields. Go to it

Show it here
  • changelogobjectoptional
  • contract_digeststringA SHA-256 fingerprint, in hex, of what a pipeline using the version must satisfy: its parameters, its ports and the variables it reads. It changes only when that contract does.
  • depthint32How many levels of components the version spans: 1 when it uses no other component.
  • expanded_node_countint32How many steps the version expands into.
  • lifecycle_stateactivedeprecatedsunsetWhere a published version sits in its retirement. A deprecated version still resolves for an exact reference and still runs, but no floating reference selects it — which is what makes deprecating the safe way to retire one. A sunset version refuses to resolve at all, exact reference included.
  • published_atstring
  • published_byobject4 fields
    • avatar_urlobjectoptional
    • emailstring
    • idstring
    • usernamestring
  • versionstring
POST/repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}/undeprecatepipeline:manage

Return a deprecated version to active

undeprecate_repo_pipeline_component_versionPOST /repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}/undeprecateOpen in the API reference

Token scope

pipeline:manage

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
  • versionstringAn exact version, such as v1.2.0

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to change a version's lifecycle
  • 404No such component or version here
  • 409The version is sunset, which is final

Receive

The same shape deprecate_group_pipeline_component_version returns — 8 fields. Go to it

Show it here
  • changelogobjectoptional
  • contract_digeststringA SHA-256 fingerprint, in hex, of what a pipeline using the version must satisfy: its parameters, its ports and the variables it reads. It changes only when that contract does.
  • depthint32How many levels of components the version spans: 1 when it uses no other component.
  • expanded_node_countint32How many steps the version expands into.
  • lifecycle_stateactivedeprecatedsunsetWhere a published version sits in its retirement. A deprecated version still resolves for an exact reference and still runs, but no floating reference selects it — which is what makes deprecating the safe way to retire one. A sunset version refuses to resolve at all, exact reference included.
  • published_atstring
  • published_byobject4 fields
    • avatar_urlobjectoptional
    • emailstring
    • idstring
    • usernamestring
  • versionstring
POST/groups/{group_id}/pipeline-components/{component_id}/versions/{version}/sunsetpipeline:manage

Sunset a published version

sunset_group_pipeline_component_versionPOST /groups/{group_id}/pipeline-components/{component_id}/versions/{version}/sunsetOpen in the API reference

Token scope

pipeline:manage

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
  • versionstringAn exact version, such as v1.2.0

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to change a version's lifecycle
  • 404No such component or version here
  • 409The request conflicts with the resource's current state; `reason` says how

Receive

The same shape deprecate_group_pipeline_component_version returns — 8 fields. Go to it

Show it here
  • changelogobjectoptional
  • contract_digeststringA SHA-256 fingerprint, in hex, of what a pipeline using the version must satisfy: its parameters, its ports and the variables it reads. It changes only when that contract does.
  • depthint32How many levels of components the version spans: 1 when it uses no other component.
  • expanded_node_countint32How many steps the version expands into.
  • lifecycle_stateactivedeprecatedsunsetWhere a published version sits in its retirement. A deprecated version still resolves for an exact reference and still runs, but no floating reference selects it — which is what makes deprecating the safe way to retire one. A sunset version refuses to resolve at all, exact reference included.
  • published_atstring
  • published_byobject4 fields
    • avatar_urlobjectoptional
    • emailstring
    • idstring
    • usernamestring
  • versionstring
POST/repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}/sunsetpipeline:manage

Sunset a published version

sunset_repo_pipeline_component_versionPOST /repositories/{repo_id}/pipeline-components/{component_id}/versions/{version}/sunsetOpen in the API reference

Token scope

pipeline:manage

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
  • versionstringAn exact version, such as v1.2.0

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to change a version's lifecycle
  • 404No such component or version here
  • 409The request conflicts with the resource's current state; `reason` says how

Receive

The same shape deprecate_group_pipeline_component_version returns — 8 fields. Go to it

Show it here
  • changelogobjectoptional
  • contract_digeststringA SHA-256 fingerprint, in hex, of what a pipeline using the version must satisfy: its parameters, its ports and the variables it reads. It changes only when that contract does.
  • depthint32How many levels of components the version spans: 1 when it uses no other component.
  • expanded_node_countint32How many steps the version expands into.
  • lifecycle_stateactivedeprecatedsunsetWhere a published version sits in its retirement. A deprecated version still resolves for an exact reference and still runs, but no floating reference selects it — which is what makes deprecating the safe way to retire one. A sunset version refuses to resolve at all, exact reference included.
  • published_atstring
  • published_byobject4 fields
    • avatar_urlobjectoptional
    • emailstring
    • idstring
    • usernamestring
  • versionstring

Consumers

6 endpoints

GET/groups/{group_id}/pipeline-components/{component_id}/usagespipeline:read

List the pipelines that reference a component

list_group_pipeline_component_usagesGET /groups/{group_id}/pipeline-components/{component_id}/usagesOpen in the API reference

Token scope

pipeline:read

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
Query
  • versionstringoptionalOnly references that last resolved to this version
  • limitint32optionalPage size (1-100, default 20)
  • next_tokenstringoptionalOpaque pagination cursor

Refuses

  • 400Malformed cursor, page size or version
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component here

Receive

  • items[]object7 fields
    • instance_idstring
    • pipeline_iduuid
    • pipeline_namestring
    • repository_iduuid
    • resolved_versionobjectoptional
    • updated_atstring
    • version_refstring
  • next_tokenobjectoptional
GET/repositories/{repo_id}/pipeline-components/{component_id}/usagespipeline:read

List the pipelines that reference a component

list_repo_pipeline_component_usagesGET /repositories/{repo_id}/pipeline-components/{component_id}/usagesOpen in the API reference

Token scope

pipeline:read

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
Query
  • versionstringoptionalOnly references that last resolved to this version
  • limitint32optionalPage size (1-100, default 20)
  • next_tokenstringoptionalOpaque pagination cursor

Refuses

  • 400Malformed cursor, page size or version
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component here

Receive

The same shape list_group_pipeline_component_usages returns — 2 fields. Go to it

Show it here
  • items[]object7 fields
    • instance_idstring
    • pipeline_iduuid
    • pipeline_namestring
    • repository_iduuid
    • resolved_versionobjectoptional
    • updated_atstring
    • version_refstring
  • next_tokenobjectoptional
GET/groups/{group_id}/pipeline-components/{component_id}/upgrade-impactpipeline:read

Report how far every consumer is from one published version

get_group_component_upgrade_impactGET /groups/{group_id}/pipeline-components/{component_id}/upgrade-impactOpen in the API reference

Token scope

pipeline:read

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
Query
  • target_versionstringoptionalThe version to measure against. Defaults to the newest published one

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component here, or the component has no published version to measure against

Receive

  • entries[]object7 fields
    • dispositionneeds_repinon_targetunresolvableWhere a pipeline using the component stands against the target version: on_target (its reference already selects it), needs_repin (its reference has to be changed to reach it) or unresolvable (its reference selects no version at all, because every candidate has been retired).
    • instance_idstring
    • pipeline_iduuid
    • pipeline_namestring
    • repository_iduuid
    • resolves_toobjectoptional
    • version_refstring
  • needs_repinint32
  • on_targetint32
  • sample_failures[]object4 fields
    • pipeline_iduuid
    • pipeline_namestring
    • repository_iduuid
    • violationsobject1 field
      • validboolean
  • sampledint32How many consumers were re-expanded against the target to see whether they still validate.
  • target_versionstring
  • total_usagesint32
  • truncatedbooleanoptionalTrue when the component has more consumers than one report covers. The remainder are reached by narrowing to a target version, or by reading the usage listing directly.
  • unresolvableint32
GET/repositories/{repo_id}/pipeline-components/{component_id}/upgrade-impactpipeline:read

Report how far every consumer is from one published version

get_repo_component_upgrade_impactGET /repositories/{repo_id}/pipeline-components/{component_id}/upgrade-impactOpen in the API reference

Token scope

pipeline:read

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
Query
  • target_versionstringoptionalThe version to measure against. Defaults to the newest published one

Refuses

  • 400The version is not a well-formed version number
  • 401Unauthenticated — no credential, or an invalid one
  • 403Reporter is required to read components
  • 404No such component here, or the component has no published version to measure against

Receive

The same shape get_group_component_upgrade_impact returns — 9 fields. Go to it

Show it here
  • entries[]object7 fields
    • dispositionneeds_repinon_targetunresolvableWhere a pipeline using the component stands against the target version: on_target (its reference already selects it), needs_repin (its reference has to be changed to reach it) or unresolvable (its reference selects no version at all, because every candidate has been retired).
    • instance_idstring
    • pipeline_iduuid
    • pipeline_namestring
    • repository_iduuid
    • resolves_toobjectoptional
    • version_refstring
  • needs_repinint32
  • on_targetint32
  • sample_failures[]object4 fields
    • pipeline_iduuid
    • pipeline_namestring
    • repository_iduuid
    • violationsobject1 field
      • validboolean
  • sampledint32How many consumers were re-expanded against the target to see whether they still validate.
  • target_versionstring
  • total_usagesint32
  • truncatedbooleanoptionalTrue when the component has more consumers than one report covers. The remainder are reached by narrowing to a target version, or by reading the usage listing directly.
  • unresolvableint32
POST/groups/{group_id}/pipeline-components/{component_id}/repinpipeline:manage

Move consuming pipelines onto a different version reference

repin_group_component_usagesPOST /groups/{group_id}/pipeline-components/{component_id}/repinOpen in the API reference

Token scope

pipeline:manage

Send

Path
  • group_iduuidThe group's id
  • component_iduuidThe component's id
Query
  • dry_runbooleanoptionalWork out what would change and write nothing
Body
  • fromobjectoptional
  • tostring

Refuses

  • 400Malformed request, or no published version satisfies the requested reference
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to re-pin a component's consumers
  • 404No such component here
  • 409The request conflicts with the resource's current state; `reason` says how

Receive

  • candidatesint32Consumers matching the filter that the sweep looked at, before authorization or validation.
  • dry_runbooleanTrue when nothing was written and the report describes what would have happened.
  • repinned[]object3 fields
    • pipeline_iduuid
    • pipeline_namestring
    • repository_iduuid
  • skipped[]object5 fields
    • detailobjectoptionalWhat went wrong, when the reason alone does not say. Carries the validation message for a pipeline that would stop validating.
    • pipeline_iduuid
    • pipeline_namestring
    • reasonalready_pinnedforbiddenpipeline_missingunreadablevalidation_failedWhy a re-pin left a pipeline unchanged: forbidden (you cannot manage its pipelines), unreadable (you cannot read its repository), already_pinned (it already uses the requested reference), validation_failed (the change would make it invalid) or pipeline_missing (the pipeline no longer exists).
    • repository_iduuid
  • tostring
  • truncatedbooleanoptionalTrue when the component has more consumers than one sweep examines. The remainder are reached by running the sweep again.
POST/repositories/{repo_id}/pipeline-components/{component_id}/repinpipeline:manage

Move consuming pipelines onto a different version reference

repin_repo_component_usagesPOST /repositories/{repo_id}/pipeline-components/{component_id}/repinOpen in the API reference

Token scope

pipeline:manage

Send

Path
  • repo_iduuidThe repository's id
  • component_iduuidThe component's id
Query
  • dry_runbooleanoptionalWork out what would change and write nothing
Body
  • fromobjectoptional
  • tostring

Refuses

  • 400Malformed request, or no published version satisfies the requested reference
  • 401Unauthenticated — no credential, or an invalid one
  • 403Maintainer is required to re-pin a component's consumers
  • 404No such component here
  • 409The request conflicts with the resource's current state; `reason` says how

Receive

The same shape repin_group_component_usages returns — 6 fields. Go to it

Show it here
  • candidatesint32Consumers matching the filter that the sweep looked at, before authorization or validation.
  • dry_runbooleanTrue when nothing was written and the report describes what would have happened.
  • repinned[]object3 fields
    • pipeline_iduuid
    • pipeline_namestring
    • repository_iduuid
  • skipped[]object5 fields
    • detailobjectoptionalWhat went wrong, when the reason alone does not say. Carries the validation message for a pipeline that would stop validating.
    • pipeline_iduuid
    • pipeline_namestring
    • reasonalready_pinnedforbiddenpipeline_missingunreadablevalidation_failedWhy a re-pin left a pipeline unchanged: forbidden (you cannot manage its pipelines), unreadable (you cannot read its repository), already_pinned (it already uses the requested reference), validation_failed (the change would make it invalid) or pipeline_missing (the pipeline no longer exists).
    • repository_iduuid
  • tostring
  • truncatedbooleanoptionalTrue when the component has more consumers than one sweep examines. The remainder are reached by running the sweep again.

Limits

Two caps are metered and enforced. A request that would exceed one is refused with 429 TOO_MANY_REQUESTS and writes nothing — there is no partially created component and no half-published version.

CapCounted perFreeProTeamEnterprise
Componentseach group and each repository, separately1002505002 000
Published versionseach component2005001 0002 000

Components are counted per scope rather than per namespace: a group holding a hundred shared components and a repository holding a hundred of its own are two separate counts against two separate ceilings. Versions are counted per component because a version is immutable and never reused, so without a ceiling a publish loop grows without bound.

Either cap can be raised for one namespace. An Owner of the root group requests an increase from the group's billing settings; the ceiling on a raised component or version limit is 50 000. Deleting a component releases its count; a version is never deleted, so the version count only falls when the whole component goes.

A component body has fixed structural bounds, and they apply on every plan. These are shape limits rather than metered quotas — exceeding one is 400, not 429.

BoundValue
Nodes in one body64
Stage slots in one body8
Parameters in one body32
Members of one parameter's value set32
Characters in an identifier the platform mints for you, such as checkout--build64
Characters in an identifier you type: an instance, a body node, a body edge20
Characters in a stage slot or parameter name32
Characters in a component name100
Encoded body size350 KB

Two operational bounds are worth planning around. A re-pin sweep and an upgrade-impact report each examine up to 500 consumers and say truncated when there are more; both read from the beginning of the consumer list and neither is narrowed by a filter, so the read that reaches every consumer is the consumer listing, which pages properly. And re-expansion is sampled: a publish's blast radius and an upgrade-impact report each re-validate up to 10 consuming pipelines — enough to catch a systematic break, not enough to prove its absence. Every listing pages at 20 by default and 100 at most.

Troubleshooting

400 PIPELINE_VALIDATION_FAILEDon create or update, naming a stage slot
Cause
A node names a slot the body does not declare, or the slot list is empty
What to do
Declare the slot in stage_slots, or move the node to a slot that exists. A body needs at least one slot and at most 8
400 PIPELINE_VALIDATION_FAILEDon create or update, naming an identifier
Cause
A duplicate node or edge identifier, or one over 20 characters
What to do
Rename it. The 20-character ceiling is on identifiers you type, and it is what leaves room for the prefix expansion adds
400 PIPELINE_VALIDATION_FAILEDon create or update, naming a port
Cause
A boundary input or output points at a node the body does not contain, the same boundary name is declared twice, or a boundary input names no internal target at all
What to do
Point each boundary port at a node inside the body, declare each boundary name once, and give every input at least one target
400 PIPELINE_VALIDATION_FAILEDon create or update, naming a parameter
Cause
A default whose JSON type contradicts the declared type, a required parameter carrying a default, a $param naming nothing, or a parameter declared twice
What to do
A required parameter may not have a default — that combination is a contradiction, since nothing would ever read it. Fix the type, or drop the default and mark the parameter optional
400 PIPELINE_VALIDATION_FAILEDon create or update, naming a parameter's default and a variable
Cause
A parameter's default contains a {"$var": …}. A default is the component author's value, and one that read the consumer's variables would make what the component needs depend on whether the consumer supplied it
What to do
Remove the $var from the default and write it in the body where the value is used. A consumer can still pass a variable as that parameter's value
400 PIPELINE_VALIDATION_FAILEDon create or update, a violation invalid_var_ref or var_ref_reserved
Cause
A {"$var": …} in the body names something that is not a variable name, or a name the platform reserves
What to do
Use the name exactly as it is declared on an environment or as a pipeline variable. A reserved name cannot be declared, so there is nothing to read
400 PIPELINE_VALIDATION_FAILEDon saving a pipeline, a violation component_param_var_refused
Cause
An instance passes {"$var": …} to a parameter that is not string, that declares allowed_values, or that the component spends on a node setting such as environment or connection
What to do
Pass a written value for that parameter. The message names the instance, the parameter and which of the three applies. To feed a setting such as environment from somewhere else, ask the component's author to read the variable in the body instead
A run of a pipeline using a component is refused, naming your instance and a variable
Cause
The component reads a variable, listed in its version's variable_requirements, that the step it becomes cannot see — or that is a secret where it runs
What to do
Declare the variable on the environment the instance deploys to, or as a pipeline variable on your repository or a group above. Read the version's variable_requirements before you add an instance to know what it needs
400 PIPELINE_VALIDATION_FAILEDon create or update, naming changes, approval or resource_group
Cause
A component body may not carry path filters, approvals or a resource group
What to do
Remove the field. Put the approval on an environment, and the path filter on the consuming pipeline's own node
400 BAD_REQUESTon create or update, about body size
Cause
The encoded body is over 350 KB
What to do
Split the component. A body is bounded at 64 nodes, and one that large is usually two components
400 PIPELINE_VALIDATION_FAILEDon create or update, naming a value set
Cause
allowed_values is empty, lists the same value twice, holds more than 32 members, or excludes the parameter's own default
What to do
An empty set is a parameter nothing can satisfy — omit the list to accept any value of the declared type. Otherwise drop the duplicate, trim the list, or bring the default inside the set
400 PIPELINE_VALIDATION_FAILEDon publish
Cause
The version you asked for is below what your change permits
What to do
Use the minimum_version the response names. Removing a parameter or a boundary port, or reading a variable the previous version did not, is a major bump; adding an optional parameter or port is a minor
400 BAD_REQUESTon publish or a lifecycle change, about the version number
Cause
The number is not v{major}.{minor}.{patch} — a leading zero, a pre-release suffix or build metadata
What to do
Use three plain numbers with a v prefix, such as v1.2.0. Pre-release and build metadata are not part of the format
400 BAD_REQUESTon re-pin, saying nothing satisfies the reference
Cause
No published version answers the target: a track reference needs an active version to select, and an exact one may not name a sunset version
What to do
Publish the version first, or point the sweep at a reference that resolves. The check runs before any pipeline is touched, so nothing was rewritten
400 BAD_REQUESTon a listing
Cause
A cursor that did not come from this listing, or a lifecycle_state that is not active, deprecated, sunset or all
What to do
Drop the cursor and start the listing again — cursors are opaque and belong to the listing that issued them — or correct the filter value. A page size outside 1–100 is not refused, it is pulled back into range
400 BAD_REQUESTon upgrade impact
Cause
target_version is not a well-formed version number
What to do
Pass an exact version such as v2.0.0, or omit it to measure against the newest published one
401 UNAUTHORIZED
Cause
No credential, an expired one, or a revoked token
What to do
Sign in again, or mint a new token. An expired token gives the same answer as no token at all
403 FORBIDDENon a read
Cause
Your token is bound to one repository or group and you are calling a different one — a resource binding is checked before access level and before visibility
What to do
Call the scope the token is bound to, or mint a token without a binding. A private scope you are simply not a member of answers 404 instead, not 403
403 FORBIDDENon a write
Cause
Creating, editing, publishing, retiring, re-pinning and deleting all need Maintainer
What to do
Ask an Owner to raise your level, or ask a Maintainer to make the change
403 INSUFFICIENT_SCOPE
Cause
The token is valid but was minted without the scope this call needs
What to do
Mint a new token carrying pipeline:manage for writes, or pipeline:read for reads. Scopes are chosen at mint time and cannot be added afterwards
404 NOT_FOUNDon a component you can see the identifier of
Cause
The component belongs to a scope that is neither this one nor one of its parents
What to do
Call it against its own group or repository. A component outside your chain answers 404 rather than 403, so its existence is not confirmed by guessing
404 NOT_FOUNDon a version
Cause
The version was never published, or the number is misspelled
What to do
List the versions and copy the number. Sunset versions are still readable, so a 404 here means the number is wrong
404 NOT_FOUNDon upgrade impact
Cause
The component has no published version to measure against
What to do
Publish a version first. There is nothing to measure a consumer against until one exists
404 NOT_FOUNDon a group or repository you are sure exists
Cause
It is private and you are not a member
What to do
A private scope answers 404 to non-members so its existence stays private. Check your membership, then check the identifier
409 CONFLICTon create or update
Cause
A component with that name already exists in this scope
What to do
Pick another name, or edit the existing component. Names are unique per scope, so the same name on a parent group and a child repository is legal — the nearest one wins
409 CONFLICTon publish
Cause
That version number is already published
What to do
Publish the next number. A version's contents never change, so a number is never reused. If you are retrying a publish that timed out, read the version list first — it may already have succeeded
409 CONFLICTon delete
Cause
At least one pipeline still references the component
What to do
Open Used by, remove the instance from each pipeline listed, then delete. The guard is live, so a reference added while you were deleting still blocks it
429 TOO_MANY_REQUESTSon create
Cause
The owning group or repository is at its component ceiling
What to do
Delete a component nobody references, or request a limit increase from the root group's billing settings
429 TOO_MANY_REQUESTSon publish
Cause
The component is at its version ceiling
What to do
Versions are never deleted, so the only routes are a limit increase or a new component for the next major line
A pipeline started running different steps and nobody edited it
Cause
Its instance uses a floating reference, and a publish moved what that reference selects
What to do
Read the run's node badges — each names the component and the version it resolved to. Pin the instance to an exact version if that pipeline needs the same bytes every time
A component you know exists is missing from the components list
Cause
The group that owns it is private and you are not a member, so it is dropped from the picker rather than shown
What to do
Ask for membership of the owning group. Pipelines in the subtree can still reference the component; only the list you choose from is filtered
A component appears in the list marked with a missing capability
Cause
The providers its nodes call are not installed for this repository's group
What to do
Install the provider on the group. The component is shown rather than hidden precisely so the missing install is visible
A pipeline stopped validating right after an instance was added, complaining about an ambiguous input
Cause
A component's boundary outputs are candidates for automatic wiring, so a second producer of the same type now exists
What to do
Draw the edge explicitly from the producer you meant. Automatic wiring refuses to guess between two candidates on purpose
A re-pin reported success but changed fewer pipelines than expected
Cause
Pipelines were skipped for a named reason — you cannot manage the repository, cannot read it, it was already on the target, it would stop validating, or it was deleted
What to do
Read the skipped rows. For forbidden, ask that repository's Maintainer to run the change; for validation_failed, the row carries the message
The re-pin or upgrade-impact report says truncated
Cause
The component has more than the 500 consumers one pass covers, and both reads start at the beginning of the consumer list
What to do
Page through Used by, which is the only read that reaches every consumer. Run the sweep again to pick up what a truncated pass left, and change the reference on any instance still outstanding in its own pipeline
The consumer list is shorter than you know it should be, or a page comes back short with a next page still to fetch
Cause
Rows for repositories you cannot read are dropped after the page has been read, so the shortfall lands inside the page rather than at the end of the listing
What to do
Keep following next_token to the end rather than stopping at a short page. To see the consumers you are missing entirely, ask for read access to those repositories, or ask somebody with wider access to run the report
A deprecated version is still running in a pipeline
Cause
Deprecating removes a version from floating tracks only; a pipeline pinned to it exactly is undisturbed, by design
What to do
Run upgrade impact to find every consumer still on it, then re-pin them. Sunset only when the version must stop running
A saved pipeline reports a warning naming a component and a version
Cause
The version its instance resolved to has been deprecated: it still runs, and the warning is the notice to move
What to do
Re-pin that instance onto an active version. Deprecation never blocks a save, so nothing is broken until the version is sunset
A pipeline that used to publish is refused, naming a component and a version, and its runs no longer start
Cause
That version was sunset, and nothing resolves it any more, not even the exact reference this pipeline wrote
What to do
Edit the instance onto an active version. Upgrade impact against the newest version tells you which pipelines are in this state
Publishing a pipeline is refused, saying a component does not exist here, on an identifier that is definitely real
Cause
The component belongs to a scope that is neither the pipeline's repository nor one of its parent groups, and that reads identically to a component that is not there at all
What to do
Move the component to a group both sides share, or create a copy in a scope the repository inherits from. A draft pipeline still saves and records the violation, so nothing is lost while you sort it out

Examples

Ship a breaking change to a shared component without breaking anybody.

Suppose rust-build on your root group is at v1.4.2, and you need to remove the cargo_flags parameter that nothing should have been using.

  1. Edit the draft to remove the parameter, and save. Nothing changes for any consumer — a draft is not referenceable.

  2. Dry-run a publish of v2.0.0. The report says the contract moved by a major step and confirms v2.0.0 as the minimum the gate permits. Its floating count is every consumer that wrote a track reference, not the ones this number reaches — none of them can cross into a major 2 on its own, so nobody moves until you move them.

  3. Publish v2.0.0 with a changelog saying what to do instead of cargo_flags.

  4. Read upgrade impact against v2.0.0. Everyone shows as needs_repin, which is exactly right: a major bump never arrives on its own.

  5. Re-pin with dry_run, from v1.* to v2.*. Read the skipped rows — a pipeline that still supplies cargo_flags appears as validation_failed with the message.

  6. Fix those pipelines, or hand their repositories the list. Then run the sweep for real.

  7. Deprecate v1.4.2 once impact reports nobody on it. It still runs for anyone pinned exactly; nothing new selects it.

Ship a fix everybody gets for free. Edit the draft, publish v1.4.3, and stop. Every pipeline on v1.* or v1.4.* picks it up at its next resolution, and the blast-radius report told you before you published whether a sample of them still validates.

Deploy one component to every environment.

Suppose a static-site component syncs a built site to S3 and invalidates the CloudFront distribution in front of it, and each environment has its own bucket and distribution.

  1. Declare WEB_S3_BUCKET and WEB_DISTRIBUTION_ID on each environment — staging and production — once. An Owner of the environment does this.

  2. In the component body, declare one string parameter, target, and spend it on both nodes' environment setting in param_slots. Write {"$var": "WEB_S3_BUCKET"} and {"$var": "WEB_DISTRIBUTION_ID"} where the two nodes' configuration needs them.

  3. Publish. The version's variable_requirements lists both names, so anyone about to use it can see what their environment has to hold.

  4. In a pipeline, add two instances, one with "params": { "target": "staging" } and one with "params": { "target": "production" }. Each reads its own environment's bucket and distribution.

  5. Change a bucket by editing the environment's variable. The next run of every pipeline deploying there picks it up, and no pipeline or component is edited.

FAQ

Can I share a component across two groups that are not related?

No. A component is usable by its owning scope and everything beneath it, and that is what makes a reference unambiguous and a consumer list meaningful. Publish it on a group that is an ancestor of both, or publish two copies. Sharing across a whole organisation, or the whole platform, is what the provider marketplace is for.

What happens if a parent group and my repository both have a component called rust-build?

The nearest one wins in the picker you choose from. But an instance stores the component's identifier, not its name, so a repository that later creates a same-named local component cannot silently redirect a pipeline that was already published against the group's one.

Can a component contain another component?

Compose them in the pipeline rather than inside each other. What a version publishes is the nodes and edges its body declares, and what a consuming pipeline gets is exactly that fragment, flattened into its own graph. Two instances side by side give you the same reuse, read more clearly in a run graph, and can be re-pinned one at a time.

Does a component carry its own triggers?

No. Triggers are keyed to a repository and a ref, and a component has neither, so a component release can never change what starts a run.

Why is my version number rejected when the change looks small?

The gate compares the parameter declarations, the boundary ports and the variables the body reads, and some small-looking edits move the contract: renaming a port, retyping a parameter, adding allowed_values where there were none, or a {"$var": …} reading a name the last version did not. The response names the minimum permitted number and the size of the step it computed.

What runs when a floating reference is ambiguous about time?

Whatever the reference resolved to at that moment, and the run records it. Each node in a run graph is badged with the component and the resolved version, so a pipeline tracking v1.* that ran last week and again today shows two different answers rather than one reference on both.

  • Pipelinesdefining a pipeline, what triggers a run, and watching one live. Saving a pipeline is where a component instance is written
  • Using providersinstalling the providers whose capabilities a component's nodes call, and why a component can be listed as unusable here
  • Service catalogenvironments and services, the two node settings a component may carry and the platform re-checks against the consuming repository
  • Billing and plansthe ceilings each plan carries, and how to ask for a higher one
  • Access tokensminting a token with pipeline:read or pipeline:manage, and why a scope cannot be added afterwards