{
  "id": "electron-playwright-e2e",
  "type": "loadout",
  "title": "Electron end-to-end tests with Playwright",
  "summary": "Playwright tests that drive the real Electron app: secure webPreferences, no Node in the renderer, IPC round trips, input validation and blocked navigation.",
  "description": "Renderer unit tests miss the Electron bugs that matter. A preload leaks ipcRenderer, a handler trusts its input, or someone sets sandbox: false to make a feature work. This loadout gives your agent Playwright's Electron support, set up properly. A fixture gives every test its own app instance and an empty userData folder, with a relaunch for persistence tests. An example suite asserts the secure webPreferences from the main process and checks that the renderer sees only the preload API. It drives an IPC feature through the UI and onto disk and back after a restart, checks the handler rejects bad input, and confirms that window.open and navigation are denied. A CI workflow runs it under xvfb on Ubuntu. The verifier runs the suite against a sandboxed Electron 44.9.0 app with @playwright/test 1.64.1. It also checks that turning the sandbox off or exposing ipcRenderer fails a test.\n",
  "highlights": [
    "Fresh app and userData per test, with relaunch for persistence",
    "Security assertions: sandbox, contextIsolation, no Node in the renderer",
    "IPC tested end to end, including handler validation",
    "Runs headless on Linux CI under xvfb-run",
    "Verified on Electron 44.9.0 and @playwright/test 1.64.1"
  ],
  "version": "1.0.0",
  "license": "MIT",
  "author": {
    "name": "Agent Loadout",
    "url": "https://loadout.jnw-it.com"
  },
  "credits": [
    {
      "title": "Playwright docs: Electron",
      "url": "https://playwright.dev/docs/api/class-electron"
    },
    {
      "title": "Playwright docs: test fixtures",
      "url": "https://playwright.dev/docs/test-fixtures"
    },
    {
      "title": "Electron docs: automated testing",
      "url": "https://www.electronjs.org/docs/latest/tutorial/automated-testing"
    },
    {
      "title": "Electron docs: security checklist",
      "url": "https://www.electronjs.org/docs/latest/tutorial/security"
    }
  ],
  "categories": [
    "web-app",
    "security"
  ],
  "stacks": [
    "electron",
    "playwright",
    "javascript",
    "desktop",
    "github-actions"
  ],
  "files": [
    {
      "path": "AGENTS.md",
      "role": "instructions",
      "description": "Rules for an Electron app whose security settings and IPC are covered by Playwright end-to-end tests.",
      "skill": null,
      "agent": null,
      "install_to": {
        "claude-code": "AGENTS.md",
        "codex": "AGENTS.md",
        "cursor": "AGENTS.md",
        "gemini-cli": "AGENTS.md",
        "antigravity-cli": "AGENTS.md",
        "copilot": "AGENTS.md"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/latest/AGENTS.md",
      "bytes": 1371,
      "lang": "markdown",
      "content": "# AGENTS.md: Electron app tested end to end with Playwright\n\nAn Electron desktop app with a sandboxed, context-isolated renderer and a narrow preload API. End-to-end tests\nuse Playwright's Electron support to drive the real app. Check `package.json` for the Electron and Playwright\nversions before using an API.\n\n## Commands\n\n- Start: `npm start`.\n- End-to-end tests: `npx playwright test` (Linux without a display: `xvfb-run -a npx playwright test`).\n- One test: `npx playwright test -g \"rejects an empty title\"`. Traces: `npx playwright show-trace test-results/.../trace.zip`.\n- Done means: the suite passes and the behaviour you changed has an end-to-end test.\n\n## Rules\n\n- Use the `electron-e2e-test` skill for any change that crosses IPC, touches `webPreferences`, the preload or\n  window handlers, or adds tests.\n- Keep `contextIsolation: true`, `sandbox: true` and `nodeIntegration: false`, and keep the tests that assert\n  them. Never weaken a security assertion to make a test pass.\n- The renderer reaches main only through named preload functions. Every `ipcMain.handle` checks the sender\n  frame and validates its arguments, and has a test for bad input.\n- Tests use the shared fixture: a fresh app and `userData` per test. No `waitForTimeout`, no CSS selectors.\n- Never add `--no-sandbox`, `--disable-web-security` or `ELECTRON_RUN_AS_NODE` to scripts or CI.\n"
    },
    {
      "path": "CLAUDE.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Claude Code.",
      "skill": null,
      "agent": "claude-code",
      "install_to": {
        "claude-code": "CLAUDE.md",
        "codex": null,
        "cursor": null,
        "gemini-cli": null,
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/CLAUDE.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/latest/CLAUDE.md",
      "bytes": 403,
      "lang": "markdown",
      "content": "# CLAUDE.md\n\n@AGENTS.md\n\n## Claude Code notes\n\n- Skills from this loadout live in `.claude/skills/`: `electron-e2e-test`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From the Agent Loadout \"Electron end-to-end tests with Playwright\" v1.0.0 — https://loadout.jnw-it.com/loadouts/electron-playwright-e2e/ -->\n"
    },
    {
      "path": "GEMINI.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Gemini CLI.",
      "skill": null,
      "agent": "gemini-cli",
      "install_to": {
        "claude-code": null,
        "codex": null,
        "cursor": null,
        "gemini-cli": "GEMINI.md",
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/GEMINI.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/latest/GEMINI.md",
      "bytes": 404,
      "lang": "markdown",
      "content": "# GEMINI.md\n\n@./AGENTS.md\n\n## Gemini CLI notes\n\n- Skills from this loadout live in `.agents/skills/`: `electron-e2e-test`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From the Agent Loadout \"Electron end-to-end tests with Playwright\" v1.0.0 — https://loadout.jnw-it.com/loadouts/electron-playwright-e2e/ -->\n"
    },
    {
      "path": "skills/electron-e2e-test/SKILL.md",
      "role": "skill",
      "description": "Setup, what every suite covers, rules and CI.",
      "skill": "electron-e2e-test",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/electron-e2e-test/SKILL.md",
        "codex": ".agents/skills/electron-e2e-test/SKILL.md",
        "cursor": ".agents/skills/electron-e2e-test/SKILL.md",
        "gemini-cli": ".agents/skills/electron-e2e-test/SKILL.md",
        "antigravity-cli": ".agents/skills/electron-e2e-test/SKILL.md",
        "copilot": ".agents/skills/electron-e2e-test/SKILL.md"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/latest/skills/electron-e2e-test/SKILL.md",
      "bytes": 3583,
      "lang": "markdown",
      "content": "---\nname: electron-e2e-test\ndescription: Write and run Playwright end-to-end tests that drive the real Electron app - main process, preload and renderer together - including security assertions on webPreferences, the preload API, IPC validation and blocked navigation. Use when adding a feature that crosses IPC, changing window or preload settings, or setting up Electron tests in CI.\n---\n\n# Electron end-to-end tests with Playwright\n\nUnit tests of the renderer miss the bugs that matter in Electron: a preload that leaks `ipcRenderer`, a\nhandler that trusts its input, a window that someone set to `sandbox: false`. Playwright's Electron support\nlaunches the real app and lets a test reach both sides: `page` for the renderer, `app.evaluate` for the main\nprocess.\n\n## Setup\n\n- Dev dependencies, pinned: `@playwright/test` and `electron`. No browser download is needed for Electron\n  tests (`npx playwright install` is not required).\n- `references/playwright.config.js`: one worker, traces kept on failure, one retry on CI only.\n- `references/electron-fixture.js`: `test.extend` fixtures. Every test gets a fresh `userData` folder,\n  its own app instance (`app.current`), its first window (`page`), and `app.relaunch()` for restart tests.\n  The main process must honour `E2E_USER_DATA`:\n\n  ```js\n  if (process.env.E2E_USER_DATA) app.setPath(\"userData\", process.env.E2E_USER_DATA);\n  ```\n\n- Run: `npx playwright test`. On Linux without a display: `xvfb-run -a npx playwright test`.\n\n## What every app's suite covers\n\n`references/app.spec.js` is a complete example. Adapt these to your app:\n\n1. Secure defaults, read from the main process:\n   `webContents.getLastWebPreferences()` has `contextIsolation: true`, `sandbox: true`,\n   `nodeIntegration: false`. A change that weakens one fails here, not in a security review.\n2. The renderer sees only the preload API: `typeof window.require`, `window.process` and\n   `window.ipcRenderer` are `\"undefined\"`, and the exposed object has exactly the functions you expect.\n3. Each IPC feature end to end: act in the UI, assert the UI, then assert the main-process effect (a file\n   in `userData`, a value from `app.evaluate`). Restart with `app.relaunch()` when persistence matters.\n4. Each handler's validation: send bad input through the UI and assert the error and that nothing was written.\n5. `window.open` and navigation away are denied, and there is still one window.\n\n## Rules\n\n- Locate by role and label (`getByRole`, `getByLabel`), never by CSS classes or XPath.\n- Wait with web-first assertions (`expect(locator).toHaveText`, `expect.poll`), never `waitForTimeout`.\n- One app per test via the fixture. No shared state between tests, no real home-directory data.\n- Never trigger `shell.openExternal` from a test (use a URL your handler denies outright); on CI it can hang shutdown.\n- Never pass `--no-sandbox`, `--disable-web-security` or similar flags to make a test pass. If the app only\n  starts with them, report it as a bug.\n- Do not stub `ipcRenderer` or the preload in e2e tests. That is what the test is for.\n- A failing test gets fixed or reported, not skipped. `test.fixme` only with a linked issue.\n\n## CI\n\n`references/electron-e2e.yml`: Ubuntu runner, `npm ci`, a step that downloads the Electron binary\n(`node -e \"require('electron')\"`, verified against Electron's checksums), then\n`xvfb-run -a npx playwright test`. Traces upload on failure.\n\n## Done means\n\nThe suite passes locally or under `xvfb-run`, the new behaviour has a test from the list above, and the\nsummary names any security assertion you changed and why.\n"
    },
    {
      "path": "skills/electron-e2e-test/references/playwright.config.js",
      "role": "reference",
      "description": "One worker, traces on failure, a CI-only retry.",
      "skill": "electron-e2e-test",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/electron-e2e-test/references/playwright.config.js",
        "codex": ".agents/skills/electron-e2e-test/references/playwright.config.js",
        "cursor": ".agents/skills/electron-e2e-test/references/playwright.config.js",
        "gemini-cli": ".agents/skills/electron-e2e-test/references/playwright.config.js",
        "antigravity-cli": ".agents/skills/electron-e2e-test/references/playwright.config.js",
        "copilot": ".agents/skills/electron-e2e-test/references/playwright.config.js"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/latest/skills/electron-e2e-test/references/playwright.config.js",
      "bytes": 323,
      "lang": "markdown",
      "content": "// Electron end-to-end tests. One worker: each test launches its own app instance.\nconst { defineConfig } = require(\"@playwright/test\");\n\nmodule.exports = defineConfig({\n  testDir: \"e2e\",\n  timeout: 30_000,\n  workers: 1,\n  retries: process.env.CI ? 1 : 0,\n  reporter: [[\"list\"]],\n  use: { trace: \"retain-on-failure\" },\n});\n"
    },
    {
      "path": "skills/electron-e2e-test/references/electron-fixture.js",
      "role": "reference",
      "description": "Per-test app, page and userData fixtures with relaunch.",
      "skill": "electron-e2e-test",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/electron-e2e-test/references/electron-fixture.js",
        "codex": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
        "cursor": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
        "gemini-cli": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
        "antigravity-cli": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
        "copilot": ".agents/skills/electron-e2e-test/references/electron-fixture.js"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/latest/skills/electron-e2e-test/references/electron-fixture.js",
      "bytes": 1463,
      "lang": "markdown",
      "content": "// Playwright fixtures for Electron: every test gets its own app instance and an empty userData folder.\n// `relaunch()` closes and restarts the app on the same userData, for persistence tests.\nconst base = require(\"@playwright/test\");\nconst fs = require(\"node:fs\");\nconst os = require(\"node:os\");\nconst path = require(\"node:path\");\n\nconst launch = (userData) =>\n  base._electron.launch({\n    args: [\".\"],\n    env: { ...process.env, E2E_USER_DATA: userData, ELECTRON_ENABLE_LOGGING: \"1\" },\n  });\n\nexports.test = base.test.extend({\n  userData: async ({}, use) => {\n    const dir = fs.mkdtempSync(path.join(os.tmpdir(), \"electron-e2e-\"));\n    await use(dir);\n    fs.rmSync(dir, { recursive: true, force: true });\n  },\n  app: async ({ userData }, use) => {\n    const holder = { current: await launch(userData) };\n    holder.relaunch = async () => {\n      await holder.current.close();\n      holder.current = await launch(userData);\n      return holder.current;\n    };\n    await use(holder);\n    // Close normally, but never let a stuck app hang the run: kill it after 10 seconds.\n    const proc = holder.current.process();\n    const timer = setTimeout(() => proc.kill(\"SIGKILL\"), 10_000);\n    await holder.current.close().catch(() => {});\n    clearTimeout(timer);\n  },\n  page: async ({ app }, use) => {\n    const page = await app.current.firstWindow();\n    await page.waitForLoadState(\"domcontentloaded\");\n    await use(page);\n  },\n});\n\nexports.expect = base.expect;\n"
    },
    {
      "path": "skills/electron-e2e-test/references/app.spec.js",
      "role": "reference",
      "description": "Five end-to-end tests, including security assertions.",
      "skill": "electron-e2e-test",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/electron-e2e-test/references/app.spec.js",
        "codex": ".agents/skills/electron-e2e-test/references/app.spec.js",
        "cursor": ".agents/skills/electron-e2e-test/references/app.spec.js",
        "gemini-cli": ".agents/skills/electron-e2e-test/references/app.spec.js",
        "antigravity-cli": ".agents/skills/electron-e2e-test/references/app.spec.js",
        "copilot": ".agents/skills/electron-e2e-test/references/app.spec.js"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/latest/skills/electron-e2e-test/references/app.spec.js",
      "bytes": 2659,
      "lang": "markdown",
      "content": "// Drives the real Electron app: main process, preload and renderer together.\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\nconst { test, expect } = require(\"./electron-fixture\");\n\ntest(\"window opens with the secure web preferences\", async ({ app, page }) => {\n  await expect(page).toHaveTitle(\"Notes\");\n  const prefs = await app.current.evaluate(({ BrowserWindow }) => {\n    const p = BrowserWindow.getAllWindows()[0].webContents.getLastWebPreferences();\n    return { contextIsolation: p.contextIsolation, sandbox: p.sandbox, nodeIntegration: p.nodeIntegration };\n  });\n  expect(prefs).toEqual({ contextIsolation: true, sandbox: true, nodeIntegration: false });\n});\n\ntest(\"the renderer has the preload API and no Node\", async ({ page }) => {\n  const globals = await page.evaluate(() => ({\n    require: typeof window.require,\n    process: typeof window.process,\n    ipcRenderer: typeof window.ipcRenderer,\n    notes: Object.keys(window.notes).sort(),\n  }));\n  expect(globals).toEqual({ require: \"undefined\", process: \"undefined\", ipcRenderer: \"undefined\", notes: [\"add\", \"list\"] });\n});\n\ntest(\"adding a note goes through IPC, is saved by main, and survives a restart\", async ({ app, page, userData }) => {\n  await page.getByLabel(\"Title\").fill(\"  Buy milk  \");\n  await page.getByRole(\"button\", { name: \"Add note\" }).click();\n  await expect(page.getByRole(\"list\", { name: \"Notes\" }).getByRole(\"listitem\")).toHaveText([\"Buy milk\"]);\n\n  const saved = JSON.parse(fs.readFileSync(path.join(userData, \"notes.json\"), \"utf8\"));\n  expect(saved.map((n) => n.title)).toEqual([\"Buy milk\"]);\n\n  const again = await (await app.relaunch()).firstWindow();\n  await expect(again.getByRole(\"listitem\")).toHaveText([\"Buy milk\"]);\n});\n\ntest(\"the main process rejects an empty title\", async ({ page, userData }) => {\n  await page.getByLabel(\"Title\").fill(\"   \");\n  await page.getByRole(\"button\", { name: \"Add note\" }).click();\n  await expect(page.getByRole(\"alert\")).toHaveText(\"Title must be 1-120 characters\");\n  expect(fs.existsSync(path.join(userData, \"notes.json\"))).toBe(false);\n});\n\ntest(\"window.open and navigation away are denied\", async ({ app, page }) => {\n  // http:// is denied without being handed to the OS browser; https:// would go to shell.openExternal,\n  // which a test must never trigger (on CI it can leave xdg-open hanging and block shutdown).\n  expect(await page.evaluate(() => window.open(\"http://example.com\") === null)).toBe(true);\n  await page.evaluate(() => {\n    window.location.href = \"https://example.com\";\n  });\n  await expect.poll(() => page.url()).toMatch(/index\\.html$/);\n  expect(app.current.windows()).toHaveLength(1);\n});\n"
    },
    {
      "path": "skills/electron-e2e-test/references/electron-e2e.yml",
      "role": "reference",
      "description": "GitHub workflow running the suite under xvfb.",
      "skill": "electron-e2e-test",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/electron-e2e-test/references/electron-e2e.yml",
        "codex": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
        "cursor": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
        "gemini-cli": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
        "antigravity-cli": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
        "copilot": ".agents/skills/electron-e2e-test/references/electron-e2e.yml"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/latest/skills/electron-e2e-test/references/electron-e2e.yml",
      "bytes": 927,
      "lang": "yaml",
      "content": "# .github/workflows/e2e.yml\n# Electron needs a display on Linux: xvfb-run provides a virtual one. The Electron binary is\n# downloaded (and checksum-verified by @electron/get) on first use, then cached.\nname: Electron e2e\n\non:\n  push:\n    branches: [main]\n  pull_request:\n\npermissions:\n  contents: read\n\njobs:\n  e2e:\n    runs-on: ubuntu-24.04\n    timeout-minutes: 15\n    steps:\n      - uses: actions/checkout@v7\n      - uses: actions/setup-node@v7\n        with:\n          node-version: 22\n          cache: npm\n      - uses: actions/cache@v6\n        with:\n          path: ~/.cache/electron\n          key: electron-${{ hashFiles('package-lock.json') }}\n      - run: npm ci\n      - run: node -e \"require('electron')\"\n      - run: xvfb-run -a npx playwright test\n      - uses: actions/upload-artifact@v7\n        if: failure()\n        with:\n          name: playwright-traces\n          path: test-results/\n          retention-days: 7\n"
    }
  ],
  "requires": {
    "tools": [
      "node",
      "npm",
      "xvfb-run"
    ],
    "env": [],
    "mcp": []
  },
  "tested": {
    "status": "untested",
    "last_run": null,
    "fixture": null,
    "per_agent": {
      "claude-code": "untested",
      "codex": "untested",
      "cursor": "untested",
      "gemini-cli": "untested",
      "antigravity-cli": "untested",
      "copilot": "untested"
    }
  },
  "security": {
    "scanned": true,
    "scanner": "intake-precheck/1",
    "verdict": "clean",
    "network": true,
    "scripts": [],
    "notes": "npm ci installs Electron and Playwright from npm; the Electron binary is downloaded from GitHub and checked against Electron's published checksums. The tests open no network connections."
  },
  "featured": false,
  "deprecated": false,
  "last_checked": "2026-10-17",
  "published": "2026-10-17",
  "updated": "2026-10-17",
  "compatibility": {
    "claude-code": "native",
    "codex": "native",
    "cursor": "native",
    "gemini-cli": "native",
    "antigravity-cli": "native",
    "copilot": "native"
  },
  "counts": {
    "rules": 1,
    "skills": 1,
    "mcp": 0
  },
  "url": "https://loadout.jnw-it.com/loadouts/electron-playwright-e2e/",
  "api_url": "https://loadout.jnw-it.com/api/loadouts/electron-playwright-e2e.json",
  "verification": {
    "level": "verified-install",
    "status": "verified",
    "label": "Verified install",
    "verified": true,
    "checked_at": "2026-10-17T21:13:34Z",
    "commit": "1810992339908c87891a39e8f0c198d6db9098fc",
    "content_current": true,
    "agent_tests": "not-run",
    "counts": {
      "pass": 9,
      "fail": 0,
      "skip": 0,
      "not_applicable": 1
    },
    "meaning": "Level 1: automated checks on the files (parse, install paths, MCP config, safety scan, references, size, licence, starter build). No AI agent was run.",
    "checks": [
      {
        "id": "listing",
        "name": "Listing",
        "status": "pass",
        "summary": "Schema valid; 8 files declared, none missing or extra",
        "details": [
          "tested.status: untested (agent tests are separate from Level 1)"
        ]
      },
      {
        "id": "parse",
        "name": "Files parse",
        "status": "pass",
        "summary": "All 8 files parse; front matter valid",
        "details": []
      },
      {
        "id": "adapters",
        "name": "Adapters",
        "status": "pass",
        "summary": "CLAUDE.md and GEMINI.md import AGENTS.md and are up to date",
        "details": [
          "CLAUDE.md: matches the generator",
          "GEMINI.md: matches the generator"
        ]
      },
      {
        "id": "install-paths",
        "name": "Install paths",
        "status": "pass",
        "summary": "Correct paths for all 6 agents; layouts re-discovered",
        "details": [
          "Claude Code: 7 files, 1 skill in .claude/skills/",
          "Codex CLI: 6 files, 1 skill in .agents/skills/",
          "Cursor: 6 files, 1 skill in .agents/skills/",
          "Gemini CLI: 7 files, 1 skill in .agents/skills/",
          "Antigravity CLI: 6 files, 1 skill in .agents/skills/",
          "GitHub Copilot: 6 files, 1 skill in .agents/skills/"
        ]
      },
      {
        "id": "mcp",
        "name": "MCP config",
        "status": "n/a",
        "summary": "No MCP servers in this loadout",
        "details": []
      },
      {
        "id": "safety",
        "name": "Safety scan",
        "status": "pass",
        "summary": "Clean: no credentials, risky shell or hidden text",
        "details": [
          "Scanner intake-precheck/1: verdict clean; network no (listing says yes)"
        ]
      },
      {
        "id": "references",
        "name": "References",
        "status": "pass",
        "summary": "2 references between files resolve for every agent",
        "details": []
      },
      {
        "id": "size",
        "name": "Size limits",
        "status": "pass",
        "summary": "8 files, 10.9 KB total; largest skills/electron-e2e-test/SKILL.md 3.5 KB",
        "details": [
          "Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule"
        ]
      },
      {
        "id": "licence",
        "name": "Licence",
        "status": "pass",
        "summary": "MIT, by Agent Loadout; text in the repository LICENSE",
        "details": []
      },
      {
        "id": "starter-build",
        "name": "Starter build",
        "status": "pass",
        "summary": "The electron-e2e-test skill's Playwright config, fixtures and five tests drive a sandboxed Electron 44.9.0 app under xvfb with @playwright/test 1.64.1: secure webPreferences, no Node in the renderer, IPC save and restart, input validation, blocked navigation. Turning the sandbox off or exposing ipcR",
        "details": [
          "Applied 13 loadout files at every agent's paths",
          "✓ npm ci (Electron and Playwright pinned): npm ci --no-audit --no-fund",
          "✓ download the Electron binary (checksum-verified by @electron/get): bash -c node -e \"const p=require('electron'); require('fs').accessSync(p); console.log('electron binary ok')\"",
          "✓ place the skill's config, fixture and tests: bash -c R=.agents/skills/electron-e2e-test/references; mkdir -p e2e && cp $R/playwright.config.js . && cp $R/electron-fixture.js $R/app.spec.js e2e/ && echo placed",
          "✓ playwright test under xvfb: xvfb-run -a npx playwright test",
          "✓ turning the sandbox off fails the suite: bash -c cp src/main.js main.bak && sed -i 's/sandbox: true,/sandbox: false,/' src/main.js && grep -q 'sandbox: false' src/main.js && xvfb-run -a npx playwright test --retries 0 2>&1; s=$?; cp main.bak src/main.js; test $s -ne 0 && echo caught",
          "✓ exposing ipcRenderer in the preload fails the suite: bash -c cp src/preload.js preload.bak && printf '%s\\n' 'contextBridge.exposeInMainWorld(\"ipcRenderer\", ipcRenderer);' >> src/preload.js && xvfb-run -a npx playwright test --retries 0 2>&1; s=$?; cp preload.bak src/preload.js; test $s -ne 0 && echo caught",
          "Covers: Playwright _electron fixtures: fresh app and userData per test, relaunch for persistence",
          "Covers: contextIsolation, sandbox and nodeIntegration asserted from the main process",
          "Covers: Renderer has only the preload API; IPC handler validation; window.open and navigation denied",
          "Covers: Runs headless on Linux under xvfb-run, as in the CI workflow"
        ]
      }
    ]
  },
  "install": {
    "claude-code": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "CLAUDE.md",
          "target": "CLAUDE.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/CLAUDE.md",
          "role": "adapter"
        },
        {
          "path": "skills/electron-e2e-test/SKILL.md",
          "target": ".claude/skills/electron-e2e-test/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/electron-e2e-test/references/playwright.config.js",
          "target": ".claude/skills/electron-e2e-test/references/playwright.config.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-fixture.js",
          "target": ".claude/skills/electron-e2e-test/references/electron-fixture.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/app.spec.js",
          "target": ".claude/skills/electron-e2e-test/references/app.spec.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-e2e.yml",
          "target": ".claude/skills/electron-e2e-test/references/electron-e2e.yml",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/electron-playwright-e2e/claude-code.zip"
    },
    "codex": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/electron-e2e-test/SKILL.md",
          "target": ".agents/skills/electron-e2e-test/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/electron-e2e-test/references/playwright.config.js",
          "target": ".agents/skills/electron-e2e-test/references/playwright.config.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-fixture.js",
          "target": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/app.spec.js",
          "target": ".agents/skills/electron-e2e-test/references/app.spec.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-e2e.yml",
          "target": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/electron-playwright-e2e/codex.zip"
    },
    "cursor": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/electron-e2e-test/SKILL.md",
          "target": ".agents/skills/electron-e2e-test/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/electron-e2e-test/references/playwright.config.js",
          "target": ".agents/skills/electron-e2e-test/references/playwright.config.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-fixture.js",
          "target": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/app.spec.js",
          "target": ".agents/skills/electron-e2e-test/references/app.spec.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-e2e.yml",
          "target": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/electron-playwright-e2e/cursor.zip"
    },
    "gemini-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "GEMINI.md",
          "target": "GEMINI.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/GEMINI.md",
          "role": "adapter"
        },
        {
          "path": "skills/electron-e2e-test/SKILL.md",
          "target": ".agents/skills/electron-e2e-test/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/electron-e2e-test/references/playwright.config.js",
          "target": ".agents/skills/electron-e2e-test/references/playwright.config.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-fixture.js",
          "target": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/app.spec.js",
          "target": ".agents/skills/electron-e2e-test/references/app.spec.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-e2e.yml",
          "target": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/electron-playwright-e2e/gemini-cli.zip"
    },
    "antigravity-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/electron-e2e-test/SKILL.md",
          "target": ".agents/skills/electron-e2e-test/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/electron-e2e-test/references/playwright.config.js",
          "target": ".agents/skills/electron-e2e-test/references/playwright.config.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-fixture.js",
          "target": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/app.spec.js",
          "target": ".agents/skills/electron-e2e-test/references/app.spec.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-e2e.yml",
          "target": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/electron-playwright-e2e/antigravity-cli.zip"
    },
    "copilot": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/electron-e2e-test/SKILL.md",
          "target": ".agents/skills/electron-e2e-test/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/electron-e2e-test/references/playwright.config.js",
          "target": ".agents/skills/electron-e2e-test/references/playwright.config.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-fixture.js",
          "target": ".agents/skills/electron-e2e-test/references/electron-fixture.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/app.spec.js",
          "target": ".agents/skills/electron-e2e-test/references/app.spec.js",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js",
          "role": "reference"
        },
        {
          "path": "skills/electron-e2e-test/references/electron-e2e.yml",
          "target": ".agents/skills/electron-e2e-test/references/electron-e2e.yml",
          "raw_url": "https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml",
          "role": "reference"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/electron-playwright-e2e/copilot.zip"
    }
  },
  "source_zip_url": "https://loadout.jnw-it.com/download/electron-playwright-e2e/source.zip"
}