FPO templates
An FPO template wraps a full product object (FPO). Use it to share a reusable product definition and collect values from each person who imports it.
Use an FPO template when you need to:
- Keep the product structure stable.
- Collect names, URLs, or environment-specific values during import.
- Ask for the credentials that the product’s tools need.
- Preview the product on the dashboard import page (
use.runtype.com/now) before you create it.
Template shape
An FPO template uses these top-level keys:
versionsets the template document format version. Use1.0or1.1.productObjectcontains the FPO.template.variablescontains metadata for each variable that the FPO references.
Set productObject.version to 1.0, 1.1, or 2.0. Use 2.0 for new templates. In 2.0, place inline agent runtime fields under agent.config. In 1.0 and 1.1, place those fields directly on the agent object.
The following table lists the top-level keys of productObject:
The _meta object needs five non-empty strings: schemaVersion, catalogVersion, generatedAt, generatorVersion, and planHash. When you write a template by hand, fill them with descriptive values, as the example template does.
Each capability sets exactly one of flow, agent, existingFlowId, or existingAgentId.
An existingFlowId or existingAgentId must belong to the account that imports the template. For
any other account, the import fails with a “not found or not owned by current account” error. In a
template that you share with other accounts, define each capability inline with flow or agent.
Use variable references in string values within the FPO:
Variable manifest
Declare each variable in template.variables with the following fields:
A template can declare up to 50 variables.
An inputType: "secret" variable is substituted literally into the resolved product object, so
Runtype stores the supplied value in the product record. Validation reports a
TEMPLATE_VARIABLE_SECRET_IS_UNSAFE warning for every secret variable. To collect a credential,
declare it in the tool’s auth.secrets and reference it as {{secret:KEY}}. For more
information, see Collect credentials. Never put live secrets in template
files.
Resolution rules
Runtype resolves a template with these rules:
- Every
{{variableName}}reference must be declared in the manifest. - Inline defaults such as
{{apiKey|default}}are not allowed. Define defaults withtemplate.variables[].defaultValue. - A template must declare at least one variable, or at least one tool with
auth.setupRequired: trueand one or moreauth.secretsentries. - References to
{{secret:NAME}}and to system variables, such as{{_now.iso}}or{{userMessage}}, don’t need a declaration. Runtype leaves them for run time. - Every other
{{...}}token counts as a template variable, including a runtime token in a step prompt or a Liquid template. To keep a runtime token, declare a template variable whosedefaultValueis the token, and reference that variable in its place. - A value supplied for a
numbervariable is converted to a number. A non-numeric value counts as missing. - A value supplied for a
booleanvariable is converted from the stringstrueandfalse. Any other value counts as missing. - When a field value is exactly
{{variableName}}and the variable is anumberorboolean, the field keeps that scalar type. - Every other substitution resolves to a string.
Collect credentials
To ask the importer for an API key or token, declare it as a pending secret on the tool that uses it. Reference the secret in the tool configuration with {{secret:KEY}}. Runtype stores the value in your secrets, not in the product object.
The following fields define a tool’s auth object:
Use the following structure to reference a pending secret in a tool:
The import preview returns these entries in pendingSecrets. The dashboard import page lists them under Secrets to configure after import, with each secret’s key, tool name, description, and a Get key link to docsUrl. When you create the product, Runtype adds each secret to your account without a value. If your account already has a secret with the same key, the product uses that secret instead. Validation doesn’t check the key format, and the import skips any secret whose key breaks the format rule in the preceding table. To set a value, see Managing secrets.
Example template
Use this complete template as a starting point:
Add scheduled jobs
Use the top-level productObject.schedules[] array for cron or one-time automation. Each schedule targets a capability through capabilityId. Importing the FPO creates the schedule.
A capability that a schedule targets doesn’t need a surface route. Don’t add a type: "schedule" surface to trigger the schedule. Add a schedule surface only when users or operators need a dedicated surface to inspect and manage schedule behavior.
The following fields define a schedule in an FPO:
Use the following structure to define a scheduled capability:
Add eval suites
Use the optional top-level productObject.evals[] array to include eval suites in a product. Each suite targets a capability through capabilityId. Importing the FPO creates the suite, its graders, and its example cases with the capability’s flow or agent.
The following fields define an eval suite in an FPO:
Use the following structure to add an eval suite:
When you re-import the product, Runtype replaces only the cases that came from the FPO. Cases that you author in the dashboard or save from a run stay in the suite, and Runtype doesn’t add them to the FPO when you export the product definition.
For grader and case concepts, see What are Evals?. Use Managing eval suites to edit imported suites in the dashboard.
Add skills
Use the optional top-level productObject.skills[] array to include agent skills in a product. A skill is a loadable context bundle with a markdown body and optional capabilities that it activates when loaded. Importing the FPO publishes each skill and binds it to the agent-backed capabilities listed in bindTo.
The following fields define a skill in an FPO:
Do not declare mcpServers in a skill’s capabilities. The validator rejects the key with an explicit error. Bind MCP tools with a saved tool ID or an inline tool.
Use the following structure to add a skill:
Pin a skill version
Each bindTo entry is either an FPO capability ID or an object with capability and version. A capability ID binds the skill so that the agent follows the skill’s published version. An object pins the binding to the skill version with that version number:
Importing the FPO publishes the skill content as a new version, so an agent that follows the published version starts using the new content. A pinned agent keeps the version it names until you change the pin. If the skill has no version with that number, product ensure reports the skill as failed and doesn’t write that binding. Pulling a product returns each pinned binding in the object form.
Validate a template
Validate a template before you share it. The runtype CLI validates locally without an API call. The API endpoint is POST /v1/public/products/validate-template.
Save the example template as customer-support-fpo-template.json, then validate it with one of the following samples.
CLI
TypeScript
cURL
The command exits with code 0 when the template is valid. It exits with code 1 when validation finds errors, when the defaults resolve to an invalid FPO, or when the command can’t read or parse the input. A variable without a default is reported but doesn’t fail the command. To read the template from standard input, pass - as the path.
The endpoint returns 400 with the code INVALID_JSON when the request body isn’t valid JSON. Otherwise, it returns the following fields:
A variable without a default leaves valid set to true. It sets defaultsSufficient to false and adds a MISSING_TEMPLATE_VARIABLE entry to defaultsValidation.errors. The importer supplies that value during import.
The following table lists the template-specific issue codes:
Share a template
To let other people import your template, follow these steps:
- Host the template JSON file at a public HTTPS URL, such as a raw GitHub file URL.
- URL-encode the file URL.
- Share the import link
https://use.runtype.com/now?from=ENCODED_TEMPLATE_URL. The link opens the dashboard import page with a preview of the template. - Optional: Add a Deploy to Runtype button to your repository. For the Markdown snippet, see Create a repository button.
Replace ENCODED_TEMPLATE_URL with the URL-encoded address of your template file.
Create a product from a template
To create a product from a template with the API, follow these steps:
- Preview the template with
POST /v1/quick-start/imports/preview. Send the template as a hosted file withsource.kind: "url"or inline withsource.kind: "json". - Collect values for the variables that the preview response lists without defaults.
- Create the product with
POST /v1/quick-start/create. Send the values invariables, with theimportTokenfrom the preview response.
An API key must hold a scope for everything that the template creates, such as SECRETS:WRITE for a template that declares secrets. A Test key can’t hold SECRETS:WRITE, so it can’t create a template product that declares secrets. For the full scope list, see Required API key scopes in the importing guide, which also has request and response examples.
Next steps
Continue with these guides:
- Quickstart: Make your first call to the Runtype API.
- Agent Skills: Bind loadable context bundles to agents.