Skip to main content

Built-in Core Activities

Three activities with no external dependency: read the clock, pause, and run a whole workflow inside a single activity.

The rest of the builtin.* namespace is documented separately — state, secret, event and deploy.

Defaults​

ActivityTimeoutMax attemptsLocal
builtin.now—1yes
builtin.delay—1yes
builtin.execute_workflow86400 s (1 day)1no

builtin.now and builtin.delay run locally by default because a trip to a worker queue would cost more than the work itself.


builtin.now​

Returns the current timestamp on the worker.

Input

None.

Output

A datetime value (not an object with fields). Store it with output.as and use it directly.

Example

- task_name: get-timestamp
activity:
type: builtin.now
output:
as: started_at

# ... later
- task_name: summarise-run
set:
- run_label: '{{ started_at.strftime("%Y-%m-%d") }}'
- elapsed_sec: '{{ (finished_at - started_at).total_seconds() }}'
Determinism

builtin.now reads the worker's clock at execution time. On the Temporal runtime the value is recorded in workflow history, so a replay sees the original timestamp rather than the clock of the replaying worker.


builtin.delay​

Pauses the workflow for a given duration.

Input

FieldTypeRequiredDefaultDescription
durationstr | numbernonullHow long to wait. A number is seconds; a string is a pandas-style interval such as 5s, 10min, 1h30m. Omitting it is a no-op

Output

true when a delay was performed, null when duration was omitted.

Example

- task_name: wait-5-seconds
activity:
type: builtin.delay
input:
duration: 5s

A polling loop — raise: break leaves the loop once the job is done:

- task_name: poll-status
loop:
in: '{{ range(max_polls) }}'
do:
tasks:
- task_name: check-status
activity:
type: http.request
input:
method: GET
url: '{{ status_url }}'
output_json: true
output:
set:
- status: '{{ _["json"] }}'
- task_name: stop-when-done
raise:
if: '{{ status["state"] == "done" }}'
type: break
- task_name: wait-before-next-poll
activity:
type: builtin.delay
input:
duration: 30s
Long waits belong in wait_for

builtin.delay holds an activity slot for its whole duration. To pause for hours or days, or until something happens, use a wait_for task or a state machine instead — see Events.


builtin.execute_workflow​

Runs an entire workflow in memory, inside one activity, using an embedded engine.

Reach for it when a workflow moves large data between tasks. On the Temporal runtime every activity input and output crosses the wire and is capped at 2 MB; an embedded run keeps intermediate data in the worker's process, so neither limit nor marshalling cost applies.

The trade is observability: tasks inside the embedded workflow are not individual Temporal activities, so they get no per-task history and no per-task retry. The whole embedded run succeeds or fails as one unit.

For an ordinary child workflow, use the workflow task instead. This activity is the lower-level alternative: the spec to run is resolved when the activity runs, so it can be picked from data — a name held in a variable, or YAML generated at runtime.

Input

FieldTypeRequiredDefaultDescription
wfspecWorkflowSpecInfoyes—Which workflow to run
input_dataanynonullInput passed to that workflow; it becomes the embedded workflow's input
optionsWorkflowExecuteOptionsnonullExecution options

WorkflowSpecInfo​

Identify a deployed workflow by name (plus optional version), or supply the spec inline as content. Inline content is how a dynamically generated workflow is run without deploying it.

FieldTypeRequiredDefaultDescription
namestrnonullName of a deployed wfspec
versionstrnolatestVersion to run
contentstr | list[str]nonullThe wfspec YAML itself — a complete document with header and main. With a list, item 0 is the entry point

WorkflowExecuteOptions​

The commonly used fields; all are optional.

FieldTypeDescription
debug_modeboolPublish debug events for the embedded run
catch_exceptionboolReturn the error instead of failing the activity
trace_idstrCorrelate the embedded run with the caller's trace
workflow_idstrIdentifier for the embedded run
tierstrExecution tier
execute_modestrin-memory, standalone-activity or workflow
retry_policydictTimeout and retry settings for the embedded run
enable_otel_traceboolEmit OpenTelemetry spans

Output

The embedded workflow's own output, unchanged.

Examples

Running a deployed spec by name:

- task_name: run-signal-analysis
activity:
type: builtin.execute_workflow
input:
wfspec:
name: multi-timeframe-trading-signal
input_data:
symbol: '{{ symbol }}'
confluence_threshold: '{{ confluence_threshold }}'
hourly_prices: '{{ hist_candles }}'
output:
as: last_result

Running an inline spec. The #literal modifier keeps the embedded document's {{ }} expressions from being evaluated by the caller; they run inside the embedded workflow:

header:
schema_version: 2.0.0
workflow_name: run-embedded-sum

context:
summing_child#literal: |
header:
schema_version: 2.0.0
workflow_name: embedded-sum
input:
numbers: []
output:
count: '{{ len(numbers) }}'
total: '{{ sum(numbers) }}'
main:
set: []

input:
numbers: [3, 4, 5]

output: '{{ result }}'

main:
task_name: run-inline-child
activity:
type: builtin.execute_workflow
input:
wfspec:
content: '{{ summing_child }}'
input_data:
numbers: '{{ numbers }}'
options:
catch_exception: true # a failing child comes back as data
output:
as: result

A complete example, including a spec chosen at runtime, is in moco-examples/activities/builtin-execute-workflow.yaml.

What the embedded workflow can call

It sees the activities of the worker it runs on. On the base worker that is the core provider set; on the agent worker it additionally includes claude_agent.*. It cannot reach activities served by a different worker type.

Not retried

builtin.execute_workflow ships max_attempts: 1 — a retry would re-run every side effect inside the embedded workflow. It heartbeats every 20 seconds so Temporal detects a dead worker within a minute rather than waiting out the one-day timeout.