Skip to main content
After this guide, your tools store records in an agent-scoped collection, read them back by exact filter, and find them by meaning. Data holds many records per agent; for one record per end user, write to the end user’s record instead (Identify users). Verified against lua-cli 3.33.0. Before you begin
  • A skill on the agent to hold the tools (Add a tool to a skill).
  • A test collection name. Collections are shared by the sandbox and production (About environments), so a local run writes the same data the live agent reads.
1

Store an entry with search text

Data.create takes the collection, the object to store, and an optional string that is embedded for semantic search. Put every term a question might use into that string: it is stored beside data as the entry’s searchText and is the only text search() matches against.
src/skills/tools/AddKnownIssueTool.ts
The returned entry exposes the stored fields directly (entry.product) and through entry.data. Store searchText as a plain string in deployed code; the options object is covered under Options you may need.
2

Find entries by meaning

Data.search embeds the query and returns the closest entries as a flat array, best match first, each with a score from 0 to 1. limit is at most 20 and scoreThreshold defaults to 0.6.
src/skills/tools/FindKnownIssueTool.ts
Raise the threshold when unrelated entries come back, lower it when good ones are missing; 0.7 is a sensible start for support text.
3

Filter entries exactly

Data.get takes a Lua Query filter over the stored fields and returns one page as { data, pagination }. Entries here are plain objects, so read fields through entry.data. Pages hold at most 100 entries.
src/skills/tools/ListOpenIssuesTool.ts
A bare value means equality; $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, and $exists are the field operators, and $and and $or combine clauses at the root.
4

Update and delete

Data.update merges the fields you pass into the entry and keeps the rest; pass a replacement string as the fourth argument to re-index it. Data.delete removes one entry by id.
src/skills/tools/ResolveKnownIssueTool.ts
A delete is permanent; there is no recycle bin.
5

Register the tools in a skill

The skill’s context says who may add and resolve issues; only tools in a skill on LuaAgent.skills are compiled.
src/skills/known-issues.skill.ts
The agent file below is the quickstart’s; if yours differs, add only the highlighted lines to your own LuaAgent.
src/index.ts
6

Verify

Store an entry, then search for it with different words. Both runs hit the real collection.
Output
The query shares no word with the stored title, and the match still scores above 0.7. Clean up with resolve_known_issue and "remove": true.
7

Release

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). Run `lua version promote v<n>` to deploy.; <n> comes from that line, promote accepts <n> or v<n> and asks no confirmation, and in a script n=$(lua version list --limit 1 --json --ci | jq -r '.[0].version') reads it.

Options you may need

Declare an index for filtered fields

When a collection grows large, a filter on a field without an index slows down and eventually fails with an error naming the field. The third argument of create() and fourth of update() also accept { searchText, index: ['product'] }; a nested pair such as [['product', 'status']] declares a compound index. At most 2 fields per index, 3 declarations per call, and 5 indexes per agent; an index is dropped 14 days after its last declaration or filtered read.
Local runs only. The deployed runtime doesn’t accept the options object yet and fails with searchText must be a string. In deployed code, pass searchText as a plain string.

Read one entry by id

Data.getEntry('known-issues', id) returns the entry with direct field access and throws when no entry has that id; entry.save() writes back fields you assigned on it.

If it isn’t working

Only searchText is embedded, not data. Include the fields you expect people to search by, and re-index existing entries with Data.update(collection, id, {}, newSearchText).
get() returns plain entries: read entry.data.title. search(), create(), and getEntry() return instances with direct access.
The filter used an operator or a depth outside the grammar. The codes and limits are on the Lua Query page.

Next steps

Data reference

Every method, return shape, limit, and error.

Lua Query

The full filter grammar and its limits.

Identify users

One record per end user, and keeping accounts apart.

Add knowledge

For documents the agent should answer from, use knowledge instead.