| name | create-workflow |
| description | Collaborative workflow design - guides users through creating well-structured crayon workflows with embedded descriptions. |
Create Workflow
Design and write a workflow with embedded description fields for crayon.
Pre-flight check
1. Detect Project Type
Check the current working directory and handle one of three cases:
Case 1: Empty directory (no files, or only dotfiles like .git)
→ Tell the user this skill must be run inside a crayon project. Stop here.
Case 2: Existing crayon project (has src/crayon/workflows/ or src/crayon/agents/ directories)
→ Good to go. Continue to step 2.
Case 3: Existing non-crayon directory (has files/projects but no crayon structure — e.g., home directory, another repo)
→ Tell the user this skill must be run from inside a crayon project directory. Stop here.
2. Discover Integrations
IMPORTANT Do this step only after step 1 (scaffolding) is done.
Call mcp__plugin_crayon_crayon-local-tools__list_integrations to see what external integrations are available (Salesforce, Slack, HubSpot, etc.). This authenticates via crayon cloud and may open a browser for login if not yet authenticated.
CRITICAL: If the tool returns an error (authentication failure, empty response, etc.), you MUST stop immediately. Do NOT continue with any further steps. Do NOT offer to create the workflow without integrations. Do NOT skip this step.
Tell the user the list_integrations call failed and suggest they try running crayon login from their terminal if the automatic browser auth didn't work, then run /crayon:create-workflow again.
Then stop. Do not proceed to any subsequent steps.
Once the tool succeeds, the returned integration IDs are what nodes declare in their integrations: [...] arrays.
IMPORTANT — stay in design mode: Do NOT read integration-specific guides (e.g., integrations/salesforce), call get_connection, or research SDKs/libraries during this phase. You only need the integration IDs for node stub integrations: [...] arrays. All integration research and connection checks happen later in /crayon:refine-node.
3. Read Existing Context
- Read
src/crayon/workflows/*.ts — existing workflows to reuse or reference
- Read
src/crayon/agents/*.md — existing agents that could be reused
- Ensure
src/crayon/workflows/ and src/crayon/agents/ directories exist
Writing the Workflow (Incremental — file watcher updates live)
Once the flow is approved, write the workflow incrementally as TypeScript with embedded description fields. The file watcher picks up changes automatically — no compile step needed per-task.
This phase focuses on WHAT each node does, not HOW. Capture purpose and intent in plain language. Implementation details (exact fields, API schemas, tool configs) are handled later by /crayon:refine-node.
Step-by-step
IMPORTANT: Write one node at a time, not all at once. The file watcher picks up changes — each save updates the graph live. Batch-writing all nodes defeats this and gives the user no chance to see the workflow take shape.
-
Write the workflow file — create src/crayon/workflows/<name>.ts with the scaffold template below, including a flow-only description field and an empty run() method. Import nothing yet.
-
For each task in order (one at a time — save the workflow file after each):
a. Create the node/agent stub file with its own description field (see Node Stub Creation below)
b. Add the import to the workflow file
c. Add the task to the workflow's description field
d. Add the ctx.run() call to the workflow's run() method
e. Save the workflow file — the graph gains a new node immediately
-
After all tasks are written:
a. Save a version — Call the create_version MCP tool with a message like:
Scaffold workflow: <workflow-name>
<Describe what changed — like a good git commit message body.>
b. Immediately invoke /crayon:refine-node to add typed schemas and implementation details. Do NOT ask the user — just proceed directly.
Workflow Scaffold Template
import { z } from "zod";
import { Workflow } from "runcrayon";
const <Name>InputSchema = z.object({
});
type <Name>Input = z.infer<typeof <Name>InputSchema>;
const <Name>OutputSchema = z.object({});
type <Name>Output = z.infer<typeof <Name>OutputSchema>;
export const <camelCaseName> = Workflow.create({
name: "<kebab-case-name>",
version: 1,
description: `
<One-line summary of what the workflow does.>
## Tasks
### 1. Task Name
**Node:** \`node-name\` (node|agent)
### 2. Another Task
**Node:** \`another-node\` (agent)
**Loop:** for each item in items
`,
inputSchema: <Name>InputSchema,
outputSchema: <Name>OutputSchema,
async run(ctx, inputs: <Name>Input): Promise<<Name>Output> {
const result1 = await ctx.run(<nodeRef>, { });
return {} as <Name>Output;
},
});
Workflow Description Format (flow-only)
The workflow description field captures only flow-level concerns — task ordering, conditions, decisions, loops. Node-specific details live in the node's own description field.
<One-line summary>
## Tasks
### 1. Task Name
**Node:** `node-name` (agent|node)
### 2. Decision Name
**Condition:** `variable.field >= value`
**If true:** continue to task 3
**If false:** return early with outputs
### 3. Loop Task
**Node:** `loop-node` (agent)
**Loop:** for each lead in leads
### 4. Final Task
**Node:** `final-node` (node)
**Return:** (describe what the workflow returns)
Node Description Format (node-specific)
Each node/agent's description field captures what that node does, its inputs and outputs in plain language.
<What this node does — one or two sentences.>
**Input Description:** <what information this task needs>
**Output Description:** <what this task produces>
For nodes with side effects (sending messages, updating records, writing data), use this extended format:
<What this node does — one or two sentences.>
**Side Effect:** <what external action is performed and the target>
**Test Mode:** <what happens when ctx.testMode is true — typically "Returns the <action details> without actually <performing the action>">
**Input Description:** <what information this task needs — include target if dynamic>
**Output Description:** <what this task produces — MUST include action details (e.g., messageSent, recipient, fieldsUpdated, testMode)>
The **Side Effect:** tag marks the node as having side effects so the compiler generates ctx.testMode guards. The **Test Mode:** description spells out the exact expected behavior to reduce ambiguity in code generation.
Node Stub Creation
For each task in the workflow, create a stub file:
For (node) tasks → src/crayon/nodes/<name>.ts:
import { z } from "zod";
import { Node } from "runcrayon";
export const <camelCaseName> = Node.create({
name: "<kebab-case-name>",
description: `
<What this node does.>
**Input Description:** <plain language>
**Output Description:** <plain language>
`,
inputSchema: z.object({}),
outputSchema: z.object({}),
async execute(ctx, input) {
return {} as any;
},
});
For (agent) tasks → src/crayon/agents/<name>.ts + src/crayon/agents/<name>.md:
import { z } from "zod";
import { Agent } from "runcrayon";
import { fileURLToPath } from "url";
import path from "path";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export const <camelCaseName> = Agent.create({
name: "<kebab-case-name>",
integrations: ["openai"],
description: `
<What this agent does.>
**Input Description:** <plain language>
**Output Description:** <plain language>
`,
inputSchema: z.object({}),
outputSchema: z.object({}),
tools: {},
specPath: path.resolve(__dirname, "./<name>.md"),
});
Also create the agent spec file src/crayon/agents/<name>.md (colocated with the agent code):
---
name: <agent-name>
---
# <Agent Title>
<Brief description of what the agent does>
## Task
<Derived from description>
## Guidelines
- Prefer primary sources over aggregators
- If information is unavailable, say so rather than guessing
- Keep output structured and consistent
## Output Format
Return a JSON object with:
- TODO: define fields during refinement
Node Types
| Type | When to use |
|---|
(agent) | Needs AI reasoning/judgment |
(node) | Deterministic function or API call |
Built-in nodes: web_read
Naming Conventions
- Workflow names: lowercase with hyphens (e.g.,
lead-scoring)
- Node names: lowercase with hyphens (e.g.,
company-researcher)
Principles
- Draft first, ask later — make your best guess and let the user correct, rather than interrogating upfront
- Concrete over abstract — push for specific conditions, not vague descriptions (e.g.,
score >= 80 not "if it's good")
- Leverage existing — prefer reusing existing agents/nodes over creating new ones
- What, not how — capture intent in plain language; implementation details come during refinement
- Run it yourself — when the user wants to test a workflow or node, use the
runWorkflow / runNode MCP tools or run CLI commands yourself.
- Side effects require intentional targets — nodes that send messages, update records, or write to external systems must name WHO/WHERE the action targets. The target should either be traced to a workflow input / upstream node output, or be a deliberate constant with clear rationale. Never fabricate or randomly choose a target.