> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modulex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Run your first workflow

> Build your first ModuleX workflow with no code — describe it to the AI Composer or drag nodes onto the canvas, then run it and watch the live result stream in.

export const MediaEmbed = ({id, type = 'screenshot', caption = '', ext, ratio = '16 / 9'}) => {
  const isVideo = type === 'video' || type === 'app_video';
  const resolvedExt = ext || (isVideo ? 'mp4' : type === 'screenshot' ? 'webp' : 'svg');
  const src = 'https://media.modulex.dev/' + id + '.' + resolvedExt;
  const [status, setStatus] = useState('loading');
  const [isDev, setIsDev] = useState(false);
  const [inView, setInView] = useState(false);
  const boxRef = useRef(null);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const h = window.location.hostname;
    setIsDev(h === 'localhost' || h === '127.0.0.1' || h.endsWith('.mintlify.app'));
  }, []);
  useEffect(() => {
    if (inView) return;
    if (typeof IntersectionObserver === 'undefined') {
      setInView(true);
      return;
    }
    const el = boxRef.current;
    if (!el) return;
    const io = new IntersectionObserver(entries => {
      if (entries.some(e => e.isIntersecting)) {
        setInView(true);
        io.disconnect();
      }
    }, {
      rootMargin: '300px'
    });
    io.observe(el);
    return () => io.disconnect();
  }, [inView]);
  if (status === 'missing') {
    if (!isDev) return null;
    return <div style={{
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      gap: '0.4rem',
      padding: '1rem 1.25rem',
      margin: '1.25rem 0',
      width: '100%',
      aspectRatio: ratio,
      boxSizing: 'border-box',
      border: '1px dashed rgba(128,128,128,0.45)',
      borderRadius: '0.75rem',
      background: 'rgba(128,128,128,0.06)',
      color: 'currentColor',
      fontSize: '0.85rem',
      lineHeight: 1.45
    }}>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '0.5rem',
      opacity: 0.75
    }}>
          <span aria-hidden="true">🎬</span>
          <code style={{
      fontSize: '0.75rem'
    }}>{id}</code>
          <span style={{
      fontSize: '0.65rem',
      textTransform: 'uppercase',
      letterSpacing: '0.04em',
      padding: '0.1rem 0.4rem',
      borderRadius: '0.4rem',
      background: 'rgba(128,128,128,0.18)'
    }}>
            {type}
          </span>
        </div>
        <div style={{
      opacity: 0.9
    }}>{caption || 'Media not uploaded yet.'}</div>
        <div style={{
      fontSize: '0.7rem',
      opacity: 0.5
    }}>
          Upload to R2 as <code>{id}.{resolvedExt}</code> — preview only, hidden in production.
        </div>
      </div>;
  }
  const mediaStyle = {
    display: status === 'loaded' ? 'block' : 'none',
    width: '100%',
    height: 'auto',
    borderRadius: '0.75rem'
  };
  const media = isVideo ? <video src={inView ? src : undefined} autoPlay loop muted playsInline preload="metadata" onLoadedData={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} /> : <img src={inView ? src : undefined} alt={caption} onLoad={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} />;
  return <figure style={{
    margin: '1.25rem 0'
  }}>
      <div ref={boxRef} style={status === 'loaded' ? {
    width: '100%'
  } : {
    width: '100%',
    aspectRatio: ratio,
    borderRadius: '0.75rem',
    background: 'rgba(128,128,128,0.06)'
  }}>
        {media}
      </div>
      {status === 'loaded' && caption ? <figcaption style={{
    marginTop: '0.5rem',
    textAlign: 'center',
    fontSize: '0.85rem',
    opacity: 0.7
  }}>
          {caption}
        </figcaption> : null}
    </figure>;
};

This is the fastest way to see ModuleX work end to end. You will create a workflow in the
[workflow builder](/workflow-builder/overview), run it, and watch each step report its result
live — all without writing code or touching the API.

You have two ways to build, and you can mix them:

<CardGroup cols={2}>
  <Card title="Describe it to the AI Composer" icon="sparkles">
    Type what you want in plain English. The [AI Composer](/concepts/ai-composer) generates an
    editable workflow on the canvas for you.
  </Card>

  <Card title="Build it by hand on the canvas" icon="hand-pointer">
    Drag [nodes](/workflow-builder/nodes/overview) onto the [canvas](/workflow-builder/canvas)
    and connect them yourself. Full control, no AI.
  </Card>
</CardGroup>

<MediaEmbed id="MX-MEDIA-1040" type="app_video" caption={"A complete no-code first-workflow walkthrough: open the builder, describe a workflow to the Composer, watch it build the canvas, click Run, and watch the live stream finish."} />

## Before you start

<Steps>
  <Step title="Sign in to the ModuleX app">
    Open the app and sign in. If this is your first time, create an account and an
    organization — every workflow belongs to an organization.
  </Step>

  <Step title="Open the workflow builder">
    Go to the workflow builder. If you have no workflows yet, you will see an empty state with a
    **Create your first workflow** button.
  </Step>
</Steps>

<Note>
  Building and running workflows in the app requires an **owner** or **admin** role in your
  organization. If you do not have it, ask an organization owner to grant access. See
  [organizations, roles & membership](/concepts/organizations-roles).
</Note>

## Option A — Describe it to the Composer

The [AI Composer](/concepts/ai-composer) turns a plain-English description into a real,
editable workflow on the canvas. It is the quickest way to get a working draft.

<Steps>
  <Step title="Create a workflow and open the Composer">
    From the builder, create a new workflow. The right-hand panel includes a **Chat** tab — this
    is the Composer.
  </Step>

  <Step title="Describe what you want">
    Type a request in your own words, for example:

    ```text Example Composer prompt theme={null}
    Create a workflow that summarizes the input text and posts the summary to a Slack channel.
    ```

    The Composer streams its work back to you: you will see it plan, add nodes, connect them, and
    explain what it changed.
  </Step>

  <Step title="Answer any questions it asks">
    The Composer may pause to ask you something — for example, which option to use or to connect a
    credential for an integration like Slack. Answer in the chat and it continues. This pause-and-ask
    behavior is [human-in-the-loop](/concepts/ai-composer); the Composer waits for your reply before
    moving on.
  </Step>

  <Step title="Keep or undo the changes">
    When the Composer finishes, its edits appear on the canvas as **pending changes**. Use **Save**
    to keep them or **Revert** to roll back to the previous version. Nothing is permanent until you
    save.
  </Step>
</Steps>

<Tip>
  The Composer edits a real workflow graph, not a throwaway preview. After it finishes you can keep
  refining by hand on the canvas, or ask it for more changes in the same chat. For a longer,
  guided build, see [build a workflow with Composer](/guides/build-with-composer).
</Tip>

<MediaEmbed id="MX-MEDIA-1041" type="app_video" caption={"The Composer generating a workflow from a single prompt and pausing once to ask the user to connect a credential."} />

## Option B — Build it by hand on the canvas

Prefer to drive it yourself? Build directly on the [canvas](/workflow-builder/canvas).

<Steps>
  <Step title="Add nodes">
    Drag [nodes](/workflow-builder/nodes/overview) from the node dock onto the canvas. Each node is
    one step. Common starting points:

    <CardGroup cols={2}>
      <Card title="LLM node" icon="message-square" href="/workflow-builder/nodes/llm">
        Call a language model with a prompt to draft, summarize, or classify text.
      </Card>

      <Card title="Tool node" icon="plug" href="/workflow-builder/nodes/tool">
        Call an integration action, such as sending a Slack message or creating a record.
      </Card>

      <Card title="Knowledge node" icon="book-open" href="/workflow-builder/nodes/knowledge">
        Retrieve relevant context from a knowledge base.
      </Card>

      <Card title="Conditional node" icon="git-branch" href="/workflow-builder/nodes/conditional">
        Branch the flow or loop over a list of items.
      </Card>
    </CardGroup>
  </Step>

  <Step title="Connect the steps">
    Draw an edge from the **start** marker into your first node, then connect each node to the next.
    The start marker is added for you — you connect your steps to it. Every node passes its result
    forward so later steps can use it.
  </Step>

  <Step title="Configure each node">
    Select a node to open the detail panel and fill in its settings — the prompt for an LLM node, the
    action and inputs for a tool node, and so on. If a node needs a connected account, the builder
    flags it so you can connect a [credential](/integrations/authentication) before running.
  </Step>
</Steps>

<Tip>
  The canvas validates as you build. It will flag a node that has no path from the start marker, a node
  that is missing a required credential, or a knowledge node with no query — so you can fix issues
  before you run.
</Tip>

## Run it and watch the stream

When your workflow is ready, run it from the builder and watch each step report back in real time.

<Steps>
  <Step title="Click Run">
    Select **Run**. If your workflow takes input, enter the values it asks for first. The builder
    runs the workflow exactly as it appears on your canvas — you do not need to deploy it first to
    test it.
  </Step>

  <Step title="Watch the live stream">
    Each node moves through **pending → running → completed** as the run progresses, and its output
    appears as it finishes. Behind the scenes this is a live event stream, so you see results arrive
    step by step rather than waiting for the whole run to end.
  </Step>

  <Step title="Respond if the workflow pauses">
    If your workflow includes an [interrupt node](/workflow-builder/nodes/interrupt), the run pauses
    and asks you a question. Answer it and the run continues from where it stopped — it stays the same
    run.
  </Step>

  <Step title="Inspect the result">
    When the run finishes, open the node outputs to see what each step produced. The **Runs** panel
    keeps a history of past runs so you can revisit any of them.
  </Step>
</Steps>

<MediaEmbed id="MX-MEDIA-1042" type="app_video" caption={"A workflow running in the builder with node statuses updating live and outputs appearing as each step completes."} />

### What if a run is blocked?

Some steps use ModuleX-managed models and storage, which are metered in
[credits](/concepts/credits-billing). If your organization has run out of its plan allowance and
has no wallet balance to cover the overage, a run can be refused before it starts — you will see a
billing message instead of a run, and nothing is charged. To fix it, top up or upgrade. Learn how
this works in [usage gating & limits](/billing/usage-gating).

<Note>
  Using your own provider keys (BYOK) is not metered in credits. Managed models and managed knowledge
  are. See [credits & the billing model](/concepts/credits-billing) for what consumes credits.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Tour the workflow builder" icon="layout-dashboard" href="/workflow-builder/overview">
    Learn the canvas, nodes, and controls in depth.
  </Card>

  <Card title="Build with the Composer" icon="sparkles" href="/guides/build-with-composer">
    A full walkthrough from prompt to running workflow.
  </Card>

  <Card title="Run a workflow from chat" icon="message-circle" href="/platform/chat/workflow-run">
    Trigger and watch a run directly inside a chat.
  </Card>

  <Card title="Run a workflow from code" icon="terminal" href="/get-started/first-api-call">
    Do the same thing programmatically with cURL, Python, or JavaScript.
  </Card>
</CardGroup>
