The Skript book · Chapter 10

Functions

A function is a named, reusable block of steps. Skript's syntax for defining one is the same construction English uses — an infinitive:

to welcome the lead
  reply on whatsapp "Welcome, {name}!"
  add tag "welcomed"

to, then a name — which may be several words — then an indented body. And the syntax for calling it is even smaller: you write the name as a plain sentence, anywhere a step can go. Here is both halves together, running:

when a new lead arrives
  welcome the lead
  log "rule finished"

to welcome the lead
  reply on whatsapp "Welcome, {name}!"
  add tag "welcomed"
output — real, executed at build time
▶ example.skript — Skode Skript · local simulation

  ● event: lead.created                → name: Ada · phone: +1 555 0100 · email: [email protected]
  ƒ welcome the lead                   → run your function
  ✉ reply on whatsapp                  → "Welcome, Ada!"
  ⚑ add tag "welcomed"                 → tagged
  • log                                → rule finished

  ✔ done in 2.1ms — 1 message · tags: welcomed

Trace-reading note: the ƒ line marks the call, and the function's own steps follow it. When the body ends, control returns to the caller — log "rule finished" ran after the function's two steps, exactly as the order of the trace shows.

Where definitions live, and when

Function definitions sit at the top level of the file — beside your when rules, never inside them — and their order does not matter. Define after use, use after define; the interpreter reads the whole file before running anything. This is worth a demonstration because it shapes how files get organised — rules first, telling the story; vocabulary after, alphabetically if you like:

when a new lead arrives
  file the paperwork

to file the paperwork
  note the arrival and stamp it

to note the arrival
  log "noted: {name}"

to stamp it
  add tag "processed"
output — real, executed at build time
▶ example.skript — Skode Skript · local simulation

  ● event: lead.created                → name: Ada Lovelace · phone: +1 555 0100 · email: [email protected]
  ƒ file the paperwork                 → run your function
  ƒ note the arrival                   → run your function
  • log                                → noted: Ada Lovelace
  ƒ stamp it                           → run your function
  ⚑ add tag "processed"                → tagged

  ✔ done in 2.1ms — tags: processed

That example also shows the second big fact: functions call functions. file the paperwork is defined entirely in terms of two other functions, and the trace nests all three calls in order. This is how skripts grow past twenty lines without becoming unreadable — the rule stays a five-line summary, and each named step hides one screen of honest detail.

Shared state, not parameters

Skript functions take no parameters and return no values — deliberately. They read and write the same namespace as everything else: event fields, your variables, the score. Where another language passes arguments, a skript sets the stage first:

set discount to 15
apply the discount

to apply the discount
  set final_price to 200 - 200 * discount / 100
  log "with {discount} percent off: {final_price}"
output — real, executed at build time
▶ example.skript — Skode Skript · local simulation

  ● event: script                      → name: Demo
  ✎ set discount                       → = 15
  ƒ apply the discount                 → run your function
  ✎ set final_price                    → = 170
  • log                                → with 15 percent off: 170

  ✔ done in 2.1ms

Is that a compromise? Yes — a knowing one. Parameters earn their keep in libraries used by strangers; a skript is a page of logic owned by one team, where "set the variable, then say the sentence" is simpler than a calling convention, and where every function's effect is fully visible in the trace. When you genuinely need parameterised, reusable machinery, that is what marketplace packages and Skode Functions are for — Skript functions are for naming this file's ideas.

Two guardrails

First: since a function may call itself (nothing forbids it), runaway recursion is possible — and, like the infinite while, it is caught rather than fatal. Sixteen levels deep, the interpreter calls it what it almost certainly is:

when a new lead arrives
  echo

to echo
  echo
output — real, executed at build time
✗ line 5: "echo" calls itself too deeply (16 levels) — probably an accidental loop

Second: a definition must not be empty, and defining the same name twice is an error — both caught at check time, before anything runs. The error chapter (13) shows the exact messages.

The naming craft

Because calls read as sentences inside your rule, the name of a function is user interface. The difference between a good skript and a great one is mostly here. Some conventions that hold up:

  • Name the business meaning, not the mechanics: escalate to a human, not send msg and tag 2.
  • Keep rule bodies at one altitude: either all raw steps or all function calls. Mixed altitudes read like a recipe that suddenly explains chemistry.
  • If you cannot name a block of steps, that is information — the block probably contains two ideas. Split it.

Functions complete the language core: values, variables, lists, decisions, loops, and now named abstraction. Everything after this chapter is vocabulary — the built-in actions that touch the business world — and craft.