Workflows
What workflows are
A workflow is a sequence of steps, each handled by a specialized agent, that together accomplish a complex task. Instead of one agent doing everything, workflows assign the right specialist to each step.
Example — Research & Report workflow:
Step 1 → Web Researcher agent — find sources on the topic
Step 2 → Fact Checker agent — verify the top claims
Step 3 → Summarizer agent — distill to key points
Step 4 → Report Generator agent — format as a structured document
Each step runs one after the other. If you want steps 1 and 2 to run in parallel, you configure execution_mode: parallel.
Built-in workflow templates
AI Partner ships with 9 pre-built templates ready to use immediately:
Web research → structured analysis → document. Best for market research, topic briefings, and deep dives.
Read a codebase → generate inline docs, README, and architecture notes. Best for onboarding and code handoff.
Topic research → script → thumbnails brief → SEO metadata. End-to-end video content in one run.
Research a trend → write a high-engagement LinkedIn post with hook, insight, and CTA.
Input a theme → generate 5–10 caption + visual-brief pairs ready for scheduling.
Client brief → competitive landscape → gap analysis → slide-ready findings report.
Planner-driven: the engine discovers and injects steps at runtime based on what it finds. Good for open-ended research.
Feed a JSON array (companies, URLs, topics) → one parallel research step per item → unified summary.
Writer → validator → loop back if rejected → final approved output. Demonstrates the on_validation_fail contract.
Starting a workflow
From the chat input
Type / in the chat input to open the Workflow Command Palette:
/ → shows workflow list
Research & Report
Code Review
Data Analysis
Content Creation
Competitive Analysis
Due Diligence
[+ Custom]
Select a template, describe your intent, optionally attach a document, and click Start. A live progress card appears in the conversation.
From the Workflows panel
Go to sidebar → Workflows:
- Pick a template
- Describe what you want
- (Optional) attach input files — documents, PDFs, spreadsheets, images
- Preview the step breakdown
- Click Run
The Workflows panel shows per-step agent status, live log lines, and output file previews as the pipeline runs.
Attaching input files
Click Attach files in the run form to upload one or more input documents. Files are saved as real binary files to the run's input/ workspace directory — not injected as text. Every agent in the pipeline can read them with read_file using the full workspace path that is automatically appended to each step's task.
Supported formats: .txt, .md, .csv, .pdf, .docx, .xlsx, .json, .zip, .png, .jpg, and more. Up to 10 files, 25 MB each.
Example: attach a competitor_brief.pdf before running a Due Diligence workflow. The researcher agent reads the PDF directly — no manual copy-paste.
Re-using parameters (presets)
Every time you successfully start a run, AI Partner saves the parameter values to browser storage (up to 3 per template). Next time you open the run form, click Load previous… in the header dropdown to pre-fill all fields instantly.
The Run Again button on a completed run's status banner also pre-fills the form with that run's exact parameters.
Choosing the delivery format
The run form has a Delivery format dropdown. Pick how the final deliverable is rendered:
| Format | Best for |
|---|---|
| HTML (default) | A polished, self-contained web page — opens anywhere, no dependencies |
| Print-ready A4 documents | |
PowerPoint (.pptx) | Slide decks — one slide per ## heading |
Word (.docx) | Editable documents with real headings, bullets, and tables |
Excel (.xlsx) | Tabular/data deliverables — one sheet per table |
How it works — content first, format second
Agents never generate binary files directly. Every step produces grounded markdown/json source (validated for content quality). When the run finishes, the engine runs a deterministic render step that converts the primary deliverable into the format you chose:
agent writes → output/report.md (the source — always kept)
↓ render
delivery_format = pptx → output/report.pptx (downloadable alongside the source)
This separation is deliberate: the model focuses on getting the content right, and a reliable renderer handles presentation. The markdown/json source is always kept and downloadable next to the rendered file.
Notes
- HTML, PDF, Word render from any markdown deliverable (headings, bullets, tables, paragraphs are preserved — no literal
**or#). - PowerPoint turns each
##section into a slide. - Excel needs tabular data — markdown tables or a JSON array. If the source has no tables, it gracefully falls back to HTML (a warning is included in the completion event).
- Rendering never fails a run. If a render step errors (e.g. a missing dependency), the run still completes and the markdown source is delivered, with a
render_warningin theworkflow:completedevent.
The format is chosen per run — the same template can produce a PPTX one day and a PDF the next without editing the template.
Watching a workflow run
Text progress view
The Workflows panel (and the in-chat progress card) shows:
Workflow: Competitive Analysis
Topic: B2B project management tools
Status: Running • Step 2 of 4
Step 1: Web Researcher ✅ Complete (47s) → found 12 sources
Step 2: Fact Checker 🔄 Running → verifying pricing claims
Step 3: Summarizer ⏳ Waiting
Step 4: Report Generator ⏳ Waiting
Output files: (none yet)
When complete:
Step 4: Report Generator ✅ Complete (28s)
Output files:
→ competitive_analysis_2026_05_13.docx [Download]
→ competitive_analysis_2026_05_13.xlsx [Download]
Visual canvas view
Switch to the Canvas tab in the Workflows panel to see a live node graph of the workflow:
┌─────────────────────────────────────────────────────────┐
│ [Web Researcher]──────→[Fact Checker] │
│ ✅ 47s 🔄 running │
│ │ │
│ └──────────────→[Summarizer] │
│ ⏳ waiting │
│ │ │
│ ↓ │
│ [Report Generator] │
│ ⏳ waiting │
└─────────────────────────────────────────────────────────┘
Each node shows:
- Agent profile name and avatar color
- Status — running (spinner), complete (✅), waiting (⏳), or failed (❌)
- Duration once finished
- Files produced — click any node to see files that step generated
Arrows between nodes show data dependencies. File handoff arrows (with the file icon) indicate that one step's output is passed as input to the next.
The canvas updates in real time via Socket.IO events. Click any step node to open its detailed log in a side panel.
Saving a workflow from a conversation
After any strategy discussion, analysis session, or process walkthrough in chat, you can tell the agent to save the process as a reusable template — no JSON editing or form filling needed.
Examples of what to say:
- "Save this as a workflow"
- "Create a workflow from our trading strategy discussion"
- "Make this repeatable"
- "Add this to my workflows"
The agent will:
- Summarise the repeatable process from the conversation
- Call the
create_workflow_from_contexttool — which uses the same production template generator as the built-in templates (live agent slugs from the database, connected integration status, per-role tool rules) - Validate the generated template — if validation fails, the agent refines its summary and retries once
- Save the template under your account
- Confirm with the step count and parameter names: "Workflow 'EMA Crossover Strategy' saved — 4 steps. Parameters: ticker, timeframe."
The Workflows panel refreshes automatically — the new template appears in the gallery and command palette (/) without any manual navigation.
What makes a good workflow candidate
Use this for repeatable processes — tasks you'll run again with different inputs each time:
| Good candidate | Not a workflow |
|---|---|
| Analyse a YouTube video → extract hooks → produce recreation brief | "What's the best hook for this specific video?" |
| Fetch NSE tickers → apply EMA filter → backtest → produce report | "What's the current market outlook?" |
| Scrape job postings → extract required skills → weekly skills-gap report | "Find me some Python jobs" |
The agent requires a repeatable process with variable inputs. One-shot analysis and single questions are handled by the standard chat / goal-execution path — they don't need to be workflows.
If validation fails
The agent will return the validation errors and what to fix. Refining your instructions helps:
- Be specific about steps in order — what does each phase do?
- Name the variable inputs that change per run (these become template parameters)
- Describe the output files each step should produce
Then say: "Try saving this as a workflow again." The agent retries with the improved context.
Template ownership
Templates you save from chat are yours — not visible to other users in a shared deployment. Built-in system templates are visible to everyone and cannot be deleted via the API.
Creating a custom workflow
Go to Workflows → + New Template:
- 1Name and describe the workflow
Give it a name and a description that appears in the command palette.
- 2Add steps
For each step, specify:
- Step name — e.g., "Gather competitor pricing"
- Agent profile — which specialist handles this step
- Instructions — what this agent should do with its input
- Tool whitelist — limit which tools this step can use (optional)
- Required integrations — fail early if a key is missing (optional)
- 3Set dependencies and execution mode
Use
depends_onto declare which prior steps must complete before this step starts. Steps that share no dependencies run in parallel automatically — no mode field needed.Pattern How to configure Sequential Step B lists Step A in depends_onParallel Steps A and B both list the same prior step (or nothing) — they run concurrently Fan-out (foreach) Add a foreachconfig object to the step — one parallel execution per item in a JSON arrayValidation loop Add on_validation_failto the validator step — loops back to a prior step on rejectionThere is no
execution_modefield. Parallelism is derived from thedepends_ongraph. - 4Save and use
Save the template. It appears immediately in the command palette (
/) and Workflows panel.
Example: custom due diligence workflow
Templates are JSON. Parallelism comes from depends_on — steps A and B with no shared dependency run concurrently; step C that depends on both waits for both.
{
"id": "vendor-due-diligence",
"name": "Vendor Due Diligence",
"description": "Research a vendor before signing a contract",
"parameters": [
{ "name": "company", "type": "string", "description": "Vendor company name", "required": true }
],
"steps": [
{
"id": "background",
"name": "Company Background",
"agent": "researcher",
"task": "Research {{company}}: history, founders, investors, and public revenue signals. Write findings to handoff/background.md",
"produces": ["handoff/background.md"]
},
{
"id": "news",
"name": "News & Reputation Check",
"agent": "researcher",
"task": "Find recent news, G2/Trustpilot/Glassdoor reviews, and controversy for {{company}}. Write to handoff/news.md",
"produces": ["handoff/news.md"]
},
{
"id": "financials",
"name": "Financial Health Check",
"agent": "analyst",
"task": "Find funding history, last valuation, and profitability signals for {{company}}. Write to handoff/financials.md",
"produces": ["handoff/financials.md"]
},
{
"id": "summary",
"name": "Risk Summary",
"agent": "writer",
"task": "Read handoff/background.md, handoff/news.md, handoff/financials.md. Write a 1-page risk summary with a Go/No-Go recommendation to output/risk-summary.md",
"depends_on": ["background", "news", "financials"],
"consumes": ["handoff/background.md", "handoff/news.md", "handoff/financials.md"],
"produces": ["output/risk-summary.md"]
}
],
"output_files": ["output/risk-summary.md"]
}
background, news, and financials have no shared dependency so they run in parallel. summary waits for all three.
Foreach mode example
Use foreach to run the same analysis across multiple items in parallel:
Run the Competitive Analysis workflow for these companies:
Asana, Monday.com, ClickUp, Notion, Linear
With foreach mode on the research step:
- 5 parallel Web Researcher agents run simultaneously
- Each handles one company
- The Summarizer step waits for all 5 to finish
- The Report Generator produces one unified comparison document
Workflow vs. single goal
| Single goal | Workflow | |
|---|---|---|
| Best for | Ad-hoc, one-off tasks | Repeatable, structured processes |
| Agent count | 1 main + up to 5 sub-agents | Defined specialist per step |
| Output | Whatever the goal produces | Structured per-step outputs |
| Reuse | Learned as a skill | Reused as a template |
| Control | Goal-level pause/cancel | Per-step visibility and control |
Use a single goal for "research NVIDIA earnings". Use a workflow for "every Friday, research our top 5 competitors and produce a weekly brief".
Determinism + intelligence — what makes workflows different
AI Partner workflows are a deterministic pipeline of intelligent agents. Two ideas matter:
- The pipeline shape is your contract. You author the DAG: which steps run, in what order, with what dependencies. The engine never re-orders or invents steps. n8n / Zapier work the same way at this layer.
- Each node is an agent, not a deterministic API call. Inside the step's
tool_whitelist, the agent picks tools, retries on its own, decides which prompt structure to write, and adapts to what the data actually looks like. n8n nodes can't do this.
The result: predictable orchestration, intelligent execution.
A few specific engine behaviours follow from this contract:
Steps run autonomously
Workflow steps run with approvalMode='none'. The engine does NOT pause for human approval when the agent calls run_command, write_file, or any tool inside its scoped whitelist. Declaring the step in the template IS the authorization.
What still surfaces to you:
- Tools in the engine's
alwaysDenylist (payments, table drops, etc.) are blocked regardless. - Browser CAPTCHA / login walls trigger HITL via the partner-mode browser control state machine — these are genuinely machine-impossible blockers.
If a step needs a human gate, have the agent call request_user_approval explicitly as part of its task.
Tools are scoped per step
Every step in a built-in template declares a tool_whitelist listing exactly the tools that step's agent can call. A researcher step can't accidentally send_email; a writer step can't delete_file. This is the contract layer between "what the step is supposed to do" and "what it can actually do."
When you author your own templates, start from the default tool set for the agent's role and loosen it only when a specific step genuinely needs a tool that isn't included.
Retries don't double-fire side-effects
The engine keeps a per-step ledger. If a workflow is paused and resumed, or on_failure: "retry" triggers, it checks the ledger first — a "completed" step returns its cached result instead of relaunching the agent, so a step that sent an email or posted to Slack will NOT re-send on retry.
Side-effect-heavy steps are therefore safe to mark on_failure: "retry".
Integration calls produce audit receipts
Any step that calls a known integration tool (messaging_send, slack_send_message, twitter_post, gmail_send, create_pr, etc.) automatically gets a receipt captured on its StepResult:
{
"tool": "slack_send_message",
"result_id": "1734522345.000100",
"recipient": "#announcements",
"content_hash": "9c4f81a3b…",
"timestamp": "2026-05-19T14:22:10.123Z"
}
Receipts appear in the run-detail UI under each step's panel. They give you the channel's returned id (message_id, post_url, etc.), recipient, and a content hash for verification.
Step execution
Each workflow step is dispatched as a single scoped task to a sub-agent. There is no goal-decomposition pass — the step's task description is passed directly to the agent without an additional planning call.
This keeps steps deterministic and cheap:
| Property | Value |
|---|---|
| Agent instances per step | 1 |
| LLM calls before first tool | 1 (the agent's first ReAct reason call) |
| Re-decomposition | None — the template IS the decomposition |
| Workspace path | <workspace>/runs/<runId>/ — no cascading |
| Sub-delegation | Disabled (noSubDelegate: true) |
The workspaceRoot from run.workspace_root flows directly into the step's stepContract. Every file path the agent writes lands at <workspace>/runs/<runId>/handoff/<file> (or wherever the step task says), never at the global /workspace/handoff/.
Produces gates — how steps are validated
When a step declares produces[], the engine converts each path into a StepGate:
{ "path": "handoff/trend-analysis.md", "minBytes": 1, "maxAgeMs": 3600000 }
After the agent finishes, verifyProducesGates() checks each gate: file must exist, meet the minimum size, and have been written within the step's time window. A gate failure marks the step as failed and triggers the step's on_failure handler.
Because the agent is blocked from returning until it produces the required files (via the stepContract.gates list), produces verification and agent-level completion are guaranteed to agree.
For quality gating beyond existence/size checks, use a dedicated validator step and declare on_validation_fail on it — this loops back to a specified prior step (e.g., a writer) when the validator rejects output. See Validation Loop below.
Validation loop pattern
Add on_validation_fail to a validator step to loop back to a prior step when it rejects output:
{
"id": "validate",
"name": "Validate Report",
"agent": "validator",
"task": "Read output/report.md. If it meets the quality bar write APPROVED on line 1. Otherwise write REJECTED and your reason.",
"depends_on": ["write"],
"consumes": ["output/report.md"],
"produces": ["handoff/validation.md"],
"on_validation_fail": {
"goto": "write",
"max_loops": 3,
"inject_feedback": true
}
}
| Field | Description |
|---|---|
goto | Step ID to jump back to when validation fails |
max_loops | Maximum retry iterations before the workflow fails |
inject_feedback | If true, the validator's rejection reason is injected into the retry agent's context |
Structured handoff contracts
Plain string consumes / produces entries do a basic existence check. For stricter contracts use ProducesGate objects and ConsumeRef objects — they add schema validation, resolved path injection, and hard-fail attribution when a contract is broken.
ProducesGate — typed output declaration
"produces": [{
"path": "handoff/data.json",
"alias": "market_data",
"format": "json",
"json_keys": ["title", "summary", "key_findings"],
"min_size": 50
}]
| Field | Description |
|---|---|
path | Workspace-relative path (required) |
alias | Logical name referenceable by downstream ConsumeRef entries |
format | json | csv | markdown | text — informs schema gates and agent context |
json_keys | Top-level JSON keys that must exist — fails the step if any are missing |
csv_columns | CSV header column names that must exist — fails the step if any are missing |
min_size | Minimum file size in bytes (default: 1) |
must_contain | Regex (gims) that file content must match |
must_be_fresh | File mtime must be after step start — rejects stale files (default: true) |
ConsumeRef — typed input reference
"consumes": [{
"from_step": "produce_data",
"alias": "market_data",
"inject_as": "market_data_path"
}]
| Field | Description |
|---|---|
from_step | ID of the step that declared the alias in its produces gate |
alias | Matches ProducesGate.alias on the producing step |
inject_as | Optional: {{inject_as}} is substituted in the step's task with the resolved absolute path |
Unlike plain string consumes (which auto-skip when a file is missing), a ConsumeRef that can't be resolved causes the step to hard-fail with attribution — a missing typed alias is a contract violation, not a transient condition.
The agent's task context also includes a schema hint:
- /workspace/runs/abc/handoff/data.json [file from "produce_data" (alias: market_data), format: json, JSON keys: [title, summary, key_findings]] (substituted as {{market_data_path}} above)
Full 2-step example
{
"steps": [
{
"id": "research",
"name": "Research",
"agent": "researcher",
"task": "Research {{topic}}. Write a JSON file to handoff/data.json with keys: title, summary, key_findings.",
"produces": [{
"path": "handoff/data.json",
"alias": "research_data",
"format": "json",
"json_keys": ["title", "summary", "key_findings"],
"min_size": 50
}]
},
{
"id": "write",
"name": "Write Report",
"agent": "writer",
"task": "Read the research from {{research_data_path}} and write a report to output/report.md.",
"depends_on": ["research"],
"consumes": [{ "from_step": "research", "alias": "research_data", "inject_as": "research_data_path" }],
"produces": ["output/report.md"]
}
]
}
Plain string consumes / produces remain fully supported — no changes needed for existing templates.
Live feed — workflow:step:log
While a step is running, the server emits a workflow:step:log Socket.IO event after every tool call:
{
"runId": "abc123",
"stepId": "trend_research",
"tool": "write_file",
"summary": "Wrote 3 KB to handoff/trend-analysis.md",
"success": true,
"iteration": 4
}
The Workflows panel subscribes to these events and renders a per-tool log line in the Live Action Feed panel. No polling — updates are pushed in real time.
Reasoning-notes handoff between steps
After each step finishes, its agent leaves a brief reasoning summary at handoff/.<step_id>_notes.md. When the next step launches, that note is injected into the agent's task as context. So each step doesn't start cold — it inherits what the previous specialist found, what it decided, and what to pay attention to.
You don't configure this. It's enabled for every workflow step automatically.
The publisher agent — multi-channel delivery
For workflows that end in "send a message" / "post to Slack" / "tweet this" / "email the team", use the publisher agent profile. It:
- Reads pre-approved content from a file (never edits it)
- Picks the right channel tool based on the step's task instructions (
slack_send_message,twitter_post,gmail_send, ormessaging_sendfor Telegram/Discord/WhatsApp/Signal) - Writes a receipt JSON to
output/<step-id>-receipt.jsonfor audit and retry safety
Example step:
{
"id": "notify_team",
"name": "Notify Team",
"agent": "publisher",
"tool_whitelist": ["read_file", "write_file", "create_directory",
"messaging_send", "slack_send_message"],
"required_integrations": ["slack"],
"depends_on": ["write_report"],
"consumes": ["output/report.md"],
"task": "Read output/report.md. Post a 2-line summary with the report link to the #announcements Slack channel.",
"produces": ["output/notify-receipt.json"]
}
For Telegram-only workflows the legacy telegram-reporter profile still works, but prefer publisher for new templates — it handles all channels uniformly.
Scheduling recurring workflow runs
Every template card in the Workflows gallery has a calendar icon (hover to reveal). Clicking it opens the Schedule modal:
- Choose a frequency: Daily at 9 AM, Weekdays at 9 AM, Monday at 9 AM, Every hour, or Custom (enter any valid cron expression)
- Fill in the template's parameters — these are fixed for every scheduled run
- Give the scheduled task a name
- Click Schedule
The task is registered in the Task Scheduler with mode: workflow. It fires at each cron tick exactly like a manually started run — a new run is created, the workspace is initialized, and agents execute step by step.
You can view, edit, pause, or delete scheduled workflow tasks in sidebar → Task Scheduler.
Example: schedule the Competitive Analysis workflow every Monday at 9 AM with niche: SaaS project management tools so a fresh brief is ready every week without any manual action.
Cost visibility
After each step completes, the engine queries the LLM usage log and attaches the cost to the step result. The Workflows panel shows:
- Per step:
$0.003label next to the step duration in the step list - Run total: total cost in the green completion banner (e.g.,
$0.04)
Cost tracking works for any LLM provider — OpenAI, Groq, DeepSeek, Anthropic, local Ollama (where cost is $0.00). The values come from estimated_cost in the llm_usage table.
Completion callbacks
If you want to be notified when a run completes without keeping the browser open, expand POST callback on completion in the run form footer and enter a URL. When the run finishes (success or failure), AI Partner sends a JSON POST:
{
"runId": "wf_run_1748123456_a1b2c3d4",
"status": "completed",
"templateId": "competitive-analysis",
"completedAt": "2026-05-21T09:14:22.000Z",
"error": null
}
Use this to chain into Zapier, Make, or any webhook endpoint. The POST is fire-and-forget — a delivery failure does not affect the run.
Concurrent run limit
By default, a maximum of 3 workflow runs can be active simultaneously. Starting a 4th returns:
Concurrency limit reached (3 active runs). Try again shortly.
Your administrator can change this limit in the server configuration.
Deleting old runs
The Workflows gallery shows past runs in the History tab. Each run in a terminal state (completed / failed / cancelled) has a trash icon: clicking it removes the DB record and the workspace directory under runs/<runId>/. Active or paused runs don't show delete — cancel them first.