Publish semantics
README.yml and AGENT.yml from each stored source are resolved and published with the release set. Builds and commit must finish within one hour. Component identifiers survive display-name and workspace-namespace changes. Previous identifiers resolve with a warning naming the current qualified name; neighbor references display the target's current name. README errors distinguish private targets, targets not released yet, and unknown targets. Bare backend aliases resolve within the caller's workspace.
ppl component promote --with <sibling_prerelease_version_id,...> releases a component family together. Every member is built first, then all releases commit together with README references validated against the complete set. A failed build or reference check leaves all members unreleased. Visibility permissions still apply.
Publish semantics
TL;DR
- Publish and promote (release) are two separate operations. Publish stores a private prerelease build the caller can test; promote releases a chosen prerelease into the public, pinnable version.
- Every component build moves through two states:
prerelease(private to the caller, deployable only by them) andreleased(public, deployable by anyone in the workspace's audience). Publish creates the first; promote turns it into the second. - A prerelease is a validated snapshot of the source tree. The build runs on the platform to confirm it compiles, the resulting image is stored privately, no registry push happens, no catalog tags move. Your first publish of a component creates its prerelease with a new ID; every later publish overwrites that prerelease in place, so the prerelease ID stays the same and names the newest build.
- A promote releases that prerelease into the released catalog: the image goes to the registry, the tags declared in
component.yml(latest/default/custom) move, catalog-facing fields (categories, modalities, neighbors, alternatives) sync, the version flips state. The ID does not change. - The two operations answer different questions. Publish answers "does this build". Promote answers "is this version public". Keeping them separate keeps a build that only passes validation out of the public catalog.
- The CLI is cwd-driven:
ppl component publishandppl component promoteboth resolve the component from the working directory'scomponent.yml. There is no version-id argument on promote; the cwd component's latest prerelease is the target.
Why two states exist
Publish and promote (release) are two separate operations. Publish stores a private prerelease build the caller can test; promote releases a chosen prerelease into the public, pinnable version. Keeping them separate means a build stays private until something explicitly promotes it, so nobody pinning the public tag depends on an unreleased build.
Publish validates a build and stores the resulting snapshot for testing. The build runs on the platform's builder, the image is stored privately to the caller, and the artifact is addressable by its prerelease ID. Nobody else sees it. The caller can deploy it in a test backend, run a live-fixture loop, and compare its behavior to the previous version. None of that activity is visible outside the caller's workspace.
Promote is the separate decision that the validated prerelease is ready to release — made public in the catalog, tagged as latest / default / whatever the component declares, and deployable by everyone whose visibility scope includes it. A released version is what other people pin against.
The split makes "is this version safe to depend on" answerable. A pinned released version has been through both validation (publish) and a human decision (promote). A prerelease ID is private exploration by construction: the right artifact for tests, the wrong artifact for production.
What publish actually does
Publish freezes the current state of the component's source tree into your prerelease of the component. The CLI runs from the component's root directory (the one with component.yml and src/), packages the source, the manifest, any Docker stage files present, the assets directory, and a LICENSE if small enough. It sends that bundle to the platform's build system, the build runs remotely, and on success the platform records it as a version in state prerelease. Your first publish of the component creates that version with a new ID; every later publish overwrites it in place under the same ID.
ppl component publishppl component publish -m "describe the change"ppl component publish --dry-run # validate without writing anything
--dry-run runs the same packaging and remote build and reports success, but does not create the remote component, persist any local link, register a version, or push anything to the registry. It is the loop for fast iteration while editing src/ — when --dry-run passes, the platform-side build agrees with the source.
The lookup-or-create behavior is what makes the first publish and every subsequent publish behave predictably. If the working directory is linked to an existing component, publish writes your prerelease of that component. If not, it looks the component up by name (the name: from component.yml); a single match links to it; zero matches require explicit -y / --yes consent to create a new remote component. Linking is non-destructive and adopting an existing remote does not require consent; creating a new remote does, since the consent flag gates the one action that produces a new object.
What publish does not do is equally load-bearing. It does not push to a public registry; the image stays private. It does not change a released version; a later publish overwrites only your existing prerelease of the component, in place and under the same ID. It does not redeploy; backends still pin to whatever version they were created against, and a vertex has to be bumped to a newer version and the backend redeployed for the new code to run.
What promote actually does
component promote --into <target> replaces a released version named by UUID or the same component's default or latest tag alias. A first release uses bare promote. The person's review covers the replacement.
Promote takes a specific prerelease (the one belonging to the cwd component) and runs the release steps on it: rebuild the image from the stored source (so the registry image is reproducible from the recorded source bundle rather than from the caller's local docker cache at publish time), push it to the platform registry, apply the tags declared in component.yml (latest, default, or whatever the manifest names), sync the catalog-facing fields (categories, modalities, neighbors.upstream, neighbors.downstream, alternatives), and flip the version's state to released. The ID does not change; the version that was prerelease is now released.
cd <component-root>ppl component promote
There is no version_id argument because the cwd component's prerelease is the target. Tags and catalog fields are sourced from component.yml at promote time — there is no separate "update tags" verb, and the platform rejects tag writes against a prerelease, since tags are the public contract and a prerelease has no public contract. Until promote runs, the latest and default tags still point at the previously released version, so a new build does not change what the public resolves.
Check the existing versions before promoting (ppl component versions <component_id> lists them oldest first, with each version's release state and tags). promote resolves the cwd component's single prerelease and releases it; the tags declared in component.yml decide where latest and default land. A component has at most one prerelease at a time, so there is never any ambiguity about which version promote acts on.
The cwd discipline
Both publish and promote resolve the target component from the working directory. The CLI walks up from the current directory looking for a linked component.yml; the first one found is the component being operated on. Neither command takes a version-id argument — the cwd is the argument. Running publish from the wrong directory publishes the wrong component; running promote from the wrong directory promotes the wrong prerelease.
Resolving from the working directory keeps the target tied to the source tree on disk rather than to a separately supplied identifier. The directory the caller is standing in is the component being operated on.
How publish, promote, and deploy compose
The three verbs are independent operations that compose into the release loop:
- Publish writes a prerelease that is deployable by the caller. The next step is usually a live-backend test on the prerelease (see Test with a live backend).
- Promote releases the prerelease into the catalog. Promoted versions sit in the catalog available to be pinned.
- Deploy runs a backend on a runtime. Backends pin to specific version IDs; promoting a prerelease does not change any deployed backend's pinned version. To roll a backend forward, change the vertex's version (
ppl backend change-version) and redeploy.
The three operate on different surfaces. Publish produces only private prereleases. Promote changes only the catalog; no running deployment moves. Deploy touches the runtime but not the catalog. Because the surfaces are distinct, each step runs without coordinating the others.
Where this fits
Publish semantics are the contract every other release-related decision relies on. A prerelease ID names the newest build you published. Publishing replaces that build under the same ID and reopens only checklist rules whose inputs changed: execution or test changes need another live test, while README edits preserve live proof and unrelated reviews. Promotion depends on the validated prerelease being exactly what the registry serves. Deployments depend on pinned versions not changing underneath them. Those guarantees all follow from the same rule: publish overwrites your prerelease, promote releases it, deploy pins, and publish never touches a released version.
The model uses two verbs instead of one. In return, a released version always corresponds to a single recorded build that went through validation and the person's release review, and publishing again never changes the build a backend pinned to a released version runs.
Related
- Quickstart — empty directory to released.
- Test with a live backend — what to do after publish lands.
- The lease lifecycle — ephemeral scope for the test loop.
- Components — the underlying object publish operates on.
- Build systems — how the platform turns source into a validated image.
- component.yml — manifest reference (tags, catalog fields).