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 for how routing is decided.

Usage

bash
praisonai run [OPTIONS] [TARGET]

Arguments

ArgumentDescription
TARGETAgent 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), the router hands TARGET to the modern agent runner whenever it ends in .yaml / .yml (even if the file does not exist yet — the runner is what emits the clear file-not-found error), or it is an existing file on disk. Only a TARGET that is neither of those and is 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.

Bare Prompts and YAML

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

bash
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
bash
# Typo? Wrong directory? You still get a clear error from the runner.
praisonai run typo.yaml
# Error: [Errno 2] No such file or directory: 'typo.yaml'

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

Diagram

Yes

No

No — legacy-only flag

Yes / no flags

praisonai ARGV

First token is
Typer command?

Typer command

All flags
run-supported?

Legacy argparse
+ stderr notice

Modern Typer run
prompt or .yaml

Same as: praisonai run TARGET flags

YAML workflows through the modern run engine

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:

CapabilityFlags
Session continuity--continue, --session <id>, --fork
Output modes`–output silent\actions\verbose\json\stream\stream-json`
First-run credential gateOllama detection + setup wizard rescue
Permissions & approval--allow, --deny, --approval, --permission-default
bash
# 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.

Options

OptionShortDescriptionDefault
--output-oOutput mode: text, plain, verbose, silent, actions, json, stream, stream-jsontext
--model-mLLM model to usegpt-4o-mini
--framework-fFramework: praisonai, crewai, autogenpraisonai
--interactive-iEnable interactive modefalse
--verbose-vVerbose outputfalse
--streamStream outputtrue
--no-streamDisable streaming
--traceEnable tracingfalse
--memoryEnable memoryfalse
--tools-tComma-separated tool names (e.g. web_search,github) or a tools.py file path (resolved via ToolResolver)
--toolsetComma-separated named toolset groups to load
--allow-local-toolsLoad project-local .praisonai/tools/*.py for this run only (equivalent to PRAISONAI_ALLOW_LOCAL_TOOLS=true, but strictly per-invocation)false
--pure / --no-pluginsSkip discovery/loading of external plugins for this run only (equivalent to PRAISONAI_NO_PLUGINS=1); persisted enable/disable state is unchanged.false
--max-tokensMaximum output tokens16000
--continue-cContinue the most recent session for this projectfalse
--session-sResume a specific session ID
--forkFork from the specified session (requires --session)false
--pick / --interactive-sessionInteractively pick a recent session to resume before running (TTY only; ignored with --session / --continue or --json). Aborts with exit 1 if the user cancels or no sessions exist. See Pick a session to resume.false
--no-saveDon’t auto-save the session after executionfalse
--no-rulesDisable 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
--instructionsExtra 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.
--append-system-promptAppend text (literal or @file) to the system prompt for this invocation only. Env fallback: PRAISONAI_APPEND_SYSTEM_PROMPT. Never persisted. See 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.None
--no-contextDisable AGENTS.md/CLAUDE.md auto-loading into system promptfalse
--agent-aUse a named custom agent from .praisonai/agents/
--subagentsComma-separated named agents (.praisonai/agents/*.md) the running agent may delegate to. Omit to expose agents marked mode: subagent.
--thinkingReasoning effort for this invocation: off, minimal, low, medium, high
--commandExecute a named custom command; TARGET becomes $ARGUMENTS
--allowAllow a permission pattern (e.g. 'bash:git *'); repeatable
--denyDeny a permission pattern; repeatable
--permissionsPath to a YAML permission rules file
--permission-defaultDefault action for unmatched patterns: allow, deny, or ask
--approvalApproval backend mode: console, plan, accept-edits, bypass
--planRead-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
--restoreRestore 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-checkpointDisable automatic pre-run checkpoint for this invocationfalse
--attachEvent-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. Observers can also steer or interrupt the live turn via praisonai attach -m "..." <id> and praisonai attach --interrupt <id>. See Attach.
--worktreeRun on an isolated git worktree/branch (branch-per-task); no-op outside a git repofalse
--keepWith --worktree, keep the worktree/branch after the run for review instead of tearing it downfalse
--append-system-promptAppend 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.

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
# 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
export PRAISONAI_APPEND_SYSTEM_PROMPT="Reply in strict JSON, no prose."
praisonai run "Summarise the changelog"

See 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.

Diagram

praisonai run –image

📝 Prompt

🖼️ ImageHandler

📷 Local path or URL

🤖 Vision LLM

✅ Answer

  1. Attach one image
    bash
    praisonai run "Describe this screenshot" --image bug.png
  2. Attach multiple images

    Repeat the flag — never comma-separate a single value.

    bash
    praisonai run "Which of these two designs has better contrast?" \
      --image mock-a.png --image mock-b.png
  3. Attach a remote URL

    Any http:// or https:// URL is accepted verbatim.

    bash
    praisonai run "Summarize this architecture diagram" \
      --image https://raw.githubusercontent.com/example/repo/main/arch.png

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
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.

Multimodal Agents (Python / YAML)

Attach images from the Python SDK or a YAML workflow — the full multimodal story.

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
praisonai run --agent lead --subagents researcher,reviewer "Draft and review a brief on X"

See 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.

Diagram
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
# 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:

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.

No changes produced

The worktree checkout and its branch are torn down entirely — nothing is left behind.

No changes on '<branch>'.
–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.

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

Piped Input

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

bash
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 for the full behaviour.

Output Modes

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

text (default)

Rich-formatted human-readable output in the terminal.

bash
praisonai run "What is the capital of France?"

actions

Runs in-process with the core actions preset — a structured event stream written by the core preset. Standalone-safe (pip install praisonai-code).

bash
praisonai run --output actions "What is the capital of France?"

json

Emits one single-line {"result": "<text or null>", "status": "<outcome>"} envelope on stdout for every outcome — ok on success, truncated on a step-limit cutoff, failed on an empty-result failure, and content_filtered / refused / length_truncated on a provider block.

bash
praisonai run --output json "What is the capital of France?"
# {"result": "Paris", "status": "ok"}

A --output json | script pipe never sees empty stdout — the envelope is written before the exit-2 reporters run (fixes #5665 via PR #5685). Standalone-safe.

stream

Prints the final answer text on stdout. On exit 2 (blocked / truncated) it also prints the partial answer, unless --quiet is set. Standalone-safe.

bash
praisonai run --output stream "What is the capital of France?"
# Paris

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
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
{"event":"run.retry","data":{"schema_version":1,"attempt":2,"max_attempts":5,"delay":4.0,"reason":"rate_limit"}}

On exit 2 raw partial text is deliberately not printed (it would corrupt the NDJSON protocol); the terminal run.result event carries ok: false instead. See Stream Events for the full event protocol reference.

silent

No stdout output — useful when you only need the exit code.

bash
praisonai run --output silent "Run tests" && echo "passed"

verbose

Includes diagnostic details alongside normal output. Useful for debugging.

bash
praisonai run --output verbose "What is the capital of France?"

Partial-answer stdout on exit 2

On a blocked / truncated run (exit 2), the mode-specific stdout payload is written before the exit reporter runs, so a pipe or redirect never loses it.

Diagram

ok

blocked / truncated

stream + –quiet

📝 run –output

🔍 outcome

✅ stdout payload

✅ stdout payload first

⚠️ exit-2 reporter

🚫 suppress partial print

ModeExit-2 stdoutNotes
--output json`{“result”: “<partial text or null>”, “status”: “truncated\content_filtered\refused\length_truncated”}`Single-line envelope; always printed
--output streamThe partial answer textSuppressed when --quiet is set
--output stream-jsonTerminal run.result event with ok: false (no raw text)Raw text would corrupt the NDJSON protocol
--output actionsStructured events already emitted by the core presetNo extra CLI write

The --output stream quiet-mode suppression keeps --quiet honest in the exit-2 path. The --output json envelope writes on every outcome (ok, failed, truncated, content_filtered, refused, length_truncated), so a scripting consumer can always parse .status out of stdout (via PR #5685).


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.

Diagram

‘praisonai run outcome’

No: None or empty

content_filtered

refused

length_truncated

No

Yes: real answer

No

Yes

📝 Agent.start/run result

🔍 non-empty?

🔍 last_stop_reason
provider block?

🛡️ exit 2
status: ‘content_filtered’

🚫 exit 2
status: ‘refused’

✂️ exit 2
status: ‘length_truncated’

❌ exit 1
run_failed + remediation

🔍 last_stop_reason
== ‘max_steps’?

✅ exit 0
Run completed

⚠️ exit 2
status: ‘truncated’
summary preserved

ExitWhenEmitted where
0Agent returned a non-empty result and did not hit the step/iteration limitAll modes
1Agent 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--pick used, but the user cancelled or no sessions existDirect prompt / YAML
1No API key configured in CI modeDirect prompt
1Worktree flag combined with --attach, --agent, --command, or --profileDirect prompt
1--image combined with --agent / --profile / a YAML file / --output actions, or a comma inside a single --image valueDirect-prompt run
1Warm-runtime major-version mismatch on --attach--attach <id>
2Run 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)
2Provider content filter blocked the response (agent.last_stop_reason == "content_filtered")All three run paths (_run_prompt, --agent, --profile / --profile-deep)
2Model refused to answer / safety refusal (agent.last_stop_reason == "refused")All three run paths
2Response hit the model’s output length limit (agent.last_stop_reason == "length_truncated")All three run paths
2Single-word direct prompt collides with a reserved command / typo guardDirect prompt

Unified envelope (--output json)

Every outcome prints a single-line {"result": "<text or null>", "status": "<outcome>"} envelope on stdout — success included:

json
{"result": "Paris", "status": "ok"}

The subsections below document each non-ok outcome; they all share this envelope shape.

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
{"status": "failed", "result": null}

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

json
{"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

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
{"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.

See Step Budget for how max_steps truncation works, and Agent Run Outcomes → CLI Mapping 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
{"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 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
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
# 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 .status field of the unified envelope — every outcome carries one:

bash
result=$(praisonai run --output json "Refactor the auth module and add tests")
status=$(echo "$result" | jq -r '.status')
case "$status" in
  ok)               echo "done" ;;
  truncated)        echo "hit the step limit; raise ExecutionConfig(max_steps=…) 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 '.result // "run failed"'; exit 1 ;;
esac

Or branch on the exit code directly:

bash
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 for the truncation contract, and Agent Run Outcomes → CLI Mapping 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
pip install praisonai-code
praisonai-code chat
praisonai-code code "Refactor this function"

Every text mode — default run "…" and --output plain|verbose|silent|actions|json|stream|stream-json — plus interactive chat/code runs with no wrapper. The structured-mode in-process dispatch and the per-mode stdout contract (the {result, status} envelope for json, partial-answer-before-exit for stream) were cemented by PR #5685. 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 for the full command matrix.


Examples

Run a built-in preset (no YAML required)

bash
# 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
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
# 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.

Run with a custom agent and CLI permission override

bash
# 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
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.

Run with a custom command

bash
praisonai run --command summarise "Long text here"

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

Run from YAML file

bash
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.

Run with a prompt

bash
praisonai run "What is the capital of France?"

Run in read-only planning mode

bash
# 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 and Permissions.

Run in a monorepo

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

bash
# 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
praisonai run "Explain quantum computing" --model gpt-4o

Run in interactive mode

bash
praisonai run agents.yaml

Run with memory enabled

bash
praisonai run "Remember my name is John" --memory

Run with verbose output

bash
praisonai run agents.yaml --verbose

Run with custom tools

bash
# 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).

Run with project-local tools

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

bash
# 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.

Resume a previous session

Continue where you left off in your current project:

bash
praisonai run "now add tests" --continue

Resume a specific session by ID:

bash
praisonai run "what were we working on?" --session abc12345

Fork from a session to try a different approach:

bash
praisonai run "try a different approach" --fork --session abc12345

Pick a session to resume

No id handy? Use --pick (alias --interactive-session) to choose a recent session from a picker, then run a new prompt against it:

bash
# Pick a recent session interactively, then run a new prompt against it
praisonai run --pick "now add tests"

# Alias
praisonai run --interactive-session "now add tests"

--pick opens the same picker as session resume. It is a no-op when --session or --continue already names a session, and silently ignored under --json or a non-TTY so scripts and CI keep today’s behaviour. On a TTY with no --session / --continue, cancelling or an empty store aborts the run with exit code 1 rather than falling through to a fresh run.

Run without saving the session:

bash
praisonai run "one-off question" --no-save

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
praisonai run "Quick one-off task" --no-rules

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

bash
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
praisonai run "Refactor the auth module" --worktree
praisonai run agents.yaml --worktree --keep

See Run in an Isolated 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.

bash
# Terminal A
praisonai daemon start --background
praisonai run "Research topic X" --attach my-session

# Terminal B
praisonai attach my-session

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
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>
Diagram

Isolated Run

Yes

No

📋 praisonai run –worktree

🌱 git worktree
praisonai/branch

🧠 Agent runs
cwd=worktree

Changes?

💾 auto-commit
keep branch

🧹 remove branch + worktree

🔀 git merge branch

--worktree provisions a fresh git worktree on a new branch, chdirs 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

Diagram
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.

SituationWorktree checkoutBranchReported
No changesRemovedRemovedNo changes on '<branch>'.
Any change (tracked or untracked)PrunedRetained with auto-commitCommitted changes to branch '<branch>'. Review/merge with: git merge <branch>
--keepRetainedRetainedWorktree kept at <path> (branch '<branch>'). Review/merge then remove with: git worktree remove.
Commit fails (e.g. no git identity)Retained for manual reviewRetainedWarning: Could not commit isolated changes; worktree kept at <path> ...
Cwd is not a git repon/a (no-op)n/aWarning: Not a git repository; running without worktree isolation.

When to use it

Diagram

No

Yes

No

Yes

Yes

No

Yes

No

Should I use –worktree?

Will the agent
edit files?

Multiple agents
in parallel?

Want to review
before applying?

Inside a git repo?

❌ Skip –worktree
no isolation needed

⚠️ –worktree becomes a no-op
runs in current cwd

✅ –worktree
one branch per run

✅ –worktree –keep
inspect the worktree

Recipes

bash
# 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
# 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
# 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 withBehaviour
--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.

Best practices

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.

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.

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.

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.

See 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 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.

bash
# 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
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.

VariableEffectPrecedence
PRAISON_NO_RULES=true (1/true/yes, case-insensitive)Same as passing --no-rules; skips both the up-front load and the subtree hookCLI flag wins if both set
PRAISON_NO_CONTEXT=trueSkips the up-front AGENTS.md/CLAUDE.md walk-up injectionCLI 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. 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
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, so MISTRAL_API_KEY (or any catalogue key) also silences the credential gate:

bash
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
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, First-run Onboarding, and 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 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 for the full breakdown.

Diagram

Session Flow

📋 Run 1

💾 Session stored per project

🔄 Run 2 –continue

📈 Conversation continues

  1. Continue the last run

    Continue the most recent session for your current project:

    bash
    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.

  2. Resume a specific session

    Resume a specific session by ID (find IDs with praisonai session list):

    bash
    praisonai run --session abc123 "what were we working on?"

    Errors out if the session ID does not exist in the current project.

  3. Try a different approach without losing history

    Fork from an existing session to try alternatives:

    bash
    praisonai run --fork --session abc123 "try Postgres instead of SQLite"

    Creates a new session ID copied from the source. Both sessions evolve independently.

  4. 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.

    Diagram
    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.

    RestoredFrom
    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

Choosing between the flags

Diagram

Need session continuity?

Just keep going?

Have a specific session ID?

Want to branch without affecting original?

Don’t want this run remembered?

–continue

–session

–fork –session

–no-save

Prompt mode

bash
# 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"

YAML mode

bash
# 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

Session usage footer

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

Diagram

Usage footer

📝 praisonai run

🧠 Agent

token_collector

accumulate_session_usage

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

bash
$ 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; the stdout envelope carries result and status, and usage is attached when the run records it:

bash
$ praisonai run --output json "Summarise yesterday's PRs"
{"result":"...","status":"ok","session_id":"abc12345","usage":{"input_tokens":1240,"output_tokens":3980,"total_tokens":5220,"cost":0.0140,"requests":1}}

The minimal envelope is {"result": "...", "status": "ok"}; session_id and usage are added on paths that record them.

Troubleshooting session continuity

`–continue` runs but the agent has no memory of the previous turn

Fixed in PR #1963 — sessions were discovered but history was not loaded. Upgrade praisonai and re-run.

`–output actions` with `–auto-save` raised TypeError about `auto_save`

Fixed by commit 7016bfa (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.

Session continuity works in prompt mode but not with agents.yaml

Also fixed by PR #1963 — YAML and file-mode runs use the same project session store as prompt-mode runs.

`praisonai-code run –output json '…' | script` prints nothing on standalone

Pre-PR #5685 (merged 2026-10-07), --output json/stream/stream-json on a pip install praisonai-code-only install fell through to the wrapper’s handle_direct_prompt and failed with praisonai.cli.legacy.direct_prompt requires the praisonai wrapper. Upgrade to a build with #5685 — the three structured modes now dispatch in-process and --output json writes the {result, status} envelope on every outcome.


Agent File Format

Create an agents.yaml file:

yaml
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.


Checkpoint & Rewind

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

Diagram
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
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 for the config block.

New checkpoint flags:

FlagDescriptionDefault
`–restore <id\last\latest>`Restore the workspace to a checkpoint and exit — nothing runs.—
--no-checkpointDisable the automatic pre-run checkpoint for this invocation.false

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
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
ArgumentEffect
--revert (no value)Revert the last 1 turn.
--revert last / --revert latestRevert the last 1 turn.
--revert NRevert 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.


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.

bash
praisonai run workflow.yaml \
  --deny "bash:rm *" \
  --allow "bash:pytest *" \
  --approval console \
  --approval-timeout 60

Precedence ladder

Diagram

Yes

No

Yes

No

Yes

No

praisonai run workflow.yaml

–approval set?

Use that backend
console / plan / accept-edits / bypass

Any –allow / –deny /
–permissions / –permission-default?

Implicit console backend
so deny / ask rules are enforced

Project config rules?
.praisonai/permissions.yaml

No gate — legacy default preserved

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

What propagates to a YAML run

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.

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
# No --approval, but the deny rule still activates a console backend
praisonai run workflow.yaml --deny "bash:rm *"
–approve-all-tools and –approval-timeout propagate

Both propagate to YAML runs, matching the single-agent run "<prompt>" semantics.

bash
praisonai run workflow.yaml --approve-all-tools --approval-timeout 120
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.

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.

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.

For the full approval-gating story and backend semantics, see Approval › YAML workflow approval gating.


See Also