Local-first analysis — no server-side processing

TokenSave for OpenClaw

Find wasted AI jobs and diagnose avoidable spend from OpenClaw exports.

STEP 1
Export Data
Run this command on the machine where OpenClaw is running:
openclaw export
This generates a diagnostic archive. Upload it below.
Files never leave this device.
Parsing files...
Upload an OpenClaw diagnostic export to identify wasted jobs, avoidable spend, and high-cost execution patterns — entirely on your device.

Pre-flight Check

Paste a job draft or upload a job JSON to check if it will likely waste tokens before it goes live.

Job Draft

Context Export (optional)

// ── Mode switching ─────────────────────────────────────────────────────── (function() { var tabD = document.getElementById('tabDiagnose'); var tabP = document.getElementById('tabPreflight'); var diag = document.getElementById('diagnoseMode'); var pre = document.getElementById('preflightMode'); if (!tabD || !tabP || !diag || !pre) return; function switchMode(mode) { if (mode === 'preflight') { diag.style.display = 'none'; pre.style.display = 'block'; tabD.classList.remove('active'); tabP.classList.add('active'); } else { diag.style.display = 'block'; pre.style.display = 'none'; tabP.classList.remove('active'); tabD.classList.add('active'); } } tabD.addEventListener('click', function() { switchMode('diagnose'); }); tabP.addEventListener('click', function() { switchMode('preflight'); }); })(); // ── Fixtures ─────────────────────────────────────────────────────────── var FIXTURES = { block: { name: 'health-check-cron', schedule: '*/5 * * * *', model: 'claude-sonnet-4', agentTurn: true, task: 'run service health check' }, warn1: { name: 'data-sync', schedule: '*/45 * * * *', model: 'minimax', agentTurn: true, task: 'sync customer records' }, warn2: { name: 'simple-ping', schedule: '0 */6 * * *', model: 'claude-opus-4', agentTurn: false, task: 'check if endpoint is alive' }, pass: { name: 'daily-report', schedule: '0 9 * * *', model: 'minimax', agentTurn: false, task: 'generate daily summary' }, // v0.3.1 credibility fixtures: // W4: unknown model must trigger W4 (no silent fallback) unknownModel: { name: 'log-reader', schedule: '0 */2 * * *', model: 'unknown-model-xyz', agentTurn: false, task: 'process logs nightly' }, // B3 non-match: same name/schedule/agentTurn/task but different model → NOT a duplicate b3DifferentModel: { name: 'health-check', schedule: '*/10 * * * *', model: 'gpt-4o', agentTurn: true, task: 'run health check' }, // B2: unparseable schedule must trigger B2 b2Unparseable: { name: 'nightly-job', schedule: 'at midnight', model: 'minimax', agentTurn: false, task: 'run nightly report' }, // Parseable cron must NOT trigger B2 parseableCron: { name: 'six-hourly-sync', schedule: '0 */6 * * *', model: 'minimax', agentTurn: false, task: 'sync data every six hours' } }; document.getElementById('fixBlock').addEventListener('click', function() { document.getElementById('preflightDraft').value = JSON.stringify(FIXTURES.block, null, 2); }); document.getElementById('fixWarn1').addEventListener('click', function() { document.getElementById('preflightDraft').value = JSON.stringify(FIXTURES.warn1, null, 2); }); document.getElementById('fixWarn2').addEventListener('click', function() { document.getElementById('preflightDraft').value = JSON.stringify(FIXTURES.warn2, null, 2); }); document.getElementById('fixPass').addEventListener('click', function() { document.getElementById('preflightDraft').value = JSON.stringify(FIXTURES.pass, null, 2); }); document.getElementById('fixUnknownModel').addEventListener('click', function() { document.getElementById('preflightDraft').value = JSON.stringify(FIXTURES.unknownModel, null, 2); }); document.getElementById('fixB3DiffModel').addEventListener('click', function() { document.getElementById('preflightDraft').value = JSON.stringify(FIXTURES.b3DifferentModel, null, 2); }); document.getElementById('fixB2Unparseable').addEventListener('click', function() { document.getElementById('preflightDraft').value = JSON.stringify(FIXTURES.b2Unparseable, null, 2); }); document.getElementById('fixParseableCron').addEventListener('click', function() { document.getElementById('preflightDraft').value = JSON.stringify(FIXTURES.parseableCron, null, 2); }); // ── Context export parser ────────────────────────────────────────────── function parseContextExport(file) { return new Promise(function(resolve) { var reader = new FileReader(); reader.onload = function(e) { try { var data = JSON.parse(e.target.result); var jobs = []; if (Array.isArray(data)) jobs = data; else if (data.jobs) jobs = data.jobs; else if (data.results) jobs = data.results; else if (data.data) jobs = data.data; else if (typeof data === 'object') jobs = [data]; resolve(jobs); } catch(err) { resolve([]); } }; reader.readAsText(file); }); } // ── Preflight rule engine ─────────────────────────────────────────────── function preflightCheck(jobDraft, contextJobs) { var SCHEDULE_BLOCK = 30; var SCHEDULE_WARN = 60; var PREMIUM_RE = /opus|sonnet|haiku|gpt-4|gpt-5/i; var SIMPLE_RE = /check|monitor|heartbeat|ping|status|lint|health|watchdog|keep.?alive/i; var name = ((jobDraft.name||'').trim()); var schedule = ((jobDraft.schedule||'').trim()); var model = ((jobDraft.model||'').trim()); var agentTurn = !!(jobDraft.agentTurn); var task = ((jobDraft.task||jobDraft.promptText||jobDraft.description||jobDraft.prompt||'').trim()); var taskLC = task.toLowerCase(); var schedMin = parseScheduleMinutes(schedule); var isPremium = PREMIUM_RE.test(model); var isSimple = SIMPLE_RE.test(taskLC); var isRecurring = schedule && !/once|one.?time|manual/i.test(schedule); var blocked = [], warned = []; var evidence = {}; var suggestedFix = '', suggestedCmd = ''; // B1: agent-turn + short schedule if (agentTurn && schedMin != null && schedMin < SCHEDULE_BLOCK) { blocked.push('B1'); evidence['agentTurn'] = 'true'; evidence['schedule'] = schedMin + ' min'; evidence['threshold'] = '<' + SCHEDULE_BLOCK + ' min'; suggestedFix = 'Reduce frequency to >= ' + SCHEDULE_BLOCK + ' min, or disable agent-turn.'; suggestedCmd = '# Reduce frequency:\nopenclaw job edit ' + name + ' --schedule "*/30 * * * *"' + (agentTurn ? '\n# Or disable agent-turn:\nopenclaw job edit ' + name + ' --no-agent-turn' : ''); } // B2: recurring with unparseable schedule if (isRecurring && schedMin == null && schedule) { blocked.push('B2'); evidence['schedule'] = schedule; evidence['parseable'] = 'false'; suggestedFix = 'Set a parseable cron schedule so TokenSave can assess risk.'; suggestedCmd = '# Use a standard cron expression:\nopenclaw job edit ' + name + ' --schedule "0 */6 * * *"'; } // B3: exact duplicate in context // Exact = name + schedule + model + agent-turn + task hash (strictest consistent definition) if (contextJobs && contextJobs.length > 0) { var normN = name.toLowerCase().replace(/[\s_-]+/g, '-'); var normS = schedule.toLowerCase().replace(/\s+/g, ''); var normM = model.toLowerCase().replace(/[\s_-]+/g, '-'); var normT = taskLC.replace(/[\s,.?!:;]+/g, '-').substring(0, 40); outer: for (var i = 0; i < contextJobs.length; i++) { var ctx = contextJobs[i]; var ctxN = ((ctx.name||'').toLowerCase().replace(/[\s_-]+/g, '-')); var ctxS = ((ctx.schedule||'').toLowerCase().replace(/\s+/g, '')); var ctxM = ((ctx.model||'').toLowerCase().replace(/[\s_-]+/g, '-')); var ctxA = !!(ctx.raw ? ctx.raw.agentTurn||ctx.raw.agent_turn||ctx.raw.agent_turn_enabled : ctx.agentTurn); var ctxT = ((ctx.task||ctx.promptText||ctx.description||ctx.prompt||'').toLowerCase().replace(/[\s,.?!:;]+/g, '-').substring(0, 40)); if (ctxN === normN && ctxS === normS && ctxM === normM && ctxA === agentTurn && ctxT === normT) { blocked.push('B3'); evidence['duplicateOf'] = ctx.name || ctxN; evidence['matchType'] = 'exact (name + schedule + model + agent-turn + task)'; suggestedFix = 'Duplicate of "' + (ctx.name||ctxN) + '". Consider removing or merging.'; suggestedCmd = '# Remove duplicate:\nopenclaw job delete ' + name; break outer; } } } // W1: premium model on simple recurring if (isPremium && isSimple && isRecurring) { warned.push('W1'); evidence['model'] = model; evidence['taskType'] = 'simple recurring check'; if (!suggestedFix) { suggestedFix = 'Premium model on a simple recurring check. Consider swapping to a lower-cost model (e.g. MiniMax M2.7).'; suggestedCmd = '# Use a cheaper model:\nopenclaw job edit ' + name + ' --model minimax'; } } // W2: agent-turn + medium schedule if (agentTurn && schedMin != null && schedMin >= SCHEDULE_BLOCK && schedMin < SCHEDULE_WARN) { warned.push('W2'); if (!('agentTurn' in evidence)) { evidence['agentTurn'] = 'true'; evidence['schedule'] = schedMin + ' min (' + SCHEDULE_BLOCK + '–' + SCHEDULE_WARN + ' min range)'; } if (!suggestedFix) { suggestedFix = 'Agent-turn on a ' + schedMin + 'min schedule. Confirm this frequency is necessary or reduce further.'; suggestedCmd = '# Reduce frequency or remove agent-turn:\nopenclaw job edit ' + name + ' --schedule "0 */1 * * *"' + (agentTurn ? '\nopenclaw job edit ' + name + ' --no-agent-turn' : ''); } } // W3: simple recurring, short schedule if (isSimple && isRecurring && schedMin != null && schedMin < SCHEDULE_WARN) { warned.push('W3'); if (!('taskType' in evidence)) { evidence['taskType'] = 'simple recurring (' + schedMin + 'min)'; } if (!suggestedFix) { suggestedFix = 'Simple recurring task every ' + schedMin + ' min. Verify this frequency is needed, or scale back to >= ' + SCHEDULE_WARN + ' min.'; suggestedCmd = '# Reduce frequency:\nopenclaw job edit ' + name + ' --schedule "0 */1 * * *"'; } } // W4: unknown model var rate = detectCostRate({ model: model }); if (rate.unknown || !model) { warned.push('W4'); evidence['model'] = model || '(empty)'; evidence['pricingKnown'] = 'false'; if (!suggestedFix) { suggestedFix = 'Model is unknown or pricing cannot be determined. Cost estimates may be inaccurate.'; suggestedCmd = '# Set a known model:\nopenclaw job edit ' + name + ' --model minimax'; } } // W5: similar to historically wasteful patterns if (contextJobs && contextJobs.length > 0 && !blocked.includes('B3')) { for (var j = 0; j < contextJobs.length; j++) { var ctxJ = contextJobs[j]; var ctxIssues = ctxJ.issues || []; var hasWaste = ctxIssues.length > 0 && !ctxIssues.includes('OK'); if (hasWaste) { var ctxSchedMin = parseScheduleMinutes(ctxJ.schedule||''); if (ctxSchedMin !== null && schedMin !== null && Math.abs(ctxSchedMin - schedMin) < 5 && !!(ctxJ.raw ? ctxJ.raw.agentTurn : ctxJ.agentTurn) === agentTurn) { warned.push('W5'); evidence['similarToHistoricalWaste'] = ctxJ.name || ('job at ' + ctxSchedMin + 'min'); evidence['histWasteBadges'] = ctxIssues.join(', '); if (!suggestedFix) { suggestedFix = 'Configuration similar to historically wasteful job "' + (ctxJ.name||'') + '" (' + ctxIssues.join(', ') + '). Review before deploying.'; } break; } } } } var verdict = blocked.length > 0 ? 'BLOCK' : (warned.length > 0 ? 'WARN' : 'PASS'); var risk = blocked.length > 0 ? 'high' : (warned.length > 1 ? 'medium' : 'low'); var whyMatters = verdict === 'BLOCK' ? 'This configuration will likely waste tokens with high confidence. Do not deploy without changes.' : verdict === 'WARN' ? 'This configuration has risk signals. Review the warnings before deploying.' : 'No obvious waste signals detected. This configuration looks reasonable.'; return { verdict: verdict, triggered_rules: blocked.concat(warned), evidence: evidence, estimated_risk: risk, why_this_matters: whyMatters, recommended_change: suggestedFix || 'No changes needed.', suggested_command: suggestedCmd || '' }; } // ── Render preflight verdict ─────────────────────────────────────────── function renderPreflightVerdict(result) { var vClass = result.verdict.toLowerCase(); var ruleColor = { B1:'rule-block', B2:'rule-block', B3:'rule-block', W1:'rule-warn', W2:'rule-warn', W3:'rule-warn', W4:'rule-warn', W5:'rule-warn' }; var html = '
'; html += '
'; html += '' + result.verdict + ''; html += 'Risk: ' + result.estimated_risk + ''; html += '
'; html += '
' + escapeHtml(result.why_this_matters) + '
'; if (result.triggered_rules.length > 0) { html += '
'; html += '
Triggered rules
'; html += '
'; for (var i = 0; i < result.triggered_rules.length; i++) { var r = result.triggered_rules[i]; html += '' + escapeHtml(r) + ''; } html += '
'; } var evKeys = Object.keys(result.evidence); if (evKeys.length > 0) { html += '
'; html += '
Evidence
'; html += '
'; for (var k = 0; k < evKeys.length; k++) { var key = evKeys[k]; html += '
' + escapeHtml(key) + '
' + escapeHtml(String(result.evidence[key])) + '
'; } html += '
'; } html += '
'; html += '
Recommended change
'; html += '
' + escapeHtml(result.recommended_change) + '
'; if (result.suggested_command) { html += '
' + escapeHtml(result.suggested_command) + '
'; } html += '
'; return html; } // ── Run preflight ─────────────────────────────────────────────────────── var contextJobs = []; var contextFile = document.getElementById('preflightContext'); if (contextFile) { contextFile.addEventListener('change', function() { var file = this.files[0]; if (!file) return; parseContextExport(file).then(function(jobs) { contextJobs = jobs; }); }); } var runBtn = document.getElementById('runPreflightBtn'); if (runBtn) { runBtn.addEventListener('click', function() { var draftEl = document.getElementById('preflightDraft'); var resultsEl = document.getElementById('preflightResults'); if (!draftEl || !resultsEl) return; var raw = draftEl.value.trim(); if (!raw) { resultsEl.innerHTML = '
Please paste a job draft JSON first.
'; return; } var jobDraft; try { jobDraft = JSON.parse(raw); } catch(e) { resultsEl.innerHTML = '
Invalid JSON: ' + escapeHtml(e.message) + '
'; return; } var result = preflightCheck(jobDraft, contextJobs); var contextStatus = ''; if (contextFile && contextFile.files && contextFile.files.length > 0) { if (contextJobs.length > 0) { contextStatus = '
Context loaded: ' + contextJobs.length + ' job(s) checked for duplicates.
'; } else { contextStatus = '
Context file loaded but no matching jobs found for B3/W5.
'; } } resultsEl.innerHTML = contextStatus + renderPreflightVerdict(result); }); }