pub struct OrchestratorHandle { /* private fields */ }Expand description
The primary public API for embedding xchecker.
OrchestratorHandle provides a stable interface for creating specs and running
phases programmatically. It is the canonical way to use xchecker outside of the CLI.
§Overview
Use OrchestratorHandle to:
- Create and manage specs programmatically
- Execute individual phases or the full workflow
- Query spec status and artifacts
- Configure execution options
§Construction
There are two ways to create an OrchestratorHandle:
OrchestratorHandle::new: Uses environment-based config discovery (same as CLI)OrchestratorHandle::from_config: Uses explicit configuration (deterministic)
§Threading
OrchestratorHandle is NOT guaranteed Send or Sync in 1.x.
Treat as single-threaded; concurrent use is undefined behavior.
This may be relaxed in future versions.
§Mutability
Methods that execute phases take &mut self to encode “sequential use only”
semantics. This prevents accidental concurrent use at compile time.
§Sync vs Async
Public APIs are synchronous and manage their own async runtime internally. Tokio is an implementation detail not exposed to library consumers.
§Example
use xchecker_engine::orchestrator::OrchestratorHandle;
use xchecker_engine::types::PhaseId;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Using environment-based config discovery
let mut handle = OrchestratorHandle::new("my-spec")?;
// Run a single phase
handle.run_phase(PhaseId::Requirements).await?;
// Check status
let status = handle.status()?;
println!("Artifacts: {}", status.artifacts.len());
// Get the spec ID
println!("Spec: {}", handle.spec_id());
Ok(())
}§Using Explicit Configuration
use xchecker_engine::config::Config;
use xchecker_engine::orchestrator::OrchestratorHandle;
// Create explicit config programmatically
let config = Config::discover(&Default::default())?;
let handle = OrchestratorHandle::from_config("my-spec", config)?;§Error Handling
All methods return Result types. Errors are returned as XCheckerError
which provides:
- Rich context about what went wrong
- Actionable suggestions for resolution
- Mapping to CLI exit codes via
XCheckerError::to_exit_code
Implementations§
Source§impl OrchestratorHandle
impl OrchestratorHandle
Sourcepub fn new(spec_id: &str) -> Result<Self, XCheckerError>
pub fn new(spec_id: &str) -> Result<Self, XCheckerError>
Create a handle using environment-based config discovery.
This uses the same discovery logic as the CLI:
XCHECKER_HOMEenvironment variable- Upward search for
.xchecker/config.toml - Built-in defaults
Acquires an exclusive lock on the spec directory.
§Errors
Returns error if:
- Configuration discovery fails
- Orchestrator creation fails
- Lock cannot be acquired
§Example
use xchecker_engine::orchestrator::OrchestratorHandle;
let handle = OrchestratorHandle::new("my-spec")?;Sourcepub fn from_config(spec_id: &str, config: Config) -> Result<Self, XCheckerError>
pub fn from_config(spec_id: &str, config: Config) -> Result<Self, XCheckerError>
Create a handle using explicit configuration.
This does NOT probe the global environment or filesystem for config. Use this when you need deterministic behavior independent of the user’s environment.
§Errors
Returns error if:
- Orchestrator creation fails
- Lock cannot be acquired
§Example
use xchecker_engine::config::Config;
use xchecker_engine::orchestrator::OrchestratorHandle;
// Create explicit config programmatically
let config = Config::discover(&Default::default())?;
let handle = OrchestratorHandle::from_config("my-spec", config)?;Sourcepub fn with_force(spec_id: &str, force: bool) -> Result<Self, XCheckerError>
pub fn with_force(spec_id: &str, force: bool) -> Result<Self, XCheckerError>
Create a handle with force flag for lock override.
Use with caution: forcing lock override can lead to race conditions if another process is actively working on the spec.
§Errors
Returns error if orchestrator creation fails.
Sourcepub fn with_config_and_force(
spec_id: &str,
config: OrchestratorConfig,
force: bool,
) -> Result<Self, XCheckerError>
pub fn with_config_and_force( spec_id: &str, config: OrchestratorConfig, force: bool, ) -> Result<Self, XCheckerError>
Create a handle with custom OrchestratorConfig and force flag.
This is used by the CLI when it needs to pass specific orchestrator configuration options.
§Errors
Returns error if orchestrator creation fails.
Sourcepub fn readonly(spec_id: &str) -> Result<Self, XCheckerError>
pub fn readonly(spec_id: &str) -> Result<Self, XCheckerError>
Create a read-only handle for status inspection.
Does not acquire locks, allowing inspection while another process is actively working on the spec.
§Errors
Returns error if orchestrator creation fails.
Sourcepub async fn run_phase(&mut self, phase: PhaseId) -> Result<ExecutionResult>
pub async fn run_phase(&mut self, phase: PhaseId) -> Result<ExecutionResult>
Execute a single phase.
Behavior matches the CLI xchecker resume --phase <phase> command.
Takes &mut self to enforce sequential use.
§Errors
Returns error if transition is invalid or execution fails.
§Example
use xchecker_engine::orchestrator::OrchestratorHandle;
use xchecker_engine::types::PhaseId;
let mut handle = OrchestratorHandle::new("my-spec")?;
handle.run_phase(PhaseId::Requirements).await?;Sourcepub async fn run_all(&mut self) -> Result<ExecutionResult>
pub async fn run_all(&mut self) -> Result<ExecutionResult>
Execute all phases in sequence.
Stops on first failure. Behavior matches the CLI xchecker spec command.
Takes &mut self to enforce sequential use.
§Errors
Returns error if any phase fails.
§Example
use xchecker_engine::orchestrator::OrchestratorHandle;
let mut handle = OrchestratorHandle::new("my-spec")?;
handle.run_all().await?;Sourcepub fn status(&self) -> Result<StatusOutput, XCheckerError>
pub fn status(&self) -> Result<StatusOutput, XCheckerError>
Get the current spec status.
Returns StatusOutput which is part of the stable public API.
§Errors
Returns error if status generation fails.
Sourcepub fn last_receipt_path(&self) -> Option<PathBuf>
pub fn last_receipt_path(&self) -> Option<PathBuf>
Get the path to the most recent receipt.
Returns None if no receipts have been written.
Sourcepub fn can_run_phase(&self, phase: PhaseId) -> Result<bool>
pub fn can_run_phase(&self, phase: PhaseId) -> Result<bool>
Check if a phase can be run.
Validates that all dependencies are satisfied and have successful receipts.
§Returns
true if the phase can be executed, false otherwise.
Sourcepub fn current_phase(&self) -> Result<Option<PhaseId>>
pub fn current_phase(&self) -> Result<Option<PhaseId>>
Get the current phase state.
Returns the last successfully completed phase, or None if no phases
have been completed.
Sourcepub fn legal_next_phases(&self) -> Result<Vec<PhaseId>>
pub fn legal_next_phases(&self) -> Result<Vec<PhaseId>>
Get legal next phases from current state.
Returns a list of phases that can be validly executed based on the current workflow state.
Sourcepub fn set_config(&mut self, key: &str, value: &str)
pub fn set_config(&mut self, key: &str, value: &str)
Set a configuration option.
Common keys include:
model: LLM model to usephase_timeout: Timeout in secondsapply_fixups: Whether to apply fixups or preview
Sourcepub fn get_config(&self, key: &str) -> Option<&String>
pub fn get_config(&self, key: &str) -> Option<&String>
Get a configuration option.
Returns None if the key is not set.
Sourcepub fn set_dry_run(&mut self, dry_run: bool)
pub fn set_dry_run(&mut self, dry_run: bool)
Enable or disable dry-run mode.
In dry-run mode, phases are simulated without calling the LLM.
Sourcepub fn orchestrator_config(&self) -> &OrchestratorConfig
pub fn orchestrator_config(&self) -> &OrchestratorConfig
Get the current orchestrator configuration.
Returns a reference to the configuration used for phase execution.