# CLI, Session, and Tool Lifecycle

> How the pi executable parses inputs, creates cwd-bound services, resolves models and settings, persists sessions, dispatches built-in tools, and bridges into the core agent.

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

## Source Files

- `packages/coding-agent/src/main.ts`
- `packages/coding-agent/src/cli/args.ts`
- `packages/coding-agent/src/core/sdk.ts`
- `packages/coding-agent/src/core/agent-session-services.ts`
- `packages/coding-agent/src/core/agent-session.ts`
- `packages/coding-agent/src/core/session-manager.ts`
- `packages/coding-agent/src/core/tools/index.ts`
- `packages/coding-agent/src/core/tools/bash.ts`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [packages/coding-agent/src/cli.ts](packages/coding-agent/src/cli.ts)
- [packages/coding-agent/src/main.ts](packages/coding-agent/src/main.ts)
- [packages/coding-agent/src/cli/args.ts](packages/coding-agent/src/cli/args.ts)
- [packages/coding-agent/src/core/sdk.ts](packages/coding-agent/src/core/sdk.ts)
- [packages/coding-agent/src/core/agent-session-services.ts](packages/coding-agent/src/core/agent-session-services.ts)
- [packages/coding-agent/src/core/agent-session-runtime.ts](packages/coding-agent/src/core/agent-session-runtime.ts)
- [packages/coding-agent/src/core/agent-session.ts](packages/coding-agent/src/core/agent-session.ts)
- [packages/coding-agent/src/core/session-manager.ts](packages/coding-agent/src/core/session-manager.ts)
- [packages/coding-agent/src/core/model-resolver.ts](packages/coding-agent/src/core/model-resolver.ts)
- [packages/coding-agent/src/core/settings-manager.ts](packages/coding-agent/src/core/settings-manager.ts)
- [packages/coding-agent/src/core/resource-loader.ts](packages/coding-agent/src/core/resource-loader.ts)
- [packages/coding-agent/src/core/tools/index.ts](packages/coding-agent/src/core/tools/index.ts)
- [packages/coding-agent/src/core/tools/bash.ts](packages/coding-agent/src/core/tools/bash.ts)
- [packages/coding-agent/src/modes/print-mode.ts](packages/coding-agent/src/modes/print-mode.ts)
- [packages/coding-agent/src/modes/rpc/rpc-mode.ts](packages/coding-agent/src/modes/rpc/rpc-mode.ts)
</details>

# CLI, Session, and Tool Lifecycle

This page explains how the `pi` executable becomes an agent runtime: CLI flags are parsed, a session target determines the effective `cwd`, cwd-bound services are created, models/settings/resources are resolved, built-in and extension tools are registered, and the resulting `AgentSession` is handed to interactive, print, JSON, or RPC modes.

No `STRATEGY.md` or `docs/solutions/**` source was present in this checkout, so implementation claims below are grounded in repository code. The page shape follows the bundled Compound Engineering wiki guidance and remains provider-neutral: models, skills, extensions, and tools are file/repository/catalog resources, not tied to one hosted model provider.

## Executable entrypoint and high-level boundary

The published package exposes `pi` as `dist/cli.js`; the source entrypoint is `packages/coding-agent/src/cli.ts`. That file sets the process title, marks `PI_CODING_AGENT`, configures the HTTP dispatcher once, and calls `main(process.argv.slice(2))`.

Sources: [packages/coding-agent/package.json:1-12](), [packages/coding-agent/src/cli.ts:1-20]()

```mermaid
flowchart LR
  subgraph Executable
    CLI["src/cli.ts\nprocess/env setup"]
    Main["src/main.ts\nparse, select cwd/session, choose mode"]
  end

  subgraph CwdBoundRuntime["cwd-bound runtime"]
    Services["agent-session-services.ts\nsettings, auth, models, resources"]
    Runtime["agent-session-runtime.ts\nsession replacement host"]
    Session["agent-session.ts\nAgent facade + extensions + tools"]
  end

  subgraph PersistenceAndTools["storage and tools"]
    Sessions["session-manager.ts\nJSONL tree sessions"]
    Tools["core/tools/*\nbuiltin tool definitions"]
  end

  subgraph Modes["I/O modes"]
    Interactive["InteractiveMode"]
    Print["runPrintMode"]
    RPC["runRpcMode"]
  end

  CLI --> Main
  Main --> Services
  Services --> Session
  Main --> Runtime
  Runtime --> Session
  Session --> Sessions
  Session --> Tools
  Runtime --> Interactive
  Runtime --> Print
  Runtime --> RPC
```

## CLI parsing and application mode selection

`parseArgs()` recognizes model/provider flags, session controls, tool controls, resource-loading flags, output modes, `@file` arguments, and unknown long flags. Unknown long flags are preserved in `unknownFlags`; later runtime creation applies them to extension-registered flags, which lets extensions add CLI surface without changing the base parser.

Sources: [packages/coding-agent/src/cli/args.ts:10-178](), [packages/coding-agent/src/core/agent-session-services.ts:68-123]()

| Concern | Flags / input | Runtime effect |
|---|---|---|
| Mode | `--mode text/json/rpc`, `--print`, piped stdin | `main.ts` chooses `interactive`, `print`, `json`, or `rpc`; non-TTY stdin forces print mode unless RPC is selected. |
| Session | `--session`, `--continue`, `--resume`, `--fork`, `--no-session`, `--session-dir` | `main.ts` creates, opens, resumes, forks, or disables persistence through `SessionManager`. |
| Model | `--provider`, `--model`, `--models`, `--thinking`, `--api-key` | Model resolution and thinking level are converted into `CreateAgentSessionOptions`. |
| Tools | `--tools`, `--no-tools`, `--no-builtin-tools` | Creates an allowlist or suppresses default built-ins. |
| Resources | `--extension`, `--skill`, `--prompt-template`, `--theme`, `--no-*` | Passed to `DefaultResourceLoader` as cwd-resolved additional paths and disable switches. |

Sources: [packages/coding-agent/src/main.ts:90-113](), [packages/coding-agent/src/main.ts:321-384](), [packages/coding-agent/src/main.ts:393-665]()

## Session selection determines the effective `cwd`

Startup settings are loaded from the process cwd only to resolve session lookup settings such as `sessionDir`. Then `main.ts` creates the target `SessionManager`. This matters because `--session` and `--resume` may select a session created in another project; project-local settings, context files, extensions, provider registrations, and enabled models are not resolved until after the session’s effective cwd is known.

Sources: [packages/coding-agent/src/main.ts:151-278](), [packages/coding-agent/src/main.ts:471-520]()

Session target behavior:

- `--no-session` uses `SessionManager.inMemory()`.
- `--fork` resolves a path or ID prefix and creates a new session in the current project.
- `--session` opens local/path sessions directly; if an ID resolves globally in another project, the CLI prompts to fork into the current directory.
- `--resume` opens a selector backed by local and global session listing.
- `--continue` opens the most recent session for the selected session directory.
- Otherwise, a new persisted session is created.

Sources: [packages/coding-agent/src/main.ts:202-278](), [packages/coding-agent/src/core/session-manager.ts:1311-1395]()

## Cwd-bound services

`createAgentSessionServices()` is the service factory for one effective cwd. It resolves `cwd` and `agentDir`, creates or reuses auth/settings/model services, constructs a `DefaultResourceLoader`, reloads resources, registers extension-provided model providers, and applies extension CLI flag values as diagnostics instead of printing or exiting.

Sources: [packages/coding-agent/src/core/agent-session-services.ts:18-65](), [packages/coding-agent/src/core/agent-session-services.ts:130-169]()

`createAgentSessionFromServices()` then passes those already-created services into the SDK-level `createAgentSession()`. This split is intentional: the CLI can first resolve cwd-bound model/tool/session options against the correct services, then construct the session.

Sources: [packages/coding-agent/src/core/agent-session-services.ts:174-198]()

`DefaultResourceLoader` owns portable resource discovery. It loads extensions, skills, prompt templates, themes, context files, system prompt sources, and package resources from configured settings plus CLI-provided paths. Context discovery includes global agent-dir context and ancestor project context files unless disabled.

Sources: [packages/coding-agent/src/core/resource-loader.ts:21-54](), [packages/coding-agent/src/core/resource-loader.ts:69-106](), [packages/coding-agent/src/core/resource-loader.ts:108-143](), [packages/coding-agent/src/core/resource-loader.ts:274-390]()

## Model and settings resolution

Settings are layered from global and project files using a recursive merge where project settings override global settings. The `Settings` shape includes default provider/model/thinking level, enabled model patterns, package/resource sources, terminal/image behavior, retry settings, shell path/prefix, and session directory.

Sources: [packages/coding-agent/src/core/settings-manager.ts:68-138](), [packages/coding-agent/src/core/settings-manager.ts:564-649](), [packages/coding-agent/src/core/settings-manager.ts:763-784](), [packages/coding-agent/src/core/settings-manager.ts:1008-1012]()

Model resolution has two related paths:

1. `resolveCliModel()` handles a single CLI model, including `provider/model`, provider inference, exact matching, fuzzy matching, optional `:<thinking>`, and custom model-id fallback for known providers.
2. `resolveModelScope()` expands `--models` or `enabledModels` into a cycling scope, supporting glob patterns and optional thinking suffixes.

Sources: [packages/coding-agent/src/core/model-resolver.ts:260-487]()

Inside `createAgentSession()`, existing sessions can restore their saved model when configured auth is still available. If no model is restored or provided, `findInitialModel()` falls back through scoped models, settings defaults, known provider defaults, then the first available authenticated model. Thinking level is restored from the session when possible, otherwise from settings/defaults, and finally clamped to model capabilities.

Sources: [packages/coding-agent/src/core/sdk.ts:202-287](), [packages/coding-agent/src/core/model-resolver.ts:490-562]()

## Session persistence model

`SessionManager` stores sessions as append-only JSONL trees. The header records session id, timestamp, cwd, version, and optional parent session. Every entry has `id` and `parentId`, so appending creates a child of the current leaf and branch navigation can move through history without rewriting existing entries.

Sources: [packages/coding-agent/src/core/session-manager.ts:1-140](), [packages/coding-agent/src/core/session-manager.ts:711-912]()

The LLM context is not simply “all lines in the file.” `buildSessionContext()` walks from the active leaf to the root, restores model/thinking state from entries, inserts compaction summaries, includes kept messages after compaction, and includes branch/custom messages that participate in context.

Sources: [packages/coding-agent/src/core/session-manager.ts:330-421]()

Persistence is delayed until a session has an assistant message; then accumulated entries are flushed and later entries append one JSON line at a time. This avoids saving incomplete one-sided sessions while preserving an append-only log once an assistant response exists.

Sources: [packages/coding-agent/src/core/session-manager.ts:827-867]()

## Built-in tools and bash lifecycle

The built-in tool registry knows seven tool names: `read`, `bash`, `edit`, `write`, `grep`, `find`, and `ls`. `createAllToolDefinitions()` creates definitions for all of them, while SDK defaults activate only `read`, `bash`, `edit`, and `write` unless CLI/tool options change the active set.

Sources: [packages/coding-agent/src/core/tools/index.ts:54-141](), [packages/coding-agent/src/core/sdk.ts:289-297]()

`AgentSession._buildRuntime()` rebuilds builtin definitions with cwd-bound options. The bash definition receives `shellCommandPrefix` and `shellPath` from settings; read receives image auto-resize settings. Extension tools and SDK custom tools are merged into the registry, then wrapped so extension hooks can observe or modify calls/results.

Sources: [packages/coding-agent/src/core/agent-session.ts:2253-2414]()

The bash tool is explicitly pluggable. `BashOperations.exec()` can be replaced, but the default local implementation uses the configured shell, validates cwd existence, spawns a child process, streams stdout/stderr, supports abort signals, supports per-call timeout, kills the process tree on abort/timeout, and tracks detached child pids. Output is accumulated, truncated by line/byte limits, and saved to a temp file when needed.

Sources: [packages/coding-agent/src/core/tools/bash.ts:22-149](), [packages/coding-agent/src/core/tools/bash.ts:252-426]()

## Bridging into the core agent

`createAgentSession()` constructs the core `Agent` with model, thinking level, tool list, context conversion, provider streaming, provider request/response extension hooks, queueing behavior, transport, retry settings, and session id. API keys and provider headers are resolved through `ModelRegistry` at request time, keeping provider choice outside the CLI lifecycle itself.

Sources: [packages/coding-agent/src/core/sdk.ts:299-374]()

`AgentSession` is the shared lifecycle facade used by all modes. It subscribes to core agent events, forwards them to extensions, emits them to UI/RPC/print subscribers, and persists finalized user/assistant/tool result messages through `SessionManager`. It also owns model/thinking changes, compaction, queues, extension bindings, tool registry state, and system prompt rebuilding.

Sources: [packages/coding-agent/src/core/agent-session.ts:302-340](), [packages/coding-agent/src/core/agent-session.ts:486-520](), [packages/coding-agent/src/core/agent-session.ts:2041-2414]()

Prompt submission goes through `AgentSession.prompt()`: extension slash commands can run immediately, input hooks can handle or transform text/images, skills and prompt templates expand, streaming prompts are queued as steer/follow-up messages, model/auth preflight is checked, pending bash messages are flushed, extension `before_agent_start` hooks can inject custom messages or modify the system prompt, and the core agent is finally prompted.

Sources: [packages/coding-agent/src/core/agent-session.ts:962-1116]()

## Runtime replacement: new, resume, fork, import

`AgentSessionRuntime` owns the active `AgentSession` plus cwd-bound services. Replacement flows emit extension lifecycle hooks, tear down the old session, create a new runtime through the same factory, apply the new session/services, and optionally rebind host UI or command contexts. This keeps `/new`, resume/switch, fork, and import behavior consistent with initial startup.

Sources: [packages/coding-agent/src/core/agent-session-runtime.ts:55-165](), [packages/coding-agent/src/core/agent-session-runtime.ts:166-407]()

## Run modes

After runtime creation and diagnostics, `main.ts` dispatches by mode:

- RPC mode calls `runRpcMode(runtime)`.
- Interactive mode constructs `InteractiveMode` with migrated-provider and startup-message context.
- Print/text and JSON modes call `runPrintMode()` and then restore stdout/exit with the returned code.

Sources: [packages/coding-agent/src/main.ts:650-716]()

`runPrintMode()` binds extension command actions, subscribes to session events for JSON mode, sends the initial message and follow-up messages, prints the final assistant text in text mode, and disposes the runtime in `finally`.

Sources: [packages/coding-agent/src/modes/print-mode.ts:1-142]()

`runRpcMode()` is a headless JSON stdin/stdout protocol. It takes over stdout, emits JSON responses/events, exposes extension UI requests over the protocol, and keeps the same `AgentSessionRuntime` replacement host as other modes.

Sources: [packages/coding-agent/src/modes/rpc/rpc-mode.ts:1-50]()

## Summary

The CLI lifecycle is intentionally staged: parse flags, select or create a session to establish the effective cwd, build cwd-bound services/resources, resolve model/thinking/tool options, construct `AgentSession`, then hand a runtime host to the selected I/O mode. Sessions persist as JSONL trees, tools are definition-first and cwd-bound, and provider/model selection stays behind registries and settings rather than being hardcoded into the executable.

Sources: [packages/coding-agent/src/main.ts:471-716](), [packages/coding-agent/src/core/sdk.ts:202-416](), [packages/coding-agent/src/core/session-manager.ts:711-912]()
