template: section of lua.skill.yaml that you author, frozen at publish together with the source agent’s promoted version, and served to installers as a display-only projection. This page lists every field of the authored section and the served manifest, and summarizes the install result. The lints that guard the fields are on Lints and consent.
Verified against lua-cli 3.33.0.
Sections
lua marketplace template draft writes the section and publish sends it. Whenever the section exists, all seven authored sections are sent on every publish, and an absent or empty section clears the server’s copy. The env contract is not in the file: declare it with --env-contract "KEY=description" (KEY?= for optional) on publish; omitting the flag keeps the previous version’s contract.
The frozen primitives (skills, webhooks, jobs, preprocessors, postprocessors, triggers, workflows, model) are never authored here.
connections[]
One entry per capability the agent plugs into, satisfiable by any platform in its list. Connections the installer already holds are reused; only gaps are requested.string
required
Stable identity of the capability. Non-empty and unique; renaming it is remove-plus-add for installers.
string
required
Discovery label, for example
crm. platforms decides what satisfies it.boolean
required
true blocks the install until satisfied. false is offered and never blocks; primitives bound to a declined connection are installed inert.'user' | 'org'
Which grant may satisfy it. Omit to accept either.
string
required
Label of the connect prompt. Non-empty.
string
required
Why the agent needs it. Non-empty.
array
required
At least one
{ type, oauthScopes? }. type is an integration type such as hubspot; types are unique per entry. oauthScopes is refused at publish while granted-scope capture rolls out.string[]
Skill keys in this version that depend on the connection. A multi-platform entry whose bound skill calls platform-native tools is refused; narrow
platforms or use capability-level access.lua.skill.yaml
name, authSupport (token, oauth, or both), and scopes as { scope, displayName, description? }.
personaTemplate
The persona with{{VAR}} slots, each declared and typed. Installer answers land on the installed agent; the manifest carries only the declarations.
string | { base?, voice?, text? }
required
The prompt text; the object form matches the persona’s channel branches. At least 40 literal characters must remain across branches beside the slots.
array
required
One declaration per slot. Every
{{TOKEN}} needs an entry and every entry must appear in at least one branch.boolean
required
true lets the installer edit the resolved text; the edit is stored verbatim and wins over substitution.vars[] entry:
string
required
Matches
[A-Za-z_][A-Za-z0-9_]*. persona is reserved. Must not collide with an env contract key.string
required
Form label. Non-empty.
string
required
Help text. Non-empty.
'string' | 'number' | 'boolean' | 'enum' | 'model'
required
model holds a model code; enum and maxLength are not allowed on it.boolean
default:"false"
A var that is not required must carry a
default.string | number | boolean
Must match
type; for enum, a member of the list.string[]
Required for
type: enum: unique, non-empty strings. Not allowed on other types.string
Input placeholder, for example
Acme Inc..integer
default:"256"
Strings only; 1 to 2000.
{ param: string, equals: string[] }
Ask only while
param (another var or an env contract key) has one of equals. A conditional var must carry a default. Rules under showIf rules.lua.skill.yaml
triggerPresets
A map keyed by trigger key covering the version’s jobs, webhooks, triggers, and connection-event triggers. Keys you don’t author default to{ enabled: true }; connection-event keys are always enabled: false.
boolean
required
Recommended default. The desktop install form asks the installer to confirm each key; a CLI
install arms the recommended defaults. true is refused on a connection-event key.string
Falls back to the primitive’s name, then the humanized key.
string
What enabling does.
array
Schedule fields the installer may change. Not allowed on connection-event keys. Every job with a
cron schedule gets a preset.timezone entry at publish whether or not you declare one.editableParams[] entry:
string
required
preset.seconds on an interval schedule, preset.timezone on a cron schedule, or workflowRef.input.<dotpath> for a workflow schedule’s input. One entry per path.string
required
Form label; a raw path is never shown.
string
Help text under the field.
string
Display only, for example
minutes.number
default:"60"
For
preset.seconds: at least 60 and a multiple of 60.number
At least
min.number
default:"60"
For
preset.seconds: a multiple of 60.seconds is 60 or a multiple of it, both in the frozen job and in the envelope; the frozen schedule must satisfy its own envelope, and a once schedule cannot be published. workflowRef.input.* entries may also carry default and required.
lua.skill.yaml
paramsMeta
Display metadata for env contract keys, keyed by the key. Every key must exist in the contract, and once the section is present every contract key needs an entry with adisplayName.
string
required
Form label. Non-empty.
string
Falls back to the contract’s description.
'string' | 'number' | 'boolean' | 'enum' | 'model'
required
Values are stored as strings; the type drives validation. A
model value is not checked against the model catalog at install.string | number | boolean
Must match
type; for enum, a member.string[]
Required for
type: enum; unique, non-empty strings.string
Input placeholder.
integer
Strings only; 1 to 2000.
number
Numbers only; finite and not greater than
max. A numeric default must fall inside the range.number
Numbers only; finite.
{ param: string, equals: string[] }
Ask only while
param (another env contract key) has one of equals. A hidden key is neither required nor validated, and any value for it is cleared.LUA_TRIGGER_URL__ are reserved: at install the platform writes one such variable per webhook-source trigger, holding that install’s trigger URL, and removes it at uninstall.
lua.skill.yaml
onInstall, onUninstall, installPolicy
onInstall and onUninstall are { tool?, instruction? } with at least one field; installPolicy is { perWorkspace: 'single' | 'multiple' }. Fields, timing, and refusals are on Lifecycle hooks.
Served manifest
Installers read a projection of the frozen version: display metadata and requirements, never code, trigger instructions, or values. Fields are enriched at read time.object
array
key, displayName, description, version; source (agent or marketplace) with marketplaceSkillId and versionId when composed from a marketplace skill.array
The authored entries with each platform enriched:
{ type, name, authSupport, oauthScopes?: { scope, displayName, description? }[] }.array
array
{ template, vars[], editable }
The authored section; each var carries
name, displayName, description, type, and any required, default, enum, placeholder, maxLength, showIf.array
Per frozen workflow:
key, displayName, description?, version, form (graph or script), stepCount, hasApproval, hasSchedule, hasSignalWait, hasJobTier, and, when set, jobSecondsMax, inputSchema, outputSchema, budget, concurrencyPolicy, schedule, scheduleInput, workspace, params, outputVisibility, envTemplateKeys, knowledge, replyChannels, protocolVersion, phases, scriptSurface. Absent on a version without workflows.object
Served verbatim so the install and uninstall screens can show them;
onInstall.startWorkflow serves the workflow key only.Install result
lua marketplace template install --json prints the install result: the ledger row (templateId, agentId, orgId, installedVersion, appliedAgentVersion, status of installed or apply_failed, lastError, allowCreatorUpdates, appliedBy, appliedAt, installedBy), the outcome fields armedTriggers, blockedTriggers, unwatchedTriggers, triggerEndpoints, hiddenParamsCleared, and personaSkipped, and the lifecycle hook outcomes. The field reference, the request bodies, and the one-call deploy result are on the agent templates API.
The install request the CLI sends carries version, envValues (from --env-vars), and allowCreatorUpdates only; contentHash, connectionSelections, triggerOverrides, personaVars, editedPersona, acceptModifiedPrimitives, acceptWithdrawnParams, and model are REST-only fields of the same route, so persona answers, connection choices, trigger overrides, and drift acceptance come from the desktop install form or the agent templates API. envValues is a request field, never a result field. The publish request carries sourceAgentVersion, changelog, envContract, the seven sections, and skipAutoApply; the version response adds approvalStatus (public templates), autoApplyRunId, and autoApplyTargetCount when a fan-out was started.
See also
- Publish a template — the how-to that fills this section in
- Lints and consent — every lint code and the consent surface
- Lifecycle hooks —
onInstall,onUninstall,installPolicy lua marketplace—draft,publish,view --versionlua.skill.yaml— the rest of the file

