{"id":51136167,"url":"https://github.com/contember/opice","last_synced_at":"2026-06-25T18:01:45.619Z","repository":{"id":359147307,"uuid":"1243682200","full_name":"contember/opice","owner":"contember","description":"AI-driven E2E browser test harness","archived":false,"fork":false,"pushed_at":"2026-06-22T16:43:41.000Z","size":536,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-22T17:16:20.673Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/contember.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-19T15:05:50.000Z","updated_at":"2026-06-22T15:29:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/contember/opice","commit_stats":null,"previous_names":["contember/opice"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/contember/opice","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contember%2Fopice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contember%2Fopice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contember%2Fopice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contember%2Fopice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/contember","download_url":"https://codeload.github.com/contember/opice/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contember%2Fopice/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34786238,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-25T02:00:05.521Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-25T18:01:44.673Z","updated_at":"2026-06-25T18:01:45.613Z","avatar_url":"https://github.com/contember.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Opice\n\nAI-driven E2E browser test harness. Human-readable scenarios → LLM-generated tests → deterministic CI runs → centralized reporting.\n\n\u003e Status: **v1 done**. Single-user, single-tenant. Ready to dogfood.\n\n## What it is\n\nA monkey-testing harness (hence \"opice\") for web apps:\n\n1. You write a human-readable scenario in markdown (`login.scenario.md`).\n2. The `opice-author` Claude Code skill walks the running app via `opice-browser` (a stateful [Playwright](https://playwright.dev) browser), generates a `*.test.ts` file with `data-testid`/role/label selectors, verifies it passes, commits.\n3. CI runs the generated tests deterministically (no LLM in the loop) via `opice test`, streaming results + screenshots to the central reporting platform.\n4. The dashboard SPA shows the runs / scenarios / steps / screenshots, type-safely fetched via the worker's tRPC-like `/rpc` endpoint.\n\n## Architecture\n\n- **Tests live in your repo.** Reviewed in PRs, atomic with UI changes, debuggable locally.\n- **Browser runs in CI** (or locally) — Playwright in-process under `bun test`. No remote browser farm.\n- **Reporting platform on Cloudflare:** Worker (`/api/v1/*` ingest, `/rpc` for dashboard, `/screenshots/*` proxy), D1 for run metadata, R2 for screenshots, served SPA via `ASSETS` binding.\n- **Dashboard SPA** with buzola routing + React Query, RPC client typed from the worker's `AppRouter`.\n- **AI authoring is local** — Claude Code skill on your machine. No server-side LLM.\n\n## Repo layout\n\n```\nopice/\n├── packages/\n│   ├── harness/    # @opice/harness — Playwright runtime: el(), byRole(), browserTest(), step(), command()\n│   ├── browser/    # @opice/browser — opice-browser: stateful Playwright CLI for authoring (CDP)\n│   ├── worker/     # CF Worker — D1 + R2 + ingest API + /rpc + dashboard ASSETS\n│   ├── dashboard/  # React SPA (buzola + react-query), built into worker/ASSETS\n│   └── cli/        # opice CLI — init + test wrapper\n├── skills/\n│   └── opice-author/  # Claude Code skill, install via bun run skills:install\n├── scripts/\n│   └── install-skills.ts\n└── okena.yaml      # `okena` services: worker (18181) + dashboard vite (18182)\n```\n\n## Quickstart\n\n```bash\n# 1. Boot the platform\nbun install\nbun --filter @opice/worker run db:migrate:local\nbun --filter @opice/worker run dev      # worker on http://localhost:18181\n\n# In another terminal:\nbun --filter @opice/dashboard run dev   # vite dev on http://localhost:18182\n# Or just `okena` if you have it — see okena.yaml\n\n# 2. Create a project in the dashboard → \"New project\".\n#    Locally the operator gate is open (a default-admin persona — no Cloudflare\n#    Access needed), so you land straight in. Creating a project shows its\n#    OPICE_DSN (write) + OPICE_READ_DSN once — copy the OPICE_DSN.\n\n# 3. Wire opice into your project\ncd ~/projects/my-app\nbunx opice init --project=my-app --endpoint=http://localhost:18181 --with-workflow\necho \"OPICE_DSN=\u003cthe OPICE_DSN from step 2\u003e\" \u003e\u003e .env\n\n# 4. Author a scenario\necho \"# Login flow ... \" \u003e tests/login.scenario.md\n# In Claude Code: /opice-author tests/login.scenario.md\n\n# 5. Run + report\nbunx opice test tests/login.test.ts\n# Watch results stream into http://localhost:18182\n# Or, no platform needed — write a local HTML report (the dashboard, offline):\nbunx opice test tests/login.test.ts --report   # writes .opice/report.html\n```\n\n## Deploy\n\nGitHub Actions live in [`.github/workflows/`](.github/workflows):\n\n- **`ci.yml`** — runs on every PR + push to main. Typechecks every package, generates buzola routes, builds the dashboard.\n- **`deploy.yml`** — push to `main` deploys `stage`; push to `deploy/prod` deploys `prod`. `workflow_dispatch` is also wired up as a manual backup with an env picker. Both targets run `bunx oblaka oblaka.ts --env=\u003cenv\u003e --state-namespace=opice-state --remote`, which provisions D1 (`opice`) + R2 if missing (oblaka also auto-creates the `opice-state` KV namespace it stores resource state in), deploys the worker, then applies pending D1 migrations.\n\nOperator authentication is **Cloudflare Access** at the edge; authorization + audit + run-share capability tokens come from the **propustka** IAM Worker, reached over the `IAM` service binding (declared off-local in `oblaka.ts`). opice is not fully behind Access — anonymous run-share links + the machine ingest/read DSN plane reach the Worker directly (see `packages/worker/CLAUDE.md`).\n\nRequired repository secrets:\n\n| Secret | Used by |\n| --- | --- |\n| `CLOUDFLARE_API_TOKEN` | oblaka + wrangler |\n| `CLOUDFLARE_ACCOUNT_ID` | oblaka + wrangler |\n| `OPICE_SELF_READ_TOKEN` | the self-test job (a global read DSN token, minted once in the dashboard) |\n\nSet distinct values per GitHub *environment* (`stage` / `prod`) and the workflow picks them up via the `environment:` key.\n\n## v1 roadmap\n\n- [x] Week 1: `@opice/harness` extracted from bindx prototype\n- [x] Week 2: CF Worker + D1 + R2 + SPA dashboard\n- [x] Week 3: `opice-author` Claude skill\n- [x] Week 4: `@opice/cli` (init + test) + GH Action template + dogfooded on bindx\n\n## Non-goals (v1)\n\n- Visual regression (screenshots are evidence, not asserts)\n- Multi-tenant SaaS (single-org — operators sign in via Cloudflare Access, authorization from the propustka IAM directory; plus per-run capability-token links for read-only sharing)\n- AI in CI loop (authoring is local only)\n- Browser farm in platform (you run your own browser)\n\nSee the **Non-goals** and **Architecture** sections above for the design decisions and locked-in tradeoffs.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontember%2Fopice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcontember%2Fopice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontember%2Fopice/lists"}