Local e2e
Outbound sales, autopiloted.
npx -y skills add aitit-inc/leadace --skill local-e2eAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Local LeadAce E2E testing skill. Triggers: 'local E2E', 'ローカル E2E', 'local-e2e', 'E2E テスト', E2E run against the local stack. Encodes the prerequisites: host-side `claude` CLI, real Google OAuth, local Supabase / Workers / Frontend. Concrete scenarios are user-supplied per run.
SKILL.md
10.4 KB, as published. Nobody here has run it
Local E2E test skill
Drive the local stack (Supabase / API Worker / MCP Worker / Frontend) from the host claude CLI, isolated under CLAUDE_CONFIG_DIR=$REPO_ROOT/e2e/.claude-state, against user-supplied scenarios.
The plugin is rsynced to e2e/.plugin-staging/ on every run with the staged .mcp.json URL hard-coded to http://localhost:8788/mcp and loaded via --plugin-dir. Claude Code's plugin loader only expands ${user_config.KEY}, not ${ENV_VAR:-default}, so an env-var override on the original plugin/.mcp.json would not take effect; the staging step writes the literal URL instead. LEADACE_MCP_URL=... still works as an override at staging-build time.
Concrete test scenarios come from the user. This skill captures the prerequisites, run procedure, and cleanup needed to drive them safely.
Core principles
- Never touch production.
api.leadace.ai/mcp.leadace.ai/ the production Supabase project are off-limits. Everything runs against the local stack. - Don't bypass OAuth. Google OAuth, Supabase Auth, and MCP OAuth all run their real flows. No test-only backdoors in the codebase (so self-host installs run the same code path).
- Local DB is fair game, but be careful not to clobber another in-flight workspace. Reset with
npx supabase db reset; reseedmaster_documentswithcd backend && npx tsx scripts/seed-master-documents.ts. - Don't touch host-side Claude state. The harness uses
$REPO_ROOT/e2e/.claude-state/asCLAUDE_CONFIG_DIRand never writes to~/.claude/.
Pre-flight checks
The local stack must be running on the host:
| Service | Start command | Health check |
|---|---|---|
| Supabase Auth (54321) + Postgres (54322) | npx supabase start | curl http://localhost:54321/auth/v1/health |
| API Worker (8787) | cd backend && npm run dev:api | curl http://localhost:8787/health |
| MCP Worker (8788) | cd backend && npm run dev:mcp | curl http://localhost:8788/.well-known/oauth-authorization-server |
| Frontend (5273) | cd frontend && npm run dev | curl http://localhost:5273 |
| Claude CLI | (host install) | claude --version |
./e2e/preflight.sh runs all five at once and prints a FAIL: line for any missing piece.
One-time setup
Detailed harness setup lives in e2e/README.md. The skeleton:
- In Google Cloud Console, create a Web OAuth client and add
http://localhost:54321/auth/v1/callbackto its redirect URIs. - Export
SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_ID/SECRET, thennpx supabase stop && start(persist viadirenv+.envrc—.envrc.examplelives at the repo root). - Put the same values in
backend/.dev.varsasGOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET. - Run
./e2e/setup.shto populate the harness state dir with a Claude Code login + the LeadAce MCP OAuth grant:/login(sign in via browser if not already)/leadace overview(★ verify the OAuth dance URL ishttp://localhost:8788/authorize, click Allow, browser lands on127.0.0.1:47291/callback)/exit
State persists in e2e/.claude-state/ (gitignored), so subsequent runs skip the dance. After a wrangler dev restart, MCP refresh tokens are lost with the in-memory KV — re-run setup.sh (/login is a no-op, /leadace overview redoes the MCP OAuth only).
Running
0. Standard smoke (onboarding chain)
A one-shot wrapper that runs /leadace end-to-end (intent classification + env_check Mode B + strategy_drafting Mode B + 4B-4 summary) and auto-cleans the project it created:
./e2e/smoke.sh # default URL: https://example.com
./e2e/smoke.sh https://leadace.ai # custom URL
SKIP_CLEANUP=1 ./e2e/smoke.sh # keep the project for manual inspection
Behavior:
- Prompts include "no interactive Q&A available, sensible defaults, do not send outreach" so the run is headless.
- The
/leadaceresult ends inPROJECT_ID=<id>; the shell parses it. - Unless
SKIP_CLEANUP=1, the wrapper invokes/delete-project <id>to leave the tenant clean. - Output JSON:
e2e/output/smoke-leadace-*.jsonandsmoke-cleanup-*.json. - Exit codes: 0 = all OK, 1 =
/leadacefailed, 2 = couldn't parse PROJECT_ID, 3 = cleanup failed.
The harness budget defaults to --max-budget-usd 1.50 (MAX_BUDGET_USD env override). The cost figure is an API-equivalent reference under subscription auth, not a real charge — it consumes Claude Pro/Max/Team rate quota only.
1. Worker log tail (optional, side-by-side)
smoke.sh does not read Worker logs. For bug investigations or behavior deep-dives, tail in a separate terminal: each wrangler dev window already prints HTTP method / path / status / Worker logs. Request IDs make API ⇔ MCP correlation easy to eyeball.
2. Arbitrary scenario runs (when smoke.sh is too narrow)
./e2e/run.sh "<prompt>"
Examples:
./e2e/run.sh "/leadace https://example.com"
./e2e/run.sh "/daily-cycle <project-id>"
Phrasing the prompt so it includes "no interactive Q&A is available" pushes the agent toward defaults — smoke.sh's prompt is a good template. Output JSON streams to stdout; capture with > e2e/output/run-$(date +%s).json if you want to keep it.
3. DB inspection
The local Postgres is reachable at psql 'postgresql://postgres:postgres@localhost:54322/postgres'. Supabase Studio UI: http://localhost:54323.
-- Recent outreach
SELECT id, project_id, prospect_id, status, sent_at, error_message
FROM outreach_logs ORDER BY sent_at DESC LIMIT 10;
-- Prospect status distribution for one project
SELECT status, COUNT(*) FROM project_prospects
WHERE project_id = '<project-id>' GROUP BY status;
-- Test accounts
SELECT id, email FROM auth.users ORDER BY created_at DESC LIMIT 5;
The local DB is not the production DB — SELECT / UPDATE / DELETE are fair game without per-operation approval. Production-DB operations still require the standard per-operation user approval, but that path doesn't enter this skill.
4. Triggering Cloudflare cron jobs
wrangler dev does not fire scheduled triggers automatically. The API Worker is started with --test-scheduled, which exposes a /__scheduled endpoint that fires the scheduled handler on demand:
./e2e/trigger-cron.sh # fires the daily org-signals refresh
curl 'http://localhost:8787/__scheduled?cron=0+3+*+*+*' # raw equivalent
Watch the API Worker terminal for [scheduled] org-signals refresh log lines. The handler runs on the local DB only and respects the per-run cap inside runDailySignalRefresh.
5. Cleanup
To delete a single project: invoke /delete-project <id> via Claude (smoke.sh does this automatically).
To wipe the local DB end-to-end:
npx supabase db reset
cd backend && npx tsx scripts/seed-master-documents.ts
To reset the harness Claude state (forces re-login):
rm -rf e2e/.claude-state
Troubleshooting
./e2e/preflight.shfails withFAIL: API Worker(or similar): the named service isn't running on the host. Start it from the table above./authorizereturns 500 during./e2e/setup.sh: the MCP Worker likely has env vars missing. Checkbackend/.dev.varsforSUPABASE_JWT_SECRET/SUPABASE_URL/SUPABASE_ANON_KEY/WEB_API_URL.- Google consent screen says
redirect_uri_mismatch: the Web OAuth client in Google Cloud Console lackshttp://localhost:54321/auth/v1/callback. - After
wrangler devrestart Claude saysMCP needs authorization: the local MCP KV is in-memory and didn't survive the restart. Re-run./e2e/setup.sh(only the/leadace overviewMCP OAuth step needs redoing). MCP_OAUTH_CALLBACK_PORTcollides with another process: override withMCP_OAUTH_CALLBACK_PORT=<port> ./e2e/setup.sh.- Host-side
claudeis reading the harness state: check thatCLAUDE_CONFIG_DIRisn't still exported in the shell you're invokingclaudefrom. Going through./e2e/*.shalways isolates correctly. /leadace overviewlists unfamiliar / production-looking projects: either staging is stale, ore2e/.claude-stateretains an old production OAuth refresh token.rm -rf e2e/.claude-state e2e/.plugin-stagingand redo./e2e/setup.sh. During the OAuth dance, confirm the URL begins withhttp://localhost:8788/authorize.
Do not
- Add
--dangerously-skip-permissions(or any other safety bypass) to harness scenarios. - Leave
LEADACE_MCP_URLpointed at production (https://mcp.leadace.ai/mcp); the harness defaults tolocalhost:8788, but env overrides are honored. - Commit
accounts.local.json(the*.local.jsonignore covers it, but be explicit). - Commit
e2e/.claude-state/(covered bye2e/.gitignore).
Coverage status
Curl-only regressions (no Claude session, no Anthropic budget) — run all via
./e2e/regression-all.sh, or each individually:
- ✅
regression-build-list-dedup.sh—check_prospect_dedup+ Phase 1.5 + normalize-domain. - ✅
regression-outbound.sh—send-and-record: compliance gate, draft mode, country guardrail, real-Gmail send (redirected toE2E_RECIPIENT_OVERRIDE). - ✅
regression-skip-reachable.sh—skip_prospect('skipped' audit row, all reasons) +listReachablecandidate-stage country filter (US/CA/JP/NULL admitted, GB excluded). - ✅
regression-followup-sequence.sh— P1 day-scale follow-up: seed/advance viamarkProspectContacted, thelistReachablefollow-up arm (short_cycle_followup/touchNumber), reply stop-wiring, the enabled=false kill-switch + effective-disabled (omitted-enabled) clear, and the disabled/no-backfill path.
Onboarding chain is covered by ./e2e/smoke.sh (drives the Claude CLI; needs a live MCP grant).
Still Phase 2 (not yet implemented):
- daily-cycle full run — chain check-responses → evaluate → outbound + build-list end-to-end.
- Reaction detection automation — either plant replies in a test mailbox so
/check-responsescan pick them up, or substitute the inquiry-landing webhook path.
Related resources
- Harness internals:
e2e/README.md - Local dev setup:
docs/self-host.md→ Local development - Plugin skill catalog:
plugin/skills/