"""Public CLI for pyro-mcp."""

from __future__ import annotations

import argparse
import json
import shlex
import sys
from pathlib import Path
from textwrap import dedent
from typing import Any

from pyro_mcp import __version__
from pyro_mcp.api import Pyro
from pyro_mcp.contract import PUBLIC_MCP_PROFILES
from pyro_mcp.demo import run_demo
from pyro_mcp.ollama_demo import DEFAULT_OLLAMA_BASE_URL, DEFAULT_OLLAMA_MODEL, run_ollama_tool_demo
from pyro_mcp.runtime import DEFAULT_PLATFORM, doctor_report
from pyro_mcp.vm_environments import DEFAULT_CATALOG_VERSION
from pyro_mcp.vm_manager import (
    DEFAULT_MEM_MIB,
    DEFAULT_SERVICE_LOG_TAIL_LINES,
    DEFAULT_SERVICE_READY_INTERVAL_MS,
    DEFAULT_SERVICE_READY_TIMEOUT_SECONDS,
    DEFAULT_VCPU_COUNT,
    DEFAULT_WORKSPACE_DISK_READ_MAX_BYTES,
    DEFAULT_WORKSPACE_FILE_READ_MAX_BYTES,
    WORKSPACE_GUEST_PATH,
    WORKSPACE_SHELL_SIGNAL_NAMES,
)


def _print_json(payload: dict[str, Any]) -> None:
    print(json.dumps(payload, indent=2, sort_keys=True))


def _print_id_only(value: object) -> None:
    print(str(value), flush=True)


def _write_stream(text: str, *, stream: Any) -> None:
    if text == "":
        return
    stream.write(text)
    stream.flush()


def _print_read_content(text: str, *, content_only: bool) -> None:
    _write_stream(text, stream=sys.stdout)
    if not content_only and text != "" and not text.endswith("\n"):
        _write_stream("\n", stream=sys.stdout)


def _print_run_human(payload: dict[str, Any]) -> None:
    stdout = str(payload.get("stdout", ""))
    stderr = str(payload.get("stderr", ""))
    _write_stream(stdout, stream=sys.stdout)
    _write_stream(stderr, stream=sys.stderr)
    print(
        "[run] "
        f"environment={str(payload.get('environment', 'unknown'))} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))} "
        f"exit_code={int(payload.get('exit_code', 1))} "
        f"duration_ms={int(payload.get('duration_ms', 0))}",
        file=sys.stderr,
        flush=True,
    )


def _print_phase(prefix: str, *, phase: str, **fields: object) -> None:
    details = " ".join(f"{key}={value}" for key, value in fields.items())
    suffix = f" {details}" if details else ""
    print(f"[{prefix}] phase={phase}{suffix}", file=sys.stderr, flush=True)


def _print_env_list_human(payload: dict[str, Any]) -> None:
    print(f"Catalog version: {payload.get('catalog_version', 'unknown')}")
    environments = payload.get("environments")
    if not isinstance(environments, list) or not environments:
        print("No environments found.")
        return
    for entry in environments:
        if not isinstance(entry, dict):
            continue
        status = "installed" if bool(entry.get("installed")) else "not installed"
        print(
            f"{str(entry.get('name', 'unknown'))} [{status}] "
            f"{str(entry.get('description', '')).strip()}".rstrip()
        )


def _print_env_detail_human(payload: dict[str, Any], *, action: str) -> None:
    print(f"{action}: {str(payload.get('name', 'unknown'))}")
    print(f"Version: {str(payload.get('version', 'unknown'))}")
    print(
        f"Distribution: {str(payload.get('distribution', 'unknown'))} "
        f"{str(payload.get('distribution_version', 'unknown'))}"
    )
    print(f"Installed: {'yes' if bool(payload.get('installed')) else 'no'}")
    print(f"Cache dir: {str(payload.get('cache_dir', 'unknown'))}")
    packages = payload.get("default_packages")
    if isinstance(packages, list) and packages:
        print("Default packages: " + ", ".join(str(item) for item in packages))
    description = str(payload.get("description", "")).strip()
    if description != "":
        print(f"Description: {description}")
    if payload.get("installed"):
        print(f"Install dir: {str(payload.get('install_dir', 'unknown'))}")
        install_manifest = payload.get("install_manifest")
        if install_manifest is not None:
            print(f"Install manifest: {str(install_manifest)}")
        kernel_image = payload.get("kernel_image")
        if kernel_image is not None:
            print(f"Kernel image: {str(kernel_image)}")
        rootfs_image = payload.get("rootfs_image")
        if rootfs_image is not None:
            print(f"Rootfs image: {str(rootfs_image)}")
    registry = payload.get("oci_registry")
    repository = payload.get("oci_repository")
    reference = payload.get("oci_reference")
    if isinstance(registry, str) and isinstance(repository, str) and isinstance(reference, str):
        print(f"OCI source: {registry}/{repository}:{reference}")


def _print_prune_human(payload: dict[str, Any]) -> None:
    count = int(payload.get("count", 0))
    print(f"Deleted {count} cached environment entr{'y' if count == 1 else 'ies'}.")
    deleted = payload.get("deleted_environment_dirs")
    if isinstance(deleted, list):
        for entry in deleted:
            print(f"- {entry}")


def _print_doctor_human(payload: dict[str, Any]) -> None:
    issues = payload.get("issues")
    runtime_ok = bool(payload.get("runtime_ok"))
    print(f"Platform: {str(payload.get('platform', 'unknown'))}")
    print(f"Runtime: {'PASS' if runtime_ok else 'FAIL'}")
    kvm = payload.get("kvm")
    if isinstance(kvm, dict):
        print(
            "KVM: "
            f"exists={'yes' if bool(kvm.get('exists')) else 'no'} "
            f"readable={'yes' if bool(kvm.get('readable')) else 'no'} "
            f"writable={'yes' if bool(kvm.get('writable')) else 'no'}"
        )
    runtime = payload.get("runtime")
    if isinstance(runtime, dict):
        print(f"Environment cache: {str(runtime.get('cache_dir', 'unknown'))}")
        capabilities = runtime.get("capabilities")
        if isinstance(capabilities, dict):
            print(
                "Capabilities: "
                f"vm_boot={'yes' if bool(capabilities.get('supports_vm_boot')) else 'no'} "
                f"guest_exec={'yes' if bool(capabilities.get('supports_guest_exec')) else 'no'} "
                "guest_network="
                f"{'yes' if bool(capabilities.get('supports_guest_network')) else 'no'}"
            )
    networking = payload.get("networking")
    if isinstance(networking, dict):
        print(
            "Networking: "
            f"tun={'yes' if bool(networking.get('tun_available')) else 'no'} "
            f"ip_forward={'yes' if bool(networking.get('ip_forward_enabled')) else 'no'}"
        )
    if isinstance(issues, list) and issues:
        print("Issues:")
        for issue in issues:
            print(f"- {issue}")


def _print_workspace_summary_human(payload: dict[str, Any], *, action: str) -> None:
    print(f"{action} ID: {str(payload.get('workspace_id', 'unknown'))}")
    name = payload.get("name")
    if isinstance(name, str) and name != "":
        print(f"Name: {name}")
    labels = payload.get("labels")
    if isinstance(labels, dict) and labels:
        rendered_labels = ", ".join(
            f"{str(key)}={str(value)}" for key, value in sorted(labels.items())
        )
        print(f"Labels: {rendered_labels}")
    print(f"Environment: {str(payload.get('environment', 'unknown'))}")
    print(f"State: {str(payload.get('state', 'unknown'))}")
    print(f"Workspace: {str(payload.get('workspace_path', '/workspace'))}")
    last_activity_at = payload.get("last_activity_at")
    if last_activity_at is not None:
        print(f"Last activity at: {last_activity_at}")
    print(f"Network policy: {str(payload.get('network_policy', 'off'))}")
    workspace_seed = payload.get("workspace_seed")
    if isinstance(workspace_seed, dict):
        mode = str(workspace_seed.get("mode", "empty"))
        seed_path = workspace_seed.get("seed_path")
        if isinstance(seed_path, str) and seed_path != "":
            print(f"Workspace seed: {mode} from {seed_path}")
        else:
            print(f"Workspace seed: {mode}")
    secrets = payload.get("secrets")
    if isinstance(secrets, list) and secrets:
        secret_descriptions = []
        for secret in secrets:
            if not isinstance(secret, dict):
                continue
            secret_descriptions.append(
                f"{str(secret.get('name', 'unknown'))} "
                f"({str(secret.get('source_kind', 'literal'))})"
            )
        if secret_descriptions:
            print("Secrets: " + ", ".join(secret_descriptions))
    print(f"Execution mode: {str(payload.get('execution_mode', 'pending'))}")
    print(
        f"Resources: {int(payload.get('vcpu_count', 0))} vCPU / "
        f"{int(payload.get('mem_mib', 0))} MiB"
    )
    print(f"Command count: {int(payload.get('command_count', 0))}")
    print(f"Reset count: {int(payload.get('reset_count', 0))}")
    last_reset_at = payload.get("last_reset_at")
    if last_reset_at is not None:
        print(f"Last reset at: {last_reset_at}")
    print(
        "Services: "
        f"{int(payload.get('running_service_count', 0))}/"
        f"{int(payload.get('service_count', 0))} running"
    )
    last_command = payload.get("last_command")
    if isinstance(last_command, dict):
        print(
            "Last command: "
            f"{str(last_command.get('command', 'unknown'))} "
            f"(exit_code={int(last_command.get('exit_code', -1))})"
        )


def _print_workspace_list_human(payload: dict[str, Any]) -> None:
    workspaces = payload.get("workspaces")
    if not isinstance(workspaces, list) or not workspaces:
        print("No workspaces.")
        return
    for workspace in workspaces:
        if not isinstance(workspace, dict):
            continue
        rendered_labels = ""
        labels = workspace.get("labels")
        if isinstance(labels, dict) and labels:
            rendered_labels = " labels=" + ",".join(
                f"{str(key)}={str(value)}" for key, value in sorted(labels.items())
            )
        rendered_name = ""
        name = workspace.get("name")
        if isinstance(name, str) and name != "":
            rendered_name = f" name={name!r}"
        print(
            "[workspace] "
            f"workspace_id={str(workspace.get('workspace_id', 'unknown'))}"
            f"{rendered_name} "
            f"state={str(workspace.get('state', 'unknown'))} "
            f"environment={str(workspace.get('environment', 'unknown'))}"
            f"{rendered_labels} "
            f"last_activity_at={workspace.get('last_activity_at')} "
            f"expires_at={workspace.get('expires_at')} "
            f"commands={int(workspace.get('command_count', 0))} "
            f"services={int(workspace.get('running_service_count', 0))}/"
            f"{int(workspace.get('service_count', 0))}"
        )


def _print_workspace_exec_human(payload: dict[str, Any]) -> None:
    stdout = str(payload.get("stdout", ""))
    stderr = str(payload.get("stderr", ""))
    _write_stream(stdout, stream=sys.stdout)
    _write_stream(stderr, stream=sys.stderr)
    print(
        "[workspace-exec] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"sequence={int(payload.get('sequence', 0))} "
        f"cwd={str(payload.get('cwd', WORKSPACE_GUEST_PATH))} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))} "
        f"exit_code={int(payload.get('exit_code', 1))} "
        f"duration_ms={int(payload.get('duration_ms', 0))}",
        file=sys.stderr,
        flush=True,
    )


def _print_workspace_sync_human(payload: dict[str, Any]) -> None:
    workspace_sync = payload.get("workspace_sync")
    if not isinstance(workspace_sync, dict):
        print(f"Synced workspace: {str(payload.get('workspace_id', 'unknown'))}")
        return
    print(
        "[workspace-sync] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"mode={str(workspace_sync.get('mode', 'unknown'))} "
        f"source={str(workspace_sync.get('source_path', 'unknown'))} "
        f"destination={str(workspace_sync.get('destination', WORKSPACE_GUEST_PATH))} "
        f"entry_count={int(workspace_sync.get('entry_count', 0))} "
        f"bytes_written={int(workspace_sync.get('bytes_written', 0))} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))}"
    )


def _print_workspace_export_human(payload: dict[str, Any]) -> None:
    print(
        "[workspace-export] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"workspace_path={str(payload.get('workspace_path', WORKSPACE_GUEST_PATH))} "
        f"output_path={str(payload.get('output_path', 'unknown'))} "
        f"artifact_type={str(payload.get('artifact_type', 'unknown'))} "
        f"entry_count={int(payload.get('entry_count', 0))} "
        f"bytes_written={int(payload.get('bytes_written', 0))} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))}"
    )


def _print_workspace_disk_export_human(payload: dict[str, Any]) -> None:
    print(
        "[workspace-disk-export] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"output_path={str(payload.get('output_path', 'unknown'))} "
        f"disk_format={str(payload.get('disk_format', 'unknown'))} "
        f"bytes_written={int(payload.get('bytes_written', 0))}"
    )


def _print_workspace_disk_list_human(payload: dict[str, Any]) -> None:
    print(
        f"Workspace disk path: {str(payload.get('path', WORKSPACE_GUEST_PATH))} "
        f"(recursive={'yes' if bool(payload.get('recursive')) else 'no'})"
    )
    entries = payload.get("entries")
    if not isinstance(entries, list) or not entries:
        print("No workspace disk entries found.")
        return
    for entry in entries:
        if not isinstance(entry, dict):
            continue
        line = (
            f"{str(entry.get('path', 'unknown'))} "
            f"[{str(entry.get('artifact_type', 'unknown'))}] "
            f"size={int(entry.get('size_bytes', 0))}"
        )
        link_target = entry.get("link_target")
        if isinstance(link_target, str) and link_target != "":
            line += f" -> {link_target}"
        print(line)


def _print_workspace_disk_read_human(
    payload: dict[str, Any], *, content_only: bool = False
) -> None:
    _print_read_content(str(payload.get("content", "")), content_only=content_only)
    if content_only:
        return
    print(
        "[workspace-disk-read] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"path={str(payload.get('path', 'unknown'))} "
        f"size_bytes={int(payload.get('size_bytes', 0))} "
        f"truncated={'yes' if bool(payload.get('truncated', False)) else 'no'}",
        file=sys.stderr,
        flush=True,
    )


def _print_workspace_diff_human(payload: dict[str, Any]) -> None:
    if not bool(payload.get("changed")):
        print("No workspace changes.")
        return
    summary = payload.get("summary")
    if isinstance(summary, dict):
        print(
            "[workspace-diff] "
            f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
            f"total={int(summary.get('total', 0))} "
            f"added={int(summary.get('added', 0))} "
            f"modified={int(summary.get('modified', 0))} "
            f"deleted={int(summary.get('deleted', 0))} "
            f"type_changed={int(summary.get('type_changed', 0))} "
            f"text_patched={int(summary.get('text_patched', 0))} "
            f"non_text={int(summary.get('non_text', 0))}"
        )
    patch = str(payload.get("patch", ""))
    if patch != "":
        print(patch, end="" if patch.endswith("\n") else "\n")


def _print_workspace_file_list_human(payload: dict[str, Any]) -> None:
    print(
        f"Workspace path: {str(payload.get('path', WORKSPACE_GUEST_PATH))} "
        f"(recursive={'yes' if bool(payload.get('recursive')) else 'no'})"
    )
    entries = payload.get("entries")
    if not isinstance(entries, list) or not entries:
        print("No workspace entries found.")
        return
    for entry in entries:
        if not isinstance(entry, dict):
            continue
        line = (
            f"{str(entry.get('path', 'unknown'))} "
            f"[{str(entry.get('artifact_type', 'unknown'))}] "
            f"size={int(entry.get('size_bytes', 0))}"
        )
        link_target = entry.get("link_target")
        if isinstance(link_target, str) and link_target != "":
            line += f" -> {link_target}"
        print(line)


def _print_workspace_file_read_human(
    payload: dict[str, Any], *, content_only: bool = False
) -> None:
    _print_read_content(str(payload.get("content", "")), content_only=content_only)
    if content_only:
        return
    print(
        "[workspace-file-read] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"path={str(payload.get('path', 'unknown'))} "
        f"size_bytes={int(payload.get('size_bytes', 0))} "
        f"truncated={'yes' if bool(payload.get('truncated', False)) else 'no'}",
        file=sys.stderr,
        flush=True,
    )


def _print_workspace_file_write_human(payload: dict[str, Any]) -> None:
    print(
        "[workspace-file-write] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"path={str(payload.get('path', 'unknown'))} "
        f"bytes_written={int(payload.get('bytes_written', 0))} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))}"
    )


def _print_workspace_patch_human(payload: dict[str, Any]) -> None:
    summary = payload.get("summary")
    if isinstance(summary, dict):
        print(
            "[workspace-patch] "
            f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
            f"total={int(summary.get('total', 0))} "
            f"added={int(summary.get('added', 0))} "
            f"modified={int(summary.get('modified', 0))} "
            f"deleted={int(summary.get('deleted', 0))} "
            f"execution_mode={str(payload.get('execution_mode', 'unknown'))}"
        )
        return
    print(
        "[workspace-patch] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))}"
    )


def _print_workspace_logs_human(payload: dict[str, Any]) -> None:
    entries = payload.get("entries")
    if not isinstance(entries, list) or not entries:
        print("No workspace logs found.")
        return
    for entry in entries:
        if not isinstance(entry, dict):
            continue
        print(
            f"#{int(entry.get('sequence', 0))} "
            f"exit_code={int(entry.get('exit_code', -1))} "
            f"duration_ms={int(entry.get('duration_ms', 0))} "
            f"cwd={str(entry.get('cwd', WORKSPACE_GUEST_PATH))}"
        )
        print(f"$ {str(entry.get('command', ''))}")
        stdout = str(entry.get("stdout", ""))
        stderr = str(entry.get("stderr", ""))
        if stdout != "":
            print(stdout, end="" if stdout.endswith("\n") else "\n")
        if stderr != "":
            print(stderr, end="" if stderr.endswith("\n") else "\n", file=sys.stderr)


def _print_workspace_snapshot_human(payload: dict[str, Any], *, prefix: str) -> None:
    snapshot = payload.get("snapshot")
    if not isinstance(snapshot, dict):
        print(f"[{prefix}] workspace_id={str(payload.get('workspace_id', 'unknown'))}")
        return
    print(
        f"[{prefix}] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"snapshot_name={str(snapshot.get('snapshot_name', 'unknown'))} "
        f"kind={str(snapshot.get('kind', 'unknown'))} "
        f"entry_count={int(snapshot.get('entry_count', 0))} "
        f"bytes_written={int(snapshot.get('bytes_written', 0))}"
    )


def _print_workspace_snapshot_list_human(payload: dict[str, Any]) -> None:
    snapshots = payload.get("snapshots")
    if not isinstance(snapshots, list) or not snapshots:
        print("No workspace snapshots found.")
        return
    for snapshot in snapshots:
        if not isinstance(snapshot, dict):
            continue
        print(
            f"{str(snapshot.get('snapshot_name', 'unknown'))} "
            f"[{str(snapshot.get('kind', 'unknown'))}] "
            f"entry_count={int(snapshot.get('entry_count', 0))} "
            f"bytes_written={int(snapshot.get('bytes_written', 0))} "
            f"deletable={'yes' if bool(snapshot.get('deletable', False)) else 'no'}"
        )


def _print_workspace_reset_human(payload: dict[str, Any]) -> None:
    _print_workspace_summary_human(payload, action="Reset workspace")
    workspace_reset = payload.get("workspace_reset")
    if isinstance(workspace_reset, dict):
        print(
            "Reset source: "
            f"{str(workspace_reset.get('snapshot_name', 'unknown'))} "
            f"({str(workspace_reset.get('kind', 'unknown'))})"
        )
        print(
            "Reset restore: "
            f"destination={str(workspace_reset.get('destination', WORKSPACE_GUEST_PATH))} "
            f"entry_count={int(workspace_reset.get('entry_count', 0))} "
            f"bytes_written={int(workspace_reset.get('bytes_written', 0))}"
        )


def _print_workspace_shell_summary_human(payload: dict[str, Any], *, prefix: str) -> None:
    print(
        f"[{prefix}] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"shell_id={str(payload.get('shell_id', 'unknown'))} "
        f"state={str(payload.get('state', 'unknown'))} "
        f"cwd={str(payload.get('cwd', WORKSPACE_GUEST_PATH))} "
        f"cols={int(payload.get('cols', 0))} "
        f"rows={int(payload.get('rows', 0))} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))}",
        file=sys.stderr,
        flush=True,
    )


def _print_workspace_shell_read_human(payload: dict[str, Any]) -> None:
    _write_stream(str(payload.get("output", "")), stream=sys.stdout)
    print(
        "[workspace-shell-read] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"shell_id={str(payload.get('shell_id', 'unknown'))} "
        f"state={str(payload.get('state', 'unknown'))} "
        f"cursor={int(payload.get('cursor', 0))} "
        f"next_cursor={int(payload.get('next_cursor', 0))} "
        f"truncated={bool(payload.get('truncated', False))} "
        f"plain={bool(payload.get('plain', False))} "
        f"wait_for_idle_ms={payload.get('wait_for_idle_ms')} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))}",
        file=sys.stderr,
        flush=True,
    )


def _print_workspace_service_summary_human(payload: dict[str, Any], *, prefix: str) -> None:
    published_ports = payload.get("published_ports")
    published_text = ""
    if isinstance(published_ports, list) and published_ports:
        parts = []
        for item in published_ports:
            if not isinstance(item, dict):
                continue
            parts.append(
                f"{str(item.get('host', '127.0.0.1'))}:{int(item.get('host_port', 0))}"
                f"->{int(item.get('guest_port', 0))}/{str(item.get('protocol', 'tcp'))}"
            )
        if parts:
            published_text = " published_ports=" + ",".join(parts)
    print(
        f"[{prefix}] "
        f"workspace_id={str(payload.get('workspace_id', 'unknown'))} "
        f"service_name={str(payload.get('service_name', 'unknown'))} "
        f"state={str(payload.get('state', 'unknown'))} "
        f"cwd={str(payload.get('cwd', WORKSPACE_GUEST_PATH))} "
        f"execution_mode={str(payload.get('execution_mode', 'unknown'))}"
        f"{published_text}",
        file=sys.stderr,
        flush=True,
    )


def _print_workspace_service_list_human(payload: dict[str, Any]) -> None:
    services = payload.get("services")
    if not isinstance(services, list) or not services:
        print("No workspace services found.")
        return
    for service in services:
        if not isinstance(service, dict):
            continue
        print(
            f"{str(service.get('service_name', 'unknown'))} "
            f"[{str(service.get('state', 'unknown'))}] "
            f"cwd={str(service.get('cwd', WORKSPACE_GUEST_PATH))}"
            + (
                " published="
                + ",".join(
                    f"{str(item.get('host', '127.0.0.1'))}:{int(item.get('host_port', 0))}"
                    f"->{int(item.get('guest_port', 0))}/{str(item.get('protocol', 'tcp'))}"
                    for item in service.get("published_ports", [])
                    if isinstance(item, dict)
                )
                if isinstance(service.get("published_ports"), list)
                and service.get("published_ports")
                else ""
            )
        )


def _print_workspace_service_logs_human(payload: dict[str, Any]) -> None:
    stdout = str(payload.get("stdout", ""))
    stderr = str(payload.get("stderr", ""))
    _write_stream(stdout, stream=sys.stdout)
    _write_stream(stderr, stream=sys.stderr)
    _print_workspace_service_summary_human(payload, prefix="workspace-service-logs")


class _HelpFormatter(
    argparse.RawDescriptionHelpFormatter,
    argparse.ArgumentDefaultsHelpFormatter,
):
    """Help formatter with examples and default values."""

    def _get_help_string(self, action: argparse.Action) -> str:
        if action.default is None and action.help is not None:
            return action.help
        help_string = super()._get_help_string(action)
        if help_string is None:
            return ""
        return help_string


def _build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        description=(
            "Run stable one-shot and persistent workspace workflows on supported "
            "Linux x86_64 KVM hosts."
        ),
        epilog=dedent(
            """
            Suggested first run:
              pyro doctor
              pyro env list
              pyro env pull debian:12
              pyro run debian:12 -- git --version

            Continue into the stable workspace path after that:
              pyro workspace create debian:12 --seed-path ./repo --id-only
              pyro workspace sync push WORKSPACE_ID ./changes
              pyro workspace exec WORKSPACE_ID -- cat note.txt
              pyro workspace diff WORKSPACE_ID
              pyro workspace snapshot create WORKSPACE_ID checkpoint
              pyro workspace reset WORKSPACE_ID --snapshot checkpoint
              pyro workspace shell open WORKSPACE_ID --id-only
              pyro workspace service start WORKSPACE_ID app --ready-file .ready -- \
                sh -lc 'touch .ready && while true; do sleep 60; done'
              pyro workspace export WORKSPACE_ID note.txt --output ./note.txt

            Use `pyro mcp serve` only after the CLI validation path works.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
    subparsers = parser.add_subparsers(dest="command", required=True, metavar="COMMAND")

    env_parser = subparsers.add_parser(
        "env",
        help="Inspect and manage curated environments.",
        description="Inspect, install, and prune curated Linux environments.",
        epilog=dedent(
            """
            Examples:
              pyro env list
              pyro env pull debian:12
              pyro env inspect debian:12
            """
        ),
        formatter_class=_HelpFormatter,
    )
    env_subparsers = env_parser.add_subparsers(dest="env_command", required=True, metavar="ENV")
    list_parser = env_subparsers.add_parser(
        "list",
        help="List official environments.",
        description="List the shipped environment catalog and show local install status.",
        epilog="Example:\n  pyro env list",
        formatter_class=_HelpFormatter,
    )
    list_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    pull_parser = env_subparsers.add_parser(
        "pull",
        help="Install an environment into the local cache.",
        description=(
            "Download and install one official environment into the local cache from "
            "the configured OCI registry."
        ),
        epilog=dedent(
            """
            Example:
              pyro env pull debian:12

            The first pull downloads from public Docker Hub, requires outbound HTTPS,
            and needs local cache space for the guest image.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    pull_parser.add_argument(
        "environment",
        metavar="ENVIRONMENT",
        help="Environment name from `pyro env list`, for example `debian:12`.",
    )
    pull_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    inspect_parser = env_subparsers.add_parser(
        "inspect",
        help="Inspect one environment.",
        description="Show catalog and local cache details for one environment.",
        epilog="Example:\n  pyro env inspect debian:12",
        formatter_class=_HelpFormatter,
    )
    inspect_parser.add_argument(
        "environment",
        metavar="ENVIRONMENT",
        help="Environment name from `pyro env list`, for example `debian:12`.",
    )
    inspect_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    prune_parser = env_subparsers.add_parser(
        "prune",
        help="Delete stale cached environments.",
        description="Remove cached environment installs that are no longer referenced.",
        epilog="Example:\n  pyro env prune",
        formatter_class=_HelpFormatter,
    )
    prune_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )

    mcp_parser = subparsers.add_parser(
        "mcp",
        help="Run the MCP server.",
        description=(
            "Run the MCP server after you have already validated the host and "
            "guest execution with `pyro doctor` and `pyro run`. Start most "
            "chat hosts with `workspace-core`."
        ),
        epilog=dedent(
            """
            Examples:
              pyro mcp serve --profile workspace-core
              pyro mcp serve --profile vm-run
              pyro mcp serve --profile workspace-full
            """
        ),
        formatter_class=_HelpFormatter,
    )
    mcp_subparsers = mcp_parser.add_subparsers(dest="mcp_command", required=True, metavar="MCP")
    mcp_serve_parser = mcp_subparsers.add_parser(
        "serve",
        help="Run the MCP server over stdio.",
        description=(
            "Expose pyro tools over stdio for an MCP client. "
            "`workspace-core` is the recommended first profile for most chat hosts."
        ),
        epilog=dedent(
            """
            Recommended first start:
              pyro mcp serve --profile workspace-core

            Profiles:
              workspace-core: recommended default for normal persistent chat editing
              vm-run: smallest one-shot-only surface
              workspace-full: advanced 3.x compatibility surface for shells, services,
                snapshots, secrets, network policy, and disk tools

            `workspace-full` remains the default in 3.x for compatibility, but most new
            chat hosts should start with `workspace-core`.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    mcp_serve_parser.add_argument(
        "--profile",
        choices=PUBLIC_MCP_PROFILES,
        default="workspace-full",
        help=(
            "Expose only one model-facing tool profile. `workspace-core` is the "
            "recommended first profile for most chat hosts; `workspace-full` "
            "preserves the current full MCP surface for 3.x compatibility."
        ),
    )

    run_parser = subparsers.add_parser(
        "run",
        help="Run one command inside an ephemeral VM.",
        description="Run one non-interactive command in a temporary Firecracker microVM.",
        epilog=dedent(
            """
            Examples:
              pyro run debian:12 -- git --version
              pyro run debian:12 --network -- python3 -c "import urllib.request as u; print(u.urlopen('https://example.com').status)"

            The guest command output and the [run] summary are written to different
            streams, so they may appear in either order. Use --json for a deterministic
            structured result.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    run_parser.add_argument(
        "environment",
        metavar="ENVIRONMENT",
        help="Curated environment to boot, for example `debian:12`.",
    )
    run_parser.add_argument(
        "--vcpu-count",
        type=int,
        default=DEFAULT_VCPU_COUNT,
        help="Number of virtual CPUs to allocate to the guest.",
    )
    run_parser.add_argument(
        "--mem-mib",
        type=int,
        default=DEFAULT_MEM_MIB,
        help="Guest memory allocation in MiB.",
    )
    run_parser.add_argument(
        "--timeout-seconds",
        type=int,
        default=30,
        help="Maximum time allowed for the guest command.",
    )
    run_parser.add_argument(
        "--ttl-seconds",
        type=int,
        default=600,
        help="Time-to-live for temporary VM artifacts before cleanup.",
    )
    run_parser.add_argument(
        "--network",
        action="store_true",
        help="Enable outbound guest networking. Requires TAP/NAT privileges on the host.",
    )
    run_parser.add_argument(
        "--allow-host-compat",
        action="store_true",
        help=(
            "Opt into host-side compatibility execution if guest boot or guest exec "
            "is unavailable."
        ),
    )
    run_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    run_parser.add_argument(
        "command_args",
        nargs="*",
        metavar="ARG",
        help=(
            "Command and arguments to run inside the guest. Prefix them with `--`, "
            "for example `pyro run debian:12 -- git --version`."
        ),
    )

    workspace_parser = subparsers.add_parser(
        "workspace",
        help="Manage persistent workspaces.",
        description=(
            "Use the stable workspace contract when you need one sandbox to stay alive "
            "across repeated exec, shell, service, diff, export, snapshot, and reset calls."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace create debian:12 --seed-path ./repo --id-only
              pyro workspace create debian:12 --name repro-fix --label issue=123
              pyro workspace list
              pyro workspace update WORKSPACE_ID --name retry-run --label owner=codex
              pyro workspace sync push WORKSPACE_ID ./repo --dest src
              pyro workspace file read WORKSPACE_ID src/app.py
              pyro workspace patch apply WORKSPACE_ID --patch-file fix.patch
              pyro workspace exec WORKSPACE_ID -- sh -lc 'printf "hello\\n" > note.txt'
              pyro workspace stop WORKSPACE_ID
              pyro workspace disk list WORKSPACE_ID
              pyro workspace disk export WORKSPACE_ID --output ./workspace.ext4
              pyro workspace start WORKSPACE_ID
              pyro workspace snapshot create WORKSPACE_ID checkpoint
              pyro workspace reset WORKSPACE_ID --snapshot checkpoint
              pyro workspace diff WORKSPACE_ID
              pyro workspace export WORKSPACE_ID src/note.txt --output ./note.txt
              pyro workspace shell open WORKSPACE_ID --id-only
              pyro workspace service start WORKSPACE_ID app --ready-file .ready -- \
                sh -lc 'touch .ready && while true; do sleep 60; done'
              pyro workspace logs WORKSPACE_ID

            `pyro run` remains the fastest one-shot proof. `pyro workspace ...` is the
            stable path when an agent needs to inhabit one sandbox over time.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_subparsers = workspace_parser.add_subparsers(
        dest="workspace_command",
        required=True,
        metavar="WORKSPACE",
    )
    workspace_create_parser = workspace_subparsers.add_parser(
        "create",
        help="Create and start a persistent workspace.",
        description=(
            "Create and start a stable persistent workspace that stays alive across repeated "
            "exec, shell, service, diff, export, snapshot, and reset calls."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace create debian:12 --id-only
              pyro workspace create debian:12 --seed-path ./repo --id-only
              pyro workspace create debian:12 --name repro-fix --label issue=123
              pyro workspace create debian:12 --network-policy egress
              pyro workspace create debian:12 --secret API_TOKEN=expected
              pyro workspace list
              pyro workspace update WORKSPACE_ID --label owner=codex
              pyro workspace sync push WORKSPACE_ID ./changes
              pyro workspace snapshot create WORKSPACE_ID checkpoint
              pyro workspace reset WORKSPACE_ID --snapshot checkpoint
              pyro workspace diff WORKSPACE_ID
              pyro workspace service start WORKSPACE_ID app --ready-file .ready -- \
                sh -lc 'touch .ready && while true; do sleep 60; done'
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_create_parser.add_argument(
        "environment",
        metavar="ENVIRONMENT",
        help="Curated environment to boot, for example `debian:12`.",
    )
    workspace_create_parser.add_argument(
        "--vcpu-count",
        type=int,
        default=DEFAULT_VCPU_COUNT,
        help="Number of virtual CPUs to allocate to the guest.",
    )
    workspace_create_parser.add_argument(
        "--mem-mib",
        type=int,
        default=DEFAULT_MEM_MIB,
        help="Guest memory allocation in MiB.",
    )
    workspace_create_parser.add_argument(
        "--ttl-seconds",
        type=int,
        default=600,
        help="Time-to-live for the workspace before automatic cleanup.",
    )
    workspace_create_parser.add_argument(
        "--network-policy",
        choices=("off", "egress", "egress+published-ports"),
        default="off",
        help="Workspace network policy.",
    )
    workspace_create_parser.add_argument(
        "--allow-host-compat",
        action="store_true",
        help=(
            "Opt into host-side compatibility execution if guest boot or guest exec "
            "is unavailable."
        ),
    )
    workspace_create_parser.add_argument(
        "--seed-path",
        help=(
            "Optional host directory or .tar/.tar.gz/.tgz archive to seed into `/workspace` "
            "before the workspace is returned."
        ),
    )
    workspace_create_parser.add_argument(
        "--name",
        help="Optional human-friendly workspace name.",
    )
    workspace_create_parser.add_argument(
        "--label",
        action="append",
        default=[],
        metavar="KEY=VALUE",
        help="Attach one discovery label to the workspace. May be repeated.",
    )
    workspace_create_parser.add_argument(
        "--secret",
        action="append",
        default=[],
        metavar="NAME=VALUE",
        help="Persist one literal UTF-8 secret for this workspace.",
    )
    workspace_create_parser.add_argument(
        "--secret-file",
        action="append",
        default=[],
        metavar="NAME=PATH",
        help="Persist one UTF-8 secret copied from a host file at create time.",
    )
    workspace_create_output_group = workspace_create_parser.add_mutually_exclusive_group()
    workspace_create_output_group.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_create_output_group.add_argument(
        "--id-only",
        action="store_true",
        help="Print only the new workspace identifier.",
    )
    workspace_exec_parser = workspace_subparsers.add_parser(
        "exec",
        help="Run one command inside an existing workspace.",
        description=(
            "Run one non-interactive command in the persistent `/workspace` "
            "for a workspace."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace exec WORKSPACE_ID -- cat note.txt
              pyro workspace exec WORKSPACE_ID --secret-env API_TOKEN -- \
                sh -lc 'test \"$API_TOKEN\" = \"expected\"'
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_exec_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_exec_parser.add_argument(
        "--timeout-seconds",
        type=int,
        default=30,
        help="Maximum time allowed for the workspace command.",
    )
    workspace_exec_parser.add_argument(
        "--secret-env",
        action="append",
        default=[],
        metavar="SECRET[=ENV_VAR]",
        help="Expose one persisted workspace secret as an environment variable for this exec.",
    )
    workspace_exec_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_exec_parser.add_argument(
        "command_args",
        nargs="*",
        metavar="ARG",
        help=(
            "Command and arguments to run inside the workspace. Prefix them with `--`, "
            "for example `pyro workspace exec WORKSPACE_ID -- cat note.txt`."
        ),
    )
    workspace_sync_parser = workspace_subparsers.add_parser(
        "sync",
        help="Push host content into a started workspace.",
        description=(
            "Push host directory or archive content into `/workspace` for an existing "
            "started workspace."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace sync push WORKSPACE_ID ./repo
              pyro workspace sync push WORKSPACE_ID ./patches --dest src

            Sync is non-atomic. If a sync fails partway through, prefer reset over repair with
            `pyro workspace reset WORKSPACE_ID`.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_sync_subparsers = workspace_sync_parser.add_subparsers(
        dest="workspace_sync_command",
        required=True,
        metavar="SYNC",
    )
    workspace_sync_push_parser = workspace_sync_subparsers.add_parser(
        "push",
        help="Push one host directory or archive into a started workspace.",
        description="Import host content into `/workspace` or a subdirectory of it.",
        epilog="Example:\n  pyro workspace sync push WORKSPACE_ID ./repo --dest src",
        formatter_class=_HelpFormatter,
    )
    workspace_sync_push_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_sync_push_parser.add_argument(
        "source_path",
        metavar="SOURCE_PATH",
        help="Host directory or .tar/.tar.gz/.tgz archive to push into the workspace.",
    )
    workspace_sync_push_parser.add_argument(
        "--dest",
        default=WORKSPACE_GUEST_PATH,
        help="Workspace destination path. Relative values resolve inside `/workspace`.",
    )
    workspace_sync_push_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_export_parser = workspace_subparsers.add_parser(
        "export",
        help="Export one workspace path to the host.",
        description="Export one file or directory from `/workspace` to an explicit host path.",
        epilog="Example:\n  pyro workspace export WORKSPACE_ID src/note.txt --output ./note.txt",
        formatter_class=_HelpFormatter,
    )
    workspace_export_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_export_parser.add_argument(
        "path",
        metavar="PATH",
        help="Workspace path to export. Relative values resolve inside `/workspace`.",
    )
    workspace_export_parser.add_argument(
        "--output",
        required=True,
        help="Exact host path to create for the exported file or directory.",
    )
    workspace_export_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_diff_parser = workspace_subparsers.add_parser(
        "diff",
        help="Diff `/workspace` against the create-time baseline.",
        description="Compare the current `/workspace` tree to the immutable workspace baseline.",
        epilog=dedent(
            """
            Example:
              pyro workspace diff WORKSPACE_ID

            Use `workspace export` to copy a changed file or directory back to the host.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_diff_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_diff_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_file_parser = workspace_subparsers.add_parser(
        "file",
        help="List, read, and write workspace files without shell quoting.",
        description=(
            "Use workspace file operations for model-native tree inspection and text edits "
            "inside one started workspace."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace file list WORKSPACE_ID
              pyro workspace file read WORKSPACE_ID src/app.py
              pyro workspace file write WORKSPACE_ID src/app.py --text-file ./app.py
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_file_subparsers = workspace_file_parser.add_subparsers(
        dest="workspace_file_command",
        required=True,
        metavar="FILE",
    )
    workspace_file_list_parser = workspace_file_subparsers.add_parser(
        "list",
        help="List metadata for one live workspace path.",
        description="List files, directories, and symlinks under one started workspace path.",
        epilog="Example:\n  pyro workspace file list WORKSPACE_ID src --recursive",
        formatter_class=_HelpFormatter,
    )
    workspace_file_list_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_file_list_parser.add_argument(
        "path",
        nargs="?",
        default=WORKSPACE_GUEST_PATH,
        metavar="PATH",
        help="Workspace path to inspect. Relative values resolve inside `/workspace`.",
    )
    workspace_file_list_parser.add_argument(
        "--recursive",
        action="store_true",
        help="Walk directories recursively.",
    )
    workspace_file_list_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_file_read_parser = workspace_file_subparsers.add_parser(
        "read",
        help="Read one regular text file from a started workspace.",
        description=(
            "Read one regular text file under `/workspace`. This is bounded and does not "
            "follow symlinks."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace file read WORKSPACE_ID src/app.py
              pyro workspace file read WORKSPACE_ID src/app.py --content-only
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_file_read_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_file_read_parser.add_argument("path", metavar="PATH")
    workspace_file_read_parser.add_argument(
        "--max-bytes",
        type=int,
        default=DEFAULT_WORKSPACE_FILE_READ_MAX_BYTES,
        help="Maximum number of bytes to return in the decoded text response.",
    )
    workspace_file_read_output_group = workspace_file_read_parser.add_mutually_exclusive_group()
    workspace_file_read_output_group.add_argument(
        "--content-only",
        action="store_true",
        help="Print only the decoded file content with no human summary footer.",
    )
    workspace_file_read_output_group.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_file_write_parser = workspace_file_subparsers.add_parser(
        "write",
        help="Create or replace one regular text file in a started workspace.",
        description=(
            "Write one UTF-8 text file under `/workspace`. Missing parent directories are "
            "created automatically."
        ),
        epilog=(
            "Example:\n"
            "  pyro workspace file write WORKSPACE_ID src/app.py --text-file ./app.py"
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_file_write_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_file_write_parser.add_argument("path", metavar="PATH")
    workspace_file_write_input_group = workspace_file_write_parser.add_mutually_exclusive_group(
        required=True
    )
    workspace_file_write_input_group.add_argument(
        "--text",
        help="UTF-8 text content to write into the target file.",
    )
    workspace_file_write_input_group.add_argument(
        "--text-file",
        metavar="PATH",
        help="Read UTF-8 text content from a host file.",
    )
    workspace_file_write_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_patch_parser = workspace_subparsers.add_parser(
        "patch",
        help="Apply unified text patches inside a started workspace.",
        description=(
            "Apply add/modify/delete unified text patches under `/workspace` without shell "
            "editing tricks."
        ),
        epilog=dedent(
            """
            Example:
              pyro workspace patch apply WORKSPACE_ID --patch-file fix.patch

            Patch application is preflighted but not fully transactional. If an apply fails
            partway through, prefer `pyro workspace reset WORKSPACE_ID`.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_patch_subparsers = workspace_patch_parser.add_subparsers(
        dest="workspace_patch_command",
        required=True,
        metavar="PATCH",
    )
    workspace_patch_apply_parser = workspace_patch_subparsers.add_parser(
        "apply",
        help="Apply one unified text patch to a started workspace.",
        description=(
            "Apply one unified text patch for add, modify, and delete operations under "
            "`/workspace`."
        ),
        epilog="Example:\n  pyro workspace patch apply WORKSPACE_ID --patch-file fix.patch",
        formatter_class=_HelpFormatter,
    )
    workspace_patch_apply_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_patch_input_group = workspace_patch_apply_parser.add_mutually_exclusive_group(
        required=True
    )
    workspace_patch_input_group.add_argument(
        "--patch",
        help="Unified text patch to apply under `/workspace`.",
    )
    workspace_patch_input_group.add_argument(
        "--patch-file",
        metavar="PATH",
        help="Read a unified text patch from a UTF-8 host file.",
    )
    workspace_patch_apply_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_snapshot_parser = workspace_subparsers.add_parser(
        "snapshot",
        help="Create, list, and delete workspace snapshots.",
        description=(
            "Manage explicit named snapshots in addition to the implicit create-time baseline."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace snapshot create WORKSPACE_ID checkpoint
              pyro workspace snapshot list WORKSPACE_ID
              pyro workspace snapshot delete WORKSPACE_ID checkpoint

            Use `workspace reset` to restore `/workspace` from `baseline` or one named snapshot.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_snapshot_subparsers = workspace_snapshot_parser.add_subparsers(
        dest="workspace_snapshot_command",
        required=True,
        metavar="SNAPSHOT",
    )
    workspace_snapshot_create_parser = workspace_snapshot_subparsers.add_parser(
        "create",
        help="Create one named snapshot from the current workspace.",
        description="Capture the current `/workspace` tree as one named snapshot.",
        epilog="Example:\n  pyro workspace snapshot create WORKSPACE_ID checkpoint",
        formatter_class=_HelpFormatter,
    )
    workspace_snapshot_create_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_snapshot_create_parser.add_argument("snapshot_name", metavar="SNAPSHOT_NAME")
    workspace_snapshot_create_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_snapshot_list_parser = workspace_snapshot_subparsers.add_parser(
        "list",
        help="List the baseline plus named snapshots.",
        description="List the implicit baseline snapshot plus any named snapshots for a workspace.",
        epilog="Example:\n  pyro workspace snapshot list WORKSPACE_ID",
        formatter_class=_HelpFormatter,
    )
    workspace_snapshot_list_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_snapshot_list_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_snapshot_delete_parser = workspace_snapshot_subparsers.add_parser(
        "delete",
        help="Delete one named snapshot.",
        description="Delete one named snapshot while leaving the implicit baseline intact.",
        epilog="Example:\n  pyro workspace snapshot delete WORKSPACE_ID checkpoint",
        formatter_class=_HelpFormatter,
    )
    workspace_snapshot_delete_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_snapshot_delete_parser.add_argument("snapshot_name", metavar="SNAPSHOT_NAME")
    workspace_snapshot_delete_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_reset_parser = workspace_subparsers.add_parser(
        "reset",
        help="Recreate a workspace from baseline or one named snapshot.",
        description=(
            "Recreate the full sandbox and restore `/workspace` from the baseline "
            "or one named snapshot."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace reset WORKSPACE_ID
              pyro workspace reset WORKSPACE_ID --snapshot checkpoint

            Prefer reset over repair: reset clears command history, shells, and services so the
            workspace comes back clean from `baseline` or one named snapshot.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_reset_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_reset_parser.add_argument(
        "--snapshot",
        default="baseline",
        help="Snapshot name to restore. Defaults to the implicit `baseline` snapshot.",
    )
    workspace_reset_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_stop_parser = workspace_subparsers.add_parser(
        "stop",
        help="Stop one workspace without resetting it.",
        description=(
            "Stop the backing sandbox, close shells, stop services, and preserve the "
            "workspace filesystem, history, and snapshots."
        ),
        epilog="Example:\n  pyro workspace stop WORKSPACE_ID",
        formatter_class=_HelpFormatter,
    )
    workspace_stop_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_stop_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_start_parser = workspace_subparsers.add_parser(
        "start",
        help="Start one stopped workspace without resetting it.",
        description=(
            "Start a previously stopped workspace from its preserved rootfs and "
            "workspace state."
        ),
        epilog="Example:\n  pyro workspace start WORKSPACE_ID",
        formatter_class=_HelpFormatter,
    )
    workspace_start_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_start_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_disk_parser = workspace_subparsers.add_parser(
        "disk",
        help="Inspect or export a stopped workspace disk.",
        description=(
            "Use secondary stopped-workspace disk tools for raw ext4 export and offline "
            "inspection without booting the guest."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace stop WORKSPACE_ID
              pyro workspace disk list WORKSPACE_ID
              pyro workspace disk read WORKSPACE_ID note.txt
              pyro workspace disk export WORKSPACE_ID --output ./workspace.ext4

            Disk tools are secondary to `workspace export` and require a stopped, guest-backed
            workspace.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_disk_subparsers = workspace_disk_parser.add_subparsers(
        dest="workspace_disk_command",
        required=True,
        metavar="DISK",
    )
    workspace_disk_export_parser = workspace_disk_subparsers.add_parser(
        "export",
        help="Export the raw stopped workspace rootfs image.",
        description="Copy the raw stopped workspace rootfs ext4 image to an explicit host path.",
        epilog="Example:\n  pyro workspace disk export WORKSPACE_ID --output ./workspace.ext4",
        formatter_class=_HelpFormatter,
    )
    workspace_disk_export_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_disk_export_parser.add_argument(
        "--output",
        required=True,
        help="Exact host path to create for the exported raw ext4 image.",
    )
    workspace_disk_export_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_disk_list_parser = workspace_disk_subparsers.add_parser(
        "list",
        help="List files from a stopped workspace rootfs path.",
        description=(
            "Inspect one stopped workspace rootfs path without booting the guest. Relative "
            "paths resolve inside `/workspace`; absolute paths inspect any guest path."
        ),
        epilog="Example:\n  pyro workspace disk list WORKSPACE_ID src --recursive",
        formatter_class=_HelpFormatter,
    )
    workspace_disk_list_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_disk_list_parser.add_argument(
        "path",
        nargs="?",
        default=WORKSPACE_GUEST_PATH,
        metavar="PATH",
        help="Guest path to inspect. Defaults to `/workspace`.",
    )
    workspace_disk_list_parser.add_argument(
        "--recursive",
        action="store_true",
        help="Recurse into nested directories.",
    )
    workspace_disk_list_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_disk_read_parser = workspace_disk_subparsers.add_parser(
        "read",
        help="Read one regular file from a stopped workspace rootfs.",
        description=(
            "Read one regular file from a stopped workspace rootfs without booting the guest. "
            "Relative paths resolve inside `/workspace`; absolute paths inspect any guest path."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace disk read WORKSPACE_ID note.txt --max-bytes 4096
              pyro workspace disk read WORKSPACE_ID note.txt --content-only
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_disk_read_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_disk_read_parser.add_argument("path", metavar="PATH")
    workspace_disk_read_parser.add_argument(
        "--max-bytes",
        type=int,
        default=DEFAULT_WORKSPACE_DISK_READ_MAX_BYTES,
        help="Maximum number of decoded UTF-8 bytes to return.",
    )
    workspace_disk_read_output_group = workspace_disk_read_parser.add_mutually_exclusive_group()
    workspace_disk_read_output_group.add_argument(
        "--content-only",
        action="store_true",
        help="Print only the decoded file content with no human summary footer.",
    )
    workspace_disk_read_output_group.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_shell_parser = workspace_subparsers.add_parser(
        "shell",
        help="Open and manage persistent interactive shells.",
        description=(
            "Open one or more persistent interactive PTY shell sessions inside a started "
            "workspace."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace shell open WORKSPACE_ID --id-only
              pyro workspace shell write WORKSPACE_ID SHELL_ID --input 'pwd'
              pyro workspace shell read WORKSPACE_ID SHELL_ID --plain --wait-for-idle-ms 300
              pyro workspace shell signal WORKSPACE_ID SHELL_ID --signal INT
              pyro workspace shell close WORKSPACE_ID SHELL_ID

            Use `workspace exec` for one-shot commands. Use `workspace shell` when you need
            an interactive process that keeps its state between calls.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_shell_subparsers = workspace_shell_parser.add_subparsers(
        dest="workspace_shell_command",
        required=True,
        metavar="SHELL",
    )
    workspace_shell_open_parser = workspace_shell_subparsers.add_parser(
        "open",
        help="Open a persistent interactive shell.",
        description="Open a new PTY shell inside a started workspace.",
        epilog="Example:\n  pyro workspace shell open WORKSPACE_ID --cwd src --id-only",
        formatter_class=_HelpFormatter,
    )
    workspace_shell_open_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_shell_open_parser.add_argument(
        "--cwd",
        default=WORKSPACE_GUEST_PATH,
        help="Shell working directory. Relative values resolve inside `/workspace`.",
    )
    workspace_shell_open_parser.add_argument(
        "--cols",
        type=int,
        default=120,
        help="Shell terminal width in columns.",
    )
    workspace_shell_open_parser.add_argument(
        "--rows",
        type=int,
        default=30,
        help="Shell terminal height in rows.",
    )
    workspace_shell_open_parser.add_argument(
        "--secret-env",
        action="append",
        default=[],
        metavar="SECRET[=ENV_VAR]",
        help="Expose one persisted workspace secret as an environment variable in the shell.",
    )
    workspace_shell_open_output_group = workspace_shell_open_parser.add_mutually_exclusive_group()
    workspace_shell_open_output_group.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_shell_open_output_group.add_argument(
        "--id-only",
        action="store_true",
        help="Print only the new shell identifier.",
    )
    workspace_shell_read_parser = workspace_shell_subparsers.add_parser(
        "read",
        help="Read merged PTY output from a shell.",
        description="Read merged text output from a persistent workspace shell.",
        epilog=dedent(
            """
            Example:
              pyro workspace shell read WORKSPACE_ID SHELL_ID --plain --wait-for-idle-ms 300

            Shell output is written to stdout. The read summary is written to stderr.
            Use --plain for chat-friendly output and --json for a deterministic structured response.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_shell_read_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_shell_read_parser.add_argument(
        "shell_id",
        metavar="SHELL_ID",
        help="Persistent shell identifier returned by `workspace shell open`.",
    )
    workspace_shell_read_parser.add_argument(
        "--cursor",
        type=int,
        default=0,
        help="Character offset into the merged shell output buffer.",
    )
    workspace_shell_read_parser.add_argument(
        "--max-chars",
        type=int,
        default=65536,
        help="Maximum number of characters to return from the current cursor position.",
    )
    workspace_shell_read_parser.add_argument(
        "--plain",
        action="store_true",
        help="Strip terminal control sequences and normalize shell output for chat consumption.",
    )
    workspace_shell_read_parser.add_argument(
        "--wait-for-idle-ms",
        type=int,
        default=None,
        help="Wait for this many milliseconds of shell-idle time before returning output.",
    )
    workspace_shell_read_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_shell_write_parser = workspace_shell_subparsers.add_parser(
        "write",
        help="Write text input into a shell.",
        description="Write text input into a persistent workspace shell.",
        epilog="Example:\n  pyro workspace shell write WORKSPACE_ID SHELL_ID --input 'pwd'",
        formatter_class=_HelpFormatter,
    )
    workspace_shell_write_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_shell_write_parser.add_argument(
        "shell_id",
        metavar="SHELL_ID",
        help="Persistent shell identifier returned by `workspace shell open`.",
    )
    workspace_shell_write_parser.add_argument(
        "--input",
        required=True,
        help="Text to send to the shell.",
    )
    workspace_shell_write_parser.add_argument(
        "--no-newline",
        action="store_true",
        help="Do not append a trailing newline after the provided input.",
    )
    workspace_shell_write_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_shell_signal_parser = workspace_shell_subparsers.add_parser(
        "signal",
        help="Send a signal to a shell process group.",
        description="Send a control signal to a persistent workspace shell.",
        epilog="Example:\n  pyro workspace shell signal WORKSPACE_ID SHELL_ID --signal INT",
        formatter_class=_HelpFormatter,
    )
    workspace_shell_signal_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_shell_signal_parser.add_argument(
        "shell_id",
        metavar="SHELL_ID",
        help="Persistent shell identifier returned by `workspace shell open`.",
    )
    workspace_shell_signal_parser.add_argument(
        "--signal",
        default="INT",
        choices=WORKSPACE_SHELL_SIGNAL_NAMES,
        help="Signal name to send to the shell process group.",
    )
    workspace_shell_signal_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_shell_close_parser = workspace_shell_subparsers.add_parser(
        "close",
        help="Close a persistent shell.",
        description="Close a persistent workspace shell and release its PTY state.",
        epilog="Example:\n  pyro workspace shell close WORKSPACE_ID SHELL_ID",
        formatter_class=_HelpFormatter,
    )
    workspace_shell_close_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_shell_close_parser.add_argument(
        "shell_id",
        metavar="SHELL_ID",
        help="Persistent shell identifier returned by `workspace shell open`.",
    )
    workspace_shell_close_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_service_parser = workspace_subparsers.add_parser(
        "service",
        help="Manage long-running services inside a workspace.",
        description=(
            "Start, inspect, and stop named long-running services inside one started workspace."
        ),
        epilog=dedent(
            """
            Examples:
              pyro workspace service start WORKSPACE_ID app --ready-file .ready -- \
                sh -lc 'touch .ready && while true; do sleep 60; done'
              pyro workspace service start WORKSPACE_ID app --ready-file .ready --publish 8080 -- \
                sh -lc 'touch .ready && python3 -m http.server 8080'
              pyro workspace service list WORKSPACE_ID
              pyro workspace service status WORKSPACE_ID app
              pyro workspace service logs WORKSPACE_ID app --tail-lines 50
              pyro workspace service stop WORKSPACE_ID app

            Use `--ready-file` by default in the curated Debian environments. `--ready-command`
            remains available as an escape hatch.
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_service_subparsers = workspace_service_parser.add_subparsers(
        dest="workspace_service_command",
        required=True,
        metavar="SERVICE",
    )
    workspace_service_start_parser = workspace_service_subparsers.add_parser(
        "start",
        help="Start one named long-running service.",
        description="Start a named service inside a started workspace with optional readiness.",
        epilog=dedent(
            """
            Examples:
              pyro workspace service start WORKSPACE_ID app --ready-file .ready -- \
                sh -lc 'touch .ready && while true; do sleep 60; done'
              pyro workspace service start WORKSPACE_ID app \
                --ready-file .ready --publish 18080:8080 -- \
                sh -lc 'touch .ready && python3 -m http.server 8080'
              pyro workspace service start WORKSPACE_ID app --secret-env API_TOKEN -- \
                sh -lc 'test \"$API_TOKEN\" = \"expected\"; touch .ready; \
while true; do sleep 60; done'
              pyro workspace service start WORKSPACE_ID app --ready-command 'test -f .ready' -- \
                sh -lc 'touch .ready && while true; do sleep 60; done'
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_service_start_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_service_start_parser.add_argument("service_name", metavar="SERVICE_NAME")
    workspace_service_start_parser.add_argument(
        "--cwd",
        default=WORKSPACE_GUEST_PATH,
        help="Service working directory. Relative values resolve inside `/workspace`.",
    )
    workspace_service_start_parser.add_argument(
        "--ready-file",
        help="Mark the service ready once this workspace path exists.",
    )
    workspace_service_start_parser.add_argument(
        "--ready-tcp",
        help="Mark the service ready once this HOST:PORT accepts guest-local TCP connections.",
    )
    workspace_service_start_parser.add_argument(
        "--ready-http",
        help="Mark the service ready once this guest-local URL returns 2xx or 3xx.",
    )
    workspace_service_start_parser.add_argument(
        "--ready-command",
        help="Escape hatch readiness probe command. Use typed readiness when possible.",
    )
    workspace_service_start_parser.add_argument(
        "--ready-timeout-seconds",
        type=int,
        default=DEFAULT_SERVICE_READY_TIMEOUT_SECONDS,
        help="Maximum time to wait for readiness before failing the service start.",
    )
    workspace_service_start_parser.add_argument(
        "--ready-interval-ms",
        type=int,
        default=DEFAULT_SERVICE_READY_INTERVAL_MS,
        help="Polling interval between readiness checks.",
    )
    workspace_service_start_parser.add_argument(
        "--secret-env",
        action="append",
        default=[],
        metavar="SECRET[=ENV_VAR]",
        help="Expose one persisted workspace secret as an environment variable for this service.",
    )
    workspace_service_start_parser.add_argument(
        "--publish",
        action="append",
        default=[],
        metavar="GUEST_PORT|HOST_PORT:GUEST_PORT",
        help=(
            "Publish one guest TCP port on 127.0.0.1. Requires workspace network policy "
            "`egress+published-ports`."
        ),
    )
    workspace_service_start_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_service_start_parser.add_argument(
        "command_args",
        nargs="*",
        metavar="ARG",
        help="Service command and arguments. Prefix them with `--`.",
    )
    workspace_service_list_parser = workspace_service_subparsers.add_parser(
        "list",
        help="List named services in one workspace.",
        description="List named services and their current states for one workspace.",
        epilog="Example:\n  pyro workspace service list WORKSPACE_ID",
        formatter_class=_HelpFormatter,
    )
    workspace_service_list_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_service_list_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_service_status_parser = workspace_service_subparsers.add_parser(
        "status",
        help="Inspect one service.",
        description="Show state and readiness metadata for one named workspace service.",
        epilog="Example:\n  pyro workspace service status WORKSPACE_ID app",
        formatter_class=_HelpFormatter,
    )
    workspace_service_status_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_service_status_parser.add_argument("service_name", metavar="SERVICE_NAME")
    workspace_service_status_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_service_logs_parser = workspace_service_subparsers.add_parser(
        "logs",
        help="Read persisted service stdout and stderr.",
        description="Read service stdout and stderr without using `workspace logs`.",
        epilog="Example:\n  pyro workspace service logs WORKSPACE_ID app --tail-lines 50",
        formatter_class=_HelpFormatter,
    )
    workspace_service_logs_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_service_logs_parser.add_argument("service_name", metavar="SERVICE_NAME")
    workspace_service_logs_parser.add_argument(
        "--tail-lines",
        type=int,
        default=DEFAULT_SERVICE_LOG_TAIL_LINES,
        help="Maximum number of trailing lines to return from each service log stream.",
    )
    workspace_service_logs_parser.add_argument(
        "--all",
        action="store_true",
        help="Return full stdout and stderr instead of tailing them.",
    )
    workspace_service_logs_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_service_stop_parser = workspace_service_subparsers.add_parser(
        "stop",
        help="Stop one running service.",
        description="Stop one named workspace service with TERM then KILL fallback.",
        epilog="Example:\n  pyro workspace service stop WORKSPACE_ID app",
        formatter_class=_HelpFormatter,
    )
    workspace_service_stop_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_service_stop_parser.add_argument("service_name", metavar="SERVICE_NAME")
    workspace_service_stop_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_list_parser = workspace_subparsers.add_parser(
        "list",
        help="List persisted workspaces.",
        description="List persisted workspaces with names, labels, state, and activity ordering.",
        epilog="Example:\n  pyro workspace list",
        formatter_class=_HelpFormatter,
    )
    workspace_list_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_update_parser = workspace_subparsers.add_parser(
        "update",
        help="Update workspace name or labels.",
        description="Update discovery metadata for one existing workspace.",
        epilog=dedent(
            """
            Examples:
              pyro workspace update WORKSPACE_ID --name repro-fix
              pyro workspace update WORKSPACE_ID --label owner=codex --label issue=123
              pyro workspace update WORKSPACE_ID --clear-label issue --clear-name
            """
        ),
        formatter_class=_HelpFormatter,
    )
    workspace_update_parser.add_argument("workspace_id", metavar="WORKSPACE_ID")
    workspace_update_parser.add_argument("--name", help="Set or replace the workspace name.")
    workspace_update_parser.add_argument(
        "--clear-name",
        action="store_true",
        help="Clear the current workspace name.",
    )
    workspace_update_parser.add_argument(
        "--label",
        action="append",
        default=[],
        metavar="KEY=VALUE",
        help="Upsert one workspace label. May be repeated.",
    )
    workspace_update_parser.add_argument(
        "--clear-label",
        action="append",
        default=[],
        metavar="KEY",
        help="Remove one workspace label key. May be repeated.",
    )
    workspace_update_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_status_parser = workspace_subparsers.add_parser(
        "status",
        help="Inspect one workspace.",
        description="Show workspace state, sizing, workspace path, and latest command metadata.",
        epilog="Example:\n  pyro workspace status WORKSPACE_ID",
        formatter_class=_HelpFormatter,
    )
    workspace_status_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_status_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_logs_parser = workspace_subparsers.add_parser(
        "logs",
        help="Show command history for one workspace.",
        description=(
            "Show persisted command history, including stdout and stderr, "
            "for one workspace."
        ),
        epilog="Example:\n  pyro workspace logs WORKSPACE_ID",
        formatter_class=_HelpFormatter,
    )
    workspace_logs_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_logs_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )
    workspace_delete_parser = workspace_subparsers.add_parser(
        "delete",
        help="Delete one workspace.",
        description="Stop the backing sandbox if needed and remove the workspace.",
        epilog="Example:\n  pyro workspace delete WORKSPACE_ID",
        formatter_class=_HelpFormatter,
    )
    workspace_delete_parser.add_argument(
        "workspace_id",
        metavar="WORKSPACE_ID",
        help="Persistent workspace identifier.",
    )
    workspace_delete_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )

    doctor_parser = subparsers.add_parser(
        "doctor",
        help="Inspect runtime and host diagnostics.",
        description="Check host prerequisites and embedded runtime health before your first run.",
        epilog=dedent(
            """
            Examples:
              pyro doctor
              pyro doctor --json
            """
        ),
        formatter_class=_HelpFormatter,
    )
    doctor_parser.add_argument(
        "--platform",
        default=DEFAULT_PLATFORM,
        help="Runtime platform to inspect.",
    )
    doctor_parser.add_argument(
        "--json",
        action="store_true",
        help="Print structured JSON instead of human-readable output.",
    )

    demo_parser = subparsers.add_parser(
        "demo",
        help="Run built-in demos.",
        description="Run built-in demos after the basic CLI validation path works.",
        epilog=dedent(
            """
            Examples:
              pyro demo
              pyro demo --network
              pyro demo ollama --verbose
            """
        ),
        formatter_class=_HelpFormatter,
    )
    demo_subparsers = demo_parser.add_subparsers(dest="demo_command", metavar="DEMO")
    demo_parser.add_argument(
        "--network",
        action="store_true",
        help="Enable outbound guest networking for the deterministic demo.",
    )
    ollama_parser = demo_subparsers.add_parser(
        "ollama",
        help="Run the Ollama MCP demo.",
        description="Run the Ollama tool-calling demo against the `vm_run` and lifecycle tools.",
        epilog=dedent(
            """
            Example:
              pyro demo ollama --model llama3.2:3b --verbose
            """
        ),
        formatter_class=_HelpFormatter,
    )
    ollama_parser.add_argument(
        "--base-url",
        default=DEFAULT_OLLAMA_BASE_URL,
        help="OpenAI-compatible base URL for the Ollama server.",
    )
    ollama_parser.add_argument(
        "--model",
        default=DEFAULT_OLLAMA_MODEL,
        help="Ollama model name to use for tool calling.",
    )
    ollama_parser.add_argument(
        "-v",
        "--verbose",
        action="store_true",
        help="Print full tool loop output instead of only the summary.",
    )

    return parser


def _require_command(command_args: list[str]) -> str:
    if command_args and command_args[0] == "--":
        command_args = command_args[1:]
    if not command_args:
        raise ValueError("command is required after `--`")
    return shlex.join(command_args)


def _read_utf8_text_file(path_value: str, *, option_name: str) -> str:
    if path_value.strip() == "":
        raise ValueError(f"{option_name} must not be empty")
    candidate = Path(path_value).expanduser()
    if not candidate.exists():
        raise ValueError(f"{option_name} file not found: {candidate}")
    if candidate.is_dir():
        raise ValueError(f"{option_name} must point to a file, not a directory: {candidate}")
    try:
        return candidate.read_text(encoding="utf-8")
    except UnicodeDecodeError as exc:
        raise ValueError(f"{option_name} must contain UTF-8 text: {candidate}") from exc


def _parse_workspace_secret_option(value: str) -> dict[str, str]:
    name, sep, secret_value = value.partition("=")
    if sep == "" or name.strip() == "" or secret_value == "":
        raise ValueError("workspace secrets must use NAME=VALUE")
    return {"name": name.strip(), "value": secret_value}


def _parse_workspace_secret_file_option(value: str) -> dict[str, str]:
    name, sep, file_path = value.partition("=")
    if sep == "" or name.strip() == "" or file_path.strip() == "":
        raise ValueError("workspace secret files must use NAME=PATH")
    return {"name": name.strip(), "file_path": file_path.strip()}


def _parse_workspace_secret_env_options(values: list[str]) -> dict[str, str]:
    parsed: dict[str, str] = {}
    for raw_value in values:
        secret_name, sep, env_name = raw_value.partition("=")
        normalized_secret_name = secret_name.strip()
        if normalized_secret_name == "":
            raise ValueError("workspace secret env mappings must name a secret")
        normalized_env_name = env_name.strip() if sep != "" else normalized_secret_name
        if normalized_env_name == "":
            raise ValueError("workspace secret env mappings must name an environment variable")
        if normalized_secret_name in parsed:
            raise ValueError(
                f"workspace secret env mapping references {normalized_secret_name!r} more than once"
            )
        parsed[normalized_secret_name] = normalized_env_name
    return parsed


def _parse_workspace_label_options(values: list[str]) -> dict[str, str]:
    parsed: dict[str, str] = {}
    for raw_value in values:
        key, sep, label_value = raw_value.partition("=")
        if sep == "" or key.strip() == "" or label_value.strip() == "":
            raise ValueError("workspace labels must use KEY=VALUE")
        parsed[key.strip()] = label_value.strip()
    return parsed


def _parse_workspace_clear_label_options(values: list[str]) -> list[str]:
    parsed: list[str] = []
    for raw_value in values:
        label_key = raw_value.strip()
        if label_key == "":
            raise ValueError("workspace clear-label values must not be empty")
        parsed.append(label_key)
    return parsed


def _parse_workspace_publish_options(values: list[str]) -> list[dict[str, int | None]]:
    parsed: list[dict[str, int | None]] = []
    for raw_value in values:
        candidate = raw_value.strip()
        if candidate == "":
            raise ValueError("published ports must not be empty")
        if ":" in candidate:
            raw_host_port, raw_guest_port = candidate.split(":", 1)
            try:
                host_port = int(raw_host_port)
                guest_port = int(raw_guest_port)
            except ValueError as exc:
                raise ValueError(
                    "published ports must use GUEST_PORT or HOST_PORT:GUEST_PORT"
                ) from exc
            parsed.append({"host_port": host_port, "guest_port": guest_port})
        else:
            try:
                guest_port = int(candidate)
            except ValueError as exc:
                raise ValueError(
                    "published ports must use GUEST_PORT or HOST_PORT:GUEST_PORT"
                ) from exc
            parsed.append({"host_port": None, "guest_port": guest_port})
    return parsed


def main() -> None:
    args = _build_parser().parse_args()
    pyro = Pyro()
    if args.command == "env":
        if args.env_command == "list":
            list_payload: dict[str, Any] = {
                "catalog_version": DEFAULT_CATALOG_VERSION,
                "environments": pyro.list_environments(),
            }
            if bool(args.json):
                _print_json(list_payload)
            else:
                _print_env_list_human(list_payload)
            return
        if args.env_command == "pull":
            if bool(args.json):
                pull_payload = pyro.pull_environment(args.environment)
                _print_json(pull_payload)
            else:
                _print_phase("pull", phase="install", environment=args.environment)
                pull_payload = pyro.pull_environment(args.environment)
                _print_phase("pull", phase="ready", environment=args.environment)
                _print_env_detail_human(pull_payload, action="Pulled")
            return
        if args.env_command == "inspect":
            inspect_payload = pyro.inspect_environment(args.environment)
            if bool(args.json):
                _print_json(inspect_payload)
            else:
                _print_env_detail_human(inspect_payload, action="Environment")
            return
        if args.env_command == "prune":
            prune_payload = pyro.prune_environments()
            if bool(args.json):
                _print_json(prune_payload)
            else:
                _print_prune_human(prune_payload)
            return
    if args.command == "mcp":
        pyro.create_server(profile=args.profile).run(transport="stdio")
        return
    if args.command == "run":
        command = _require_command(args.command_args)
        if bool(args.json):
            try:
                result = pyro.run_in_vm(
                    environment=args.environment,
                    command=command,
                    vcpu_count=args.vcpu_count,
                    mem_mib=args.mem_mib,
                    timeout_seconds=args.timeout_seconds,
                    ttl_seconds=args.ttl_seconds,
                    network=args.network,
                    allow_host_compat=args.allow_host_compat,
                )
            except Exception as exc:  # noqa: BLE001
                _print_json({"ok": False, "error": str(exc)})
                raise SystemExit(1) from exc
            _print_json(result)
        else:
            vm_id: str | None = None
            try:
                _print_phase("run", phase="create", environment=args.environment)
                created = pyro.create_vm(
                    environment=args.environment,
                    vcpu_count=args.vcpu_count,
                    mem_mib=args.mem_mib,
                    ttl_seconds=args.ttl_seconds,
                    network=args.network,
                    allow_host_compat=args.allow_host_compat,
                )
                vm_id = str(created["vm_id"])
                _print_phase("run", phase="start", vm_id=vm_id)
                pyro.start_vm(vm_id)
                _print_phase("run", phase="execute", vm_id=vm_id)
                result = pyro.exec_vm(vm_id, command=command, timeout_seconds=args.timeout_seconds)
            except Exception as exc:  # noqa: BLE001
                if vm_id is not None:
                    try:
                        pyro.manager.delete_vm(vm_id, reason="run_vm_error_cleanup")
                    except ValueError:
                        pass
                print(f"[error] {exc}", file=sys.stderr, flush=True)
                raise SystemExit(1) from exc
            _print_run_human(result)
        exit_code = int(result.get("exit_code", 1))
        if exit_code != 0:
            raise SystemExit(exit_code)
        return
    if args.command == "workspace":
        if args.workspace_command == "create":
            secrets = [
                *(
                    _parse_workspace_secret_option(value)
                    for value in getattr(args, "secret", [])
                ),
                *(
                    _parse_workspace_secret_file_option(value)
                    for value in getattr(args, "secret_file", [])
                ),
            ]
            labels = _parse_workspace_label_options(getattr(args, "label", []))
            payload = pyro.create_workspace(
                environment=args.environment,
                vcpu_count=args.vcpu_count,
                mem_mib=args.mem_mib,
                ttl_seconds=args.ttl_seconds,
                network_policy=getattr(args, "network_policy", "off"),
                allow_host_compat=args.allow_host_compat,
                seed_path=args.seed_path,
                secrets=secrets or None,
                name=args.name,
                labels=labels or None,
            )
            if bool(getattr(args, "id_only", False)):
                _print_id_only(payload["workspace_id"])
            elif bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_summary_human(payload, action="Workspace")
            return
        if args.workspace_command == "list":
            payload = pyro.list_workspaces()
            if bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_list_human(payload)
            return
        if args.workspace_command == "update":
            labels = _parse_workspace_label_options(getattr(args, "label", []))
            clear_labels = _parse_workspace_clear_label_options(
                getattr(args, "clear_label", [])
            )
            try:
                payload = pyro.update_workspace(
                    args.workspace_id,
                    name=args.name,
                    clear_name=bool(args.clear_name),
                    labels=labels or None,
                    clear_labels=clear_labels or None,
                )
            except Exception as exc:  # noqa: BLE001
                if bool(args.json):
                    _print_json({"ok": False, "error": str(exc)})
                else:
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                raise SystemExit(1) from exc
            if bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_summary_human(payload, action="Workspace")
            return
        if args.workspace_command == "exec":
            command = _require_command(args.command_args)
            secret_env = _parse_workspace_secret_env_options(getattr(args, "secret_env", []))
            if bool(args.json):
                try:
                    payload = pyro.exec_workspace(
                        args.workspace_id,
                        command=command,
                        timeout_seconds=args.timeout_seconds,
                        secret_env=secret_env or None,
                    )
                except Exception as exc:  # noqa: BLE001
                    _print_json({"ok": False, "error": str(exc)})
                    raise SystemExit(1) from exc
                _print_json(payload)
            else:
                try:
                    payload = pyro.exec_workspace(
                        args.workspace_id,
                        command=command,
                        timeout_seconds=args.timeout_seconds,
                        secret_env=secret_env or None,
                    )
                except Exception as exc:  # noqa: BLE001
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                _print_workspace_exec_human(payload)
            exit_code = int(payload.get("exit_code", 1))
            if exit_code != 0:
                raise SystemExit(exit_code)
            return
        if args.workspace_command == "sync" and args.workspace_sync_command == "push":
            if bool(args.json):
                try:
                    payload = pyro.push_workspace_sync(
                        args.workspace_id,
                        args.source_path,
                        dest=args.dest,
                    )
                except Exception as exc:  # noqa: BLE001
                    _print_json({"ok": False, "error": str(exc)})
                    raise SystemExit(1) from exc
                _print_json(payload)
            else:
                try:
                    payload = pyro.push_workspace_sync(
                        args.workspace_id,
                        args.source_path,
                        dest=args.dest,
                    )
                except Exception as exc:  # noqa: BLE001
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                _print_workspace_sync_human(payload)
            return
        if args.workspace_command == "export":
            if bool(args.json):
                try:
                    payload = pyro.export_workspace(
                        args.workspace_id,
                        args.path,
                        output_path=args.output,
                    )
                except Exception as exc:  # noqa: BLE001
                    _print_json({"ok": False, "error": str(exc)})
                    raise SystemExit(1) from exc
                _print_json(payload)
            else:
                try:
                    payload = pyro.export_workspace(
                        args.workspace_id,
                        args.path,
                        output_path=args.output,
                    )
                except Exception as exc:  # noqa: BLE001
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                _print_workspace_export_human(payload)
            return
        if args.workspace_command == "diff":
            if bool(args.json):
                try:
                    payload = pyro.diff_workspace(args.workspace_id)
                except Exception as exc:  # noqa: BLE001
                    _print_json({"ok": False, "error": str(exc)})
                    raise SystemExit(1) from exc
                _print_json(payload)
            else:
                try:
                    payload = pyro.diff_workspace(args.workspace_id)
                except Exception as exc:  # noqa: BLE001
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                _print_workspace_diff_human(payload)
            return
        if args.workspace_command == "file":
            if args.workspace_file_command == "list":
                try:
                    payload = pyro.list_workspace_files(
                        args.workspace_id,
                        path=args.path,
                        recursive=bool(args.recursive),
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_file_list_human(payload)
                return
            if args.workspace_file_command == "read":
                try:
                    payload = pyro.read_workspace_file(
                        args.workspace_id,
                        args.path,
                        max_bytes=args.max_bytes,
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_file_read_human(
                        payload,
                        content_only=bool(getattr(args, "content_only", False)),
                    )
                return
            if args.workspace_file_command == "write":
                text = (
                    args.text
                    if getattr(args, "text", None) is not None
                    else _read_utf8_text_file(args.text_file, option_name="--text-file")
                )
                try:
                    payload = pyro.write_workspace_file(
                        args.workspace_id,
                        args.path,
                        text=text,
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_file_write_human(payload)
                return
        if args.workspace_command == "patch" and args.workspace_patch_command == "apply":
            patch_text = (
                args.patch
                if getattr(args, "patch", None) is not None
                else _read_utf8_text_file(args.patch_file, option_name="--patch-file")
            )
            try:
                payload = pyro.apply_workspace_patch(
                    args.workspace_id,
                    patch=patch_text,
                )
            except Exception as exc:  # noqa: BLE001
                if bool(args.json):
                    _print_json({"ok": False, "error": str(exc)})
                else:
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                raise SystemExit(1) from exc
            if bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_patch_human(payload)
            return
        if args.workspace_command == "snapshot":
            if args.workspace_snapshot_command == "create":
                try:
                    payload = pyro.create_snapshot(args.workspace_id, args.snapshot_name)
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_snapshot_human(
                        payload,
                        prefix="workspace-snapshot-create",
                    )
                return
            if args.workspace_snapshot_command == "list":
                try:
                    payload = pyro.list_snapshots(args.workspace_id)
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_snapshot_list_human(payload)
                return
            if args.workspace_snapshot_command == "delete":
                try:
                    payload = pyro.delete_snapshot(args.workspace_id, args.snapshot_name)
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    print(
                        "Deleted workspace snapshot: "
                        f"{str(payload.get('snapshot_name', 'unknown'))}"
                    )
                return
        if args.workspace_command == "reset":
            try:
                payload = pyro.reset_workspace(
                    args.workspace_id,
                    snapshot=args.snapshot,
                )
            except Exception as exc:  # noqa: BLE001
                if bool(args.json):
                    _print_json({"ok": False, "error": str(exc)})
                else:
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                raise SystemExit(1) from exc
            if bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_reset_human(payload)
            return
        if args.workspace_command == "stop":
            try:
                payload = pyro.stop_workspace(args.workspace_id)
            except Exception as exc:  # noqa: BLE001
                if bool(args.json):
                    _print_json({"ok": False, "error": str(exc)})
                else:
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                raise SystemExit(1) from exc
            if bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_summary_human(payload, action="Stopped workspace")
            return
        if args.workspace_command == "start":
            try:
                payload = pyro.start_workspace(args.workspace_id)
            except Exception as exc:  # noqa: BLE001
                if bool(args.json):
                    _print_json({"ok": False, "error": str(exc)})
                else:
                    print(f"[error] {exc}", file=sys.stderr, flush=True)
                raise SystemExit(1) from exc
            if bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_summary_human(payload, action="Started workspace")
            return
        if args.workspace_command == "disk":
            if args.workspace_disk_command == "export":
                try:
                    payload = pyro.export_workspace_disk(
                        args.workspace_id,
                        output_path=args.output,
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_disk_export_human(payload)
                return
            if args.workspace_disk_command == "list":
                try:
                    payload = pyro.list_workspace_disk(
                        args.workspace_id,
                        path=args.path,
                        recursive=bool(args.recursive),
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_disk_list_human(payload)
                return
            if args.workspace_disk_command == "read":
                try:
                    payload = pyro.read_workspace_disk(
                        args.workspace_id,
                        args.path,
                        max_bytes=args.max_bytes,
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_disk_read_human(
                        payload,
                        content_only=bool(getattr(args, "content_only", False)),
                    )
                return
        if args.workspace_command == "shell":
            if args.workspace_shell_command == "open":
                secret_env = _parse_workspace_secret_env_options(getattr(args, "secret_env", []))
                try:
                    payload = pyro.open_shell(
                        args.workspace_id,
                        cwd=args.cwd,
                        cols=args.cols,
                        rows=args.rows,
                        secret_env=secret_env or None,
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(getattr(args, "id_only", False)):
                    _print_id_only(payload["shell_id"])
                elif bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_shell_summary_human(payload, prefix="workspace-shell-open")
                return
            if args.workspace_shell_command == "read":
                try:
                    payload = pyro.read_shell(
                        args.workspace_id,
                        args.shell_id,
                        cursor=args.cursor,
                        max_chars=args.max_chars,
                        plain=bool(args.plain),
                        wait_for_idle_ms=args.wait_for_idle_ms,
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_shell_read_human(payload)
                return
            if args.workspace_shell_command == "write":
                try:
                    payload = pyro.write_shell(
                        args.workspace_id,
                        args.shell_id,
                        input=args.input,
                        append_newline=not bool(args.no_newline),
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_shell_summary_human(payload, prefix="workspace-shell-write")
                return
            if args.workspace_shell_command == "signal":
                try:
                    payload = pyro.signal_shell(
                        args.workspace_id,
                        args.shell_id,
                        signal_name=args.signal,
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_shell_summary_human(
                        payload,
                        prefix="workspace-shell-signal",
                    )
                return
            if args.workspace_shell_command == "close":
                try:
                    payload = pyro.close_shell(args.workspace_id, args.shell_id)
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_shell_summary_human(payload, prefix="workspace-shell-close")
                return
        if args.workspace_command == "service":
            if args.workspace_service_command == "start":
                readiness_count = sum(
                    value is not None
                    for value in (
                        args.ready_file,
                        args.ready_tcp,
                        args.ready_http,
                        args.ready_command,
                    )
                )
                if readiness_count > 1:
                    error = (
                        "choose at most one of --ready-file, --ready-tcp, "
                        "--ready-http, or --ready-command"
                    )
                    if bool(args.json):
                        _print_json({"ok": False, "error": error})
                    else:
                        print(f"[error] {error}", file=sys.stderr, flush=True)
                    raise SystemExit(1)
                readiness: dict[str, Any] | None = None
                if args.ready_file is not None:
                    readiness = {"type": "file", "path": args.ready_file}
                elif args.ready_tcp is not None:
                    readiness = {"type": "tcp", "address": args.ready_tcp}
                elif args.ready_http is not None:
                    readiness = {"type": "http", "url": args.ready_http}
                elif args.ready_command is not None:
                    readiness = {"type": "command", "command": args.ready_command}
                command = _require_command(args.command_args)
                secret_env = _parse_workspace_secret_env_options(getattr(args, "secret_env", []))
                published_ports = _parse_workspace_publish_options(getattr(args, "publish", []))
                try:
                    payload = pyro.start_service(
                        args.workspace_id,
                        args.service_name,
                        command=command,
                        cwd=args.cwd,
                        readiness=readiness,
                        ready_timeout_seconds=args.ready_timeout_seconds,
                        ready_interval_ms=args.ready_interval_ms,
                        secret_env=secret_env or None,
                        published_ports=published_ports or None,
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_service_summary_human(
                        payload,
                        prefix="workspace-service-start",
                    )
                return
            if args.workspace_service_command == "list":
                try:
                    payload = pyro.list_services(args.workspace_id)
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_service_list_human(payload)
                return
            if args.workspace_service_command == "status":
                try:
                    payload = pyro.status_service(args.workspace_id, args.service_name)
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_service_summary_human(
                        payload,
                        prefix="workspace-service-status",
                    )
                return
            if args.workspace_service_command == "logs":
                try:
                    payload = pyro.logs_service(
                        args.workspace_id,
                        args.service_name,
                        tail_lines=args.tail_lines,
                        all=bool(args.all),
                    )
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_service_logs_human(payload)
                return
            if args.workspace_service_command == "stop":
                try:
                    payload = pyro.stop_service(args.workspace_id, args.service_name)
                except Exception as exc:  # noqa: BLE001
                    if bool(args.json):
                        _print_json({"ok": False, "error": str(exc)})
                    else:
                        print(f"[error] {exc}", file=sys.stderr, flush=True)
                    raise SystemExit(1) from exc
                if bool(args.json):
                    _print_json(payload)
                else:
                    _print_workspace_service_summary_human(
                        payload,
                        prefix="workspace-service-stop",
                    )
                return
        if args.workspace_command == "status":
            payload = pyro.status_workspace(args.workspace_id)
            if bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_summary_human(payload, action="Workspace")
            return
        if args.workspace_command == "logs":
            payload = pyro.logs_workspace(args.workspace_id)
            if bool(args.json):
                _print_json(payload)
            else:
                _print_workspace_logs_human(payload)
            return
        if args.workspace_command == "delete":
            payload = pyro.delete_workspace(args.workspace_id)
            if bool(args.json):
                _print_json(payload)
            else:
                print(f"Deleted workspace: {str(payload.get('workspace_id', 'unknown'))}")
            return
    if args.command == "doctor":
        payload = doctor_report(platform=args.platform)
        if bool(args.json):
            _print_json(payload)
        else:
            _print_doctor_human(payload)
        return
    if args.command == "demo" and args.demo_command == "ollama":
        try:
            result = run_ollama_tool_demo(
                base_url=args.base_url,
                model=args.model,
                verbose=args.verbose,
                log=lambda message: print(message, flush=True),
            )
        except Exception as exc:  # noqa: BLE001
            print(f"[error] {exc}", flush=True)
            raise SystemExit(1) from exc
        exec_result = result["exec_result"]
        if not isinstance(exec_result, dict):
            raise RuntimeError("demo produced invalid execution result")
        print(
            f"[summary] exit_code={int(exec_result.get('exit_code', -1))} "
            f"fallback_used={bool(result.get('fallback_used'))} "
            f"execution_mode={str(exec_result.get('execution_mode', 'unknown'))}",
            flush=True,
        )
        if args.verbose:
            print(f"[summary] stdout={str(exec_result.get('stdout', '')).strip()}", flush=True)
        return
    result = run_demo(network=bool(args.network))
    _print_json(result)
