{"_id":"@athree/create-project","_rev":"10-c84eac77c737f6382e4ea359062d8c60","name":"@athree/create-project","dist-tags":{"latest":"1.4.0"},"versions":{"1.0.2":{"name":"@athree/create-project","version":"1.0.2","_id":"@athree/create-project@1.0.2","maintainers":[{"name":"christellevs","email":"christelle.marie@gmail.com"},{"name":"inca","email":"boris@okunskiy.name"}],"bin":{"create-project":"bin/create.js"},"dist":{"shasum":"8992eb4906572b9e7d8a63d3ff443112892fe4d9","tarball":"https://registry.npmjs.org/@athree/create-project/-/create-project-1.0.2.tgz","fileCount":13,"integrity":"sha512-XOHWgAKhEu+gPKcZA8JQm91l/wa58EseG/SzqiHDs1Qw7PqRxEu/bywQePlAv2/s5vpLckkFoPFlUD3xTHerFw==","signatures":[{"sig":"MEUCIQCRsc7S6iKPvbpjCSuCNyT2L/ahwAqVdhk9krlaXhoQ+QIgOzGlWyqXjjAIV+PBGRwMH78cNrSBxYNVoPKhA8UQQ3c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13331},"type":"module","exports":{".":"./out/index.js"},"gitHead":"6aec9633bac01447ebfb5c65cb2d0fbfc0be7a76","scripts":{"dev":"npm run clean && npm run dev:ts","lint":"eslint src/","clean":"rm -rf out/ *.tsbuildinfo","dev:ts":"tsc -b -w","compile":"npm run clean && npm run compile:ts","lint:fix":"eslint src/ --fix","compile:ts":"tsc -b"},"_npmUser":{"name":"christellevs","email":"christelle.marie@gmail.com"},"_npmVersion":"10.9.4","description":"Create a new A3 automation project","directories":{},"sideEffects":false,"_nodeVersion":"22.21.1","dependencies":{"zod":"^4.2.0","yaml":"^2.8.2","mesh-ioc":"^4.1.0","mesh-config":"^1.2.1","@athree/runner":"^2.0.1","@athree/module-loader":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.22.0","typescript":"^5.9.3","@types/node":"^24.10.1","@nodescript/eslint-config":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/create-project_1.0.2_1768307620616_0.4085387140903518","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@athree/create-project","version":"1.0.3","_id":"@athree/create-project@1.0.3","maintainers":[{"name":"christellevs","email":"christelle.marie@gmail.com"},{"name":"inca","email":"boris@okunskiy.name"}],"bin":{"create-project":"bin/create.js"},"dist":{"shasum":"85d7ea839a7e7963a0e2361e2e2b8c459a0330c2","tarball":"https://registry.npmjs.org/@athree/create-project/-/create-project-1.0.3.tgz","fileCount":13,"integrity":"sha512-DRG086UhXqYSwSGPmBXUVu8RXYiwMWzf6ipCIhn7CsRxuHhDcmSa6T/PSwjncH6tWIhkY6l9GpCyI+gwS6xTTA==","signatures":[{"sig":"MEQCIANFOccvRky9omL4bp11nXwM6GT9j5F9bQNZN7iISi66AiBhRxJNSdfZDUiIH9USkobjw3x0/pBbuEtxtZ/ZLsj/Yw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13434},"type":"module","exports":{".":"./out/index.js"},"gitHead":"eade1ccfe8f9990e819f28c2868b383e1d4e5885","scripts":{"dev":"npm run clean && npm run dev:ts","lint":"eslint src/","clean":"rm -rf out/ *.tsbuildinfo","dev:ts":"tsc -b -w","compile":"npm run clean && npm run compile:ts","lint:fix":"eslint src/ --fix","compile:ts":"tsc -b"},"_npmUser":{"name":"christellevs","email":"christelle.marie@gmail.com"},"_npmVersion":"10.9.4","description":"Create a new A3 automation project","directories":{},"sideEffects":false,"_nodeVersion":"22.21.1","dependencies":{"zod":"^4.2.0","yaml":"^2.8.2","mesh-ioc":"^4.1.0","mesh-config":"^1.2.1","@athree/runner":"^2.0.1","@athree/module-loader":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.22.0","typescript":"^5.9.3","@types/node":"^24.10.1","@nodescript/eslint-config":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/create-project_1.0.3_1768307959471_0.12421022866731901","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@athree/create-project","version":"1.0.4","_id":"@athree/create-project@1.0.4","maintainers":[{"name":"christellevs","email":"christelle.marie@gmail.com"},{"name":"inca","email":"boris@okunskiy.name"}],"bin":{"create-project":"bin/create.js"},"dist":{"shasum":"cf41a8deb35b9b2d46c4e321d42e9faaa86243b8","tarball":"https://registry.npmjs.org/@athree/create-project/-/create-project-1.0.4.tgz","fileCount":13,"integrity":"sha512-ebXsnc2Mw9mivIxZcNVMEeWaHF2LdwaB8CuQlbTnFQJwae6atIXngRNRzFx86b56wmneuonQPNCSQg6Uf43oLA==","signatures":[{"sig":"MEUCIF0kMpDpnOxc6F1brfgLGDydpbZ1Ob/0S2Rs+CWc7zcnAiEAtX2bjZuRNWOD7sjx0JSG5bB90R2xumjWLbZEFpZI5LI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13547},"type":"module","exports":{".":"./out/index.js"},"gitHead":"78afe242958b3f846ba3da45c9a8131d3294e726","scripts":{"dev":"npm run clean && npm run dev:ts","lint":"eslint src/","clean":"rm -rf out/ *.tsbuildinfo","dev:ts":"tsc -b -w","compile":"npm run clean && npm run compile:ts","lint:fix":"eslint src/ --fix","compile:ts":"tsc -b"},"_npmUser":{"name":"christellevs","email":"christelle.marie@gmail.com"},"_npmVersion":"10.9.4","description":"Create a new A3 automation project","directories":{},"sideEffects":false,"_nodeVersion":"22.21.1","dependencies":{"zod":"^4.2.0","yaml":"^2.8.2","mesh-ioc":"^4.1.0","mesh-config":"^1.2.1","@athree/runner":"^2.0.1","@athree/module-loader":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.22.0","typescript":"^5.9.3","@types/node":"^24.10.1","@nodescript/eslint-config":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/create-project_1.0.4_1768308457484_0.7060625312642517","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@athree/create-project","version":"1.1.0","_id":"@athree/create-project@1.1.0","maintainers":[{"name":"christellevs","email":"christelle.marie@gmail.com"},{"name":"inca","email":"boris@okunskiy.name"}],"bin":{"create-project":"bin/create.js"},"dist":{"shasum":"5b5bd274d2209d59fd61023987758cb45a79e21d","tarball":"https://registry.npmjs.org/@athree/create-project/-/create-project-1.1.0.tgz","fileCount":14,"integrity":"sha512-1y4EDRxgQVpvfLp2KYjeSCGV0UsirBM8OoDpBxuBfp5hPg80+jJq7xf6fuW3maWzEfn/9huQsqqybzlMHgNHuA==","signatures":[{"sig":"MEUCIQDZNmDIoZ3cvii7e1F7fWdBihvFULo8b3W7hLQQiGuiewIgH1KKSeXcCgT6JOKEnKeSwiMB6Bc9YGWPXoNGaLWbsLg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14032},"type":"module","exports":{".":"./out/index.js"},"gitHead":"7148d9346f89d3d256712e4c642df8256f3635bd","scripts":{"dev":"npm run clean && npm run dev:ts","lint":"eslint src/","clean":"rm -rf out/ *.tsbuildinfo","dev:ts":"tsc -b -w","compile":"npm run clean && npm run compile:ts","lint:fix":"eslint src/ --fix","compile:ts":"tsc -b"},"_npmUser":{"name":"christellevs","email":"christelle.marie@gmail.com"},"_npmVersion":"10.9.4","description":"Create a new A3 automation project","directories":{},"sideEffects":false,"_nodeVersion":"22.21.1","dependencies":{"zod":"^4.2.0","yaml":"^2.8.2","mesh-ioc":"^4.1.0","mesh-config":"^1.2.1","@athree/runner":"^2.0.1","@athree/module-loader":"^2.0.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.22.0","typescript":"^5.9.3","@types/node":"^24.10.1","@nodescript/eslint-config":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/create-project_1.1.0_1768411048832_0.5495179581182179","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@athree/create-project","version":"1.2.0","_id":"@athree/create-project@1.2.0","maintainers":[{"name":"christellevs","email":"christelle.marie@gmail.com"},{"name":"inca","email":"boris@okunskiy.name"},{"name":"marcusgreenwood_ubio","email":"mg2@ub.io"}],"bin":{"create-project":"bin/create.js"},"dist":{"shasum":"b123ed7318c73b76c2438698c0f4f4e107273009","tarball":"https://registry.npmjs.org/@athree/create-project/-/create-project-1.2.0.tgz","fileCount":18,"integrity":"sha512-5As86zIbd7Betg0GItgweAkg7Eplbh8NR2NcsZDlTSC/sCQcvn1GAppDDjJUyinHVr3Qf4zwS2D1rN0W+hqgfw==","signatures":[{"sig":"MEUCIEXShNugOdCD1U4rCWuvCTWgXNsNzeOIIbOSrfEmKVBIAiEAuYEgjMgtWXFy6d4G+/5GYoKbv9eQo532NW9CYX1OOOM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":22633},"type":"module","exports":{".":"./out/index.js"},"gitHead":"34c7a2b137072cebd78413701a4b0f1c410b7a16","scripts":{"dev":"npm run clean && run-p dev:ts dev:assets","lint":"eslint src/","clean":"rm -rf out/ *.tsbuildinfo","dev:ts":"tsc -b -w","compile":"npm run clean && npm run compile:ts && npm run compile:assets","lint:fix":"eslint src/ --fix","compile:ts":"tsc -b","dev:assets":"cpx 'src/**/*.md' out/ --watch","compile:assets":"cpx 'src/**/*.md' out/"},"_npmUser":{"name":"christellevs","email":"christelle.marie@gmail.com"},"_npmVersion":"10.9.4","description":"Create a new A3 automation project","directories":{},"sideEffects":false,"_nodeVersion":"22.21.1","dependencies":{"zod":"^4.2.0","yaml":"^2.8.2","mesh-ioc":"^4.1.0","mesh-config":"^1.2.1","@athree/runner":"^3.0.1","@athree/module-loader":"^3.0.1"},"_hasShrinkwrap":false,"devDependencies":{"cpx":"^1.5.0","eslint":"^9.22.0","typescript":"^5.9.3","@types/node":"^24.10.1","npm-run-all":"^4.1.5","@nodescript/eslint-config":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/create-project_1.2.0_1769529782048_0.9698142584169451","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@athree/create-project","version":"1.2.1","_id":"@athree/create-project@1.2.1","maintainers":[{"name":"christellevs","email":"christelle.marie@gmail.com"},{"name":"inca","email":"boris@okunskiy.name"},{"name":"marcusgreenwood_ubio","email":"mg2@ub.io"}],"bin":{"create-project":"bin/create.js"},"dist":{"shasum":"88220a8fd0607cf7496b92a0c0ec959fd61a6f09","tarball":"https://registry.npmjs.org/@athree/create-project/-/create-project-1.2.1.tgz","fileCount":18,"integrity":"sha512-+Muk2XtExWAE7qMRN0jjFfDkBH9mkp2QXc1w80NWBBThbq+6v1IMsyJUY+0+VGSw17lfhZosDY542cTXnQ2/eQ==","signatures":[{"sig":"MEQCIFiuKTAYxXPgOro0467qmKt87tlYDG2jALFl8p7JoZhoAiAgdtc7NOzjMVVXq/Eqh23ii7iCssiyfqukkTLOjfKHxg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":23421},"type":"module","exports":{".":"./out/index.js"},"gitHead":"18bfd8afb14024911f88974a438ff0b5ab349423","scripts":{"dev":"npm run clean && run-p dev:ts dev:assets","lint":"eslint src/","clean":"rm -rf out/ *.tsbuildinfo","dev:ts":"tsc -b -w","compile":"npm run clean && npm run compile:ts && npm run compile:assets","lint:fix":"eslint src/ --fix","compile:ts":"tsc -b","dev:assets":"cpx 'src/**/*.md' out/ --watch","compile:assets":"cpx 'src/**/*.md' out/"},"_npmUser":{"name":"christellevs","email":"christelle.marie@gmail.com"},"_npmVersion":"10.9.4","description":"Create a new A3 automation project","directories":{},"sideEffects":false,"_nodeVersion":"22.21.1","dependencies":{"zod":"^4.2.0","yaml":"^2.8.2","mesh-ioc":"^4.1.0","mesh-config":"^1.2.1","@athree/runner":"^3.0.1","@athree/module-loader":"^3.0.1"},"_hasShrinkwrap":false,"devDependencies":{"cpx":"^1.5.0","eslint":"^9.22.0","typescript":"^5.9.3","@types/node":"^24.10.1","npm-run-all":"^4.1.5","@nodescript/eslint-config":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/create-project_1.2.1_1769530045394_0.3974308992333415","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@athree/create-project","version":"1.3.0","_id":"@athree/create-project@1.3.0","maintainers":[{"name":"christellevs","email":"christelle.marie@gmail.com"},{"name":"inca","email":"boris@okunskiy.name"},{"name":"marcusgreenwood_ubio","email":"mg2@ub.io"}],"bin":{"create-project":"bin/create.js"},"dist":{"shasum":"1795e1f1129f2f3e6b4885a38cdc7d12dcedcdbc","tarball":"https://registry.npmjs.org/@athree/create-project/-/create-project-1.3.0.tgz","fileCount":71,"integrity":"sha512-IQ3aYGSQqkNZ4E+9R2gLGDVkVFfDC3y5Tmp/HYjXfXeLTyC1QUhA2DiXkIsLqDSp1csNtKY4J+5mQdgYe8g2vw==","signatures":[{"sig":"MEUCIQD47Yqc5q6cq12+pziXFHsnzQ2egvHfJi4uGjg9dcX5GAIgFwA+eRPwqskQK0Xa3iOdANV4KVBSCRBMEc+TkDAtc/A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2550267},"type":"module","exports":{".":"./out/index.js"},"gitHead":"b4a6bb76523bad6aaac5d86d6ab5c1ca87a18401","scripts":{"dev":"npm run clean && run-p dev:ts dev:assets","lint":"eslint src/","clean":"rm -rf out/ *.tsbuildinfo","dev:ts":"tsc -b -w","compile":"npm run clean && npm run compile:ts && npm run compile:assets","lint:fix":"eslint src/ --fix","compile:ts":"tsc -b","dev:assets":"cpx 'src/**/*.md' out/ --watch","compile:assets":"cpx 'src/**/*.md' out/"},"_npmUser":{"name":"christellevs","email":"christelle.marie@gmail.com"},"_npmVersion":"10.9.4","description":"Create a new A3 automation project","directories":{},"sideEffects":false,"_nodeVersion":"22.21.1","dependencies":{"zod":"^4.2.0","yaml":"^2.8.2","mesh-ioc":"^4.1.0","mesh-config":"^1.2.1","@athree/runner":"^3.0.1","@athree/module-loader":"^3.0.1"},"_hasShrinkwrap":false,"devDependencies":{"cpx":"^1.5.0","eslint":"^9.22.0","typescript":"^5.9.3","@types/node":"^24.10.1","npm-run-all":"^4.1.5","@nodescript/eslint-config":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/create-project_1.3.0_1770291447144_0.7945654660286425","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@athree/create-project","version":"1.4.0","_id":"@athree/create-project@1.4.0","maintainers":[{"name":"christellevs","email":"christelle.marie@gmail.com"},{"name":"inca","email":"boris@okunskiy.name"},{"name":"marcusgreenwood_ubio","email":"mg2@ub.io"}],"bin":{"create-project":"bin/create.js"},"dist":{"shasum":"eb95a2040d8f396d3d0bf386813a60acd98036ca","tarball":"https://registry.npmjs.org/@athree/create-project/-/create-project-1.4.0.tgz","fileCount":71,"integrity":"sha512-UrGzvuMyYL2B4tY8tptfg3O6yQaUzUdKFokgq7Kq+5AopdFX3V1uaRmFShSmOp64YDvyEZOuQPvsBJsKYnIMGg==","signatures":[{"sig":"MEYCIQDrw8oU5+lIGdvcpyvsh44zDxIZiiLFEm072IRpKkBvtQIhAIU95WOgSXXX9xdRgoK5vh/l1+vpEqLPMwXVXRepqq39","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2550578},"type":"module","exports":{".":"./out/index.js"},"gitHead":"e20b29813d67f09fdd737836559991236d0f9236","scripts":{"dev":"npm run clean && run-p dev:ts dev:assets","lint":"eslint src/","clean":"rm -rf out/ *.tsbuildinfo","dev:ts":"tsc -b -w","compile":"npm run clean && npm run compile:ts && npm run compile:assets","lint:fix":"eslint src/ --fix","compile:ts":"tsc -b","dev:assets":"cpx 'src/**/*.md' out/ --watch","compile:assets":"cpx 'src/**/*.md' out/"},"_npmUser":{"name":"christellevs","email":"christelle.marie@gmail.com"},"_npmVersion":"10.9.4","description":"Create a new A3 automation project","directories":{},"sideEffects":false,"_nodeVersion":"22.21.1","dependencies":{"zod":"^4.2.0","yaml":"^2.8.2","mesh-ioc":"^4.1.0","mesh-config":"^1.2.1","@athree/runner":"3.4.0","@athree/module-loader":"3.4.0"},"_hasShrinkwrap":false,"devDependencies":{"cpx":"^1.5.0","eslint":"^9.22.0","typescript":"^5.9.3","@types/node":"^24.10.1","npm-run-all":"^4.1.5","@nodescript/eslint-config":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/create-project_1.4.0_1771004979733_0.39072747525952956","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-01-13T12:33:40.509Z","modified":"2026-03-20T14:34:47.139Z","1.0.2":"2026-01-13T12:33:40.759Z","1.0.3":"2026-01-13T12:39:19.638Z","1.0.4":"2026-01-13T12:47:37.621Z","1.1.0":"2026-01-14T17:17:28.991Z","1.2.0":"2026-01-27T16:03:02.215Z","1.2.1":"2026-01-27T16:07:25.553Z","1.3.0":"2026-02-05T11:37:27.351Z","1.4.0":"2026-02-13T17:49:39.938Z"},"description":"Create a new A3 automation project","maintainers":[{"email":"mihonninja@gmail.com","name":"mihon"},{"email":"christelle.marie@gmail.com","name":"christellevs"},{"email":"boris@okunskiy.name","name":"inca"},{"email":"mg2@ub.io","name":"marcusgreenwood_ubio"}],"readme":"# A3 Project Template\n\nCreate and scaffold A3 automation workflows.\n\n> **Note:** Always use the latest versions of `@athree/runner` and `@athree/module-loader`.\n> You can find the latest versions on npm:\n> - [@athree/runner](https://www.npmjs.com/package/@athree/runner)\n> - [@athree/module-loader](https://www.npmjs.com/package/@athree/module-loader)\n>\n> Or check the latest release commits at https://github.com/ubio/athree/commits/main/\n\n## Create a New Project\n\n```bash\nnpx @athree/create-project a3-project-starter\ncd a3-project-starter\nnpm i && npm run compile\n```\n\n**Naming convention:** Projects should be named `a3-project-{name}` (e.g., `a3-project-hotel-rates`).\n\n> **Note:** You must run `npm run compile` for the project to appear in your local athree runner.\n\nOr clone manually:\n\n```bash\ncp -r a3-project-template a3-project-starter\ncd a3-project-starter\nnpm i && npm run compile\n```\n\n## Adding Project to Runner\n\nUse the **Add Project** button in the A3 runner UI to add your project directory. The runner will automatically detect workflows in compiled projects.\n\n## Environment Setup\n\nConfigure your environment variables before running workflows:\n\n```bash\ncp .env.example .env\n# Edit .env and add your API keys\n```\n\n**Required variables:**\n- At least one LLM API key: `GOOGLEAI_API_KEY`, `OPENAI_API_KEY`, or `ANTHROPIC_API_KEY`\n\n**Optional variables:**\n- `CHROME_HEADLESS` — Run browser in headless mode (default: `true`)\n- `CHROME_KEEP_OPEN` — Keep browser open between runs (default: `true`)\n- `CHROME_PERSISTENT` — Use persistent browser profile (default: `false`). Required for extensions. See [Chrome Extensions](#chrome-extensions).\n- `EXTENSIONS_CONFIG_PATH` — Path to your `extensions.json` file. See [Chrome Extensions](#chrome-extensions).\n\n## Chrome Extensions\n\nBrowser extensions (e.g. captcha solvers, cookie consent handlers) can be automatically installed into the Chrome profile before your workflow runs. This requires four steps:\n\n### Step 1: Install the dependency\n\n```bash\nnpm install @athree/runner-extensions\n```\n\n### Step 2: Create the extensions directory and config\n\nThis template ships with the `idcac` (I don't care about cookies) extension pre-installed in `chrome-extensions/`. To add more extensions, copy unpacked extension directories from `a3-rate-shopper/chrome-extensions/` or other projects and add entries to `extensions.json`.\n\n```\n├── chrome-extensions/\n│   ├── extensions.json          # Extension manifest\n│   ├── idcac/                   # Pre-installed: cookie consent automation\n│   └── {your-extension}/        # Add more as needed\n```\n\nEach extension must be an **unpacked Chrome extension** (a directory containing a `manifest.json`). You can get these by:\n- Copying from an existing project (e.g. `a3-rate-shopper/chrome-extensions/`)\n- Downloading a `.crx` file and extracting it\n- Cloning the extension source from GitHub\n\nThe `extensions.json` file lists which extensions to load:\n\n```json\n{\n    \"extensions\": [\n        {\n            \"name\": \"idcac\",\n            \"path\": \"./chrome-extensions/idcac\",\n            \"description\": \"I don't care about cookies - Cookie consent automation\",\n            \"enabled\": true,\n            \"loadInPersistent\": true,\n            \"loadInTransient\": true\n        }\n    ]\n}\n```\n\nTo add a captcha solver, copy the directory and add an entry:\n\n```json\n{\n    \"name\": \"capsolver\",\n    \"path\": \"./chrome-extensions/capsolver\",\n    \"description\": \"CapSolver - Automated captcha solving extension\",\n    \"enabled\": true,\n    \"loadInPersistent\": true,\n    \"loadInTransient\": false\n}\n```\n\n**Fields:**\n- `name` — Human-readable identifier\n- `path` — Relative path from the project root to the unpacked extension directory\n- `description` — What the extension does\n- `enabled` — Set to `false` to skip without removing the entry\n- `loadInPersistent` — Load when the browser runs in persistent mode (`CHROME_PERSISTENT=true`)\n- `loadInTransient` — Load when the browser runs in transient mode (default)\n\n### Step 3: Set environment variables\n\nAdd these to your `.env` file:\n\n```bash\nCHROME_PERSISTENT=true\nEXTENSIONS_CONFIG_PATH=./chrome-extensions/extensions.json\n```\n\n> **Important:** Most captcha solver extensions set `loadInPersistent: true` and `loadInTransient: false`, so `CHROME_PERSISTENT=true` is required for them to load.\n\n### Step 4: Call `installExtensions()` in your workflow\n\nIn your workflow's `run()` method, register the service and install extensions **before** calling `getPage()`:\n\n```typescript\nimport { BrowserService, workflow } from '@athree/runner';\nimport { BrowserExtensionsService } from '@athree/runner-extensions';\nimport { dep, Mesh } from 'mesh-ioc';\n\n@workflow({ title: 'My Workflow' })\nexport class MyWorkflow {\n    @dep() private browserService!: BrowserService;\n    @dep() private browserExtensionsService!: BrowserExtensionsService;\n    @dep() private mesh!: Mesh;\n\n    async run() {\n        // 1. Register and install extensions (BEFORE getPage)\n        this.mesh.service(BrowserExtensionsService);\n        await this.browserExtensionsService.installExtensions(\n            true,\n            this.browserService.userDataDir,\n        );\n\n        // 2. Now get the page — extensions will be active\n        const page = await this.browserService.getPage();\n        await page.goto('https://example.com');\n\n        // ... rest of your workflow\n    }\n}\n```\n\n**Key points:**\n- `this.mesh.service(BrowserExtensionsService)` registers the service in the DI container\n- `installExtensions(true, ...)` — first argument is `isPersistent` (matches against `loadInPersistent`/`loadInTransient` in config)\n- Extensions are installed into the Chrome user data directory, so they persist across runs\n- The service uses Puppeteer internally to enable Chrome developer mode and load unpacked extensions\n- Extensions only get installed once — subsequent runs detect they are already present and skip installation\n\n## Project Structure\n\n```\n├── chrome-extensions/           # Browser extensions (see Chrome Extensions)\n│   ├── extensions.json          # Extension manifest\n│   └── idcac/                   # Cookie consent handler (pre-installed)\n├── datasets/                    # Input YAML files (one per service)\n├── services/                    # Output directory (gitignored)\n│   └── {service-id}/\n│       ├── screenshot.png       # Page screenshot\n│       └── result.json          # Workflow result\n├── src/\n│   ├── instructions/            # LLM instructions (markdown files)\n│   ├── schema/                  # Zod schemas (Dataset, Result)\n│   └── workflows/               # Workflow classes\n```\n\n## Included Workflows\n\n### SimpleScreenshot\n\nA minimal workflow demonstrating basic browser automation:\n1. Navigates to a URL\n2. Waits for page load\n3. Takes a full-page screenshot\n\nUseful as a starting point or for testing browser connectivity.\n\n### SimpleGenericWebAgent\n\nDemonstrates the `GenericWebAgent` pattern:\n1. Navigates to a URL\n2. Creates a `GenericWebAgent` via `AgentsService`\n3. Runs the agent with a simple text objective\n\nThis is the simplest way to use LLM-powered web automation - no stages, no schemas, just a one-shot LLM call with browser tools.\n\n### SimpleLearningAgentExtract\n\nDemonstrates the learning agent pattern with stages:\n1. Loads instructions from a markdown file\n2. Sets up automation context with input/output schemas\n3. Uses `AutomationRunner.learn()` to execute with LLM guidance\n4. The LLM creates reusable stages to navigate and extract data\n\nUse this pattern for complex, multi-step automations that benefit from reusable stages.\n\n## Getting Started\n\n1. Set up environment variables (see [Environment Setup](#environment-setup))\n2. Run `npm run compile` to build the project\n3. Update the dataset in the workflow (or load from `datasets/`)\n4. Define instructions in `src/instructions/` for LLM-powered workflows\n5. Update schemas in `src/schema/` to match your data\n\n## Key Services\n\n- `ChatService` — Send messages to the UI\n- `BrowserService` — Access the browser page for screenshots, navigation\n- `AgentsService` — Create LLM agents (`createGenericWebAgent()`, `createPageExtractor()`)\n- `AutomationRunner` — Run automations with `run()` (existing stages) or `learn()` (LLM-guided)\n- `AutomationContext` — Manage automation state, inputs, outputs, and schemas\n\n## GenericWebAgent Pattern\n\nFor simple one-shot LLM tasks, use `GenericWebAgent`:\n\n```typescript\nimport { AgentsService, BrowserService, workflow } from '@athree/runner';\nimport { dep } from 'mesh-ioc';\n\n@workflow({ title: 'My Workflow' })\nexport class MyWorkflow {\n    @dep() private browserService!: BrowserService;\n    @dep() private agentsService!: AgentsService;\n\n    async run() {\n        const page = await this.browserService.getPage();\n        await page.goto('https://example.com');\n\n        const agent = this.agentsService.createGenericWebAgent();\n        agent.addUserContext({ currentUrl: page.url() });\n\n        await agent.run('Extract the main heading and description from this page.');\n    }\n}\n```\n\n## Learning Agent Pattern\n\nFor complex multi-step automations with reusable stages, use the learning agent:\n\n```typescript\nimport { AutomationRunner, AutomationContext, workflow } from '@athree/runner';\nimport { dep } from 'mesh-ioc';\nimport { z } from 'zod';\n\n@workflow({ title: 'My Workflow' })\nexport class MyWorkflow {\n    @dep() private automationRunner!: AutomationRunner;\n    @dep() private automation!: AutomationContext;\n\n    async run() {\n        const result = await this.automationRunner.learn({\n            automationId: 'my-automation',\n            instructions,           // Loaded from .md file\n            inputs: { url },        // Input data\n            inputsSchema,           // Zod schema for inputs\n            outputsSchema,          // Zod schema for expected outputs\n            learningModel: 'gemini-2.5-flash',  // Optional: specify LLM model\n        });\n\n        const outputs = this.automation.outputs;\n    }\n}\n```\n\n## Instructions Files\n\nInstructions tell the LLM how to handle different page states. Place them in `src/instructions/`:\n\n```markdown\n# Goal\nExtract product details from the page.\n\n# Output Fields\n- `ctx.outputs.title` - Product title\n- `ctx.outputs.price` - Product price\n- `ctx.outputs.status` - \"success\" or \"failure\"\n\n# Instructions\n## Product page\n1. Extract the title from h1\n2. Extract the price\n3. Set status to \"success\"\n```\n\n## Tips\n\n- Define clear output fields in your instructions\n- Use Zod schemas to validate inputs and outputs\n- The LLM creates reusable stages that can be re-run without LLM\n- Save results to the `services/` folder\n","readmeFilename":"README.md"}