Skip to main content
Use a YAML action template to compose existing actions into a reusable action.

Template shape

Create a .yml file in your registry templates directory. Define inputs in expects, run actions in steps, and return the final value from returns.
  • Start every file with type: action.
  • Use tools.<integration> for the namespace.
  • Set title, description, display_group, namespace, and name in definition.
  • Define inputs in expects.
  • Build the action in steps.
  • Return the final value from returns.

Expressions

Use ${{ }} for expressions. Use inputs to read the inputs you defined in expects. Use steps to read the result of an earlier step. After a step runs, its output is available at steps.<ref>.result.
Read an input
Read an earlier step result
Build one step from another
You can use:
  • inputs
  • steps
  • SECRETS
  • VARS
  • FN.*

Secrets

Declare what each template needs under definition.secrets (API keys, structured types, or OAuth). That list drives which credentials must exist for the action when the workflow runs. Use the same ${{ SECRETS... }} paths in args as in any other expression. Use the same ${{ SECRETS... }} syntax as workflow actions. Custom secrets (API keys, SSH, mTLS, CA bundles, and so on):
OAuth tokens live under <provider_id>_oauth. The key is the provider ID in uppercase plus _USER_TOKEN or _SERVICE_TOKEN:
  • authorization_code: ${{ SECRETS.<provider_id>_oauth.<PROVIDER_ID_UPPER>_USER_TOKEN }}
  • client_credentials: ${{ SECRETS.<provider_id>_oauth.<PROVIDER_ID_UPPER>_SERVICE_TOKEN }}
Optional fallback when either grant type is allowed:

Python UDFs

Declare credentials in @registry.register(..., secrets=[...]).
  • RegistrySecret: static keys; set secret_type to ssh_key, mtls, or ca_cert when needed (secret types). Optional: optional, optional_keys.
  • RegistryOAuthSecret: declares a dependency on an existing OAuth integration. Pass the provider_id and grant_type that match the integration in your workspace (a mismatch — for example declaring authorization_code when the integration uses client_credentials — will not resolve).
Read values with secrets.get("<KEY>") (key only, e.g. GOOGLE_DRIVE_USER_TOKEN), not a SECRETS. path.

YAML

Under definition, set a secrets list (same validator as Python). Custom (optional secret_type for structured secrets):
OAuth:
The provider_id and grant_type must match an integration already configured in your workspace. Use ${{ SECRETS.<provider_id>_oauth.<TOKEN_KEY> }} in args. Set optional: true on an OAuth entry when it is not always required.

Example providers

See integrations/google_drive.py and integrations/slack_sdk.py for UDFs that use OAuth credentials. See tracecat_registry/core/ssh.py for an ssh_key secret example. For YAML templates, see microsoft_teams/send_message.yml (authorization_code), google_docs/create_document.yml (client_credentials), and microsoft_sentinel/.../get_alert_rule_template.yml (optional dual grant). See templates/tools/exa/search.yml for a simple API key template. For the full list of built-in provider IDs, see tracecat/integrations/providers/__init__.py.

Limitations

  • Template steps only support ref, action, and args.
  • Template steps run in order.
  • Template steps do not support run_if, for_each, join_strategy, start_delay, timeout, or max_attempts.
  • Templates can call tools actions, other templates, and core.script.run_python. Other platform actions are not supported inside templates.
  • If a later step fails, you do not get a final result with earlier step outputs. Keep templates short. In practice, do not build templates with more than 2 steps.

Example templates

All integrations in Tracecat are open source. Browse template actions for more examples. For concrete examples, browse the Slack templates and CrowdStrike templates.