> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kayanos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Form builder context

> Understand the values, tree shortcuts, repeatable instances, and online/offline limits available to a KayanOS form expression.

## Use this page before writing a form expression

Every KayanOS form expression is evaluated in a context: the form, its submitted or in-progress values, the current item in the form tree, and selected session/member identifiers. The same expression can be valid in one field and empty or misleading in another because its context is different.

Use this reference for defaults, visibility, editability, validation, calculated values, action text, and other form-builder expressions. It describes values exposed by the form builder; it does not grant access, turn a visibility condition into authorization, or make a lookup safe for a public participant. For syntax and the full function catalog, use [Expression language syntax](/reference/expressions/language-syntax) and [Form expressions and lookups](/reference/expressions/forms-and-lookups).

![KayanOS form-builder context for a Citizen Service Request form.](https://kayanos.app/docs-images/en/reference/forms-form-builder-context.png)

## First identify where the expression runs

Before copying an expression, identify all four parts of its context:

| Question                        | Why it matters                                                                                                             |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Which item evaluates it?        | A field has `$value` and `$defaultValue`; an action, text block, or signature has different item properties.               |
| Is the item inside a repeater?  | `$index`, `$item`, parent/sibling relationships, and the stored value shape change.                                        |
| Is the form regular or offline? | Offline forms intentionally block several data-backed features and context-dependent functions.                            |
| Who is using the session?       | `currentUserType`, member/public identifiers, session ownership, and server policy affect what should be shown or allowed. |

The builder shows representative context shapes to help author an expression. Those shapes are not a production data preview and must not be used to infer that a field, selector result, or record is available to every participant at runtime.

## Form-level roots and identifiers

The shared context exposes these stable roots and identifiers:

| Name                            | Meaning                                                                                                                                                     | Example use                                                                          |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `$form`                         | The current form object: title, description, editable state, variables, and child structure.                                                                | Use when a rule truly depends on a form-level property.                              |
| `$`                             | Declared variables directly, plus exposed top-level form children. Each field entry is an exposed field object; read its submitted answer through `.value`. | `$.service_category.value == "regulated"`                                            |
| `organizationId`                | The active organization ID.                                                                                                                                 | Pass only where a released helper explicitly needs organization context.             |
| `formId` / `formVersionId`      | The form and the version supplying the current structure.                                                                                                   | Diagnose a version-specific behavior; do not display technical IDs to a public user. |
| `sessionId`                     | The current form-session identifier when one exists.                                                                                                        | Correlate a controlled support/test record.                                          |
| `initiatorId` / `initiatorType` | The session initiator and whether it is a member or public participant.                                                                                     | Adapt harmless wording, never decide authorization.                                  |
| `publicUserId`                  | The public participant identifier when available.                                                                                                           | Use only in an approved public-session design.                                       |
| `referenceNumber`               | The session's exposed reference number when available.                                                                                                      | Display a receipt-style reference after a reviewed submission.                       |
| `$form.submissionNumber`        | The same human-facing submission number, such as `RC-023`, exposed explicitly on the form object.                                                           | `"Submission " + $form.submissionNumber`                                             |
| `sessionInScopes`               | Scope tokens attached to the session.                                                                                                                       | Diagnose context; do not rely on an expression to enforce a scope rule.              |
| `currentMemberId`               | Current signed-in member identifier when applicable.                                                                                                        | Use only where a released expression/helper contract permits it.                     |
| `currentUserType`               | `member`, `public`, or no value.                                                                                                                            | Offer a safe presentation difference between public and member experiences.          |

Use `$form.submissionNumber` when the expression should name the public-facing
submission number explicitly. It is not the internal `sessionId`, and there is
no root `submissionNumber` alias.

`$` is not a magic database root. It begins with form variables and includes top-level form children that are exposed into the shared context. Variables are values, but a field key resolves to its exposed field object—use `.value` to read the stored answer. A nested repeatable value should be accessed through its local item/parent context rather than assumed to be a top-level value.

```jexl theme={null}
$.service_category.value == "regulated" && currentUserType == "member"
```

This can show a short internal reminder to a member. It must not authorize a regulated decision or expose data to a public participant.

## The current item and tree shortcuts

Each item has a location in the form tree. KayanOS gives an item local shortcuts so an expression does not need a fragile path across the entire form.

| Shortcut                | Available from               | Meaning                                                                                           |
| ----------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------- |
| `$this`                 | Current item context         | The item evaluating the expression. Use it only when the selected expression surface exposes it.  |
| `$parent`               | A child item                 | The direct parent section or repeater instance.                                                   |
| `$siblings`             | An item with siblings        | Nearby child items of the same parent.                                                            |
| `$grandparent`          | Nested item                  | The parent of `$parent`.                                                                          |
| `$uncles`               | Nested item                  | The children belonging to `$grandparent`; useful only when the structure is intentionally stable. |
| `$repeatables`          | Inside one or more repeaters | Repeater containers found while walking upward from the item.                                     |
| `$repeatable_instances` | Inside a repeater instance   | The current instance for each enclosing repeater.                                                 |
| `$index`                | Inside a repeater            | Current instance position; treat it as a display/indexing value, not a business identifier.       |
| `$item`                 | Inside a loop-mode repeater  | The loop source item. It is not provided merely because a user-controlled repeater exists.        |
| `$value`                | Field context                | Current field value.                                                                              |
| `$defaultValue`         | Field context                | The configured default before or alongside user input.                                            |

Use a sibling value for a local condition. This is clearer and safer than relying on a long, brittle path.

```jexl theme={null}
$siblings.requires_inspection.value == true
```

If `requires_inspection` can be absent, handle that outcome deliberately instead of treating an error/empty value as approval.

```jexl theme={null}
($siblings.requires_inspection.value || false) == true
```

The builder also maintains item paths such as child and repeater-instance paths to construct context and autocomplete. Treat these paths as builder navigation aids, not as a public integration contract or a substitute for a field key.

## Values by field type

The expression editor provides representative shapes so a builder can see how an item is expected to behave. The actual saved value still depends on the field configuration and user input.

| Field family           | Typical expression value shape                                                            | Careful use                                                                                       |
| ---------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Text, textarea         | Text                                                                                      | Trim/validate only when the service rule requires it; an empty value is common.                   |
| Number                 | Number                                                                                    | Check for missing/non-numeric input before calculation.                                           |
| Boolean                | `true` or `false`                                                                         | Prefer an explicit comparison where a missing value has a different meaning.                      |
| Date, date-time, time  | Date/time value                                                                           | Use date helpers and test timezone/display behavior.                                              |
| Money                  | Numeric amount plus the configured `currency`                                             | Do not assume currency conversion; compare or calculate only within a reviewed currency contract. |
| Select                 | One option value, or an array for multi-select                                            | Compare stored option values, not only visible labels.                                            |
| Rich text              | Rich-text value                                                                           | Do not treat it as trusted plain text for a public output.                                        |
| File                   | File metadata such as storage key, name, original name, size, and type                    | Never expose file metadata or a file link to an unauthorized participant through an expression.   |
| Entity selection       | Selected identifier plus a representative record shape in the builder                     | Availability depends on the configured source and runtime permissions.                            |
| Form-session selection | One record or an array; selected-session `saved_state` may be shaped from the source form | Guard missing source sessions and do not rely on this in offline forms.                           |
| Calculated value       | A derived value surface                                                                   | Keep the calculation deterministic and avoid using it as an authorization decision.               |

For a multi-select field, test the actual array behavior rather than copying a single-select equality check:

```jexl theme={null}
contains($.requested_services.value, "inspection")
```

Only use a function when it is listed for the form context. The expression editor may display a general helper that the offline validator or runtime blocks.

## Exposed item objects and nested arrays

Autocomplete mirrors the public form objects used by expressions. Every item exposes `key`, `path`, and a category discriminator in `type` (for example, `field` or `section`); fields also expose their concrete input kind in `fieldType`, plus `title`, `tooltip`, `value`, `defaultValue`, `editable`, `required`, `validation`, `isValid`, and `index`. Selectors add `selectionType`, `options`, and either `record` or `records`. Money fields add `currency`, and file fields add `multiple`, `accept`, and `maxSizeBytes`.

Sections expose `title`, `description`, `editable`, `children`, `index`, and `isValid`. Repeaters expose `repeaterTitle`, `minRepeat`, `maxRepeat`, `requestedRepeat`, `actualRepeat`, `instances`, `repeatType`, and `isValid`; section repeaters also expose `layoutMode`, `tableResponsiveMode`, and `tableColumns`. Actions expose `title`, `description`, `clickable`, `loading`, `actionType`, `isValid`, and `calls`. Action-type-specific properties such as `linkTarget` and `docxFieldKey` appear only when that action supports them.

Array suggestions use one representative element so that typing after an array mapper such as `.signatures[.` or `.instances[.` can reveal its properties. This sample element is autocomplete metadata, not proof that the live array is non-empty.

### Signature object

A signature item exposes the current and superseded signing state:

| Property                                                          | Shape and meaning                                                                                                      |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `ready`, `activeRequestId`, `revision`, `snapshotHash`, `isValid` | Current preparation/readiness metadata. `activeRequestId` can be absent at runtime.                                    |
| `snapshotProof`                                                   | Proof metadata: `fileUrl`, `fileName`, `fileType`, `fileSizeBytes`, and `sha256`; it can be null before proof exists.  |
| `snapshotItems`                                                   | Scoped snapshot items with `key`, `type`, `title`, optional `description`, optional `value`, and recursive `children`. |
| `signatures`, `staleSignatures`                                   | Arrays of signature summaries. Current arrays can be empty; stale summaries represent superseded requests.             |

Each signature summary exposes `id`, `requestId`, `ruleKey`, `memberId`, `resolution`, `status`, `notes`, `reason`, `signingCapacity`, `signedAt`, `symbolicSignature`, `symbolicSignatureHash`, and `stale`. Treat `signingCapacity` and `symbolicSignature` as evidence payloads whose internal structure can evolve; do not write policy rules against undocumented nested fields.

```jexl theme={null}
$.approval_signature.signatures[.status == "completed" && .resolution == "approve"]
```

An empty result means no matching current signature. It does not mean that a stale signature is current, that prerequisites were satisfied, or that the participant is authorized to approve.

## Repeatables: context changes per instance

Use a repeater when the Citizen Service Request needs a variable number of observations, documents, or inspection rows. Each instance has its own local values. A rule inside an observation row should use that row’s value/siblings, not a request-wide value that happens to share a label.

### User-controlled repeaters

In a user-controlled repeater, a member or participant adds/removes instances within the configured bounds. `$index` identifies the current instance position for wording such as “Observation 2”; it is not a stable record ID and can change if rows are reordered or removed.

```jexl theme={null}
"Observation " + ($index + 1)
```

Validate the actual values in every instance. A repeat count alone must never decide whether a request is eligible for approval.

### Loop-mode repeaters

In a loop-mode repeater, `$item` is available for the source item and `$index` is its position. Use a reviewed fallback for an optional property.

```jexl theme={null}
"Inspection " + ($index + 1) + ": " + ($item.site_name || "site not supplied")
```

Test the first item, a later item, an empty source item, and no source items. Do not assume `$item` exists in a user-controlled repeater.

### A simple local rule

For a repeatable observation, make the note required only when the current row is marked unsafe:

```jexl theme={null}
$siblings.safety_status.value == "unsafe"
```

Then test safe, unsafe, missing, first-row, later-row, and newly added-row cases. A visibility or required expression changes the form experience; the server-side workflow still owns the final transition/approval decision.

## Regular versus offline forms

Offline forms are a constrained form type, not regular forms delayed until connectivity returns. The form builder disables actions, variables, entity-selection fields, form-session-selection fields, entity-backed option sources, public links, and prefilled links for offline structures. It also blocks data/permission-dependent expression functions.

For an offline inspection form, keep expressions local and deterministic:

```jexl theme={null}
$.requires_inspection.value == true && isNotEmpty($.site_address.value)
```

Do not use form lookups, permission helpers, or a selected entity/session as the condition that makes an offline submission valid. See [Offline forms](/build/offline-forms) for package, local-file, and synchronization behavior, and [Form expressions and lookups](/reference/expressions/forms-and-lookups) for blocked lookup/permission functions.

## Route a session to a role at an entity

A dynamic role scope is a form-level routing item. It resolves a role and an entity when a regular form session is saved. Configure the role and routing separately. For example:

* **Role key:** `printing_manager`
* **Scope Type:** `locations`
* **Routing Code:** `$.location.value`

The entity returned by Routing Code must belong to Scope Type. The code can use other form fields and may return one qualified entity reference, an array of references, or `null`. Existing forms that use `roleScope(roleKey, entityId)` continue to run, but new routing items do not require that helper.

* `null` means “no route” and is valid.
* A non-null route whose role or entity does not exist, belongs to another organization, or does not match Scope Type blocks the save.
* Routing attaches the session to a role at an entity; it does not grant List, Open, Update, Delete, or action verbs.
* An empty role still receives the routed backlog. No session or member record is rewritten when a member is assigned to that role later.
* Builder preview is diagnostic only. The server resolves and validates the route again before persisting it.
* Offline forms do not support dynamic role scopes.

In role permissions, each enabled form verb uses one binding mode. **Entity scope** grants that verb for sessions of the form at the selected entity scope. **Role at entity** grants it only for sessions of that form routed to this role at that entity. When a form supports both modes, select the intended mode per verb; the modes are not combined.

## Build and test a context-dependent rule

Use this small, repeatable test protocol:

1. State the decision in plain language: “Show the inspection details when `requires_inspection` is true in this request.”
2. Put the rule on the field/section that owns the decision, not a distant item.
3. Use the smallest local root or sibling reference that expresses it.
4. Test member and public sessions if the form supports both; confirm they see only the intended harmless difference.
5. Test absent/null, false, true, first/later repeater instance, and a saved/reopened session.
6. Test the corresponding server action or submission. Verify an unauthorized actor remains denied even if they can force a client-side value.
7. For offline forms, run the offline validator and test a real synchronized submission before publishing.

## Common mistakes

| Mistake                                             | Why it fails                                             | Better approach                                                                       |
| --------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Copying a template or serial expression into a form | Roots and helper availability differ by context.         | Start with the form context and link to the context-specific helper page.             |
| Using `$item` in a non-loop repeater                | `$item` is supplied only for loop-mode repeater context. | Use the current field/sibling/instance context, or redesign the repeater.             |
| Treating `$index` as a permanent identifier         | It is a position, not a stable record key.               | Store/use an approved business identifier where needed.                               |
| Hiding a field to protect data                      | Client visibility is not access control.                 | Enforce the rule in server-side permissions and avoid exposing sensitive lookup data. |
| Relying on an online function offline               | The offline structure/validator intentionally blocks it. | Use local values and deterministic helpers, or make the form regular.                 |
| Assuming a builder sample shape is live data        | Autocomplete shapes are representative.                  | Test a real controlled session with actual configured field values.                   |

## Related guides

* [Expression language syntax](/reference/expressions/language-syntax)
* [Form expressions and lookups](/reference/expressions/forms-and-lookups)
* [Form helpers and lookup filters](/reference/expressions/helpers/forms)
* [Forms, fields, and repeatables](/build/form-fields-and-repeatables)
* [Offline forms](/build/offline-forms)
* [Permissions and availability](/reference/permissions-and-availability)
