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

# Run

> Run agents from files or prompts

The `run` command executes agents from YAML configuration files or direct prompts.

The same modern engine also handles bare prompts with `run`-supported flags: `praisonai "fix bug" --model gpt-4o` is equivalent to `praisonai run "fix bug" --model gpt-4o`. See [CLI Dispatcher](/docs/features/cli-dispatcher) for how routing is decided.

<Note>
  You can omit the `run` subcommand for prompts **and** YAML workflows: `praisonai "..."` and `praisonai agents.yaml` are equivalent to `praisonai run "..."` and `praisonai run agents.yaml` (see [YAML workflows through the modern run engine](#yaml-workflows-through-the-modern-run-engine)). Flags that `run` accepts (`--output`, `--continue`, `--session`, `--fork`, `--stream`, `--allow`, `--deny`, `--approval`, `--permission-default`, `--plan`, …) reach the modern engine on either shape; only legacy-only flags (`--auto`, `--serve`, `--n8n`, …) drop to the legacy dispatcher. The short-form `-s` (legacy `--save`) and `-f` (legacy `--file`) stay on legacy to protect existing scripts — use the long forms `--session` / `--framework` for modern behaviour.
</Note>

<Note>
  Single-word direct prompts that look like reserved commands or common typos now fail fast with a hint on `stderr` and exit code `2`. To send a genuine single word to the model, use `praisonai run "<word>"` explicitly. See [Unknown Command Guard](/docs/docs/cli/cli#unknown-command-guard).
</Note>

<Info>
  `praisonai run` exits **`1`** whenever the agent fails to produce a result. Under `--output json` / `--output stream-json` the failure surfaces as `{"status": "failed", "code": "run_failed"}` with an actionable remediation. See [Exit Codes](#exit-codes) for the full table.
</Info>

<Info>
  `praisonai run` exits **`2`** when the run hits its `max_iter` / `max_steps` budget and wraps up with a partial-progress summary. Under `--output json` / `--output stream-json` this surfaces as `{"status": "truncated", "result": "<summary>"}`, so CI and scripts never mistake a truncated run for a completed one. See [Exit Codes](#exit-codes) and the [Truncated payload](#truncated-payload-output-json-output-stream-json) subsection.
</Info>

<Info>
  Exit **`2`** also covers three provider-block outcomes — `content_filtered`, `refused`, and `length_truncated` — when the model's `finish_reason` / `refusal` signals a content-filter block, safety refusal, or length cutoff. Under `--output json` the `status` carries the specific reason (`{"status": "<reason>", "result": "<partial text or null>"}`). See the [Provider-block payload](#provider-block-payload-output-json-output-stream-json) subsection.
</Info>

<Note>
  `praisonai run "..."` with no cloud key and no `--model` picks a reachable local model automatically. If Ollama (or any OpenAI-compatible local server) is running, you'll see a one-line stderr notice and the run continues:

  ```
  No cloud key found; using local model ollama/llama3.2. Run `praisonai setup` to add a hosted provider.
  ```

  An explicit `--model` still takes over. See [Keyless Local-First Run](/docs/features/keyless-local-first-run).
</Note>

## Usage

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run [OPTIONS] [TARGET]
```

## Arguments

| Argument | Description                             |
| -------- | --------------------------------------- |
| `TARGET` | Agent file (YAML) or direct prompt text |

`TARGET` may be a YAML/agent file path or a direct prompt. When you type the verb explicitly (`praisonai run TARGET`), a `TARGET` that is not `.yaml`/`.yml`, not an existing file, and not a reserved async-jobs verb (`submit / status / result / cancel / list / stream`) falls through to the jobs argparse parser and errors out. For free-text prompts, prefer the bare-prompt shape (`praisonai "TARGET"`), which reaches the modern engine unconditionally — see [CLI Dispatcher](/docs/features/cli-dispatcher).

## Bare Prompts and YAML

You can drop the `run` keyword entirely for one-shot prompts **and** YAML workflows:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai "Find the weather in London"       # equivalent to: praisonai run "Find the weather in London"
praisonai build a weather agent               # unquoted multi-token prompt also works
praisonai "fix the auth bug" --model gpt-4o   # run-supported flag → still modern engine
praisonai agents.yaml                         # equivalent to: praisonai run agents.yaml
praisonai agents.yaml --continue --output json  # run flags apply to YAML too
```

Both shapes inherit everything `run` gives you — `--output` modes, session continuity, credential gate, and permissions.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    A[praisonai ARGV] --> B{First token is<br/>Typer command?}
    B -->|Yes| C[Typer command]
    B -->|No| D{All flags<br/>run-supported?}
    D -->|No — legacy-only flag| E[Legacy argparse<br/>+ stderr notice]
    D -->|Yes / no flags| F[Modern Typer run<br/>prompt or .yaml]
    F --> G[Same as: praisonai run TARGET flags]

    classDef decision fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef legacy fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef modern fill:#10B981,stroke:#7C90A0,color:#fff

    class B,D decision
    class C,E legacy
    class F,G modern
```

<Note>
  A prompt or a `.yaml`/`.yml` workflow whose flags are all accepted by `run` (`--continue`, `--session`, `--output`, `--stream`, `--framework`, …) reaches the modern engine; the value of a value-taking option stays attached to its flag. Only a genuinely legacy-only flag (`--auto`, `--serve`, `--n8n`, …) keeps the legacy dispatcher — and when one forces that, a one-line stderr notice points at `praisonai run "…"`. The short-form `-s` (legacy `--save`) and `-f` (legacy `--file`) also stay on legacy to protect existing scripts; use `--session` / `--framework` for the modern equivalents. Multi-token unquoted prompts are joined into a single `run` positional so `praisonai build a weather agent` reaches the model as one prompt.
</Note>

## YAML workflows through the modern run engine

<Note>
  Both shapes reach the same modern engine. `praisonai agents.yaml` was rewritten to `praisonai run agents.yaml` by the unified dispatcher (PR #3797); typing `run` explicitly used to fall into the async-jobs argparse parser and exit 2 with `invalid choice: 'agents.yaml'` (issue #4374). Since PR [#4424](https://github.com/MervinPraison/PraisonAI/pull/4424), the legacy `run` branch inspects its first positional and routes YAML paths, existing files, and anything that is not a reserved job verb (`submit / status / result / cancel / list / stream`) into the modern agent runner. See [Async Jobs → How routing works inside `run`](/docs/cli/async-jobs#how-routing-works-inside-run) for the full split.
</Note>

`praisonai agents.yaml` now flows through the same modern `run` envelope as `praisonai run agents.yaml` — the router forwards a `.yaml`/`.yml` target to the Typer `run` engine automatically.

That unlocks the full `run` surface for plain YAML invocations:

| Capability                | Flags                                                     |
| ------------------------- | --------------------------------------------------------- |
| Session continuity        | `--continue`, `--session <id>`, `--fork`                  |
| Output modes              | `--output silent\|actions\|verbose\|json\|stream`         |
| First-run credential gate | Ollama detection + setup wizard rescue                    |
| Permissions & approval    | `--allow`, `--deny`, `--approval`, `--permission-default` |

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# YAML with structured output + a named session
praisonai agents.yaml --output json --session mysess

# Resume the last run of this workflow
praisonai agents.yaml --continue

# Branch off an existing session without mutating it
praisonai agents.yaml --session mysess --fork

# Permission-gated YAML workflow
praisonai agents.yaml --plan
praisonai agents.yaml --allow "bash:git *" --approval console
```

`--framework crewai` / `--framework autogen` is a `run` option, so multi-framework YAML is carried into the modern envelope too.

<Note>
  **Legacy fallback.** A YAML target carrying a genuinely legacy-only flag (or a short option whose meaning differs between engines, e.g. `-s` / `-f`) still drops to the legacy dispatcher — and prints a one-line notice so you know the flag downshifted you. Remove the legacy-only flag to stay on the modern engine.
</Note>

## Options

| Option                    | Short | Description                                                                                                                                                                                                                                                                                  | Default       |
| ------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `--output`                | `-o`  | Output mode: `text`, `json`, `stream-json`, `silent`, `verbose`                                                                                                                                                                                                                              | `text`        |
| `--model`                 | `-m`  | LLM model to use                                                                                                                                                                                                                                                                             | `gpt-4o-mini` |
| `--framework`             | `-f`  | Framework: praisonai, crewai, autogen                                                                                                                                                                                                                                                        | `praisonai`   |
| `--interactive`           | `-i`  | Enable interactive mode                                                                                                                                                                                                                                                                      | `false`       |
| `--verbose`               | `-v`  | Verbose output                                                                                                                                                                                                                                                                               | `false`       |
| `--stream`                |       | Stream output                                                                                                                                                                                                                                                                                | `true`        |
| `--no-stream`             |       | Disable streaming                                                                                                                                                                                                                                                                            |               |
| `--trace`                 |       | Enable tracing                                                                                                                                                                                                                                                                               | `false`       |
| `--memory`                |       | Enable memory                                                                                                                                                                                                                                                                                | `false`       |
| `--tools`                 | `-t`  | Comma-separated tool names (e.g. `web_search,github`) or a `tools.py` file path (resolved via [ToolResolver](/docs/features/tool-resolver))                                                                                                                                                       |               |
| `--toolset`               |       | Comma-separated named toolset groups to load                                                                                                                                                                                                                                                 |               |
| `--allow-local-tools`     |       | Load project-local `.praisonai/tools/*.py` for this run only (equivalent to `PRAISONAI_ALLOW_LOCAL_TOOLS=true`, but strictly per-invocation)                                                                                                                                                 | `false`       |
| `--pure` / `--no-plugins` |       | Skip discovery/loading of external plugins for this run only (equivalent to `PRAISONAI_NO_PLUGINS=1`); persisted enable/disable state is unchanged.                                                                                                                                          | `false`       |
| `--max-tokens`            |       | Maximum output tokens                                                                                                                                                                                                                                                                        | `16000`       |
| `--continue`              | `-c`  | Continue the most recent session for this project                                                                                                                                                                                                                                            | `false`       |
| `--session`               | `-s`  | Resume a specific session ID                                                                                                                                                                                                                                                                 |               |
| `--fork`                  |       | Fork from the specified session (requires `--session`)                                                                                                                                                                                                                                       | `false`       |
| `--no-save`               |       | Don't auto-save the session after execution                                                                                                                                                                                                                                                  | `false`       |
| `--no-rules`              |       | Disable auto-injection of project instruction files (AGENTS.md, CLAUDE.md, etc.) — includes both the up-front project-root walk-up and the on-demand subtree attach fired as the agent touches files under a nested AGENTS.md. Also suppresses config-declared and `--instructions` sources. | `false`       |
| `--instructions`          |       | Extra instruction/context source (file path, glob, or `http(s)://` URL) to load alongside `AGENTS.md` / `CLAUDE.md`. Repeatable; merges on top of config-declared `instructions`. See [Instruction Sources](/docs/features/instruction-sources).                                                  |               |
| `--append-system-prompt`  |       | Append text (literal or `@file`) to the system prompt for this invocation only. Env fallback: `PRAISONAI_APPEND_SYSTEM_PROMPT`. Never persisted. See [Append System Prompt](/docs/features/append-system-prompt).                                                                                 | `None`        |
| `--image <path_or_url>`   |       | Attach an image (local path or `http(s)://` URL) to a one-shot run so the agent can see it. Repeatable for multiple images. Supported formats: `.png .jpg .jpeg .gif .webp .bmp .svg .tiff`. Direct-prompt runs only. See [Attach an image](#attach-an-image---image).                       | `None`        |
| `--no-context`            |       | Disable AGENTS.md/CLAUDE.md auto-loading into system prompt                                                                                                                                                                                                                                  | `false`       |
| `--agent`                 | `-a`  | Use a named custom agent from `.praisonai/agents/`                                                                                                                                                                                                                                           |               |
| `--subagents`             |       | Comma-separated named agents (`.praisonai/agents/*.md`) the running agent may delegate to. Omit to expose agents marked `mode: subagent`.                                                                                                                                                    |               |
| `--thinking`              |       | Reasoning effort for this invocation: `off`, `minimal`, `low`, `medium`, `high`                                                                                                                                                                                                              |               |
| `--command`               |       | Execute a named custom command; `TARGET` becomes `$ARGUMENTS`                                                                                                                                                                                                                                |               |
| `--allow`                 |       | Allow a permission pattern (e.g. `'bash:git *'`); repeatable                                                                                                                                                                                                                                 |               |
| `--deny`                  |       | Deny a permission pattern; repeatable                                                                                                                                                                                                                                                        |               |
| `--permissions`           |       | Path to a YAML permission rules file                                                                                                                                                                                                                                                         |               |
| `--permission-default`    |       | Default action for unmatched patterns: `allow`, `deny`, or `ask`                                                                                                                                                                                                                             |               |
| `--approval`              |       | Approval backend mode: `console`, `plan`, `accept-edits`, `bypass`                                                                                                                                                                                                                           |               |
| `--plan`                  |       | Read-only planning mode — the agent may explore/read/search but every mutating tool (write/edit/delete/shell/exec) is denied. Discoverable alias for `--approval plan`. Cannot be combined with `--approval`, `--allow`, `--deny`, or `--permission-default` (exits 1).                      | `false`       |
| `--restore`               |       | Restore workspace to a checkpoint (`id`, `last`, or `latest`) and exit                                                                                                                                                                                                                       |               |
| `--revert <ref>`          |       | Revert files + conversation together to a prior turn (`last` or N), showing the diff first, and exit                                                                                                                                                                                         | —             |
| `--no-checkpoint`         |       | Disable automatic pre-run checkpoint for this invocation                                                                                                                                                                                                                                     | `false`       |
| `--attach`                |       | Event-stream label used only to fan out live events to `praisonai attach <id>` clients. It does **not** by itself select or persist a conversation. Paired with `--no-save`, the run streams events under `<id>` but stays on the anonymous, non-persisted path.                             |               |
| `--worktree`              |       | Run on an isolated git worktree/branch (branch-per-task); no-op outside a git repo                                                                                                                                                                                                           | `false`       |
| `--keep`                  |       | With `--worktree`, keep the worktree/branch after the run for review instead of tearing it down                                                                                                                                                                                              | `false`       |
| `--append-system-prompt`  |       | Append text (or `@file`) to the system prompt for this invocation only. Env fallback: `PRAISONAI_APPEND_SYSTEM_PROMPT`. Runs in-process (bypasses the warm runtime). See [Append System Prompt](/docs/features/append-system-prompt).                                                             |               |

<Note>
  Setting `--append-system-prompt` keeps `run` in-process; the warm-runtime fast path is bypassed for this invocation so the suffix is always applied. See [Append System Prompt](/docs/features/append-system-prompt).
</Note>

<Note>
  The permission and approval flags (`--allow`, `--deny`, `--permissions`, `--permission-default`, `--approval`, `--approve-all-tools`, `--approval-timeout`) are honoured on **both** paths — a direct prompt **and** a YAML workflow file. On the YAML path, any `--allow` / `--deny` / `--permissions` / `--permission-default` rule with no explicit `--approval` implicitly activates the `console` backend so `deny` / `ask` patterns are actually enforced. See [YAML Workflows Are Permission-Gated](#yaml-workflows-are-permission-gated).
</Note>

<Note>
  `--plan` is honoured on the YAML path and under `--profile` too — a profiled run (`praisonai run --plan --profile "…"`) stays strictly read-only, and the profiling report still prints. It's a discoverable alias for `--approval plan` (`PermissionMode.PLAN`); see [Permission Modes](/docs/features/permission-modes).
</Note>

<Note>
  For workflow guidance, see [Isolated Runs](/docs/features/cli-worktree-isolation) or the flag-focused guide at [Run --worktree](/docs/features/run-worktree).
</Note>

<Tip>
  Pass `--pure` (alias `--no-plugins`) to skip external-plugin discovery for a single run without touching your saved enable/disable state — see [Pure Mode](/docs/features/pure-mode).
</Tip>

### Append to the system prompt

`--append-system-prompt` adds a one-off suffix to the assembled system prompt for a single run. It is never persisted and disappears when the process exits.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Literal text
praisonai run "Refactor this module" --append-system-prompt "Always answer in French"

# Read the suffix from a file (@file form)
praisonai run "Refactor this module" --append-system-prompt @policy.md
```

Omit the flag and set the environment variable instead — handy for CI:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
export PRAISONAI_APPEND_SYSTEM_PROMPT="Reply in strict JSON, no prose."
praisonai run "Summarise the changelog"
```

<Note>
  `--append-system-prompt` **bypasses the warm runtime** and runs in-process. The warm runtime is a separate process that never receives the CLI's `PRAISONAI_APPEND_SYSTEM_PROMPT` export and reuses a cached agent whose system prompt is already assembled — so attaching would silently drop the suffix. The in-process path applies it correctly, at the cost of a slightly higher first-invocation startup than a plain `run`.
</Note>

See [Append System Prompt](/docs/features/append-system-prompt) for the full behaviour.

### Attach an image (`--image`)

`--image` attaches a screenshot, mockup, or diagram to a single `praisonai run` so a vision-capable agent can see it — no code, no YAML.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "praisonai run --image"
        P[📝 Prompt] --> R[🖼️ ImageHandler]
        I[📷 Local path or URL] --> R
        R --> V[🤖 Vision LLM]
        V --> A[✅ Answer]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff

    class P,I input
    class R,V process
    class A result
```

<Steps>
  <Step title="Attach one image">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run "Describe this screenshot" --image bug.png
    ```
  </Step>

  <Step title="Attach multiple images">
    Repeat the flag — never comma-separate a single value.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run "Which of these two designs has better contrast?" \
      --image mock-a.png --image mock-b.png
    ```
  </Step>

  <Step title="Attach a remote URL">
    Any `http://` or `https://` URL is accepted verbatim.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run "Summarize this architecture diagram" \
      --image https://raw.githubusercontent.com/example/repo/main/arch.png
    ```
  </Step>
</Steps>

**How it works:** the run is routed through the vision path and picks a vision-capable model — defaulting to `gpt-4o`. Override it with `--model`, but the model you pick must support vision.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "Extract every visible number" --image invoice.jpg --model gpt-4o
```

Supported formats: `.png` `.jpg` `.jpeg` `.gif` `.webp` `.bmp` `.svg` `.tiff`. An unsupported extension or a missing local file fails before any model call.

<Warning>
  `--image` is supported for **direct prompt runs only**. Each of these fails fast with exit code `1`:

  ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  # ❌ --image is not supported with a YAML workflow
  praisonai run agents.yaml --image bug.png

  # ❌ --image is not supported with --agent (or --profile / --profile-deep)
  praisonai run "Describe this" --agent researcher --image bug.png

  # ❌ --image cannot combine with --output actions
  praisonai run "Describe this" --output actions --image bug.png
  ```

  The `--agent` / `--profile` / YAML cases print:
  `--image is only supported for direct prompt runs (not with --agent, --profile, or a YAML file)`.
  The actions case prints `--image cannot be combined with --output actions`.
</Warning>

<Tip>
  Multiple images use **repeated `--image` flags** — do not comma-separate one value. A single value containing a comma is rejected:

  ```
  Invalid --image value 'a,b.png': paths/URLs must not contain a comma. Pass multiple images with repeated --image flags.
  ```
</Tip>

<Note>
  Image runs always execute **in-process** — attaching an image transparently falls back from the warm runtime, matching `--append-system-prompt` and `--worktree`. The warm runtime is a separate process that cannot carry a per-invocation attachment.
</Note>

<Card title="Multimodal Agents (Python / YAML)" icon="images" href="/docs/features/multimodal#one-shot-cli">
  Attach images from the Python SDK or a YAML workflow — the full multimodal story.
</Card>

### Delegating to Named Agents

Let a running agent delegate sub-tasks to your own named agents in `.praisonai/agents/*.md`. Pass `--subagents` to opt agents in for a single run, or mark agents with `mode: subagent` to expose them on every run.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run --agent lead --subagents researcher,reviewer "Draft and review a brief on X"
```

See [Named Agent Delegation](/docs/features/named-agent-delegation) for the full guide.

### Isolated Runs (Git Worktree)

Add `--worktree` and each run gets its own git branch and checkout — concurrent runs never clobber each other's edits.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Run as praisonai run --worktree
    participant Worktree as Isolated Worktree
    participant Agent

    User->>Run: praisonai run --worktree "prompt"
    Run->>Worktree: create fresh branch + checkout
    Worktree-->>Agent: isolated working directory
    Agent->>Worktree: edit files
    Worktree->>Run: commit changes to branch on exit
    Run-->>User: "Review/merge with: git merge <branch>"

    classDef user fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef tree fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff

    class User,Agent user
    class Run,Worktree tree
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Prompt run on a fresh branch — output committed to the branch on exit
praisonai run --worktree "Refactor the auth module and add tests"

# YAML file run — same isolation, YAML loaded from the original checkout
praisonai run --worktree agents.yaml

# Keep the worktree checkout for in-place review after the run
praisonai run --worktree --keep "Draft a migration plan"

# Two concurrent runs of the same target get independent worktrees/branches
praisonai run --worktree "task A" &
praisonai run --worktree "task A" &
```

**What happens on exit** depends on what the run produced:

<AccordionGroup>
  <Accordion title="Changes produced (default)">
    The run commits everything (`git add -A` + `git commit --no-verify`) to the isolated branch, then removes the worktree checkout while keeping the branch. You'll see:

    ```
    Committed changes to branch '<branch>'. Review/merge with: git merge <branch>
    ```

    If the commit can't be made (e.g. no git identity configured), the worktree is kept in place with a warning so output is never lost.
  </Accordion>

  <Accordion title="No changes produced">
    The worktree checkout **and** its branch are torn down entirely — nothing is left behind.

    ```
    No changes on '<branch>'.
    ```
  </Accordion>

  <Accordion title="--keep set">
    The worktree checkout stays in place for in-place review, regardless of whether changes were made.

    ```
    Worktree kept at <path> (branch '<branch>'). Review/merge then remove with: git worktree remove.
    ```
  </Accordion>
</AccordionGroup>

<Note>
  `--worktree` is a no-op outside a git repository — it prints `Not a git repository; running without worktree isolation.` and runs in place, so it's safe to add unconditionally. Change detection uses `git status --porcelain`, so brand-new untracked output counts as a change.
</Note>

<Warning>
  Isolation applies to **direct prompt** and **YAML file** runs only. These combinations are rejected up front (exit code 1):

  * `--worktree` + `--attach` — the warm runtime is a separate process whose working directory can't be redirected.
  * `--worktree` + `--agent` / `--command` / `--profile` / `--profile-deep` — only prompt and YAML runs are supported.
  * `--keep` without `--worktree` — `--keep requires --worktree`.

  When `--worktree` is used with a warm-runtime-eligible prompt, the run falls back to in-process execution so it never attaches to a cached warm agent.
</Warning>

<Note>
  Human-facing worktree messages are suppressed under `--output json` / `--output stream-json`, so structured runs stay machine-parseable.
</Note>

This CLI flag wraps the same core primitive documented for the Python API. Pick the layer that fits:

<CardGroup cols={2}>
  <Card title="Python API — GitWorktreeAdapter" icon="code" href="/docs/features/workspace-isolation">
    Provision worktrees directly from Python for concurrent agents.
  </Card>

  <Card title="Per-Kanban-Task Worktrees" icon="kanban" href="/docs/features/kanban#per-task-worktree-isolation">
    Give each kanban task its own worktree with `workspace_kind="worktree"`.
  </Card>
</CardGroup>

## Piped Input

`praisonai run` composes in Unix pipelines. Piped stdin is merged with your prompt argument (prompt first, then piped body).

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
cat error.log | praisonai run "Diagnose the root cause"
git diff       | praisonai run "Review these changes for bugs"
```

Piped input is **skipped** when:

* `TARGET` is an existing `.yaml` / `.yml` file (case-insensitive).
* `--agent` or `--command` is used.
* `--restore` is set (the command exits before ingestion).

See [Piped Input](/docs/features/cli-piped-stdin) for the full behaviour.

## Output Modes

`--output` controls how results and events are written to stdout.

<Tabs>
  <Tab title="text (default)">
    Rich-formatted human-readable output in the terminal.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run "What is the capital of France?"
    ```
  </Tab>

  <Tab title="json">
    Emits a single JSON object at the end of the run containing the final result.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run --output json "What is the capital of France?"
    ```
  </Tab>

  <Tab title="stream-json">
    Emits one JSON object per line (NDJSON) as the run progresses — one event per agent action. Ideal for CI pipelines, scripts, and observability tooling.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run --output stream-json "Find the weather in London"
    ```

    Transient rate limits surface as a `run.retry` event **before** the wait, so a rate-limited run shows a live countdown instead of a silent hang:

    ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    {"event":"run.retry","data":{"schema_version":1,"attempt":2,"max_attempts":5,"delay":4.0,"reason":"rate_limit"}}
    ```

    See [Stream Events](/docs/features/run-stream-events) for the full event protocol reference.
  </Tab>

  <Tab title="silent">
    No stdout output — useful when you only need the exit code.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run --output silent "Run tests" && echo "passed"
    ```
  </Tab>

  <Tab title="verbose">
    Includes diagnostic details alongside normal output. Useful for debugging.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run --output verbose "What is the capital of France?"
    ```
  </Tab>
</Tabs>

***

## Exit Codes

`praisonai run` returns a non-zero exit code whenever the agent fails to produce a result, so CI pipelines and scripts can branch on the exit code instead of scraping stderr.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "praisonai run outcome"
        Start[📝 Agent.start/run result] --> Check{🔍 non-empty?}
        Check -->|No: None or empty| Block{🔍 last_stop_reason<br/>provider block?}
        Block -->|content_filtered| CF[🛡️ exit 2<br/>status: "content_filtered"]
        Block -->|refused| Ref[🚫 exit 2<br/>status: "refused"]
        Block -->|length_truncated| Len[✂️ exit 2<br/>status: "length_truncated"]
        Block -->|No| Fail[❌ exit 1<br/>run_failed + remediation]
        Check -->|Yes: real answer| Reason{🔍 last_stop_reason<br/>== "max_steps"?}
        Reason -->|No| Ok[✅ exit 0<br/>Run completed]
        Reason -->|Yes| Trunc[⚠️ exit 2<br/>status: "truncated"<br/>summary preserved]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef gate fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef success fill:#10B981,stroke:#7C90A0,color:#fff
    classDef truncated fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef failure fill:#8B0000,stroke:#7C90A0,color:#fff

    class Start input
    class Check,Reason,Block gate
    class Ok success
    class Trunc,CF,Ref,Len truncated
    class Fail failure
```

| Exit | When                                                                                                                           | Emitted where                                                                                                                         |
| ---- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `0`  | Agent returned a non-empty result **and** did not hit the step/iteration limit                                                 | All modes                                                                                                                             |
| `1`  | Agent returned `None` or empty (swallowed LLM/auth error, guardrail block, tool failure)                                       | All run modes (direct prompt, YAML file, `--agent`, `--attach`, `--profile`, `--profile-deep`)                                        |
| `1`  | No API key configured in CI mode                                                                                               | Direct prompt                                                                                                                         |
| `1`  | Worktree flag combined with `--attach`, `--agent`, `--command`, or `--profile`                                                 | Direct prompt                                                                                                                         |
| `1`  | `--image` combined with `--agent` / `--profile` / a YAML file / `--output actions`, or a comma inside a single `--image` value | Direct-prompt run                                                                                                                     |
| `1`  | Warm-runtime major-version mismatch on `--attach`                                                                              | `--attach <id>`                                                                                                                       |
| `2`  | Run hit its `max_iter` / `max_steps` budget and returned a wrap-up summary (`agent.last_stop_reason == "max_steps"`)           | Actions path (`_run_prompt`), `--agent` (custom-agent) path, `--profile` / `--profile-deep` (profiling report is still printed first) |
| `2`  | Provider content filter blocked the response (`agent.last_stop_reason == "content_filtered"`)                                  | All three run paths (`_run_prompt`, `--agent`, `--profile` / `--profile-deep`)                                                        |
| `2`  | Model refused to answer / safety refusal (`agent.last_stop_reason == "refused"`)                                               | All three run paths                                                                                                                   |
| `2`  | Response hit the model's output length limit (`agent.last_stop_reason == "length_truncated"`)                                  | All three run paths                                                                                                                   |
| `2`  | Single-word direct prompt collides with a reserved command / typo guard                                                        | Direct prompt                                                                                                                         |

<Note>
  Exit `2` covers several independent cases: **step-limit truncation** (`status: "truncated"`, PR [#4100](https://github.com/MervinPraison/PraisonAI/pull/4100)), the three **provider blocks** (`status: "content_filtered" \| "refused" \| "length_truncated"`, PR [#4472](https://github.com/MervinPraison/PraisonAI/pull/4472)), and the pre-existing **reserved-command guard**. They share the exit code but are unrelated — each incomplete-run case emits its specific `status` under `--output json`, while the guard fails fast before any run.
</Note>

### Failure payload (`--output json` / `--output stream-json`)

When the agent produces no result, the CLI emits a machine-readable failure object **and** exits `1`:

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{"status": "failed", "result": null}
```

The paired error event carries the same status and an error code:

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{"code": "run_failed", "status": "failed", "message": "Run failed: the agent did not produce a result."}
```

The human-facing stderr line includes an actionable remediation:

```
Run failed: the agent did not produce a result.
Re-run with --verbose to see the underlying error, or check credentials with: praisonai setup
```

<Note>
  The failure contract applies to **every** run path — direct prompt, YAML file, `--agent`, `--attach`, `--profile`, and `--profile-deep`. Profiled runs still print the profiling report before exiting non-zero, so you keep the profile even on failure.
</Note>

### Truncated payload (`--output json` / `--output stream-json`)

When a run hits its `max_iter` / `max_steps` budget, the CLI keeps the wrap-up summary but marks the run **truncated** and exits `2`:

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{"status": "truncated", "result": "…wrap-up summary text preserved verbatim…"}
```

In interactive (non-JSON) mode the CLI also prints a one-line stderr notice so a human knows the answer is partial:

```
Run hit the step/iteration limit; the answer above is a summary of partial progress, not a completed task. Raise the budget with ExecutionConfig(max_steps=...) on the agent (or `execution: {max_steps: ...}` in the YAML) and re-run.
```

JSON / stream-JSON consumers do **not** receive this stderr warning (the CLI checks `output.is_json_mode`) — the `status: "truncated"` field is the machine signal.

<Note>
  **stream-json contract:** the terminal `run.result` event is emitted with `ok: false` (not `ok: true`), in lockstep with exit `2`. A stream-json consumer therefore never sees a contradictory success terminal event ahead of the `truncated` status. The classification runs `bridge.emit_run_result(result, ok=succeeded and not truncated)`, covered by the regression test `test_actions_stream_reports_truncated_run_not_ok`.
</Note>

See [Step Budget](/docs/features/max-steps) for how `max_steps` truncation works, and [Agent Run Outcomes → CLI Mapping](/docs/docs/features/agent-run-outcomes#cli-mapping-praisonai-run) for the SDK-to-CLI status mapping.

### Provider-block payload (`--output json` / `--output stream-json`)

When the model's `finish_reason` / `refusal` signals a content-filter block, safety refusal, or length cutoff, the CLI preserves any partial text but marks the run with the **specific reason** and exits `2`:

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{"status": "content_filtered", "result": "<partial text or null>"}
{"status": "refused", "result": "<partial text or null>"}
{"status": "length_truncated", "result": "<partial text or null>"}
```

In interactive (non-JSON) mode the CLI prints the matching human-readable warning to stderr:

```
Run blocked: the provider's content filter blocked the response.
Run refused: the model declined to answer (safety refusal).
Run truncated: the response hit the model's output length limit.
```

JSON / stream-JSON consumers do **not** receive the stderr warning — the `status` field carries the machine signal. A provider block wins over a generic empty-result failure, so an actionable reason is never masked as a plain `run_failed`. See [Provider block outcomes](/docs/features/run-outcome#provider-block-outcomes) for the SDK-level classifier and precedence.

### CI usage

Test the run in-process first — the CLI's exit-code contract mirrors this success test.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

agent = Agent(instructions="Answer succinctly")
result = agent.start("Summarise yesterday's PRs")

if not (result and (not isinstance(result, str) or result.strip())):
    raise SystemExit("Agent run failed")
```

The CLI does the same success test for you and returns exit `1` on failure:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Fails the CI job when the agent swallows an error
if ! praisonai run "Summarise yesterday's PRs"; then
  echo "Agent run failed"
  exit 1
fi
```

Branch on the JSON `status` to handle all three outcomes — `success`, `truncated`, and `failed`:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
result=$(praisonai run --output json "Refactor the auth module and add tests")
status=$(echo "$result" | jq -r '.status // "success"')
case "$status" in
  success)          echo "done" ;;
  truncated)        echo "hit the step limit; raise ExecutionConfig(max_steps=…) in the YAML and re-run"; exit 2 ;;
  content_filtered) echo "provider blocked the response; try rephrasing"; exit 2 ;;
  refused)          echo "model declined; try a different model"; exit 2 ;;
  length_truncated) echo "response cut off; re-run with a higher --max-tokens"; exit 2 ;;
  failed)           echo "$result" | jq -r '.message'; exit 1 ;;
esac
```

Or branch on the exit code directly:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "…big task…"
case $? in
  0) echo "done" ;;
  1) echo "run failed" ;;
  2) echo "incomplete run (truncated / content_filtered / refused / length_truncated) — check --output json status" ;;
esac
```

See [Step Budget](/docs/features/max-steps) for the truncation contract, and [Agent Run Outcomes → CLI Mapping](/docs/docs/features/agent-run-outcomes#cli-mapping-praisonai-run) for how the SDK-level statuses map to these exit signals.

***

## Standalone vs wrapper

On a standalone `pip install praisonai-code` install, default `run "…"` and the human-readable text modes (`--output plain/verbose/silent`) route through the in-process `Agent` (PR #2853) — the same path used by the structured modes (`--output actions|json|stream|stream-json`). As of PR #3818, `chat` and `code` also open their resident interactive TUI standalone — `pip install praisonai-code` alone delivers `run`, `chat`, and `code`:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
pip install praisonai-code
praisonai-code chat
praisonai-code code "Refactor this function"
```

<Note>
  Pre-PR-#3818 `praisonai-code` builds emitted `Error: chat requires the praisonai wrapper` on a standalone install. Upgrading to a build with the resident TUI removes that hint — `chat` and `code` now run without the wrapper.
</Note>

Every text mode — default `run "…"` and `--output plain|verbose|silent|actions|json|stream|stream-json` — plus interactive `chat`/`code` runs with no wrapper. The wrapper (`pip install praisonai`) still adds the gateway, channel bots, and the richer legacy interactive dispatch. See the [PraisonAI Code CLI standalone-limits table](/docs/docs/features/praisonai-code-cli#standalone-limits) for the full command matrix.

<Note>
  **`run --output actions` honours `--tools` and `--toolset`.** These flags were previously dropped in actions mode; they now reach parity with the default, YAML, and Python surfaces. The same [ToolResolver](/docs/features/tool-resolver) path resolves comma-separated names, and `tools.py` file paths continue to load as before.

  ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  praisonai run --output actions --tools tavily_search,github "Research the latest release"
  ```
</Note>

<Note>
  **`run --agent` honours `--tools`, `--toolset`, and auto-discovers `.praisonai/tools/*.py`.** These were previously silently dropped when `--agent` was used. The `--agent` path now composes its toolset by unioning the agent's frontmatter `tools:` list with `--tools`/`--toolset` and (when `PRAISONAI_ALLOW_LOCAL_TOOLS=true` or `--allow-local-tools` is set) auto-discovered project-local tools, dedup'd by callable identity. Fixes [#3047](https://github.com/MervinPraison/PraisonAI/issues/3047).

  ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  praisonai run --agent researcher \
    --tools github,tavily_search \
    --allow-local-tools \
    "Greet Ada, then research WebAssembly 3.0"
  ```
</Note>

***

## Examples

### Run a built-in preset (no YAML required)

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Read-only planner — never modifies files
praisonai run --agent plan "explore the codebase"

# Code reviewer that asks before shell commands
praisonai run --agent review "review the recent diff"

# Full toolset
praisonai run --agent build "add a /health endpoint"
```

### Run with a custom agent

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run --agent researcher "Find info on X"
```

### Run with delegatable subagents

Let the running agent hand named sub-tasks to your other `.praisonai/agents/*.md` agents, each under its own model/tools/permissions.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Expose named agents with `mode: subagent` in frontmatter
praisonai run --agent lead "Research 3 vector DBs, then draft an eval script"

# Or opt any named agents in explicitly
praisonai run --agent lead --subagents researcher,coder "Research 3 vector DBs, then draft an eval script"
```

Wiring is a no-op when no delegatable agents exist — default runs are unchanged. See [Named Agent Delegation](/docs/features/named-agent-delegation).

### Run with a custom agent and CLI permission override

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Agent definition has mode: review (bash:*: ask)
# --allow overrides to let git commands run without prompting
praisonai run --agent reviewer "review the diff" --allow 'bash:git *'
```

### Run with reasoning effort

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run --thinking medium "Plan a release checklist for v4.7"

# Works with custom agents too
praisonai run --agent researcher --thinking high "Deep dive on vector DB options"
```

`--thinking` applies across direct-prompt, actions-mode, and custom-agent paths. See [Thinking](/docs/cli/thinking).

### Run with a custom command

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run --command summarise "Long text here"
```

Session flags (`--continue`, `--session`, `--fork`, `--no-save`) work with `--agent`.

### Run from YAML file

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run agents.yaml
```

To gate a workflow file with the same `--allow` / `--deny` / `--approval` rules you use on a prompt run, see [YAML Workflows Are Permission-Gated](#yaml-workflows-are-permission-gated).

### Run with a prompt

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "What is the capital of France?"
```

### Run in read-only planning mode

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Read-only run — the agent explores but writes nothing
praisonai run --plan "Audit the auth module and propose a refactor"
```

`--plan` denies every mutating tool (write/edit/delete/shell/exec). See [Permission Modes](/docs/features/permission-modes) and [Permissions](/docs/cli/permissions).

### Run in a monorepo

Touching a nested package auto-loads that package's `AGENTS.md` — no config, same as `chat`.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# From the repo root, touching a nested package auto-loads packages/foo/AGENTS.md
praisonai run "refactor packages/foo/bar.py to use the new logger"

# Opt out for a one-off run
praisonai run --no-rules "just print the file, don't apply project rules"

# Or globally in CI
export PRAISON_NO_RULES=true
```

### Run with specific model

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "Explain quantum computing" --model gpt-4o
```

### Run in interactive mode

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run agents.yaml
```

### Run with memory enabled

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "Remember my name is John" --memory
```

### Run with verbose output

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run agents.yaml --verbose
```

### Run with custom tools

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# By name — the agent picks up built-in tools, no file needed
praisonai run "Summarise today's AI news" --tools "web_search,github"

# Or from a file
praisonai run agents.yaml --tools tools.py
```

In `run` actions mode, `--tools` and `--toolset` are now wired end-to-end (previously silently dropped). The same is now true for `run --agent <name>` — `--tools`/`--toolset` merge into the agent's frontmatter `tools:` list instead of being dropped ([#3047](https://github.com/MervinPraison/PraisonAI/issues/3047)).

### Run with project-local tools

Local `.praisonai/tools/*.py` files require an opt-in because loading them executes Python:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Discoverable per-invocation flag (recommended)
praisonai run --allow-local-tools "use the greet tool"

# Env-var equivalent (persists for the shell)
PRAISONAI_ALLOW_LOCAL_TOOLS=true praisonai run "use the greet tool"

# --agent runs also auto-discover .praisonai/tools/*.py now
praisonai run --agent researcher --allow-local-tools "use the greet tool to greet Ada"
```

If tool files exist but neither is set, `run` prints a one-line hint naming the location(s) and enable step — no more silent skip. See [Project-Local Tools](/docs/features/project-local-tools).

### Resume a previous session

Continue where you left off in your current project:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "now add tests" --continue
```

Resume a specific session by ID:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "what were we working on?" --session abc12345
```

Fork from a session to try a different approach:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "try a different approach" --fork --session abc12345
```

Run without saving the session:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "one-off question" --no-save
```

<Note>
  `--continue` and `--session` restore the model recorded on that session — even if your default model has changed since. Pass `--model <name>` to override and update the recorded model going forward. See [Session Resume — Model Restoration](/docs/cli/session-resume#model-restoration).
</Note>

<Note>
  After every run with an active session, a compact usage footer prints to stdout:

  ```
  1,240 in / 3,980 out · $0.0140
  ```

  This footer is silenced under `--output json`. Token and cost totals accumulate across resumed runs — they are never reset. See [Cost Tracking](/docs/cli/cost-tracking) for per-session totals.
</Note>

### Run without project instruction files

By default, `praisonai run` auto-loads `AGENTS.md`, `CLAUDE.md`, `PRAISON.md`, etc. from the project root **and** attaches nested-subtree instruction files as the agent touches them. Use `--no-rules` (or `PRAISON_NO_RULES=true`) to opt out of both:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "Quick one-off task" --no-rules
```

Use `--verbose` to see which instruction files were loaded:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "What does this codebase do?" --verbose
# > Loaded project instructions: AGENTS.md, CLAUDE.md
```

***

## Isolated worktree runs

Pass `--worktree` to run the agent on a fresh git branch and worktree so its output never touches your working tree. Add `--keep` to retain the worktree and branch for review.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "Refactor the auth module" --worktree
praisonai run agents.yaml --worktree --keep
```

See [Run in an Isolated Worktree](/docs/features/run-worktree) for the full teardown behaviour matrix and rejected-combination rules.

***

## Live session attach

Tag a warm-runtime run with a session id so other terminals can stream its events with [`praisonai attach`](/docs/cli/attach).

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Terminal A
praisonai daemon start --background
praisonai run "Research topic X" --attach my-session

# Terminal B
praisonai attach my-session
```

<Note>
  `--attach <id>` is an **event-stream label**, not a session identity — it only fans out live events to `praisonai attach <id>` clients (falling back to the session id when omitted). It does not by itself select or persist a conversation; persistence is driven by `--session <id>` or `--continue`. So `praisonai run "..." --no-save --attach obs-1` streams events under `obs-1` but persists nothing.

  `--attach` is supported for **direct prompt runs only** — not YAML files, `--agent`, or `--command`. Requires a compatible warm runtime (`praisonai daemon start`). Major-version mismatch falls back to in-process execution for `run`, or exit code 1 for `attach`.
</Note>

***

## Isolated Runs (`--worktree`)

Add `--worktree` to run the agent on a fresh git branch and worktree so its edits never touch your working tree.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run "refactor auth to use bcrypt" --worktree
# > Isolated run on branch 'praisonai/refactor-auth-<uid>' (./.praisonai/worktrees/refactor-auth-<uid>)
# ... agent runs ...
# > Committed changes to branch 'praisonai/refactor-auth-<uid>'.
# > Review/merge with: git merge praisonai/refactor-auth-<uid>
```

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Isolated Run"
        Start[📋 praisonai run --worktree] --> Fork[🌱 git worktree<br/>praisonai/branch]
        Fork --> Agent[🧠 Agent runs<br/>cwd=worktree]
        Agent --> Result{Changes?}
        Result -->|Yes| Commit[💾 auto-commit<br/>keep branch]
        Result -->|No| Prune[🧹 remove branch + worktree]
        Commit --> Merge[🔀 git merge branch]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff
    classDef prune fill:#189AB4,stroke:#7C90A0,color:#fff

    class Start input
    class Fork,Agent process
    class Commit,Merge result
    class Prune prune
```

`--worktree` provisions a fresh git worktree on a new branch, `chdir`s into it, runs the agent, then prints the branch name and a `git status --short` summary. Every other flag (`--tools`, `--model`, `--session`, `--thinking`, `--memory`) applies unchanged.

### How teardown protects your output

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant CLI as praisonai run
    participant Git
    participant Agent
    participant Workspace as Original cwd

    User->>CLI: praisonai run --worktree "prompt"
    CLI->>Git: git worktree add (fresh branch)
    Git-->>CLI: worktree ready
    CLI->>Workspace: chdir(worktree)
    CLI->>Agent: run(...)
    Agent-->>CLI: done (files changed?)

    alt changes present
        CLI->>Git: git add -A && git commit --no-verify
        CLI->>Git: git worktree remove (checkout only)
        CLI-->>User: "Committed changes to branch 'praisonai/...'. Review/merge with: git merge praisonai/..."
    else no changes
        CLI->>Git: git worktree remove + delete branch
        CLI-->>User: "No changes on 'praisonai/...'."
    end

    classDef user fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef cli fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef git fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef agent fill:#10B981,stroke:#7C90A0,color:#fff

    class User user
    class CLI cli
    class Git,Workspace git
    class Agent agent
```

Changes are detected with `git status --porcelain`, so brand-new untracked files count. When the agent produced output, the CLI auto-commits everything to the branch (`praisonai run: <target>`, `--no-verify`) and retains the branch — only the worktree checkout is pruned. A run with no changes is torn down completely.

If the auto-commit fails (for example no `user.email`/`user.name` is configured, or a hook rejects it), the worktree checkout is kept in place with a `Could not commit isolated changes; worktree kept at <path> (branch '<branch>') for manual review.` warning — your output is never lost.

### What happens on teardown

The run detects changes with `git status --porcelain`, so brand-new (untracked) files are never lost.

| Situation                             | Worktree checkout              | Branch                        | Reported                                                                                           |
| ------------------------------------- | ------------------------------ | ----------------------------- | -------------------------------------------------------------------------------------------------- |
| No changes                            | Removed                        | Removed                       | `No changes on '<branch>'.`                                                                        |
| Any change (tracked **or** untracked) | Pruned                         | **Retained** with auto-commit | `Committed changes to branch '<branch>'. Review/merge with: git merge <branch>`                    |
| `--keep`                              | **Retained**                   | **Retained**                  | `Worktree kept at <path> (branch '<branch>'). Review/merge then remove with: git worktree remove.` |
| Commit fails (e.g. no git identity)   | **Retained** for manual review | Retained                      | Warning: `Could not commit isolated changes; worktree kept at <path> ...`                          |
| Cwd is not a git repo                 | n/a (no-op)                    | n/a                           | Warning: `Not a git repository; running without worktree isolation.`                               |

<Warning>
  `--worktree` never destroys the agent's output. On any change the branch is committed and retained even without `--keep` — only the worktree checkout is pruned.
</Warning>

### When to use it

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Start([Should I use --worktree?])
    Editing{Will the agent<br/>edit files?}
    Multiple{Multiple agents<br/>in parallel?}
    Review{Want to review<br/>before applying?}
    Git{Inside a git repo?}

    Start --> Editing
    Editing -->|No| Skip[❌ Skip --worktree<br/>no isolation needed]
    Editing -->|Yes| Git
    Git -->|No| NoOp[⚠️ --worktree becomes a no-op<br/>runs in current cwd]
    Git -->|Yes| Multiple
    Multiple -->|Yes| Use[✅ --worktree<br/>one branch per run]
    Multiple -->|No| Review
    Review -->|Yes| Keep[✅ --worktree --keep<br/>inspect the worktree]
    Review -->|No| Use

    classDef question fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef action fill:#10B981,stroke:#7C90A0,color:#fff
    classDef warn fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef skip fill:#8B0000,stroke:#7C90A0,color:#fff

    class Start,Editing,Multiple,Review,Git question
    class Use,Keep action
    class NoOp warn
    class Skip skip
```

### Recipes

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Run an agent on a fresh branch, then merge if you like the result
praisonai run agents.yaml --worktree
# → prints:  Committed changes to branch 'praisonai/agents.yaml-a1b2c3d4'.
#            Review/merge with: git merge praisonai/agents.yaml-a1b2c3d4
git merge praisonai/agents.yaml-a1b2c3d4
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Keep the worktree open for hands-on review
praisonai run agents.yaml --worktree --keep
# → prints:  Worktree kept at /path (branch 'praisonai/...').
#            Review/merge then remove with: git worktree remove.
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Run several agents in parallel on the same repo — each gets its own branch
praisonai run "Add tests to lib/api" --worktree &
praisonai run "Refactor lib/db"      --worktree &
wait
```

A short `uuid4` token is appended to each run's branch name (e.g. `praisonai/agents.yaml-a1b2c3d4`), so concurrent runs of the same target never collide.

### Compatibility

The CLI rejects incompatible combinations at parse time.

| Combined with                                               | Behaviour                                                                                                                                             |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--attach <id>`                                             | ❌ `Error: --worktree cannot be combined with --attach` — isolated runs stay in-process, but `--attach` targets the warm runtime (a separate process). |
| `--keep` without `--worktree`                               | ❌ `Error: --keep requires --worktree` — `--keep` is meaningless without isolation.                                                                    |
| `--agent <name>`                                            | ❌ `Error: --worktree is only supported for direct prompt and YAML file runs` — the custom-agent flow has its own execution path.                      |
| `--command <name>`                                          | ❌ Same error — the custom-command flow has its own execution path.                                                                                    |
| `--profile` / `--profile-deep`                              | ❌ Same error — the profiling flow has its own execution path.                                                                                         |
| `--session <id>` / `--continue`                             | ✅ Works — session state is stored outside the worktree.                                                                                               |
| `--tools`, `--toolset`, `--model`, `--thinking`, `--memory` | ✅ Works — orthogonal to isolation.                                                                                                                    |
| Warm runtime (`praisonai daemon start`)                     | ⚠️ Bypassed — isolated runs always execute in-process, even when a warm runtime is available.                                                         |

<Tip>
  A short random 8-char token is appended to every branch/worktree name, so two runs of the **same** target never collide — run `praisonai run "..." --worktree` twice in parallel and each gets its own branch and directory.
</Tip>

### Best practices

<AccordionGroup>
  <Accordion title="Auto-commit means your output is never lost">
    On completion, any tracked or untracked change is committed to the branch and the branch is retained. Even if the auto-commit fails (missing `user.email`/`user.name`, hook rejection), the worktree checkout is kept in place — you never have to fight the CLI for your agent's output.
  </Accordion>

  <Accordion title="Use --keep for inspection, not for saving output">
    Auto-commit already preserves your work on a branch. `--keep` is for cases where you want to review files in place before merging — compare screenshots, or run a local dev server against the checkout.
  </Accordion>

  <Accordion title="Non-git directories still work">
    The flag is a transparent no-op outside git. Wire it into every project script without conditionals: `praisonai run --worktree "..."` runs in the current cwd if there's no repo, printing `Not a git repository; running without worktree isolation.`
  </Accordion>

  <Accordion title="Cleaning up abandoned worktrees">
    `--keep` never auto-removes. When you're done: `git worktree remove <path> && git branch -D praisonai/…`. To see leftovers from all runs: `git worktree list`.
  </Accordion>
</AccordionGroup>

<Note>
  Three ways to get worktree isolation, one shared primitive:

  * **CLI (this page)** — `praisonai run --worktree` for one-off human-driven runs.
  * **Kanban** — set `workspace_kind="worktree"` on a task so dispatched workers each get one ([Per-Task Worktree Isolation](/docs/docs/features/kanban#per-task-worktree-isolation)).
  * **Library** — instantiate `GitWorktreeAdapter` yourself for programmatic isolation ([Workspace Isolation](/docs/features/workspace-isolation)).
</Note>

## See [Workspace Isolation](/docs/features/workspace-isolation) for the underlying `GitWorktreeAdapter` and the Python API.

## Project context

By default, `praisonai run` walks up from the current directory to your git root and prepends any `AGENTS.md` / `CLAUDE.md` / `agents.md` / `.agents/AGENTS.md` it finds to the agent's system prompt, layered on top of `~/.praisonai/AGENTS.md`. In a monorepo it also attaches a nested `packages/foo/AGENTS.md` the first time the agent touches a file under `packages/foo/` (parity with `chat`, wired in PR #3552). Pass `--no-context` (or set `PRAISON_NO_CONTEXT=true`) to disable the up-front walk-up, or `--no-rules` (or `PRAISON_NO_RULES=true`) to disable both. See [Context Files](/docs/features/context-files) for details.

### Declared instruction sources

To declare extra instruction sources — files, globs, or URLs — that load on every run, use the top-level `instructions:` config key or the repeatable `--instructions` flag. Config sources merge first, then `--instructions` flags append on top; the result is prepended to the agent's backstory as `# Project Instructions`. See [Instruction Sources](/docs/features/instruction-sources).

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# One-off: layer an extra rules file on top of AGENTS.md for this run only
praisonai run --instructions docs/rules.md "explain this codebase"

# Repeatable: multiple sources merge in order
praisonai run \
  --instructions ~/company/ai-rules.md \
  --instructions docs/standards/*.md \
  "review the diff"
```

The `--agent` and `--command` paths honour declared instructions too:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run --agent lead --instructions docs/rules.md "task"
praisonai run --command review --instructions docs/rules.md "task"
```

`--no-rules` (or `PRAISON_NO_RULES=true`) suppresses these declared sources along with the auto-discovered walk-up.

### Environment variables

These env vars gate the same context behaviour as the flags, for CI and scripted runs.

| Variable                                                     | Effect                                                                             | Precedence                       |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------- | -------------------------------- |
| `PRAISON_NO_RULES=true` (`1`/`true`/`yes`, case-insensitive) | Same as passing `--no-rules`; skips both the up-front load and the subtree hook    | CLI flag wins if both set        |
| `PRAISON_NO_CONTEXT=true`                                    | Skips the up-front `AGENTS.md`/`CLAUDE.md` walk-up injection                       | CLI flag wins if both set        |
| `PRAISON_CONTEXT_BUDGET=<int>`                               | Char budget for the subtree hook. `0` (or missing / non-integer) disables the cap. | Applies to both `chat` and `run` |

## First-run Credential Check

`praisonai run` verifies credentials are configured before doing any work. With no cloud key, it first checks for a reachable local endpoint and adopts it automatically — the prompt below only appears when nothing is reachable.

If no cloud key and no local endpoint is found, you'll see:

**Interactive (TTY):**

```
No API key configured.
Would you like to run the setup wizard now? [Y/n]:
```

**Local model reachable (no cloud key needed):**

```
No cloud key found; using local model ollama/llama3.2. Run `praisonai setup` to add a hosted provider.
```

**CI / non-interactive (no key and no local endpoint):**

```
Error: No API key configured. Run: praisonai setup
(a running local endpoint such as Ollama would be used automatically)
```

When no cloud key is set, PraisonAI probes for a local OpenAI-compatible endpoint (Ollama or any `/v1`-speaking server) and adopts it automatically before falling back — see [Keyless local-first fallback](/docs/docs/models#keyless-local-first-fallback-no-env-vars-set). Non-TTY/CI still exits `1` when nothing is detected, so pipelines fail safe.

Exit code is `1` in CI mode. Set any supported env var to bypass the check entirely:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
export OPENAI_API_KEY=sk-...
praisonai run "hello"
```

"Supported env var" now means any of the 14 credential keys in the [Credential → default-model map](/docs/cli/setup#credential--default-model-map), so `MISTRAL_API_KEY` (or any catalogue key) also silences the credential gate:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
export MISTRAL_API_KEY=...
praisonai run "hello"
# Uses mistral/mistral-large-latest — no --model, no wizard.
```

### Local model fallback

When no cloud key is configured, `praisonai run "..."` probes for a reachable local endpoint (Ollama or any OpenAI-compatible server) and adopts its model + base URL for the run — no `--model` needed. A cloud key always wins; the local probe only runs as a fallback.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
ollama serve
praisonai run "Summarise this file"
# stderr: No cloud key found; using local model ollama/llama3.2. Run `praisonai setup` to add a hosted provider.
```

See [Auth](/docs/cli/auth), [First-run Onboarding](/docs/features/first-run-onboarding), and [Keyless Local-First Run](/docs/features/keyless-local-first-run) for the full behaviour matrix and CI examples.

***

## Session Continuity

Pick up where you left off — `praisonai run` remembers per-project conversations and tracks cumulative token usage and cost.

### Continue / session runs attach to the warm daemon

When a warm daemon is running, `--continue` and `--session <id>` runs now attach to it and reuse a warm, per-session agent instead of paying cold-start each turn. The first turn rehydrates history from the project session store; subsequent turns run against the retained warm agent. On failure the warm agent is dropped and the next turn rehydrates cleanly from the store, so recovery semantics match the in-process path. Fork (`--fork`) still runs the first turn in-process to mint the new id, then attaches warm on later turns against that id. See [Daemon](/docs/features/daemon) for the full warm-runtime lifecycle.

### Usage footer

When running with an active session (`--session <id>` or `--continue`), a compact footer appears after each answer:

```
1,240 in / 3,980 out · $0.0140
```

The footer is suppressed in `--json` / `--output json` mode, but usage is still persisted into the session record. Totals accumulate across runs and survive resume. See [Cost & Token Tracking](/docs/docs/cli/session#cost--token-tracking) for the full breakdown.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Session Flow"
        A[📋 Run 1] --> B[💾 Session stored per project]
        B --> C[🔄 Run 2 --continue]
        C --> D[📈 Conversation continues]
    end
    
    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff
    
    class A input
    class B,C process
    class D output
```

<Steps>
  <Step title="Continue the last run">
    Continue the most recent session for your current project:

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run --continue "now add tests"
    ```

    `--continue` searches **both** the project store and the global default store, so it resolves the genuinely most-recent **root** session — including ones created by `chat`, gateway, TUI, API, or a bare `Agent(memory={"session_id": "..."})`. If no previous session exists, a warning is shown and a new session starts.
  </Step>

  <Step title="Resume a specific session">
    Resume a specific session by ID (find IDs with `praisonai session list`):

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run --session abc123 "what were we working on?"
    ```

    Errors out if the session ID does not exist in the current project.
  </Step>

  <Step title="Try a different approach without losing history">
    Fork from an existing session to try alternatives:

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run --fork --session abc123 "try Postgres instead of SQLite"
    ```

    Creates a new session ID copied from the source. Both sessions evolve independently.
  </Step>

  <Step title="What gets restored on --continue / --session">
    When you use `--continue` or `--session <id>`, every prior user, assistant, **assistant-tool-call**, and **tool-result** message in that session is replayed into the agent's chat history before your new prompt runs. The agent answers with full awareness of what was discussed *and* what tools it called — no manual context-passing required. Tool-call persistence in the default JSON store landed in PraisonAI PR [#3099](https://github.com/MervinPraison/PraisonAI/pull/3099).

    ```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    sequenceDiagram
        participant User
        participant CLI
        participant PS as Project session store
        participant GS as Global default store
        participant Agent

        User->>CLI: praisonai run --continue "..."
        CLI->>PS: list_sessions(limit)
        CLI->>GS: list_sessions(limit)
        Note over CLI: merge + dedup by session_id, freshest wins, prefer root sessions
        CLI->>PS: get_chat_history(session_id)
        PS-->>CLI: prior turns
        CLI->>Agent: pre-populate chat_history, then run new prompt
        Agent-->>User: response (aware of prior turns)

        classDef cli fill:#8B0000,stroke:#7C90A0,color:#fff
        classDef store fill:#189AB4,stroke:#7C90A0,color:#fff
        classDef result fill:#10B981,stroke:#7C90A0,color:#fff

        class User,CLI cli
        class PS,GS store
        class Agent result
    ```

    **Restored automatically:** user, assistant, assistant-tool-call, and tool-result `chat_history` messages; `auto_save` continues for the resumed session.

    **Not restored:** intermediate scratchpad beyond the persisted tool turns; file artefacts from earlier runs remain on disk but are not re-emitted.

    | Restored                                                           | From                                                                                                                                                                                                                                                                          |
    | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Chat history (user + assistant + tool-call + tool-result messages) | Project store: `~/.praisonai/sessions/projects/<project_id>/<session_id>.json` — or global store: `~/.praisonai/sessions/<session_id>.json` (used when `--continue` picks up a session created by `chat`, gateway, TUI, API, or a bare `Agent(memory={"session_id": "..."})`) |
    | Auto-save bookmark (only new messages appended)                    | Same file the session lives in                                                                                                                                                                                                                                                |
    | Session ID                                                         | `--session <id>` flag, or the last **root** session across both stores for `--continue`                                                                                                                                                                                       |

    <Note>
      As of the fix for [PraisonAI #2655](https://github.com/MervinPraison/PraisonAI/issues/2655), `--continue` searches both the project-scoped store **and** the global default store, so sessions created by `chat`, gateway, TUI, API, or a bare `Agent(memory={"session_id": "..."})` are all resumable. Sub-agent / forked child sessions are skipped in favour of the last root session.
    </Note>

    <Note>
      History restore and save wiring landed in [PR #1963](https://github.com/MervinPraison/PraisonAI/pull/1963). Earlier builds discovered the session but silently dropped prior history on resume — upgrade `praisonai` if `--continue` returns empty context.
    </Note>
  </Step>
</Steps>

### Choosing between the flags

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Start(["Need session continuity?"])
    Continue["Just keep going?"] 
    SpecificSession["Have a specific session ID?"]
    Branch["Want to branch without affecting original?"]
    NoSave["Don't want this run remembered?"]
    
    Start --> Continue
    Start --> SpecificSession
    Start --> Branch
    Start --> NoSave
    
    Continue --> ContinueFlag["--continue"]
    SpecificSession --> SessionFlag["--session <id>"]
    Branch --> ForkFlag["--fork --session <id>"]
    NoSave --> NoSaveFlag["--no-save"]
    
    classDef question fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef answer fill:#10B981,stroke:#7C90A0,color:#fff
    
    class Start,Continue,SpecificSession,Branch,NoSave question
    class ContinueFlag,SessionFlag,ForkFlag,NoSaveFlag answer
```

<Tabs>
  <Tab title="Prompt mode">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # First run
    praisonai run "Build a FastAPI todo app"

    # Continue tomorrow
    praisonai run --continue "now add tests"

    # Continue with specific session
    praisonai run --session abc123 "deploy it to Fly.io"

    # Resume while emitting structured tool actions (JSON stream)
    praisonai run --session abc123 --output actions "deploy it to Fly.io"
    ```
  </Tab>

  <Tab title="YAML mode">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # First run
    praisonai run agents.yaml

    # Continue with YAML file
    praisonai run agents.yaml --continue

    # Continue with specific session
    praisonai run agents.yaml --session abc123

    # Fork a YAML run to try a variation
    praisonai run agents.yaml --fork --session abc123
    ```
  </Tab>
</Tabs>

<Note>
  `--continue` / `--session` / `--fork` / `--no-save` work for YAML/team runs identically to prompt runs. Prior team conversation — per-agent chat history **and** shared team state — is replayed. The flags are honored **regardless of whether `agents.yaml` sets `memory: true`**; session continuity opts the team into shared memory automatically. See [YAML / Team Session Continuity](/docs/features/yaml-session-continuity).
</Note>

### Session usage footer

After every prompt run inside an active session, a single-line footer shows cumulative token and cost totals:

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Usage footer"
        Run[📝 praisonai run] --> Agent[🧠 Agent]
        Agent --> Collect[token_collector]
        Collect --> Accumulate[accumulate_session_usage]
        Accumulate --> Footer[⚡ 1,240 in / 3,980 out · $0.0140]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff

    class Run input
    class Agent,Collect,Accumulate process
    class Footer result
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
$ praisonai run "Summarise yesterday's PRs"
... (agent output) ...
1,240 in / 3,980 out · $0.0140
```

The format is:

```
{input_tokens:,} in / {output_tokens:,} out · ${cost:.4f}
```

* Totals are **cumulative since session start** — not just the last prompt.
* **Best-effort:** if usage cannot be read or priced, the footer is silently skipped.
* **Suppressed in JSON mode** (`--output json`, `--output stream-json`). There is no `--no-usage` flag.
* Usage is persisted to `~/.praisonai/sessions/<id>.json` so resuming with `--continue` or `--session <id>` rehydrates the totals and keeps accumulating.

**JSON mode** — the footer is suppressed but usage is included in the payload:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
$ praisonai run --output json "Summarise yesterday's PRs"
{"session_id":"abc12345","output":"...","usage":{"input_tokens":1240,"output_tokens":3980,"total_tokens":5220,"cost":0.0140,"requests":1}}
```

### Troubleshooting session continuity

<AccordionGroup>
  <Accordion title="`--continue` runs but the agent has no memory of the previous turn">
    Fixed in [PR #1963](https://github.com/MervinPraison/PraisonAI/pull/1963) — sessions were discovered but history was not loaded. Upgrade `praisonai` and re-run.
  </Accordion>

  <Accordion title="`--output actions --session <id>` raised TypeError about resume_session">
    Fixed by [PR #1963](https://github.com/MervinPraison/PraisonAI/pull/1963). Upgrade `praisonai`.
  </Accordion>

  <Accordion title="`--output actions` with `--auto-save` raised TypeError about `auto_save`">
    Fixed by [commit `7016bfa`](https://github.com/MervinPraison/PraisonAI/commit/7016bfaf5772b0c40d567cfbafeb363b21874505) (issue #2700). The actions-output branch of `run` re-imported `build_cli_memory_config` / `apply_cli_session_continuity` from `praisonai_code.cli.utils.project`, shadowing the correct `praisonai_code.cli.state.project_sessions` versions. The stale variant lacked the `auto_save` keyword, so wiring session continuity in actions mode raised `TypeError: apply_cli_session_continuity() got an unexpected keyword argument 'auto_save'`. Upgrade `praisonai-code` and re-run.
  </Accordion>

  <Accordion title="Session continuity works in prompt mode but not with agents.yaml">
    Also fixed by [PR #1963](https://github.com/MervinPraison/PraisonAI/pull/1963) — YAML and file-mode runs use the same project session store as prompt-mode runs.
  </Accordion>

  <Accordion title="`--no-save` together with `--session <id>`">
    `--no-save` wins — the run still resumes from the named session (agent has context), but new messages are not persisted. Useful for read-only follow-ups on an existing thread.
  </Accordion>
</AccordionGroup>

<Info>
  Sessions are scoped to the current project — detected from the git root, or the current directory if you're not in a repo. Two projects never see each other's sessions.
</Info>

***

## Agent File Format

Create an `agents.yaml` file:

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
framework: praisonai
topic: Research Assistant
roles:
  researcher:
    backstory: Expert research analyst
    goal: Find accurate information
    role: Researcher
    tasks:
      research_task:
        description: Research the given topic
        expected_output: Comprehensive research summary
```

## Session Management

Sessions are scoped to the **current project** (git root, or current directory if not a git repository). Each run auto-saves to a generated `session-<uuid8>` unless `--no-save` is set.

<Note>
  Use `praisonai session list` to view saved sessions for the current project, or `praisonai session list --all` to see sessions across all projects.
</Note>

***

## Checkpoint & Rewind

`praisonai run` auto-checkpoints your workspace before YAML-file runs so a bad turn can be rewound with one command.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant CLI as praisonai run
    participant CP as Checkpoint Engine
    participant Agents

    User->>CLI: praisonai run agents.yaml
    CLI->>CP: auto-checkpoint (run:<id>)
    CP-->>CLI: ✅ saved
    CLI->>Agents: execute
    Agents-->>User: results

    User->>CLI: praisonai run --restore last
    CLI->>CP: restore last checkpoint
    CP-->>User: workspace rewound

    classDef user fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef cli fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef cp fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef agents fill:#10B981,stroke:#7C90A0,color:#fff

    class User user
    class CLI cli
    class CP cp
    class Agents agents
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run agents.yaml            # auto-checkpoint, then run
praisonai run --restore last         # rewind workspace, exit
praisonai run agents.yaml --no-checkpoint   # skip the auto-checkpoint
```

**Auto-checkpoint behaviour:**

* Runs before any YAML-file execution (`*.yaml` / `*.yml` targets only).
* Label: `run:<run_id>` (or `"auto checkpoint before run"` as a fallback).
* Workspace: the directory of the target YAML file, not the current directory.
* Plain-prompt runs are skipped to avoid empty-checkpoint noise.
* Best-effort — failures are swallowed and never block the run. Use `--verbose` to see `"Auto-checkpoint skipped: …"` on failure.
* Gated by `checkpoints.auto` (default `true`) in your project config; override per-run with `--no-checkpoint`.
* Reads `checkpoints.storage_dir` from your project config so the auto-checkpoint/restore path shares the same store as `praisonai code --checkpoints` sessions. See [Checkpoints](/docs/features/checkpoints) for the config block.

**New checkpoint flags:**

| Flag                           | Description                                                    | Default |
| ------------------------------ | -------------------------------------------------------------- | ------- |
| `--restore <id\|last\|latest>` | Restore the workspace to a checkpoint and exit — nothing runs. | —       |
| `--no-checkpoint`              | Disable the automatic pre-run checkpoint for this invocation.  | `false` |

<Note>
  `--restore` rewinds the workspace and exits **before** any agent execution — it is a pure undo, not a run.
  See [Checkpoints](/docs/features/checkpoints) and [Checkpoint CLI](/docs/cli/checkpoint) for managing checkpoints directly.
</Note>

### Coherent rewind (`--revert`)

Roll files **and** the named session's conversation back to a prior turn, then exit. Distinct from `--restore`, which is file-only.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run --revert                        # last turn, files-only preview
praisonai run --revert last --session my-feat # last turn, rewinds my-feat conversation too
praisonai run --revert 3    --session my-feat # last 3 turns
```

| Argument                            | Effect                           |
| ----------------------------------- | -------------------------------- |
| `--revert` (no value)               | Revert the last 1 turn.          |
| `--revert last` / `--revert latest` | Revert the last 1 turn.          |
| `--revert N`                        | Revert the last N turns (N ≥ 1). |

When `--session <id>` is provided the flag also rewinds that session's conversation to the same boundary. Rewind counts real **user messages** (not a fixed 2·N assumption) so tool/system messages don't orphan a partial turn.

<Note>
  File checkpoints are workspace-wide (they carry no session tag). In a workspace shared by multiple sessions the Nth-back file checkpoint may not belong to the session whose conversation is being rewound — the CLI prints this note explicitly and recommends interactive `/undo` for fully per-session coherence.
</Note>

***

## YAML Workflows Are Permission-Gated

`praisonai run workflow.yaml` honours the **same** approval and permission flags as a single-agent `praisonai run "<prompt>"`. The flags are threaded onto the workflow engine, so a YAML run can no longer bypass a `deny` rule that a prompt run would enforce.

<Warning>
  On older versions these flags were silently dropped on the YAML path, so a `--deny "bash:rm *"` on a workflow file did nothing. They are now enforced. Runs with **no** permission or approval flags are unchanged — see the backward-compatible default below.
</Warning>

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run workflow.yaml \
  --deny "bash:rm *" \
  --allow "bash:pytest *" \
  --approval console \
  --approval-timeout 60
```

### Precedence ladder

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Start[praisonai run workflow.yaml] --> Explicit{--approval set?}
    Explicit -->|Yes| Backend[Use that backend<br/>console / plan / accept-edits / bypass]
    Explicit -->|No| Rules{Any --allow / --deny /<br/>--permissions / --permission-default?}
    Rules -->|Yes| Console[Implicit console backend<br/>so deny / ask rules are enforced]
    Rules -->|No| Config{Project config rules?<br/>.praisonai/permissions.yaml}
    Config -->|Yes| Console
    Config -->|No| Legacy[No gate — legacy default preserved]

    classDef start fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef gate fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef backend fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef legacy fill:#8B0000,stroke:#7C90A0,color:#fff

    class Start start
    class Explicit,Rules,Config gate
    class Backend,Console backend
    class Legacy legacy
```

| Priority | Condition                                                                                    | Result                                                             |
| -------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| 1        | `--approval <mode>` set explicitly                                                           | That backend wins (`console`, `plan`, `accept-edits`, `bypass`)    |
| 2        | Any `--allow` / `--deny` / `--permissions` / `--permission-default` present, no `--approval` | Implicit `console` backend so `deny` / `ask` patterns are enforced |
| 3        | Project config rules (`.praisonai/permissions.yaml`, etc.)                                   | Merged into the same rule set as the prompt path                   |
| 4        | No approval flags **and** no permission rules                                                | Legacy default — **no gate**, prior behaviour preserved exactly    |

### What propagates to a YAML run

<AccordionGroup>
  <Accordion title="Explicit --approval wins">
    `praisonai run workflow.yaml --approval console` (or `plan`, `accept-edits`, `bypass`) sets the backend for the workflow run — identical to the prompt path.
  </Accordion>

  <Accordion title="Permission rules imply --approval console">
    A `--deny`, `--allow`, `--permissions`, or `--permission-default` on its own activates a `console` backend. Without this, a permission rule on a YAML workflow used to be silently bypassed.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # No --approval, but the deny rule still activates a console backend
    praisonai run workflow.yaml --deny "bash:rm *"
    ```
  </Accordion>

  <Accordion title="--approve-all-tools and --approval-timeout propagate">
    Both propagate to YAML runs, matching the single-agent `run "<prompt>"` semantics.

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run workflow.yaml --approve-all-tools --approval-timeout 120
    ```
  </Accordion>

  <Accordion title="Backward-compatible default (no flags → no gate)">
    A plain `praisonai run workflow.yaml --no-save` with no permission or approval flags threads no approval override at all, so the legacy engine preserves prior behaviour exactly. Existing pipelines see no change.
  </Accordion>

  <Accordion title="Composes with session flags">
    `--continue`, `--session <id>`, `--fork`, and `--no-save` already flow into the same YAML engine; the approval/permission flags now compose with them. A `--no-save` workflow run with only `--allow` sets approval **without** persisting a session.
  </Accordion>

  <Accordion title="Rule-source precedence (CLI + project config)">
    Permission rules come from CLI flags **and** project config, merged the same way the prompt path merges them — so a YAML run picks up `.praisonai/permissions.yaml` (or equivalent) identically. See [Permissions](/docs/features/permissions).
  </Accordion>
</AccordionGroup>

For the full approval-gating story and backend semantics, see [Approval › YAML workflow approval gating](/docs/features/approval#yaml-workflow-approval-gating).

***

## See Also

* [Isolated Runs (`--worktree`)](/docs/features/cli-worktree-isolation) - Run on a fresh git branch per run
* [Session](/docs/cli/session) - Session management commands
* [Project-Scoped Sessions](/docs/features/project-sessions) - How project sessions work
* [Checkpoints](/docs/features/checkpoints) - Auto-checkpoint and rewind feature
* [Checkpoint CLI](/docs/cli/checkpoint) - Checkpoint subcommands
* [Agents](/docs/cli/agents) - Agent management
* [Custom Agents, Commands & Tools](/docs/features/custom-agents-commands) - Define agents and how their tools compose on `--agent`
* [Project-Local Tools](/docs/features/project-local-tools) - Auto-discovered `.praisonai/tools/*.py` on `run` and `run --agent`
* [Workspace Isolation](/docs/features/workspace-isolation) - `--worktree` per-run git isolation and the `GitWorktreeAdapter` Python API
* [Workflow](/docs/cli/workflow) - Workflow execution
* [Interactive TUI](/docs/cli/interactive-tui) - Interactive terminal interface
* [Attach](/docs/cli/attach) - Stream live events from a warm-runtime session
* [Workspace Isolation](/docs/features/workspace-isolation) - Per-agent git worktree adapter (the SDK primitive `--worktree` exposes)
