Building self-healing Playwright with JS Proxy
How Autowright detects, diagnoses, and fixes automation failures
Autowright is a self-healing wrapper around Playwright. When a test or a scraper breaks — because a selector changed, a page restructured, or a new captcha appeared — it captures a full forensic bundle, ships it to an AI fixer running on Claude Agent SDK, and the fixer opens a pull request with a proposed fix.
This isn’t magic. It works because of a small architectural decision: wrap every Playwright object in a JS Proxy.
Why Proxy, not patches
The naive approach to adding observability to Playwright is to wrap every
method with a higher-order function. That works, but it’s fragile — you miss
chained calls, you miss this bindings, and every time Playwright adds a new
method you have to remember to wrap it.
A Proxy handler sidesteps all of that. You intercept get, and every
property access flows through your instrumentation automatically.
function wrap<T extends object>(target: T, onError: ErrorHook): T {
return new Proxy(target, {
get(obj, prop, receiver) {
const value = Reflect.get(obj, prop, receiver);
if (typeof value !== 'function') return value;
return async (...args: unknown[]) => {
try {
return await value.apply(obj, args);
} catch (err) {
await onError(err as Error, { prop: String(prop), args });
throw err;
}
};
},
});
}
This gives you a single choke point for capturing DOM snapshots, screenshots, network logs, console output, and the full action trace — the inputs the AI fixer needs to reason about what happened.
Full post coming soon. Future sections: the 12 error categories, the 24 validated recovery scenarios, and how the fixer’s PR hit-rate improved once we started feeding it the last 5 successful runs as context.