# How Openship SystemManager Performs Prerequisite Checks and Automated Installations

> Learn how the Openship SystemManager automates installations and checks prerequisites. Discover its declarative rule engine, state caching, and atomic install-verify cycles for efficient deployments.

- Repository: [oblien/openship](https://github.com/oblien/openship)
- Tags: how-to-guide
- Published: 2026-07-30

---

**The Openship SystemManager orchestrates prerequisite validation and automated installation through a declarative rule engine that maps features to components, caches state for fast-path checks, and executes atomic install-verify cycles protected by concurrency locks.**

The SystemManager in the `oblien/openship` repository serves as the core orchestration layer for self-hosting deployments. It abstracts the complexity of system-level dependencies by automating the detection, validation, and installation of required components. Understanding how Openship SystemManager performs prerequisite checks and automated installations reveals a sophisticated architecture designed for reliability and performance.

## Declarative Prerequisite Mapping

The manager begins by resolving what components are actually needed for your specific runtime mode. In [`packages/adapters/src/system/setup.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/system/setup.ts), the `resolveRules()` method (lines 65‑82) returns an array of **PrerequisiteRule** objects that map high-level features—such as `build`, `deploy`, or `edge`—to their underlying system components like `git`, `docker`, or `edge`.

These rules differ between **docker** and **bare** runtime modes, allowing the same manager logic to support containerized and native deployments without code changes. The `resolveRequired()` method (lines 85‑88) then flattens these rules into a concrete list of components that must be present for the selected mode.

## Initialization and State Management

When instantiated, the **SystemManager** constructor (lines 30‑39) initializes several critical dependencies:

- The runtime mode (`docker` or `bare`) and a command **executor** (typically `LocalCommandExecutor`)
- Cached rule and component lists to avoid repeated resolution
- A **SetupStateStore** instance (defaulting to `FileStateStore`) for persisting component health across restarts
- An optional **ProvisionLock** to serialize concurrent installation attempts

This design ensures that the manager maintains both volatile in-memory caches (`cachedState`) and durable persistence for long-running server processes.

## Fast-Path Readiness Verification

Performance is prioritized through aggressive caching. The `isReady()` method (lines 53‑66) implements a fast-path check that reads the cached **SetupState**. If `setupComplete` is true and the cache is fresh, it returns `true` instantly without touching the filesystem or network.

If the cache exceeds the **CACHE_TTL_MS** (24‑hour TTL), the method triggers a background `verify()` call while still returning `true` to avoid blocking hot paths. This stale-while-revalidate pattern ensures that production servers remain responsive while eventually converging on accurate system state.

## Component Health Verification

When explicit validation is required, the manager delegates to the low-level check module in [`packages/adapters/src/system/checks.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/system/checks.ts). The `checkAll()` method (lines 78‑92) iterates every registered component, executes health probes via `checkAll(this.executor)`, and marks missing components in the cached state.

For mode-specific validation, `checkRequired()` (lines 95‑103) limits the scope to components returned by `resolveRequired()`. Feature-level granularity is provided by `checkFeature()` (lines 108‑124), which first consults the cache and falls back to live `checkComponents` calls only when necessary. Hard dependencies can enforce readiness through `requireFeature()` (lines 126‑131), which throws immediately if prerequisites are unmet.

## Atomic Installation Workflows

Automatic remediation follows a strict **check‑install‑re‑validate** cycle. The `ensureFeature()` method (lines 166‑184) checks feature readiness, invokes `ensureNamedComponents` to install any missing dependencies, and then re-verifies the final state.

The `ensureNamedComponents` method (lines 445‑486) is the critical section protected by the optional **ProvisionLock**. It executes:

1. Current health assessment
2. Bulk installation via `installMany` for missing components
3. Post-installation verification
4. Cache state updates

If any installer fails, the entire transaction throws, preventing partial system states.

Individual component installation is handled by `installComponent()` (lines 113‑122), which looks up concrete implementations from the **COMPONENT_INSTALLERS** registry defined in [`packages/adapters/src/system/installer.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/system/installer.ts). This registry pattern enables OS-specific install scripts while keeping the manager agnostic of platform details.

## Complete Setup Orchestration

The `setup()` method (lines 131‑187) serves as the entry point for the dashboard wizard found in `apps/dashboard/src/app/(dashboard)/servers/_components/server-setup-wizard.tsx`. This method:

1. Logs the required component list for the selected mode
2. Runs `checkRequired()` to discover gaps
3. Executes `installMany()` to provision missing components
4. Validates the final aggregated state
5. Marks the setup as complete via `markSetupComplete()`

This orchestration provides the seamless one-click setup experience in the Openship dashboard.

## State Persistence Layer

Durability is handled through the `SetupStateStore` abstraction defined in [`packages/adapters/src/system/state.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/system/state.ts). The manager synchronizes memory and disk via `loadState()`, `updateStateFromChecks()` (lines 224‑260), and component-specific markers like `markComponentInstalled()`. The default `FileStateStore` implementation persists JSON state to disk, though the abstraction allows for database-backed stores in clustered deployments.

## Practical Implementation Example

```typescript
// Initialize the manager for Docker-based deployments
import { SystemManager } from "packages/adapters/src/system/setup";
import { LocalCommandExecutor } from "packages/adapters/src/types";

const executor = new LocalCommandExecutor();
const manager = new SystemManager("docker", { executor });

// Fast-path cached check
const ready = await manager.isReady(); // boolean

// Automatic remediation for deployment features
await manager.ensureFeature("deploy", (log) => console.log(log.message));

// Full wizard execution with progress logging
await manager.setup((log) => console.log(`[${log.level}] ${log.message}`));

```

## Summary

- **Declarative prerequisite mapping** via `PrerequisiteRule` separates feature requirements from component implementations, supporting both Docker and bare-metal modes without logic duplication.
- **Cache-first architecture** with a 24‑hour TTL provides sub-millisecond readiness checks while guaranteeing eventual consistency through background revalidation.
- **Concurrency safety** is enforced by an optional `ProvisionLock` that serializes the entire check-install-validate block across multiple processes or requests.
- **Atomic installation cycles** ensure that partial failures never leave the system in an inconsistent state.
- **Extensible installer plumbing** through the `COMPONENT_INSTALLERS` registry allows platform-specific implementations without modifying core manager logic.

## Frequently Asked Questions

### What is the difference between checkFeature and ensureFeature?

The `checkFeature()` method performs read-only validation against cached or live component state, returning a readiness result without side effects. In contrast, `ensureFeature()` is a write-capable operation that triggers automatic installation of missing components via the `ensureNamedComponents` critical section, followed by re-validation to confirm success.

### How does SystemManager handle concurrent installation requests?

The manager accepts an optional `ProvisionLock` in its constructor. When provided, `ensureNamedComponents()` acquires this lock before entering the check-install-validate cycle, ensuring that only one installation process runs at a time per host. This prevents race conditions when multiple deployments target the same server simultaneously.

### What happens if a prerequisite check cache is older than 24 hours?

When `isReady()` detects a stale cache (exceeding `CACHE_TTL_MS`), it triggers a background `verify()` task to refresh component health while immediately returning `true` based on the existing cached state. This stale-while-revalidate approach keeps request latency low while ensuring that long-running servers eventually detect system changes.

### Where are the concrete installer implementations defined?

Concrete installers are registered in the `COMPONENT_INSTALLERS` map within [`packages/adapters/src/system/installer.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/system/installer.ts). Each entry maps a component name (e.g., `docker`, `git`) to an async installer function that handles OS-specific logic. The `SystemManager` invokes these through `runInstaller()` without hard-coding platform dependencies, enabling support for diverse operating systems.