Skip to Content
We are live but in Staging πŸŽ‰
Scriptum LanguageFile Structure & Declarations

File Structure & Declarations

Every .scriptum file has the same skeleton: an optional band of annotation comments, the script header, a set of declaration blocks, and then the body of steps. The declaration blocks must appear in a fixed order. This page covers the header, the four declaration blocks, comments, the -- @ annotations, and how all of it becomes the ScriptContract.

The skeleton

-- @accepts_content_type ... (optional annotations, before `script`) script "Name" (required) Free-text description... (optional) version "0.1.0" (optional) enum Name = A | B | C (optional, zero or more) input ... (optional) output ... (optional) stream ... (optional) import tools ... (optional) env ... (optional) <body steps> (the workflow)

The order matters. The parser expects the declaration blocks in exactly this sequence: input β†’ output β†’ stream β†’ tools β†’ env. Placing env before the tools block, for example, causes the parser to skip the misplaced block. When in doubt, follow the order above.

The script header

script "Research Agent" Research a topic from multiple angles, evaluate findings, and produce a structured summary with sources. version "1.0.0"
  • The string after script is the script’s name and primary identifier.
  • Any plain-text lines after the name (before version or the first declaration block) become the description. This is syntax, not a comment β€” it is the script’s documentation and is preserved in the contract.
  • version takes a semantic version. It is optional but recommended; published versions are immutable snapshots.

The input block

Inputs are the script’s typed parameters. Each line is name : type [constraints] [= default] [-- comment].

input topic : text -- The subject to research depth : number = 3 -- How many cycles (default: 3) verbose : boolean = false -- Show detailed output tags : list<text> -- Optional category tags
  • A field without a default is required; the runtime rejects a thread that does not supply it.
  • A field with a default is optional.
  • The trailing -- comment is captured as the field’s documentation.
  • Inputs use the full type system β€” primitives, list<T>, object shapes, enums, and constraints.

The output block

Outputs declare the shape the script returns. The compiler checks that your emit steps actually produce these fields with matching types.

output summary : text -- Final research summary sources : list -- All sources used

Outputs can carry constraints too, and list<object> outputs can declare an inline object schema with indented child fields:

output status : text artifact_id : text total_objects : integer min(0)

The stream block

The stream block declares the shape of values pushed by yield during execution. It is the streaming counterpart to output: where output describes the terminal result, stream describes the per-event payloads a consumer receives in real time over WatchThread.

output transcript : text summary : text stream transcript : text meta : object

See Streaming for how yield and pipe produce these values.

The tools block

The tools block lists every tool the script may call. Each tool is resolved against the ToolCatalog at compile time; a name that does not resolve is a compile error. There are two equivalent spellings β€” import tools (preferred) and the legacy bare tools.

import tools file_read from native -- a native built-in echo from native http_request from mcp("ignite") -- an Ignite-backed tool

A few forms you will see in real scripts:

  • name from native β€” a built-in Rust tool that always exists, no config.
  • name from mcp("server") β€” a tool discovered from an Ignite source.
  • * from native β€” wildcard import of every native tool.
  • Namespaced names β€” fully qualified Ignite tools can be imported and aliased:
import tools * from native ignite::public::read_data_source as read_source ignite::public::chunk_text as chunk_text vector_store_insert from native

The as alias lets you refer to a long namespaced tool by a short local name in the body (do "Read Source" with read_source).

You do not list the internal model capabilities (llm, embed, rerank, transcribe, infer) in the tools block β€” they are handled directly by the engine. See Core Action Steps.

The env block

The env block declares the environment variables and secrets the script needs. Values are resolved at runtime from the tenant environment store; they never live in the script source.

env SLACK_TOKEN from "SLACK_TOKEN" SLACK_CHANNEL_ID from "SLACK_CHANNEL_ID" LLM_MODEL = "gpt-4o"

Three forms appear in practice:

  • NAME from "SOURCE_KEY" β€” alias mapping: read the tenant store key SOURCE_KEY and expose it to the script as NAME.
  • NAME = "value" β€” a default value, used when the store has no entry.
  • NAME : text from "SOURCE_KEY" = "fallback" β€” env vars can carry an explicit type and constraints, identical to input fields. Untyped declarations default to text.
env MILVUS_ENDPOINT : text length(0, 2048) = "" EMBED_MODEL : TextEmbedModel = "jina-embeddings-v4"

Inside the body, read an env value with the env(NAME) function or by interpolation:

do "Embed" with embed model = env(EMBED_MODEL) texts = chunks -> embed_result

The send primitive reads channel credentials (Slack token, SMTP settings) from these env vars automatically.

Comments

Comments use -- and run to the end of the line. There are no block comments.

-- This is a single-line comment. -- Multi-line notes are written as consecutive single-line comments. do "Search" with web_search -- inline comments are fine too query = topic -> results

Note that --- (three or more dashes) is also treated as an ordinary comment β€” it is not a section separator. Section separators use ### (see below).

Sections with ###

### lines create labeled phases. They render as headers in the visual view and become section nodes in the IR; they have no effect on data flow.

### Phase 1: Discovery ### do "Search" with web_search query = topic -> results ### Phase 2: Analysis ### each result in results.matches do "Classify" with classify text = result.snippet -> categories

The -- @ annotations

Annotation comments start with -- @ and appear before the script keyword. The compiler recognizes two that shape how the platform routes data to the script:

-- @accepts_content_type text/plain, text/html, application/pdf -- @accepts_extension txt, md, html, pdf script "text_embedding_index" version "0.1.0"
  • @accepts_content_type β€” a comma-separated list of MIME types this script accepts as input data. Globs like image/* are allowed. Consumers (UI dispatch, K3 routing) match these patterns against actual files to decide which script handles an incoming object.
  • @accepts_extension β€” a comma-separated list of file extensions (a leading dot is optional; matching is case-insensitive). The canonical wire form is lowercase without the dot, so .PDF and pdf are equivalent.

Multiple annotation lines stack, and values are deduplicated. Other @-tags you may see in template files (@tags, @labels, @description) are metadata read by the template tooling and are otherwise ignored by the language compiler.

The ScriptContract

Taken together, the declaration blocks define the ScriptContract β€” the typed public interface of the script:

  • inputs β€” required and optional parameters, with types and constraints.
  • outputs β€” the terminal result shape.
  • stream β€” the per-event payload shape (if the script yields).
  • tools β€” the resolved capabilities the script depends on.
  • env β€” the secrets/configuration it expects from the tenant store.
  • accepted content types / extensions β€” the data this script is willing to process.

The contract is what the runtime validates against when a thread is created: it checks that supplied inputs satisfy the input types and constraints, and that required env vars are available. Because the contract is derived entirely from the source, editing a declaration block changes the contract β€” and the compiler re-checks the whole script against it.

Next: dig into the type system that powers these declarations in The Type System.