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, the eight always-sent sections in the table below (every row except tagline) are sent on every publish, and an absent or empty one clears the server’s copy. The optional tagline is the one exception: it is sent only when its key is present, so leaving it out keeps the current tagline. 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
tagline
A one-line pitch for the Hire card, shown ahead of the description. Optional; when it is absent the card uses the description.- Up to 90 characters, counted after runs of spaces and line breaks are collapsed to one space and the ends trimmed. Longer is refused: by the CLI before anything is sent (
template.tagline in lua.skill.yaml is 95 characters; keep it to 90 or fewer) and by the server with400 TAGLINE_TOO_LONG, before the publish takes a version number. - Sent on
publishonly when the key is present. Leave the key out to keep the current tagline; set it to an empty value to clear it. - It is listing copy, like the description: it belongs to the template, not to one version, and it changes when the publish lands (for a public template, before the version is approved).
lua marketplace template create --taglineandPATCH /marketplace/templates/:templateIdset it too. - Lua staff may edit the tagline on the listing.
draftwrites the listing’s tagline intotemplate.taglinewhen the listing has one, and says so (tagline: updated from the listing); when the listing has none it keeps the file’s value, including one you have not published yet. - When the file’s tagline differs from the listing’s,
publishwarns that it replaces it (The listing's tagline is "…"; this publish replaces it with …). In a terminal it asks first; declining stops the publish and points todraft. Under--yes,--force,--cior without a terminal it warns and carries on; with--jsonthe warning goes to stderr. Rundraftbeforepublishto keep a staff edit. - If the listing cannot be read,
draftandpublishcarry on without the pull or the warning.
onInstall, onUninstall, sharedData, installPolicy
onInstall and onUninstall are { tool?, instruction? } with at least one field; sharedData is a list of { name, access: 'read' | 'write' }; 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.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

