Skip to main content

From agent to template

You never hand-write a template manifest. You build a real agent, and the platform does the heavy lifting: publishing freezes every primitive from your promoted agent version automatically, and a draft composer infers the rest — connections, persona variables, trigger presets — into your project’s lua.skill.yaml for you to review like a diff. Your job is the product decisions: which connections are required, what the installer-facing copy says, which automations should be on by default. This guide follows one agent end to end: Standup Sidekick, a small agent that logs the wins a user mentions during the day (log_win / list_wins tools in a standup-skill), nudges them before standup with a scheduled standup-nudge job, and has a persona (“You are the Standup Sidekick for Acme Demo Co…”).
New to templates? Read Agent Templates first for the model — what a template contains, lifecycle, and consent. This page is the hands-on authoring journey.

Step 1 — Build and promote the source agent

Nothing template-specific yet: build Standup Sidekick the normal way.
Use it until you’re happy with it. The promoted version is what publishing will freeze.

Step 2 — Create the template listing

Run this from the project connected to your source agent:
Templates are private by default — only your organization can find and install them. Add --visibility public to head for the public catalog (which adds a review step, below).

Step 3 — Run the draft composer

The draft composer writes a template: section into your lua.skill.yaml, composed from what your agent actually is: Re-running draft later (say, after adding a skill for v2) performs an additive merge: newly inferred entries are appended, your existing keys are never modified, and the CLI prints a per-section diff of what it added versus kept. A full overwrite of your authored sections requires an explicit --force. Use --source-version <n> to compose from a specific promoted agent version instead of the active one.
Inference proposes; you dispose. Required-versus-optional, the platform allow-list, and every installer-facing string are product decisions the composer can only draft. Review the section like any diff before publishing.

Step 4 — Edit the template: section

Here’s a realistic authored section for Standup Sidekick after the composer ran and the creator polished it. The persona got two variables, the nudge job’s interval became installer-editable, and an optional chat connection was declared for posting nudges:
A few rules worth knowing while you edit:
  • Every installer-facing entry needs displayName and description. The deploy screen renders its copy straight from this section — a raw key is never shown as a form label, and publish rejects entries missing them.
  • Keys are identity. A connection key, trigger key, param name, or persona var name is its stable identity across versions — renaming one means “remove + add”, which costs installers their setting for it. Keep keys stable across versions.
  • The whole section is serialized on every publish. When a template: section exists, all four subsections (connections, personaTemplate, triggerPresets, paramsMeta) are always sent — an empty or deleted subsection is an explicit clear, not “keep the previous version’s”. Clearing or narrowing anything prompts you with the consequence before publishing (see below).
  • The env contract is declared at publish, via the --env-contract flag — paramsMeta carries the display metadata for those variables:
Every attribute you can author here — with types, defaults, constraints, and the exact lint each one is guarded by — is in the Template Manifest Reference.

Step 5 — Publish

Publishing freezes your agent’s active promoted version plus the authored template: section into an immutable, integer-numbered template version (v1, v2, v3 — not semver). Use --source-version <n> to freeze a specific promoted version instead of the active one. If this publish clears or narrows previously authored sections (you removed a declared connection, dropped a persona var), the CLI prints the consequence per section and asks for confirmation. --yes auto-confirms only that consequence prompt — useful in CI — without skipping any other confirmation the way --force does.

The lint battery

Publish is the quality gate: a version that would fail on an installer’s agent — or render an unusable deploy screen — is rejected at publish, with actionable errors, and a rejected publish burns no version number. Among what it checks:
  • Schedules must actually be schedulable. Interval schedules run on whole minutes only — a fractional-minute interval would silently never fire, so it’s rejected up front. Publishing Standup Sidekick with seconds: 90 fails with:
  • Persona variables must be declared, both ways. Every {{VAR}} in the persona template needs a matching vars entry, and vice versa — across every persona branch, including voice text. Reserved names (like persona) are rejected.
  • Declarations must be self-consistent. Enum lists non-empty, defaults satisfying their own type, every editableParams.path resolving into its trigger entry, optional vars carrying a default.
  • Connections must be real. Every platform in an allow-list must exist in the integration catalog and match the declared capability; OAuth platforms must declare their scopes (that’s what the installer consents to).
  • Portability must be authored, not hoped. A capability may list multiple platforms only when the skills bound to it reach the connection through the capability, not through platform-specific calls — otherwise the allow-list is narrowed to the platform the code actually uses.
  • No secrets in frozen code. A hardcoded API key in skill source is caught and rejected, pointing at the file and line, with the fix: declare it in the env contract so each installer supplies their own.
  • No voice yet. A source agent with voices or device triggers can’t publish — voice templates aren’t supported in V1, and the error says so rather than shipping a template that deploys half-working.

Step 6 — Visibility and review

Private templates are installable by your org the moment they’re published — this is the fleet path, and it needs no review. Going public adds platform review, and review is per version:
  • Flipping a private template public enqueues its latest version for review; it lists publicly once approved. Older published versions stay org-only unless republished.
  • Every version you publish while public enters review, and isn’t installable by others — including through the update badge — until approved.
  • Your own self-test installs are exempt: you can install a pending version onto your org’s agents to verify it before anyone else can.
  • A rejection leaves your prior approved versions listed. Versions are immutable — resubmitting means publishing a new version with the fix.
Two kinds of change behave differently when you ship v-next, and it pays to know which you’re making:
  • Code-only changes — you rewrote a tool’s implementation, fixed a bug, improved a prompt inside a skill — flow to opted-in installs (allowCreatorUpdates) under their standing consent. This is the everyday fleet-update path.
  • Consent-surface changes — a widened OAuth scope, an added or changed connection, a changed trigger instruction — require re-consent from every install, opted-in included. Your push is rejected per target until the installer reviews and accepts the new surface themselves.
Installers also always get a server-computed update preview before accepting: your changelog, what’s added/removed/changed, scope deltas, and which of their armed automations survive. Their persona edits and schedule tweaks are preserved across your update — see what survives an update for the installer’s side.

Step 8 — Roll out

There’s no separate canary flag — a canary is the same apply aimed at a smaller target list. Check the per-target result table (and the agents themselves) before going wide. Pass --no-wait to get the run ID immediately and check on it later with status. What a rollout will and won’t do on each target:
  • Won’t arm anything new. Renamed or newly added triggers land disabled, awaiting the installer’s confirmation. A trigger the installer paused stays paused.
  • Won’t strand targets on a new required env key. Targets missing it flip to a pending-input state with an installer prompt, rather than shipping a broken agent.
  • Won’t overwrite installer customizations silently. Installer-edited personas are skipped; installer-tuned schedule params are re-applied over your new preset; hand-edits to managed primitives surface an explicit confirm instead of a silent revert.
  • Fails loudly. Any failed target marks the run failed and exits non-zero; successful targets are unaffected and a re-run is safe.

Step 9 — Retire

  • Deprecate a version to block new installs of it — existing installs are unaffected, and the changelog carries the reason. You can’t deprecate the only approved version of a still-listed public template; unlist first.
  • Unlist the template to soft-retire it: no new installs, no more creator applies. Existing installs keep running with what they have, can still uninstall, and can still re-run their same installed version to rebind a connection.
There is no hard delete — unlist + deprecate is the complete retirement path, and it keeps the audit trail and install ledger intact for every agent still running your template.