Product

Solutions

Resources

Pricing

Self-Managed Pipelines

PipelinesTektonCI/CDService Hub

A self-managed pipeline is plain Tekton YAML in your repository. Planton compiles it at dispatch into one self-contained run — every task reference resolved inline, the platform's parameter contract verified, the compiled definition stamped on the run record — and then handles what it always handles: webhook triggering, credentials, status streaming, the deploy stage, and approval gates.

Platform track or your own pipeline

A service's spec.build selects exactly one builder:

BuilderWho writes the pipelineDeploy stage
dockerfilePlanton's release-pinned dockerfile trackPlanton
buildpacksPlanton's release-pinned buildpacks trackPlanton
tektonPipelineYou, as Tekton YAML in your repository (or an organization-published pipeline)Planton

Choose your own pipeline when you need build steps the platform tracks do not have: test suites, linting, security scanning, a build tool like Bazel, parallel or conditional tasks.

The pipeline file

By default the pipeline lives at .planton/pipeline.yaml under the service's project root — beside the service's Dockerfile and its _kustomize tree. Selecting it is one line:

spec:
  build:
    tektonPipeline: {}
    registry: my-registry
    imageRepositoryPath: acme/storefront

To keep it elsewhere, name the path (relative to the project root):

spec:
  build:
    tektonPipeline:
      yamlFile: ci/build.yaml

The file is a tekton.dev/v1 Pipeline document. It is read at the exact commit being built — never from a branch.

Tasks beside the pipeline

A pipeline references tasks by their plain Tekton name:

tasks:
  - name: lint
    taskRef:
      name: eslint-check

The compiler resolves a plain reference from three places, most specific first:

  1. Your repository — a Task document in a tasks/ directory beside the pipeline file (.planton/tasks/*.yaml for the default location), or a second document in the pipeline file itself (----separated, exactly as kubectl apply -f accepts).
  2. Your organization — a published TektonTask record with that name.
  3. The platform cataloggit-clone, buildkit-daemonless, buildpacks, kustomize-build (their definitions live in the open-source repository under cicd/tekton/tasks/).

A repository task with the same name as a catalog task wins — your file is what runs, and the run record shows it. A taskRef that uses a remote resolver (resolver: git, hub, bundles) is refused: compiled pipelines are self-contained, so nothing is fetched at run time.

A repository task is an ordinary Tekton Task:

# .planton/tasks/eslint-check.yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: eslint-check
spec:
  workspaces:
    - name: source
  steps:
    - name: lint
      image: node:20-alpine@sha256:fb4cd12c85ee03686f6af5362a0b0d56d50c58a04632e6c0fb8363f609372293
      workingDir: $(workspaces.source.path)
      script: |
        npm ci && npx eslint .

The parameter contract

Planton supplies one set of parameters to every build, and the compiler verifies it against your pipeline's spec.params in both directions before dispatch: a supplied parameter your pipeline does not declare is a compile error, and a declared parameter with no default that nothing supplies is a compile error. Your pipeline must therefore declare every one of these (defaults are fine):

ParameterValue
git-urlThe repository clone URL
git-revisionThe commit SHA being built
git-branchThe branch name (empty for a tag build)
project-rootThe service's project root within the repository
sparse-checkout-directoriesComma-separated sparse-checkout patterns (may be empty)
owner-identifier-label-key, owner-identifier-label-valueStamp these on everything the pipeline creates — log attribution selects by them
kustomize-manifests-config-map-nameWhere the deploy stage reads the rendered overlays
kustomize-base-directoryThe service's kustomize base directory
image-namePresent when the build names a registry: <registryHost>/<imageRepositoryPath>:<commitSha>
dockerfile-config-map-name, build-context, dockerfile-pathDockerfile builds only

Plus anything you put under build.tektonPipeline.params (free-form key/value pairs; they cannot shadow the platform's names).

Trigger facts — supplied only if you declare them

Three more parameters describe the run, and the platform supplies them only when your pipeline declares them, so an existing pipeline never has to change:

ParameterValue
git-tagThe tag name for a tag build; empty otherwise
pull-request-numberThe pull request number for a pull-request build; empty otherwise
trigger-typewebhook, manual, or rerun

Gate a task with Tekton's own when — no platform grammar to learn:

spec:
  params:
    - name: git-tag
      type: string
      default: ""
  tasks:
    - name: sbom
      when:
        - input: "$(params.git-tag)"
          operator: notin
          values: [""]
      taskRef:
        name: generate-sbom

Workspaces

The platform binds one pipeline-level workspace: source, the cloned repository. Declare it and pass it to your tasks. A pipeline that requires any other workspace is refused at compile time — declare it optional: true or drop it. Secrets are always runtime references (secret names, mounts), never values in a definition.

Validate before you push

planton service pipeline validate .planton/pipeline.yaml -o json

The same compiler that runs at dispatch runs locally: it discovers the tasks beside the file, resolves catalog references, checks the parameter contract, and reports every problem in one pass. The platform's contract stands in for the dispatch — the parameters every build receives count as supplied, and a pipeline that forgets to declare one is refused here exactly as the dispatch would refuse it — so pass --param only for the pipeline's own parameters (--param git-tag=v1.4.0 exercises a when); --task <name>=<path> supplies a task the way an organization-published record would. The JSON carries valid, source, pin, compiler_version, compiled_bytes, tasks_resolved (each with the rung that answered it), and errors; the exit code is 1 on any error. A pipeline that validates clean compiles clean. An agent working through Planton's MCP server has the same loop as the validate_service_pipeline tool: pointed at your service it reads the pipeline and the task files beside it straight from your repository — at HEAD, or at the exact commit a run built — answers with the same report, and resolves the tasks your organization has published without you naming them; it also accepts the files themselves for a change that exists only in the conversation.

Compile verdicts

CodeMeaningFix
invalid_yamlA document is not valid YAMLFix the YAML; the message names the file
invalid_pipeline_schemaThe document is not a tekton.dev/v1 Pipeline, or fails Tekton's own validationCorrect apiVersion/kind, or the field Tekton names
multiple_pipeline_documentsThe source contains more than one PipelineKeep one Pipeline per source; extra documents may only be Tasks
unexpected_document_kindA document beside the pipeline is neither a Pipeline nor a TaskRemove it, or move it out of the pipeline's tasks/ directory
duplicate_task_definitionTwo repository documents define a Task with the same nameRename one
unresolved_task_refA taskRef names nothing in your repository, your organization, or the catalogAdd the Task beside the pipeline, publish it, or fix the name
resolver_ref_unsupportedA taskRef uses a remote resolverReference the task by name; inline it or add it beside the pipeline
undeclared_paramThe platform supplies a parameter the pipeline does not declare (or a build.tektonPipeline.params key is not declared)Declare it under spec.params — every pipeline declares the nine always-supplied parameters
missing_required_paramA declared parameter has no default and nothing supplies itGive it a default, or set it under build.tektonPipeline.params
unbindable_workspaceThe pipeline requires a workspace the platform does not bindUse source, or mark the workspace optional: true
dangling_result_reference$(tasks.X.results.Y) names a task or result that does not existFix the task or result name
literal_secret_envAn env var looks like a literal secret valueUse a secret reference or a mounted workspace
repo_file_unreadableThe pipeline file could not be read at the built commitCheck yamlFile and that the file exists at that commit

What a run records

Every run stamps the compiled definition on its record: the exact YAML that executed, source: repo, and the commit SHA as its pin. A rerun replays those bytes byte-identically. The run view and planton service pipeline get show them; see Pipelines for the run model.

Organization-published pipelines and tasks

An organization writes a pipeline once and every service consumes it by name. Two record kinds carry the Tekton content verbatim:

  • TektonTask — exactly one tekton.dev/v1 Task document in spec.yamlContent. Any pipeline in the organization (a repository pipeline or a published one) references it with a plain taskRef: {name: <name>}; it resolves after the pipeline's own tasks and before the platform catalog.
  • TektonPipeline — one tekton.dev/v1 Pipeline plus any Task documents it bundles (----separated) in spec.yamlContent. A service consumes it with one line: spec.build.tektonPipeline: {pipeline: <name>}.

Both are organization-owned records with a description (one line, indexed for search) and an overviewMarkdown where the publishing team documents what a consumer must supply — the parameters a service passes under build.tektonPipeline.params, and whether the service must name a container registry. The record's metadata.name must equal the Tekton document's metadata.name and must be a Tekton name (lowercase letters, digits, hyphens), so the record's name is also its slug: planton get TektonPipeline <name>, the service's pipeline: <name>, and a taskRef all use the same one name.

apiVersion: service-hub.planton.ai/v1alpha1
kind: TektonPipeline
metadata: {name: node-service-ci, org: acme}
spec:
  description: Clone, lint, build with BuildKit, render kustomize
  overviewMarkdown: |
    Set `spec.build.registry` (this pipeline pushes an image) and
    `build.tektonPipeline.params.node-version`.
  yamlContent: |
    apiVersion: tekton.dev/v1
    kind: Pipeline
    metadata: {name: node-service-ci}
    spec: ...   # declares the platform contract, image-name, node-version

Publishing is one planton apply -f per record, tasks first. The publish check runs before the record is written — at the CLI, through the assistant's tools, and at the API: the same compiler that runs at dispatch verifies the document shape, the name law, every task reference (against the bundled tasks, the organization's published tasks, and the catalog), the parameter contract, workspaces, result references, and Tekton's own admission rules. A record that would not compile is refused with the verdicts above in one sentence, and nothing is written. A pipeline that references a task the organization has not published yet is refused with unresolved_task_ref: publish the task first, or bundle it as a second document.

Consuming is verified when the service is applied: a build.tektonPipeline.pipeline naming no published record is refused there, with the fix in the sentence — never at the first build. Each run of a consuming service stamps source: org_published and the pin <record id>@<record spec updated-at>; updating a record changes what the next fresh run compiles, while reruns replay the stamp they carry.

Deleting is refused while anything depends on the record: a TektonPipeline any service still builds from (the refusal names the services), a TektonTask any published pipeline still references (the refusal names the pipelines). Repository pipelines that reference a deleted task learn at their next compile through unresolved_task_ref.

There is no catalog page. planton search --kind TektonPipeline (or TektonTask) lists what the organization has published; planton get TektonPipeline <name> shows a record with its documentation; the assistant reads the same through its get_tekton_pipeline / get_tekton_task tools and search.

Next article

CI/CD on Your Laptop

Planton Desktop turns a laptop into a complete CI/CD control plane. You push a commit to GitHub, and the machine on your desk notices the push, builds the commit inside a pod on a build cluster it runs for you, pushes the image to your registry with your own sign-in, deploys to the cluster or cloud you connected, puts a status on your commit, and tells you when it is done. Nothing is hosted, nothing has a public address, and there is no configuration step on this page. Hosted CI starts from a...
Read next article