Skip to content

The Orchestrator

The Orchestrator operates as the primary deterministic state machine for Protostar. It is responsible for bridging the gap between declarative module configurations and imperative disk/shell mutations, ensuring the local filesystem is manipulated safely and predictably.

To guarantee idempotency and prevent partial initialization states (e.g., half-written configuration files following a pre-flight failure), the Orchestrator enforces a strict, multi-phase execution topology.

  • Idempotent Execution

    Execution logic is strictly decoupled from state definition. Running the Orchestrator repeatedly yields the same mathematical environment baseline without corrupting existing user configurations.

  • Deterministic Sequencing

    Dependencies and tasks are not executed arbitrarily. The Orchestrator enforces a strict, statically defined execution sequence, ensuring that structural scaffolding and abstract syntax trees (like TOML payloads) are fully resolved and merged before any shell subprocesses attempt to read them.

  • Telemetry & Triage

    Acts as the top-level exception handler. Traps sys.exit, OS-level I/O constraints, and unhandled runtime exceptions to provide clean terminal exits or automated GitHub crash reports.


Execution Topology

The Orchestrator processes the environment payload in a distinct lifecycle. State aggregation is strictly isolated from the side-effect phase, ensuring that execution only proceeds if the host system satisfies all required boundary conditions.

flowchart TD
    %% Styling
    classDef core fill:#1e293b,stroke:#00e5ff,stroke-width:2px,color:#fff;
    classDef phase fill:#334155,stroke:#475569,stroke-width:1px,color:#e2e8f0;
    classDef error fill:#7f1d1d,stroke:#f87171,stroke-width:1px,color:#fff;
    classDef success fill:#14532d,stroke:#4ade80,stroke-width:1px,color:#fff;

    %% Nodes
    CLI([CLI Invocation]) --> O[Orchestrator]:::core

    subgraph VerificationPhase [Verification Phase]
        direction TB
        C{Collision Intercept}:::phase
        C -- Conflicting Configs --> P[TUI: Merge / Overwrite / Abort]
        P -- Abort --> Exit1([Safe Exit Code 1]):::error
        C -- Clean Workspace --> F[Pre-Flight Checks]:::phase
        P -- Authorize --> F
        F -- Missing Binaries --> Exit2([Safe Exit Code 1]):::error
    end

    O --> VerificationPhase

    subgraph AggregationPhase [Aggregation Phase]
        direction LR
        M[Manifest Aggregation]:::phase
        L[Language Modules] -.-> E[(EnvironmentManifest)]
        T[Tooling Modules] -.-> E
        P_Pre[Domain Presets] -.-> E
        M --> L & T & P_Pre
    end

    VerificationPhase -- System Nominal --> AggregationPhase

    subgraph SideEffectRealization [Side-Effect Realization]
        direction TB
        X[System Executor]:::core
        D1[Validate & Merge ASTs]
        D2[Write Directories & Files]
        D3[Execute Shell Subprocesses]
        X --> D1 --> D2 --> D3
    end

    E --> SideEffectRealization
    SideEffectRealization --> End([Environment Stabilized]):::success

The Lifecycle Phases

Before a single byte of memory is allocated for the manifest payload, the Orchestrator scans the local directory for module-specific collision markers (e.g., an existing pyproject.toml or Cargo.toml).

  • Interactive Environments: Protostar halts and launches a TUI prompting the developer to Merge, Overwrite, or Abort.

  • Headless Environments (CI/CD): Protostar safely aborts with a non-zero exit code to prevent destructive mutations, unless the -f / --force flag is explicitly provided (which defaults to a safe MERGE strategy).

Every loaded module executes its pre_flight() method. This step guarantees that all required system binaries (like uv, cargo, git, or direnv) are installed and accessible in the system $PATH. If a dependency is missing, execution halts immediately before any disk I/O occurs.

The Orchestrator iterates through the universal System Workspace, Language, Tooling, and Preset modules. Each module deterministically appends its required dependencies, ignores, and configuration payloads to the EnvironmentManifest. Global configuration injections (e.g., custom PyPI dependencies) are appended last to ensure they override module defaults.

The Orchestrator hands the fully resolved manifest to the SystemExecutor. The executor flushes the state to disk in a highly specific topological order:

  1. Validates existing TOML files for syntax errors.
  2. Creates directories and injects base files.
  3. Modifies configurations via AST deep-merging.
  4. Writes deduplicated ignore files and Docker artifacts.
  5. Writes local IDE settings.
  6. Executes sequential subprocesses (package resolution, git hooks).

Telemetry & Crash Reporting

The Orchestrator serves as the absolute boundary for exception propagation. By trapping errors at the highest level, it guarantees that users are never presented with a raw, unformatted Python stack trace unless explicitly requested via the --verbose flag.

  • Expected Anomalies: Standard errors like FileExistsError, OSError (e.g., read-only filesystems), or RuntimeError (e.g., network timeouts during dependency resolution) are caught and gracefully presented as a clean abort message in the terminal.
  • Critical Failures: If Protostar encounters an unhandled internal exception (a genuine bug or AST parsing collapse), it traps the stack trace, collects a vector of the environment state, and outputs a URL-encoded link. Clicking this link instantly opens a pre-populated GitHub issue so the telemetry isn't lost to the void.

Simulated Critical Failure Payload

When a catastrophic failure occurs, the Orchestrator encodes the following telemetry into the GitHub issue body:

Environment

  • OS: Darwin 25.3.0
  • Python: 3.14.3
  • Command: protostar init --python --astro --crash-test

Traceback

Traceback (most recent call last):
File "/opt/homebrew/bin/protostar", line 8, in <module>
    sys.exit(main())
File "/opt/homebrew/lib/python3.12/site-packages/protostar/cli.py", line 150, in handle_init
    engine.run()
File "/opt/homebrew/lib/python3.12/site-packages/protostar/orchestrator.py", line 105, in run
    raise TypeError("INTENTIONAL_CRASH")
TypeError: INTENTIONAL_CRASH

API Reference

Core Interface: Orchestrator

protostar.orchestrator.Orchestrator

Manages the lifecycle of the Python environment scaffolding process.

Source code in src/protostar/orchestrator.py
class Orchestrator:
    """Manages the lifecycle of the Python environment scaffolding process."""

    def __init__(
        self,
        modules: list[BootstrapModule],
        config: ProtostarConfig,
        presets: list[PresetModule] | None = None,
        docker: bool = False,
        force: bool = False,
    ) -> None:
        """Initializes the orchestrator with the requested modules and presets.

        Args:
            modules: The ordered stack of bootstrap layers to execute.
            config: The active Protostar configuration instance.
            presets: Domain-specific dependency and directory presets. Defaults to an empty list.
            docker: If True, scaffolds a .dockerignore from the manifest ignores. Defaults to False.
            force: If True, bypasses interactive prompts and forces a merge on collisions. Defaults to False.
        """
        self.modules = modules
        self.config = config
        self.presets = presets or []
        self.docker = docker
        self.force = force
        self.manifest = EnvironmentManifest()

    def _evaluate_collisions(self) -> None:
        """Evaluates the workspace for critical configuration file collisions.

        Halts execution with an interactive prompt if existing configuration markers
        are found on disk. Non-interactive environments default to a safe abort
        unless the --force flag is explicitly provided.
        """
        collision_targets = set()
        for mod in self.modules:
            for marker in mod.collision_markers:
                if marker.exists():
                    collision_targets.add(marker)

        if not collision_targets:
            return

        # 1. Immediate override: Evaluate explicit force flag first
        if self.force:
            logger.debug(
                "--force flag provided. Defaulting to MERGE collision strategy."
            )
            self.manifest.collision_strategy = CollisionStrategy.MERGE
            return

        # 2. Evaluate non-interactive fallback logic
        if not sys.stdin.isatty() or "PYTEST_CURRENT_TEST" in os.environ:
            console.print(
                "\n[bold red]Orbital Collision Detected:[/bold red] The target workspace is not empty."
            )
            console.print(
                "Aborting to prevent destructive mutations in a non-interactive context.\n"
                "Use the [bold cyan]--force[/bold cyan] flag to bypass this check and merge safely."
            )
            sys.exit(1)

        # 3. Fallback to interactive prompt
        import questionary
        from questionary import Choice

        console.print(
            "\n[bold yellow]Gravitational Anomaly:[/bold yellow] Protostar detected existing configuration files in the workspace."
        )
        for target in collision_targets:
            console.print(f"  - {target}")

        choice = questionary.select(
            "\nHow would you like to proceed?",
            choices=[
                Choice(
                    title="Merge     (Safely injects missing configs; preserves existing user data)",
                    value=CollisionStrategy.MERGE,
                ),
                Choice(
                    title="Overwrite (Forces injection; updates existing keys to match Protostar)",
                    value=CollisionStrategy.OVERWRITE,
                ),
                Choice(
                    title="Abort     (Safely exit without modifying the environment)",
                    value=CollisionStrategy.ABORT,
                ),
            ],
            style=questionary.Style(
                [
                    ("answer", "fg:cyan bold"),
                    ("pointer", "fg:cyan bold"),
                    ("selected", "fg:cyan"),
                ]
            ),
        ).ask()

        if not choice or choice == CollisionStrategy.ABORT:
            console.print(
                "\n[bold red]ABORTED:[/bold red] Environment initialization cancelled by user."
            )
            sys.exit(1)

        self.manifest.collision_strategy = choice

    def run(self) -> None:
        """Executes the pre-flight, build, and realization phases."""
        console.print("[bold]Protostar Ignition Sequence Initiated[/bold]")

        try:
            # Phase 1: Collision Intercept
            self._evaluate_collisions()

            # Phase 2: Pre-flight Verification
            for mod in self.modules:
                mod.pre_flight()

            # Phase 3: Manifest Aggregation
            for mod in self.modules:
                mod.build(self.manifest)

            for preset in self.presets:
                logger.debug(f"Building {preset.name} preset.")
                preset.build(self.manifest)

            # Inject global configuration states using the injected config
            if self.config.global_dev_dependencies:
                logger.debug("Injecting global dev dependencies from configuration.")
                for dep in self.config.global_dev_dependencies:
                    self.manifest.add_dev_dependency(dep)

            if self.config.pyproject_injections:
                logger.debug(
                    "Injecting global pyproject.toml payloads from configuration."
                )
                for payload in self.config.pyproject_injections.values():
                    self.manifest.add_file_append("pyproject.toml", payload)

            # Phase 4: System Execution
            executor = SystemExecutor(self.manifest, self.config, self.docker)
            executor.execute()

            # Phase 5: Telemetry Evaluation
            if executor.warnings:
                console.print(
                    "\n[bold yellow]PARTIAL SUCCESS:[/bold yellow] Environment scaffolded, but some non-critical tasks encountered issues."
                )
                for warning in executor.warnings:
                    console.print(f"[yellow]  ⚠ {warning}[/yellow]")
            else:
                console.print(
                    "\n[bold green]SUCCESS:[/bold green] Accretion disk stabilized. Environment ready."
                )

        except Exception as e:
            # Catch expected operational errors and OS-level I/O constraints
            if isinstance(e, (RuntimeError, ValueError, FileExistsError, OSError)):
                console.print(f"\n[bold red]ABORTED:[/bold red] {e}")
                sys.exit(1)

            console.print(
                "\n[bold red]CRITICAL FAILURE:[/bold red] Protostar encountered an unexpected error."
            )

            tb_str = "".join(traceback.format_exception(type(e), e, e.__traceback__))
            issue_body = (
                "### Environment\n"
                f"- **OS**: {platform.system()} {platform.release()}\n"
                f"- **Python**: {sys.version.split()[0]}\n"
                f"- **Command**: `{' '.join(sys.argv)}`\n\n"
                "### Traceback\n"
                f"```python\n{tb_str}\n```\n"
            )

            encoded_body = urllib.parse.quote(issue_body)
            issue_url = f"https://github.com/jacksonfergusondev/protostar/issues/new?title=Crash+Report&body={encoded_body}"

            console.print(
                "This looks like a bug. Please help us fix it by submitting an issue with your telemetry:"
            )
            # Render via Rich's OSC 8 link syntax
            console.print(
                f"[bold cyan][link={issue_url}]Click here to open a GitHub issue with your telemetry[/link][/bold cyan]"
            )

            logger.debug("Stack trace:", exc_info=True)
            sys.exit(1)

__init__

__init__(
    modules, config, presets=None, docker=False, force=False
)

Initializes the orchestrator with the requested modules and presets.

Parameters:

Name Type Description Default
modules list[BootstrapModule]

The ordered stack of bootstrap layers to execute.

required
config ProtostarConfig

The active Protostar configuration instance.

required
presets list[PresetModule] | None

Domain-specific dependency and directory presets. Defaults to an empty list.

None
docker bool

If True, scaffolds a .dockerignore from the manifest ignores. Defaults to False.

False
force bool

If True, bypasses interactive prompts and forces a merge on collisions. Defaults to False.

False
Source code in src/protostar/orchestrator.py
def __init__(
    self,
    modules: list[BootstrapModule],
    config: ProtostarConfig,
    presets: list[PresetModule] | None = None,
    docker: bool = False,
    force: bool = False,
) -> None:
    """Initializes the orchestrator with the requested modules and presets.

    Args:
        modules: The ordered stack of bootstrap layers to execute.
        config: The active Protostar configuration instance.
        presets: Domain-specific dependency and directory presets. Defaults to an empty list.
        docker: If True, scaffolds a .dockerignore from the manifest ignores. Defaults to False.
        force: If True, bypasses interactive prompts and forces a merge on collisions. Defaults to False.
    """
    self.modules = modules
    self.config = config
    self.presets = presets or []
    self.docker = docker
    self.force = force
    self.manifest = EnvironmentManifest()

run

run()

Executes the pre-flight, build, and realization phases.

Source code in src/protostar/orchestrator.py
def run(self) -> None:
    """Executes the pre-flight, build, and realization phases."""
    console.print("[bold]Protostar Ignition Sequence Initiated[/bold]")

    try:
        # Phase 1: Collision Intercept
        self._evaluate_collisions()

        # Phase 2: Pre-flight Verification
        for mod in self.modules:
            mod.pre_flight()

        # Phase 3: Manifest Aggregation
        for mod in self.modules:
            mod.build(self.manifest)

        for preset in self.presets:
            logger.debug(f"Building {preset.name} preset.")
            preset.build(self.manifest)

        # Inject global configuration states using the injected config
        if self.config.global_dev_dependencies:
            logger.debug("Injecting global dev dependencies from configuration.")
            for dep in self.config.global_dev_dependencies:
                self.manifest.add_dev_dependency(dep)

        if self.config.pyproject_injections:
            logger.debug(
                "Injecting global pyproject.toml payloads from configuration."
            )
            for payload in self.config.pyproject_injections.values():
                self.manifest.add_file_append("pyproject.toml", payload)

        # Phase 4: System Execution
        executor = SystemExecutor(self.manifest, self.config, self.docker)
        executor.execute()

        # Phase 5: Telemetry Evaluation
        if executor.warnings:
            console.print(
                "\n[bold yellow]PARTIAL SUCCESS:[/bold yellow] Environment scaffolded, but some non-critical tasks encountered issues."
            )
            for warning in executor.warnings:
                console.print(f"[yellow]  ⚠ {warning}[/yellow]")
        else:
            console.print(
                "\n[bold green]SUCCESS:[/bold green] Accretion disk stabilized. Environment ready."
            )

    except Exception as e:
        # Catch expected operational errors and OS-level I/O constraints
        if isinstance(e, (RuntimeError, ValueError, FileExistsError, OSError)):
            console.print(f"\n[bold red]ABORTED:[/bold red] {e}")
            sys.exit(1)

        console.print(
            "\n[bold red]CRITICAL FAILURE:[/bold red] Protostar encountered an unexpected error."
        )

        tb_str = "".join(traceback.format_exception(type(e), e, e.__traceback__))
        issue_body = (
            "### Environment\n"
            f"- **OS**: {platform.system()} {platform.release()}\n"
            f"- **Python**: {sys.version.split()[0]}\n"
            f"- **Command**: `{' '.join(sys.argv)}`\n\n"
            "### Traceback\n"
            f"```python\n{tb_str}\n```\n"
        )

        encoded_body = urllib.parse.quote(issue_body)
        issue_url = f"https://github.com/jacksonfergusondev/protostar/issues/new?title=Crash+Report&body={encoded_body}"

        console.print(
            "This looks like a bug. Please help us fix it by submitting an issue with your telemetry:"
        )
        # Render via Rich's OSC 8 link syntax
        console.print(
            f"[bold cyan][link={issue_url}]Click here to open a GitHub issue with your telemetry[/link][/bold cyan]"
        )

        logger.debug("Stack trace:", exc_info=True)
        sys.exit(1)