Code

Code assistant mode for programming tasks

The code command starts a code assistant session optimized for programming tasks.

Usage

bash
praisonai code [OPTIONS] [PROMPT]

Arguments

ArgumentDescription
PROMPTCode-related prompt or question

Options

OptionShortDescriptionDefault
--model-mLLM model to usegpt-4o-mini
--verbose-vVerbose outputfalse
--tools-tComma-separated tool names (e.g. web_search,github) or a tools.py file path
--workspace-wRoot the code tools at this directory (sets PRAISONAI_WORKSPACE). Default: current directory, or the resumed session’s directory when --continue / --session is used.
--file-fAttach file(s) to context. Fully wired as of PR #4943 — attachments are forwarded to the agent via the shared attachment loader used by praisonai chat, so the model actually reads the file (previously the flag was accepted and silently dropped). Repeatable.
--no-acpDisable ACP tools (file operations)false
--no-lspDisable LSP tools (code intelligence)false
--safe / --no-safeSafe mode: prompt before file writes and shell commands (default: on). --no-safe disables it and registers AutoApproveBackend on the approval registry. Re-running in safe mode within the same process clears a bypass a prior --no-safe installed.true
--autonomy / --no-autonomyEnable agent autonomy for complex tasks. Wired as of PraisonAI PR #4943 (and #4946) so it now feeds AsyncTUIConfig.autonomy_mode (previously declared but never reached the config), mirroring the same flag on praisonai chat. Pass --no-autonomy to disable.true
--dangerously-skip-approvalSkip all tool approval prompts. Registers AutoApproveBackend on the approval registry (so the core @require_approval gate is also bypassed) and exports PRAISON_APPROVAL_MODE=auto / PRAISONAI_TOOL_SAFETY=off for the subprocess tree. Strictly opt-in; mutually exclusive with --plan. See Tool Approval.false
--planRead-only planning mode — the agent may explore/read/search but every mutating tool is denied. Discoverable alias for the read-only planning permission mode. Cannot be combined with --no-safe or --dangerously-skip-approval (exits 1).false
--session-sSession ID to resume
--resumeResume a session by id in headless -p mode (alias of --session for scripted multi-turn). --session still wins when both are set.
--continue-cContinue last sessionfalse
--print-pHeadless one-shot: emit a clean machine-readable result and exit with a status-reflecting code. Requires a prompt.false
--output-oOutput format for -p: json (default) or text. Requires -p.json when -p set
--no-contextDisable AGENTS.md/CLAUDE.md auto-loading into system promptfalse
--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
--agent-aNamed custom agent profile from .praisonai/agents/ (tools + permission scope)
--thinkingReasoning effort for this invocation: off, minimal, low, medium, high
--max-stepsMaximum tool-calling steps for this coding session. Raises both ExecutionConfig.max_steps and ExecutionConfig.max_tool_calls_per_turn (the two tool loops enforce different knobs). Env fallback: PRAISONAI_CODE_MAX_STEPS. See Step budget for coding sessions.200
--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
--checkpoints / --no-checkpointsAuto-checkpoint the workspace before each file-mutating turn, enabling in-session /undo and /revert. On by default for interactive praisonai code; pass --no-checkpoints to disable it for this run.--checkpoints
--revert <ref>One-shot: restore workspace to a prior checkpoint (id, short id, or last) and exit—

Append to the system prompt

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

bash
# Literal text
praisonai code --append-system-prompt "Always answer in French"

# Read the suffix from a file (@file form)
praisonai code --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 code

See Append System Prompt for the full behaviour.

Piped Input

praisonai code reads piped stdin when the prompt is provided in the shell pipeline.

bash
cat data.json | praisonai code "Write a parser for this shape"

Prompt argument is merged first, piped body second (joined with \n). See Piped Input.

Step budget for coding sessions

praisonai code runs with a coding-sized step budget by default: 200 steps, applied to both tool-execution loops.

Diagram

–max-steps N

PRAISONAI_CODE_MAX_STEPS

DEFAULT_CODE_MAX_STEPS = 200

ExecutionConfig(max_steps=N,
max_tool_calls_per_turn=N)

The core Agent defaults (max_steps=20, max_tool_calls_per_turn=10) are tuned for a general-purpose Q&A agent with two or three tools, and are left untouched — no library user’s behaviour changes. But 10 tool calls is “list files, read two files, one grep”: it cannot reach a test run. The coding CLI raises the ceiling for its own sessions only.

Override

  1. Explicit flag
    bash
    praisonai code --max-steps 300 "Refactor the auth module across all files"
  2. Environment fallback (CI / sandbox)
    bash
    export PRAISONAI_CODE_MAX_STEPS=300
    praisonai code "Refactor the auth module across all files"

Precedence: --max-steps flag > PRAISONAI_CODE_MAX_STEPS env > DEFAULT_CODE_MAX_STEPS (200). An unparseable or non-positive value falls through to the next source.

The flag raises both budget knobs to the same value, because:

Model routingBounded by
OpenAI-native (gpt-4o-mini, the default)ExecutionConfig.max_steps
LiteLLM (gemini/, anthropic/, ollama, …)ExecutionConfig.max_steps and ExecutionConfig.max_tool_calls_per_turn per turn

Raising only one leaves the other as the real (and invisible) ceiling.

Why 200?

A coding agent’s unit of work is read → edit → run tests → read the failure (≈4 calls per fix attempt), before any orientation. 200 steps is ~50 edit/verify cycles, chosen to cover the tail rather than the median: trajectories cluster at 20–40 steps, but hard tasks — the ones benchmarks measure — run past 100, and a budget at the median silently truncates those. Runaway loops stay bounded by the orthogonal guards (per-tool loop guard, ExecutionConfig.max_execution_time, max_budget, model context window).

What about max_tool_calls_per_turn?

The LiteLLM tool loop counts every tool call in a turn against max_tool_calls_per_turn, while the OpenAI-native loop is bounded by max_steps. --max-steps sets both to the same value so a Gemini/Anthropic-routed session isn’t capped at 10 calls while an OpenAI-routed one runs to your budget.

Does this change the SDK defaults?

No. The coding budget applies only to praisonai code. The Python Agent defaults (max_steps=20, max_tool_calls_per_turn=10) are unchanged.

See Step Budget for the general ExecutionConfig.max_steps contract and how to detect truncation with agent.last_stop_reason.

Headless truncation contract (code -p)

A budget-exhausted headless run exits 2 with status: "truncated" — distinct from a hard failure (1) and a clean completion (0).

Diagram

📝 code -p task

🔧 LLM tool loop

⚠️ Budget exhausted

📝 Wrap-up summary

⛔ exit 2
status: truncated

This matches praisonai run → truncation and closes a hazard where a wrap-up summary (a perfectly non-empty string) was classified as status: "ok", exit 0, silently reporting truncation as success to CI and benchmark adapters.

bash
praisonai code -p --output json --max-steps 6 \
  "Run pytest and fix every failing test until 0 failures"

# → exit 2
# → {"result": "Tool call limit reached (…). Task may be too complex …",
#    "session_id": null, "usage": {…}, "status": "truncated"}

Under --output text, a stderr warning follows the printed result:

Warning: run hit the step/tool-call budget; the output above is a summary of partial progress, not a completed task. Re-run with a higher --max-steps.

JSON / stream-JSON consumers do not see this stderr line — the status: "truncated" field is the machine signal.

The shared truncation check (run._run_was_truncated) resolves through agent.last_stop_reason == "max_steps", so code -p and praisonai run agree on the 0 / 1 / 2 exit-code contract.

First-run credential gate

praisonai code routes first-run onboarding through the shared credential gate, so a keyless newcomer is offered the setup wizard (interactive) or exits with a hint (headless) instead of dead-ending on a raw provider error.

Diagram

Yes

No

Yes

No

Yes

No

🚀 praisonai code

Configured?

✅ Run normally

Local endpoint
reachable? no –model

🖥️ Adopt local model
stderr notice → continue

Headless?
-p / piped stdin

⛔ exit 1
Run: praisonai setup

🧙 Offer setup wizard

SituationOutcome
Configured (any provider key or stored credential)Runs normally with your chosen model.
Keyless, local Ollama / OpenAI-compatible endpoint reachable (no --model)Adopts the local model; one-line stderr notice; continues.
Keyless, headless (-p / --print or piped stdin)Exits 1 with Error: No API key configured. Run: praisonai setup.
Keyless, interactive TTYPrompts Would you like to run the setup wizard now?. Y → wizard runs, re-checks, continues. n → exits 0 with a hint.

See First-run Onboarding for the full flow and Setup for the wizard.

Headless / scripting mode

-p/--print runs one task and prints a clean, machine-readable result — no Chat mode: banners, no profiling block — then exits with a code that reflects success or failure. This is the scripting parity code shares with run --output json and chat --json.

bash
praisonai code -p "Write a Python function to sort a list" --output json
Diagram

ok

failed / error

📝 code -p task

🤖 Minimal code agent

📦 JSON / text on stdout

status

✅ exit 0

⛔ exit non-zero

JSON envelope

--output json (the default under -p) prints a single-line JSON object on stdout:

json
{"result": "def sort_list(items): return sorted(items)", "session_id": null, "usage": {"in": 128, "out": 42, "cost": 0.0001}, "status": "ok"}

On a model with no known price, cost is null instead of a guessed figure:

json
{"result": "def sort_list(items): return sorted(items)", "session_id": null, "usage": {"in": 128, "out": 42, "cost": null}, "status": "ok"}
FieldMeaning
resultThe agent’s answer as a string, or null when nothing was produced.
session_idThe resolved session id when --resume/--session/--continue was used, else null.
usage.inInput tokens for this run.
usage.outOutput tokens for this run.
usage.costEstimated cost from the token collector + pricing table. null when tokens were spent on a model the resolver couldn’t price (no static entry, not in litellm’s map, no prefix match) — see Cost Tracking. The keys in, out, cost are stable across releases.
statusok on success, truncated when the step/tool budget was exhausted (exit 2), failed on an empty result, error when the agent raised.
errorPresent only when status is error — the exception message.

Text mode

--output text prints just the result on stdout — nothing else — so it pipes cleanly:

bash
praisonai code -p "What is 2+2?" --output text
# 4

Errors go to stderr; status is carried by the exit code.

Exit-code contract

The exit code lets CI, benchmarks, and shell scripts branch on success without parsing stdout.

statusWhenExit code
okNon-empty result0
truncatedStep/tool budget exhausted (last_stop_reason == "max_steps")2
failedEmpty / None result1
errorThe agent raised an exception1

See Headless truncation contract (code -p) for the truncated case.

bash
if praisonai code -p "Generate the release notes" --output text > notes.md; then
  echo "wrote notes.md"
else
  echo "generation failed" >&2
fi

Scripted multi-turn with --resume

--resume <id> composes with -p so a script can carry a session across calls. The id flows back out in the envelope’s session_id:

bash
praisonai code --resume my-feature -p "Draft the auth refactor" --output json
praisonai code --resume my-feature -p "Now add tests"          --output json

Fail-closed options

Headless mode runs a minimal code agent, so options that need the full interactive wiring are rejected up front (exit 1) rather than silently dropped:

Rejected under -pWhy
--no-acpToggles the resident split-pane TUI’s runtime ACP tool server, which the one-shot headless agent does not spin up.
--no-lspToggles the resident split-pane TUI’s runtime LSP tool server, which the one-shot headless agent does not spin up.
--profile / --profile-deepPrints a human report and always exits 0 — it would break the machine-readable contract.

Two more guards keep the contract explicit: --output without -p errors, and -p without a prompt errors.

The mcp tool group is enabled by default under -p as of PR #4965 — if your project declares mcp.servers, those tools reach the headless agent alongside the built-ins. Opt out with PRAISON_TOOLS_DISABLE=mcp (the same knob that works interactively). See MCP tools in coding sessions.

Honored under -p: --model, --thinking, --verbose, --workspace, --resume / --session / --continue, --tools, --agent, and --plan (as of PraisonAI PR #4026). --tools and the profile’s named tools are merged onto the default headless coding toolset (de-duped by identity), so custom tools add to the defaults rather than replacing them. --plan and a profile’s declarative permissions are enforced via a non-interactive approval backend, so honouring the scope is a tightening (deny/ask fails closed) — never an interactive prompt that would stall a scripted run.

Diagram

praisonai code -p — headless

–tools name / .py

–agent name

–plan

–no-acp / –no-lsp

📝 prompt

flag?

🔧 ToolResolver → merge with defaults

👤 profile: instructions + tools + permissions

🔒 read-only backend

⛔ exit 1

🔌 mcp group
from mcp.servers

🤖 headless agent

📦 JSON / text envelope

Sessions

praisonai code shares the canonical session store at ~/.praisonai/sessions/ (Windows: %USERPROFILE%\.praisonai\sessions\). Every conversation you start here is the same session object the rest of the CLI reads and writes.

Diagram

Unified session store

💻 praisonai code
REPL / TUI

📂 ~/.praisonai/sessions/

▶️ praisonai run
–continue / –session

📋 praisonai session
list / show / export

📊 praisonai dashboard

Sessions created inside praisonai code are visible to:

  • praisonai session list (and list --all)
  • praisonai session show <id> / delete <id> / export <id> / share <id> / unshare <id>
  • praisonai run --continue / --session <id> — same id, same conversation
  • the praisonai dashboard
bash
# Start a session in code, then continue it from run
praisonai code --session my-feature "Draft the auth refactor"
praisonai run --session my-feature "Now add tests"

# List and export the same session
praisonai session list
praisonai session export my-feature

See Session Management for the full command set and Storage Paths for where files live.

Examples

Start code assistant

bash
praisonai code

Ask a coding question

bash
praisonai code "Write a Python function to sort a list"

Specify language context

bash
praisonai code --language python "Explain decorators"

Disable safe mode (opt out of approval prompts)

bash
praisonai code --no-safe "Refactor main.py"

Full bypass (no approval prompts, applies to subprocess tree)

bash
praisonai code --dangerously-skip-approval "Clean up old logs"

Headless one-shot for scripts

bash
# Machine-readable JSON envelope on stdout, status-reflecting exit code
praisonai code -p "Write a Python function to sort a list" --output json

See Headless / scripting mode for the envelope shape and exit-code contract.

Headless one-shot with a custom tool

--tools is now first-class under -p. The resolved tools are merged onto the default headless coding toolset (ACP + edit + search + LSP + MCP), so custom tools add to the defaults rather than replacing them.

bash
# Add the `github` tool to a scripted coding run
praisonai code -p --tools github "Open a PR that fixes the failing lint" --output json

With mcp.servers set in your project config, MCP tools are in the default set too — the resolved --tools argument stacks on top of ACP + edit + search + LSP + MCP. See MCP tools in coding sessions.

--tools accepts either comma-separated names resolved through ToolResolver (identical to run --tools) or a ./tools.py file path. If a user tools.py fails at import time, the failure is reported through the same machine-readable JSON envelope (status: "error", non-zero exit) — never as a raw traceback.

Headless one-shot under a named agent profile

--agent <name> loads a profile from .praisonai/agents/ and applies its instructions, role, goal, llm, and named tools to the headless run. Its declarative permissions are enforced via a non-interactive approval backend, so a pinned least-privilege profile runs safely in CI.

bash
# Least-privilege review profile — instructions + permission scope from .praisonai/agents/reviewer.md
praisonai code -p --agent reviewer "Audit src/security/ for auth bugs" --output json

An explicit --model still wins over the profile’s llm. See Custom Agents & Commands for profile definitions.

Headless read-only planning (--plan)

--plan under -p runs a read-only headless session: reads, searches, and LSP queries are allowed, but every mutating tool (write, edit, shell) is denied by a non-interactive PermissionMode.PLAN backend. Ideal for CI review jobs that must produce a plan without touching the tree.

bash
# Plan-only headless run — writes/edits/shell are denied
praisonai code -p --plan "Draft a migration plan for the auth module" --output json

--plan overrides any profile permission scope with the read-only planning mode. See Permission Modes and Approval.

Read-only planning session

bash
# REPL session that can read/search but never writes or shells
praisonai code --plan "Draft a migration plan for the auth module"

--plan is the read-only planning permission mode (PermissionMode.PLAN). See Permission Modes and Permissions.

Reasoning effort (per invocation)

bash
praisonai code --thinking high "Refactor src/utils.py for readability"

Custom agent profile

bash
# Profile defined in .praisonai/agents/plan.md
praisonai code --agent plan "Review the auth module and propose a refactor"

# Profile + reasoning effort combined
praisonai code --agent reviewer --thinking high "Audit src/security/"

See Custom Agents & Commands for profile definitions and Thinking for budget levels.

Append a one-off instruction (per invocation)

bash
praisonai code --append-system-prompt "Always answer in French"

The text is appended to the end of the system prompt for this run only — never written to any agent file. See Append System Prompt.

Project context

By default, praisonai code 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. Pass --no-context (or set PRAISON_NO_CONTEXT=true) to disable. See Context Files for details.

Workspace directory

praisonai code runs its file, edit, search, and shell tools inside one workspace directory. Everything the agent reads and writes is contained there.

Diagram

Yes

No

Yes

No

Yes

No

Yes

No

praisonai code launched

–workspace passed?

Use flag value

PRAISONAI_WORKSPACE set?

Use env value

PRAISON_WORKSPACE set?
legacy

Use legacy env value

–continue or –session?

Use the session’s
original directory

Use current directory

Pick a workspace explicitly

bash
praisonai code --workspace ./src "Refactor the auth module"

Everything the agent reads or writes stays inside ./src.

Pick a workspace with an environment variable

bash
export PRAISONAI_WORKSPACE=/path/to/project
praisonai code "Add tests for user.py"

PRAISONAI_WORKSPACE is the canonical name. The older PRAISON_WORKSPACE still works for backwards compatibility, but PRAISONAI_WORKSPACE wins when both are set.

Resume back into the same directory

bash
praisonai code --continue           # resumes the last session in its original directory
praisonai code --session abc123     # resumes that specific session in its original directory

Launch praisonai code --continue from any shell — the tools re-root into the directory the session was created in, so the conversation stays consistent.

If the recorded directory no longer exists you’ll see a warning and the tools fall back to the current directory:

⚠ Session workspace no longer exists: /old/path — using current directory instead.

An explicit --workspace always wins over the resumed directory.

Windows Automation

For Windows automation scenarios, use the --no-acp flag and set UTF-8 encoding. The -w flag is now honored end-to-end, so the agent’s tools operate inside the directory you pass:

powershell
# Windows PowerShell
$env:PRAISON_APPROVAL_MODE = "auto"
$env:PYTHONIOENCODING       = "utf-8"

praisonai code -w . --no-acp "Fix the failing tests"

See the Windows Automation section in Real-world Examples for complete setup instructions.

Auto checkpointing & in-session undo

Workspace checkpointing is on by default for interactive praisonai code sessions, so /undo and /revert work out of the box. Disable per-run with --no-checkpoints, or project-wide with checkpoints.auto: false (or PRAISONAI_CHECKPOINTS=off).

bash
praisonai code "Refactor auth module"
Diagram

🚀 Session start

📸 Baseline checkpoint

📝 Turn 1 edits

📸 Checkpoint 1

📝 Turn 2 edits

⏪ /revert

How /undo differs by mode

ModeWhat /undo does
Checkpointing on (default for interactive praisonai code)Removes the last turn from history and restores workspace files to the pre-turn checkpoint (diff preview first)
Checkpointing off (--no-checkpoints, checkpoints.auto: false, or PRAISONAI_CHECKPOINTS=off)Removes the last assistant+user message from history only

Interactive slash commands

Type these inside a praisonai code REPL (checkpointing is on by default; disable with --no-checkpoints):

CommandWhat it does
/undoUndo the last turn: remove from history and restore workspace files
/revertSame as /revert 1 — roll back 1 turn
/revert lastExplicit alias for the last 1 turn
/revert 2Roll the workspace back 2 turns

Both commands show a diff preview before restoring and refuse to run while a turn is still in progress.

One-shot revert from CLI

bash
praisonai code --revert last

Shows the diff preview and restores the workspace, then exits.

Project config

Enable checkpointing for all praisonai code sessions in a project:

yaml
# agents.yaml
checkpoints:
  auto: true
  storage_dir: ./.praisonai/checkpoints   # optional — shared with praisonai run

Precedence (highest last): default → checkpoints.auto (config) → PRAISONAI_CHECKPOINTS (env). Interactive praisonai code passes default=True, so checkpointing is on unless you disable it.

See Checkpoints for the full checkpoint feature reference.

Shell execution (PRAISON_SHELL)

PRAISON_SHELL picks the containment posture for every execute_command call.

PRAISON_SHELLBehaviour
unset / off (default)Operators are refused with an error naming the operator; plain commands run as before
sandboxedEvery command runs as /bin/sh -c inside OS containment (Seatbelt/bwrap), writable only in PRAISONAI_WORKSPACE + $TMPDIR, secrets scrubbed; refuses if enforcement can’t be proven. Also applies to headless -p
unsafeOperators run in a real /bin/sh -c, no containment — opt-in only

The real-shell path is gated by the same critical-risk execute_command approval as the plain executor. See Shell Modes and OS Sandbox.

MCP tools in coding sessions

Declaring mcp.servers in your project config makes those tools appear inside praisonai code (both the interactive TUI and the -p headless one-shot) as a standard mcp tool group.

yaml
# praison.yaml
mcp:
  servers:
    tiny_add:
      command: python
      args: ["tiny_add_server.py"]
bash
praisonai code

The coding session reuses the same collector as praisonai run, so the server’s tools (for example tiny_add) reach the agent. Two rules apply:

  • Opt out with PRAISON_TOOLS_DISABLE=mcp to drop the whole group.
  • No shadowing — an MCP server can never override a built-in tool name; the built-in wins and the duplicate MCP tool is skipped.

See MCP and Load MCP Tools.

See Also