MEMORY:manages session and persistent state.CONSTRAINTS:enforces business rules.
MEMORY
Memory in ABL defines how an agent stores, retrieves, and persists information across conversation turns, sessions, and users. TheMEMORY: block declares four categories: session variables, persistent variables, remember triggers, and recall instructions.
Overview
Every agent has access to a memory configuration that controls data lifecycle:- Session variables exist for the duration of a single conversation session.
- Persistent variables survive across sessions, scoped to a user or project.
- Remember triggers automatically store values when conditions are met.
- Recall instructions load stored facts at specific lifecycle events.
Session variables
Session variables hold data that is relevant only during a single conversation. They are created when the session starts and discarded when the session ends (unlessRESET: never is specified).
Syntax
Properties
Reset behavior
Example: typed session variables
Write authority
A session variable can declareREADONLY: true so the model cannot write it, leaving an authored hook SET (or on_result, or a FLOW SET) to compute its value:
In YAML the same key is lowercase:
readonly: true.
MATCH_SCORE(said, stored, kind?) returns 0-100 (or -1 when there’s nothing to judge — a missing value, a PII vault token, or an input over 1,024 characters; -1 is below every threshold, so a rule written as MATCH_SCORE(...) >= 70 fails closed). MATCHES(said, stored, kind?) is the pass/fail form on the platform’s own match bands, and MATCH_RESULT(said, stored, kind?) returns "match", "retry", "mismatch", or "missing". These are a said-versus-stored identity comparison, not a regex test — the infix a MATCHES "pattern" operator is the regex form. kind is optional (default text); pass "auto" to detect the kind from the stored value’s shape, or "exact" to turn off every voice allowance and require equality after normalization. See Built-in function reference for the full signatures, kind values, and match bands.Model writers
In a multi-agent project, several agents can share one session field — routing state, a verification result — and by default any agent’s model can write it.MODEL_WRITERS names exactly which agents’ models may:
The YAML key is
model_writers. Names are case-sensitive agent names; every explicit declaration of the same shared field across the project must agree, and a conflicting pair fails closed (denied for everyone) rather than picking one. A full-project compile rejects a name that isn’t a real agent in the project (SESSION_MODEL_WRITER_UNKNOWN); compiling a single agent in isolation defers that specific check. An invalid list (not an array of plain agent-name strings) is rejected at parse/compile time (MEMORY_MODEL_WRITERS_INVALID, SESSION_MODEL_WRITERS_INVALID) — the field is not left silently unprotected on invalid input.
Authored proof, in brief. Once a project declares any
MODEL_WRITERS, a value arriving at a protected field through a HANDOFF/DELEGATE return MAP/SET must be traceable to something the platform itself produced — an executed tool result, or a value a hook/on_result/ON_START/ESCALATE action set directly. A value that is merely model-written (even copied through an ordinary SET), or sourced from raw caller input, secure-input collection, or a confirmation/inference step, does not count as proof — even if it’s byte-identical to a previously proven value. A return assignment that can’t establish this is skipped (the field keeps its prior value) and the runtime traces RETURN_MODEL_WRITER_UNTRUSTED_SOURCE. Prefer a static return MAP/SET path (a literal tool-result field) over a dynamic/computed expression when the source needs to flow into a writer-protected field — an expression the runtime can’t statically resolve is treated conservatively and may be refused even when the underlying value is genuinely trustworthy.Model-visible session and persistent values
A session or persistent entry can opt out of automatic model context withMODEL_VISIBLE: false (YAML: model_visible: false). Omitted or true preserves the existing automatic projection. The value stays fully available to deterministic expressions, conditions, tools, mappings, persistence, and recall — this is a placement control over what the model sees automatically, not a write-authority or access-scope change:
{{catalog_mapping}} can still place the value at the intended prompt location, subject to the usual access and sensitive-value rules — MODEL_VISIBLE: false is not a guarantee the value can never reach a model, only that it isn’t included automatically. Deterministic rule evaluation and ML extraction always see the real value regardless of this setting. An excluded ancestor path excludes its descendants, even one marked true. The excluded path must be a literal, dot-separated path — numeric array positions are supported, but a wildcard, a bracket selector, an empty segment, or a __proto__/prototype/constructor segment is rejected (MEMORY_MODEL_VISIBLE_PATH_UNSUPPORTED) rather than silently left visible.
Each consuming agent’s own memory declaration governs its automatic context.
MODEL_VISIBLE requires matching authoring, parser/compiler, and Runtime versions deployed together — an older Runtime does not enforce it.Persistent variables
Persistent variables survive across sessions. They are stored in a fact store and scoped to either a specific user or to the entire project.Syntax
user.* or project.*), but you can override this with the SCOPE property.
Properties
Scoping rules
- User scope (
SCOPE: user): Values are unique per authenticated user. Two users in the same project see different values for the same path. - Project scope (
SCOPE: project): Values are shared across all users within the project. Useful for reference data, feature flags, or global configuration. - Execution-tree scope (
SCOPE: execution_tree): Values are shared across one handoff tree / long-running execution — visible to the agents participating in that orchestration but not persisted per-user or per-project.
As shorthand, a
READS: sub-block declares persistent paths with ACCESS: read, and a WRITES: sub-block declares them with ACCESS: write — an alternative to listing each path under persistent: with an explicit ACCESS.Remember triggers
Remember triggers define rules for automatically storing values into persistent memory when a condition is met during conversation.Syntax
STORE:
value -> target
arrow form always uses overwrite. append, unique, and maxSize apply to
array-typed targets in user, project, and execution_tree scopes.
Properties
TTL format
TTL values use a duration string:
Example:
"90d" means the stored fact expires 90 days after it was written.
Recall instructions
Recall instructions define when and how to load persistent facts back into the session context. They execute at specific lifecycle events.Syntax
Properties
Recall events
ON: accepts these canonical lifecycle event patterns:
Recall actions
Accessing memory in expressions
Session variables are accessed by name in expressions and template strings:SET assignments in flow steps, ON_START, or hooks are written to session memory and available for the remainder of the session.
CONSTRAINTS
Constraints are deterministic business rules that the runtime evaluates against the current session state. Authors can still group constraints under named phases for readability, but phase names are currently labels only: the compiler flattens constraints into a single runtime list unless a constraint explicitly gates itself withWHEN or a structural checkpoint construct.
Overview
Constraints enforce guardrails on agent behavior that are separate from LLM instructions. They are deterministic checks evaluated by the runtime, not suggestions to the model. A constraint that fails blocks the current operation and triggers anON_FAIL action.
Phases
Named phases are retained as authoring labels for readability, review, and organization. They do not currently create separate runtime execution phases by themselves.Syntax
always, pre_booking, or eligibility_check when they help readers understand intent, but use WHEN to gate applicability and BEFORE only for explicit structural checkpoint targets.
Requirement rules
Each requirement within a phase uses one of three keywords:REQUIRE, LIMIT, or RESTRICT.
REQUIRE
The most common form. Asserts that a condition must be true. If the condition evaluates to false, theON_FAIL action is triggered.
LIMIT
Expresses a numeric boundary. Semantically equivalent toREQUIRE with a comparison, but communicates intent more clearly.
RESTRICT
Expresses a prohibition. The condition describes what is forbidden; when it evaluates to true, the constraint fails.WHEN
UseWHEN: to make a constraint apply only in a specific context without overloading the phase label.
BEFORE
UseBEFORE for structural checkpoints that the runtime knows how to activate.
BEFORE calling <tool_name>BEFORE returning results
BEFORE targets are retained for compatibility, but they are warning-only and have no runtime effect. Prefer IMPLIES or WHEN for that form.
A
BEFORE calling <tool_name> rule’s condition (REQUIRE/LIMIT/RESTRICT) or WHEN can read the about-to-be-sent arguments via tool_args, but only when the agent sets EXECUTION: guardrail_builtins: true. Without it, tool_args is unbound: the rule cannot read the arguments, so it never holds, and the tool call is refused. The compiler warns GUARDRAIL_BUILTIN_NOT_BOUND for this case.IMPLIES
IMPLIES is an inline condition operator (not a top-level keyword) for expressing conditional requirements. A IMPLIES B is lowered to NOT (A) OR (B) — that is, “if A holds, then B must also hold.” Use it inside the condition of a REQUIRE/LIMIT/RESTRICT rule:
ON_FAIL actions
ON_FAIL accepts a single-line action — a message string, HANDOFF <Agent>, or ESCALATE — or a structured block. The block form can respond, reset state, and route in one place:
The
CLEAR key lets an ON_FAIL block reset dependent state directly — you no longer need a separate CLEAR-only step solely to clear variables before a retry.An
ON_FAIL RESPOND message may use {{_abl_constraint_fail_count}} — this failure’s 1-based ordinal for the constraint within the current conversation. Pair it with MAX_REPEATS/ON_EXHAUSTED to vary the message as attempts run out, then hand off once the cap is reached:Constraint properties
ON_FAIL actions
TheON_FAIL value determines what happens when a constraint fails.
String message (respond)
The most common form. Sends a message to the user and halts the current operation.HANDOFF
Transfers control to another agent. Active flow and reasoning runtime checkpoints execute the handoff immediately when the constraint fails.ESCALATE
Triggers human escalation.Block
Silently blocks the operation without a user-facing message.Structured ON_FAIL block
For more control, use a structured block that combines multiple actions.Structured ON_FAIL properties
Collect and retry example
GOTO example
Severity levels
Constraint evaluation order
- Constraint phase names such as
alwaysorpre_bookingare labels only; the compiler flattens all constraints into one runtime list. WHENgates a constraint to a specific context, and structuralBEFOREgates it to supported checkpoints such as tool calls or final responses.- Inline flow-step
CHECKexpressions are separate fromCONSTRAINTSand evaluate directly againststep.check. - Declaration order is preserved in the flattened list.
- Evaluation stops at the first
error-severity failure. Warnings do not halt evaluation.
Template interpolation in messages
ON_FAIL message strings support {{variable}} interpolation using the current session context:
Related articles:
- Guardrails — input/output safety checks (distinct from business rule constraints)
- Expressions and functions — condition expression syntax
- Multi-Agent and Supervisor — HANDOFF and ESCALATE actions referenced in ON_FAIL
- Lifecycle and hooks —
ON_STARThandler where initial memory setup occurs - Data types — type definitions used in
TYPEdeclarations