Skip to main content
When background queue processing is enabled, you can create filters that read cached eval scores - no re-running evals needed. Set cachedOnly: true on the view and use ctx.evalResults in filter functions.
my-evals.js
import { createApp } from 'claudeye';

const app = createApp();

// ── Evals that produce scores ────────────────────────────────────
app.eval('quality', ({ entries }) => {
  const assistantMsgs = entries.filter(e => e.type === 'assistant');
  const avgLength = assistantMsgs.reduce((sum, e) => {
    const content = typeof e.message?.content === 'string' ? e.message.content : '';
    return sum + content.length;
  }, 0) / (assistantMsgs.length || 1);
  const score = Math.min(avgLength / 500, 1);
  return { pass: score > 0.5, score };
});

app.eval('efficiency', ({ stats }) => {
  const score = Math.max(0, 1 - stats.turnCount / 100);
  return { pass: score > 0.3, score, message: `${stats.turnCount} turns` };
});

// ── cachedOnly view with per-eval score filters ──────────────────
// Sessions appear here only after the background queue processes them.
app.dashboard.view('eval-results', { cachedOnly: true, label: 'Eval Score Filters' })
  .filter('quality-score',
    (ctx) => ctx.evalResults?.['quality']?.score ?? 0,
    { label: 'Quality Score' }
  )
  .filter('efficiency-score',
    (ctx) => ctx.evalResults?.['efficiency']?.score ?? 0,
    { label: 'Efficiency Score' }
  )
  .filter('all-passing', (ctx) => {
    if (!ctx.evalResults) return false;
    return Object.values(ctx.evalResults).every(r => r.pass);
  }, { label: 'All Evals Passing' });

app.listen();
# Enable background queue so sessions get pre-processed
claudeye --evals ./my-evals.js --queue-interval 60
Sessions appear in the eval-results view as the background queue processes them.