# Generate with AI > Use the editor's AI assistant or one-shot generator, and start from an example prompt that reliably produces a valid workflow. The workflow editor's **Generate with AI** panel drafts a workflow from a plain description and suggests any dataset schemas the workflow needs. Nothing is saved, created, or executed until you review the draft and choose to insert it. The panel has two modes: - **Assistant** — a conversation. It can list existing datasets, propose a dataset schema for approval, and regenerate the workflow after you edit the proposal. Dataset and project creation always stop at an approval card. - **One-shot generation** — a single prompt that returns a draft plus suggested dataset schemas. Both modes produce the same validated workflow. The generated source is compiled and checked, so a draft that cannot compile is repaired or reported instead of being inserted. The assistant can also design a dataset from a workflow you already have: ask something like "create the dataset table this workflow writes". It reads the current editor buffer, derives the columns from the workflow's dataset and agent steps, and opens the usual schema approval card. Approving creates only the dataset; the workflow is left untouched. ## Before you start - AI must be configured on the server (otherwise the panel says it is not available). - Agent steps need a provider key enabled for the project. If none is enabled yet, the generator uses the explicit `provider.key("bountyhub/not-configured")` placeholder; enable a provider before running the workflow. - Refer to project modules and configuration by their real names. Read [config](/workflows/config) and [modules](/workflows/modules) for the shapes the generator understands. ## Example prompt This prompt exercises activities, artifacts, datasets, and an agent output contract, and reliably produces a workflow the compiler accepts. Paste it as-is (adjust the target), or use it as a template for your own requests. ```text Build a daily reconnaissance workflow for example.com. Use three activities: 1. discover - Trigger: trigger.cron("0 2 * * *") - Run the bountyhub/subfinder module against the target. - Store each discovered subdomain in the dataset "subdomains" with these columns: - subdomain (text) - source (text, literal "subfinder") - Upload the subdomain list as artifact "subdomains". 2. probe - Trigger: trigger.on(discover.succeeded()) - Download the "subdomains" artifact. - Run the bountyhub/httpx module on it. - Store each live service in the dataset "live-hosts" with these columns: - host (text) - status_code (integer) - title (text) - Upload the live-host list as artifact "live". 3. triage - Trigger: trigger.on(probe.succeeded()) - Download the "live" artifact. - Run a step.agent that reviews the live hosts and identifies admin, dev, staging and login surfaces. - The agent must write JSONL with exactly these fields: host, reason, confidence. - Store the agent output in the dataset "triage-results" with these columns: - host (text) - reason (text) - confidence (text) - If the project has no provider key configured yet, use provider.key("bountyhub/not-configured") as the placeholder. If any of those datasets do not exist, return them in suggested_datasets with exactly those columns. Do not invent dataset tables or columns. Do not use run.timestamp or any other invented run attribute; if a timestamp is required, omit it. Use one activity per tool and pass data between activities only with artifacts. ``` Why it works: - **One activity per tool.** Each stage names a single tool and its own trigger, matching the shape in [Steps](/workflows/steps) instead of one large activity. - **Artifacts are the only hand-off.** Each producer uploads and each consumer downloads the same artifact name; no activity reads another one's workspace. - **Datasets are fully specified.** Table names, column names, kinds, and the literal source value leave nothing to invent. A missing dataset is returned as a schema proposal, not a broken reference. - **The agent output is a contract.** `host`, `reason`, `confidence` as JSONL matches the dataset columns one-to-one. - **Forbidden shortcuts are named.** Banning `run.timestamp` and invented columns removes the two most common repair loops.