Core Action Steps
The core steps do the actual work: do calls a tool, and let computes a value.
This page covers both, then walks through the three kinds of capability you can
invoke with do β native tools, K3 / Ignite tools, and the built-in model
capabilities (llm, embed, rerank, transcribe, infer).
do β call a tool
do is the workhorse. It names the action, picks a tool with with, passes
named inputs, and binds the result.
do "Search the web" with web_search
query = topic
max_results = 20
-> results- The string is the step label.
with web_searchselects the tool (which must be in the tools block β except for the internal model capabilities below, which need no declaration).- Each indented
name = exprline is a named input. They are validated against the toolβs input schema: required inputs must be present, and types must match. -> resultsbinds the toolβs full output object.
A short form puts the inputs in braces on one line:
do "Quick search" with web_search { query = topic }
-> resultsEach do can carry one on error: recovery clause (retry, fallback, or
ignore) β see Error Handling.
let β compute a value
let binds the result of an expression to a name. Unlike do, it calls no
tool β it is pure computation over values already in scope.
let counter = counter + 1
let is_ready = status == "ready" and retries < 3
let query_vector = [0.5, 0.3, 0.8, 0.1]
let cosine_scores = map(raw_scores, item => item.similarity)
let resolved_url = transferred.content.urlUse let to reshape data, derive flags for check/decide, build records for
a later tool call, or hold a running counter inside repeat.
Invoking native tools
Native tools are built-in Rust functions β file operations, search, shell,
HTTP, vector-store writes, K3 table writes, and the echo passthrough used for
testing. They are always available; import them from native.
import tools
file_glob from native
echo from native
do "Find Rust files" with file_glob
pattern = "crates/scriptum-compiler/src/*.rs"
-> glob_result
do "Tag a file" with echo
message = glob_result.matches[0]
-> taggedInvoking K3 / Ignite tools
K3 is where structured data lands. K3 (and other Ignite-backed) tools are
imported by name β often namespaced and aliased β and called exactly like native
tools. Below, a transcript is written into a K3 table: first ensure the schema,
then insert rows. (Adapted from templates/vision/audio_transcription.scriptum.)
import tools
k3_table_ensure_schema from native
k3_table_insert from native
env
K3_GRPC_ENDPOINT = ""
K3_SERVICE_ACCOUNT_ID = ""
K3_SERVICE_ACCOUNT_SECRET = ""
do "Ensure Schema" with k3_table_ensure_schema
bucket = bucket
table_name = table_name
org_id = org_id
columns = {
input_ref: { type: "text", nullable: false },
transcript: { type: "text", nullable: true },
summary: { type: "text", nullable: true },
created_at: { type: "timestamp", nullable: true, default: "CURRENT_TIMESTAMP()" }
}
merge_keys = merge_keys
k3_endpoint = env(K3_GRPC_ENDPOINT)
service_account_id = env(K3_SERVICE_ACCOUNT_ID)
service_account_secret = env(K3_SERVICE_ACCOUNT_SECRET)
-> ensured
do "Write to warehouse" with k3_table_insert
bucket = bucket
table_name = table_name
org_id = org_id
rows = [{ input_ref: input_ref, transcript: transcript.text, summary: summary.text }]
match_columns = merge_keys
assume_schema_ok = true
k3_endpoint = env(K3_GRPC_ENDPOINT)
service_account_id = env(K3_SERVICE_ACCOUNT_ID)
service_account_secret = env(K3_SERVICE_ACCOUNT_SECRET)
-> wh_statusThe pattern generalizes: Ignite serverless tools (text extraction, chunking, data-source resolution, vector-store operations) are imported under their namespace and aliased for readability:
import tools
ignite::public::read_data_source as read_source
ignite::public::chunk_text as chunk_text
vector_store_insert from native
do "Read Source" with read_source
source = { provider: "Public" }
object = { type: "Url", value: resolved_url }
format = "String"
-> raw_dataThe internal model capabilities
Five capabilities are built into the engine and dispatched to Igniteβs managed
model service. You call them with do ... with <name>, just like a tool, but
they need no entry in the tools block.
| Capability | do ... with | What it does |
|---|---|---|
llm | with llm | LLM chat completion |
embed | with embed | text / multimodal embeddings |
rerank | with rerank | document reranking against a query |
transcribe | with transcribe | audio / video β text |
infer | with infer | generic model inference (classification, detection, diarization, β¦) |
llm β chat completion
Pass a prompt (and optional system, model, temperature, max_tokens).
The output has a .text field with the completion. If you do not name a model,
the managed LLM is used.
do "Classify" with llm
system = "You are a document classification engine. Output valid JSON only."
prompt = "Classify this text. Output JSON with document_type, topics, sensitivity.\n\nText:\n{text}"
model = llm_model
max_tokens = 512
-> classification
emit "Done"
tags = classification.textYou can run several models in one script just by setting model per call:
do "Deep analysis" with llm
prompt = "In 3 bullet points, explain {topic}."
model = "kimi-k2.5"
-> analysis
do "Quick summary" with llm
prompt = "Summarize in one sentence: {analysis.text}"
model = "moonshot-v1-auto"
-> summaryembed β embeddings
Pass the texts to embed (and a model, optional dimensions, task_type,
encoding_format). The output exposes the vectors under .data.
do "Embed text" with embed
model = embed_model
texts = [test_text, "A second sentence for batch embedding."]
-> embed_result
do "Log embed" with echo
message = "Embed returned {count(embed_result.data)} vectors"
-> embed_logrerank β reranking
Pass a query and a list of documents; the output ranks them by relevance.
do "Rerank documents" with rerank
model = rerank_model
query = test_query
documents = ["The fox is a clever animal.", "Dogs are loyal pets.", "The weather is sunny."]
-> rerank_result
do "Log rerank" with echo
message = "Top index: {rerank_result.results[0].index}, score: {rerank_result.results[0].relevance_score}"
-> rerank_logtranscribe β speech to text
Pass the audio (base64 content or a URL) and a model. The output has a
.text field with the transcript.
do "Read audio" with read_source
source = { provider: "Public" }
object = { type: "Url", value: resolved_url }
format = "Base64"
-> audio_data
do "Transcribe audio" with transcribe
model = transcribe_model
audio = audio_data.content
-> transcriptinfer β generic inference
infer runs any other model β classifiers, detectors, diarization β and returns
raw model output (logits, labels) that you postprocess with Scriptum
expressions.
do "Classify sentiment" with infer
model = infer_model
text = test_text
-> infer_resultdo "Audio classification" with infer
model = audio_class_model
input = { "type": "audio_url", "audio_url": resolved_url }
-> cls_raw
let probs = softmax(cls_raw.logits)
let best_idx = argmax(probs)
let label = cls_raw.labels[best_idx]A worked example: internal models end to end
This script exercises embed, rerank, and infer in sequence and logs each
result with echo. (Adapted from examples/test_internal_models.scriptum.)
script "test_internal_models"
version "0.1.0"
input
test_text : text = "The quick brown fox jumps over the lazy dog."
test_query : text = "What animal is mentioned?"
embed_model : text = "jina-embeddings-v4"
rerank_model : text = "jina-reranker-v2"
infer_model : text = "distilbert-sst2"
output
embed_result : object
rerank_result : object
infer_result : object
import tools
echo from native
### Test Embed ###
do "Embed text" with embed
model = embed_model
texts = [test_text, "A second sentence for batch embedding."]
-> embed_result
### Test Rerank ###
do "Rerank documents" with rerank
model = rerank_model
query = test_query
documents = ["The fox is a clever animal.", "Dogs are loyal pets.", "The weather is sunny."]
-> rerank_result
### Test Infer ###
do "Classify sentiment" with infer
model = infer_model
text = test_text
-> infer_result
emit "Test Results"
embed_result = embed_result
rerank_result = rerank_result
infer_result = infer_resultNext: orchestrate these actions with loops, branches, and parallelism in Control Flow & Concurrency.