Skip to content

Instantly share code, notes, and snippets.

@toriningen
Last active June 9, 2025 03:39
Show Gist options
  • Save toriningen/9f7b4d663902ae62654613dc65d51028 to your computer and use it in GitHub Desktop.
Save toriningen/9f7b4d663902ae62654613dc65d51028 to your computer and use it in GitHub Desktop.
Notify when a Codex task completes or fails
// ==UserScript==
// @name Codex Task Notifier
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Notify when a Codex task completes or fails
// @match https://chatgpt.com/codex/tasks/*
// @grant GM_notification
// @grant window.focus
// @run-at document-end
// @updateURL https://gist.githubusercontent.com/toriningen/9f7b4d663902ae62654613dc65d51028/raw/codex-notifier.user.js
// @downloadURL https://gist.githubusercontent.com/toriningen/9f7b4d663902ae62654613dc65d51028/raw/codex-notifier.user.js
// @supportURL https://gist.github.com/toriningen/9f7b4d663902ae62654613dc65d51028
// ==/UserScript==
(async function() {
'use strict';
const ICON_SUCCESS = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAMAAABrrFhUAAAAnFBMVEUAAABBrUn///9ArUhBrEhArEmp2qvS69NRtFfa79tLslKq2qzY7tlOs1RBq0nU7NZTtVpStVnT7NRPs1ZCrErW7dhDqUs+rEc/q0c/rkrv+PBIo1E/rEq74b5Fpk8+r0e948C54rq14LdDr0tBrkc5s0L1+/Vpv288sURvwnVUtVm24Ljc8d5Eq0xqwHExwDeg1qNcuWJ9x4NQolWrzcLbAAAAAXRSTlMAQObYZgAACRpJREFUeNrs3el20zAQBeC5kQ1uSNK0SbPQkABNoezb+78biaiDi2NrGS8jm+8ncA5HY410KzkN/de0JSJAqRhPxNB//IU6DEdKoUz619QxKtIP2Zb+l1FHqqDiGL6i0KfCaoVUD4uAqsRQawoNFKoT3IqAGgS0N2T7vn8lQL1iYEmCxWhAHJFQaIwigdCsDcmCpslaDxVsdLYECu0Qshas1rDXvRKgbROQg+6N/yCm1qwiyEC2urL45WyoeUsIsgdZ6Fz3Zylq1K8HSDO/p+Y87OYQZ76lMh1d/Z76Qk1YQ64J1S+KIZdSVLeJ5PGf3w360f5/Lak+Atf+M/Z00r/Hr0Wk9Xb8dW0GUn70s0Kp7ob/pitwj7DcUrUWCMz8gap0G84CmJovq5z/wU2Ao/vqnv8ivAmg9W7/z+nj/ld5BVTAE+BA9gsvDVC9boCjBbHcInSLe2LYh3ECUFsTLAIZv6qpCRDIT8Dff6Jct9e/6Nng3XuU63IBDuMfDF5+VSjT5fG/GBy9/IAye3I3QQiOz197916hxKajE+Aw/tTL8grsO5mA9PzXjF0Qk5v7L5BPP/+/3n1FiXX3jkDS8We6ACXmXTsDSef/ky5QKNaxO5Dc89ddULoOdGoH0OPPMWTCLrwDUjp+UybsTgTK9b/dbhh1pQHS8Tt3AdmQ9wqg7fw3Z0LViWvQ/PPP74aMJhAfgUqevzkTxubnv4ds6fj9uiBG6CugYf4bd8N94PcgpvGbM+Em6Algnv/m3bAn4y9eB1Trn36ud/6bMyEVuxP1OZii58/ugkAzUDp+dhfchpmCDfPfIRNuvxWOX/BVYO75+++GahHgHpAbP28lDO4gUI/fzyucQWdtIZXufz8XY5xB53wTexfCeP7XVzgrqA5gjP95gvNCOgvnzP8hCqzD2QIYz/8yQaFgCsCZ/x9RJJwCMOb/zRBlAhm///MfzVAikAJw5v8U5ULYAjjr3wwm8icAL/8ZBFAAXv4zk/5OKKf/r2BhIjsGc/Of2UT0D4L8/Gcm+aU4Xv6ztJH7udDoGT//mSmhvxVK9z8//5ltpa6BvPxn71ZoCuDs/zO4EDp+Vv5zI7EDOM8/gSOBM4CX/9xILABn/R/CkcACcPb/GdzFpO2k/CTE2/88TGRNAE7+HyP8AnD6fww/kgrAO//wIqoAvPsvb2I+HsA7//AV3/E+HhCDocLzDwbWBBj/TMDHP//g4LwbqF4P3sZwIiP/ZTHWwLtXh///jWP/iMh/Wf4/C969Hhy9ieFCRP7LiD3fjtTzX3PrAhn5L4sOdnCnDvOfXwH++QfX2msN0PNfc+wCKfkvY+5XgNeDrE+2FRCT/zJ8CpD2v0cXiMh/WZH7JqD3vyyH3VBK/ntSALjS4/eqgJj895ciYsx/Rhew33+qiFK0Zj9/7dMEBvW8/8QvABzo/S/LYTcUlP8y1JLgIh0/qwv47z9ViRRs6fzHrICI/JcRxwQz8/xPu4Axfkb+4xVgDSPD+ueUCfn3X1UXIIJZdv9jdEH75x+MFtD5z8CUiPjnHwkqR7BzGj9vHRCz/6XWdmtAOv+5XcCa/5dDVE4pYjx/50zIvf+qA8Ek2/+8dUDU+v/I4lQ8l/98d0Pu+y91MB+IZPMfbx2QcP7hU4B0/nO7QMT5R05sLkBm/JyVUMb5R87c9KJw2v/cLpCV/06Wxlflvw80bhdw77/qoozX4z9GAyNzJhSX/1IWl6Ozi4HG6QLu/VdtrC5Hp5cDA1MeEHT+kWPxkUGVPOd1Qfv3X8WU1Rsiw8+cOSDh/qvQ3O5To8mIsQ6IzH+Pll/oCCbq6jljDnyXl/9SCnQEs6H/HPj8Tl7+OyENFhLv3VDA/Re3ANr0euBFwv2XqQCbCGZq5lUBmfnvhOyngF8mlHL/VWDjVABMbwaOpOa/FLkUwCMTSs1/XgXQhk5dIO38s7gACnbcMqHY/HeiKAVbamrdBXLz3wmd7GBtbLkSCjz/yyFy74GzmTC0/Jfy/AUK+UwYWv5Lef4KDZU8rUB4+e+R8imANv48qMf1DA2ijB2cXGVWwvDy3yNFGesI9gyZUNz9Z4EVZcFRmglDzH+PiFOA4kwo8P6rAOtXyhZmQon3XwWIOQXU+CbU/U8jbgHOZUKh919nEbsC+Vszae8/lVH8AujdMKjzj6yKfrF0NhOKvf86J6K8DTwko3DOP7IWlAd3+tYsmPOPrAp/vf5wFMr5R1aVX7CQjELKf1pc7VdsTJ8HlP+0DZ0HP2p8GUz+06J11V+zM7sIJf9pUfVftDS9EX/+kVX1V23pTBhE/jOMnzZ7+Bp+DiD/aepLPV86nozk5z9NUQn40plQfP77g8ps4G88kp7/jvZUCjH8JRcC778cC0BLMEyv5d1//SMmg9u5gjc1u5ab/7S7FZk8LMAwuxDy/lOBOzLbguPqRmz+O1I1F0BnQqH5TyMbEViGF4Luv55ak5UNeJKRsPOPlJqTnT0Yym7NbhK0aUm2wDS+Ebf/HammClCQCS+HaBfZA9f0UsL91xMxOVBg0buhqPX/YEIuInCNP+fef2lVRG7AdnUj4vwjRa7Ao7tAxPnHHxNytQFTJhNef0TbyN0ebMmFgPx3tCIf4NOZcNT6/FfkB1z61uxyitaRnwn4frz9gbatyNcCfO1/j5cif7s5gndHriR/F2czDSD7+2gdReRD7LdxuiM3oXwtvyW1JL4Y4VJ00Oc5QNTvClBV7hEgdUtccr+a2sIcVKWH4CLhPeX0KxLSST9XQqJeV0Dn3/5WIFpSPTYIw4oe9bMCO1CNAtgNt1Su4z8e76hukeQjkrmis3qzGeypETsI9UAN2S4k9oGi5nzbijsnUiCDjq8E1LQVBImX1AIBt15/qJhsdbMNtuSie7mQ2hT9Lq/ecRCGgSAM+9d421QIGSlKGgoa7n89BFJSIAiPPLx2vhusd8ab+wkuCpkdWjLqgwMNuWTf/oAsYnBEbC44w6Tqx59OwS7GvzslVues+5sXwe/2RwmxDidn/zNhAHsd/8FYWPQf/WcRGpbQQAqF6pnvXFLyX2gRfzIr4M//jhm/FEKApWJz/04v0LETE2IEcbVQsU4a1jySgIhqSXxJbooGMXEA5B3UAAAAAElFTkSuQmCC";
const ICON_FAILURE = "data:image/png;base64,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";
const CHECK_INTERVAL = 5000;
const STATUS_RUNNING = "running";
const STATUS_SUCCESS = "success";
const STATUS_FAILURE = "failure";
function delay(timeout) {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
}
function getTaskName() {
const el = document.querySelector('div.min-w-0:nth-child(3) > div:nth-child(1)');
if (el) {
return el.textContent.trim();
}
return "(unknown task)";
}
function getStatus() {
const footer = document.querySelector('#wham-message-modal-footer');
if (!footer) {
return STATUS_RUNNING;
}
if (footer.querySelector('#prompt-textarea')) {
return STATUS_SUCCESS;
} else {
return STATUS_FAILURE;
}
}
async function waitUntilComplete() {
console.debug(`codex-notifier: wait until complete`);
while (true) {
const status = getStatus();
if (status != STATUS_RUNNING) {
return status == STATUS_SUCCESS;
}
await delay(CHECK_INTERVAL);
}
}
async function waitUntilRunning() {
console.debug(`codex-notifier: wait until running`);
while (true) {
const status = getStatus();
if (status == STATUS_RUNNING) {
return;
}
await delay(CHECK_INTERVAL);
}
}
while (true) {
await waitUntilRunning();
const success = await waitUntilComplete();
const title = `Codex task ${success ? "completed" : "failed"}`;
const text = getTaskName();
const image = success ? ICON_SUCCESS : ICON_FAILURE;
console.debug(`codex-notifier: showing notification`);
GM_notification({
title,
text,
image,
timeout: 0,
onclick(event) {
console.debug(`codex-notifier: notification clicked`);
window.focus();
}
});
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment