Skip to content

A member on plunge

llms.txt lists every page for an agent

plunge is a Pulumi fork with its own state backends. A Pulumi member can run on it, and chant then runs plunge where it would run pulumi. The member kind, the graph and the node ids are the same. The plunge-member example in lexicons/pulumi/examples/ is a workspace with one such member.

SourceSays plunge whenRead
pulumi.member.engineit is "plunge"first; when set, it decides
plywood.ymlengine: plunge, or a backend starting with plungewhen the config sets no engine
PULUMI_BACKEND_URLit starts with plungeafter plywood.yml
Pulumi.yaml backend.urlit starts with plunge (plunge+file://..., plunge://...)last

With none of these naming plunge, the member runs stock pulumi. The CLI’s login state is not read. The plan output prints which source decided.

PUL015 checks one direction only. A config that says engine: "pulumi" while the resolved engine would be plunge, from plywood.yml, PULUMI_BACKEND_URL or Pulumi.yaml, runs stock pulumi against a backend it cannot open, and PUL015 reports that at build time with the source in the message. The reverse, engine: "plunge" with a stock backend, is never reported, because plunge opens stock backends and that is a valid setup.

ReadCommandChanges the stack
graphnone; the export in the index store, else the checked-in stack-export.jsonno
export after an applyplunge stack export --stack <name>, from the pulumi-up apply onlyno
change setplunge preview --jsonno
applied outputsplunge stack output --json --show-secrets=falseno
driftplunge drift --resource <urn> --stream --stack <name>, per resourceno
engine factsplunge graph --json --stack <name>, once per memberno
adoption previewplunge stack adopt --json --stack <name> [--file <file>], from PulumiAdoptOpno
adoptionplunge stack adopt --json --yes --stack <name> [--file <file>], from PulumiAdoptOp after its gatewrites plunge’s records

runAllowedPlunge refuses any other argv before it reaches the binary, as ruled on #4476. For plunge graph it lets through exactly four argv (#4529):

plunge graph --json
plunge graph --json --stack <stack>
plunge graph --json --versions
plunge graph --json --stack <stack> --versions

Flags go in that order, each at most once. Any outputs or secrets flag is refused, since chant never asks plunge for an output value.

plunge graph --json prints the stack’s graph from plunge’s records, in the engine graph document of #4520. It reads no live object and makes no provider call. chant reads it two ways:

ReadSourceWhat it adds
describeResourcesplunge graph --json --stack <name>each node as a resource, with plunge’s physicalId and its facts on ResourceMetadata.facts; ownership is unknown and no marker is set
the grapha checked-in engine-graph.json beside stack-export.jsonnodes[].facts, and the property edges with grain: "property"

The export’s dependencies and parent edges carry grain: "instance" on every member. The graph’s provider edges are not taken, since providers have no node. Facts are for people and for readers that show the graph: nothing in chant decides from them. plunge’s markers say source: "record", what its record says it wrote, and its ownership is only bound or pending.

describeResources leaves --versions off: it costs one version listing per record. Take the file with the same command the read runs:

Terminal window
plunge graph --json --stack dev > engine-graph.json

A stock member gets no facts, and chant runs nothing new for it. A plunge older than plunge graph fails the read, and every entity is then not-observed with read-failed.

plunge drift --stream prints drift-record NDJSON, one record per line, so chant decodes it rather than mapping a refresh’s steps. Each record is placed on a node by the same URN rule the graph uses (@intentius/chant/pulumi-urn). A resource plunge cannot read, such as a component with no cloud object, comes back not-observed with plunge’s reason.

A stack chant applies with pulumi-up gets its export written to the index store after each plunge up, as a stock stack does. A stack applied outside chant checks in the same stack-export.json a stock member does, taken with plunge:

Terminal window
plunge stack export --file stack-export.json

Every check on The stack export applies to it.

PulumiAdoptOp moves stock Pulumi stacks onto plunge’s records, one wave per stack, behind a gate:

import { PulumiAdoptOp } from "@intentius/chant-lexicon-pulumi";
export const { op } = PulumiAdoptOp({
name: "adopt-infra",
stacks: [{ member: "infra", dir: "./infra", stack: "dev" }],
});

The Check phase runs chant’s shared bucket check on the bucket the plunge+ backend URL names and refuses a stack whose bucket fails a setting that is not waived (allow_insecure on the URL, PLUNGE_ALLOW_INSECURE, or the stack’s allowInsecure). The Export phase takes each stack’s stock checkpoint with pulumi stack export --stack <name> into a scratch file, which is the copy to import if you back out. For each stack, Preview runs plunge stack adopt --json, the gate binds that document’s digest, and Adopt runs it again with --yes. A stack coming from Pulumi Cloud sets from: { backend: "https://api.pulumi.com" }, and one exported by hand sets from: { file }; plunge then adopts the export with --file.

Each gate waits on the workspace ledger until chant approve <op> <gate>, and the run is recorded there like any Op run. Adoption calls no cloud API. The next plunge up adds the plunge-stack and plunge-urn tags.

chant