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.
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
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:
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:
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.
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:
| Field | Compact preview pin |
|---|---|
| Revision | runtime b10400 / model 23749fefcc72300e3a2ad315e1317431b06b590a |
| License | MIT / Apache-2.0 |
| Provenance | github.com/ggml-org/llama.cpp and huggingface.co/Qwen/Qwen3-0.6B-GGUF |
| Size | platform runtime archive plus 639446688 model bytes |
| Storage | SHAFT_USER_CACHE — never an absolute cache path |
| Resources | compact floor 2 GB RAM, 2 CPUs, 3 GB free disk |
| Update | explicit reviewed plan; pin-bound; no silent float |
| Cleanup | owner-manifest only; unknown siblings preserved |
| Fallback | deterministic 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:
| Surface | Command |
|---|---|
| CLI | shaft-cli setup status --profile LOCAL_AI --mode MANAGED and shaft-cli setup verify --profile LOCAL_AI --mode MANAGED |
| MCP | setup_status and setup_verify |
| IntelliJ | the generic MCP setup tools; there is no second lifecycle |
| CI / headless | keep 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
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:
- Node 24.19.0.
- Appium 3.6.0.
- Inspector plugin 2026.7.1.
- UiAutomator2 8.2.2.
- Android command-line tools 15859902, platform-tools, Emulator, API 36,
build-tools 36.0.0 with
aapt2, and a host-compatible Google APIs image. - 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:
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:
| Option | Release default | Constraint |
|---|---|---|
--api-level | 36 | Must match the release manifest. |
--device-profile | pixel_8 | Must match the release manifest. |
--image-tag | google_apis | Must match the release manifest. |
--abi | host | Resolves to x86_64 or arm64-v8a for the current host. |
--avd-name | shaft_pixel_8_api_36 | Use a safe Android identifier. |
--ram-mb | 4096 | Choose 2048 through 32768 MB. |
--cores | 2 | Choose 1 through 16 cores. |
--port | 4723 | Choose 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:
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:
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
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
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
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
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
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
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:
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:
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
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.
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
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:
| Option | Default | Effect |
|---|---|---|
--offline | false | Require verified cached artifacts and disable network access. |
--auto-start | false | Bind a startup request for providers that own a service. |
--prefer-system-tools=true|false | true | Bind whether a provider may prefer a compatible host tool. |
--reuse-owned-processes=true|false | true | Bind whether a provider may reuse compatible SHAFT-owned processes. |
--startup-timeout <duration> | PT2M | Bind a positive ISO-8601 startup timeout for providers with lifecycle support. |
--shutdown-timeout <duration> | PT30S | Bind 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.
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:
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:
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 code | Meaning |
|---|---|
0 | Ready or successful. |
2 | Invalid input, policy, or approval. |
3 | Missing or degraded readiness. |
4 | No provider supports the requested operation. |
5 | Execution 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.