コンテンツにスキップ

Configuration

The config schema (team defaults overlaid by per-target config), its resolution to an Effective config for one target, and the Git config source (github:owner/repo@ref:path).

bajutsu.config

Configuration — team defaults overlaid by per-target config.

Split along its four responsibilities (BE-0252), one submodule each, with a one-directional dependency from resolution outward: input schema (schema) -> resolved output types (effective) <- merge/derivation (resolve) and platform-narrowing accessors (accessors). The public API is re-exported here, so from bajutsu.config import Effective, resolve, require_ios, … is unchanged and no call site outside this package is touched.

AiConfig dataclass

The resolved ai block (BE-0047): which provider/model/endpoint/key the AI paths use.

Lives with the rest of the resolved config (not the AI client) so the deterministic core can read the block without importing the periphery AI stack (BE-0112). Every field is optional — an absent field falls back to the environment in the AI-client factory, so a config with no ai: block behaves exactly as before. key_env holds the NAME of the env var that carries the key, never the key itself.

AndroidConfig dataclass

Android (adb) target knobs (BE-0126 / BE-0007). On Effective only when platform is android.

DoctorThresholds dataclass

Configurable doctor id-coverage thresholds (BE-0024), grouped out of Effective (BE-0252).

Teams with many decorative elements can tune thresholds (often lowering ok and/or fail for leniency) without changing the tool.

Effective dataclass

The resolved config for one target.

platform property

The resolved platform (ios / android / web), derived from the sub-config's type (BE-0126).

rebased(root, *, confine=True)

A copy with the relative path fields resolved against root.

The common path fields — scenarios / baselines / schemas / goldens — and the iOS or Android sub-config's app_path are rebased; a future path field is rebased by adding it here. build (a shell command) and setup (resolved relative to the scenario, not the cwd) are intentionally absent. Called for a Git checkout (BE-0063), for an uploaded bundle, and — with confine=False, root the config file's own directory — for a local config (BE-0242), so the caller's working directory no longer decides where a config's paths point.

confine gates the escape check: when true (an untrusted source — a fetched Git config or an uploaded bundle), an absolute or ../ value that would leave root raises ValueError, mirroring the serve-hardening path confinement (BE-0051). A local file is operator-trusted (BE-0121), so it passes confine=False and may point at a sibling outside its own directory.

EvidenceDirs dataclass

The target's evidence directory overrides (BE-0252 grouping of Effective).

Each is the target's directory for that evidence kind (config-driven run/record). None means "unset": scenarios then requires an explicit path, and each of baselines / schemas / goldens falls back to the directory beside the scenario file (or the matching --<kind> flag).

IosConfig dataclass

iOS (idb / XCUITest) target knobs (BE-0126). On Effective only when platform == "ios".

RunDefaults dataclass

Per-app run-behavior defaults (BE-0177), grouped out of Effective (BE-0252).

The layer the run consults when neither a CLI flag nor the scenario sets the value. dismiss_alerts None = built-in on with the default instruction; erase / network are the concrete built-in defaults when unset.

WebConfig dataclass

Web (Playwright) target knobs (BE-0126). On Effective only when platform == "web".

AiSettings

Bases: _Model

The ai block (BE-0047) — which provider/model/endpoint/key the AI paths use.

defaults.ai is overridable per targets.<name>.ai. Keys never live here: keyEnv is the NAME of the env var holding the key, read at call time, so a secret never lands in the repo or an uploaded bundle. Every field is optional; an unset field falls back to the environment in the factory. extra="forbid" (from _Model) rejects a stray apiKey:-style field that would tempt a literal key into config.

Config

Bases: _Model

A parsed bajutsu.config.yaml: team defaults and per-target config.

The hosted multi-tenancy orgs: block is a serve concern the core does not model (BE-0129); parse_config_dict drops it before validation so a run reading an org-bearing config keeps working, and bajutsu.serve.orgs owns the org model.

Defaults

Bases: _Model

Team-wide defaults under defaults:, overlaid by each target (see resolve).

DeviceProvider

Bases: _Model

Where a target's devices come from (targets.<name>.deviceProvider, BE-0236).

kind selects the provider adapter from the device-provider registry, defaulting to local — a locally-attached simulator / emulator / device, exactly today's --udid path — so an omitted block is unchanged. A device-cloud kind reserves a device off-host and hands the run its serial / endpoint instead. endpoint carries that address for the kinds that need one (the appium live path points at a reserved iOS device's Appium / WebDriver endpoint, BE-0238). Like the mailbox kind, an unknown value — or a required-but-missing endpoint — fails closed when the run resolves the provider, not here: the deterministic config must not import a cloud SDK (BE-0112).

DoctorConfig

Bases: _Model

Configurable thresholds for bajutsu doctor's id-coverage grading (BE-0024).

idCoverageOk is the minimum coverage to be eligible for "Ready"; idCoverageFail is the ceiling below which the grade drops to "Blocked". Both must be in [0, 1] with ok >= fail.

LaunchServer

Bases: _Model

How to bring up the app's target server (the host behind baseUrl) for a run.

Unlike mockServer (which stubs the dependencies the app calls), this hosts the app under test itself — e.g. the static page for demos/web, or the inner serve the WebUI dogfood drives. run probes readyUrl first: if it already answers it reuses it (started externally), else it runs cmd, waits on the readiness probe (a condition wait, never a fixed sleep), and tears the process down afterwards.

Mailbox

Bases: _Model

A mailbox the email step polls (targets.<name>.mailbox, BE-0046 / BE-0186).

kind selects the transport adapter (http, later imap) from the mailbox registry, defaulting to http so a pre-BE-0186 block is unchanged; an unknown kind fails closed when the runner resolves the mailbox, not here (the deterministic config must not import the registry, BE-0112). url is the inbox endpoint (GET; commonly ${secrets.*}), headers any auth. The optional response mapping absorbs a provider's JSON shape without per-provider code: messages is a dotted path to the message array (empty = the response is the array), and fields maps each normalized field (to / subject / body / receivedAt / id) to the provider's key, defaulting to the field's own name.

MockServer

Bases: _Model

A mock server that stubs the dependencies the app under test calls (mockServer: config).

NotifyEndpoint

Bases: _Model

One webhook notification sink (notify: list entry, BE-0099).

PricingEntry

Bases: _Model

Per-token rates for one (provider, model) in ai.pricing (BE-0196), USD per million tokens.

Overrides a shipped default. cacheWrite / cacheRead default to 0 for a provider that does not price cache separately, so an entry may name only input / output.

TargetConfig

Bases: _Model

One app's config under targets.<name>, overriding defaults for that target.

XcuitestConfig

Bases: _Model

Per-target XCUITest runner config (targets.<name>.xcuitest, BE-0019).

android_package(eff)

The Android target's package, or "" for a non-Android target.

idb_version_pin(eff)

The iOS target's declared idb version range (defaults.idbVersion), or None when unpinned.

ios_bundle_id(eff)

The iOS target's bundle id, or "" for a non-iOS target.

require_android(eff)

The Android sub-config, narrowed for the type checker, or a loud failure (BE-0126 / BE-0007).

The Android counterpart of require_ios / require_web, for code already on an adb-only path (the AndroidEnvironment lifecycle).

require_ios(eff)

The iOS sub-config, narrowed for the type checker, or a loud failure (BE-0126).

For code already committed to an iOS-only path (the iOS/XCUITest environment, the idb doctor probe): it narrows the platform union to IosConfig and fails fast rather than silently reading a default if a non-iOS target ever reaches it. Code that has not committed to a platform must narrow with isinstance / match instead — reading a platform's knobs off platform_config without narrowing is a type error, which is the point of the split.

require_web(eff)

The web sub-config, narrowed for the type checker, or a loud failure (BE-0126).

The web counterpart of require_ios, for code already on a web-only path (the web environment, the Playwright doctor probe).

web_base_url(eff)

The web target's base URL, or None for a non-web target.

web_engine(eff)

The web target's rendering engine, or the chromium default for a non-web target.

xcuitest_targets_real_device(eff)

True when the target drives a real iOS device via XCUITest (xcuitest.deviceType: device).

The Simulator default — and every non-iOS target — is False. Consulted by the capability narrowing that drops the simctl-backed DeviceControl / permission tokens on a real device (BE-0238): simctl reaches only the Simulator, so those capabilities do not apply on a physical device.

load_config(text)

Parse a YAML config string into a Config (see parse_config_dict).

parse_config_dict(data)

Validate an already-parsed config document into a Config.

Top-level orgs: and ui: keys are dropped before validation: the hosted multi-tenancy org model (BE-0129) and the serve UI's ui.default_theme (BE-0191) are serve concerns the deterministic core does not model, and a run in the hosted topology legitimately reads a config carrying them, so the core must ignore the keys rather than reject them under extra="forbid". bajutsu.serve.orgs / bajutsu.serve.themes parse those blocks separately. Every other unknown key still fails loudly, preserving the typo guard.

bajutsu.config_source

Acquire a config (and its scenario tree) from a Git source (BE-0063).

--config keeps accepting a local path; in addition it accepts a Git spec (github:<owner>/<repo>[@<ref>][:<path>], or git+https://<host>/<owner>/<repo>.git[@<ref>][#<path>]). The spec is materialized at an immutable commit SHA into a content-addressed cache, and the config's relative paths resolve against that checkout root. Only acquisition changes — the schema, runner, drivers, and the deterministic gate are untouched (DESIGN §6.5: git holds the history).

The GitHub transport (commits API + tarball endpoint) is the one external dependency; it is a small injectable seam so the materialization logic tests offline against a fake.

GitConfigSpec dataclass

A parsed Git config source: which repo subtree, at which ref, to load the config from.

Materialized dataclass

A repo subtree checked out at an immutable SHA: the config file, the checkout root, and the SHA.

Transport

Bases: Protocol

The Git-host calls materialization makes — injected so the logic tests offline.

is_full_sha(ref)

Whether ref is a full 40-hex commit SHA — the only ref that is an immutable, offline pin.

parse_config_spec(value)

Parse a --config value into a GitConfigSpec, or None when it is an ordinary local path.

A value with no recognized Git scheme is a local path, so every existing invocation is unchanged. A repo of exactly . or .. is a same-segment traversal (BE-0124) and is refused here, so it fails the same way an unparseable value does rather than reaching the cache path.

source_from_config(config)

A config-source record (kind + locator) for config (BE-0225).

A Git spec becomes a git source, anything else a local file source — the discriminated shape the project registry stores and serve auto-registers (launch_project_identity), so a config registered from the CLI or the API round-trips back through the run/bind path.

config_from_source(source)

Reconstruct a --config spec from a stored config-source record (BE-0225).

The inverse of source_from_config, so a registered project drives the ordinary run/bind path. A git source rebuilds the github: / git+https:// spec, preferring the resolved sha (an immutable pin the launch auto-register stamps) over a moving ref. A file source is its path.

Raises:

Type Description
ValueError

the record is malformed (not a record, no locator, a file with no path, a git missing a required field) or names a source kind with no spec form — an upload bundle has no local checkout to point --config at.

github_http_error_message(status, headers, spec)

Turn a GitHub HTTPError into an actionable message that names the real cause (BE-0224).

The rate-limit and SSO sub-types are checked before the catch-all so neither is misreported as missing repository access — more Contents: read permission fixes neither. The 404/other-403 fall-through names the most-likely-missing grant.

github_token()

A GitHub token for private repos, else gh auth token, else None.

Checks the bajutsu-owned BAJUTSU_GIT_CONFIG_TOKEN (a serve-entered credential) first, then GITHUB_TOKEN / GH_TOKEN, so a UI credential wins over an ambient token (BE-0224).

resolve_github_credential(spec)

The bearer token for spec, in documented precedence order (BE-0224).

A configured GitHub App installation first (a short-lived, per-installation, service-identity token — the answer for an unattended host), then the GITHUB_TOKEN / GH_TOKEN / gh auth token chain of github_token(), else anonymous. Resolved per acquisition (the transport is built per materialize), so a rotated secret takes effect without a serve restart.

source_provenance(spec, mat)

The run-provenance stamp for a Git config source: repo + the ref it was asked for + the SHA.

Recording the resolved sha makes a branch-based run reproducible after the fact (BE-0063) — it states the exact commit executed, not just the moving branch.

materialize(spec, *, transport=None, cache_root=None, offline=False)

Check out spec's subtree at its resolved commit SHA into a content-addressed cache.

The ref is resolved to an immutable SHA (the determinism anchor), then the tree is fetched once and extracted under <cache>/<host>/<owner>/<repo>/<sha>/. Because the directory is keyed by the SHA, a cache hit is always valid and a pinned-SHA run is offline after the first fetch.

With offline (the --config-offline switch) it never touches the network: the ref must already be a full SHA (a branch/tag can't be resolved offline) and that SHA must already be cached.