Helper manifest
A helper library is two things: source, which the host evaluates, and a manifest, which describes what is in it.
This page is the manifest’s reference. For what libraries are and how to write one, see Helper libraries.
Why it exists separately from the source
Section titled “Why it exists separately from the source”Because three things need to know what a library offers without running it:
- The formula editor, for autocomplete and signatures.
- The validator, to reject a call to a function that does not exist — at validation, rather than on row 300.
- The AI, which is told what helpers are available so it proposes expressions that will work.
Deriving that by parsing the source would be guesswork. Declaring it is a contract.
The practical consequence: a function missing from the manifest is invisible, even if the source exports it. Adding a function means adding it in both places.
The shape
Section titled “The shape”{ "namespace": "acme", "version": "1.2.0", "scope": "org", "description": "ACME-specific transforms.", "functions": [ { "name": "accountCode", "description": "The ACME account code for a customer name.", "params": [{ "name": "name", "type": "string" }], "returns": "string", "examples": [ { "call": "helpers.acme.accountCode(row.Customer)", "result": "AC-0042" } ], "tags": ["accounts"] } ]}Library fields
Section titled “Library fields”| Field | Required | Notes |
|---|---|---|
namespace |
✓ | Lower-case identifier. Becomes helpers.<namespace>.*. |
version |
✓ | Semver, 1.2.0. Exactly three numeric parts. |
scope |
✓ | org or global. Org routes only write org. |
description |
What the library is for. | |
functions |
✓ | The list below. |
Function fields
Section titled “Function fields”| Field | Required | Notes |
|---|---|---|
name |
✓ | An identifier. |
description |
✓ | One line. Read by people and by the model. |
params |
✓ | Each with name and type; optional and description allowed. |
returns |
✓ | A type, as a string. |
examples |
{ call, result } pairs. |
|
tags |
For grouping in the editor. |
Types are free-form strings, not a checked type system — string, number,
Record<string, unknown>. They document intent for a reader and for the model; they are not
enforced at run time.
Descriptions and examples earn their keep
Section titled “Descriptions and examples earn their keep”These are not decoration. The description is what somebody sees in autocomplete at the moment they are deciding whether this is the function they want, and it is what the model reads when proposing a formula.
A function described as “formats a code” will be misused. Described as “The ACME account code for a customer name — returns an empty string when the customer is unknown”, it will not.
Examples are the highest-value field after the description, because they show shape and edge cases in less space than prose:
"examples": [ { "call": "helpers.acme.accountCode('Northwind Traders')", "result": "AC-0042" }, { "call": "helpers.acme.accountCode('Unknown Ltd')", "result": "''" }]Namespacing
Section titled “Namespacing”Functions are called under their namespace:
helpers.acme.accountCode(row.Customer)The one exception is the built-in core library, which is also flattened onto helpers.* — so
helpers.trim(…) works as well as helpers.core.trim(…). Your own libraries are always
namespaced, which keeps them from colliding with each other or with a future built-in.
Versioning
Section titled “Versioning”The version is semver, and it is what a project pins.
Publishing a new version does not change what an existing project does. A project records the versions it was built against, so a change to a helper cannot silently alter an import that has been running for a year. Somebody updates the project deliberately.
That makes the version meaningful — so use it properly. A changed return shape is a major bump, whatever it looks like from inside the library.
Where it is validated
Section titled “Where it is validated”On write. The manifest is checked against the schema, its namespace must match the path it is
written to (NAMESPACE_MISMATCH otherwise), and an org route will not accept scope: "global"
(GLOBAL_LIBRARY) — a global library belongs to the product, not to an org.
A contract, hash-locked
Section titled “A contract, hash-locked”The manifest shape is one of Sloose’s versioned contracts, shared by the widget, the server, the SDK and every customer configuration repository. It does not change without a version bump, so a manifest written today keeps working.
Writing them
Section titled “Writing them”By hand, or as part of a configuration repository alongside the source — which is the better arrangement, because the manifest and the code it describes then change in the same commit and get reviewed together.