Pipeline components
- Find the components you can use here
- Create a component
- Edit the draft
- Review a component before you use it
- Check what a publish would do
- Publish a version
- List and read published versions
- Reference a component from a pipeline
- See which pipelines use a component
- Measure how far consumers are from a version
- Move consumers onto a different reference
- Retire a version safely
- Stop a version from running at all
- Delete a component
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
Share part of a pipeline as a component
Choose Pipelines, then the Components tab, then New component.
Build it the way you build a pipeline: its stage slots, the steps inside them, and the inputs a consumer wires.
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:readfor every read,pipeline:managefor every write. Scopes are fixed when a token is minted, so a script that only reports on usage should carrypipeline:readalone. - 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
| Thing | Mutable? | What it is |
|---|---|---|
| The component | yes | The identity: a name unique within its scope, a description, an owner, and a working draft of the body |
| A version | never | One publication of that draft, numbered v{major}.{minor}.{patch}. Its contents never change and a number is never reused |
| A usage | derived | One 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:
{ "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:
{ "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:
{ "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 asenvironmentorconnection. 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:
| Reference | Selects |
|---|---|
v1.2.0 | exactly 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 |
latest | the 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 changed | Lowest 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 read | major |
| 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 read | minor |
| Anything else — internal nodes, internal edges, configuration that reads no new variable, display names, the provider versions the nodes pin | patch |
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 itdeprecated still runs; an exact reference still reaches it; no floating reference selects itsunset nothing reaches it, exact references includedA 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.
gitmoap pipeline-components list-repo-pipeline-components --repo-id <id>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.
gitmoap pipeline-components list-group-pipeline-components --group-id <id>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.
gitmoap pipeline-components create-group-pipeline-component \ --group-id <id> \ --name <name>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.
gitmoap pipeline-components create-repo-pipeline-component \ --repo-id <id> \ --name <name>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.
gitmoap pipeline-components update-group-pipeline-component \ --group-id <id> \ --component-id <id> \ --name <name>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.
gitmoap pipeline-components get-group-pipeline-component \ --group-id <id> \ --component-id <id>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.
gitmoap pipeline-components publish-group-pipeline-component-version \ --group-id <id> \ --component-id <id> \ --version <version>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.
gitmoap pipeline-components list-group-pipeline-component-versions \ --group-id <id> \ --component-id <id>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.
gitmoap pipeline-components get-group-pipeline-component-version \ --group-id <id> \ --component-id <id> \ --version <id>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:
{ "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.
gitmoap pipeline-components list-group-pipeline-component-usages \ --group-id <id> \ --component-id <id>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.
gitmoap pipeline-components list-repo-pipeline-component-usages \ --repo-id <id> \ --component-id <id>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.
| Disposition | What it means | What to do |
|---|---|---|
on_target | The reference already selects the target | Nothing |
needs_repin | The reference cannot reach the target from where it is, and waiting will not change that | Re-pin it, or ask the repository's Maintainer to |
unresolvable | The reference selects no published version at all right now | Fix 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.
gitmoap pipeline-components get-group-component-upgrade-impact \ --group-id <id> \ --component-id <id>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.
gitmoap pipeline-components get-repo-component-upgrade-impact \ --repo-id <id> \ --component-id <id>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.
gitmoap pipeline-components repin-group-component-usages \ --group-id <id> \ --component-id <id> \ --to <to>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.
gitmoap pipeline-components repin-repo-component-usages \ --repo-id <id> \ --component-id <id> \ --to <to>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.
gitmoap pipeline-components deprecate-group-pipeline-component-version \ --group-id <id> \ --component-id <id> \ --version <id>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.
gitmoap pipeline-components undeprecate-group-pipeline-component-version \ --group-id <id> \ --component-id <id> \ --version <id>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.
gitmoap pipeline-components sunset-group-pipeline-component-version \ --group-id <id> \ --component-id <id> \ --version <id>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.
gitmoap pipeline-components sunset-repo-pipeline-component-version \ --repo-id <id> \ --component-id <id> \ --version <id>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.
gitmoap pipeline-components delete-group-pipeline-component \ --group-id <id> \ --component-id <id>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.
gitmoap pipeline-components delete-repo-pipeline-component \ --repo-id <id> \ --component-id <id>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
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 size401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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 referenceToken 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 size401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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
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 carry401403Maintainer is required to create a component404No such group, or it is not visible to the caller409A component with this name already exists here429The 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 referenceToken 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 carry401403Maintainer is required to create a component404No such repository, or it is not visible to the caller409A component with this name already exists here429The 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 referenceToken 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 type401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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 referenceToken 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 type401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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 referenceToken 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 malformed401Unauthenticated — no credential, or an invalid one403Maintainer is required to edit a component404No such component here409A 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 referenceToken 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 malformed401Unauthenticated — no credential, or an invalid one403Maintainer is required to edit a component404No such component here409A 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 referenceToken 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 type401Unauthenticated — no credential, or an invalid one403Maintainer is required to delete a component404No such component here409One 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 referenceToken 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 type401Unauthenticated — no credential, or an invalid one403Maintainer is required to delete a component404No such component here409One 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 referenceToken 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 minor401Unauthenticated — no credential, or an invalid one403Maintainer is required to publish a version404No such component here409This version is already published. A version's contents never change, so it is never reused429The 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 referenceToken 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 minor401Unauthenticated — no credential, or an invalid one403Maintainer is required to publish a version404No such component here409This version is already published. A version's contents never change, so it is never reused429The 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 referenceToken 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 filter401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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
deprecatedversion 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. Asunsetversion 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 referenceToken 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 filter401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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
deprecatedversion 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. Asunsetversion 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Maintainer is required to change a version's lifecycle404No such component or version here409The 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
deprecatedversion 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. Asunsetversion 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Maintainer is required to change a version's lifecycle404No such component or version here409The 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
deprecatedversion 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. Asunsetversion 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Maintainer is required to change a version's lifecycle404No such component or version here409The 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
deprecatedversion 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. Asunsetversion 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Maintainer is required to change a version's lifecycle404No such component or version here409The 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
deprecatedversion 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. Asunsetversion 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Maintainer is required to change a version's lifecycle404No such component or version here409The 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
deprecatedversion 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. Asunsetversion 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Maintainer is required to change a version's lifecycle404No such component or version here409The 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
deprecatedversion 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. Asunsetversion 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 referenceToken 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 version401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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 referenceToken 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 version401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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) orunresolvable(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
- dispositionneeds_repinon_targetunresolvableWhere a pipeline using the component stands against the target version:
- 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 referenceToken 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 number401Unauthenticated — no credential, or an invalid one403Reporter is required to read components404No 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) orunresolvable(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
- dispositionneeds_repinon_targetunresolvableWhere a pipeline using the component stands against the target version:
- 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 referenceToken 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 reference401Unauthenticated — no credential, or an invalid one403Maintainer is required to re-pin a component's consumers404No such component here409The 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) orpipeline_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 referenceToken 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 reference401Unauthenticated — no credential, or an invalid one403Maintainer is required to re-pin a component's consumers404No such component here409The 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) orpipeline_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.
| Cap | Counted per | Free | Pro | Team | Enterprise |
|---|---|---|---|---|---|
| Components | each group and each repository, separately | 100 | 250 | 500 | 2 000 |
| Published versions | each component | 200 | 500 | 1 000 | 2 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.
| Bound | Value |
|---|---|
| Nodes in one body | 64 |
| Stage slots in one body | 8 |
| Parameters in one body | 32 |
| Members of one parameter's value set | 32 |
Characters in an identifier the platform mints for you, such as checkout--build | 64 |
| Characters in an identifier you type: an instance, a body node, a body edge | 20 |
| Characters in a stage slot or parameter name | 32 |
| Characters in a component name | 100 |
| Encoded body size | 350 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
$paramnaming 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
defaultcontains 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
$varfrom 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 notstring, that declaresallowed_values, or that the component spends on a node setting such asenvironmentorconnection - 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
environmentfrom 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_requirementsbefore 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_valuesis 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_versionthe 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
vprefix, such asv1.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_statethat is notactive,deprecated,sunsetorall - 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_versionis 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
404instead, not403
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:managefor writes, orpipeline:readfor 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
404rather than403, 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
404here 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
404to 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
skippedrows. Forforbidden, ask that repository's Maintainer to run the change; forvalidation_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_tokento 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.
Edit the draft to remove the parameter, and save. Nothing changes for any consumer — a draft is not referenceable.
Dry-run a publish of
v2.0.0. The report says the contract moved by a major step and confirmsv2.0.0as 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.Publish
v2.0.0with a changelog saying what to do instead ofcargo_flags.Read upgrade impact against
v2.0.0. Everyone shows asneeds_repin, which is exactly right: a major bump never arrives on its own.Re-pin with
dry_run, fromv1.*tov2.*. Read the skipped rows — a pipeline that still suppliescargo_flagsappears asvalidation_failedwith the message.Fix those pipelines, or hand their repositories the list. Then run the sweep for real.
Deprecate
v1.4.2once 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.
Declare
WEB_S3_BUCKETandWEB_DISTRIBUTION_IDon each environment —stagingandproduction— once. An Owner of the environment does this.In the component body, declare one
stringparameter,target, and spend it on both nodes'environmentsetting inparam_slots. Write{"$var": "WEB_S3_BUCKET"}and{"$var": "WEB_DISTRIBUTION_ID"}where the two nodes' configuration needs them.Publish. The version's
variable_requirementslists both names, so anyone about to use it can see what their environment has to hold.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.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.
Related
- 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:readorpipeline:manage, and why a scope cannot be added afterwards