Skip to main content
After this guide, every incoming message passes through your code before the model reads it, and every reply passes through your code before the end user sees it. Use a processor for a rule that must hold in every conversation; for a decision the model should make, write a tool. Verified against lua-cli 3.33.0. Before you begin
1

Write a preprocessor

execute receives the end user, the message as an array of parts, and the channel. Return { action: 'proceed' }, optionally with modifiedMessage for the model to read instead, or { action: 'block', response } to end the turn with response as the reply. Lower priority runs first; the default is 100. channel is the inbound name from channels: pop for the web widget (the type lists it as web, so compare against both), whatsapp, facebook for Messenger, email, sms; lua chat sends dev. These differ from the Channels.send names (webchat, messenger).
src/preprocessors/PiiGuard.ts
2

Write a postprocessor

execute receives the end user, the original message, the model’s reply, and the channel, and must return { modifiedResponse }; that text replaces the reply.
src/postprocessors/WhatsAppFooter.ts
3

Register both on the agent

Only processors referenced from LuaAgent are compiled.
src/index.ts
4

Test them locally

lua test runs one processor on your machine with the input you give it; no model is involved.
Output
Output
To see both in a real conversation before releasing, use lua chat -e sandbox -m "reach me at [email protected]": sandbox chat uploads your processors as sandbox versions and runs them on the platform, with no push.
5

Release them

lua push uploads a version and changes nothing for end users; lua version create snapshots the agent; lua version promote <n> makes that snapshot live and is also the rollback path (Release an agent to production).
lua version create prints ✓ Created v<n> (staged); in a script, n=$(lua version list --limit 1 --json --ci | jq -r '.[0].version') then lua version promote "$n". lua push all exits 0 even when a primitive fails; check its output for component(s) failed to push.
From the promote on, both processors run on every message and reply in production, on every channel. A preprocessor that throws is skipped on text channels but blocks the turn on a voice call.
6

Verify

Send a message the guard should block, then read the log.
The reply is the guard’s response, word for word, and the log shows the blocked turn. lua logs --type postprocessor --limit 5 shows the footer being applied to WhatsApp replies.

Options you may need

Order several processors

Active processors of each kind run in ascending priority, each receiving the previous one’s output. Two processors with the same priority run in the order the database returns them, which you cannot set, so give each a distinct number.

Deploy one processor on its own

lua deploy preprocessor and lua deploy postprocessor are single-primitive shortcuts: each creates and promotes an agent version scoped to that processor, so it goes live immediately and appears in lua version list.

Block silently

response on a block is what the end user sees, and an empty string is honored differently per client: the legacy stream shows nothing, the widget shows the default text User not eligible for agent response, and a non-streaming chat call returns preprocessor_blocked with empty text. Set response whenever the end user should know why.

If it isn’t working

To turn a processor off in production without a rollback, run lua preprocessors deactivate --preprocessor-name pii-guard --ci (or lua postprocessors deactivate --postprocessor-name whatsapp-footer --ci); activate turns it back on.
Cause lua test only sees processors registered on LuaAgent.preProcessors or postProcessors. Fix Import the processor in src/index.ts, add it to the right array, and run the test again.
Cause The preprocessor threw or timed out, so the platform skipped it and continued; or another preprocessor with a lower priority blocked or replaced the message first. Fix Read lua logs --type preprocessor --limit 5 for the error, and compare the priority values of your preprocessors in code.

Next steps

About processors

Order, failure handling, streaming, and processors versus skills.

PreProcessor reference

Config fields and the result shape.

PostProcessor reference

Config fields and the response shape.

Add human handoff

A blocking preprocessor driven by a flag on the end user.