# Scripting in CoCoCo

Scripts add your own logic to CoCoCo: answer a webhook, prepare a report's data,
transform a pipeline's rows, reach a device from a workflow. They are written in
SwiftLua, a small and safe version of Lua. A script can reach only what CoCoCo gives
it, and every run has time and memory limits, so a mistake in a script stays inside
that script.

This manual has three parts:

- **The language.** *Getting started with SwiftLua* is a gentle introduction for
  anyone new to Lua; *The SwiftLua Language Guide* and *Extra libraries* are the
  full reference for the language and its libraries, such as `json`, `time` and
  `decimal`.
- **CoCoCo.** Which profile a script runs in, where scripts run and how their data
  arrives, and how to call CoCoCo; then a complete script for each kind, in
  *Workflows, webhooks and apps*, *Integrations* and *Pure scripts*; and the limits
  every run has.
- **The reference.** Every `ctx` function and object, with what it takes and returns.

## Profiles

Every script runs in one of three profiles. All three have the same language and
libraries. They differ in how much of CoCoCo a script can reach, through the global
`ctx`.

| Profile | What a script can reach | Used by |
|---|---|---|
| Normal | The language and every `ctx` function. | Playground and stored scripts, Workflow script nodes, Custom workflow actions, Incoming webhooks, Custom app server functions, Workspace handlers, MCP tools, Archive jobs, Quote price tuning |
| Integration | The language and the same `ctx` functions, narrowed to the integration: devices, templates and scripts only through the manifest's bindings; the cache, config, protobuf decoders and store belong to the instance; `ctx.integration` describes it. | Integration lifecycle hooks, Integration handler scripts, Integration server functions, Integration workflow actions, Integration upgrade scripts |
| Pure | The language only: no `ctx` and no modules. | Data pipeline stages, Report preparation scripts, Scheduler penalty functions, Product template resolvers, JDF and JMF templates |

Pure scripts run in the places where speed matters most, such as once per pipeline
row, so they have no `ctx` and cannot load other scripts. Using `ctx` in one is an
error when the script is checked:

```lua
-- A Pure script, such as a data pipeline stage, has no ctx.
local ok, result = ctx.graphql.query("{ __typename }", {})
return { ok = ok }
```

Everything a Pure script needs comes from the language itself. The `json` library,
for example, works in every profile:

```lua
-- json is one of the language's libraries, available in every profile. It
-- doesn't wait on anything, so it returns one value, with no ok flag.
local encoded = json.encode({ method = "POST", retries = 3 })

-- decode is its inverse. Invalid JSON raises a catchable error rather than
-- returning nil, so pcall it if the input is untrusted.
local decoded = json.decode(encoded)

return { encoded = encoded, retries = decoded.retries }
```