<p>Some releases add features. This one adds <em>instincts</em>. Three of them: noticing your own mistakes, not making a mess of someone else's desk, and remembering who's reliable. Suspiciously human traits for a coding agent — and all three came out of one question we kept asking ourselves: <em>where does a developer lose time when pairing with an agent?</em></p><h2>Why this release</h2><p>Watch a session closely and you'll see the same three time sinks over and over:</p><ol><li><p>The agent edits a file, declares victory, and the type error it just introduced surfaces two turns later — usually because <em>you</em> ran the check.</p></li><li><p>You want the agent to do a bigger piece of work autonomously, but you don't quite dare — it works directly in your working tree, and you've got uncommitted changes sitting there.</p></li><li><p>A provider has a bad day, failover kicks in... and picks a fallback model that has <em>also</em> been having a bad day all week. The static ranking had no way of knowing.</p></li></ol><p>0.9.20 attacks all three. Here's the why and the how.</p><h2>1. Auto-diagnostics + blast radius on every edit</h2><p>In 0.9.18 we taught the LSP extensions to resolve referenced types after an edit. That was step one. This release completes the loop — after every successful <code>edit</code> in a TypeScript, PHP, or Rust project, the agent now sees <strong>three things in the edit's own tool result</strong>, with zero extra tool calls:</p><pre><code class="language-text">Successfully replaced 1 block(s) in src/services/export.ts.

[Diagnostics — auto-checked via LSP]
2 errors in this file after the edit:
- src/services/export.ts:48:11 [2345]: Argument of type 'string' is not
  assignable to parameter of type 'ExportFormat'.
- src/services/export.ts:52:3 [2741]: Property 'compress' is missing...

[Blast radius — auto-resolved via LSP]
scheduleExport is referenced in 4 places outside this file:
- src/routes/api.ts:112
- src/jobs/nightly-export.ts:31
- src/controllers/ReportController.ts:88
- test/export.test.ts:19

[Related symbols — auto-resolved via LSP, no extra tool call needed]
- ExportFormat: type ExportFormat = "csv" | "json"
</code></pre><p><strong>Why this matters:</strong> the agent used to discover that first error when <em>you</em> did. Now it sees it before writing its next sentence — and it knows there are four call sites to update before it congratulates itself on changing a signature. Each of these used to be a full round trip: a wasted turn, a <code>grep</code>, a follow-up prompt. Now it's free context, delivered in-band.</p><p>It's built on the language servers you already have (<code>tsserver</code>, Intelephense, <code>rust-analyzer</code>), waits briefly for fresh diagnostics after syncing the file, and is entirely best-effort — if anything fails, the edit result is untouched. Rust gets a slightly longer diagnostics window because <code>rust-analyzer</code> likes to think things over.</p><h2>2. Swarm worktree mode: multi-agent work without the mess</h2><p>Our <code>/swarm</code> pipelines (build, review, refactor) have always run their stages in your session. Effective — but every write stage worked directly in <em>your</em> working tree. Autonomy with your uncommitted changes as collateral.</p><p>Now:</p><pre><code class="language-text">/swarm --worktrees build add rate limiting to the API
</code></pre><p>Here's what happens differently:</p><ul><li><p>Every stage — planner, coder, tester, reviewer, fixer — runs as its <strong>own isolated </strong><code>elyra -p</code><strong> sub-agent</strong> inside a detached <strong>git worktree</strong> based on HEAD. Your working tree is never touched while the swarm runs. Go on editing; the swarm can't step on you.</p></li><li><p>Read-only stages aren't just <em>told</em> not to edit files anymore — they're mechanically restricted to <code>read</code>, <code>grep</code>, <code>find</code>, and <code>ls</code>. A planner literally cannot write.</p></li><li><p>When all stages finish, Elyra collects the combined changes as a single patch and checks it against every file that changed in your tree during the run. Clean? The patch is applied <strong>uncommitted</strong>, ready for your review — Elyra never commits without being asked. Conflict? Nothing is applied, the conflicting paths are listed, and the worktree is kept so no work is lost.</p></li><li><p>Not in a git repo? It degrades gracefully to the classic inline mode.</p></li></ul><p><strong>Why this matters:</strong> this is the difference between "I'll run a swarm when the tree is clean and I'm watching" and "run the swarm, I'll review the diff when it's done." Isolation is what turns multi-agent pipelines from a demo into a tool.</p><h2>3. Measured routing: failover that learns from your machine</h2><p>Elyra's cross-provider failover has always been a favorite: provider melts down mid-turn, Elyra reroutes to an equivalent model from another vendor you hold keys for. But the fallback <em>ranking</em> was purely static — cost band, reasoning capability, context window. Sensible on paper. Blind in practice.</p><p>Now Elyra keeps a small local ledger (<code>~/.elyra/agent/routing-ledger.jsonl</code>) of how models actually perform <strong>for you</strong>: turn success rate, edit failures, retries, failovers away, latency, cost. When failover fires, models the ledger shows to be demonstrably unreliable get demoted in the ranking.</p><p>Check what it knows anytime:</p><pre><code class="language-text">/routing-stats

Model outcome measurements (last 30 days, local only):

- anthropic/claude-sonnet-5: 212 turns, 98% success, 3/94 edit failures,
  2 retries, 0 failovers away, $4.1120 total, 9.3s avg
- openai/gpt-5.6: 41 turns, 95% success, 1/18 edit failures, 1 retry,
  1 failover away, $1.0330 total, 7.8s avg
- somevendor/flaky-model: 12 turns, 58% success, 4/9 edit failures,
  7 retries, 5 failovers away, $0.4410 total, 21.6s avg  [demoted in failover ranking]
</code></pre><p>Also available outside a session as <code>elyra doctor routing</code>.</p><p>Three design choices worth spelling out:</p><ul><li><p><strong>A sample-size floor.</strong> Below five measured turns, a model ranks exactly as before. Thin data never changes anything; measurements only ever demote <em>demonstrated</em> problems.</p></li><li><p><strong>Demotion, not promotion.</strong> This isn't a bandit algorithm chasing scores. Static heuristics still decide; the ledger just keeps the ranking from walking into a known wall.</p></li><li><p><strong>Local, and only numbers.</strong> Model ids, counters, timings, cost. Never prompts, never file paths, never code. Nothing leaves your disk. Opt out entirely with the <code>routingLedger</code> setting.</p></li></ul><p><strong>Why this matters:</strong> every vendor-locked agent has exactly one answer when its provider stumbles: an error message. Elyra's answer is "route around it" — and as of today, "route around it <em>toward the model that's actually been working for you</em>." That's only possible because Elyra is provider-agnostic and your usage history lives on your machine.</p><h2>The thread connecting all three</h2><p>Auto-diagnostics closes the loop on a single edit. Worktree mode closes the loop on a whole pipeline. Measured routing closes the loop on model choice itself. Same idea at three scales: <strong>the agent should check its own work, and the system should learn from the outcome.</strong></p><h2>Get it</h2><pre><code class="language-bash">npm install -g @elyracode/coding-agent@latest
</code></pre><p>Then <code>/reload</code> old sessions, point a swarm at something with <code>--worktrees</code>, and take a look at <code>/routing-stats</code> in a week — it reads like a performance review your models didn't know they were getting.</p>