Skip to content

Route the cheap work to the cheap model

Here’s the backlog sitting in front of you on stash right now, and it’s deliberately lumpy:

  • Re-extract every URL saved before the readability fix. A few hundred rows: fetch the page, run it through the (now-corrected) extractor, overwrite the stored text. Mechanical. Every row is the same shape of work.
  • Redesign how the extractor handles the sites it still mangles. One judgment call with real branches - which signals to trust when a page has no clean <article> tag, how far to fall back before giving up and storing the raw text. Get it wrong and you’re back here next month with the same bug.

Run both through the same pinned model at the same reasoning depth and you’re either overpaying on the sweep or underthinking the redesign. Pi actually gives you two separate levers to avoid that, and they’re worth naming separately because they compound.

Which model answers - set by defaultModel (and defaultProvider) in settings.json, or picked mid-session:

  • /model opens the full model picker.
  • Ctrl+L opens the same selector as an overlay, without leaving what you’re typing.
  • Ctrl+P cycles through whatever’s in your enabledModels allow-list - the curated shortlist from the last lesson, not every model every provider exposes.

How hard it thinks - Pi calls this the thinking level, and it’s a first-class setting, not a hidden knob: off | minimal | low | medium | high | xhigh | max, set globally via defaultThinkingLevel, cycled mid-session with Shift+Tab, and - if a provider’s defaults don’t fit - retuned per level with thinkingBudgets (a custom token allocation for each rung of the scale).

Neither dial cares what the other is set to. That’s the point: a cheap model at high thinking and a frontier model at off are both real, useful, and completely different tools. The re-extraction sweep wants a cheap model at low or off - there’s nothing to reason about, only rows to process. The extractor redesign wants your strongest model at high - a wrong call here is a rewrite, same as it would be anywhere else in this course.

A lumpy day: four kinds of task, and two dials on each - which model answers, and how much effort it spends thinking. Everything starts where most people leave it: pinned to the expensive corner. Re-dial each task and watch what the day costs.

  • copy tweaksmechanical · five today

    Fix the onboarding typo, reword two error strings, update the footer year - one obvious answer each.

    modeleffort
    top dollar, one answer

    The most expensive corner on the board, spent on work the cheap corner ships identically. This is where a pinned dial leaks.

  • pattern-following endpointsmechanical · three today

    Add list/create endpoints that mirror the handler in the next file over.

    modeleffort
    premium for boilerplate

    Nothing about list/create forks or surprises; the expensive reasoning has nothing to grip. Reserve this corner.

  • the intermittent failurehard · once, thankfully

    A test that fails one run in five, timing-dependent, with the cause three files from the symptom.

    modeleffort
    matched - spend it here

    A genuine reasoning problem: timing-dependent, cause far from symptom, no pattern to copy. This corner exists for exactly this task.

  • the design forkhard · once

    Choose how rule conflicts resolve in the categorisation engine - several defensible designs, one gets built on.

    modeleffort
    matched - the wrong call costs a rewrite

    Several reasonable designs, and whichever wins gets built on. The delta between corners here is noise next to the cost of unpicking a bad choice later.

presets
first runs495 unitsredo tax0 unitsvs the matched day1.9×

Everything ships - no failures, no redo tax - and the day still costs 1.9× what it should. That’s the quiet leak of a pinned dial: the mechanical work bills like hard work, five and three times over. Dial it down to the cheapest corner that ships it; the hard problems keep their budget.

Numbers are illustrative - the ratios are the point (capable ≈ 5× per token, high effort ≈ 3× the tokens). The redo tax counts an underpowered task’s failed attempts plus the escalation you’d run anyway, not the hour lost to confident wrong answers.

That’s the general shape of the trap, and it’s not hypothetical on stash: pin both dials to the expensive corner out of habit and the sweep alone - a few hundred cheap, mechanical rows - bills like the redesign did. Pin them to the cheap corner instead and the redesign gets a shallow pass at a problem that forks, which is the worse mistake: you ship a confident wrong answer and pay for the rewrite anyway.

enabledModels and defaultModel only help once a cheap option is defined for Pi to route to. That’s models.json, and it’s usually easier to have Pi do the editing than to hand-write the provider block yourself - it can read its own docs and figure out the shape a new provider needs. Say you want to add a low-cost coding model behind an OpenRouter-style API key, for the sweep work specifically:

> add a custom provider to models.json for a cheap coding model I can
route the stash re-extraction backlog to, then tell me where to paste
the API key

Pi identifies that this isn’t a login-subscription provider the way OpenAI or GitHub Copilot are - it needs a models.json entry with its own baseUrl, api shape, and an apiKey field, plus (depending on how the key resolves) a matching entry in auth.json:

~/.pi/agent/models.json
{
"providers": {
"cheap-coder": {
"baseUrl": "https://openrouter.ai/api/v1",
"api": "openai-completions",
"apiKey": "$OPENROUTER_API_KEY",
"models": [
{ "id": "some-cheap-coding-model", "name": "Cheap coder", "reasoning": true, "contextWindow": 128000 }
]
}
}
}

apiKey resolves three ways - a literal string, a $ENV_VAR interpolation, or a !command whose stdout it uses - so you’re not forced to put the key in the file at all. Paste the key yourself; don’t ask Pi to read the file back and confirm it took. Agents that can read files can also print them, verbatim, to whatever terminal you’re sitting in - including one you might be sharing or recording. If a key is ever echoed back to you in plaintext, treat it as burned and rotate it, on principle, whether or not you think anyone else saw it.

Once the provider’s live, /model shows it in the picker and Ctrl+P cycles it if it’s in enabledModels. Point the re-extraction sweep at it, low thinking, and let it run through the backlog for a fraction of what the frontier model would have billed for the same mechanical rows. Keep the extractor redesign on your strongest model at high - that one still earns every token.

To make this concrete: a 50-file rename sweep might cost $0.30 on a cheap model vs. ~$4 on a frontier model. A design review on the same codebase might cost $0.80 on the frontier model and produce noticeably better output. The routing habit is about spending the $4 only where it earns its keep. (These numbers are illustrative - model pricing changes frequently, so treat them as order-of-magnitude guidance, not quotes.)

Routing between hosted models is one lever. There’s a more extreme version of “cheap” available too: a model that costs nothing per token because it’s running on the machine in front of you. See what that actually buys you - and where it runs out of room.