Skip to main content

Set up local infrastructure

Use SHAFT's setup surface to inspect external prerequisites or install supported tools into SHAFT-owned user directories. The safe default is EXTERNAL: SHAFT diagnoses the host without downloading, installing, or starting anything.

The setup catalog includes web, mobile, Grid, reporting, OCR, Healenium, ReportPortal, BrowserStack Local, agent-tool, and local-AI profiles. Provider-backed managed installation includes REPORTING, PLAYWRIGHT, MOBILE_ANDROID, MOBILE_IOS, MOBILE_WINDOWS, SELENIUM_GRID, HEALENIUM, REPORT_PORTAL, BROWSERSTACK_LOCAL, and AGENT_TOOLS. LOCAL_AI uses the existing ServiceLoader provider. WEB_LOCAL has no provider: Selenium Manager and a host browser remain the local-web path.

Reporting uses SHAFT's pinned, SHA-256-verified portable Node and adds Allure 3. Playwright adds reviewed Chromium, Firefox, WebKit, and FFmpeg payloads. Android uses the same portable Node owner and adds a reviewed Android SDK, Appium project, emulator, and SHAFT-owned virtual device.

Inspect the catalog and host

Install shaft-cli through the shaft-cli installation flow, then list the setup profiles:

shaft-cli setup catalog
shaft-cli setup doctor --profile REPORTING
shaft-cli setup status --profile REPORTING

Add --json to catalog, doctor, status, or verify when a script needs a versioned machine-readable result. Readiness commands exit with 0 when ready and 3 when the profile is missing or degraded.

Review and approve an installation

Create an exact plan before allowing any mutation. Use an absolute path for the plan file:

shaft-cli setup plan \
--profile REPORTING \
--mode MANAGED \
--output /absolute/path/reporting-plan.json

Review the JSON plan and copy the printed sha256: digest. Apply that exact plan with the same policy options used to create it:

shaft-cli setup install \
--plan /absolute/path/reporting-plan.json \
--approve sha256:<digest>

shaft-cli setup verify --profile REPORTING

apply and update are aliases for install. SHAFT rejects a changed or stale plan, a mismatched policy, a missing license acceptance, or an artifact whose checksum does not match before publishing it as installed.

warning

Treat the plan digest as a one-plan approval, not a general consent switch. Changing a version, source, checksum, destination, timeout, or policy option changes the digest and requires a new review.

Preview managed local AI

Not in a published release yet

The LOCAL_AI managed provider is available on SHAFT_ENGINE main after engine PR #4921. The delivered merge commit is a585b41980f78315aa353003ce5b5891f350a6a1. Use this workflow with a source build until a containing SHAFT release is published.

Use this profile when you want SHAFT to own a pinned llama.cpp runtime and a reviewed GGUF model. You do not need a model manager, container, service, endpoint, credential, administrator install, or machine-wide daemon. SHAFT starts an authenticated loopback child process only when an approved AI request needs it.

SHAFT continuously measures aggregate resident memory for the managed process tree. If the tree exceeds 4 GiB, or its live memory inventory cannot be read safely, SHAFT retires the session and returns the request's deterministic fallback.

Start with explicit provisioning. Enable managed local processing, select the manual compact candidate, and prevent an inference request from downloading missing artifacts before you review the setup plan:

src/main/resources/properties/custom.properties
managedLocalAi.enabled=true
managedLocalAi.transparentProvisioning=false
managedLocalAi.model=qwen3-0.6b-q8_0

Run the shared review flow. Stop after plan, inspect both actions and the printed digest, then install that exact plan:

Review and install managed local AI
shaft-cli setup status --profile LOCAL_AI --mode MANAGED
shaft-cli setup plan \
--profile LOCAL_AI \
--mode MANAGED \
--operation INSTALL \
--output /absolute/path/local-ai-plan.json
shaft-cli setup install \
--plan /absolute/path/local-ai-plan.json \
--approve sha256:<reviewed-digest> \
--accept-license MIT \
--accept-license Apache-2.0
shaft-cli setup verify --profile LOCAL_AI --mode MANAGED
shaft-cli doctor local-ai-status

The plan binds the exact runtime and model URL, version or revision, SHA-256, license, and artifact size. Installation reports phase, completed bytes, total bytes, and integer percentage on stderr, so --json output on stdout stays machine-readable. An interrupted, failed, or cancelled operation returns no receipt; fix the reported condition and retry the same still-current approved plan.

Leave --cache-root and --data-root unset to use the effective managed-local cache and the normal SHAFT data root. If you supply roots, pass both as absolute paths on plan and install, and make --cache-root exactly equal to managedLocalAi.cacheDirectory. SHAFT rejects a different cache instead of provisioning files that inference will not use.

Inspect readiness and privacy-safe diagnostics

Use setup status or setup verify for the two managed targets. Those commands print target readiness version detail. Version is empty unless READY. They report readiness/version/action, not the reviewed pin table.

Use doctor local-ai-status or MCP doctor_managed_local_ai_status for enablement, eligibility, and the DISABLED snapshot. They do not list the reviewed pin table.

The MCP setup equivalents are setup_status, setup_verify, setup_plan, and setup_install. IntelliJ uses those generic MCP setup tools instead of a second lifecycle implementation.

The pin table on this page is the documented inventory. Setup commands do not print revision, license, provenance, size, floors, update, cleanup, or fallback. Diagnostics exclude absolute cache paths, filenames, checksums, executable names, and exact host RAM, CPU, and free-disk values.

warning

Managed-local enablement grants local-processing consent only. It does not grant remote or on-premises processing consent. The compact candidate failed the current recommendation-quality gates, so use it only for manual evaluation and keep deterministic SHAFT results authoritative. managedLocalAi.enabled defaults to false. Do not flip that default to enable managed-local automatically.

Inventory, defaults, and troubleshooting

The pin table on this page is the documented inventory. setup status and setup verify print target readiness version detail even when the cache is missing or the feature is still disabled. Version is empty unless READY. Commands report readiness/version/action, not those pin-table fields:

FieldCompact preview pin
Revisionruntime b10400 / model 23749fefcc72300e3a2ad315e1317431b06b590a
LicenseMIT / Apache-2.0
Provenancegithub.com/ggml-org/llama.cpp and huggingface.co/Qwen/Qwen3-0.6B-GGUF
Sizeplatform runtime archive plus 639446688 model bytes
StorageSHAFT_USER_CACHE — never an absolute cache path
Resourcescompact floor 2 GB RAM, 2 CPUs, 3 GB free disk
Updateexplicit reviewed plan; pin-bound; no silent float
Cleanupowner-manifest only; unknown siblings preserved
Fallbackdeterministic SHAFT result remains authoritative

Release automation cannot float or silently replace model or runtime bytes. A revoked or hash-mismatched artifact stays unpublished; the last good activation remains active. An interrupted upgrade returns no receipt and does not activate the new pair. Offline setup reuses a ready cache and never downloads or substitutes a fallback URL.

Inspect readiness from each setup surface:

SurfaceCommand
CLIshaft-cli setup status --profile LOCAL_AI --mode MANAGED and shaft-cli setup verify --profile LOCAL_AI --mode MANAGED
MCPsetup_status and setup_verify
IntelliJthe generic MCP setup tools; there is no second lifecycle
CI / headlesskeep managedLocalAi.enabled=false; normal Maven never provisions or downloads; always pass -Dallure.automaticallyOpen=false

shaft-cli doctor local-ai-status and doctor_managed_local_ai_status report enablement, eligibility, and the DISABLED snapshot. They do not list the reviewed pin table.

If Maven or CI needs a local-AI assertion, run the unit tests that inspect status, setup, cache, and properties. Do not add a provision or benchmark step to a default pipeline. If a job must stay offline, pass --offline on both plan and install; a missing or revoked pin fails closed.

Clean, update, and roll back

Create and approve a separate plan for every maintenance operation. Clean removes only unchanged installations owned by the current reviewed manifest; changed, unknown, and other-version content is preserved. If changed or unknown owned content blocks cleanup, the command returns a generic failure without a receipt rather than listing each preserved installation:

shaft-cli setup plan \
--profile LOCAL_AI \
--mode MANAGED \
--operation CLEAN \
--output /absolute/path/local-ai-clean.json
shaft-cli setup install \
--plan /absolute/path/local-ai-clean.json \
--approve sha256:<reviewed-digest> \
--accept-license MIT \
--accept-license Apache-2.0

Clean verifies the activation record and every selected installation before it removes anything. If changed or unknown content blocks cleanup, SHAFT preserves the verified active/previous record and its rollback candidate. After the reviewed artifacts clean successfully, SHAFT clears the activation record, so provision and activate two different reviewed pairs again before expecting ROLLBACK planning to succeed.

For an update, create a new INSTALL plan from the current release and apply it with setup install or its setup update alias. SHAFT provisions the new content-addressed pair before activation and retains one exact prior reviewed pair.

Rollback is available only after two different reviewed pairs have activated successfully and the prior pair still verifies exactly. It swaps the cached active and previous pairs without downloading or deleting artifacts:

shaft-cli setup plan \
--profile LOCAL_AI \
--mode MANAGED \
--operation ROLLBACK \
--output /absolute/path/local-ai-rollback.json
shaft-cli setup install \
--plan /absolute/path/local-ai-rollback.json \
--approve sha256:<reviewed-digest> \
--accept-license MIT \
--accept-license Apache-2.0

SHAFT rechecks the approved candidate, complete owned file inventories, and current host eligibility under the cache lock before changing activation. A missing, changed, corrupt, or newly ineligible prior pair fails without a rollback receipt.

Install managed Android and Appium

Not in a published release yet

The MOBILE_ANDROID provider is available on SHAFT_ENGINE main after engine PR #4913 and its readiness follow-up #4917. Use these commands with a source build until a containing SHAFT release is published.

Use this profile when you want SHAFT to own one local Android emulator and its Appium server. The release plan contains exactly six ordered actions:

  1. Node 24.19.0.
  2. Appium 3.6.0.
  3. Inspector plugin 2026.7.1.
  4. UiAutomator2 8.2.2.
  5. Android command-line tools 15859902, platform-tools, Emulator, API 36, build-tools 36.0.0 with aapt2, and a host-compatible Google APIs image.
  6. A SHAFT-owned Pixel 8 AVD.

SHAFT verifies the official command-line-tools archive hash and the packaged Appium dependency lock before publication. It runs npm inside a versioned SHAFT project, not as a global install, and never enables Appium relaxed security for the owned server.

Check platform prerequisites

Install a compatible JDK and enable hardware virtualization for your host before planning a runtime. On Linux, grant the current user access to KVM. On Windows, enable a supported Android Emulator hypervisor path. On macOS, run on a host that can use Apple's virtualization support. SHAFT diagnoses these conditions with emulator -accel-check; it does not elevate, enable firmware features, change group membership, install host drivers, or edit shell profiles.

Keep loopback ports 5554 and 5555 free for the owned emulator. The default Appium port is 4723; choose another free port with --port when creating the plan. The selected system-image ABI must match the host architecture.

Review the Android plan and license

Run the shared command sequence below. Stop after plan, inspect all six actions and the printed digest, then continue with that exact digest:

Prepare and run managed Android
shaft-cli setup status --profile MOBILE_ANDROID --mode MANAGED
shaft-cli setup plan \
--profile MOBILE_ANDROID \
--mode MANAGED \
--output /absolute/path/android-plan.json
shaft-cli setup install \
--plan /absolute/path/android-plan.json \
--approve sha256:<reviewed-digest> \
--accept-license android-sdk-license
shaft-cli setup verify --profile MOBILE_ANDROID --mode MANAGED
shaft-cli setup start \
--plan /absolute/path/android-plan.json \
--approve sha256:<reviewed-digest> \
--accept-license android-sdk-license
shaft-cli setup logs --profile MOBILE_ANDROID
shaft-cli setup stop --profile MOBILE_ANDROID

android-sdk-license is an explicit approval identifier. Omitting it or supplying a different identifier fails before SHAFT creates setup roots, starts a process, or contacts the network. SHAFT supplies consent only to the reviewed package installation; it does not run a blanket sdkmanager --licenses acceptance.

Use these selectors on doctor, status, plan, verify, start, logs, or stop. You may repeat them on install, but every repeated value must match the plan:

OptionRelease defaultConstraint
--api-level36Must match the release manifest.
--device-profilepixel_8Must match the release manifest.
--image-taggoogle_apisMust match the release manifest.
--abihostResolves to x86_64 or arm64-v8a for the current host.
--avd-nameshaft_pixel_8_api_36Use a safe Android identifier.
--ram-mb4096Choose 2048 through 32768 MB.
--cores2Choose 1 through 16 cores.
--port4723Choose 1024 through 65535, excluding 5554 and 5555.

The persisted plan remains authoritative. Install reconstructs the typed request from the plan and rejects changed, missing, duplicate, or unknown selection metadata.

Use the cache and offline mode

SHAFT stores verified downloads and npm cache data under its cache root. It stores versioned Node, Appium, Android SDK, AVD, receipts, leases, and logs under its data root. Set both --cache-root and --data-root to absolute, dedicated user paths if you override the defaults.

Pass --offline to both plan and install when network access is prohibited. The Android provider currently accepts offline installation only when every required managed component is already present and verifies exactly. A cold, partial, corrupt, wrong-version, or linked state fails before npm, sdkmanager, or another setup process starts. Run one approved online install to populate the managed state before relying on offline reuse.

Start, inspect, and recover the owned runtime

start requires the reviewed plan, matching approval, accepted license, and a compatible final receipt. It starts the emulator first and waits for the exact serial, Android boot completion, package manager, selected AVD, and system image. It then starts Appium on 127.0.0.1 and accepts it only when /status reports Appium 3.6.0.

Compatible callers share a durable lease and increment its reference count. The final release or setup stop shuts down Appium, then the emulator, after validating each PID, start instant, command, root, and endpoint. SHAFT never adopts or kills an unknown process. setup logs reads only the two owned log paths and rejects a file larger than 2 MiB.

If startup fails after the emulator launches, SHAFT stops only the processes started by that call and retains their logs. If a lease is partially alive or its identity differs from the live process, preserve the lease and logs and inspect them before manual recovery. If both processes are gone, the next start removes the stale lease. Resolve occupied ports, acceleration failures, or wrong SDK/AVD revisions, then retry the same reviewed plan.

Use the typed Java API

Use AndroidSetupRequest with the additive SHAFT.Infrastructure overloads. The first phase writes a plan for review:

PlanManagedAndroid.java
import com.shaft.driver.SHAFT;
import com.shaft.infrastructure.AndroidSetupRequest;
import com.shaft.infrastructure.SetupMode;
import com.shaft.infrastructure.SetupOptions;
import com.shaft.infrastructure.SetupPlan;
import com.shaft.infrastructure.SetupPlanStore;
import com.shaft.infrastructure.SetupProfile;
import com.shaft.infrastructure.ShaftCachePaths;

import java.nio.file.Path;

public final class PlanManagedAndroid {
public static void main(String[] args) throws Exception {
SetupOptions options = SetupOptions
.defaults(SetupProfile.MOBILE_ANDROID, ShaftCachePaths.current())
.withMode(SetupMode.MANAGED);
AndroidSetupRequest request = AndroidSetupRequest.defaults();
SetupPlan plan = SHAFT.Infrastructure.plan(options, request);
SetupPlanStore.write(Path.of(args[0]).toAbsolutePath(), plan);
System.out.println(plan.digest());
}
}

Run installation and startup only after a separate review supplies the digest:

RunReviewedAndroid.java
import com.shaft.driver.SHAFT;
import com.shaft.infrastructure.AndroidSetupRequest;
import com.shaft.infrastructure.ManagedEnvironment;
import com.shaft.infrastructure.SetupApproval;
import com.shaft.infrastructure.SetupMode;
import com.shaft.infrastructure.SetupOptions;
import com.shaft.infrastructure.SetupPlan;
import com.shaft.infrastructure.SetupPlanStore;
import com.shaft.infrastructure.SetupProfile;
import com.shaft.infrastructure.ShaftCachePaths;

import java.nio.file.Path;
import java.time.Instant;
import java.util.Set;

public final class RunReviewedAndroid {
public static void main(String[] args) throws Exception {
SetupPlan plan = SetupPlanStore.read(Path.of(args[0]).toAbsolutePath());
AndroidSetupRequest request = AndroidSetupRequest.fromPlan(plan);
SetupOptions options = SetupOptions
.defaults(SetupProfile.MOBILE_ANDROID, ShaftCachePaths.current())
.withMode(SetupMode.MANAGED);
SetupApproval approval = new SetupApproval(
System.getenv("SHAFT_APPROVED_SETUP_DIGEST"),
Instant.now(),
Set.of("android-sdk-license"));

SHAFT.Infrastructure.install(plan, approval, options, request);
try (ManagedEnvironment runtime =
SHAFT.Infrastructure.start(plan, approval, options, request)) {
System.out.println(runtime.endpoint().orElseThrow());
}
}
}

Closing ManagedEnvironment releases this caller's lease. Another compatible caller can keep the same runtime alive until its own release.

Install managed iOS and Windows Appium drivers

Use MOBILE_IOS on macOS to install SHAFT's pinned Appium, Inspector, and XCUITest driver bundle. Install full Xcode 14.3 or newer and create at least one Simulator device first. SHAFT diagnoses those host prerequisites but does not install Xcode, download Simulator runtimes, or change signing and device trust settings.

shaft-cli setup plan \
--profile MOBILE_IOS \
--mode MANAGED \
--output /absolute/path/mobile-ios-plan.json
shaft-cli setup install \
--plan /absolute/path/mobile-ios-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile MOBILE_IOS --mode MANAGED

The default iOS plan binds the existing Simulator selection and Appium port 4723. Java callers can bind one exact available Simulator UDID and a different loopback port; reuse the same reviewed plan for installation.

Use MOBILE_WINDOWS on Windows to install SHAFT's pinned Appium, Inspector, and Windows driver bundle. Enable Developer Mode and install WinAppDriver 1.2.1 separately before planning. SHAFT verifies that prerequisite but never runs the privileged WinAppDriver MSI or changes Developer Mode.

shaft-cli setup plan `
--profile MOBILE_WINDOWS `
--mode MANAGED `
--output C:\plans\mobile-windows-plan.json
shaft-cli setup install `
--plan C:\plans\mobile-windows-plan.json `
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile MOBILE_WINDOWS --mode MANAGED

Both profiles keep their npm projects in separate versioned SHAFT roots. A lock checksum, direct package checksum, selected host metadata, execution policy, and destination roots are part of the approved plan. External mode remains diagnostic-only and creates no setup roots.

Start Appium without owning the host device

start launches only the SHAFT-owned Appium process from a verified MOBILE_IOS or MOBILE_WINDOWS receipt. It does not boot or shut down a Simulator. It does not launch WinAppDriver and does not stop an existing WinAppDriver process. Pre-boot the Simulator yourself. Keep Developer Mode and WinAppDriver 1.2.1 already installed on Windows.

Those start rules are always in force. The engine also has optional live host tests that skip unless you set SHAFT_SETUP_IOS_ACCEPTANCE=true and SHAFT_SETUP_IOS_UDID to an existing booted Simulator, or SHAFT_SETUP_WINDOWS_ACCEPTANCE=true on a Windows host that already has WinAppDriver. The values 1 and yes do not enable those tests. The variables do not change shaft-cli setup start.

Install managed Selenium Grid

Not in a published release yet

The SELENIUM_GRID provider is available on SHAFT_ENGINE main after engine PR #5042. Use these commands with a source build until a containing SHAFT release is published.

Use this profile when you want SHAFT to own a local Selenium Grid compose project. Docker 26.1.4+ is a host prerequisite. SHAFT diagnoses Docker; it does not install the engine or daemon.

The release plan binds image tag 4.47.0-20260808 for selenium/hub, selenium/node-chrome, selenium/node-edge, and selenium/node-firefox. The compose project name is shaft-selenium-grid. CLI planning uses the release defaults: hub port 4444, one Chrome replica, zero Edge replicas, and zero Firefox replicas. Bind a different port or replica count through Java selection components such as port_4445 and chrome_2. Those tokens are not CLI flags.

SHAFT never sets container_name and never adopts an unknown compose project or port.

shaft-cli setup status --profile SELENIUM_GRID --mode MANAGED
shaft-cli setup plan \
--profile SELENIUM_GRID \
--mode MANAGED \
--output /absolute/path/selenium-grid-plan.json
shaft-cli setup install \
--plan /absolute/path/selenium-grid-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile SELENIUM_GRID --mode MANAGED
shaft-cli setup start \
--plan /absolute/path/selenium-grid-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup logs --profile SELENIUM_GRID
shaft-cli setup stop \
--plan /absolute/path/selenium-grid-plan.json \
--approve sha256:<reviewed-digest>

start brings up only the owned shaft-selenium-grid project and accepts the hub when /wd/hub/status is healthy. stop runs compose down for that project only.

Install managed Healenium

Not in a published release yet

The HEALENIUM provider is available on SHAFT_ENGINE main after engine PR #5044. Use these commands with a source build until a containing SHAFT release is published.

Use this profile when tests need a local Healenium backend. Docker 26.1.4+ is a host prerequisite. SHAFT diagnoses Docker; it does not install the engine or daemon. The release plan pins healenium/hlm-backend:3.4.6, healenium/hlm-selector-imitator:1.4, and postgres:15.5-alpine in compose project shaft-healenium. CLI defaults are backend port 7878 and imitator port 8000. Bind different ports through Java selection components backend_7879 and imitate_8001; the two ports must differ. Those tokens are not CLI flags.

shaft-cli setup status --profile HEALENIUM --mode MANAGED
shaft-cli setup plan \
--profile HEALENIUM \
--mode MANAGED \
--output /absolute/path/healenium-plan.json
shaft-cli setup install \
--plan /absolute/path/healenium-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile HEALENIUM --mode MANAGED
shaft-cli setup start \
--plan /absolute/path/healenium-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup logs --profile HEALENIUM
shaft-cli setup stop \
--plan /absolute/path/healenium-plan.json \
--approve sha256:<reviewed-digest>

Point SHAFT.Properties.healenium at localhost and the reviewed backend port. See self-healing locators for the opt-in engine property.

Install managed ReportPortal

Not in a published release yet

The REPORT_PORTAL provider is available on SHAFT_ENGINE main after engine PR #5046. Use these commands with a source build until a containing SHAFT release is published.

Use this profile only for local development. SHAFT owns an official-core ReportPortal compose project named shaft-reportportal and does not start the analyzer. Docker 26.1.4+ is a host prerequisite. SHAFT diagnoses Docker; it does not install the engine or daemon. The CLI default UI port is 8080. Bind a different UI port through Java selection component ui_8081. That token is not a CLI flag.

shaft-cli setup status --profile REPORT_PORTAL --mode MANAGED
shaft-cli setup plan \
--profile REPORT_PORTAL \
--mode MANAGED \
--output /absolute/path/reportportal-plan.json
shaft-cli setup install \
--plan /absolute/path/reportportal-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile REPORT_PORTAL --mode MANAGED
shaft-cli setup start \
--plan /absolute/path/reportportal-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup logs --profile REPORT_PORTAL
shaft-cli setup stop \
--plan /absolute/path/reportportal-plan.json \
--approve sha256:<reviewed-digest>

The stack uses official ReportPortal local-dev defaults. Change those credentials before exposing the UI beyond loopback.

Install managed BrowserStack Local

Not in a published release yet

The BROWSERSTACK_LOCAL provider is available on SHAFT_ENGINE main after engine PR #5048 and stop-until-dead follow-up #5049. Use these commands with a source build until a containing SHAFT release is published.

Use this profile when cloud sessions need a SHAFT-owned BrowserStack Local tunnel to a private network. The plan pins official BrowserStack Local v8.9 archives for Windows, Linux x64, and macOS. Linux ARM64 has no versioned v8.9 archive; use x64 or a later pin.

shaft-cli setup status --profile BROWSERSTACK_LOCAL --mode MANAGED
shaft-cli setup plan \
--profile BROWSERSTACK_LOCAL \
--mode MANAGED \
--output /absolute/path/browserstack-local-plan.json
shaft-cli setup install \
--plan /absolute/path/browserstack-local-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile BROWSERSTACK_LOCAL --mode MANAGED

Set BROWSERSTACK_ACCESS_KEY in the environment before start. Do not put the key in the plan file or in a checked-in properties example.

shaft-cli setup start \
--plan /absolute/path/browserstack-local-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup logs --profile BROWSERSTACK_LOCAL
shaft-cli setup stop \
--plan /absolute/path/browserstack-local-plan.json \
--approve sha256:<reviewed-digest>

stop waits until the owned process is dead. A later start then cannot race the dying tunnel.

See BrowserStack sessions for direct cloud sessions and the optional SDK module.

Diagnose agent tools

Not in a published release yet

The AGENT_TOOLS provider is available on SHAFT_ENGINE main after engine PR #5052. Use these commands with a source build until a containing SHAFT release is published.

Use this profile to diagnose host agent prerequisites. JAVA, MAVEN, PYTHON, and NODE stay diagnose-only: Java 25+, Maven 3.9.0+, Python 3.10+, and Node 20+. SHAFT does not install those host tools.

In MANAGED mode the AGENT_CLI action writes a pinned agent-clients.json that detects gh. It does not download vendor CLIs.

shaft-cli setup status --profile AGENT_TOOLS --mode MANAGED
shaft-cli setup plan \
--profile AGENT_TOOLS \
--mode MANAGED \
--output /absolute/path/agent-tools-plan.json
shaft-cli setup install \
--plan /absolute/path/agent-tools-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile AGENT_TOOLS --mode MANAGED

start and stop are unsupported. Install a missing JDK, Maven, Python, or Node yourself, then rerun status or verify.

Install managed Playwright browsers

Not in a published release yet

The PLAYWRIGHT provider is tracked by engine PR #4922. Use these commands with a source build until a containing SHAFT release is published.

Use the managed profile when local Playwright tests need SHAFT-owned browser payloads. The plan couples Playwright Java 1.62.0 to Chromium revision 1234, Firefox revision 1538, WebKit revision 2336, FFmpeg revision 1011, and the shared Node 24.19.0 owner. Each official archive URL, size, and SHA-256 digest is part of the reviewed release manifest and plan.

Run the shared command sequence. Stop after plan, inspect all five actions and the printed digest, then install that exact plan:

Prepare managed Playwright browsers
shaft-cli setup status --profile PLAYWRIGHT --mode MANAGED
shaft-cli setup plan \
--profile PLAYWRIGHT \
--mode MANAGED \
--output /absolute/path/playwright-plan.json
shaft-cli setup install \
--plan /absolute/path/playwright-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile PLAYWRIGHT --mode MANAGED

SHAFT downloads each archive through the verified artifact store first. It then points Playwright's downloader at a temporary 127.0.0.1 mirror that serves only those verified files. Setup never runs install-deps, sudo, apt, dnf, brew, a GUI installer, or a package-manager elevation flow. Install required host libraries separately when a Linux browser diagnostic reports a missing shared library.

The release accepts Windows x64 or ARM64, Ubuntu 24.04 x64, and macOS 15 on x64 or ARM64. It rejects a different Linux distribution, Ubuntu release, macOS major version, or unsupported architecture instead of substituting a nearby browser build.

Pass --offline to both plan and install to prohibit network access. A warm verified artifact cache or a compatible published receipt can be reused. A cold, incomplete, corrupt, wrong-version, or linked state fails without an outbound fallback or partial final receipt.

Configure the engine to consume the reviewed installation:

src/main/resources/properties/custom.properties
infrastructure.mode=MANAGED
infrastructure.profile=PLAYWRIGHT
infrastructure.cacheDirectory=/absolute/path/shaft-playwright-cache

playwright.connectionMode=local
playwright.channel=
playwright.browserName=chromium
headlessExecution=true

Use an absolute cache directory. For a local session with no channel override, SHAFT validates the compatible receipt and supplies the owned browser root only to the Playwright child process. It does not install a missing browser during driver creation and does not change the parent process environment.

An explicit remote connection, Chromium channel, or existing PLAYWRIGHT_BROWSERS_PATH wins over managed lookup. This keeps caller-owned browser paths and remote endpoints unchanged.

Install managed Lighthouse

Not released

This workflow depends on SHAFT Engine issue #4884. It is not yet available on SHAFT_ENGINE main or in a published SHAFT release. Keep using the current Lighthouse flow until a release that contains the managed LIGHTHOUSE provider is available.

Install the LIGHTHOUSE profile before a test calls generateLightHouseReport(). SHAFT manages its own Node 24.19.0 and Lighthouse 13.4.1 under the configured tool root. It does not use a global Node or npm installation.

Prepare managed Lighthouse
shaft-cli setup status --profile LIGHTHOUSE
shaft-cli setup plan \
--profile LIGHTHOUSE \
--mode MANAGED \
--output /absolute/path/lighthouse-plan.json
shaft-cli setup install \
--plan /absolute/path/lighthouse-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile LIGHTHOUSE

Stop after plan and review the JSON plus its printed digest before running install. The plan binds the exact Node artifact, Lighthouse package archive, bundled dependency lock, destinations, and policy. Report generation only uses an already verified installation; it never installs a missing toolchain.

For a cold offline install, pass --offline to both plan and install. The SHAFT cache must already contain the verified Node and Lighthouse artifacts and the complete transitive npm cache required by the bundled lock. An already verified managed installation can be reused without those cached downloads. A missing or corrupt entry needed by a cold install fails without network access or a partially published Lighthouse installation.

Use the default SHAFT roots for this preview. The CLI can bind separate custom cache and data roots, but the Browser Actions runtime currently exposes only infrastructure.cacheDirectory and cannot reproduce every such layout.

Preview: managed OCR setup

Not released

This workflow is not yet available on SHAFT_ENGINE main or in a published SHAFT release. Keep using the current OCR first-use model flow until a release that contains the complete setup stack is available.

The preview defaults to the eng and ara model bundle. Omit --language to use that bundle, or repeat exact Tesseract codes on plan and selected status/verify commands. Install recovers the selected languages from the reviewed plan:

shaft-cli setup plan --profile OCR --mode MANAGED \
--language fra --language deu \
--output /absolute/path/ocr-plan.json
shaft-cli setup install --plan /absolute/path/ocr-plan.json \
--approve sha256:<reviewed-digest>
shaft-cli setup verify --profile OCR --language fra --language deu

The reviewed actions bind the normalized component set. Repeating --language during install is optional and must match when supplied. The planned OCR provider enforces --offline: it can accept a verified installed model, legacy model, or artifact-cache entry without network access. It has no start, stop, or logs lifecycle.

Keep policy options identical

Plan and install accept the same execution policy:

OptionDefaultEffect
--offlinefalseRequire verified cached artifacts and disable network access.
--auto-startfalseBind a startup request for providers that own a service.
--prefer-system-tools=true|falsetrueBind whether a provider may prefer a compatible host tool.
--reuse-owned-processes=true|falsetrueBind whether a provider may reuse compatible SHAFT-owned processes.
--startup-timeout <duration>PT2MBind a positive ISO-8601 startup timeout for providers with lifecycle support.
--shutdown-timeout <duration>PT30SBind a positive ISO-8601 shutdown timeout for providers with lifecycle support.

Pass any non-default option to both commands. You may also pass an absolute --cache-root and --data-root pair to both commands; SHAFT rejects a single root or a relative path.

The current REPORTING provider enforces --offline. It has no owned service, so auto-start, process reuse, and lifecycle timeouts are policy-bound for provider parity but do not change a reporting install. Reporting installs SHAFT-owned portable tools rather than adopting system Node or Allure. The unreleased LIGHTHOUSE provider follows the same lifecycle shape.

warning

Custom roots become mutable SHAFT-owned storage. Use dedicated, user-scoped directories. Do not point them at a repository, shared or system directory, or a path reached through a symlink alias.

Use the Java API

Configure the same policy through SHAFT.Properties.infrastructure, then plan and explicitly approve the immutable result:

ReportingInfrastructure.java
import com.shaft.driver.SHAFT;
import com.shaft.infrastructure.SetupMode;
import com.shaft.infrastructure.SetupPlan;
import com.shaft.infrastructure.SetupPlanStore;
import com.shaft.infrastructure.SetupProfile;

import java.nio.file.Path;

public final class ReportingInfrastructure {
public static void main(String[] args) throws Exception {
SHAFT.Properties.infrastructure.set()
.profile(SetupProfile.REPORTING)
.mode(SetupMode.MANAGED)
.offline(false)
.autoStart(false);

SetupPlan plan = SHAFT.Infrastructure.plan();
SetupPlanStore.write(Path.of(args[0]).toAbsolutePath(), plan);

// Stop this phase and review the written JSON plus this digest.
System.out.println(plan.digest());
}
}

Run the mutation in a separate phase. Supply the digest you reviewed instead of deriving it from a newly generated plan:

InstallReviewedReportingPlan.java
import com.shaft.driver.SHAFT;
import com.shaft.infrastructure.SetupApproval;
import com.shaft.infrastructure.SetupMode;
import com.shaft.infrastructure.SetupPlan;
import com.shaft.infrastructure.SetupPlanStore;
import com.shaft.infrastructure.SetupProfile;
import com.shaft.infrastructure.SetupReceipt;

import java.nio.file.Path;
import java.time.Instant;
import java.util.Set;

public final class InstallReviewedReportingPlan {
public static void main(String[] args) throws Exception {
SetupPlan plan = SetupPlanStore.read(Path.of(args[0]).toAbsolutePath());
String reviewedDigest = System.getenv("SHAFT_APPROVED_SETUP_DIGEST");

// Recreate every policy value used by the planning phase.
SHAFT.Properties.infrastructure.set()
.profile(SetupProfile.REPORTING)
.mode(SetupMode.MANAGED)
.offline(false)
.autoStart(false);

if (!plan.executionPolicyDigest().equals(
SHAFT.Infrastructure.options().policyDigest())) {
throw new IllegalStateException(
"Current setup policy differs from the reviewed plan");
}

SetupApproval approval = new SetupApproval(
reviewedDigest, Instant.now(), Set.of());
SetupReceipt receipt = SHAFT.Infrastructure.install(plan, approval);
System.out.println(receipt.planDigest());
}
}

Use SHAFT.Infrastructure.catalog(), doctor(), status(), and verify() for read-only inspection. install(...) and start(...) require both the exact plan and its approval; there is no unapproved mutation overload.

Use an absolute plan path in both Java phases. Reproduce every property and path from the planning phase before installation; schema 3 rejects even a single policy or destination difference.

The configuration defaults are:

infrastructure.mode=EXTERNAL
infrastructure.profile=REPORTING
infrastructure.cacheDirectory=
infrastructure.offline=false
infrastructure.autoStart=false
infrastructure.preferSystemTools=true
infrastructure.reuseOwnedProcesses=true
infrastructure.startupTimeout=PT2M
infrastructure.shutdownTimeout=PT30S

Set infrastructure.cacheDirectory only to an absolute path. An empty value uses the platform-specific SHAFT cache and application-data locations.

Understand remote precedence

An explicit remote execution address keeps endpoint-backed profiles external, even when infrastructure.mode=MANAGED. This applies to web, Selenium Grid, mobile, and Healenium profiles, so a remote test configuration cannot unexpectedly provision local infrastructure. It does not change unrelated profiles such as REPORTING or LIGHTHOUSE.

Interpret CLI failures

Exit codeMeaning
0Ready or successful.
2Invalid input, policy, or approval.
3Missing or degraded readiness.
4No provider supports the requested operation.
5Execution or integrity failure.

An install is atomic per action, not across the entire plan. If a later action fails, an earlier verified action can remain installed while the final profile receipt is absent. Fix the failure and retry the same approved plan; SHAFT re-verifies compatible completed state before continuing.

If setup reports that both an artifact destination and its .quarantine recovery file exist, preserve both files and stop. Verify each against the reviewed action checksum, then deliberately retain the valid copy before retrying. Never blindly delete the quarantine: it may be the only known-good pre-replacement artifact.

start and stop return unsupported for profiles without an owned service. SHAFT does not adopt or stop an unknown process. Use shaft-cli setup logs --profile REPORTING to read an existing provider log; it returns 3 when no owned log exists.