DEV Community

ByteChef
ByteChef

Posted on Originally published at blog.bytechef.io

Turn One Sentence Into a Working Automation: Prompt-to-Workflow in Your SaaS

Originally published on the ByteChef blog. Part 10 of the ByteChef Embedded series.

Some automation requests are fuzzy. Those deserve a conversation. But a lot of them aren't:

"When a lead comes in, post it to #sales and email them a welcome note."

That's already a full spec. A chat would only slow the user down.

So we built New from Prompt: the user writes a sentence, clicks Generate, and gets a finished, validated workflow back. Your app makes one HTTP call. No streaming, no transcript, no client-side AI code.

Here's how it works and what it takes to ship it in your own product.

TL;DR

  • One request: POST /api/embedded/v1/automation/workflows/generate with {prompt, systemPrompt?}, signed with the connected user's JWT.
  • ByteChef creates a draft workflow in the user's own project, runs its workflow agent in autonomous mode, and returns the new workflow's UUID once it's built and validated.
  • The agent only uses integrations you enabled plus connection-free components (webhooks, schedules, conditions, loops).
  • The result is a draft. Nothing runs until the user reviews and publishes it.

Where it fits

ByteChef Embedded gives your users five ways to create a workflow:

Create menu in the sample app

Option The user... Best when
New from Template Picks a workflow you built You know the common automations up front
New from Embedded Workflow Builder Drags nodes on ByteChef's canvas The user is comfortable with visual builders
New from Prompt Writes one description, gets one workflow The request is short and clear
New from Chat Talks it through with an agent The request is fuzzy
New from Custom Workflow Builder Fills in a UI you designed You want full control

Prompt is the lowest-effort AI option, for the user and for you.

The dialog

Two fields: what the user wants, and an optional system prompt with your house rules.

Empty Generate Workflow dialog

The form rejects anything under ten characters, so "Slack" alone doesn't hit the server:

Validation error

While ByteChef works, the button reads "Generating...". When the UUID comes back, the dialog closes and the list reloads. Our lead workflow took 47 seconds.

Dialog while generating

Workflow list after generation

The component is a plain react-hook-form dialog:

const formSchema = z.object({
    prompt: z.string().min(10, 'Please describe the workflow in a sentence or two.'),
    systemPrompt: z.string().optional(),
});

const handleSubmit = async (values: FormValues) => {
    setError(null);
    setIsSubmitting(true);

    try {
        const workflowUuid = await generateWorkflow(values.prompt, values.systemPrompt);

        form.reset();
        onClose();
        onWorkflowGenerated(workflowUuid);
    } catch (e) {
        setError(e instanceof Error ? e.message : 'Failed to generate workflow. Please try again.');
    } finally {
        setIsSubmitting(false);
    }
};
Enter fullscreen mode Exit fullscreen mode

All the AI lives on the server. The browser collects two strings and waits.

One call

export async function generateWorkflow(prompt: string, systemPrompt?: string): Promise<string> {
    const trimmed = systemPrompt?.trim();

    const response = await fetchWithAuth('/api/embedded/v1/automation/workflows/generate', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify(trimmed ? {prompt, systemPrompt: trimmed} : {prompt}),
    });

    if (!response.ok) {
        throw new Error(`Failed to generate workflow: ${response.status}`);
    }

    const uuid = (await response.text()).trim();

    return uuid.startsWith('"') && uuid.endsWith('"') ? uuid.slice(1, -1) : uuid;
}
Enter fullscreen mode Exit fullscreen mode

On the wire:

POST /api/embedded/v1/automation/workflows/generate
Authorization: Bearer <connected user's JWT>
X-Environment: DEVELOPMENT
Content-Type: application/json

{
  "prompt": "When a new lead arrives on a webhook with name, email and company, post it to the #sales Slack channel and send the lead a short welcome email from Gmail.",
  "systemPrompt": "Always notify the team in Slack, never by email. Keep workflows under five steps."
}
Enter fullscreen mode Exit fullscreen mode
HTTP/1.1 200 OK
Content-Type: application/json

"8b0c5d1e-..."
Enter fullscreen mode Exit fullscreen mode

Two things to know:

  • It's synchronous. ByteChef answers when the agent is done. Small workflows take under a minute, big ones several. The server waits up to ten minutes.
  • Send X-Environment. It defaults to PRODUCTION, which is rarely what you want while developing.

Four shapes of the same endpoint

Called from Create new Rebuild existing
Browser (user's JWT) POST /automation/workflows/generate POST /automation/workflows/{uuid}/generate
Your backend (API key) POST /{externalUserId}/automation/workflows/generate POST /{externalUserId}/automation/workflows/{uuid}/generate

The rebuild form powers a "Change it with AI" button: same UUID, rewritten definition. The backend form lets your server generate a starter automation right after onboarding, so the user's Automations page isn't empty on day one.

What happens on the server

  1. Resolve user and project. ByteChef reads the external user ID from the JWT and finds (or creates) their personal project for that environment.
  2. Create a draft. An empty workflow is saved first, labeled with the user's prompt (cut to 80 chars).
  3. Build the allow-list. Every component with an enabled integration in this environment, plus every connection-free component.
  4. Run the agent autonomously. The same BUILD agent behind New from Chat and ByteChef's Copilot, with autonomous: true.
  5. Return the UUID. On failure or timeout, the draft is deleted. A failed generation leaves nothing behind.

Autonomous mode

In autonomous mode the agent:

  • never asks follow-up questions; it picks the most common, sensible default
  • never pauses to show a plan
  • keeps the label it was given
  • saves once, at the end, after the full workflow validates

Otherwise it's the same agent: it searches the catalog (searchTask, listTasks), reads definitions (getTaskDefinition, getTaskProperties), validates each task (validateTask), then validates the whole workflow before saving. What you get back isn't a guess at JSON. It passed the same validator as a hand-built workflow.

Where the chat agent would stop and show a channel picker or a "Connect Slack" card, the prompt agent picks a value, builds the step, and leaves the connection for the user to choose in the editor.

Your house rules: the system prompt

The user decides what the workflow does. You decide how it's built:

Always notify the team in Slack, never by email.
Keep workflows under five steps.
Use the Europe/Berlin time zone for every schedule unless the user names another.
Never delete records in the CRM; update a status field instead.
Enter fullscreen mode Exit fullscreen mode

Note how this plays with our example. The user asked for a welcome email to the lead; the rule says "never by email". The agent read the rule the way a colleague would: it's about notifying the team. It built three steps: webhook trigger, Slack message to #sales, Gmail welcome email to the lead.

How ByteChef treats it:

  • Trimmed and capped at 4,000 characters.
  • Applies to one generation only. Nothing is stored, so send it every time.
  • Appended under a heading marking it as integrator instructions, applied only where it doesn't conflict with build rules, the workflow contract or safety constraints. It steers the agent; it can't hijack it.

In the sample it's a text box so you can play with it. In production, generate it in your code from your conventions and what you know about the user. Don't hand it to end users.

Security boundaries

Anyone with a connected user's JWT can call this with any text. So ByteChef trusts nothing in the request except the two strings:

  • The workflow is always the user's. Rebuild looks the UUID up inside the user's project only.
  • Agent state is built server-side. Mode, workflow ID, project and environment don't come from the request.
  • The agent stays in the user's project. No touching other workflows, no project-level changes.
  • The allow-list is enforced everywhere. Components outside it don't show up in search, can't be looked up, and are rejected on validation, including inside conditions, loops and AI agent nodes.

That last one matters more here than in chat. A chat agent asked for "Salesforce deals to Slack" when you don't offer Salesforce can ask what to do instead. A prompt agent can't ask, so it never produces nodes for apps your users can't connect.

Handing off to the editor

The generated workflow is a real ByteChef workflow, so send the user straight to the editor:

const router = useRouter();

<GenerateWorkflowDialog
    // ...
    onWorkflowGenerated={(workflowUuid) => router.push(`/automations/${workflowUuid}`)}
/>
Enter fullscreen mode Exit fullscreen mode

Here's what the agent built from the lead prompt:

Generated workflow in the editor

It set the Slack channel to sales, wrote a message referencing the webhook payload (${autoRespondWithHTTP200_1.body.name} and friends), addressed the Gmail step to the lead, and even added a workflow description.

The editor shows what's left:

Editor issues panel

  • 2 errors: the Slack and Gmail connections. The agent can't pick accounts for the user. With connectionDialogAllowed={true}, they connect right there.
  • 5 warnings: webhook fields. A webhook payload has no fixed shape, so the editor reminds you to check body.name, body.email and body.company.

Draft to running

Generated workflows are drafts. Nothing runs until published and enabled, which is the right default for something an AI just wrote:

await fetchWithAuth(`/api/embedded/v1/automation/workflows/${workflowUuid}/publish`, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({description: 'Generated from prompt'}),
});

await fetchWithAuth(`/api/embedded/v1/automation/workflows/${workflowUuid}/enable`, {method: 'POST'});
Enter fullscreen mode Exit fullscreen mode

Prompt vs. Chat

New from Prompt New from Chat
Requests One POST, one JSON response One AG-UI stream per turn
Agent mode Autonomous, picks defaults Interactive, asks questions
Missing connection Builds the step, user connects in editor Shows a Connect card in the thread
Code in your app A form and a fetch A chat component and its deps
Best for Clear, short requests Fuzzy requests

They combine well: generate a first version from a prompt, then offer "Change it with AI" via the rebuild endpoint.

Prerequisites

  • bytechef.ai.copilot.enabled=true
  • An AI provider configured for the environment
  • Integrations enabled for the environment (without them, the agent can still build schedules, webhooks and logic)

Embedded workflows and workflow generation are Enterprise Edition features.

Before you ship it

  • Raise timeouts on every proxy, load balancer and serverless function in the path (many stop at 30 or 60 seconds), or call the backend endpoint from a job and notify the user.
  • Show real progress. "Generating..." is fine for ten seconds, not two minutes.
  • Map errors to messages users can act on.
  • Redirect to the editor with the returned UUID.
  • Own the system prompt in code.
  • Send X-Environment explicitly.
  • Rate-limit generation. Every request burns model tokens on your AI provider account.
  • Seed better examples. Use your own integrations in the placeholder, or offer clickable starter prompts.

Who owns what

You: the button, the form, the system prompt, which integrations are enabled, the waiting experience, what happens with the UUID.

ByteChef: the per-user project and draft, the agent and its tools, catalog search and validation, the allow-list and security boundary, the editor, ConnectDialog and credential storage, and the engine that runs the result.

Your code is a form, one fetch and a redirect. Behind it is an agent that knows every action in your catalog.

Try it

Enable the copilot and an AI provider in ByteChef, run the embedded sample app, and open Automations → New from Prompt. Describe something small with one of your connected apps and click Generate.

ByteChef is open source (Apache 2.0). If this was useful, a ⭐ on GitHub helps a lot.

The full series: connect apps, ComponentKit, AI chat assistant, event triggers, workflows as APIs, MCP agents, custom builder, templates, New from Chat, and New from Prompt. All on the ByteChef blog.

Top comments (0)