macos-vm-e2e-lab
Route PwrAgent macOS Tart, self-hosted runner, headed E2E, and visual-golden work through PwrSuiteLab Control MCP, with managed-controller fallback only when MCP is unavailable. Use when a user mentio
SKILL.md.agents/skills/macos-vm-e2e-lab/SKILL.md
GitHubPwrAgent macOS VM E2E lab
PwrAgent does not own the Tart lab, runner VMs, or guest OS baseline. PwrSuiteLab does. Do not provision a product-local Tart lab from this repository. Do not clone a Cirrus image or register a GitHub Actions runner from these files.
Keep the boundary explicit: product tests and CI contracts belong in PwrAgent; private lab inventory, configuration, transport, diagnosis, and recovery belong only in PwrSuiteLab. Never copy private access values, addresses, usernames, fingerprints, keys, configuration contents, host inventory, or lab construction details into PwrAgent.
Prefer PwrSuiteLab Control MCP
Discover the connected Control tools and obtain the current tools/list
schemas before invoking them. In PwrAgent, use search_mcp_tools and
call_mcp_tool for live connection tools. Read Control's served
skill://manage-pwrlab-e2e/SKILL.md, plus skill://inspect-pwrlab/SKILL.md
for status and skill://operate-pwrlab/SKILL.md for operations. Discover these
with skills/list and skills/get, then read their contents through
resources/read; older clients can use resources/list and resources/read.
The connected server's current schema and served skills are authoritative.
Do not require a local lab checkout or a Federation handoff for this MCP path.
An existing Operate grant authorizes matching exposed MCP operations within
the requested task without per-operation dialogs. A Read only grant does not.
Report an explicit permission_denied; do not switch transports to bypass it.
Rebuilding a VM or changing access remains a separate operator-authorized task.
Keep Control open and preserve its target, transport, and ownership guards.
Required caller fields on every run and acquire
Place caller attribution beside target and job, never inside job:
{
"target": "<exact E2E target from lab_status>",
"agent_name": "Codex",
"project_name": "PwrAgent",
"thread_name": "Verify macOS visual goldens",
"job": {
"repository": "/absolute/path/to/clean/committed/worktree",
"setup": [["pnpm", "install", "--frozen-lockfile"]],
"command": ["env", "PWRAGENT_E2E_DISABLE_GPU=1", "pnpm", "test:desktop-e2e", "e2e/visual-regression.spec.ts"],
"artifacts": ["apps/desktop/test-results", "apps/desktop/playwright-report"],
"timeout_seconds": 3600
}
}
Replace agent_name with the calling agent (for example, Claude Code when
Claude is calling), project_name with the actual repository display name,
and thread_name with the current task title. The example assumes the guest
runtime versions required by current CI and package.json; see
CONTRIBUTING.md for product setup requirements.
For lab_e2e_acquire, use the same top-level target and attribution but omit
job. Add pr_number as decimal digits in a string only when known.
Submit and collect a headed test job
- Call
lab_statusand select the exact target of the dedicated E2E role. Never select a GitHub Actions runner or use the physical host desktop. Refresh status before submitting another job; the VM may have stopped while preparing it.lab_e2e_runstarts the configured VM when necessary. - Use this thread's clean, committed local worktree on the Control host. Only committed HEAD and locally available submodule/LFS content travel; obtain required LFS objects first. Never discard changes to make it clean. Select setup, runtime versions, commands, and artifacts from the repository's current package scripts and CI. See the product example in CONTRIBUTING.md.
- Call
lab_e2e_runwith top-leveltarget,agent_name,project_name,thread_name, andjob. Both run andlab_e2e_acquirerequire those three attribution fields, including a run consuming an existing reservation. Use the actual agent,PwrAgentas the project, and the current thread title (or a descriptive task title if unavailable). Addpr_numberas a string of decimal digits when known; omit it otherwise. Attribution is display metadata, not authorization; do not include credentials or local paths. - Set
job.repositoryto the absolute worktree path,job.commandto an argv array,job.setupto an ordered array of argv arrays, andjob.artifactsto relative checkout paths. These are not shell strings. For a necessary shell function or compound command, explicitly use["bash", "-c", "..."]and source/select the required runtime there. Dependency installation runs in the guest; do not install host tools or copy host environment files or credentials as a workaround. - Save the request ID and
run_id. Polllab_request_statusfor the launch request; a completed launch withjob_state: runningis not a passed test. Uselab_e2e_collectwith the target and saved run ID, polling its request if needed. Inspect the returned artifact directory and log, and report test exit code, setup failures, and missing artifacts. Never commit raw logs. Collection does not start a stopped VM: uselab_e2e_startfor the exact target before collecting, within the authorized task. Do not rerun tests just to retrieve artifacts.
Invalid arguments are not a permission diagnosis
-32602 / Invalid tool or arguments can reject a call before dispatch.
Refresh tool discovery/schema and the served skill, then check required
attribution, top-level placement, string pr_number, and argv array shapes.
Do not infer a lost Operate grant, request a re-grant, or switch to scripts or
Federation from that error alone. If a corrected call still fails, report the
schema mismatch/error for diagnosis instead of repeatedly submitting it.
For a launch/transport failure, inspect any returned request and run IDs before
retrying: a guest job may already have started.
Ownership, lock age, and recovery
Read the E2E role's lock_state, owner_kind, session_active, and
host_lock_state together. Report lock_started_at in UTC (Z) and the full
lock_age_seconds, not the chart window or Control uptime. Preserve unknown
or not-collected values; age is not an expiry or proof that recovery is safe.
A run claims the display before staging or setup; no preliminary acquire is
needed. It can consume this OAuth connection's reservation atomically, and the
guest releases its own workload lock on completion. Do not call
lab_e2e_release after that handoff. Release only this connection's interactive
reservation when finished; another connection does not inherit ownership.
An interrupted result is not a passing test. Preserve its lock until
lab_e2e_recover validates an orphan. Guarded recovery refuses live sessions,
live app reservations, malformed owners, and unknown transport state. Use
release for an owned reservation, recovery for a validated stale workload
lock. Never delete locks manually or treat age as permission for takeover.
Controller fallback only when MCP is unavailable
If Control MCP is unavailable to the client, use the existing managed controller path under the current PwrSuiteLab runbook. This fallback is not a way around invalid arguments, permission denial, a busy target, or a safety refusal. Preserve existing scoped authorizations; do not ask again for work already authorized, and do not treat an MCP grant as blanket script approval.
- Discover an existing PwrSuiteLab primary checkout through attached/linked directories, known project checkouts, or project metadata (Federation may help locate it only on this fallback path). Do not hardcode a host pathname, clone/install a lab, or operate controllers from a disposable lab worktree.
- Read that checkout's
AGENTS.md, currentmacos-tartrunbook, and applicable skills. Follow their target-resolution and approval requirements. The lab checkout is authoritative for controller flags and recovery procedures. - Test required ignored configuration with an exact filesystem existence
check:
local-config/macos-tart.shfor headed E2E orlocal-config/macos-runner.shfor runners. Never read, print, copy, or expose the config.rg --files,git ls-files, or another worktree cannot prove its absence. If missing, ask only for an existing operator-supplied path. - For headed tests use
macos-tart/run-e2e.sh --confirm-live-run --workload pwragent --local <product-worktree> <playwright-arguments>from that lab checkout. The flag asserts actual authorization; it does not grant it. Legacy scripts cannot consume a Control reservation. Do not release a reservation merely to bypass the MCP path. - For runner work use the lab's
operate-macos-gha-runnerorinspect-macos-gha-runnerskills. Rebuilds userebuild-macos-lab-vm; access/lifecycle recovery usesmanage-macos-gha-runner. Windows work usesuse-windows-vm-lab, not this macOS workflow.
If no usable primary checkout exists, ask for the existing lab pointer and
stop. Never invent a fallback lab. On either path, do not run or recommend bare
tart (including tart ip), raw SSH, manual host-key acceptance, global
known-hosts changes, password-prompting authentication, or disabled strict
host-key checking. Do not explore keys or ask the operator to take those
shortcuts. Diagnosis and recovery remain in PwrSuiteLab's supported tools.
PwrAgent product facts
These stay in this repository because they are product or CI contracts, not lab inventory:
- macOS visual goldens must match the CI renderer, a GitHub-hosted
macos-26runner. The workflow is in CONTRIBUTING.md. - PwrAgent CI does not use lab runners. Do not move a CI job onto lab machines: fork pull requests run every macOS job.
- VM E2E sets
PWRAGENT_E2E_DISABLE_GPU=1. Ordinary host E2E does not.