Local-first analysis — no server-side processing
TokenSave for OpenClaw
Find wasted AI jobs and diagnose avoidable spend from OpenClaw exports.
Run this command on the machine where OpenClaw is running:
openclaw export
This generates a diagnostic archive. Upload it below.
Upload an OpenClaw diagnostic export to identify wasted jobs, avoidable spend, and high-cost execution patterns — entirely on your device.
Highest Avoidable Spend Jobs
Ranked by absolute wasted tokens — highest first
Tap a column header to sort
|
|
|
|
|
Failure Loops Detected
Consecutive same-error failures indicate a broken job loop
Recommended Fixes
Prioritized by the waste patterns found in this export
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 += '
' + 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 = '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);
});
}