> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cekura.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Schedule Metric Optimiser Runs

> Schedule the Metric Lab Auto-Improve optimiser to run on a recurring cron — directly from Cekura, no Claude Code required.

export const CopyPageButton = () => {
  if (typeof window !== 'undefined') {
    setTimeout(function () {
      if (document.getElementById('ck-tools')) return;
      var anchor = document.getElementById('content-area') || document.querySelector('.mdx-content');
      if (!anchor) return;
      if (!document.getElementById('ck-style')) {
        var s = document.createElement('style');
        s.id = 'ck-style';
        s.textContent = '#ck-tools{position:absolute;top:6px;right:0;z-index:100;font-family:inherit;}' + '.ck-row{display:inline-flex;align-items:stretch;border:1px solid rgba(0,0,0,0.15);border-radius:8px;overflow:hidden;background:#fff;}' + ':root.dark .ck-row{background:rgba(255,255,255,0.06);border-color:rgba(255,255,255,0.12);}' + '.ck-btn{padding:5px 12px;border:none;background:none;cursor:pointer;font-size:13px;font-weight:500;font-family:inherit;color:#374151;}' + ':root.dark .ck-btn{color:#d1d5db;}' + '.ck-btn:hover{background:rgba(0,0,0,0.04);}' + ':root.dark .ck-btn:hover{background:rgba(255,255,255,0.06);}' + '.ck-chevron{padding:5px 8px;border:none;background:none;cursor:pointer;font-size:14px;font-family:inherit;color:#374151;}' + ':root.dark .ck-chevron{color:#d1d5db;}' + '.ck-chevron:hover{background:rgba(0,0,0,0.04);}' + ':root.dark .ck-chevron:hover{background:rgba(255,255,255,0.06);}' + '.ck-divider{width:1px;background:rgba(0,0,0,0.12);flex-shrink:0;}' + ':root.dark .ck-divider{background:rgba(255,255,255,0.12);}' + '.ck-dd{position:absolute;top:calc(100% + 4px);right:0;min-width:180px;background:#fff;border:1px solid rgba(0,0,0,0.12);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.1);padding:4px;display:none;z-index:200;}' + ':root.dark .ck-dd{background:#1f2937;border-color:rgba(255,255,255,0.1);box-shadow:0 4px 16px rgba(0,0,0,0.35);}' + '.ck-item{display:block;width:100%;padding:7px 12px;border:none;background:none;border-radius:6px;cursor:pointer;font-size:13px;font-family:inherit;text-align:left;color:#374151;}' + ':root.dark .ck-item{color:#d1d5db;}' + '.ck-item:hover{background:rgba(0,0,0,0.05);}' + ':root.dark .ck-item:hover{background:rgba(255,255,255,0.07);}';
        document.head.appendChild(s);
      }
      var wrap = document.createElement('div');
      wrap.id = 'ck-tools';
      var row = document.createElement('div');
      row.className = 'ck-row';
      var mainBtn = document.createElement('button');
      mainBtn.className = 'ck-btn';
      mainBtn.textContent = 'Copy page';
      var divider = document.createElement('span');
      divider.className = 'ck-divider';
      var chevron = document.createElement('button');
      chevron.className = 'ck-chevron';
      chevron.textContent = '▾';
      var dd = document.createElement('div');
      dd.className = 'ck-dd';
      function closeDD() {
        dd.style.display = 'none';
      }
      function openDD() {
        dd.style.display = 'block';
      }
      chevron.onclick = function (e) {
        e.stopPropagation();
        if (dd.style.display === 'block') {
          closeDD();
        } else {
          openDD();
        }
      };
      document.addEventListener('click', function (e) {
        if (!e.target.closest('#ck-tools')) {
          closeDD();
        }
      });
      document.addEventListener('keydown', function (e) {
        if (e.key === 'Escape') {
          closeDD();
        }
      });
      function makeItem(label, fn) {
        var b = document.createElement('button');
        b.className = 'ck-item';
        b.textContent = label;
        b.onclick = function () {
          fn();
          closeDD();
        };
        return b;
      }
      function getMarkdown() {
        var walk = function (node) {
          if (!node) return '';
          if (node.nodeType === 3) return node.textContent || '';
          if (node.nodeType !== 1) return '';
          var tag = node.tagName.toLowerCase();
          var skip = ['script', 'style', 'svg', 'noscript', 'button', 'iframe'];
          if (skip.indexOf(tag) !== -1) return '';
          if (node.id === 'ck-tools') return '';
          var ch = Array.from(node.childNodes).map(walk).join('');
          if (tag === 'h1') return '\n# ' + ch.trim() + '\n\n';
          if (tag === 'h2') return '\n## ' + ch.trim() + '\n\n';
          if (tag === 'h3') return '\n### ' + ch.trim() + '\n\n';
          if (tag === 'p') return '\n' + ch.trim() + '\n\n';
          if (tag === 'pre') return '\n```\n' + node.textContent.trim() + '\n```\n\n';
          if (tag === 'li') return '- ' + ch.trim() + '\n';
          if (tag === 'code') return '`' + ch.trim() + '`';
          return ch;
        };
        var content = document.querySelector('.mdx-content') || document.getElementById('content-area') || document.body;
        return walk(content).replace(/\n\n\n+/g, '\n\n').trim();
      }
      function copyMd() {
        var md = getMarkdown();
        navigator.clipboard.writeText(md).then(function () {
          mainBtn.textContent = 'Copied!';
          setTimeout(function () {
            mainBtn.textContent = 'Copy page';
          }, 2000);
        });
      }
      function viewMd() {
        var md = getMarkdown();
        var safe = md.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;');
        var html = '<!DOCTYPE html><html><head><meta charset="utf-8"><style>body{font-family:monospace;max-width:860px;margin:40px auto;padding:0 24px;line-height:1.7;white-space:pre-wrap;word-wrap:break-word}</style></head><body>' + safe + '</body></html>';
        window.open(URL.createObjectURL(new Blob([html], {
          type: 'text/html'
        })), '_blank');
      }
      function openClaude() {
        var prompt = 'Can you read this Cekura docs page ' + window.location.href + ' so I can ask you questions?';
        window.open('https://claude.ai/new?q=' + encodeURIComponent(prompt), '_blank');
      }
      mainBtn.onclick = copyMd;
      dd.appendChild(makeItem('Copy page', copyMd));
      dd.appendChild(makeItem('View as Markdown', viewMd));
      dd.appendChild(makeItem('Open in Claude', openClaude));
      row.appendChild(mainBtn);
      row.appendChild(divider);
      row.appendChild(chevron);
      wrap.appendChild(row);
      wrap.appendChild(dd);
      anchor.style.position = 'relative';
      anchor.insertBefore(wrap, anchor.firstChild);
    }, 50);
  }
  return null;
};

<CopyPageButton />

The [Metric Lab](/documentation/guides/metric-lab) **Auto Improve** button rewrites a metric's prompt based on the feedback annotations on its test sets. This page covers running that optimiser on a recurring schedule **from within Cekura** — no external tooling needed.

<Note>
  There are two ways to schedule the optimiser. Pick one:

  * **In-product cron** (this page): you select metrics + cron + auto-apply in the dashboard. Cekura's scheduler fires the optimiser and emails a summary.
  * **[Claude Code routine](/mcp/auto-optimize-metrics)**: a routine prompt that calls the same MCP endpoints on a `/schedule`-managed cron. Use this if you live in Claude Code and want the diffs in your inbox.

  The in-product version is the right default for most teams.
</Note>

## When to use this

* You label calls in the [Metric Lab](/documentation/guides/metric-lab) regularly and want those annotations to feed back into the metric prompt without manual clicks.
* You want the optimiser to run on a fixed cadence (weekly is a sensible default).
* You want a non-developer team member to manage the schedule from the dashboard.

If feedback annotations on a metric haven't changed since the last run, the optimiser is deterministic and the schedule will report "no changes proposed."

## Create a scheduled optimiser

<Steps>
  <Step title="Open Project > General settings">
    Go to **Settings → General** for the project containing the metrics you want to optimise.
  </Step>

  <Step title="Add a metric-optimiser schedule">
    Under **Auto-optimise metrics**, click **Add schedule**. Pick:

    * **Metrics** — one or more LLM-judge metrics in this project. The optimiser will use every test set already in each metric's Lab.
    * **Cron expression** — standard 5-field cron (`minute hour day-of-month month day-of-week`).
    * **Timezone** — IANA name (e.g. `America/Los_Angeles`).
    * **Auto-apply** — see below.
    * **Notify on** — success, failure, or both. Project members with email notifications enabled will receive the summary.
  </Step>

  <Step title="Choose read-only vs auto-apply">
    * **Read-only** (default): the optimiser runs, the proposed prompt and score are emailed to project members, the live metric is **not** modified. Use this for the first few runs while you build confidence.
    * **Auto-apply**: the optimiser overwrites the live metric prompt automatically when the optimised score is at least as good as the baseline on the labelled set. If the optimiser would regress the metric, the save is skipped and the run is reported in the summary email as "regressed — not applied."
  </Step>

  <Step title="Save">
    The schedule begins firing at the next matching cron tick.
  </Step>
</Steps>

## What each run does

For every metric on the schedule:

1. Collects every test set in the metric's Lab (every `MetricReview` row).
2. Runs the same optimiser the **Auto Improve** button uses.
3. Computes a baseline score (current prompt vs. labelled answers) and an optimised score (proposed prompt vs. labelled answers).
4. If `auto_apply` is on **and** the optimised score is not lower than the baseline, saves the optimised `description`, `evaluation_trigger`, `type`, and `custom_code` back to the metric.
5. Adds a row to the summary email: status, baseline score, optimised score, whether the change was applied.

## Cadence recommendations

* **Weekly** if your team labels reviews regularly. This is the default.
* **Daily** only if you have an active labelling workflow producing dozens of new annotations per day.
* **Monthly** if labelling is bursty (quarterly audits, post-incident reviews).

## Auto-apply safety

The score-regression guard means auto-apply will **never** overwrite your live prompt with one that scores worse on your labelled set. That said:

* Auto-apply is destructive — it overwrites the production prompt your agent evaluates against.
* Run a few weeks in read-only mode first to see the kind of changes the optimiser typically proposes.
* If a metric is critical (you alert on it, it gates deploys), keep it on read-only and apply manually after reviewing the diff.

## Troubleshooting

**The schedule reports "no changes proposed" every run.** No new feedback has been added to the metric's Lab since the last run. The optimiser is deterministic on a fixed annotation set.

**A run reports "regressed — not applied" for a metric.** The optimised prompt scored lower than the current prompt on the labelled set. This is the regression guard working as intended — review the diff in the email and either rewrite the metric prompt by hand or add more annotations to clarify the failing cases.

**I want the diff but not the auto-save.** Set the schedule to `auto_apply=false`. The optimiser still runs and emails the diff; only the save step is skipped.

**I prefer Claude Code.** Use the [Claude Code routine](/mcp/auto-optimize-metrics) instead. Both paths call the same backend optimiser.
