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