Download all docs
modifiers

Prompt

A reusable, versionable home for an LLM instruction — system text, the user template, typed variables, and model hints — kept out of your application code so prompt engineering can be tuned, tested, and attached to agents on its own.

Working with it

Opening a Prompt launches a code editor — its dedicated working surface.

How it appears

The same element type rendered as a definition, a circle instance, and a live workspace card.

Pr
type

Prompt

Manage AI prompts and system instructions

modifiersmodifierdefinition

When to use / not

When to use

  • Giving an agent (or an LLM-invoking action) a named set of system instructions you want to reuse and tune independently of the actor itself.
  • Iterating on prompt wording — versioning v1 vs v2, adjusting temperature or recommended models — without redeploying the code that calls the model.
  • Building a template with {{ variable }} placeholders that get filled per call, where `render` substitutes the variable map into the final prompt text.
  • Running A/B tests across phrasings — define weighted variants and inspect the distribution with `variants`.

When not to use

  • Storing a plain config value with no template logic — use `variable` for non-template settings; prompt is for templated LLM instructions.
  • Scoring or grading model output against expected examples — that is `evaluator`'s job; prompt holds the instruction, the evaluator tests its quality.
  • Holding the actual conversation or invoking the model yourself — prompt is resolved by the actor's LLM logic, not an HTTP middleware step; the agent or brain runs the inference.

Topology

Attaches to another element as a modifier, shaping that element's behaviour rather than running on its own.

Properties

templatestring
Prompt template with {{variable}} placeholders
formatstring
Template format
variablesarray
Template variables
model_hintsobject
Model-specific hints
examplesarray
Few-shot examples
versionstring
Prompt version
tagsarray
Tags for organization
channelstring
Messaging channel this prompt is authored for. Read by the compose-message flow to filter the option library when the user picks a channel. Leave unset for generic prompts not tied to a specific messaging channel.
intentstring
Coarse-grained intent / use case — free-form slug used by the compose-message flow to group options. Convention: lowercase, underscore-separated, short. Examples: "warm_intro", "follow_up", "meeting_ask", "re_engage", "thank_you".

Capabilities

Defined for this element
  • Evaluate
  • Observe

Operations

  • attachPOST
  • deleteDELETE
  • detachPOST
  • disablePOST
  • enablePOST
  • evaluatePOST
  • getGET
  • get_attached_modifiersGET
  • intentionGET
  • list_attachmentsGET
  • readme_updatePOST
  • renderPOST
  • schemaGET
  • updatePATCH
  • variantsGET

Ports

Inputs

  • templateconfig
  • variablesconfig
  • model_hintsconfig

Composition

Errors / when it fails

Prompt template content is required

Validation rules

  • High temperature (>1) may produce inconsistent outputs
  • Large max_tokens (>32k) may be costly and slow

Prompt (prompt)

Category: modifiers | Form: | Symbol: Pr

Manage AI prompts and system instructions

Manages AI prompt templates with variable substitution. Cascade strategy: nearest (NearestMap) — local prompt overrides inherited with the same name. Stored in resolved.prompts. The render operation substitutes {{variable_name}} placeholders with values from input.variables (or root input object). Unknown placeholders are left as-is. Null values render as empty strings, non-string values are JSON-serialized. Spec requires a template field (string). Use prompt for reusable AI instructions attached to agents; use variable for non-template config values. The variants operation lists A/B test prompt variants. Common mistake: missing the template field in spec — render will return InvalidInput error.

Guide

Overview

A Prompt resource encapsulates the art and science of LLM prompting. It separates the prompt text, system instructions, and variable logic from the application code, enabling versioning, testing, and easy iteration.

Why Prompts Exist

  • Separation of Concerns: Keep prompt engineering separate from application logic.
  • Versioning: Track changes to prompts over time (v1 vs v2).
  • Optimization: Tune model hints (temperature, model choice) specifically for the task.
  • Testing: Define input/output examples to verify prompt quality with Evaluations.

Directory Structure

customer-response/
├── README.md              # Documentation
├── .triform/              # Metadata
│   ├── triform.yaml       # kind: config/prompt
│   ├── contract.yaml      # Capabilities
│   ├── spec.yaml          # Template logic
│   └── schema.json        # Validation
└── examples/              # Usage examples

Creating a Prompt

$ triform create config/prompt customer-response

Configuration

System & Template

Define the instructions (System) and the user message (Template).

system: "You are a helpful assistant."
template: "Answer this question: {{ question }}"

Variables

Define strongly-typed variables.

variables:
  - name: question
    type: string
    required: true

Model Hints

Suggest execution parameters.

model_hints:
  recommended_models: ["gpt-4o", "claude-3-5-sonnet"]
  temperature: 0.7

Structured Output

Enforce JSON schema outputs.

output_format:
  type: json
  schema:
    type: object
    properties:
      answer: { type: string }
      confidence: { type: number }

Usage in Actions

Reference the prompt by slug:

# In action.yaml
prompt:
  ref: "@project/customer-response"
  variables:
    question: "{{ inputs.query }}"

Runtime Behavior

PropertyValue
Cascadenearest — the closest prompt definition wins per key
Eval Ordern/a (no middleware phase; resolved before LLM invocation)
Phasen/a
Fail Actionn/a (undefined variable references in {{ var }} placeholders surface as render errors)
Applies Toactors (agent, evaluator)

The render operation substitutes {{ variable_name }} placeholders using the provided variable map and returns the fully-expanded prompt text. Prompt does not participate in the HTTP middleware pipeline — it is resolved by the actor’s LLM invocation logic.

Files in This Resource

  • README.md - Documentation
  • .triform/triform.yaml - Metadata
  • .triform/contract.yaml - Capabilities
  • .triform/spec.yaml - Template definition

Relationships

  • Attaches to: circle, lab, triformer, claude-code, open-code

Capabilities

  • templating: Variable substitution
  • versioned: Version history
  • validation: Variable validation
  • hints: Model parameter hints

Properties

PropertyTypeDefaultDescription
templatestringPrompt template with {{variable}} placeholders
formatstring"text"Template format
variablesarray[]Template variables
model_hintsobjectModel-specific hints
examplesarray[]Few-shot examples
versionstring"1.0"Prompt version
tagsarray[]Tags for organization
channelstringMessaging channel this prompt is authored for. Read by the compose-message flow to filter the option library when the user picks a channel. Leave unset for generic prompts not tied to a specific messaging channel.
intentstringCoarse-grained intent / use case — free-form slug used by the compose-message flow to group options. Convention: lowercase, underscore-separated, short. Examples: “warm_intro”, “follow_up”, “meeting_ask”, “re_engage”, “thank_you”.

Operations

attach

Post /ops/attach | Auth: Read

Attach this modifier to a target element

Attaches this modifier to a target element. The target_id must be a UUID of an existing element that supports this modifier type (check applies_to in definition.yaml). Priority controls evaluation order when multiple modifiers of the same type are attached — lower priority runs first. The attachment is stored in element_modifiers table. Cascade resolution runs at bond-time to merge this modifier into the target’s resolved config. Common mistake: attaching to an incompatible element type — check topology rules first.

delete

Delete /ops/delete | Auth: Admin

Delete element (soft delete)

Soft delete — sets state to ‘deleted’ but retains the record. Cannot delete elements that have children (has_no_bond precondition) or active runs. Requires admin auth and confirmation.

detach

Post /ops/detach | Auth: Read

Detach this modifier from a target element

Removes this modifier from a target element. Requires the target_id. Pervasive modifiers (audit, policy) can only be detached at the level they were originally attached — inherited pervasive modifiers cannot be detached by child elements. After detach, cascade resolution re-runs to remove this modifier’s effect from the resolved config.

disable

Post /ops/disable | Auth: Admin

Disable element (hides and prevents use)

Idempotent — safe to call on already-disabled elements. Optionally pass a reason string. Disabled elements cannot be invoked or executed. Inverse of enable.

enable

Post /ops/enable | Auth: Admin

Enable element (makes usable and visible)

Idempotent — safe to call on already-enabled elements. Transitions element to ready/enabled state. Cannot enable deleted elements. Inverse of disable.

evaluate

Post /ops/evaluate | Auth: Read

Evaluate modifier against current context

Evaluates this modifier against a context and optional target_id. Returns applies (bool), result (modifier-specific), and message. For modifiers without custom evaluation logic, returns a default pass result. Auth-policy returns allowed/denied. This is the explicit evaluation endpoint — during normal request flow, modifiers are evaluated automatically by the cascade resolver as middleware.

get

Get /ops/get | Auth: Read

Get element details

Element is already resolved by the routing layer — this returns the cached element, not a fresh DB query. Use the path /api/{circle}/{slug} to address elements.

get_attached_modifiers

Get /ops/attached/{target_id} | Auth: Read

Get all modifiers attached to a target element

Lists all modifiers attached to a specific target element, including modifier_id, type, subcategory, and priority. Useful for debugging cascade resolution or understanding which policies apply to an element before invoking it.

intention

Get /ops/intention | Auth: Read

Get element intention with full inheritance chain

Returns three levels: direct (this element’s intention), inherited (from category and root), and resolved (final merged intention). Useful for understanding an element’s purpose in context of its hierarchy.

list_attachments

Get /ops/targets | Auth: Read

List all elements this modifier is attached to

Returns all target elements where this modifier is currently applied. Shows target_id, target_type, priority, and cascade_policy.

readme_update

Post /ops/readme_update | Auth: Write

Update element README.md content

Creates or overwrites README.md in the element’s git repo. Commits to the draft branch. Content must be provided as a markdown string.

render

Post /ops/render | Auth: Read

Render prompt with variables

Substitutes {{variable_name}} placeholders in the template with values from input.variables (object). If variables is missing, uses the root input object. Null values become empty strings, non-strings are JSON-serialized. Unknown placeholders are left as-is. Returns the rendered string, original template, and element_id. Fails with InvalidInput if spec has no “template” field. Idempotent — safe to call repeatedly for preview.

schema

Get /ops/schema | Auth: Read

Get element input/output schema (MCP tools/list compatible)

Returns type-level port schemas from the TypeRegistry — not instance-specific overrides. Includes direction (input/output), required flag, and JSON schema per port. Useful for understanding what data an element accepts and produces.

update

Patch /ops/update | Auth: Write

Update element

Partial update — send only the fields you want to change. spec, name, and intention are all independently optional. spec MUST be a JSON object when present; deep-merged into the existing spec by default. Empty {"spec":{}} preserves existing spec content but still records a new version (no-op for content, not for version state). To clear/replace the entire spec wholesale send {"spec":{...},"deep":false}. List-typed spec fields use replace semantics (the patch list replaces the existing list, no array merging). Coordinates Git + DB writes. Slug cannot be changed after creation.

variants

Get /ops/variants | Auth: Read

List prompt variants (for A/B testing)

Returns prompt variant definitions with name, weight (percentage), and content for each. Use when running A/B tests on different prompt phrasings to see the variant distribution.

Error Codes

CodeClassRetryableDescription
PROMPT_NOT_FOUNDnot_foundnoPrompt does not exist
PROMPT_VARIABLE_MISSINGvalidationnoRequired variable not provided
PROMPT_RENDER_FAILEDinternalnoTemplate rendering failed

Lifecycle / runtime

Defined for this element

Execution model: sync

Observability

Defined for this element

Metrics

  • evaluation_count
  • rejection_count

Events

  • prompt.evaluated
  • prompt.rejected

Pricing / cost

Platform default

Operation costs

  • create: free
  • update: free
  • delete: free
  • get: free
  • list: free
  • invoke: 10000 micro-AU
  • tool_use: free

Set it up

Templatestring
Prompt text with {{variable}} placeholders
Formatstring