# Run modes

> Interactive, print/JSON, RPC, and SDK modes: how each is invoked, entry points, and when to choose them.

- Repository: earendil-works/pi
- GitHub: https://github.com/earendil-works/pi
- Human docs: https://grok-wiki.com/public/docs/earendil-works-pi-7860a70e44d1
- Complete Markdown: https://grok-wiki.com/public/docs/earendil-works-pi-7860a70e44d1/llms-full.txt

## Source Files

- `packages/coding-agent/README.md`
- `packages/coding-agent/package.json`
- `packages/coding-agent/src/cli/args.ts`
- `packages/coding-agent/src/core/agent-session-runtime.ts`
- `packages/coding-agent/examples/sdk/13-session-runtime.ts`

---

---
title: "Run modes"
description: "Interactive, print/JSON, RPC, and SDK modes: how each is invoked, entry points, and when to choose them."
---

Pi (`@earendil-works/pi-coding-agent`) exposes **four run modes** from one package: interactive TUI, print/JSON (non-interactive CLI), RPC for process integration, and an SDK for embedding. The CLI binary is `pi` (`dist/cli.js`). CLI non-interactive modes are selected with `--mode` (`text` | `json` | `rpc`) and/or `--print` / `-p`. Programmatic embedding uses the package main export and optionally `./rpc-entry`.

## Mode overview

| Mode | How you enter it | Primary surface | Typical use |
|------|------------------|-----------------|-------------|
| **Interactive** | `pi` (default TUI) | Terminal UI under `modes/interactive` | Day-to-day coding agent sessions |
| **Print / text** | `--print` / `-p`, and/or `--mode text` | Non-interactive CLI stdout | One-shot prompts, scripts, pipes |
| **JSON** | `--mode json` | Structured CLI output | Machine-readable agents and automation |
| **RPC** | `--mode rpc`, or package export `./rpc-entry` | JSON command stream / process integration | Host apps that spawn or control pi as a process |
| **SDK** | `import` from `@earendil-works/pi-coding-agent` | `createAgentSession*`, `AgentSessionRuntime` | Embed sessions in your own app without the TUI |

README product language groups print and JSON as “print or JSON,” and RPC as “process integration.” The CLI parser’s `Mode` type is only `"text" | "json" | "rpc"`—interactive is the default path when those mode flags are not used for a non-interactive run.

```mermaid
flowchart TB
  subgraph entry["Entry points"]
    BIN["bin: pi → dist/cli.js"]
    MAIN["export . → dist/index.js"]
    RPCX["export ./rpc-entry → dist/rpc-entry.js"]
    CLIENT["export ./client"]
  end

  subgraph cli["CLI modes"]
    INT["Interactive TUI\n(default)"]
    TEXT["--mode text / --print"]
    JSON["--mode json"]
    RPC["--mode rpc"]
  end

  subgraph sdk["In-process embedding"]
    SVC["createAgentSessionServices"]
    SESS["createAgentSessionFromServices"]
    RT["createAgentSessionRuntime\nAgentSessionRuntime"]
  end

  BIN --> INT
  BIN --> TEXT
  BIN --> JSON
  BIN --> RPC
  RPCX --> RPC
  MAIN --> SVC --> SESS
  MAIN --> RT
  RT --> SESS
```

## Package entry points

From `packages/coding-agent/package.json`:

| Surface | Path / export | Role |
|---------|---------------|------|
| CLI binary | `"bin": { "pi": "dist/cli.js" }` | User-facing `pi` command |
| Main / SDK | `"."` → `dist/index.js` (+ types) | Programmatic agent construction |
| RPC entry | `"./rpc-entry"` → `dist/rpc-entry.js` | Process-integration entry (chmod +x in build) |
| Client | `"./client"` → `dist/client/index.js` | Client library surface |
| Config dir name | `piConfig.configDir`: `".pi"` | Package-declared agent config directory name |

Requires **Node `>=22.19.0`**.

## CLI mode flags

Argument parsing lives in `packages/coding-agent/src/cli/args.ts`.

### Mode selection

<ParamField body="--mode" type='"text" \| "json" \| "rpc"'>
Sets `Args.mode`. Only these three string values are accepted; other values are ignored (mode stays unset).
</ParamField>

<ParamField body="--print, -p" type="boolean (+ optional message)">
Sets `Args.print = true`. If the next argument is present and is not a flag/`@file` arg (with a special exception for args starting with `---`), it is consumed as a prompt message on `Args.messages`.
</ParamField>

```bash
# Mode values accepted by the parser
pi --mode text ...
pi --mode json ...
pi --mode rpc ...

# Print flag (optionally with an immediate message)
pi --print "your prompt"
pi -p "your prompt"
```

### Related run-shaping flags

These apply across CLI modes (parser-supported); they do not select a mode by themselves:

| Flag | Effect on `Args` |
|------|------------------|
| `--provider`, `--model`, `--api-key` | Provider/model/API key overrides |
| `--system-prompt`, `--append-system-prompt` | System prompt control |
| `--thinking <level>` | `off` \| `minimal` \| `low` \| `medium` \| `high` \| `xhigh` \| `max` |
| `--continue` / `-c`, `--resume` / `-r` | Session continue/resume |
| `--session`, `--session-id`, `--session-dir`, `--fork`, `--no-session`, `--name` / `-n` | Session identity and persistence |
| `--tools` / `-t`, `--exclude-tools` / `-xt`, `--no-tools` / `-nt`, `--no-builtin-tools` / `-nbt` | Tool allow/exclude surface |
| `--extension` / `-e`, `--no-extensions` / `-ne` | Extensions |
| `--skill`, `--no-skills` / `-ns` | Skills |
| `--prompt-template`, `--no-prompt-templates` / `-np` | Prompt templates |
| `--theme`, `--no-themes` | Themes |
| `--no-context-files` / `-nc` | Skip context files |
| `--tui-mode regular\|fullscreen` | Interactive TUI layout mode |
| `--approve` / `-a`, `--no-approve` / `-na` | Project trust override |
| `--offline`, `--verbose`, `--list-models`, `--export` | Misc operational flags |
| `@path` | File arguments (`fileArgs`) |
| bare strings | Prompt messages (`messages`) |
| unknown `--flags` | Collected as `unknownFlags` (extension CLI flags) |

Invalid short options produce `diagnostics` errors (`Unknown option: ...`). Invalid thinking levels produce warnings. Invalid `--tui-mode` values produce errors.

## Interactive mode

Default coding-agent experience: start authenticated `pi` with no print/RPC mode flags.

```bash
export ANTHROPIC_API_KEY=sk-ant-...
pi
# or: pi → /login (subscription)
```

By default the model gets four tools: **`read`**, **`write`**, **`edit`**, and **`bash`**. Capabilities expand via skills, prompt templates, extensions, or Pi packages.

### UI layout

| Region | Contents |
|--------|----------|
| Startup header | Shortcuts (`/hotkeys`), loaded AGENTS.md, prompt templates, skills, extensions |
| Messages | User/assistant turns, tool calls/results, notifications, errors, extension UI |
| Editor | Input; border color reflects thinking level. Can be replaced by built-in `/settings` or extension UI |
| Footer | Working directory, session name, token/cache usage, cost, context usage, current model |

Theme and asset files for this mode live under `src/modes/interactive/` (copied into `dist/modes/interactive/` at build).

### Editor inputs

| Feature | Behavior |
|---------|----------|
| `@` | Fuzzy-search project files |
| Tab | Path completion |
| Shift+Enter (Ctrl+Enter on Windows Terminal) | Multi-line input |
| Ctrl+G | External editor (`externalEditor`, `$VISUAL`, `$EDITOR`, Notepad on Windows, else `nano`) |
| Ctrl+V (Alt+V on Windows) | Paste image/text; drag images onto terminal |
| `!command` | Run bash and send output to the LLM |
| `!!command` | Run bash without sending |

### Commands (selected)

Type `/` in the editor. Extensions register custom commands; skills appear as `/skill:name`; prompt templates expand as `/templatename`.

| Command | Description |
|---------|-------------|
| `/login`, `/logout` | Provider credentials |
| `/model` | Switch models |
| `/scoped-models` | Enable/disable models for Ctrl+P cycling |
| `/settings` | Thinking level, theme, message delivery, transport |
| `/resume`, `/new`, `/name`, `/session` | Session lifecycle and metadata |
| `/tree`, `/fork`, `/clone` | Session tree / branch operations |
| `/compact [prompt]` | Manual compaction |
| `/export [file]` | Export session to HTML or JSONL |
| `/trust` | Save project trust decision (restart required) |

### Interactive-only TUI flag

<ParamField body="--tui-mode" type='"regular" \| "fullscreen"'>
Sets interactive layout mode. Requires one of those two values.
</ParamField>

## Print / text and JSON modes

Use when you do **not** want the interactive TUI: one-shot prompts, scripting, or structured automation.

| Intent | Flags |
|--------|--------|
| Print-style non-interactive run | `--print` / `-p` (optional message immediately after the flag) |
| Explicit text mode | `--mode text` |
| Structured JSON mode | `--mode json` |

```bash
pi -p "summarize the last commit"
pi --mode json -p "list open TODOs in src/"
```

Prompt text can also be supplied as bare positional arguments (`Args.messages`). File inputs use `@path` → `fileArgs`.

<Note>
The parser stores `print` and `mode` separately. Exact dispatch (for example whether `--print` alone forces text mode, exit codes, or JSON schemas) is outside this page’s supplied CLI dispatch sources; use `--mode` when you need an explicit mode value.
</Note>

## RPC mode

RPC is for **process integration**: a host controls pi over a command/event channel rather than a human TUI.

| Invocation | Location |
|------------|----------|
| CLI | `pi --mode rpc ...` |
| Package export | `@earendil-works/pi-coding-agent/rpc-entry` → `dist/rpc-entry.js` |

Build marks `dist/rpc-entry.js` executable alongside `dist/cli.js`.

Choose RPC when another process must drive prompts, lifecycle, and streaming without embedding the TypeScript API in-process. Command IDs, compaction constraints, and stream details belong on the dedicated RPC page.

## SDK mode

Embed pi in your own Node application via the **main package export** (`"."` → `dist/index.js`). This path owns sessions without the interactive TUI.

### Session construction pattern

`examples/sdk/13-session-runtime.ts` shows the intended layering:

1. `createAgentSessionServices({ cwd })` — cwd-bound services  
2. `createAgentSessionFromServices({ services, sessionManager, sessionStartEvent })` — session + related result fields  
3. `createAgentSessionRuntime(factory, { cwd, agentDir, sessionManager })` — runtime that can **replace** the active session  
4. Rebind subscriptions/extensions after each replacement to `runtime.session`  
5. `runtime.dispose()` when finished  

```ts
import {
  type CreateAgentSessionRuntimeFactory,
  createAgentSessionFromServices,
  createAgentSessionRuntime,
  createAgentSessionServices,
  getAgentDir,
  SessionManager,
} from "@earendil-works/pi-coding-agent";

const createRuntime: CreateAgentSessionRuntimeFactory = async ({
  cwd,
  sessionManager,
  sessionStartEvent,
}) => {
  const services = await createAgentSessionServices({ cwd });
  return {
    ...(await createAgentSessionFromServices({
      services,
      sessionManager,
      sessionStartEvent,
    })),
    services,
    diagnostics: services.diagnostics,
  };
};

const runtime = await createAgentSessionRuntime(createRuntime, {
  cwd: process.cwd(),
  agentDir: getAgentDir(),
  sessionManager: SessionManager.create(process.cwd()),
});

// bind to runtime.session, then:
await runtime.newSession();
// or: await runtime.switchSession(sessionFile);
await runtime.dispose();
```

### `AgentSessionRuntime` responsibilities

`AgentSessionRuntime` owns the current `AgentSession` plus cwd-bound `AgentSessionServices`.

| Member / method | Role |
|-----------------|------|
| `session`, `services`, `cwd`, `diagnostics`, `modelFallbackMessage` | Current runtime state |
| `setRebindSession(fn)` | Host rebinds after session replacement |
| `setBeforeSessionInvalidate(fn)` | Sync UI teardown after `session_shutdown`, before invalidate (must not yield) |
| `newSession({ parentSession?, setup?, withSession? })` | Teardown + create new session (`reason: "new"`) |
| `switchSession(path, { cwdOverride?, withSession?, projectTrustContextFactory? })` | Resume another session file (`reason: "resume"`) |
| Replacement hooks | `session_before_switch` / `session_before_fork` may **cancel** (`{ cancelled: true }`) |
| Teardown order | `session.abort()` → `session_shutdown` → `beforeSessionInvalidate` → `session.dispose()` |

`CreateAgentSessionRuntimeFactory` recreates cwd-bound services for the effective cwd, then builds the next `AgentSession`. Creation failures propagate to the caller.

`SessionImportFileNotFoundError` is thrown when `/import` points at a missing JSONL path.

## Choosing a mode

| If you need… | Choose | Entry |
|--------------|--------|--------|
| Human-in-the-loop coding with editor, slash commands, footer stats | Interactive | `pi` |
| One-shot or scripted prompts to stdout | Print / text | `pi -p …` or `--mode text` |
| Machine-readable non-interactive output | JSON | `--mode json` |
| External process driving pi over a protocol | RPC | `--mode rpc` or `./rpc-entry` |
| In-process control, custom UI, session replacement | SDK | main export + `AgentSessionRuntime` |

All modes share the same product defaults at the agent layer (tools, extensions, skills, providers) unless flags or SDK options narrow them. Auth remains BYOK/subscription-oriented (API keys or `/login`); modes do not hard-wire a single model vendor.

## Constraints and diagnostics

- **Mode enum is strict in the parser:** only `text`, `json`, and `rpc` assign `Args.mode`.
- **`--print` message consumption** skips the next token if it looks like a flag (except values starting with `---`) or `@file` argument.
- **Extension flags** that are not built-in land in `unknownFlags` for extension CLI handling.
- **Session replacement cancel:** extension `session_before_switch` / `session_before_fork` handlers can abort `newSession` / `switchSession` / fork paths.
- **SDK hosts** must rebind session-local subscriptions after `newSession` / `switchSession`; the example pattern unsubscribes and resubscribes on `runtime.session`.

## Related pages

<CardGroup>
  <Card title="Overview" href="/overview">
    What pi is, the four run modes, and first routes for CLI users and embedders.
  </Card>
  <Card title="Quickstart" href="/quickstart">
    Install, authenticate, start interactive pi, confirm default tools.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    Full flag and argument parsing surface for the `pi` binary.
  </Card>
  <Card title="RPC mode" href="/rpc-mode">
    Process integration via rpc-entry: commands, streams, and constraints.
  </Card>
  <Card title="SDK" href="/sdk">
    Embed via the main export: construction, hooks, models, tools, settings.
  </Card>
  <Card title="Session runtime" href="/session-runtime">
    AgentSessionRuntime services, lifecycle events, embedding without the TUI.
  </Card>
  <Card title="Package exports" href="/package-exports">
    npm surface: main, rpc-entry, client, bin, piConfig.configDir.
  </Card>
  <Card title="SDK examples" href="/sdk-examples">
    Copy-paste recipes including session runtime and full-control setups.
  </Card>
</CardGroup>
