lua test, workflow drivers, voice tests) see Test an agent before you release.
Verified against lua-cli 3.33.0. --since, --until, --environment, and --follow ship with log drains in lua-cli 3.38.0; on an earlier CLI they are unknown options.
Before you begin
- A project signed in with
lua auth configure;lua logsreads the agent inlua.skill.yaml(--agent-id <id>overrides it for another agent you administer). - Something to inspect: a conversation, a job run, a webhook call, or a workflow run that already happened.
1
Reproduce on an isolated thread
Send the smallest message that triggers the code path, on a fresh thread so earlier turns cannot influence the answer. The sandbox runs sandbox versions compiled from your local code; production runs the promoted version.When the bug is in one function rather than in the modelβs decision, skip the conversation and call the function with
lua test skill --name <tool-name> --input '<json>'; its output is exactly what the tool returned, with no log lookup needed.2
Read the entries that run wrote
Filter by primitive type and, for skills, jobs, webhooks, processors, and devices, by name. Entries print oldest first.Each tool call writes
Output
Calling tool with input β¦, then Execute function completed in <n> ms and Tool result β¦, or an ERROR entry with the thrown message. Anything your code prints with console.log appears as a DEBUG entry and console.error as an ERROR entry, so log the raw return value of a platform call before you transform it and read its real shape here. When you want to filter on a value rather than read it, log.info(message, fields) writes the same entry with the fields beside the message, where --json shows them under metadata.fields. A message field is stored up to 256 KB and then cut with [truncated; original length <n>].3
Widen or narrow the filter
--type accepts all, calls, and all eighteen log sources: skill, job, webhook, trigger, preprocessor, postprocessor, device, device-trigger, user_message, agent_response, agent_error, mcp, rag, runtime, model-resolver, workflow, workflow-step, and workflow-script. --name works with skill, job, webhook, preprocessor, postprocessor, and device. agent_error holds failures on the message path such as billing, validation, and model errors; runtime holds the agent runtimeβs own lines; model-resolver says which model a turn resolved to; user_message and agent_response show what was said, with the channel and end user ID.--limit defaults to 20 and the server caps it at 100. --since and --until bound the window β an ISO 8601 instant, or a relative 15m, 2h, 7d β and --environment production|sandbox picks one environment, since entries from both are stored together. --follow keeps the command open and prints new entries as they are written. The flag table is on the lua logs reference.4
Script it with --json
--json returns { logs, nextCursor, pagination }. Each entry carries subType (error, warn, info, debug, start, or complete; there is no level field), message, an optional duration in milliseconds, and metadata with logSource, primitiveName, primitiveId, toolName, userId, channel, environment, agentVersion, and executionId. Page with nextCursor rather than --page: above 10,000 matches pagination.totalCount is capped at 10000 and the boolean pagination.totalCountExact is false. hasNextPage is reliable either way.Output
jq '.logs[] | select(.subType == "error")'.5
Debug the CLI itself
When a command fails, it prints one line, The exit code tells you the class of failure before you read the message; see Errors and exit codes.
β <code>: <message>, plus a π‘ hint. Set LUA_DEBUG=1 (or pass --debug to lua compile) to print the stack trace under that line.6
Verify a deploy
After
lua version promote or a release, send one production message on a fresh thread and confirm that nothing was written since under agent_error or as an error under skill. A throwing tool lands under skill, not agent_error, so the check reads both types; --since and --environment bound it to the window and the environment you just changed.jq -e exits 1 when the filtered array is not empty, which is what a CI job needs; see Automate releases in CI.Options you may need
Read trigger, job, workflow, and call records
Some primitives keep their own execution records in addition tolua logs:
lua triggers logs shows up to 200 executions; lua jobs history shows the last 20 with status, duration, result, and error; lua workflows status --steps prints per-step state and output previews, lua workflows logs the runβs event stream (--follow keeps it open), and job-logs the container output of a Job-tier step. See the lua triggers, lua jobs, and lua workflows references.
Ship the same records to your own stack
lua logs is the platformβs own copy. A log drain copies the same records to a destination you own β your own HTTPS receiver, an OpenTelemetry collector, Datadog, or Better Stack β as they happen, so alerting and long-term search live where the rest of your telemetry does. It is a copy, not a move: everything a drain sends is still readable here.
Scopes for reading logs
lua logs works with any credential that can administer the agent. Over REST, reading logs needs logs:read and configuring drains needs logs:manage, which is a sensitive scope that a wildcard grant does not satisfy. The scope each log route used before is still accepted for two releases β knowledge:read on an agentβs logs, automations:read on a skillβs logs, analytics:read on the organizationβs logs and their CSV export β and a request authorized by one of those answers with Deprecation: true and a Sunset date. See Log drains REST.
How long entries are kept
Execution logs are kept for 90 days by default, then deleted. Anything you need beyond that window belongs in a drain β or in a scheduled export of your own built onlua logs --since/--until --json. See Security and data.
Keep secrets out of the logs
The runtimeβs own entries (runtime, workflow events, device command audits) redact bearer tokens, JWTs, and token=, api_key=, secret=, and password= values, and device command payload fields such as content and password are replaced with byte counts. Your own console.log output is stored as printed: do not log env('β¦') values or request headers. Local lua test runs write no server entries at all.
If it isnβt working
β usage: --type is required when using --name
β usage: --type is required when using --name
--name filters an entity list, so the CLI needs to know which list. Pass --type skill|job|webhook|preprocessor|postprocessor|device with it; message types (user_message, agent_response, agent_error, runtime, mcp, rag) have no names.β usage: lua: "mastra" is not a valid logs.type value.
β usage: lua: "mastra" is not a valid logs.type value.
The hint lists the accepted values.
--type all shows everything; runtime is the type for agent runtime and model-provider lines.β not_found: Skill "<name>" not found
β not_found: Skill "<name>" not found
Exit 3.
--name takes the primitiveβs name as it appears on the server (lua skills view, lua jobs view, lua webhooks view), or its ID. For a skill it is the skill name, not a tool name.Next steps
lua logs reference
Every filter and the entry schema.
Test an agent before you release
Reproduce with exact input before reading logs.
Troubleshoot the CLI
Exact error strings by stage, with fixes.
About security and data
Where logs live, what is redacted, and how long entries are kept.
Ship logs to your stack
Copy these records to Datadog, OTLP, or your own receiver.
lua drains
Create, verify, and watch a drain.

