Code
Code assistant mode for programming tasks
The code command starts a code assistant session optimized for programming tasks.
Usage
praisonai code [OPTIONS] [PROMPT]Arguments
| Argument | Description |
|---|---|
PROMPT | Code-related prompt or question |
Options
| Option | Short | Description | Default |
|---|---|---|---|
--model | -m | LLM model to use | gpt-4o-mini |
--verbose | -v | Verbose output | false |
--tools | -t | Comma-separated tool names (e.g. web_search,github) or a tools.py file path | |
--workspace | -w | Root the code tools at this directory (sets PRAISONAI_WORKSPACE). Default: current directory, or the resumed session’s directory when --continue / --session is used. | |
--file | -f | Attach 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-acp | Disable ACP tools (file operations) | false | |
--no-lsp | Disable LSP tools (code intelligence) | false | |
--safe / --no-safe | Safe 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-autonomy | Enable 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-approval | Skip 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 | |
--plan | Read-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 | -s | Session ID to resume | |
--resume | Resume a session by id in headless -p mode (alias of --session for scripted multi-turn). --session still wins when both are set. | ||
--continue | -c | Continue last session | false |
--print | -p | Headless one-shot: emit a clean machine-readable result and exit with a status-reflecting code. Requires a prompt. | false |
--output | -o | Output format for -p: json (default) or text. Requires -p. | json when -p set |
--no-context | Disable AGENTS.md/CLAUDE.md auto-loading into system prompt | 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 | |
--agent | -a | Named custom agent profile from .praisonai/agents/ (tools + permission scope) | |
--thinking | Reasoning effort for this invocation: off, minimal, low, medium, high | ||
--max-steps | Maximum 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-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. | None | |
--checkpoints / --no-checkpoints | Auto-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.
# 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.mdOmit the flag and set the environment variable instead — handy for CI:
export PRAISONAI_APPEND_SYSTEM_PROMPT="Reply in strict JSON, no prose."
praisonai codeSee Append System Prompt for the full behaviour.
Piped Input
praisonai code reads piped stdin when the prompt is provided in the shell pipeline.
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.
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
- Explicit flag
bash praisonai code --max-steps 300 "Refactor the auth module across all files" - 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 routing | Bounded 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).
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.
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.
| Situation | Outcome |
|---|---|
| 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 TTY | Prompts 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.
praisonai code -p "Write a Python function to sort a list" --output jsonJSON envelope
--output json (the default under -p) prints a single-line JSON object on stdout:
{"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:
{"result": "def sort_list(items): return sorted(items)", "session_id": null, "usage": {"in": 128, "out": 42, "cost": null}, "status": "ok"}| Field | Meaning |
|---|---|
result | The agent’s answer as a string, or null when nothing was produced. |
session_id | The resolved session id when --resume/--session/--continue was used, else null. |
usage.in | Input tokens for this run. |
usage.out | Output tokens for this run. |
usage.cost | Estimated 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. |
status | ok on success, truncated when the step/tool budget was exhausted (exit 2), failed on an empty result, error when the agent raised. |
error | Present only when status is error — the exception message. |
Text mode
--output text prints just the result on stdout — nothing else — so it pipes cleanly:
praisonai code -p "What is 2+2?" --output text
# 4Errors 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.
status | When | Exit code |
|---|---|---|
ok | Non-empty result | 0 |
truncated | Step/tool budget exhausted (last_stop_reason == "max_steps") | 2 |
failed | Empty / None result | 1 |
error | The agent raised an exception | 1 |
See Headless truncation contract (code -p) for the truncated case.
if praisonai code -p "Generate the release notes" --output text > notes.md; then
echo "wrote notes.md"
else
echo "generation failed" >&2
fiScripted 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:
praisonai code --resume my-feature -p "Draft the auth refactor" --output json
praisonai code --resume my-feature -p "Now add tests" --output jsonFail-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 -p | Why |
|---|---|
--no-acp | Toggles the resident split-pane TUI’s runtime ACP tool server, which the one-shot headless agent does not spin up. |
--no-lsp | Toggles the resident split-pane TUI’s runtime LSP tool server, which the one-shot headless agent does not spin up. |
--profile / --profile-deep | Prints 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.
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.
Sessions created inside praisonai code are visible to:
praisonai session list(andlist --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
# 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-featureSee Session Management for the full command set and Storage Paths for where files live.
Examples
Start code assistant
praisonai codeAsk a coding question
praisonai code "Write a Python function to sort a list"Specify language context
praisonai code --language python "Explain decorators"Disable safe mode (opt out of approval prompts)
praisonai code --no-safe "Refactor main.py"Full bypass (no approval prompts, applies to subprocess tree)
praisonai code --dangerously-skip-approval "Clean up old logs"Headless one-shot for scripts
# Machine-readable JSON envelope on stdout, status-reflecting exit code
praisonai code -p "Write a Python function to sort a list" --output jsonSee 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.
# Add the `github` tool to a scripted coding run
praisonai code -p --tools github "Open a PR that fixes the failing lint" --output jsonWith 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.
# Least-privilege review profile — instructions + permission scope from .praisonai/agents/reviewer.md
praisonai code -p --agent reviewer "Audit src/security/ for auth bugs" --output jsonAn 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.
# 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
# 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)
praisonai code --thinking high "Refactor src/utils.py for readability"Custom agent profile
# 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)
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.
Pick a workspace explicitly
praisonai code --workspace ./src "Refactor the auth module"Everything the agent reads or writes stays inside ./src.
Pick a workspace with an environment variable
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
praisonai code --continue # resumes the last session in its original directory
praisonai code --session abc123 # resumes that specific session in its original directoryLaunch 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:
# 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).
praisonai code "Refactor auth module"How /undo differs by mode
| Mode | What /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):
| Command | What it does |
|---|---|
/undo | Undo the last turn: remove from history and restore workspace files |
/revert | Same as /revert 1 — roll back 1 turn |
/revert last | Explicit alias for the last 1 turn |
/revert 2 | Roll 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
praisonai code --revert lastShows the diff preview and restores the workspace, then exits.
Project config
Enable checkpointing for all praisonai code sessions in a project:
# agents.yaml
checkpoints:
auto: true
storage_dir: ./.praisonai/checkpoints # optional — shared with praisonai runPrecedence (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_SHELL | Behaviour |
|---|---|
unset / off (default) | Operators are refused with an error naming the operator; plain commands run as before |
sandboxed | Every 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 |
unsafe | Operators 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.
# praison.yaml
mcp:
servers:
tiny_add:
command: python
args: ["tiny_add_server.py"]praisonai codeThe 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=mcpto 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
- Chat – General chat mode (
--jsonheadless output) - Piped Input – Compose
code -pin Unix pipelines and CI - LSP Code Intelligence – Language server integration
- Approval – Tool approval and safety defaults
- Checkpoints – Workspace checkpointing and undo
- Step Budget – The
max_stepscontract and the coding-sized default