Skip to main content

Agent Task Configuration Guide

A comprehensive guide to creating and configuring agent tasks in PlanOps.

Table of Contents

  1. Overview
  2. Task Structure
  3. Input Schema
  4. Output Schema
  5. Workflow Steps
  6. Templating & Variables
  7. Best Practices
  8. Complete Examples

Overview

Agent tasks are configurable, multi-step workflows that enable AI-powered automation within PlanOps. Tasks can:

  • Collect structured user input via dynamic forms
  • Call internal APIs and external services
  • Execute LLM prompts for analysis and content generation
  • Transform and process data
  • Create reports, forms, and other outputs
  • Automate complex document workflows

Key Concepts

ConceptDescription
Input SchemaDefines what information the task needs from the user
Output SchemaDefines what the task produces
WorkflowOrdered sequence of steps that execute the task logic
ContextRuntime variables like project_id, organization_id, user_id
TemplatingJinja2-based variable substitution throughout the task

Task Structure

Every agent task follows this top-level structure:

{
"task_id": "my-task-slug",
"name": "Human-Readable Task Name",
"description": "Clear description of what the task does and when to use it.",

"input_schema": { ... },
"output_schema": { ... },
"workflow": { ... },

"category": "safety",
"tags": ["compliance", "review", "documents"],
"icon": "ShieldCheck",
"color": "#DC2626",

"active": true,
"featured": false,
"required_permissions": ["documents:read", "reports:write"],

"examples": [
{
"input": { ... },
"description": "Example use case description"
}
]
}

Required Fields

FieldTypeDescription
task_idstringUnique slug identifier (lowercase, hyphens)
namestringDisplay name (4+ characters)
descriptionstringWhat the task does (40+ characters recommended)
input_schemaobjectInput field definitions
workflowobjectExecution steps

Optional Fields

FieldTypeDefaultDescription
output_schemaobjectnullOutput field definitions
categorystringnullCategory for grouping (e.g., "safety", "documents")
tagsarray[]Tags for discovery and filtering
iconstringnullLucide icon name
colorstringnullHex color code
activebooleantrueWhether task is available
featuredbooleanfalseHighlight in UI
required_permissionsarraynullPermissions needed to run
organization_idObjectIdnullScope to organization
project_idObjectIdnullScope to project
examplesarraynullExample inputs for documentation

Input Schema

The input_schema defines the form users see when running a task.

Structure

{
"input_schema": {
"fields": [
{
"name": "field_name",
"label": "Field Label",
"type": "text",
"description": "Help text for the user",
"required": true,
"default_value": null,
"placeholder": "Enter value..."
}
],
"groups": null
}
}

Field Types

Text Fields

{
"name": "project_description",
"label": "Project Description",
"type": "text",
"description": "Describe the project scope and objectives",
"required": true,
"min_length": 20,
"max_length": 5000,
"placeholder": "Enter project details..."
}

Validation options:

  • min_length / max_length: Character limits
  • pattern: Regex validation (e.g., "^[A-Z]{2}-\\d{4}$" for format "XX-0000")

Number Fields

{
"name": "period_days",
"label": "Period (Days)",
"type": "number",
"description": "Number of days to search",
"required": false,
"default_value": 7,
"min_value": 1,
"max_value": 365
}

Boolean Fields

{
"name": "include_attachments",
"label": "Include Attachments",
"type": "boolean",
"description": "Include file attachments in the review",
"required": false,
"default_value": true
}

Date/DateTime Fields

{
"name": "start_date",
"label": "Start Date",
"type": "date",
"description": "Project start date",
"required": true,
"min_date": "2024-01-01",
"max_date": "2030-12-31",
"allow_future": true
}
{
"name": "meeting_time",
"label": "Meeting Time",
"type": "datetime",
"description": "Scheduled meeting date and time",
"required": true
}

Select Fields (Static Options)

{
"name": "document_status",
"label": "Document Status",
"type": "select",
"description": "Filter by document status",
"required": false,
"default_value": "FOR_REVIEW",
"options": [
{"label": "Draft", "value": "DRAFT"},
{"label": "For Review", "value": "FOR_REVIEW"},
{"label": "Approved", "value": "APPROVED"},
{"label": "Construction", "value": "CONSTRUCTION"}
]
}

Select Fields (Dynamic Options)

Dynamic options load choices from an API at runtime:

{
"name": "organization_id",
"label": "Originating Organisation",
"type": "select",
"description": "Filter by organisation",
"required": false,
"dynamic_options": {
"url": "/api/v1/projects/{{context.project_id}}/organizations",
"method": "GET",
"query_params": {
"size": 100
},
"data_path": "items",
"label_field": "name",
"value_field": "_id"
},
"placeholder": "Select an organisation"
}

Dynamic options configuration:

PropertyRequiredDescription
urlYesAPI endpoint (supports templating)
methodYesHTTP method (usually "GET")
query_paramsNoQuery parameters object
data_pathYesPath to array in response (e.g., "items")
label_fieldYesField to display as label
value_fieldYesField to use as value

Common dynamic option patterns:

// Project reports
{
"url": "/api/v1/reports",
"method": "GET",
"query_params": {
"project_id": "{{context.project_id}}",
"limit": 100
},
"data_path": "items",
"label_field": "title",
"value_field": "id"
}

// Form templates
{
"url": "/api/v1/forms/templates",
"method": "GET",
"query_params": {
"project_id": "{{context.project_id}}",
"limit": 100
},
"data_path": "items",
"label_field": "name",
"value_field": "id"
}

// Project users
{
"url": "/api/v1/projects/{{context.project_id}}/members",
"method": "GET",
"data_path": "items",
"label_field": "name",
"value_field": "id"
}

// Agents
{
"url": "/api/v1/agents/",
"method": "GET",
"query_params": {"limit": 100},
"data_path": "items",
"label_field": "title",
"value_field": "id"
}

Multi-Select Fields

{
"name": "file_types",
"label": "File Types",
"type": "multi_select",
"description": "Select file types to include",
"required": false,
"default_value": ["pdf", "docx"],
"options": [
{"label": "PDF", "value": "pdf"},
{"label": "Word (DOCX)", "value": "docx"},
{"label": "Excel (XLSX)", "value": "xlsx"},
{"label": "AutoCAD (DWG)", "value": "dwg"}
]
}

Document Picker

{
"name": "rams_document",
"label": "RAMS Document",
"type": "document_picker",
"description": "Select the RAMS document to review",
"required": true,
"filter_by": {
"document_type": ["METHOD_STATEMENT", "RISK_ASSESSMENT"]
}
}

File Upload

{
"name": "supporting_files",
"label": "Supporting Documents",
"type": "file_upload",
"description": "Upload supporting documents",
"required": false,
"multiple": true,
"filter_by": {
"file_types": ["pdf", "docx", "doc", "txt", "jpg", "png"]
}
}

Accessing uploaded file content:

  • {{input.supporting_files.text_content}} - Extracted text (single file)
  • {{input.supporting_files.filename}} - Original filename
  • For multiple files, iterate: {% for file in input.supporting_files %}...{% endfor %}

User Picker

{
"name": "assigned_reviewer",
"label": "Assigned Reviewer",
"type": "user_picker",
"description": "Select the person to review this document",
"required": true
}

Project Picker

{
"name": "target_project",
"label": "Target Project",
"type": "project_picker",
"description": "Select the project to apply this to",
"required": true
}

Report Picker

{
"name": "source_report",
"label": "Source Report",
"type": "report_picker",
"description": "Select an existing report as the basis",
"required": false
}

Conditional Fields

Fields can show/hide based on other field values:

{
"name": "source_type",
"label": "Source Type",
"type": "select",
"required": true,
"options": [
{"label": "Direct Text", "value": "direct_text"},
{"label": "From Report", "value": "from_report"}
]
},
{
"name": "direct_text",
"label": "Enter Text",
"type": "text",
"required": false,
"depends_on": "source_type",
"show_when": {"source_type": "direct_text"}
},
{
"name": "report_id",
"label": "Select Report",
"type": "select",
"required": false,
"depends_on": "source_type",
"show_when": {"source_type": "from_report"},
"dynamic_options": { ... }
}

Output Schema

The output_schema defines what the task produces.

Structure

{
"output_schema": {
"fields": [
{
"name": "summary",
"label": "Summary",
"type": "text",
"description": "Task execution summary",
"source": "{{step.summary_step.summary_output.response}}"
},
{
"name": "outputs",
"label": "Outputs",
"type": "array",
"description": "Generated output references",
"source": "[{\"type\": \"report\", \"id\": \"{{step.create_report.report.id}}\", ...}]"
},
{
"name": "completion_time",
"label": "Completion Time",
"type": "string",
"source": "{{now().isoformat()}}"
}
],
"format": "json"
}
}

Standard Output Pattern

All tasks should include a standardized summary output:

{
"summary": "Brief description for dashboard display",
"outputs": [
{
"type": "report",
"id": "{{report_id}}",
"title": "Report Title",
"url": "/api/v1/reports/{{report_id}}",
"category": "Safety"
}
],
"completion_time": "{{timestamp}}"
}

Workflow Steps

The workflow section defines the execution logic.

Structure

{
"workflow": {
"allow_parallel": false,
"steps": [
{
"id": "step_id",
"name": "Step Name",
"type": "step_type",
"description": "What this step does",
...step-specific configuration...
"output_key": "result_key"
}
]
}
}

Step Types

1. API Call (api_call)

Call internal or external APIs:

{
"id": "fetch_documents",
"name": "Fetch Project Documents",
"type": "api_call",
"endpoint": "/api/v1/documents/search",
"method": "GET",
"parameters": {
"project_id": "{{context.project_id}}",
"query": "{{input.search_query}}",
"limit": 100
},
"output_key": "documents"
}

POST with body:

{
"id": "create_report",
"name": "Create Report",
"type": "api_call",
"endpoint": "/api/v1/reports",
"method": "POST",
"parameters": {
"title": "{{input.report_title}}",
"project_id": "{{context.project_id}}",
"content": "{{step.generate_content.content.response}}",
"category": "Safety",
"format": "Text",
"tags": ["auto-generated", "{{input.category}}"]
},
"output_key": "report"
}

Using body_source for complex payloads:

{
"id": "create_task",
"name": "Create Task via API",
"type": "api_call",
"endpoint": "/api/v1/agents/{{input.agent_id}}/tasks",
"method": "POST",
"config": {
"body_source": "step.build_payload.task_payload"
},
"output_key": "created_task"
}

2. Tool Call (tool_call)

Call built-in agent tools:

{
"id": "get_programme",
"name": "Get Project Programme",
"type": "tool_call",
"endpoint": "get_project_programme",
"parameters": {
"project_id": "{{context.project_id}}",
"include_milestones": true,
"include_tasks": true,
"include_critical_path": true
},
"output_key": "programme_data",
"on_error": "continue"
}

Available core tools:

ToolDescriptionParameters
create_project_tasksCreate tasks in a projectproject_id, tasks array
create_form_instancesCreate form instances from templatesSee form automation
submit_formSubmit values to complete a formform_instance_id, form_values
complete_form_sectionComplete a workflow sectionform_instance_id, form_section_id, form_values
search_project_usersSearch users in projectproject_id, role, search_query, limit
assign_taskAssign task to usertask_id, user_id
get_project_programmeGet programme/schedule dataproject_id

3. LLM Prompt (llm_prompt)

Execute AI prompts for analysis, generation, or transformation:

{
"id": "generate_summary",
"name": "Generate Summary",
"type": "llm_prompt",
"parameters": {
"model": "gpt-5-mini",
"fallbacks": ["gpt-5-nano"],
"temperature": 0.3
},
"prompt_template": "You are a construction safety specialist.\n\nReview the following documents:\n{{step.fetch_docs.documents}}\n\nProvide a concise summary focusing on:\n1. Key safety concerns\n2. Compliance gaps\n3. Recommended actions\n\nFormat as markdown.",
"output_key": "summary"
}

⚠️ Critical: LLM Output Structure

All LLM steps produce a standard output object:

{
"response": "<the actual generated text>",
"prompt": "<the rendered prompt sent to LLM>",
"raw_response": "<API metadata>"
}

When referencing LLM output in subsequent steps:

Correct: {{step.generate_summary.summary.response}}
Wrong: {{step.generate_summary.summary}} (returns full object with metadata)

Image generation mode:

{
"id": "create_image",
"name": "Generate Organogram Image",
"type": "llm_prompt",
"parameters": {
"model": "gemini/imagen-4.0-generate-001",
"mode": "image",
"fallbacks": ["dall-e-3"]
},
"prompt_template": "Create a professional organogram showing: {{input.structure_description}}",
"output_key": "organogram_image"
}

4. Data Transformation (data_transformation)

Transform data between steps using Jinja2 templates:

{
"id": "prepare_context",
"name": "Prepare Context",
"type": "data_transformation",
"transformation": "render_template",
"transformation_config": {
"template": "PROJECT: {{context.project_name}}\nDOCUMENTS:\n{% for doc in step.fetch_docs.documents %}* {{doc.title}} ({{doc.status}})\n{% endfor %}"
},
"output_key": "compiled_context"
}

Building JSON objects:

{
"id": "build_summary",
"name": "Build Summary Object",
"type": "data_transformation",
"transformation": "render_template",
"transformation_config": {
"template": "{\"summary\": \"Generated report for {{input.topic}}\", \"outputs\": [{\"type\": \"report\", \"id\": \"{{step.create_report.report.id}}\", \"title\": \"{{input.topic}} Report\", \"url\": \"/api/v1/reports/{{step.create_report.report.id}}\"}], \"completion_time\": \"{{now().isoformat()}}\"}"
},
"output_key": "dashboard_summary"
}

Filtering and processing arrays:

{
"transformation_config": {
"template": "{% set ns = namespace(filtered=[]) %}{% for doc in step.fetch_docs.documents %}{% if doc.status == 'APPROVED' %}{% set ns.filtered = ns.filtered + [doc] %}{% endif %}{% endfor %}{{ ns.filtered | tojson }}"
}
}

5. Form Instance Create (form_instance_create)

Create form instances for digital workflows:

{
"id": "create_signoff_form",
"name": "Create Sign-off Form",
"type": "form_instance_create",
"form_template_id": "{{input.form_template_id | default(context.default_form_id)}}",
"form_values": {
"topic": "{{input.topic}}",
"location": "{{input.location}}",
"date": "{{now().strftime('%Y-%m-%d')}}"
},
"form_config": {
"title": "Sign-off: {{input.topic}}",
"create_public_links": true
},
"condition": "{{input.create_form == true}}",
"on_error": "continue",
"output_key": "form_instance"
}

Output includes:

  • instance_id: The created form instance ID
  • public_share_url: URL for external access (if create_public_links: true)
  • status: Form status

Bulk form creation:

{
"type": "form_instance_create",
"form_template_id": "{{input.form_template_id}}",
"form_instances": [
{"form_values": {"name": "Item 1"}, "form_config": {"title": "Form 1"}},
{"form_values": {"name": "Item 2"}, "form_config": {"title": "Form 2"}}
],
"output_key": "forms"
}

6. Form Submit (form_submit)

Submit values to complete a form:

{
"id": "submit_inspection",
"name": "Submit Inspection Form",
"type": "form_submit",
"form_instance_id": "{{step.create_form.form_instance.instance_id}}",
"form_values": {
"inspector_name": "{{context.user_name}}",
"inspection_date": "{{now().strftime('%Y-%m-%d')}}",
"findings": "{{step.generate_findings.findings.response}}"
},
"output_key": "submission"
}

7. Form Section Complete (form_section_complete)

Complete a specific section in a multi-section form:

{
"id": "complete_review_section",
"name": "Complete Review Section",
"type": "form_section_complete",
"form_instance_id": "{{input.form_instance_id}}",
"form_section_id": "review_section",
"form_values": {
"reviewer_comments": "{{step.generate_review.comments.response}}",
"review_status": "APPROVED"
},
"output_key": "section_completion"
}

Step Control

Conditional Execution

{
"id": "optional_step",
"name": "Generate Extra Content",
"type": "llm_prompt",
"condition": "{{input.include_extra == true}}",
...
}
{
"condition": "{{step.fetch_docs.documents | length > 0}}"
}

Dependencies

{
"id": "final_step",
"name": "Generate Final Report",
"type": "api_call",
"depends_on": ["step_a", "step_b", "step_c"],
...
}

Error Handling

{
"id": "risky_step",
"name": "External API Call",
"type": "api_call",
"on_error": "continue",
"retry_count": 3,
...
}

Options for on_error:

  • "continue": Continue to next step
  • "stop": Halt execution
  • "retry": Retry with retry_count

Iteration

Execute a step for each item in an array:

{
"id": "process_documents",
"name": "Process Each Document",
"type": "llm_prompt",
"iterate_over": "{{step.fetch_docs.documents}}",
"prompt_template": "Summarize document: {{item.title}}\n\nContent: {{item.content}}",
"output_key": "summaries"
}

Use {{item}} for current item and {{item_index}} for 0-based index.


Templating & Variables

Available Variables

Context Variables

VariableDescription
{{context.project_id}}Current project ID
{{context.organization_id}}Current organization ID
{{context.user_id}}Executing user's ID
{{context.user_name}}Executing user's name
{{context.project_name}}Project name

Input Variables

Access user inputs: {{input.field_name}}

{{input.document_id}}
{{input.search_query | default('', true)}}
{{input.tags | join(', ')}}

Step Output Variables

Access previous step outputs: {{step.step_id.output_key}}

{{step.fetch_docs.documents}}
{{step.generate_report.content.response}}
{{step.create_report.report.id}}

Jinja2 Filters

FilterExampleDescription
default{{value | default('N/A', true)}}Fallback value
join{{list | join(', ')}}Join array
length{{items | length}}Count items
tojson{{obj | tojson}}Convert to JSON
upper / lower{{text | upper}}Case conversion
trim{{text | trim}}Remove whitespace
replace{{text | replace('a', 'b')}}String replace

Date Functions

{{now()}}                           # Current datetime
{{now().strftime('%Y-%m-%d')}} # Format date
{{now().isoformat()}} # ISO format
{{(now() - timedelta(days=7)).strftime('%Y-%m-%dT%H:%M:%SZ')}} # 7 days ago

Conditional Logic in Templates

{% if input.include_details %}
Additional details: {{input.details}}
{% endif %}

{% if step.fetch_docs.documents | length > 0 %}
Found {{step.fetch_docs.documents | length}} documents
{% else %}
No documents found
{% endif %}

Loops in Templates

{% for doc in step.fetch_docs.documents %}
- {{doc.title}} ({{doc.status}})
{% endfor %}

Best Practices

1. Task Design

  • Single purpose: Each task should do one thing well
  • Clear naming: Use descriptive names and task_ids
  • Comprehensive description: Explain what the task does and when to use it
  • Required vs optional: Only mark truly necessary fields as required
  • Default values: Provide sensible defaults where appropriate

2. Input Validation

{
"name": "email",
"type": "text",
"required": true,
"pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"placeholder": "user@example.com"
}

3. Error Handling

  • Use on_error: "continue" for non-critical steps
  • Provide fallback models for LLM steps
  • Check for empty arrays before processing
  • Use | default('', true) for optional values

4. LLM Prompts

  • Be specific about the expected output format
  • Include role/persona context
  • Provide examples when helpful
  • Request structured output (markdown, JSON) for consistency
  • Always use .response when referencing LLM output

5. Summary Step

Every task should end with a summary step:

{
"id": "summary",
"name": "Generate Summary",
"type": "data_transformation",
"transformation": "render_template",
"transformation_config": {
"template": "{\"summary\": \"Completed analysis of {{input.topic}}\", \"outputs\": [{\"type\": \"report\", \"id\": \"{{step.create_report.report.id}}\", \"title\": \"Analysis Report\", \"url\": \"/api/v1/reports/{{step.create_report.report.id}}\", \"category\": \"Analysis\"}], \"completion_time\": \"{{now().isoformat()}}\"}"
},
"depends_on": ["create_report"],
"output_key": "dashboard_summary"
}

6. Security

  • Never expose sensitive data in prompts
  • Use required_permissions appropriately
  • Validate user inputs server-side
  • Scope tasks to organization/project when appropriate

Complete Examples

Example 1: Simple Document Review

A task that reviews documents uploaded in the last N days:

{
"task_id": "recent-document-review",
"name": "Recent Document Review",
"description": "Review documents uploaded in the specified period and generate a summary report.",

"input_schema": {
"fields": [
{
"name": "period_days",
"label": "Period (Days)",
"type": "number",
"description": "Number of days to look back",
"required": false,
"default_value": 7,
"min_value": 1,
"max_value": 90
},
{
"name": "document_types",
"label": "Document Types",
"type": "multi_select",
"description": "Filter by document type",
"required": false,
"options": [
{"label": "Drawing", "value": "DRAWING"},
{"label": "Specification", "value": "SPECIFICATION"},
{"label": "Report", "value": "REPORT"}
]
}
]
},

"output_schema": {
"fields": [
{
"name": "summary",
"label": "Summary",
"type": "text",
"source": "{{step.summary.result.response}}"
},
{
"name": "report_id",
"label": "Report ID",
"type": "string",
"source": "{{step.create_report.report.id}}"
}
],
"format": "json"
},

"workflow": {
"allow_parallel": false,
"steps": [
{
"id": "fetch_documents",
"name": "Fetch Recent Documents",
"type": "api_call",
"endpoint": "/api/v1/documents/search",
"method": "GET",
"parameters": {
"project_id": "{{context.project_id}}",
"start_date": "{{(now() - timedelta(days=input.period_days | default(7))).strftime('%Y-%m-%dT%H:%M:%SZ')}}",
"document_type": "{{input.document_types | join(',') if input.document_types else ''}}",
"limit": 100
},
"output_key": "documents"
},
{
"id": "analyze_documents",
"name": "Analyze Documents",
"type": "llm_prompt",
"parameters": {
"model": "gpt-5-mini",
"fallbacks": ["gpt-5-nano"],
"temperature": 0.2
},
"prompt_template": "You are a document management specialist.\n\nReview these {{step.fetch_documents.documents | length}} documents uploaded in the last {{input.period_days | default(7)}} days:\n\n{{step.fetch_documents.documents | tojson}}\n\nProvide:\n1. Summary of document activity\n2. Key observations\n3. Any concerns or recommendations\n\nFormat as clean markdown.",
"output_key": "analysis"
},
{
"id": "create_report",
"name": "Create Report",
"type": "api_call",
"endpoint": "/api/v1/reports",
"method": "POST",
"parameters": {
"title": "Document Review - Last {{input.period_days | default(7)}} Days",
"project_id": "{{context.project_id}}",
"content": "{{step.analyze_documents.analysis.response}}",
"category": "Documents",
"format": "Text",
"tags": ["document-review", "auto-generated"]
},
"output_key": "report"
},
{
"id": "summary",
"name": "Generate Summary",
"type": "llm_prompt",
"parameters": {
"model": "gpt-5-nano"
},
"prompt_template": "Create a one-sentence summary: Reviewed {{step.fetch_documents.documents | length}} documents from the last {{input.period_days | default(7)}} days.",
"depends_on": ["create_report"],
"output_key": "result"
}
]
},

"category": "documents",
"tags": ["review", "documents", "analysis"],
"icon": "FileSearch",
"color": "#2563eb",
"active": true
}

Example 2: Toolbox Talk with Form

A task that generates a toolbox talk and creates a digital sign-off form:

{
"task_id": "toolbox-talk-generator",
"name": "Toolbox Talk Generator",
"description": "Create a toolbox talk on any safety topic with optional digital sign-off form for worker attendance.",

"input_schema": {
"fields": [
{
"name": "topic",
"label": "Topic",
"type": "text",
"description": "The safety topic for the toolbox talk",
"required": true,
"min_length": 5,
"placeholder": "e.g., Working at height, Manual handling"
},
{
"name": "audience",
"label": "Audience",
"type": "text",
"description": "Who is this talk for?",
"required": false,
"placeholder": "e.g., Scaffolders, All trades"
},
{
"name": "create_signoff_form",
"label": "Create Digital Sign-off",
"type": "boolean",
"description": "Create a form for workers to sign attendance",
"required": false,
"default_value": true
}
]
},

"workflow": {
"steps": [
{
"id": "generate_talk",
"name": "Generate Toolbox Talk",
"type": "llm_prompt",
"parameters": {
"model": "gpt-5-mini",
"temperature": 0.3
},
"prompt_template": "Create a 10-minute toolbox talk on: {{input.topic}}\n\nAudience: {{input.audience | default('General workforce')}}\n\nInclude:\n- Key hazards\n- Control measures\n- Questions for discussion\n- Key takeaways\n\nUse simple, practical language.",
"output_key": "content"
},
{
"id": "create_report",
"name": "Save as Report",
"type": "api_call",
"endpoint": "/api/v1/reports",
"method": "POST",
"parameters": {
"title": "Toolbox Talk: {{input.topic}}",
"project_id": "{{context.project_id}}",
"content": "{{step.generate_talk.content.response}}",
"category": "Safety",
"tags": ["toolbox-talk", "health-safety"]
},
"output_key": "report"
},
{
"id": "create_form",
"name": "Create Sign-off Form",
"type": "form_instance_create",
"condition": "{{input.create_signoff_form | default(true)}}",
"form_template_id": "{{context.toolbox_talk_form_template_id}}",
"form_values": {
"topic": "{{input.topic}}",
"date": "{{now().strftime('%Y-%m-%d')}}",
"report_id": "{{step.create_report.report.id}}"
},
"form_config": {
"title": "Attendance: {{input.topic}}",
"create_public_links": true
},
"on_error": "continue",
"output_key": "signoff_form"
},
{
"id": "summary",
"name": "Build Summary",
"type": "data_transformation",
"transformation": "render_template",
"transformation_config": {
"template": "{% set outputs = [{\"type\": \"report\", \"id\": step.create_report.report.id, \"title\": \"Toolbox Talk: \" ~ input.topic, \"url\": \"/api/v1/reports/\" ~ step.create_report.report.id}] %}{% if step.create_form.signoff_form.public_share_url %}{% set _ = outputs.append({\"type\": \"form\", \"id\": step.create_form.signoff_form.instance_id, \"title\": \"Sign-off Form\", \"url\": step.create_form.signoff_form.public_share_url}) %}{% endif %}{\"summary\": \"Generated toolbox talk on '{{input.topic}}'\", \"outputs\": {{outputs | tojson}}, \"completion_time\": \"{{now().isoformat()}}\"}"
},
"depends_on": ["create_form"],
"output_key": "dashboard_summary"
}
]
},

"category": "health-safety",
"tags": ["toolbox-talk", "safety", "training"],
"icon": "Shield",
"active": true
}

Example 3: Multi-Source Analysis with Conditional Steps

{
"task_id": "rams-compliance-check",
"name": "RAMS Compliance Check",
"description": "Check RAMS documents against ITP requirements with optional comparison to previous assessment.",

"input_schema": {
"fields": [
{
"name": "itp_report_id",
"label": "ITP Report",
"type": "select",
"description": "Select the pre-appointment ITP",
"required": true,
"dynamic_options": {
"url": "/api/v1/reports",
"method": "GET",
"query_params": {
"project_id": "{{context.project_id}}",
"category": "ITP",
"limit": 50
},
"data_path": "items",
"label_field": "title",
"value_field": "id"
}
},
{
"name": "rams_files",
"label": "RAMS Documents",
"type": "file_upload",
"description": "Upload RAMS documents to check",
"required": true,
"multiple": true,
"filter_by": {
"file_types": ["pdf", "docx"]
}
},
{
"name": "previous_assessment_id",
"label": "Previous Assessment (Optional)",
"type": "select",
"description": "Compare against a previous assessment",
"required": false,
"dynamic_options": {
"url": "/api/v1/reports",
"method": "GET",
"query_params": {
"project_id": "{{context.project_id}}",
"tags": "rams-assessment",
"limit": 20
},
"data_path": "items",
"label_field": "title",
"value_field": "id"
}
}
]
},

"workflow": {
"steps": [
{
"id": "fetch_itp",
"name": "Fetch ITP",
"type": "api_call",
"endpoint": "/api/v1/reports/{{input.itp_report_id}}",
"method": "GET",
"output_key": "itp"
},
{
"id": "fetch_previous",
"name": "Fetch Previous Assessment",
"type": "api_call",
"endpoint": "/api/v1/reports/{{input.previous_assessment_id}}",
"method": "GET",
"condition": "{{input.previous_assessment_id}}",
"on_error": "continue",
"output_key": "previous"
},
{
"id": "prepare_rams_content",
"name": "Prepare RAMS Content",
"type": "data_transformation",
"transformation": "render_template",
"transformation_config": {
"template": "{% for file in input.rams_files %}### {{file.filename}}\n{{file.text_content}}\n\n{% endfor %}"
},
"output_key": "rams_content"
},
{
"id": "analyze",
"name": "Analyze Compliance",
"type": "llm_prompt",
"parameters": {
"model": "gpt-5.2",
"fallbacks": ["gpt-4.1"],
"temperature": 0.2
},
"prompt_template": "You are a RAMS compliance auditor.\n\n## ITP Requirements\n{{step.fetch_itp.itp.content}}\n\n## RAMS Documents\n{{step.prepare_rams_content.rams_content}}\n\n{% if step.fetch_previous.previous %}## Previous Assessment\n{{step.fetch_previous.previous.content}}\n\nCompare with previous and note improvements/regressions.{% endif %}\n\nAudit the RAMS against the ITP. Identify gaps and weaknesses only - no recommendations.\n\nFormat:\n1. Executive Summary\n2. Compliance Gaps by ITP Section\n3. Severity Classification (Critical/Major/Minor)\n{% if step.fetch_previous.previous %}4. Change Analysis vs Previous{% endif %}",
"output_key": "analysis"
},
{
"id": "create_report",
"name": "Create Assessment Report",
"type": "api_call",
"endpoint": "/api/v1/reports",
"method": "POST",
"parameters": {
"title": "RAMS Compliance Assessment - {{now().strftime('%Y-%m-%d')}}",
"project_id": "{{context.project_id}}",
"content": "{{step.analyze.analysis.response}}",
"category": "Safety",
"tags": ["rams-assessment", "compliance", "auto-generated"]
},
"output_key": "report"
}
]
},

"category": "safety",
"tags": ["rams", "compliance", "audit"],
"required_permissions": ["documents:read", "reports:write"],
"active": true
}

API Endpoints Reference

Common Endpoints

EndpointMethodDescription
/api/v1/searchGETUnified search
/api/v1/documents/searchGETDocument search
/api/v1/documentsGETList documents
/api/v1/documents/{id}GETGet document
/api/v1/reportsGET/POSTList/create reports
/api/v1/reports/{id}GET/PATCHGet/update report
/api/v1/projects/{id}GETGet project info
/api/v1/projects/{id}/membersGETList project members
/api/v1/projects/{id}/organizationsGETList project orgs
/api/v1/forms/templatesGETList form templates
/api/v1/agents/{id}/tasksPOSTCreate task
/api/v1/agents/{id}/tasks/{task_id}PATCHUpdate task

Troubleshooting

Common Issues

1. LLM output contains metadata instead of text

❌ {{step.generate.output}}
✅ {{step.generate.output.response}}

2. Empty array in condition

"condition": "{{step.fetch.items | length > 0}}"

3. Template syntax error

  • Escape quotes in JSON: \" or use single quotes in Jinja
  • Use | default('', true) for potentially null values

4. Step not executing

  • Check condition syntax
  • Verify depends_on step IDs exist
  • Check for errors in previous steps

5. API call returning empty

  • Verify endpoint URL
  • Check method (GET vs POST)
  • Confirm parameters are templated correctly

Version History

VersionDateChanges
1.02026-01-31Initial comprehensive guide