timescale/crayon · Archived

create-workflow

Collaborative workflow design - guides users through creating well-structured crayon workflows with embedded descriptions.

First seen Jun 22, 2026

Installation

$ npx skills add timescale/crayon --skill create-workflow

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from timescale/crayon.

npx skills add timescale/crayon

Browse all from timescale/crayon

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 8
Default branch main
Open issues 0
Status Archived

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 10,443 B
  • docs SUMMARY.md 145 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

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__plugincrayoncrayon-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.

  1. 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.
  1. 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

  1. 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

// src/crayon/workflows/<name>.ts
// Auto-generated by create-workflow skill
import { z } from "zod";
import { Workflow } from "runcrayon";
// ... node/agent imports (NEVER use .js extensions — use extensionless imports) ...

const <Name>InputSchema = z.object({
  // ... from workflow inputs (use z.string(), z.number(), etc. — best guess from descriptions)
});
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> {
    // Task 1: Task Name
    const result1 = await ctx.run(<nodeRef>, { /* inputs */ });

    // Task 2: Another Task
    // ...

    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:

// src/crayon/nodes/<name>.ts
import { z } from "zod";
import { Node } from "runcrayon";

export const <camelCaseName> = Node.create({
  name: "<kebab-case-name>",
  // integrations: ["salesforce"],  // declare if this node needs external credentials
  description: `
<What this node does.>

**Input Description:** <plain language>

**Output Description:** <plain language>
`,
  inputSchema: z.object({}),
  outputSchema: z.object({}),
  async execute(ctx, input) {
    // TODO: implement
    return {} as any;
  },
});

For (agent) tasks → src/crayon/agents/<name>.ts + src/crayon/agents/<name>.md:

// src/crayon/agents/<name>.ts
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"],  // declare AI provider + any external services; keys fetched from Nango at runtime
  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

  1. Draft first, ask later — make your best guess and let the user correct, rather than interrogating upfront
  2. Concrete over abstract — push for specific conditions, not vague descriptions (e.g., score >= 80 not "if it's good")
  3. Leverage existing — prefer reusing existing agents/nodes over creating new ones
  4. What, not how — capture intent in plain language; implementation details come during refinement
  5. Run it yourself — when the user wants to test a workflow or node, use the runWorkflow / runNode MCP tools or run CLI commands yourself.
  6. 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.