Undercut for JetBrains AI Assistant

AI Assistant's own Project Rules can hold a routing policy. Give it one that stops overpaying.

Undercut is a free, MIT-licensed routing policy you save as a Project Rule inside JetBrains AI Assistant — the IDE's own chat and inline-completion assistant, not Junie — cheap tier first, escalate only on evidence, never on a vibe. AI Assistant has no built-in per-task cost dial of its own to compare against; this exists because the same overpay-by-default pattern we measured elsewhere in the agent ecosystem (see the Claude Code page) shows up anywhere an assistant defaults every task to its strongest model.

Install for AI Assistant See the benchmarks
Not the same product as Junie

JetBrains bundles several distinct coding-agent surfaces under one "AI Assistant" documentation umbrella — Junie (the autonomous agent) already has its own page on this site at /junie, with its own .junie/skills/ Agent Skills mechanism. This page is about AI Assistant's own chat/inline-completion features specifically, and the distinct Project Rules mechanism (.aiassistant/rules/) documented for it — a plain-Markdown rules file, not a SKILL.md discovery path. If you only use Junie, install from /junie instead; if you also want the rubric considered by AI Assistant's own chat, this page's install steps are for that. Source: JetBrains' own Project Rules docs.

Works anywhere a routing policy can be read
Claude Code Codex Cursor Copilot Junie AI Assistant

How this maps onto JetBrains AI Assistant

Project Rules, not Agent Skills. A plain Markdown file, always considered.

Per JetBrains' own Project Rules docs, AI Assistant reads project rules from an .aiassistant/rules/ folder at the project root, one .md file per rule. Create one from Settings | Tools | AI Assistant | Rules > New Project Rules File, or add the folder and file by hand — both produce the same thing. Each rule file carries a type, set from a control in the file's own editor tab, not YAML frontmatter: Always (applied automatically to every chat session), Manually (invoked with @rule: / #rule: or the chat's Add-attachment action), By Model Decision (the model decides relevance from a description you provide — the closest analog to a SKILL.md's trigger phrase), By File Patterns (fires when a referenced file matches a glob like *.kt or src/**), or Off. This is explicitly distinguished, in JetBrains' own docs, from cross-tool instruction files like AGENTS.md or CLAUDE.md — project rules are described as IDE-specific and scoped to AI Assistant's own chat mode, not something every agent in a repo automatically shares.

That's a genuinely different shape from every skill-native client on this site: there's no confirmed SKILL.md discovery path for AI Assistant itself, no progressive-disclosure name/description index the assistant scans before loading a body, and (per the same docs) no confirmed global or user-level rules location — project rules live only at the project root. Undercut's rubric fits this shape as plain policy text, either always in context (Always) or model-triggered off a description (By Model Decision), which is the option that most resembles how a SKILL.md's own description field already works elsewhere on this site.

Undercut's tier names — cheap, standard, frontier, apex — are generic on purpose. JetBrains AI Assistant supports a JetBrains AI subscription, your own provider API keys, or authorized provider accounts, so models.md gives a rule of thumb rather than a fixed slug: cheap resolves to the smallest/fastest model your setup has enabled, standard to the default chat model, frontier to the highest-reasoning model on offer, and apex to a single batched tie-break call. Nothing here sits between AI Assistant and its model backend — it's a rules file the IDE reads into context, no proxy, no network hop.

Install for JetBrains AI Assistant

Free. MIT. Nothing installs, nothing proxies your traffic.

Option 1 — add it as a Project Rule (confirmed path)

Create the rules folder and drop the policy text straight in, then open the file in the IDE editor and set its Rule type to Always so it's considered on every chat session:

$ mkdir -p .aiassistant/rules && curl -fsSL https://raw.githubusercontent.com/undercutsh/firstpass/main/skills/firstpass/SKILL.md -o .aiassistant/rules/firstpass.md

Prefer AI Assistant to only reach for the rubric on matching work instead of every session? Set the type to By Model Decision instead of Always, and paste the rubric's own trigger description — "use before any multi-agent fan-out, swarm, or model-tier assignment" — into the Instruction field so the model has something to match against.

Option 2 — through the Settings UI

If you'd rather not touch the filesystem directly: Settings | Tools | AI Assistant | Rules > New Project Rules File, name it firstpass, paste in the raw policy text from GitHub, and pick the Rule type from the dropdown at the top of the editor tab. This produces the identical .aiassistant/rules/firstpass.md file as Option 1.

What's still unverified: skills.sh lists no JetBrains AI Assistant install target, so the generic npx skills add undercutsh/firstpass referenced on other pages of this site does not apply here — use Option 1 or 2 above instead. JetBrains' docs describe project rules as scoped to AI Assistant's own chat mode and confirm no global or user-level rules location exists, only project root — treat that as confirmed absent rather than untested. We have not run these steps against a live IDE session ourselves; if the Rule-type control has moved in a newer AI Assistant build, the Settings path in Option 2 is the one to trust over this page.

Validate it yourself

  1. 1Read the published results — testing/README.md and the raw JSON in testing/results/
  2. 2Reproduce for free, no API key, no spend: node src/main.js --mock
  3. 3Ask AI Assistant to route a small batch of mechanical work and expand the attachments list in its response — JetBrains' own docs say this is how you confirm which rules actually applied

Zero lock-in. It's a rules file AI Assistant reads into context — delete it, or set its type to Off, and you're back to status quo.

How it works

The Undercut Rubric · v1

Six flags assign a tier. Three triggers are the only way up.

This is a named, versioned spec — not internal logic we could quietly change. When the rubric changes (a new flag, a different cap), the version number moves and the changelog says why.

Every unit of work gets scored against six flags, then assigned the cheapest tier that can plausibly handle it. It only moves up a tier when something objective proves it needs to — a failed check, a measured disagreement, an explicit uncertainty flag. It never moves up on a guess, and it never moves back down mid-task.

unit of work
6-flag rubric
0 flags
cheap~90% of units land here ✓
1–2
standard
3+/own
frontier
↑ escalate +1 tier only on: fail ×2 · two runs disagree · tagged "uncertain" residue only — never redoes the batch
See the rubric

Step 1 — Base tier, six-flag rubric

Unverifiable — can output be checked mechanically? (tests, schema, diff, grep)
Ambiguous — one right answer, or several defensible ones?
Blast — reversible? touches money, auth, user data, production, deletes?
Cross-cutting — one file/source, or reasoning across many?
Novel — pattern-following, or genuinely new design?
Format-strict — must output match an exact schema?

0 flags → cheap · 1–2 → standard · 3+ or any ownership/judgment call → frontier. Apex only when you can write one sentence stating why the marginal intelligence pays for the cost.

The override — single biggest lever

Cheap-to-verify ⇒ cheap-to-generate. If output can be checked mechanically, it starts at the lowest tier regardless of how hard it looks — verification catches failure. Only unverifiable work needs to start high.

Step 2 — Escalate exactly one tier, on evidence only

  • Verification fails twice at the current tier
  • Two cheap-tier runs disagree on ambiguous-flagged work
  • The worker tags an item "uncertain"

Residue-only handoff

The next tier up gets only the failed or uncertain items, plus verification notes. It resolves the residue — it never redoes the batch.

Hysteresis — guardrails

Never de-escalate mid-task. Max one retry per tier. Anything still unresolved goes to a single batched apex tie-break call. One hard file in a 700-file job doesn't drag the other 699 up a tier.

 unit of work
      |
  6-flag rubric
      |
  +---+----+
  | 0 flags|--> cheap
  | 1-2    |--> standard
  | 3+/own |--> frontier
  +---+----+
      | fail x2 / disagree / uncertain
      v
  escalate +1 tier
  (residue only)
      |
  still unresolved?
      v
  single batched
  apex tie-break

Why it holds up

Flags steer. Verification and escalation decide.

Even when the rubric flags are scored imperfectly, the escalator still routes work to the right tier almost every time — because a wrong flag only ever costs one extra cheap attempt, never a wrong answer or a big bill.

See the data

A stock dispatcher model reproduces the rubric flags imperfectly — Haiku hits 90% agreement, Sonnet 93%. The weakest flag (format-strict) is only 60%. None of that matters: under the shipped policy, both dispatchers still route 100% of units to the correct tier. A wrong flag changes the ladder cap, never the base tier — worst case, one extra cheap attempt.

Haiku dispatcher
90% flag agreement
100% tier-match
Sonnet dispatcher
93% flag agreement
100% tier-match

The rules are about the work, not the model.

Every rule is a property of the unit of work — verifiable, ambiguous, blast-radius — never a specific model's known weakness. Vendor cards go stale as models change; work properties don't. It's also hard-won — a format-strict rule that worked on Anthropic backfired on Gemini, which is exactly why the rubric no longer encodes per-vendor behavior.

Honest limits

What this doesn't do.

Not a proxy, not a gateway, doesn't auto-flag in production (AI Assistant scores the flags itself — measured robust to getting them wrong, see above), and doesn't promise a dollar figure for your workload. It also doesn't prove your number until you run it — every figure here is an observation from our tasks and our graders, not a guarantee about yours. It only governs AI Assistant's own chat mode: it does not extend to Junie sessions in the same IDE (see the banner above and the separate Junie page for that), there's no confirmed global or user-level rules location, and JetBrains' own docs draw a hard line between project rules and cross-tool instruction files like AGENTS.md. Full list, with the finance/procurement note and the paid-tier disclosure, is on the main page.

Undercut the top tier. Not the quality bar.

Nothing about this page expires. What does keep happening is the token bill, one session at a time, on whatever AI Assistant is currently doing with mechanical work.

View on GitHub