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

# Build a workflow

> How px0 turns a sentence into a working workflow file: what it asks, what it searches, what you approve, and how to revise it later.

`px0 init` ships no workflows at all. That is the point - you describe what you want in plain English and get a working file back, rather than adapting a template someone else wrote.

```bash theme={null}
px0 workflows new
```

Behind that one command, px0 runs an interview and four model passes, stopping for your confirmation at the points where a wrong answer would actually cost you something:

1. **Interview** - one question at a time, until the request is concrete.
2. **Clarify** - what is still genuinely ambiguous about the request?
3. **Discover** - search Composio's catalogue for the tools it needs.
4. **Confirm** - you approve the tool set before anything is authorized.
5. **Plan** - write the workflow against exactly those tools.

## 1. The interview

`px0 workflows new` opens an interview, one question at a time, until px0 has what a workflow file must pin down:

|                 |                                                                                       |
| :-------------- | :------------------------------------------------------------------------------------ |
| The job         | What should happen                                                                    |
| The sources     | What it reads: which service, account, repository, channel, folder, or your own notes |
| The delivery    | What it produces and where that goes                                                  |
| The cadence     | On demand, on a schedule, or when something happens                                   |
| Done looks like | What makes the output right rather than merely produced                               |

```
› new workflow
  answer in your own words; press Enter on a blank line to stop
› What do you want px0 to do for you?
  digest our merged PRs each week
› Which repository, and whose PRs - yours or the whole team's?
  razorpay/api, the whole team's
› Where should the digest land: a Slack channel, a file, or just printed?
  #eng on slack

› the request
Every Friday afternoon, collect the pull requests merged in razorpay/api that
week and post a short digest to the #eng Slack channel.

› Build this? [Y/edit/n]
```

One question per turn, and the model sees every answer before writing the next one - so answering "razorpay/api, every Friday" in one breath skips the two questions that would have asked for those separately. Enter on a blank line ends the interview early and the request is written from what you did say, and the interview stops after eight questions regardless.

The request is shown before the build spends a planning call on it: `edit` rewrites it, `n` cancels, anything else builds.

## 2. It asks what is still ambiguous

```
✓ Checking the request for gaps

a few questions
› Which Slack channel should the digest go to?
  #eng-standup
› Which repositories should it look at?
  razorpay/api
```

Only things that would change the generated workflow get asked - which account, which channel, how often, where output goes. The model is explicitly told not to ask about anything it can pick a sane default for, because an interrogation is worse than an assumption.

You are never trapped in this. Press Enter to skip a question; skip everything in a round and the loop ends. It asks at most three rounds regardless. `--no-clarify` skips the pass entirely and builds from the description as written.

Whatever you answer is carried into every later pass, so the plan reflects your answers rather than re-guessing them.

## 2. It searches Composio's catalogue

```
  · github: list pull requests
  · github: list pull request reviews
  · slack: send message channel
✓ Searching Composio's catalogue (3 queries)
✓ Choosing from 18 candidates
```

Notice what the model writes here: *searches*, not tool names. A toolkit plus a short capability phrase. It cannot know Composio's naming conventions - there is no `GMAIL_GET_EMAIL`, for instance - so it describes the action and px0 does the lookup. Nothing is invented along the way: a slug that does not appear in the search results is discarded.

This is why a generated workflow gets the tool that actually fits rather than the nearest of px0's ten curated ones. Composio's catalogue runs to thousands of tools, and `px0 workflows new` searches all of it.

`--no-discover` skips the search and restricts the plan to the curated tools.

## 3. You confirm the tools

```
tools selected (3)
  1.  read   composio:GITHUB_LIST_REVIEWS_FOR_A_PULL_REQUEST  Lists submitted reviews for a pull request
  2.  read   composio:GITHUB_LIST_PULL_REQUESTS               Lists pull requests for a repository
  3.  write  composio:SLACK_SEND_MESSAGE                      Posts a message to a slack channel
! this workflow could change things outside px0  SLACK_SEND_MESSAGE

Enter accepts all; list numbers to drop (e.g. 2,3); n aborts
› keep all?
```

This is the gate before anything is authorized or written, and it is worth reading rather than reflexively accepting. The model chose these tools; picking up a write tool your request never asked for is exactly the mistake this screen exists to catch.

Access is stated per tool and comes from Composio's own metadata - px0 never infers it from the name:

| Marker        | Meaning                                                        |
| :------------ | :------------------------------------------------------------- |
| `read`        | Only reads. Safe as a workflow input.                          |
| `write`       | Can post, send, or change something outside px0.               |
| `destructive` | Can delete or overwrite. Flagged separately and harder to get. |

The selection pass is told to prefer the fewest tools, prefer reads over writes, include a write only when the request explicitly asks to change something, and never include a destructive tool unless you asked to delete something.

Confirmed tools are recorded in the store, so the plan, its validation, and every future run resolve them without another catalogue lookup. A workflow keeps working offline and unchanged after it is written.

## 4. It authorizes what the plan needs

```
authorization needed (2)
! github  not authorized
! slack   not authorized
› Start authorization for github, slack? [Y/n]

› github  open this and complete the consent:
    https://backend.composio.dev/s/...
› slack   open this and complete the consent:
    https://backend.composio.dev/s/...
```

It asks before minting anything. Answer `n` and nothing is prepared - the first run that needs the app will offer a link instead. Anything already authorized is skipped:

```
✓ already authorized  github, slack
```

Authorization happens before planning, so a build that cannot possibly work - a toolkit Composio refuses to authorize at all - stops before spending a planning call on it.

A *pending* consent is different from a blocked one, and it does not throw away your work. The workflow file is valid either way, so px0 writes it and tells you what is still waiting in the browser.

## 5. It writes the plan

```
plan
{
  "trigger": {"manual": true, "schedule": "0 17 * * 5"},
  "inputs": [
    {"id": "recent_prs", "tool": "composio:GITHUB_LIST_PULL_REQUESTS",
     "args": {"owner": "razorpay", "repo": "api", "state": "all"}}
  ],
  "tools": ["composio:GITHUB_LIST_REVIEWS_FOR_A_PULL_REQUEST", "composio:SLACK_SEND_MESSAGE"],
  "output": {"target": "file", "path": "digests/pr-{date}.md"},
  "body": "...",
  "description": "Every Friday at 5pm, summarize the GitHub PRs I reviewed this week and post the digest to Slack."
}
```

Read tools land in `inputs`, which run before the prompt to gather context. Write tools land in `tools`, which the model calls during the run. px0 enforces that split: a write tool in `inputs` is a validation error, because inputs run unconditionally and a workflow should not post something just by starting.

Because this workflow carries a schedule, its output goes to a file. A scheduled run has no terminal to print to, so px0 treats schedule-plus-stdout as a validation error rather than losing the output.

Then two checks print:

* **Feasibility.** A tool that does not exist, an input with no tool, an invalid cron expression, an output path that escapes the store. These stop the build, and nothing is saved.
* **Write access.** The write tools this workflow would be granted, named again now that the plan is concrete.

## 6. Confirm and name it

```
› Generate this workflow? [y/N] y
› workflow id [summarize-the-github-pull-requests-i-rev]:
```

Accept the suggested id or type your own. For scripted use, `--yes` skips every prompt in this flow - clarifying questions, tool confirmation, authorization, and this one - and `--id <id>` names it directly.

## What you get

```
created friday-pr-digest
✓ workflow    ~/.px0/workflows/friday-pr-digest.md
✓ guidelines  summarization.md
✓ schedule    0 17 * * 5
✓ tools       composio:GITHUB_LIST_PULL_REQUESTS, composio:SLACK_SEND_MESSAGE
! authorization pending  github, slack

finish the consent in your browser, then:
  px0 workflows run friday-pr-digest --dry-run
```

Guidelines are matched to the task by topic, and a file is attached only if it genuinely matches. Every guideline is inlined verbatim into the prompt, so an unrelated one costs tokens and actively misleads the model. A commit-message workflow gets `commit-messages.md`; a workflow about haikus gets none.

The file itself is plain Markdown, and every field in it is documented in [Workflow files](/workflows/anatomy).

## Guidelines it offers to write for you

Partway through a build, px0 may stop and say something like:

```
guideline: PR comment voice and format
  · The workflow posts comments publicly under your account, so the tone
    and directness need to match how you normally write review feedback.
[INFO] would be saved as  guidelines/pr-comment-style.md
› Write it now? [y/N]
```

This is for standards px0 cannot guess: what counts as worth flagging in a review, how blunt your comments are, the voice a summary is written in. Answer in your own words - a couple of lines is plenty - and finish with an empty line:

```
› How do you like your PR review comments written?
  (finish with an empty line)
  Blunt, no softening. Always say what to do instead of just naming the
  problem. Never comment on formatting, that is the linter's job.
```

px0 shapes what you wrote into `##` sections, shows you the draft, and takes `again` if you want another pass. What gets saved is an ordinary guideline file: it has version history from v1, so `px0 guidelines log` works on it, and it is added to this workflow's `guidelines:` list - which means its text is inlined into every run from now on.

This is the only way a guideline gets created - there is no `px0 guidelines new`. Asking someone to compose a convention from a blank page is the step that stopped guidelines from being written at all, so the build drafts a defensible version and leaves editing to you.

Nothing is proposed for a workflow that already says what to do, and nothing on a topic you already have a guideline for. `--yes` skips the step entirely, since there is no sensible default for "what is your commit message convention".

## Revise a workflow

```bash theme={null}
px0 workflows edit friday-pr-digest
```

px0 shows you the sentence you originally typed, and takes a new one:

```
editing friday-pr-digest
  original request: every friday afternoon, summarize the PRs I reviewed
                    this week and post it to #eng
  tools: composio:SLACK_SEND_MESSAGE
  guidelines: pr-comment-style.md

› New instructions (blank to keep the current ones):
```

This rebuilds the workflow rather than opening the file, and that is on purpose: the tools, inputs, and guideline list all follow from the request, so revising the request and regenerating keeps them consistent with each other.

Hand-editing the body is still perfectly fine for a wording change. Just know that a hand edit will not notice when your new instruction needs a tool the workflow does not have - that is the trade you make by skipping the rebuild.

The rebuild saves under the same id, and the old version stays in the store's history:

```bash theme={null}
px0 changes list
px0 changes revert <change-id>
```

## Flags for revisions

While `px0 workflows new` relies entirely on the interactive interview, `px0 workflows edit` supports these flags to skip prompts:

| Flag            | Effect                                                                 |
| :-------------- | :--------------------------------------------------------------------- |
| `--yes`         | Skip every prompt: no clarifying questions, no confirmations           |
| `--no-clarify`  | Rebuild from the new instructions as written, without asking questions |
| `--no-discover` | Use only px0's curated tools; skip the Composio catalogue search       |

## Next steps

<CardGroup cols={2}>
  <Card title="Run a workflow" icon="play" href="/workflows/run">
    Dry runs, inputs, stdin, and what failure looks like.
  </Card>

  <Card title="Workflow files" icon="file-code" href="/workflows/anatomy">
    Every frontmatter field, and the four kinds of input.
  </Card>

  <Card title="Connections" icon="plug" href="/tools/connections">
    What happens when a consent is pending or lapses.
  </Card>

  <Card title="Schedules" icon="clock" href="/workflows/schedule">
    Make `trigger.schedule` actually fire.
  </Card>
</CardGroup>
