Ops Reference
Reference for the *.op.ts file contract: the built-in step builders and retry profiles, how search attributes are emitted, what bounds an ApplyOp delete on each target, and the files chant build generates. For how to define, gate, and run an Op, see Ops.
Step builders
Section titled “Step builders”Pre-built step builders:
| Builder | What it does |
|---|---|
shell(cmd, opts?) | Run an arbitrary shell command |
build(path) | Run chant build |
kubectlApply(manifest, opts?) | Server-side apply a manifest as chant’s field manager |
helmInstall(name, chart, opts?) | helm upgrade --install |
waitForStack(stackFile, opts?) | Poll until a chant stack output file is ready |
gitlabPipeline(projectId, ref, opts?) | Trigger a GitLab pipeline and wait |
lifecycleSnapshot(env, opts?) | chant lifecycle snapshot |
teardown(path, opts?) | Build + destroy |
Retry profiles
Section titled “Retry profiles”Each step takes an optional profile that controls Temporal retry and timeout settings:
| Profile | Suitable for |
|---|---|
fastIdempotent (default) | Quick, safe-to-retry steps |
longInfra | Slow infra changes (cluster create, Helm install) |
k8sWait | Polling until K8s resources are ready |
humanGate | Steps that may take hours |
Search attributes
Section titled “Search attributes”Each generated workflow auto-emits upsertSearchAttributes() calls so workflow runs are filterable in the Temporal UI without hand-coded boilerplate. Two emission points:
- Initial call at workflow start:
OpNameplus anysearchAttributesyou declare on the Op - Per-phase call at the start of each phase (and each
onFailurephase):Phaseset to the current phase name
Declare custom attributes on the Op:
export default Op({ name: "alb-deploy", overview: "Deploy ALB stack", searchAttributes: { Environment: "staging", Region: "us-east-1", }, phases: [ phase("Build", [/* ... */]), phase("Deploy", [/* ... */]), ],});The generated workflow.ts produces:
export async function albDeployWorkflow(): Promise<void> { upsertSearchAttributes({ OpName: ["alb-deploy"], Environment: ["staging"], Region: ["us-east-1"], });
// Phase: Build upsertSearchAttributes({ Phase: ["Build"] }); // ...
// Phase: Deploy upsertSearchAttributes({ Phase: ["Deploy"] }); // ...}For an Op with N phases this is N+1 upsert calls total. Values are wrapped as single-element arrays for the classic @temporalio/workflow API.
Registration is separate. Auto-emit assumes the attributes are already registered server-side. Declare them with the
SearchAttributeresource sochant buildemits the registration commands. See alsochant lifecyclefor snapshotting registered attributes against a live cluster.
User-provided keys merge over the OpName default; if you set searchAttributes: { OpName: "custom" } the user value wins.
Outcome-based search attributes
Section titled “Outcome-based search attributes”Activity steps support an optional outcomeAttribute field that captures the activity’s return value and surfaces it as a workflow search attribute:
phase("Diff", [ { kind: "activity", fn: "lifecycleDiff", args: { env: "prod", live: true }, // Capture lifecycleDiff's `drifted` field and tag the run Drift=true/false outcomeAttribute: { name: "Drift", from: "drifted" }, },]),The serializer turns this into:
const __r0 = await lifecycleDiff({"env":"prod","live":true});upsertSearchAttributes({ "Drift": [String(__r0?.drifted)] });from is a dot-path into the return value; when omitted, the whole return value is stringified. Counters are workflow-scoped (__r0, __r1, …), and parallel phases destructure Promise.all results so each outcome attribute fires after the corresponding activity returns.
Delete paths
Section titled “Delete paths”delete controls how apply treats resources no longer declared. The delete rides the target’s own delete path, and what bounds that path differs per target:
| target | delete path | what bounds it |
|---|---|---|
kubectl | a sweep filtered by app.kubernetes.io/managed-by=chant (and by the stack when ownership.stack is set), restricted to the namespaces the apply touched | the ownership marker — an unmarked object is never touched |
arm | pruneArmOrphans, which lists the resource group and deletes only resources carrying chant’s ownership tag | the ownership tag — an untagged resource is never touched |
cloudformation | the stack deletes resources removed from its template | the stack — a resource CloudFormation did not create is not in it |
All three are owned-only by construction.
Codegen
Section titled “Codegen”chant build emits three files per Op under dist/ops/<name>/:
| File | Purpose |
|---|---|
workflow.ts | Temporal workflow function — phases, gates, onFailure |
activities.ts | Re-exports all pre-built activity implementations |
worker.ts | Worker bootstrap — reads profile from chant.config.js |
See Ops for how to define, gate, and run an Op.