import * as c from "../ansi.js"; import { THINKING_LEVELS } from "../thinking-levels.js"; export type CliHelpPath = readonly string[]; type HelpItem = { name: string; summary: string; }; type HelpFlag = { name: string; value?: string; summary: string; required?: boolean; }; type HelpExample = { command: string; summary?: string; }; export type HelpTopic = { path: string[]; title: string; summary: string; usage?: string; description?: string[]; commonFlows?: HelpExample[]; subcommands?: HelpItem[]; arguments?: HelpItem[]; keys?: HelpItem[]; flags?: HelpFlag[]; notes?: string[]; examples?: HelpExample[]; }; type HelpJsonTopic = Omit & { path: string[] }; const HELP_TOPICS: HelpTopic[] = [ { path: [], title: "Oppi CLI", summary: "Run and manage a local Oppi server.", commonFlows: [ { command: "oppi init → oppi serve → oppi pair", summary: "first run, local server, iPhone pairing", }, { command: "oppi server install → oppi server status", summary: "run the server in the background with launchd", }, { command: "oppi schedule help", summary: "schedule future or repeated agent work", }, { command: "oppi session create --help", summary: "launch a session from scripts or automation", }, ], subcommands: [ { name: "init", summary: "write first-time config and owner credentials" }, { name: "serve/start", summary: "start the local server in this terminal" }, { name: "pair", summary: "show a signed pairing QR/link for the iOS app" }, { name: "status", summary: "show server, network, and pairing status" }, { name: "doctor", summary: "run security and environment diagnostics" }, { name: "server", summary: "install, restart, stop, or inspect the launchd service" }, { name: "config", summary: "show, get, set, or validate server config" }, { name: "workspace", summary: "list, inspect, create, update, and delete workspaces" }, { name: "worktree", summary: "list, create, open, and remove workspace worktrees" }, { name: "session", summary: "list, launch, inspect, message, resume, fork, and stop sessions", }, { name: "schedule", summary: "create and run scheduled agent work" }, { name: "agent", summary: "create, inspect, update, archive, and launch saved Agents" }, { name: "skill", summary: "inspect and update editable server Skill files" }, { name: "wait", summary: "poll session state until a condition is true" }, { name: "token", summary: "rotate the owner bearer token" }, { name: "update", summary: "check or update the npm-installed server and CLI" }, { name: "version", summary: "print the installed package version" }, ], notes: [ "Default output is terminal-friendly for humans and agents; use '--json' for strict machine parsing.", "Help, version, init, serve, pair, status, doctor, config, server, and update are available during setup; workspace, worktree, session, Agent, schedule, and wait commands require local owner credentials and a running server.", "Use ' help' or ' --help' for flags and deeper examples.", "Use '--json' with help for an agent-readable description of the same topic.", ], examples: [ { command: "oppi config set port 8080" }, { command: "oppi config set asr.sttEndpoint http://127.0.0.1:7936" }, { command: 'oppi config set tls \'{"mode":"self-signed"}\'' }, ], }, { path: ["init"], title: "Initialize Oppi", summary: "Write first-time config, generate owner credentials, and set TLS defaults.", usage: "oppi init [flags]", flags: [ { name: "--data-dir", value: "", summary: "config/data directory to initialize" }, { name: "--port", value: "", summary: "server port; defaults to 7749" }, { name: "--max-sessions", value: "", summary: "global concurrent session limit; defaults to 200", }, { name: "--yes", summary: "non-interactive setup with defaults" }, { name: "--force", summary: "continue when config already exists" }, ], notes: [ "Without --yes, init prompts when stdin is interactive.", "Init writes config.json, rotates the owner token, and generates identity keys.", ], examples: [{ command: "oppi init" }, { command: "oppi init --yes --data-dir ~/.config/oppi" }], }, { path: ["serve"], title: "Serve", summary: "Start the Oppi server in the foreground.", usage: "oppi serve [--host ]", flags: [ { name: "--host", value: "", summary: "hostname/IP encoded in first-run pairing QR" }, ], notes: [ "On first run, serve creates owner credentials, enables self-signed TLS, and prints a pairing QR.", "Press Ctrl+C to stop the foreground server.", ], examples: [{ command: "oppi serve" }, { command: "oppi serve --host mac-studio.local" }], }, { path: ["start"], title: "Start", summary: "Alias for 'oppi serve'.", usage: "oppi start [--host ]", flags: [ { name: "--host", value: "", summary: "hostname/IP encoded in first-run pairing QR" }, ], examples: [{ command: "oppi start" }], }, { path: ["pair"], title: "Pair", summary: "Generate a signed pairing QR/link for the Oppi iOS app.", usage: "oppi pair [name] [flags]", arguments: [{ name: "name", summary: "optional display name for the pairing invite" }], flags: [ { name: "--host", value: "", summary: "hostname/IP encoded in the invite" }, { name: "--json", summary: "write the invite payload as JSON" }, { name: "--show-token", summary: "print the owner bearer token in human output; unsafe" }, ], notes: [ "The QR and link carry the same signed invite.", "Use --show-token only for manual recovery; it exposes the owner token in the terminal.", ], examples: [ { command: 'oppi pair "Chen"' }, { command: "oppi pair --host mac-studio.local" }, { command: "oppi pair --json" }, ], }, { path: ["status"], title: "Status", summary: "Show server config, Local Network addresses, Tailscale status, and pairing state.", usage: "oppi status", notes: ["This reads local config and host network state; it does not contact the server API."], examples: [{ command: "oppi status" }], }, { path: ["doctor"], title: "Doctor", summary: "Run security, TLS, launchd, runtime, and environment diagnostics.", usage: "oppi doctor", notes: [ "Doctor exits non-zero for critical failures.", "It inspects TLS files but does not generate missing certificate material.", ], examples: [{ command: "oppi doctor" }], }, { path: ["update"], title: "Update", summary: "Check or update the npm-installed Oppi server and CLI.", usage: "oppi update [flags]", flags: [ { name: "--check", summary: "check update status without installing" }, { name: "--dry", summary: "show the npm update command without installing" }, ], notes: [ "Oppi server and CLI versions are installed together as the oppi-server npm package.", "Restart the running server after an update.", ], examples: [{ command: "oppi update --check" }, { command: "oppi update" }], }, { path: ["token"], title: "Token", summary: "Rotate the owner bearer token.", usage: "oppi token rotate", subcommands: [{ name: "rotate", summary: "generate a new owner token" }], notes: [ "Existing clients become unauthorized after rotation and must be paired again.", "The server must already be paired before token rotation can run.", ], examples: [{ command: "oppi token rotate" }], }, { path: ["token", "rotate"], title: "Rotate owner token", summary: "Generate a new owner bearer token and invalidate existing clients.", usage: "oppi token rotate", notes: ["Existing clients must be re-paired with 'oppi pair' after rotation."], examples: [{ command: "oppi token rotate" }], }, { path: ["config"], title: "Config", summary: "Show, read, update, or validate local Oppi server config.", usage: "oppi config [args] [flags]", subcommands: [ { name: "show", summary: "print current config as formatted JSON" }, { name: "get ", summary: "print one config value" }, { name: "set ", summary: "update one supported config value" }, { name: "validate", summary: "validate a config file" }, ], notes: [ "Config paths use dot notation, for example tls.mode or runtimeEnv.TTS_BASE_URL.", "Run 'oppi config set --help' for common keys and value formats.", ], examples: [ { command: "oppi config show" }, { command: "oppi config get port" }, { command: "oppi config set asr.sttEndpoint http://127.0.0.1:7936" }, ], }, { path: ["config", "show"], title: "Show config", summary: "Print current or default config as formatted JSON.", usage: "oppi config show [--default]", flags: [{ name: "--default", summary: "show built-in defaults instead of current config" }], examples: [{ command: "oppi config show" }, { command: "oppi config show --default" }], }, { path: ["config", "get"], title: "Get config", summary: "Print one config value.", usage: "oppi config get ", arguments: [ { name: "", summary: "config path such as port, tls.mode, or runtimeEnv.NAME" }, ], notes: ["The output is intentionally plain so scripts can read it."], examples: [{ command: "oppi config get port" }, { command: "oppi config get tls.mode" }], }, { path: ["config", "set"], title: "Set config", summary: "Update one supported config value.", usage: "oppi config set ", arguments: [ { name: "", summary: "supported config key or runtimeEnv." }, { name: "", summary: "string, number, boolean, or JSON depending on the key" }, ], keys: [ { name: "port", summary: "number; server port" }, { name: "host", summary: "string; bind address" }, { name: "maxSessionsGlobal", summary: "number; global concurrent session limit" }, { name: "runtimePathEntries", summary: "JSON array; runtime PATH entries" }, { name: "runtimeEnv.", summary: "string; one runtime environment variable" }, { name: "tls.mode", summary: "string; disabled, self-signed, tailscale, or manual" }, { name: "tls.certPath", summary: "string; manual TLS certificate path" }, { name: "asr.sttEndpoint", summary: "string; STT backend base URL" }, { name: "images.autoResize", summary: "boolean; resize large image uploads" }, { name: "extensions.voice.defaultVoiceId", summary: "string; saved voice id" }, ], notes: [ 'JSON-valued keys must receive valid JSON, for example \'{"mode":"self-signed"}\'.', "Run 'oppi config set' without enough arguments to print the complete supported-key list with current values.", ], examples: [ { command: "oppi config set port 8080" }, { command: "oppi config set runtimeEnv.TTS_BASE_URL http://127.0.0.1:7937" }, { command: "oppi config set tls.mode self-signed" }, ], }, { path: ["config", "validate"], title: "Validate config", summary: "Validate a config file and report errors or warnings.", usage: "oppi config validate [--config-file ]", flags: [ { name: "--config-file", value: "", summary: "config file to validate; defaults to current config", }, ], examples: [ { command: "oppi config validate" }, { command: "oppi config validate --config-file /tmp/config.json" }, ], }, { path: ["server"], title: "Background server", summary: "Manage the macOS LaunchAgent background server.", usage: "oppi server [flags]", subcommands: [ { name: "install", summary: "install the LaunchAgent" }, { name: "uninstall", summary: "remove the LaunchAgent" }, { name: "status", summary: "show LaunchAgent status" }, { name: "restart", summary: "restart the background server" }, { name: "stop", summary: "stop the background server" }, ], notes: ["The LaunchAgent starts Oppi automatically on login and restarts it after crashes."], examples: [ { command: "oppi server install" }, { command: "oppi server status" }, { command: "oppi server restart" }, ], }, { path: ["server", "install"], title: "Install background server", summary: "Install the LaunchAgent that starts Oppi on login.", usage: "oppi server install [--data-dir ]", flags: [ { name: "--data-dir", value: "", summary: "data directory for the installed service" }, ], examples: [ { command: "oppi server install" }, { command: "oppi server install --data-dir ~/.config/oppi" }, ], }, { path: ["server", "uninstall"], title: "Uninstall background server", summary: "Remove the Oppi LaunchAgent.", usage: "oppi server uninstall", examples: [{ command: "oppi server uninstall" }], }, { path: ["server", "status"], title: "Background server status", summary: "Show LaunchAgent installation, PID, runtime path, CLI path, and data dir.", usage: "oppi server status", examples: [{ command: "oppi server status" }], }, { path: ["server", "restart"], title: "Restart background server", summary: "Restart the background server through launchd.", usage: "oppi server restart", notes: ["Use this after config or runtime changes when Oppi is running as a LaunchAgent."], examples: [{ command: "oppi server restart" }], }, { path: ["server", "stop"], title: "Stop background server", summary: "Stop the background server through launchd.", usage: "oppi server stop", examples: [{ command: "oppi server stop" }], }, { path: ["version"], title: "Version", summary: "Print the installed oppi-server package version.", usage: "oppi version", notes: ["Aliases: oppi --version, oppi -v."], examples: [{ command: "oppi version" }], }, { path: ["workspace"], title: "Workspaces", summary: "List, inspect, create, update, and delete configured Oppi workspaces through the local API.", usage: "oppi workspace [flags]", subcommands: [ { name: "list", summary: "list configured workspaces" }, { name: "get ", summary: "show one workspace by id or unique name" }, { name: "create", summary: "create a workspace from flags and an optional JSON definition" }, { name: "update ", summary: "update a workspace from flags or JSON" }, { name: "delete ", summary: "delete a workspace from the server catalog" }, ], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [ { command: "oppi workspace list" }, { command: "oppi workspace create --name Oppi --host-mount ~/workspace/oppi --json" }, { command: "oppi workspace get oppi --json" }, ], }, { path: ["workspace", "list"], title: "List workspaces", summary: "List configured workspaces.", usage: "oppi workspace list [--json]", flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi workspace list" }, { command: "oppi workspace list --json" }], }, { path: ["workspace", "get"], title: "Get workspace", summary: "Show one workspace by workspace id or unique name.", usage: "oppi workspace get [--json]", arguments: [{ name: "", summary: "workspace id or unique name" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [ { command: "oppi workspace get ws_123" }, { command: "oppi workspace get oppi --json" }, ], }, { path: ["workspace", "create"], title: "Create workspace", summary: "Create a workspace from --name, optional field flags, and an optional JSON definition file.", usage: "oppi workspace create --name [--host-mount ] [--definition ] [--json]", flags: [ { name: "--name", value: "", summary: "workspace display name", required: true }, { name: "--host-mount", value: "", summary: "host directory mounted as the workspace root", }, { name: "--description", value: "", summary: "workspace description" }, { name: "--icon", value: "", summary: "SF Symbol name or emoji" }, { name: "--system-prompt", value: "", summary: "workspace system prompt text" }, { name: "--default-model", value: "", summary: "default model for new sessions" }, { name: "--runtime", value: "", summary: "workspace runtime mode" }, { name: "--definition", value: "", summary: "JSON CreateWorkspaceRequest fields" }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [ { command: "oppi workspace create --name Oppi --host-mount ~/workspace/oppi --json" }, ], }, { path: ["workspace", "update"], title: "Update workspace", summary: "Update a workspace by id or unique name from field flags or a JSON definition file.", usage: "oppi workspace update [--name ] [--definition ] [--json]", arguments: [{ name: "", summary: "workspace id or unique name" }], flags: [ { name: "--name", value: "", summary: "workspace display name" }, { name: "--host-mount", value: "", summary: "host directory mounted as the workspace root", }, { name: "--description", value: "", summary: "workspace description" }, { name: "--icon", value: "", summary: "SF Symbol name or emoji" }, { name: "--system-prompt", value: "", summary: "workspace system prompt text" }, { name: "--default-model", value: "", summary: "default model for new sessions" }, { name: "--runtime", value: "", summary: "workspace runtime mode" }, { name: "--definition", value: "", summary: "JSON UpdateWorkspaceRequest fields" }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi workspace update ws_123 --default-model openai/gpt-5.5 --json" }], }, { path: ["workspace", "delete"], title: "Delete workspace", summary: "Delete a workspace from the server catalog.", usage: "oppi workspace delete [--json]", arguments: [{ name: "", summary: "workspace id or unique name" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi workspace delete ws_123 --json" }], }, { path: ["worktree"], title: "Worktrees", summary: "List, create, open, and remove workspace git worktrees.", usage: "oppi worktree --workspace [flags]", subcommands: [ { name: "list", summary: "list discovered and Oppi-managed worktrees" }, { name: "get ", summary: "show one worktree by id or name; main is the default checkout", }, { name: "create", summary: "create an Oppi-managed worktree under OPPI_DATA_DIR" }, { name: "open", summary: "resolve an existing worktree by branch or path" }, { name: "status ", summary: "show worktree metadata and git status" }, { name: "preview ", summary: "preview integration into a target branch" }, { name: "remove ", summary: "remove an Oppi-managed worktree" }, ], flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name", required: true, }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "New worktrees are created under OPPI_DATA_DIR/worktrees//.", "Project-local .pi/worktrees entries remain discoverable, but remove only touches Oppi-managed data-dir worktrees.", ], examples: [ { command: "oppi worktree list --workspace ws_123" }, { command: "oppi worktree create --workspace ws_123 --branch feature/foo --json" }, { command: "oppi worktree preview wt_feature-foo-abc12345 --workspace ws_123 --into main --json", }, { command: "oppi worktree remove wt_feature-foo-abc12345 --workspace ws_123 --json" }, ], }, { path: ["worktree", "list"], title: "List worktrees", summary: "List discovered worktrees for one workspace.", usage: "oppi worktree list --workspace [--json]", flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name", required: true, }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi worktree list --workspace ws_123" }], }, { path: ["worktree", "get"], title: "Get worktree", summary: "Show one discovered worktree by id or name.", usage: "oppi worktree get --workspace [--json]", arguments: [ { name: "", summary: "worktree id or name; main is the primary checkout" }, ], flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name", required: true, }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi worktree get main --workspace ws_123 --json" }], }, { path: ["worktree", "create"], title: "Create worktree", summary: "Create an Oppi-managed git worktree under OPPI_DATA_DIR.", usage: "oppi worktree create --workspace --branch [--base ] [--json]", flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name", required: true, }, { name: "--branch", value: "", summary: "branch to create or check out", required: true, }, { name: "--base", value: "", summary: "base ref for a new branch; defaults to HEAD" }, { name: "--path", value: "", summary: "optional direct child path under OPPI_DATA_DIR/worktrees/", }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "If the branch already exists, Oppi checks out that branch in a new worktree.", "Retained session history reserves its worktree id, so the same branch or custom path cannot be recreated until that history is deleted.", "Custom paths are rejected unless they stay inside the Oppi-managed data-dir root.", ], examples: [ { command: "oppi worktree create --workspace ws_123 --branch feature/foo --json" }, { command: "oppi worktree create --workspace oppi --branch fix/crash --base main" }, ], }, { path: ["worktree", "open"], title: "Open worktree", summary: "Resolve an existing worktree by branch or path.", usage: "oppi worktree open --workspace (--branch | --path ) [--json]", flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name", required: true, }, { name: "--branch", value: "", summary: "existing branch name" }, { name: "--path", value: "", summary: "existing worktree path" }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi worktree open --workspace ws_123 --branch feature/foo --json" }], }, { path: ["worktree", "status"], title: "Worktree status", summary: "Show worktree metadata and git status without changing files.", usage: "oppi worktree status --workspace [--json]", arguments: [{ name: "", summary: "worktree id" }], flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name", required: true, }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi worktree status wt_feature-foo-abc12345 --workspace ws_123" }], }, { path: ["worktree", "preview"], title: "Preview worktree integration", summary: "Preview commits, changed files, fast-forward status, and conflicts before merging.", usage: "oppi worktree preview --workspace --into [--mode ] [--json]", arguments: [{ name: "", summary: "source worktree id" }], flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name", required: true, }, { name: "--into", value: "", summary: "target branch or ref", required: true }, { name: "--mode", value: "", summary: "intended completion mode; defaults to merge", }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "Preview is read-only and is the command agents should run before asking to complete or remove a worktree.", ], examples: [ { command: "oppi worktree preview wt_feature-foo-abc12345 --workspace ws_123 --into main --json", }, ], }, { path: ["worktree", "remove"], title: "Remove worktree", summary: "Remove an Oppi-managed data-dir worktree.", usage: "oppi worktree remove --workspace [--force] [--json]", arguments: [{ name: "", summary: "Oppi-managed worktree id" }], flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name", required: true, }, { name: "--force", summary: "allow removing dirty worktrees" }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "Remove keeps stopped session history, but refuses the main checkout, project-local .pi/worktrees entries, and worktrees with active sessions.", "Retained history reserves the removed worktree id until that history is deleted.", ], examples: [{ command: "oppi worktree remove wt_feature-foo-abc12345 --workspace ws_123" }], }, { path: ["wait"], title: "Wait", summary: "Poll session state until a condition is true.", usage: "oppi wait session --status [flags]", subcommands: [{ name: "session ", summary: "wait for a session status" }], flags: [ { name: "--status", value: "", summary: "target status; defaults to stopped" }, { name: "--timeout", value: "", summary: "maximum wait such as 900, 30s, or 5m; bare numbers are seconds", }, { name: "--poll", value: "", summary: "poll interval such as 1 or 500ms; bare numbers are seconds (default 1s)", }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi wait session sess_123 --status stopped --json" }], }, { path: ["wait", "session"], title: "Wait for a session", summary: "Poll one session until its status matches.", usage: "oppi wait session --status [--timeout ] [--json]", arguments: [{ name: "", summary: "session id" }], flags: [ { name: "--status", value: "", summary: "target status; defaults to stopped" }, { name: "--timeout", value: "", summary: "maximum wait such as 900, 30s, or 10m; bare numbers are seconds", }, { name: "--poll", value: "", summary: "poll interval such as 1 or 500ms; bare numbers are seconds (default 1s)", }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi wait session sess_123 --status stopped --timeout 10m --json" }], }, { path: ["schedule"], title: "Schedules", summary: "Schedules run Oppi actions later, repeatedly, or from a cron expression.", usage: "oppi schedule [flags]", description: [ "A schedule stores a trigger plus a new-session or existing-session action.", "New-session schedules can use workspace defaults or a saved Agent; manual and automatic runs keep history for inspection.", ], subcommands: [ { name: "list", summary: "list schedules" }, { name: "get ", summary: "show one schedule" }, { name: "create", summary: "create a new-session or existing-session schedule" }, { name: "update ", summary: "patch a schedule from a JSON definition" }, { name: "run ", summary: "run a schedule now" }, { name: "runs ", summary: "show run history for a schedule" }, { name: "pause ", summary: "pause future automatic runs" }, { name: "resume ", summary: "resume automatic runs" }, { name: "archive ", summary: "archive a schedule" }, { name: "restore ", summary: "restore an archived schedule as active" }, ], notes: ["Run 'oppi schedule create --help' for exact creation flags."], examples: [ { command: 'oppi schedule create --workspace ws_123 --prompt "Check tests" --every 1h', }, { command: "oppi schedule run sch_123 --request-id retry-001" }, { command: "oppi schedule runs sch_123 --json" }, ], }, { path: ["schedule", "create"], title: "Create a schedule", summary: "Create a schedule that launches a new workspace session when its trigger fires.", usage: "oppi schedule create (--workspace | --session ) --prompt (--at | --every | --cron ) [flags]", flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name to launch in", }, { name: "--session", value: "", summary: "existing session id to send future prompts to", }, { name: "--prompt", value: "", summary: "prompt sent when the schedule runs", required: true, }, { name: "--at", value: "", summary: "run once at an ISO timestamp" }, { name: "--every", value: "", summary: "repeat interval such as 15m, 1h, or 1d" }, { name: "--cron", value: "", summary: "cron expression for repeated runs" }, { name: "--tz", value: "", summary: "IANA time zone; defaults to the local zone" }, { name: "--name", value: "", summary: "schedule and launched-session name" }, { name: "--model", value: "", summary: "model override; fuzzy-matched against enabled Pi models", }, { name: "--agent", value: "", summary: "saved Agent id/name for new-session schedules", }, { name: "--worktree", value: "", summary: "workspace worktree id" }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "Choose exactly one trigger flag: --at, --every, or --cron.", "Choose exactly one target flag: --workspace or --session.", "Use --agent only with --workspace; existing-session schedules send prompts to the selected session.", "Run history is available with 'oppi schedule runs '.", "Manual runs are idempotent when you reuse 'oppi schedule run --request-id '; automatic runs use their schedule slot as the idempotency key.", "--model accepts exact provider/model IDs or fuzzy text like sonnet; it resolves against /models, which is filtered by Pi enabledModels.", ], examples: [ { command: 'oppi schedule create --workspace ws_123 --prompt "Summarize overnight failures" --at 2026-06-29T09:00:00Z', }, { command: 'oppi schedule create --workspace ws_123 --prompt "Run npm test" --every 1h --name "Hourly test check"', }, { command: 'oppi schedule create --workspace ws_123 --prompt "Prepare Monday status" --cron "0 9 * * 1" --tz America/Los_Angeles', }, ], }, { path: ["schedule", "list"], title: "List schedules", summary: "List configured schedules.", usage: "oppi schedule list [--workspace ] [--session ] [--agent ] [--json]", flags: [ { name: "--workspace", value: "", summary: "filter by workspace id or name" }, { name: "--session", value: "", summary: "filter by existing-session target" }, { name: "--agent", value: "", summary: "filter by saved Agent id" }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [ { command: "oppi schedule list" }, { command: "oppi schedule list --agent Reviewer --json" }, ], }, { path: ["schedule", "get"], title: "Get schedule", summary: "Show one schedule by id.", usage: "oppi schedule get [--json]", arguments: [{ name: "", summary: "schedule id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi schedule get sch_123" }], }, { path: ["schedule", "update"], title: "Update schedule", summary: "Patch a schedule from a definition or a focused model update.", usage: "oppi schedule update (--definition | --definition-json | --model | --clear-model) [--json]", arguments: [{ name: "", summary: "schedule id" }], flags: [ { name: "--definition", value: "", summary: "JSON object with schedule fields to patch", }, { name: "--definition-json", value: "", summary: "inline JSON Merge Patch object; maximum 65536 bytes", }, { name: "--model", value: "", summary: "update a new-session schedule model" }, { name: "--clear-model", summary: "remove the explicit new-session model so the Agent or workspace default applies", }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "Choose one update input. Omitted fields are unchanged; in definition JSON, null clears optional action fields.", "Action type changes require a complete action definition.", ], examples: [ { command: "oppi schedule update sch_123 --model ds4/deepseek-v4-flash --json" }, { command: "oppi schedule update sch_123 --clear-model --json" }, { command: `oppi schedule update sch_123 --definition-json '{"action":{"model":"ds4/deepseek-v4-flash"}}' --json`, }, ], }, { path: ["schedule", "run"], title: "Run schedule", summary: "Create or reuse a manual run for a schedule and dispatch it now.", usage: "oppi schedule run [--request-id ] [--json]", arguments: [{ name: "", summary: "schedule id" }], flags: [ { name: "--request-id", value: "", summary: "manual-run idempotency key; defaults to the current timestamp", }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "Manual runs are idempotent by schedule id plus --request-id.", "Reuse the same --request-id when retrying after a timeout or network failure.", ], examples: [ { command: "oppi schedule run sch_123" }, { command: "oppi schedule run sch_123 --request-id deploy-check-001 --json" }, ], }, { path: ["schedule", "runs"], title: "Schedule run history", summary: "Show run history for a schedule.", usage: "oppi schedule runs [--json]", arguments: [{ name: "", summary: "schedule id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi schedule runs sch_123" }], }, { path: ["schedule", "pause"], title: "Pause schedule", summary: "Pause future automatic runs for a schedule.", usage: "oppi schedule pause [--json]", arguments: [{ name: "", summary: "schedule id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi schedule pause sch_123" }], }, { path: ["schedule", "resume"], title: "Resume schedule", summary: "Resume automatic runs for a paused schedule.", usage: "oppi schedule resume [--json]", arguments: [{ name: "", summary: "schedule id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi schedule resume sch_123" }], }, { path: ["schedule", "archive"], title: "Archive schedule", summary: "Archive a schedule so it no longer runs automatically.", usage: "oppi schedule archive [--json]", arguments: [{ name: "", summary: "schedule id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi schedule archive sch_123" }], }, { path: ["schedule", "restore"], title: "Restore schedule", summary: "Restore an archived schedule and activate future automatic runs.", usage: "oppi schedule restore [--json]", arguments: [{ name: "", summary: "schedule id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi schedule restore sch_123" }], }, { path: ["session"], title: "Sessions", summary: "List, launch, inspect, steer, watch, resume, fork, and stop Oppi sessions through the local server API.", usage: "oppi session [flags]", subcommands: [ { name: "list", summary: "list sessions" }, { name: "get ", summary: "show session metadata" }, { name: "create", summary: "launch a workspace session" }, { name: "send ", summary: "send text; steer a busy turn or queue a follow-up" }, { name: "abort ", summary: "abort the current turn" }, { name: "dialogs ", summary: "list pending ask/extension-UI dialogs" }, { name: "respond ", summary: "answer a pending dialog" }, { name: "watch ", summary: "stream state transitions for sessions" }, { name: "wait ", summary: "block until idle or attention" }, { name: "read ", summary: "show transcript-style trace entries" }, { name: "events ", summary: "read live catch-up events" }, { name: "trace ", summary: "show raw trace entries" }, { name: "search ", summary: "search session content" }, { name: "inspect ", summary: "inspect selected turns from a session trace" }, { name: "stop ", summary: "stop a session" }, { name: "resume ", summary: "resume a stopped session" }, { name: "fork ", summary: "fork a session from a trace entry" }, { name: "delete ", summary: "delete a session" }, { name: "changes ", summary: "list files changed by a session" }, { name: "diff ", summary: "show a changed file diff" }, { name: "tool-output ", summary: "show stored tool output" }, { name: "trace-page ", summary: "show paged trace entries" }, { name: "trace-outline ", summary: "show a trace outline" }, ], notes: [ "Plain 'send' prompts an idle session and steers a busy session at the next turn boundary; use '--follow-up' to wait until current work finishes.", "Orchestrate with 'watch ' for live transitions and 'wait ' to block on one condition.", "Inspect history progressively: 'inspect --view summary' for counts, '--view outline' to choose turns, then '--view messages' or '--view tools'.", ], examples: [ { command: "oppi session watch sess_123 --until idle" }, { command: 'oppi session send sess_123 --text "focus on the failing test"' }, { command: "oppi session inspect sess_123 --view outline" }, ], }, { path: ["session", "list"], title: "List sessions", summary: "List app-style session rows, optionally filtered by workspace, worktree, status, or limit.", usage: "oppi session list [--workspace ] [--worktree ] [--json]", flags: [ { name: "--workspace", value: "", summary: "workspace id or unique name" }, { name: "--worktree", value: "", summary: "worktree id" }, { name: "--status", value: "", summary: "active, stopped, or a concrete session status", }, { name: "--limit", value: "", summary: "maximum sessions to return" }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "Without --workspace, this uses the same recent cross-workspace projection as the app home view.", "With --workspace, this uses the workspace session-list projection and includes importable local Pi TUI sessions.", ], examples: [{ command: "oppi session list --workspace ws_123 --json" }], }, { path: ["session", "get"], title: "Get session", summary: "Show session metadata without dumping transcript or trace entries.", usage: "oppi session get [--json]", arguments: [{ name: "", summary: "session id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi session get sess_123 --json" }], }, { path: ["session", "send"], title: "Send to session", summary: "Prompt an idle session, steer a busy session, or queue a follow-up.", usage: "oppi session send --text [--steer | --follow-up] [--json]", arguments: [{ name: "", summary: "session id" }], flags: [ { name: "--text", value: "", summary: "message text to send", required: true }, { name: "--steer", summary: "require a busy session and steer at the next turn boundary" }, { name: "--follow-up", summary: "require a busy session and wait until current work finishes", }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "Pass @- to --text to read the message from stdin.", "Without a delivery flag, send prompts an idle session and steers a busy session after its current tool calls, before the next model turn.", "Use --follow-up for work that should begin only after the agent finishes its current work.", ], examples: [ { command: 'oppi session send sess_123 --text "Focus on the failing test"' }, { command: 'oppi session send sess_123 --text "Afterward, summarize the fix" --follow-up' }, ], }, { path: ["session", "abort"], title: "Abort turn", summary: "Abort the current streaming turn without stopping the session.", usage: "oppi session abort [--json]", arguments: [{ name: "", summary: "session id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], notes: ["Aborts the in-flight turn only; use 'session stop' to end the session."], examples: [{ command: "oppi session abort sess_123" }], }, { path: ["session", "dialogs"], title: "List pending dialogs", summary: "List pending ask/extension-UI dialogs a session is blocked on.", usage: "oppi session dialogs [--json]", arguments: [{ name: "", summary: "session id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], notes: ["Each row shows the request id, method, prompt, and options for 'session respond'."], examples: [{ command: "oppi session dialogs sess_123 --json" }], }, { path: ["session", "respond"], title: "Respond to a dialog", summary: "Answer a pending ask/extension-UI dialog with text, an option, confirm, or cancel.", usage: "oppi session respond [--dialog ] [--text | --option | --answers | --confirm | --decline | --cancel] [--json]", arguments: [{ name: "", summary: "session id" }], flags: [ { name: "--dialog", value: "", summary: "target dialog; optional when only one is pending", }, { name: "--text", value: "", summary: "free-text answer" }, { name: "--option", value: "", summary: "selected option value" }, { name: "--answers", value: "", summary: "ask answers object for multi-question asks" }, { name: "--confirm", summary: "confirm a confirm dialog" }, { name: "--decline", summary: "decline a confirm dialog" }, { name: "--cancel", summary: "cancel/dismiss the dialog" }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: [ "Use --option for select, --text for input, and --confirm/--decline for confirm.", "Single-question asks accept --text/--option; multi-question asks need --answers.", "Choose exactly one response flag.", ], examples: [ { command: "oppi session respond sess_123 --option unit" }, { command: `oppi session respond sess_123 --dialog ask-1 --answers '{"approach":"unit"}'` }, ], }, { path: ["session", "watch"], title: "Watch sessions", summary: "Stream one compact line per state transition for one or more sessions.", usage: "oppi session watch [--until idle|attention|any-change] [--all] [--interval ] [--timeout ] [--json]", arguments: [{ name: "", summary: "one or more session ids" }], flags: [ { name: "--until", value: "", summary: "exit on idle, attention, or any-change (default idle)", }, { name: "--all", summary: "require every watched session to meet --until (default any)" }, { name: "--interval", value: "", summary: "poll interval such as 2 or 500ms; bare numbers are seconds (default 2s)", }, { name: "--timeout", value: "", summary: "max watch time such as 900, 30s, or 30m; bare numbers are seconds (default 30m)", }, { name: "--json", summary: "emit NDJSON transition/resolution events" }, ], notes: [ "Emits transitions only; the matching transition is the resolution event. any-change also detects event activity without a status change.", "With --all, idle/attention must hold for every session at resolution; exits nonzero on timeout.", ], examples: [ { command: "oppi session watch sess_123 --until idle" }, { command: "oppi session watch sess_1 sess_2 --until attention --json" }, ], }, { path: ["session", "wait"], title: "Wait for a session", summary: "Block until a session is idle or needs attention, then print the terminal state.", usage: "oppi session wait [--for idle|attention|either] [--timeout ] [--json]", arguments: [{ name: "", summary: "session id" }], flags: [ { name: "--for", value: "", summary: "idle, attention, or either (default either)", }, { name: "--timeout", value: "", summary: "max wait such as 900, 30s, or 10m; bare numbers are seconds (default 10m)", }, { name: "--poll", value: "", summary: "poll interval such as 1 or 500ms; bare numbers are seconds (default 1s)", }, { name: "--json", summary: "write the standard JSON envelope" }, ], notes: ["Use watch for multiple sessions or live state transitions."], examples: [{ command: "oppi session wait sess_123 --for idle --json" }], }, { path: ["session", "read"], title: "Read session transcript", summary: "Read transcript-style trace entries for a session.", usage: "oppi session read [--tail ] [--json]", arguments: [{ name: "", summary: "session id" }], flags: [ { name: "--tail", value: "", summary: "return only the last trace entries" }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi session read sess_123 --tail 50 --json" }], }, { path: ["session", "events"], title: "Session events", summary: "Read live catch-up events for an active session.", usage: "oppi session events [--since ] [--json]", arguments: [{ name: "", summary: "session id" }], flags: [ { name: "--since", value: "", summary: "event sequence cursor" }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi session events sess_123 --since 42 --json" }], }, { path: ["session", "trace"], title: "Session trace", summary: "Read raw trace entries for a session.", usage: "oppi session trace [--include ] [--json]", arguments: [{ name: "", summary: "session id" }], flags: [ { name: "--include", value: "", summary: "trace parts such as summary,tools" }, { name: "--json", summary: "write the standard JSON envelope" }, ], examples: [{ command: "oppi session trace sess_123 --include summary,tools --json" }], }, { path: ["session", "stop"], title: "Stop session", summary: "Stop a session through the local API.", usage: "oppi session stop [--json]", arguments: [{ name: "", summary: "session id" }], flags: [{ name: "--json", summary: "write the standard JSON envelope" }], examples: [{ command: "oppi session stop sess_123 --json" }], }, { path: ["session", "search"], title: "Search sessions", summary: "Search indexed session content.", usage: "oppi session search [query] [--workspace |--all] [--since