Skip to content

feat(error-tracking): build during the run and verify before the report - #424

Merged
ablaszkiewicz merged 5 commits into
mainfrom
feat/error-tracking-agent-builds
Oct 19, 2026
Merged

ablaszkiewicz merged 5 commits into
mainfrom
feat/error-tracking-agent-builds

Conversation

@ablaszkiewicz

@ablaszkiewicz ablaszkiewicz commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Pull requests:

  1. 👉 feat(error-tracking): build during the run and verify before the report #424: the flow's task prompts and the upload skill (this PR)
  2. feat(error-tracking): build the project in the linear fallback prompt wizard#1438: the linear-fallback prompt and the e2e profile summary
  3. feat(error-tracking): add stack-specific error-tracking fixtures wizard-workbench#4482: stack-specific test apps

Problem

The error-tracking tasks were told they cannot run the build. Each task had to write code that compiles by construction, and nothing built the finished setup. On Pi the agent can run the project's build (npm run build, cargo build, go build, Gradle, Xcode), so the flow can check its own work. Without that check, runs shipped setups that broke the build:

  • Next.js and Vite configs turned on source-map upload unconditionally, so every build without upload credentials (a teammate's checkout, a pull-request build) failed with projectId is required when sourcemaps are enabled.
  • Next.js got a posthog-node dependency that no code imported, and server errors went uncaptured.

Changes

  • verify (new task): runs after every task that edits code, when the upload subgraph is queued. It installs, runs the production build, reads the exit status and the uploader's release and upload lines, and fixes what this run broke. When configure already ran a passing build with credentials and nothing edited code after it, verify reuses that build. It always ends done, so the report still runs.
  • capture-exceptions: builds or typechecks after its edits and fixes what it broke. It covers the server runtime with the SDK's server library (for Next.js, onRequestError in instrumentation.ts) and installs only that library. In a project with no build of its own (most Python, Ruby and PHP apps) it runs nothing: no virtualenvs, package installs or Docker.
  • configure: builds after its edits. The build must pass with and without upload credentials, so the upload skips itself when they are missing. An env-file flag or loader that the project's start already has stays.
  • Seed: queues verify with the upload subgraph, alongside wire-ci, and queues the tail one task per turn so report and test-setup can name their dependencies. Python, Ruby and PHP get no verify.
  • install: installs only the SDK the init constructs. The server library is left to capture-exceptions. A Python project gets no new virtualenv: without one in the project, the package goes into the manifest only.
  • init: does not build, because install may still be running beside it. The type-narrowing guidance is gone; the later builds catch type errors.
  • init and credentials: both add their lines to .env.example with edit. They run in parallel, and a write from one dropped the other's variables.
  • The agent's shell, in capture-exceptions, configure and verify: build, never run. expo run:*, react-native run-* and flutter run open an emulator or a simulator, so an Expo app with generated native folders builds its bundle with npx expo export --source-maps. A command the shell blocks (make, sh, command -v, a Gradle wrapper outside the root) is skipped and named in the handoff, never wrapped in a new package script. The shell gets a reduced environment, so an Android build there stops at SDK location not found: the task does not retry, and the report asks the user to run that build once themselves rather than set up an SDK. In Go, go vet ./... checks the code without leaving a binary in the project root.
  • report: depends on verify and reports its build and upload. It writes the file once with write; publish_handoff is blocked for it.
  • test-setup: asks first and finishes right away on "no". On "yes" it adds the test affordance and runs the build itself.
  • Workspace packages (install, capture-exceptions, configure, verify): when detect_package_manager finds no lockfile in the app's directory, the task looks above it for the workspace root's lockfile or packageManager field and uses that manager. npm is used only when no parent has either. This rule wins over the install skill's own rule, which looks at the app's directory only. capture-exceptions declares the server library in the manifest of the package that imports it, including a package nested below the app.
  • wire-ci and link-releases: in a workspace package they look for the pipeline and deploy files at the repository root. No step fails on an empty PostHog variable, because the user merges the change before creating the secrets; the handoff names the secrets instead. With a Turborepo cache, the upload credentials go in the task's hashed env, so a build with them never replays an entry made without them, and the git variables go in passThroughEnv. The cache stays on.
  • configure changes only what the upload needs. An existing source-map setting (productionBrowserSourceMaps, Vite's build.sourcemap, webpack's devtool) stays. A dependency is upgraded only when the install or the build fails on it, and an exact pin stays exact. The upload goes into a build the project already has, here or in a package nested below; a project with none gets no new bundler, compiler or script, and the task reports not needed.
  • capture-exceptions covers an Electron main process with the server library. Its token is read the way electron-vite inlines it at build (import.meta.env.MAIN_VITE_*), because a packaged app has no .env.
  • capture-exceptions hooks NestJS through a global exception filter, the app's existing @Catch() filter when it has one. Nest's filters answer request errors before Express error middleware runs.
  • init sets up each server the project builds or deploys. A script the project only runs in development, with nothing but a dev script, gets no client.
  • Seed: server JavaScript that no build compiles or bundles is a readable-stack platform, so it gets no upload tasks and the run asks for no personal API key. A build in a nested package counts.
  • Upload skill: a tip that a build without credentials must pass: gate sourcemaps.enabled on the upload variables, and guard a posthog-cli build step on the key. wizard upload-source-maps reads this skill too.

Without the compile-by-construction reasoning the run is also shorter. On no-posthog-next, averaged over two runs on each side, the run went from 346 s to 298 s and configure from 102 s to 72 s (22 → 11.5 turns).

Test plan

  • npm test (219 passed) and npm run build (emits agents-error-tracking-verify.md).
  • Headless wizard error-tracking runs on Pi with --local-context-mill against wizard-workbench fixtures in project 89529. After each JS run, a clean npm ci and a production build, once without the run's .env and once with it:
Fixture Run Build without creds Build with creds
no-posthog-next pass; verify reused configure's build pass pass, uploader ran
no-posthog-next + a throwing API route pass; server capture through posthog-node in onRequestError pass pass, uploader ran
react-vite pass, 315 s pass pass, uploader ran
no-posthog-express pass, 323 s pass, upload skipped pass, uploader ran
no-posthog-sveltekit pass, 285 s; client and server hooks fails, see note pass, uploader ran
cicd-github-actions-node-raw pass, 288 s; deploy.yml wired, start keeps --env-file=.env pass, upload skipped pass, uploader ran
cicd-github-actions-docker-python-flask pass, 233 s; no verify — —
cicd-gitlab-ruby-sinatra pass, 208 s; no verify — —
cicd-github-actions-docker-php-laravel pass, 246 s; no verify — —
nuxt-4-3 pass, 443 s pass pass, uploader ran
no-posthog-angular pass, 321 s pass, upload skipped pass, uploader ran
no-posthog-vue pass, 258 s pass pass, uploader ran
node-webpack pass, 300 s pass pass, uploader ran
node-rollup pass, 329 s pass pass, uploader ran
no-posthog-react-router pass, 516 s, including one 134 s model turn pass pass, uploader ran
no-posthog-hono pass, 326 s pass, upload skipped pass, uploader ran
go pass, 284 s; go vet and go build pass, no blocked commands — —
rust pass, 312 s; cargo build --release passes — —
ios-spm pass, 309 s; Release xcodebuild succeeds, verify reused it — —
android pass, 260 s; Gradle stops at SDK location not found in the agent's shell, tried once — —
react-native-expo pass, 757 s, including one 412 s model turn; npx expo export passes, no emulator — —
react-native pass, 385 s; Gradle wrapper under android/ blocked, skipped — —
no-posthog-django pass, 171 s; posthog>=7.59.0 in requirements.txt, no virtualenv — —

Stack-specific and real-world apps, on the same setup: the new apps in PostHog/wizard-workbench#4482, and apps from other workbench programs.

App Run After the run
no-posthog-nestjs, no-posthog-express-tsc, no-posthog-cloudflare-worker, no-posthog-electron, create-react-app pass build passes without and with the upload credentials; CRA also with CI=true and environment variables only
next-sentry pass; Sentry keeps its own setup build passes without and with the credentials; productionBrowserSourceMaps and the exact posthog-js pin kept
no-posthog-fastapi-uv pass; release linking in deploy.yml uv sync --frozen, import without .env, and tests pass
no-posthog-spring-boot pass; capture in the @RestControllerAdvice ./gradlew build passes
vite-yarn-pnp pass; upload skipped, because the machine's yarn is Yarn 1 and the agent's shell does not allow corepack —
audit/cal-diy, apps/api (Yarn 4 workspace) pass; yarn add from the app directory, the SDK declared in the nested v2 package, the root workflow, turbo.json and docker-compose.yml wired —
audit/cal-diy, apps/web pass; verify reports the app's own NEXTAUTH_SECRET build requirement as pre-existing —
cicd-monorepo-pnpm-node-react, backend pass; pnpm, and the root deploy-backend.yml passes the build args and the key as a build secret —
tanstack-start-saas pass build passes without and with the credentials
astro-ssr-docs pass; browser and server capture, upload skipped —
flutter pass; the Android and web builds pass and the Android mapping uploaded —
ios-pod pass; the Release build fails on the app's existing iOS 13 deployment target, reported as pre-existing —
fizzy (Rails) pass; the machine lacks Ruby 3.4.7, and the report says so —

Before the workspace and configure rules, cal-diy apps/api stopped at install with EUNSUPPORTEDPROTOCOL (npm on workspace:*) and wrote no report, the pnpm backend left a package-lock.json and an unwired root workflow, and apps/web lost productionBrowserSourceMaps and its exact posthog-js pin.

A regression pass on the final prompts:

App Run After the run
no-posthog-next pass, 323 s build passes without and with the credentials; maps deleted after upload
react-vite pass, 330 s build passes without and with the credentials
no-posthog-express pass, 376 s and 312 s build passes without and with the credentials; the built server starts
cicd-github-actions-node-raw pass, 316 s; deploy.yml passes the variables with no failure check build passes without credentials, with .env, and with environment variables only
cicd-github-actions-docker-python-flask pass, 277 s; meets the workbench README expectations imports and serves under Python 3.12
no-posthog-nestjs pass, 357 s; capture in AllExceptionsFilter for 5xx, upload in the Docker build before the prune with the key as a build secret build passes without and with the credentials; tests pass
no-posthog-express-no-build pass, 133 s; install, init, capture and report only, no API key asked —
audit/cal-diy, apps/api pass, two runs; v2 set up with a global Nest filter, Yarn from the app directory, Turborepo env and passThroughEnv with the cache on verify builds @calcom/api-v2

Earlier cal.com runs in this pass shaped those rules: one used npm and stopped at install, two set up the dev-only proxy beside v2 (one of them added an esbuild build to it), one turned Turborepo's cache off, and one wired capture through setupExpressErrorHandler, which Nest's filters bypass.

The Python, Ruby and PHP runs meet the expectations in the workbench's apps/error-tracking/README.md. Every completed run wrote the report file once, and no task called publish_handoff.

Before the shell rules above, the same fixtures ran into them: android took 604 s (Gradle retried for about 6 minutes), react-native-expo took 696 s (expo run:android opened the emulator twice), go and rust tried make, sh and command -v, go left its binary in the project root, and no-posthog-django left a .venv in the project. One more react-native run on the final prompts stopped when a model call hung for 2 hours and npm install timed out; its configure skipped the blocked Gradle wrapper without adding a script.

Note

Outside this change:

  • The wizard's agent shell passes no ANDROID_HOME, so no Android build can run in it, and its fence allows any npx expo subcommand, including expo run:*. Both live in the wizard's shared agent code.
  • The SvelteKit reference example reads the token from $env/static/public, so a SvelteKit build without .env fails with "PUBLIC_POSTHOG_PROJECT_TOKEN" is not exported by "virtual:env/static/public". Switching example-apps/sveltekit and the SvelteKit init guidance to $env/dynamic/public would fix it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ShmV3MZAFkwMroJi6AiBmu

Tasks run the project's build after their edits instead of writing code
that compiles by construction. A new verify task builds the finished setup
before the report, and builds without upload credentials still pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ShmV3MZAFkwMroJi6AiBmu
@github-actions

Copy link
Copy Markdown

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci ai-observability
  • /wizard-ci basic-integration
  • /wizard-ci feature-flags
  • /wizard-ci mcp-analytics
  • /wizard-ci replay-vision
  • /wizard-ci revenue
  • /wizard-ci self-driving
  • /wizard-ci warehouse
  • /wizard-ci warehouse-seeded

Test an individual app:

  • /wizard-ci ai-observability/anthropic
  • /wizard-ci ai-observability/google-adk
  • /wizard-ci ai-observability/groq
Show more apps
  • /wizard-ci ai-observability/manual-capture
  • /wizard-ci ai-observability/openai
  • /wizard-ci ai-observability/openai-agents
  • /wizard-ci ai-observability/opentelemetry
  • /wizard-ci ai-observability/vercel-ai
  • /wizard-ci basic-integration/android
  • /wizard-ci basic-integration/angular
  • /wizard-ci basic-integration/astro
  • /wizard-ci basic-integration/django
  • /wizard-ci basic-integration/fastapi
  • /wizard-ci basic-integration/flask
  • /wizard-ci basic-integration/flutter
  • /wizard-ci basic-integration/javascript-node
  • /wizard-ci basic-integration/javascript-web
  • /wizard-ci basic-integration/laravel
  • /wizard-ci basic-integration/next-js
  • /wizard-ci basic-integration/nuxt
  • /wizard-ci basic-integration/python
  • /wizard-ci basic-integration/rails
  • /wizard-ci basic-integration/react-native
  • /wizard-ci basic-integration/react-router
  • /wizard-ci basic-integration/sveltekit
  • /wizard-ci basic-integration/swift
  • /wizard-ci basic-integration/tanstack-router
  • /wizard-ci basic-integration/tanstack-start
  • /wizard-ci basic-integration/vue
  • /wizard-ci feature-flags/django
  • /wizard-ci feature-flags/next-js
  • /wizard-ci mcp-analytics/custom-dispatcher
  • /wizard-ci mcp-analytics/typescript-sdk
  • /wizard-ci replay-vision/javascript-node
  • /wizard-ci replay-vision/next-js
  • /wizard-ci replay-vision/react-vite
  • /wizard-ci revenue/stripe
  • /wizard-ci self-driving/astro
  • /wizard-ci self-driving/fastapi
  • /wizard-ci self-driving/nuxt
  • /wizard-ci self-driving/react-router
  • /wizard-ci self-driving/sveltekit
  • /wizard-ci warehouse/monorepo-env
  • /wizard-ci warehouse/multi-source-next
  • /wizard-ci warehouse/stripe-node
  • /wizard-ci warehouse/zero-source
  • /wizard-ci warehouse-seeded/next-stripe
  • /wizard-ci warehouse-seeded/next-stripe-declined

Test against a wizard branch:

  • /wizard-ci all wizard:my-branch

Add wizard:<branch> to any command above to pin the wizard branch. It defaults to main.

Results will be posted here when complete.

ablaszkiewicz and others added 2 commits October 12, 2026 22:50
…t shell's limits

Tasks build but never run the app (no emulator or simulator), skip commands
the shell blocks instead of wrapping them, and treat a missing SDK in the
reduced shell as the shell's limit. Python installs no new virtualenv, and
init and credentials merge into .env.example instead of overwriting it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ShmV3MZAFkwMroJi6AiBmu
… settings

A package inside a workspace installs with the manager whose lockfile sits at
the workspace root, declares the SDK in the manifest that imports it, and gets
the CI and deploy files at the repository root wired. CI steps never fail on a
missing PostHog secret, configure keeps existing source-map settings and pins,
and an Electron main process gets its own capture with a build-time token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ShmV3MZAFkwMroJi6AiBmu
ablaszkiewicz and others added 2 commits October 14, 2026 16:04
…steps on the key

configure may upgrade a dependency when the install fails on it, not only the
build. wire-ci names the condition a posthog-cli pipeline step needs to skip
itself when the key is empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ShmV3MZAFkwMroJi6AiBmu
…roject has them

init sets up the server the project builds or deploys, not a dev-only script
beside it, and capture hooks NestJS through a global exception filter. Server
JavaScript that no build compiles gets no upload tasks, and configure never
adds a build to create one. install's workspace package-manager rule wins over
the skill's own rule, and wire-ci hashes the upload credentials in a Turborepo
cache while passing the git variables through.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ShmV3MZAFkwMroJi6AiBmu
@ablaszkiewicz
ablaszkiewicz marked this pull request as ready for review October 14, 2026 20:56
@ablaszkiewicz
ablaszkiewicz requested review from a team as code owners October 14, 2026 20:56
@ablaszkiewicz
ablaszkiewicz merged commit 480834b into main Oct 19, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants