NewEvals run before every pull request

Ship agent work like
production code.

Kestrel runs your coding agents in sealed sandboxes, keeps what they learn about your repo, and opens a pull request only when the evals pass.

web-app / mainSandbox: isolated

Opens a PR when 48 checks pass
Agent run One agent run: a task moves from the queue into a sandbox, a branch leaves the main line for it, the agent reads the repo and writes a diff, eight tests pass one by one, and only then is a pull request opened and merged back onto the main line. float R(float k) { return 3.5 + 9.4 * k; } // A task card from its first column and title row: a marker, a title, two lines of text, on a faint body. float card(vec2 q) { if (q.x < -3.5 || q.x > 87.5 || q.y < -4.7 || q.y >= 23.5) return 0.0; float r = floor(q.y / 9.4 + 0.5); float v = 0.15; if (r < 0.5) v = q.x < 3.5 ? 1.05 : (q.x > 10.5 && q.x < 59.5 ? 0.7 : v); else if (r < 1.5) v = q.x > 10.5 && q.x < 80.5 ? 0.24 : v; else v = q.x > 10.5 && q.x < 52.5 ? 0.24 : v; return v; } // A faint link: a soft band from a to b, at least a column wide and a cell tall, so it never falls between samples. float lk(vec2 p, vec2 a, vec2 b, float k) { vec2 ab = b - a; float h = clamp(dot(p - a, ab) / dot(ab, ab), 0.0, 1.0); vec2 d = (p - a - ab * h) / vec2(3.6, 4.8); return k * (1.0 - sm(0.8, 1.05, length(d))); } vec2 bz(vec2 a, vec2 c, vec2 b, float u) { return mix(mix(a, c, u), mix(c, b, u), u); } float field(vec2 p, float t) { if (p.x < 18.0 || p.x > 702.0 || p.y < 18.0 || p.y > 442.0) return 0.0; float ph = TAU * t / T; float v = 0.0; float gr = floor((p.y - 3.5) / 9.4 + 0.5); // the cell row this sample is on // This run's clock: before 0.6 s the last run is still on screen, so its parts read the clock a cycle on and are // torn down from 0.3 to 0.55 s. float tt = t < 0.6 ? t + T : t; float env = 1.0 - sm(T + 0.3, T + 0.55, tt); float appear = sm(1.15, 1.25, tt) * env; // the repo, checked out into the sandbox // The queue: the top task leaves at 0.45 s, the rest move up one, and a new task joins at the bottom. float q = ease((t - 0.55) / 0.4); for (int j = 1; j < 4; j++) v += card(p - vec2(32.0, R(9.0) + 47.0 * (float(j) - q))); v += sm(0.95, 1.2, t) * card(p - vec2(32.0, R(24.0))); // The task: waiting, carried into the sandbox's header (0.45 to 0.9 s), held there for the run. if (t < 0.45) v += card(p - vec2(32.0, R(9.0))); else if (t < 0.9) v += card(p - vec2(32.0, R(9.0)) - vec2(119.0, -28.2) * ease((t - 0.45) / 0.45)); v += (t >= 0.9 ? 1.0 : 1.0 - sm(0.3, 0.55, t)) * card(p - vec2(151.0, R(6.0))); // Main: the trunk, a commit every 70 px, each earlier run's merge a small arch. After a merge the view follows main // one commit to the left (0.55 to 0.95 s), and the merge's arch shows as its branch goes (0.3 to 0.55 s). float X = -70.0 * ease((t - 0.55) / 0.4); float old = sm(18.0, 150.0, p.x); if (gr == 42.0 && p.x < 515.0 + X + 70.0 * ease((t - 4.05) / 0.13) + 1.0) v += 0.42 * old; for (int k = 0; k < 8; k++) { float x = 515.0 - 70.0 * float(k) + X; v += old * (blob(p, vec2(x, R(42.0)), 9.5, 1.15) + blob(p, vec2(x, R(42.0)), 16.0, 0.2)); float e = (length((p - vec2(x - 35.0, R(42.0))) / vec2(35.0, 28.2)) - 1.0) * 26.0; v += old * (k == 0 ? sm(0.3, 0.55, t) : 1.0) * 0.4 * exp(-e * e / 40.0) * step(p.y, 392.0); } // This run's merge commit lands at 4.18 s and flares. v += sm(4.12, 4.2, t) * (blob(p, vec2(585.0 + X, R(42.0)), 9.5, 1.15) + blob(p, vec2(585.0 + X, R(42.0)), 16.0, 0.2)); v += blob(p, vec2(585.0 + X, R(42.0)), 16.0, 0.8 * exp(-pow((t - 4.24) / 0.1, 2.0))); // This run's branch: up from main's head into the sandbox (0.95 to 1.15 s). if (tt > 0.95) { float tip = R(42.0) - 58.0 * ease((tt - 0.95) / 0.2); if (abs(p.x - 445.0) < 1.0 && p.y > tip && p.y < 392.0) v += 0.45 * env; if (tt < 1.15) v += blob(p, vec2(445.0, tip), 7.0, 1.2); } // Pushed from the test strip to the PR (3.5 to 3.72 s). float pu = (tt - 3.5) / 0.22; if (pu > 0.0) { float tip = mix(473.0, 564.0, ease(pu)); if (gr == 31.0 && p.x > 469.0 && p.x < tip) v += 0.42 * env; if (pu < 1.0) v += blob(p, vec2(tip, R(31.0)), 7.5, 1.25); } // Merged: from the PR down onto main (3.92 to 4.18 s). float mu = (tt - 3.92) / 0.26; if (mu > 0.0) { vec2 A = vec2(599.0, 318.0); vec2 C = vec2(599.0, 380.0); vec2 B = vec2(528.0, 396.0); float um = ease(mu); float ln = 0.0; for (int i = 0; i < 8; i++) { float a = float(i) / 8.0; if (a < um) ln = max(ln, lk(p, bz(A, C, B, a), bz(A, C, B, min(a + 0.125, um)), 0.42)); } v += env * ln; if (mu < 1.0) v += blob(p, bz(A, C, B, um), 7.5, 1.25); } // The PR card on a faint body, drawn row by row as it opens (3.72 s): title, branch into main, description, diffstat, // five passed checks and the merge button, which flashes when pressed (3.88 s) and dims once merged. float open = tt - 3.72; if (open > 0.0 && p.x > 560.0 && p.x < 680.0 && gr >= 9.0 && gr <= 30.0) { float c = floor((p.x - 564.0) / 7.0 + 0.5); float pv = 0.15; if (gr == 9.0) pv = c <= 12.0 ? 0.7 : pv; else if (gr == 11.0) pv = c <= 5.0 || (c >= 7.0 && c <= 11.0) ? 0.42 : pv; else if (gr == 13.0) pv = c <= 16.0 ? 0.24 : pv; else if (gr == 14.0) pv = c <= 14.0 ? 0.24 : pv; else if (gr == 15.0) pv = c <= 8.0 ? 0.24 : pv; else if (gr == 17.0) pv = c <= 6.0 && mod(c, 2.0) < 0.5 ? 1.05 : (c == 8.0 ? 0.42 : pv); else if (gr >= 19.0 && gr <= 27.0 && mod(gr, 2.0) > 0.5) { float len = ((gr - 19.0) / 2.0 < 0.5 ? 12.0 : ((gr - 19.0) / 2.0 < 1.5 ? 10.0 : ((gr - 19.0) / 2.0 < 2.5 ? 14.0 : ((gr - 19.0) / 2.0 < 3.5 ? 8.0 : 11.0)))); pv = c == 0.0 ? 1.05 : (c >= 2.0 && c <= len + 1.0 ? 0.42 : pv); } else if (gr >= 29.0 && c <= 12.0) pv = mix(0.75, 0.4, sm(4.0, 4.2, tt)) + 0.5 * exp(-pow((tt - 3.9) / 0.04, 2.0)); v += env * step(0.006 * (gr - 9.0), open) * pv; } // The sandbox's floor: faint grit while the sandbox exists (from the task's arrival to the teardown). if (p.x > 142.0 && p.x < 478.0 && p.y > 42.0 && p.y < 334.0) v += 0.17 * sm(0.9, 1.05, tt) * env * step(0.86, hash(floor(p / vec2(7.0, 9.4)) + 5.3)); // The repo tree: a marker per row (a folder denser than a file), the name, and nesting guides. A row lights as the // agent reads it and stays read. if (p.x > 146.0 && p.x < 232.0 && gr >= 11.0 && gr <= 33.0 && mod(gr, 2.0) > 0.5) { float i = (gr - 11.0) / 2.0; float lvl = (i < 0.5 ? 0.0 : (i < 1.5 ? 1.0 : (i < 2.5 ? 2.0 : (i < 3.5 ? 2.0 : (i < 4.5 ? 2.0 : (i < 5.5 ? 1.0 : (i < 6.5 ? 2.0 : (i < 7.5 ? 2.0 : (i < 8.5 ? 1.0 : (i < 9.5 ? 0.0 : (i < 10.5 ? 1.0 : 0.0))))))))))); float dir = (i < 0.5 ? 1.0 : (i < 1.5 ? 1.0 : (i < 2.5 ? 0.0 : (i < 3.5 ? 0.0 : (i < 4.5 ? 0.0 : (i < 5.5 ? 1.0 : (i < 6.5 ? 0.0 : (i < 7.5 ? 0.0 : (i < 8.5 ? 0.0 : (i < 9.5 ? 1.0 : (i < 10.5 ? 0.0 : 0.0))))))))))); float len = (i < 0.5 ? 5.0 : (i < 1.5 ? 4.0 : (i < 2.5 ? 6.0 : (i < 3.5 ? 4.0 : (i < 4.5 ? 5.0 : (i < 5.5 ? 3.0 : (i < 6.5 ? 6.0 : (i < 7.5 ? 3.0 : (i < 8.5 ? 5.0 : (i < 9.5 ? 4.0 : (i < 10.5 ? 6.0 : 4.0))))))))))); float c = floor((p.x - 151.0) / 7.0 + 0.5) - 2.0 * lvl; float ti = 1.25 + 0.7 * i / 11.0; float rv = 0.0; if (c == 0.0) rv = dir > 0.5 ? 0.7 : 0.4; else if (c >= 2.0 && c <= len + 1.0) rv = 0.22 + 0.24 * sm(ti - 0.03, ti, tt); v += appear * (rv + (rv > 0.0 ? 0.55 * exp(-pow((tt - ti) / 0.05, 2.0)) : 0.0)); } if (abs(p.x - 151.0) < 1.0 && ((gr >= 12.0 && gr <= 27.0) || (gr >= 30.0 && gr <= 31.0))) v += 0.17 * appear; if (abs(p.x - 165.0) < 1.0 && ((gr >= 14.0 && gr <= 19.0) || (gr >= 22.0 && gr <= 25.0))) v += 0.17 * appear; // The diff: context and removed lines are there from the checkout; the agent marks the removed ones and types the // added ones in, one after another. if (p.x > 293.0 && p.x < 470.0 && gr >= 11.0 && gr <= 25.0 && mod(gr, 2.0) > 0.5) { float j = (gr - 11.0) / 2.0; float ty = (j < 0.5 ? 0.0 : (j < 1.5 ? 2.0 : (j < 2.5 ? 1.0 : (j < 3.5 ? 1.0 : (j < 4.5 ? 1.0 : (j < 5.5 ? 0.0 : (j < 6.5 ? 1.0 : 1.0))))))); float ind = (j < 0.5 ? 0.0 : (j < 1.5 ? 1.0 : (j < 2.5 ? 1.0 : (j < 3.5 ? 2.0 : (j < 4.5 ? 2.0 : (j < 5.5 ? 1.0 : (j < 6.5 ? 1.0 : 0.0))))))); float len = (j < 0.5 ? 12.0 : (j < 1.5 ? 15.0 : (j < 2.5 ? 17.0 : (j < 3.5 ? 13.0 : (j < 4.5 ? 10.0 : (j < 5.5 ? 14.0 : (j < 6.5 ? 18.0 : 5.0))))))); float wj = 2.2 + 0.55 * j / 7.0; float wr = sm(wj - 0.02, wj + 0.02, tt) * env; float c = floor((p.x - 312.0) / 7.0 + 0.5) - 2.0 * ind; float dv = 0.0; if (abs(p.x - 298.0) < 1.0) dv = ty > 1.5 ? 0.7 * wr : (ty > 0.5 ? 1.05 * wr : 0.0); else if (c >= 0.0 && c < len) { if (ty < 0.5) dv = 0.22 * appear; else if (ty > 1.5) dv = 0.22 * appear + 0.2 * wr; else dv = 0.7 * env * step(c, len * clamp((tt - wj) / 0.07, 0.0, 1.0) - 0.5); } v += dv + (dv > 0.0 ? 0.4 * exp(-pow((tt - wj - 0.04) / 0.05, 2.0)) : 0.0); } // The test strip: eight slots; each test's bar rises while it runs (one after another from 2.8 s) and goes solid, // its top densest, once it passes. if (p.x > 308.0 && p.x < 470.0 && gr >= 29.0 && gr <= 33.0) { float sx = floor((p.x - 312.0) / 7.0 + 0.5); float i = floor(sx / 3.0); if (sx - 3.0 * i < 1.5) { float h = (i < 0.5 ? 3.0 : (i < 1.5 ? 2.0 : (i < 2.5 ? 4.0 : (i < 3.5 ? 3.0 : (i < 4.5 ? 2.0 : (i < 5.5 ? 5.0 : (i < 6.5 ? 3.0 : 2.0))))))); float f = clamp((tt - 2.8 - 0.075 * i) / 0.09, 0.0, 1.0); float lv = 33.0 - gr; // 0 on the baseline float bar = lv < h * f - 0.01 ? (f < 1.0 ? 0.5 : (lv > h - 1.5 ? 1.05 : 0.7)) : 0.0; v += max(0.15 * appear, bar * env); } } // The agent, between the repo and the diff: a bright rim, an inner ring, a speckled floor and a dense core that // churns, brighter while it works, with a mark turning on its rim. Its beam goes to what it is working on: the task // (0.95 to 1.15 s), each repo row in turn (1.25 to 1.95 s), each diff line in turn (2.2 to 2.75 s). vec2 ac = vec2(263.0, 182.0); float work = sm(0.9, 1.05, t) * (1.0 - sm(2.8, 3.0, t)); float d = length(p - ac) / 30.0; float inside = 1.0 - sm(0.9, 1.0, d); float churn = noise(p * 0.11 + 1.6 * vec2(cos(ph), sin(ph))); v += (0.4 + 0.12 * work) * exp(-pow(d - 1.0, 2.0) / 0.012); v += inside * (0.3 * exp(-pow(d - 0.62, 2.0) / 0.006) + 0.14); v += blob(p, ac, 17.0, (1.05 + 0.3 * work) * (0.85 + 0.6 * (churn - 0.5))); v += blob(p, ac + 30.0 * vec2(cos(2.0 * ph), sin(2.0 * ph)), 5.5, 0.55 + 0.4 * work); vec2 aim = vec2(0.0); float beam = 0.0; if (tt > 0.95 && tt < 1.15) { aim = vec2(236.0, R(7.0)); beam = sm(0.95, 0.99, tt) * (1.0 - sm(1.11, 1.15, tt)); } else if (tt > 1.25 && tt < 1.95) { aim = vec2(232.0, mix(R(11.0), R(33.0), (tt - 1.25) / 0.7)); beam = sm(1.25, 1.29, tt) * (1.0 - sm(1.91, 1.95, tt)); } else if (tt > 2.2 && tt < 2.75) { aim = vec2(292.0, mix(R(11.0), R(25.0), (tt - 2.2) / 0.55)); beam = sm(2.2, 2.24, tt) * (1.0 - sm(2.71, 2.75, tt)); } if (beam > 0.0) v += beam * step(1.0, d) * (lk(p, ac + 30.0 * normalize(aim - ac), aim, 0.45) + blob(p, aim, 5.0, 0.6)); return v; }
41,280runs a day
11 minmedian task to PR
93%PRs merged unchanged
0outbound calls allowed
How a run works

Three rules every run follows

Agents are fast and confident. Kestrel gives them walls, a memory and a reviewer, so what reaches your repo is work you would have merged anyway.

Sandbox A rack of sealed cells, one task in each: the repo is copied into one cell, an agent works inside it, its request to the network stops at the wall, and only the diff it wrote leaves through the out port before the cell is wiped clean. const float T0 = 3.52; float rr(float a, float lo, float hi) { return step(lo - 0.5, a) * step(a, hi + 0.5); } float eq(float a, float b) { return step(abs(a - b), 0.5); } float X(float c) { return 4.0 + 7.0 * c; } float Y(float r) { return 3.5 + 9.4 * r; } float eout(float u) { u = clamp(u, 0.0, 1.0); return 1.0 - pow(1.0 - u, 3.0); } vec3 treeRow(float i) { if (i < 0.5) return vec3(0.0, 4.0, 1.0); if (i < 1.5) return vec3(1.0, 6.0, 0.0); if (i < 2.5) return vec3(1.0, 8.0, 0.0); if (i < 3.5) return vec3(1.0, 3.0, 1.0); if (i < 4.5) return vec3(2.0, 5.0, 0.0); if (i < 5.5) return vec3(2.0, 7.0, 0.0); if (i < 6.5) return vec3(1.0, 5.0, 0.0); if (i < 7.5) return vec3(0.0, 4.0, 1.0); if (i < 8.5) return vec3(1.0, 7.0, 0.0); if (i < 9.5) return vec3(1.0, 4.0, 0.0); if (i < 10.5) return vec3(0.0, 6.0, 0.0); if (i < 11.5) return vec3(0.0, 3.0, 0.0); return vec3(0.0); } vec2 diffRow(float i) { if (i < 0.5) return vec2(1.0, 7.0); if (i < 1.5) return vec2(1.0, 5.0); if (i < 2.5) return vec2(0.0, 4.0); if (i < 3.5) return vec2(1.0, 6.0); if (i < 4.5) return vec2(0.0, 5.0); if (i < 5.5) return vec2(1.0, 3.0); return vec2(0.0); } float entry(float C, float s, vec3 e) { return eq(C, s) * (e.z > 0.5 ? 1.05 : 0.72) + rr(C, s + 2.0, s + 1.0 + e.y) * (e.z > 0.5 ? 0.62 : 0.42); } float dline(float C, float g, vec2 d, float upto) { float txt = rr(C, g + 2.0, min(g + 1.0 + d.y, g + 1.0 + upto)); return eq(C, g) * (d.x > 0.5 ? 1.0 : 0.45) + txt * (d.x > 0.5 ? 0.72 : 0.4); } float walls(float C, float R, float c0, float c1, float r0, float r1, float pr, float oin, float oout) { float port = rr(R, pr - 1.0, pr + 1.0); float wall = (eq(C, c0) + eq(C, c1)) * rr(R, r0, r1) + (eq(R, r0) + eq(R, r1)) * rr(C, c0 + 1.0, c1 - 1.0); wall *= 1.0 - port * (eq(C, c0) * oin + eq(C, c1) * oout); float inner = (eq(C, c0 + 1.0) + eq(C, c1 - 1.0)) * rr(R, r0 + 1.0, r1 - 1.0); inner *= 1.0 - port * (eq(C, c0 + 1.0) * oin + eq(C, c1 - 1.0) * oout); float liner = (eq(R, r0 + 1.0) + eq(R, r1 - 1.0)) * rr(C, c0 + 2.0, c1 - 2.0); float collar = (rr(C, c0 - 2.0, c0 - 1.0) + rr(C, c1 + 1.0, c1 + 2.0)) * (eq(R, pr - 2.0) + eq(R, pr + 2.0)); float bolt = (eq(C, c0 - 1.0) + eq(C, c1 + 1.0)) * rr(R, r0, r1) * eq(mod(R - r0, 4.0), 2.0) * step(2.5, abs(R - pr)); bolt += (eq(R, r0 - 1.0) + eq(R, r1 + 1.0)) * rr(C, c0, c1) * eq(mod(C - c0, 5.0), 2.0); float room = rr(C, c0 + 2.0, c1 - 2.0) * rr(R, r0 + 2.0, r1 - 2.0); return 1.05 * wall + 0.62 * inner + 0.4 * liner + 0.62 * collar + 0.5 * bolt + room * (0.13 + 0.12 * step(0.9, hash(vec2(C, R) + 7.1))); } float agent(vec2 p, vec2 c, float R0, float on, float work, float ang, float ph, float fi) { float d = length(p - c); float churn = noise(p * 0.1 + vec2(3.0 * fi + 1.3 * cos(ph), 2.0 * fi + 1.3 * sin(ph))); float v = blob(p, c, R0 * 0.6, on * (1.3 + 0.2 * work + 0.4 * (churn - 0.5))); v += on * 0.45 * exp(-pow(d - R0, 2.0) / 30.0); v += on * 0.12 * step(d, R0 - 4.0); v += work * blob(p, c + R0 * vec2(cos(ang), sin(ang)), 6.0, 1.2); return v; } float sibling(vec2 p, float C, float R, float r0, float fi, float ang, float lines, float ph) { float v = walls(C, R, 30.0, 70.0, r0, r0 + 8.0, r0 + 4.0, 0.0, 0.0); float i = R - (r0 + 2.0); if (i > -0.5 && i < 4.5) v += entry(C, 34.0 + treeRow(i).x, treeRow(i)) + eq(C, 33.0) * 0.26; float k = R - (r0 + 3.0); if (k > -0.5 && k < lines - 0.5) v += dline(C, 58.0, diffRow(k), 9.0); v += agent(p, vec2(X(52.0), Y(r0 + 4.0)), 15.0, 1.0, 1.0, ang, ph, fi); return 0.5 * v; } float field(vec2 p, float t) { if (p.x < 18.0 || p.x > 702.0 || p.y < 18.0 || p.y > 442.0) return 0.0; float C = floor((p.x - 4.0) / 7.0 + 0.5); float R = floor((p.y - 3.5) / 9.4 + 0.5); float ph = TAU * t / T; float tau = mod(t + T0, T); float v = 0.0; float oin = sm(0.0, 0.08, tau) * (1.0 - sm(0.98, 1.06, tau)); float oout = sm(3.10, 3.18, tau) * (1.0 - sm(3.42, 3.50, tau)); float wx = tau < 3.55 ? -10.0 : mix(214.0, 500.0, ease((tau - 3.55) / 0.45)); float keep = 1.0 - step(p.x, wx); v += walls(C, R, 30.0, 70.0, 16.0, 33.0, 25.0, oin, oout); v += sibling(p, C, R, 4.0, 1.0, ph + 0.8, 2.0, ph); v += sibling(p, C, R, 37.0, 2.0, ph + 3.4, 0.0, ph); float hit = sm(2.19, 2.22, tau) * (1.0 - sm(2.24, 2.55, tau)); v += 0.45 * hit * eq(C, 70.0) * rr(R, 17.0, 21.0) * exp(-pow(R - 19.0, 2.0) / 3.0); v += 0.3 * (eq(R, 24.0) + eq(R, 26.0)) * (rr(C, 21.0, 27.0) + rr(C, 73.0, 75.0)); { float i = R - 19.0; if (i > -0.5 && i < 11.5) { vec3 e = treeRow(i); float dep = 0.10 + 0.1 * floor(i / 2.0); float lit = sm(dep, dep + 0.04, tau) * (1.0 - sm(dep + 0.12, dep + 0.28, tau)); v += entry(C, 9.0 + e.x, e) * (1.0 + 0.6 * lit) + eq(C, 8.0) * 0.26; } } float crossed = 0.0; for (int j = 0; j < 6; j++) { float dep = 0.10 + 0.1 * float(j); float u = (tau - dep) / 0.36; crossed += step(dep + 0.2, tau); if (u > 0.0 && u < 1.0) { vec2 A = vec2(146.0, 238.5), B = vec2(228.0, 238.5), D = vec2(300.0, Y(19.5 + 2.0 * float(j))); float l1 = length(B - A), l2 = length(D - B); float s = u * (l1 + l2); vec2 c = s < l1 ? mix(A, B, s / l1) : mix(B, D, (s - l1) / l2); v += blob(p, c, 6.5, 1.15 * sm(0.0, 0.08, u) * (1.0 - sm(0.88, 1.0, u))); } } { float i = R - 19.0; if (i > -0.5 && i < 11.5) { vec3 e = treeRow(i); float j = floor(i / 2.0); float arr = 0.46 + 0.1 * j; float rd = 1.18 + 0.1333 * j; float lit = sm(rd, rd + 0.03, tau) * (1.0 - sm(rd + 0.12, rd + 0.2, tau)); v += keep * sm(arr - 0.03, arr + 0.03, tau) * (entry(C, 34.0 + e.x, e) * (1.0 + 0.6 * lit) + eq(C, 33.0) * 0.26); } } vec2 core = vec2(X(52.0), Y(25.0)); float on = sm(0.98, 1.18, tau); float work = sm(1.18, 1.26, tau) * (1.0 - sm(2.98, 3.08, tau)); v += keep * agent(p, core, 24.0, on, work, TAU * 3.0 * (tau - 1.18) / 1.9, ph, 0.0); if (tau > 1.18 && tau < 1.98) { float j = floor((tau - 1.18) / 0.1333); v += seg(p, core, vec2(X(45.0), Y(19.5 + 2.0 * j)), 2.8, 0.42); } if (tau > 2.46 && tau < 3.06) { float i = floor((tau - 2.46) / 0.1); v += seg(p, core, vec2(X(59.0), Y(21.0 + i)), 2.8, 0.42); } { vec2 A = vec2(388.0, 226.0), W = vec2(476.0, 182.1); vec2 back = normalize(A - W); float k = 1.15 * sm(1.98, 2.03, tau) * (1.0 - sm(2.28, 2.42, tau)); if (k > 0.0) { vec2 c = tau < 2.2 ? mix(A, W, ease((tau - 1.98) / 0.22)) : W + back * 20.0 * eout((tau - 2.2) / 0.22); float sq = exp(-pow((tau - 2.2) / 0.05, 2.0)); vec2 d = (p - c) / vec2(9.0 * (1.0 - 0.45 * sq), 9.0 * (1.0 + 0.6 * sq)); v += k * exp(-dot(d, d)); } float sy = 10.0 + 60.0 * max(tau - 2.2, 0.0); v += 0.8 * hit * step(p.x, 488.0) * exp(-pow(p.x - 482.0, 2.0) / 18.0 - pow(p.y - 182.1, 2.0) / (sy * sy)); } { float g = sm(3.05, 3.2, tau); float e = ease(g); for (int k = 0; k < 6; k++) { float i = float(k); float rowR = floor(mix(21.0 + i, 25.0, e) + 0.5); float wr = clamp((tau - 2.46 - 0.1 * i) / 0.08, 0.0, 1.0); if (wr > 0.0 && eq(R, rowR) > 0.5) v += keep * (1.0 - sm(0.6, 1.0, g)) * dline(C - floor(3.0 * e + 0.5), 58.0, diffRow(i), 8.0 * wr); } float u = (tau - 3.2) / 0.22; v += blob(p, vec2(462.0, 238.5), 9.0, 1.3 * sm(3.12, 3.2, tau) * step(tau, 3.2)); if (u > 0.0 && u < 1.0) { vec2 A = vec2(462.0, 238.5), B = vec2(518.0, 238.5), D = vec2(572.0, 252.0); float l1 = length(B - A), l2 = length(D - B); float s = ease(u) * (l1 + l2); vec2 c = s < l1 ? mix(A, B, s / l1) : mix(B, D, (s - l1) / l2); v += blob(p, c, 9.0, 1.3 * (1.0 - sm(0.85, 1.0, u))); } } { float i = R - 24.0; if (i > -0.5 && i < 5.5) { float a0 = 3.38 + 0.015 * i; float hand = ease((tau - 4.02) / 0.28); float vis = sm(a0, a0 + 0.04, tau) * (1.0 - sm(4.06, 4.3, tau)); v += vis * dline(C - floor(3.0 * hand + 0.5), 79.0, diffRow(i), 9.0); } } if (tau > 3.55 && tau < 4.0) { float wv = sm(3.55, 3.6, tau) * (1.0 - sm(3.94, 4.0, tau)); v += wv * rr(R, 18.0, 31.0) * (1.05 * exp(-pow(p.x - wx, 2.0) / 28.0) + 0.22 * step(p.x, wx) * step(wx - 40.0, p.x) * step(0.6, hash(vec2(C, R) + 2.3))); } { float clr = tau < 0.12 ? 1.0 - sm(0.0, 0.12, tau) : 0.0; float hIn = tau < 0.12 ? 6.0 * clr : crossed; float nNet = tau < 0.12 ? clr : step(2.22, tau); float hOut = tau < 0.12 ? clr : step(3.29, tau); float base = 43.0; float slots = (rr(C, 79.0, 80.0) + rr(C, 85.0, 86.0) + rr(C, 91.0, 92.0)) * rr(R, 37.0, base) * 0.13; float inBar = rr(C, 79.0, 80.0) * rr(R, base - hIn + 1.0, base) * step(0.5, hIn) * (eq(R, base - floor(hIn + 0.5) + 1.0) > 0.5 ? 1.05 : 0.62); float outBar = rr(C, 91.0, 92.0) * eq(R, base) * hOut * 1.05; float netMark = rr(C, 85.0, 86.0) * eq(R, base) * nNet * 0.5; v += max(slots, max(inBar, max(outBar, netMark))); } float near = 0.0; v += blob(p, vec2(566.0, 102.0), 6.0, 1.0 + 0.12 * sin(ph + 0.0)); near = max(near, exp(-dot(p - vec2(566.0, 102.0), p - vec2(566.0, 102.0)) / 420.0)); v += blob(p, vec2(600.0, 88.0), 6.0, 1.0 + 0.12 * sin(ph + 1.3)); near = max(near, exp(-dot(p - vec2(600.0, 88.0), p - vec2(600.0, 88.0)) / 420.0)); v += blob(p, vec2(636.0, 100.0), 6.0, 1.0 + 0.12 * sin(ph + 2.6)); near = max(near, exp(-dot(p - vec2(636.0, 100.0), p - vec2(636.0, 100.0)) / 420.0)); v += blob(p, vec2(584.0, 128.0), 6.0, 1.0 + 0.12 * sin(ph + 3.9)); near = max(near, exp(-dot(p - vec2(584.0, 128.0), p - vec2(584.0, 128.0)) / 420.0)); v += blob(p, vec2(620.0, 128.0), 6.0, 1.0 + 0.12 * sin(ph + 5.2)); near = max(near, exp(-dot(p - vec2(620.0, 128.0), p - vec2(620.0, 128.0)) / 420.0)); v += blob(p, vec2(648.0, 118.0), 6.0, 1.0 + 0.12 * sin(ph + 6.5)); near = max(near, exp(-dot(p - vec2(648.0, 118.0), p - vec2(648.0, 118.0)) / 420.0)); float ln = 0.0; ln = max(ln, seg(p, vec2(566.0, 102.0), vec2(600.0, 88.0), 3.4, 0.3)); ln = max(ln, seg(p, vec2(600.0, 88.0), vec2(636.0, 100.0), 3.4, 0.3)); ln = max(ln, seg(p, vec2(566.0, 102.0), vec2(584.0, 128.0), 3.4, 0.3)); ln = max(ln, seg(p, vec2(584.0, 128.0), vec2(620.0, 128.0), 3.4, 0.3)); ln = max(ln, seg(p, vec2(600.0, 88.0), vec2(620.0, 128.0), 3.4, 0.3)); ln = max(ln, seg(p, vec2(636.0, 100.0), vec2(648.0, 118.0), 3.4, 0.3)); ln = max(ln, seg(p, vec2(620.0, 128.0), vec2(648.0, 118.0), 3.4, 0.3)); v += ln; float hs = hash(vec2(C, R) + 3.7); v += near * step(0.78, hs) * (0.24 + 0.1 * sin(ph + hs * 40.0)); float ne = length((p - vec2(607.0, 110.0)) / vec2(56.0, 36.0)); v += (1.0 - sm(0.82, 1.0, ne)) * step(0.5, hs) * 0.19 + 0.3 * exp(-pow(ne - 1.0, 2.0) / 0.006) * step(0.35, hs); { vec2 A = vec2(510.0, 176.0), B = vec2(578.0, 132.0); vec2 ab = B - A; float h = clamp(dot(p - A, ab) / dot(ab, ab), 0.0, 1.0); vec2 d = (p - A - ab * h) / vec2(3.6, 4.8); v += 0.32 * (1.0 - sm(0.8, 1.05, length(d))) * step(0.5, fract(h * length(ab) / 16.0)); } return v; }
01 / Isolate

Every task gets its own sandbox

The repo goes in and only the diff comes out. Outbound network is off, and the sandbox is thrown away when the task ends.

Agent memory vec3 memory(float t) { vec2 A = vec2(96.0, 96.0), S = vec2(236.0, 147.0), M = vec2(392.0, 150.0), D = vec2(420.0, 304.0 + 7.0 * sin(420.0 * 0.017 + 2.0 * 1.9) + 3.0 * sin(420.0 * 0.05 + 2.0)); if (t < 0.2) return vec3(A, 0.0); if (t < 0.7) return vec3(mix(A, S, ease((t - 0.2) / 0.5)), 1.2 * sm(0.2, 0.3, t)); if (t < 1.7) { float u = (t - 0.7) / 1.0; return vec3(mix(S, M, u) + vec2(0.0, 7.0 * sin(u * 9.0)), 1.2); } if (t < 3.0) { float u = (t - 1.7) / 1.3; float e = 1.0 - pow(1.0 - u, 2.4); return vec3(mix(M, D, e), 1.2); } return vec3(D, 0.0); } float field(vec2 p, float t) { float ph = TAU * t / T; float v = blob(p, vec2(96.0, 96.0), 26.0, 1.05); if (p.x > 164.0 && p.x < 676.0) { // short-term: a surface that churns, blobs welling up and sinking back float n = noise(vec2(p.x * 0.03 + 0.8 * cos(ph), p.y * 0.07 + 0.8 * sin(ph))) * 0.6 + noise(vec2(p.x * 0.07 - 0.5 * sin(ph), p.y * 0.12 + 0.5 * cos(ph))) * 0.4; v += exp(-pow(p.y - 147.0, 2.0) / 500.0) * (0.12 + 1.05 * smoothstep(0.35, 0.85, n)); // long-term: wavy strata of uneven thickness, older and fainter the deeper they lie, the top two sliding faster. // Each layer's tokens repeat every 12 columns and slide a whole number of those a cycle, so the loop closes. for (int i = 0; i < 5; i++) { float fi = float(i); float y = 224.0 + 40.0 * fi + 7.0 * sin(p.x * 0.017 + fi * 1.9) + 3.0 * sin(p.x * 0.05 + fi); float th = 9.0 + 5.0 * noise(vec2(p.x * 0.02, fi * 3.0)); float slide = 84.0 * (i < 2 ? 2.0 : 1.0) * t / T; float tok = step(0.18, hash(vec2(mod(floor((p.x + slide) / 7.0), 12.0), fi))); v += tok * exp(-pow(p.y - y, 2.0) / (th * th)) * (0.85 - 0.1 * fi); } } vec3 m = memory(t); vec2 dir = normalize(vec2(0.18, 1.0)); v += blob(p, m.xy, 11.0, m.z) + blob(p, m.xy - dir * 13.0, 8.0, m.z * 0.35 * step(1.7, t) * step(t, 3.0)); // it settles: a seam spreading along its layer, cooling into it if (t > 2.9) { float u = sm(2.9, 4.1, t); vec2 d = p - memory(2.99).xy; v += (1.0 - u) * 1.1 * exp(-(d.x * d.x) / pow(10.0 + 80.0 * u, 2.0) - (d.y * d.y) / 36.0); } return v; }
02 / Remember

It learns your repo once

What an agent works out about your codebase settles into long-term memory, so the next run starts where the last one left off.

Eval gate An agent writes a diff that runs through six checks in order; it fails the evals and goes back to the agent with the failure, and the revised diff passes every check before a pull request opens. const float LANE = 200.9; const float LK = 21.0; float stepx(float u) { return u - sin(TAU * u) / TAU; } // one check to the next, at rest at each // A diff hunk of five lines: a gutter mark (added, removed, context) and a code line of its own length. float hunk(float c, float r, float ver) { float kind = 0.0; float len = 2.0; if (ver < 0.5) { if (r < 0.5) { kind = 1.0; len = 4.0; } else if (r < 1.5) { kind = -1.0; len = 3.0; } else if (r < 2.5) { kind = 0.0; len = 2.0; } else if (r < 3.5) { kind = 1.0; len = 4.0; } else { kind = 1.0; len = 2.0; } } else { if (r < 0.5) { kind = 1.0; len = 3.0; } else if (r < 1.5) { kind = 1.0; len = 4.0; } else if (r < 2.5) { kind = -1.0; len = 2.0; } else if (r < 3.5) { kind = 1.0; len = 4.0; } else { kind = 0.0; len = 3.0; } } if (c < 0.5) return kind > 0.5 ? 1.1 : kind < -0.5 ? 0.5 : 0.2; if (c > len + 0.5) return 0.0; return kind > 0.5 ? 0.68 : kind < -0.5 ? 0.4 : 0.3; } // The diff at centre q, written as far as w (0 to 1, line by line), with its failure attached under it (fl). float diff(vec2 p, vec2 q, float ver, float w, float fl, float k) { float c = floor((p.x - q.x) / 7.0 + 2.5); float r = floor((p.y - q.y) / 9.4 + 2.5); if (c < 0.0 || c > 4.0 || r < 0.0 || r > 5.0) return 0.0; if (r > 4.5) return fl * (c < 0.5 ? 1.3 : 1.05); if (r + c / 5.0 >= w * 5.0) return 0.0; return k * hunk(c, r, ver); } // The point a distance d along the return path. vec2 back(float d) { if (d <= 21.0) return mix(vec2(427.5, 200.9), vec2(406.5, 200.9), (d - 0.0) / 21.0); if (d <= 124.4) return mix(vec2(406.5, 200.9), vec2(406.5, 304.3), (d - 21.0) / 103.4); if (d <= 421.9) return mix(vec2(406.5, 304.3), vec2(109.0, 304.3), (d - 124.4) / 297.5); if (d <= 489.3) return mix(vec2(109.0, 304.3), vec2(109.0, 236.9), (d - 421.9) / 67.4); return vec2(109.0, 236.9); } // One check's run for a diff that reached it at a: its cells light out from the lane, a cell at a time, up and down // the stage; stopAt under 7 is a test that failed there, and the run stops. Then the light fades back to idle. float scan(float dc, float a, float stopAt, float t) { float s0 = a - 0.06; if (t < s0) return 0.0; float reach = min(7.0 * (t - s0) / 0.12, stopAt); if (dc > floor(reach) + 0.5) return 0.0; float done = s0 + 0.12 * stopAt / 7.0; float fade = 1.0 - sm(done, done + (stopAt < 6.5 ? 0.25 : 0.45), t); float head = (t < done && abs(dc - floor(reach)) < 0.5) ? 0.2 : 0.0; return fade * (1.0 + head); } // Held across the seam: on from on0, and still on from the last cycle until the board clears. float held(float on0, float t) { return max(sm(on0, on0 + 0.06, t), 1.0 - sm(0.25, 0.43, t)); } float field(vec2 p, float t) { if (p.x < 18.0 || p.x > 702.0) return 0.0; float ph = TAU * t / T; float col = floor((p.x - 4.0) / 7.0 + 0.5) - 2.0; float cell = floor(p.y / 9.4); float v = 0.0; // the agent: a bright rim, an inner ring, a speckled floor and a core that churns, and flares while it writes float wr = sm(0.2, 0.3, t) * (1.0 - sm(0.5, 0.7, t)) + sm(2.26, 2.36, t) * (1.0 - sm(2.58, 2.78, t)); { vec2 c = vec2(109.0, LANE); float d = length(p - c) / 30.0; float inside = 1.0 - sm(0.9, 1.0, d); float churn = noise(p * 0.09 + vec2(1.4 * cos(ph), 1.4 * sin(ph))); v += 0.46 * exp(-pow(d - 1.0, 2.0) / 0.008); v += inside * 0.26 * exp(-pow(d - 0.64, 2.0) / 0.005); v += inside * (0.12 + 0.12 * step(0.82, hash(floor(p / vec2(7.0, 9.4)) + 1.3))); v += blob(p, c, 13.2, 0.82 + 0.5 * (churn - 0.5) + 0.45 * wr); } // the forward lane, agent to pull request, and the return lane under the gate, back up into the agent if (abs(cell - LK) < 0.5 && col > 17.0 && col < 81.0) v = max(v, 0.2); if (abs(cell - 32.0) < 0.5 && col >= 13.0 && col <= 65.0) v = max(v, 0.2); if (abs(col - 13.0) < 0.5 && cell > 24.0 && cell < 32.0) v = max(v, 0.2); // the gate's floor: a speckle between the stages, so the gate reads as one housing if (col > 32.0 && col < 67.0 && abs(cell - LK) < 7.5 && step(0.62, hash(vec2(col, cell) + 2.3)) > 0.5) v = max(v, 0.22); // the gate: six stages of test cells, a header and footer cell on each, in order; each runs as the diff reaches it float rel = col - 34.0; float s = floor(rel / 6.0); float dc = abs(cell - LK); if (s >= 0.0 && s <= 5.0 && rel - 6.0 * s < 1.5 && dc < 7.5) { float hs = hash(vec2(col, cell) + 7.1); float base = dc > 6.5 ? 0.85 : 0.42 + 0.2 * step(0.55, hs) * (0.7 + 0.3 * sin(ph + hs * 40.0)); float a1 = 0.84 + s * 0.18; float a2 = 2.92 + s * 0.18; float lit = 0.0; if (s < 4.0 - 0.5) lit = scan(dc, a1, 7.0, t); else if (s < 4.0 + 0.5) lit = scan(dc, a1, 5.0, t); lit = max(lit, scan(dc, a2, 7.0, t)); v = max(v, max(base, lit * (dc > 6.5 ? 1.1 : 1.0))); // the failing test: it flares as the run reaches it, and dims once the diff is back at the agent if (s > 4.0 - 0.5 && s < 4.0 + 0.5 && abs(cell - 16.0) < 0.5) v = max(v, 1.3 * sm(1.576, 1.616, t) * (1.0 - sm(2.07, 2.42, t))); } // the record: a row of six slots per run, each filled as its check passes; run 1 stops at EVALS if (s >= 0.0 && s <= 5.0 && rel - 6.0 * s < 1.5) { if (cell > 35.5 && cell < 37.5) { float fl = s < 4.0 - 0.5 ? held(0.9 + s * 0.18, t) : 0.0; v = max(v, 0.15 + 0.85 * fl); } if (cell > 38.5 && cell < 40.5) v = max(v, 0.15 + 0.85 * held(2.98 + s * 0.18, t)); } // the pull request: a faint outline waiting; it opens once the diff that passed reaches it float open = held(4.18, t); float pc = col - 81.0; float pk = cell - 16.0; if (pc >= 0.0 && pc <= 8.0 && pk >= 0.0 && pk <= 10.0) { bool rim = pc < 0.5 || pc > 7.5 || pk < 0.5 || pk > 9.5; float card = rim ? 0.42 : 0.0; if (abs(pk - 1.0) < 0.5 && pc >= 1.0 && pc <= 6.0) card = 1.05; // the title if (abs(pk - 2.0) < 0.5 && pc >= 1.0 && pc <= 3.0) card = 0.3; // the branch if (pk > 3.5 && pk < 8.5 && pc >= 1.0 && pc <= 5.0) card = max(card, 0.95 * hunk(pc - 1.0, pk - 4.0, 1.0)); // the diff's lines if (abs(pk - 9.0) < 0.5 && pc >= 1.0 && pc <= 6.0) card = max(0.2, 0.95 * held(4.24 + 0.035 * pc, t)); // six check pips v = max(v, rim ? max(0.15, card * open) : card * open); } // diff 1: written, through the four checks it passes, stopped at EVALS, then back to the agent with its failure float fl = sm(1.586, 1.646, t); if (t > 0.25 && t < 0.5) v = max(v, diff(p, vec2(179.0, LANE), 0.0, (t - 0.25) / 0.25, 0.0, 1.0)); else if (t >= 0.5 && t < 0.84) v = max(v, diff(p, vec2(mix(179.0, 259.5, ease((t - 0.5) / 0.34)), LANE), 0.0, 1.0, 0.0, 1.0)); else if (t >= 0.84 && t < 1.66) { float x = 259.5 + 42.0 * stepx(min((t - 0.84) / 0.18, 4.0)); v = max(v, diff(p, vec2(x, LANE), 0.0, 1.0, fl, 1.0)); } else if (t >= 1.66 && t < 2.32) { float u = (t - 1.66) / 0.66; float k = 1.0 - sm(0.88, 1.0, u); v = max(v, diff(p, back(ease(u) * 489.3), 0.0, 1.0, k, k)); } // diff 2: written, through all six checks, out to the pull request if (t > 2.34 && t < 2.58) v = max(v, diff(p, vec2(179.0, LANE), 1.0, (t - 2.34) / 0.24, 0.0, 1.0)); else if (t >= 2.58 && t < 2.92) v = max(v, diff(p, vec2(mix(179.0, 259.5, ease((t - 2.58) / 0.34)), LANE), 1.0, 1.0, 0.0, 1.0)); else if (t >= 2.92 && t < 3.88) v = max(v, diff(p, vec2(259.5 + 42.0 * stepx((t - 2.92) / 0.18), LANE), 1.0, 1.0, 0.0, 1.0)); else if (t >= 3.88 && t < 4.2) { float u = (t - 3.88) / 0.32; v = max(v, diff(p, vec2(mix(469.5, 613.0, ease(u)), LANE), 1.0, 1.0, 0.0, 1.0 - sm(0.8, 1.0, u))); } return v; }
03 / Review

No pull request until the evals pass

Every diff runs your tests and our evals. A failing diff goes back to the agent with the failure attached.

Model routing

Every step on the right model

Kestrel scores each step before it runs. Renames and lookups go to a small, fast model. Only the hard reasoning reaches the large one, so a run costs what it should.

kestrel.yaml
routing:
  small:  score < 0.4   # 72% of steps
  medium: score < 0.8   # 21%
  large:  score ≥ 0.8   # 7%, the hard ones
Model routing Prompts flow into a router that sends most of them to a small model, some to a medium one, and the rare hard prompt to a large one, which flares as it lands. const vec2 GATE = vec2(252.0, 230.0); const float IN0 = 24.0; // the ribbon's left end const float GX = 236.0; // where it meets the gate const float SPEED = 212.0; // route of prompt i: 0 small, 1 medium, 2 large (seven, two, one) float route(int i) { return i == 1 || i == 5 ? 1.0 : i == 8 ? 2.0 : 0.0; } float exitY(float r) { return r < 0.5 ? 150.0 : r < 1.5 ? 230.0 : 310.0; } vec2 poolC(float r) { return r < 0.5 ? vec2(390.0, 92.0) : r < 1.5 ? vec2(500.0, 200.0) : vec2(590.0, 344.0); } float poolR(float r) { return r < 0.5 ? 32.0 : r < 1.5 ? 48.0 : 68.0; } vec2 ctrl(float r) { return r < 0.5 ? vec2(336.0, 152.0) : r < 1.5 ? vec2(390.0, 228.0) : vec2(380.0, 312.0); } float travel(float r) { return r < 0.5 ? 0.42 : r < 1.5 ? 0.72 : 1.2; } // a bigger model is further and slower vec2 bez(vec2 a, vec2 c, vec2 b, float u) { return mix(mix(a, c, u), mix(c, b, u), u); } vec2 chanAt(float r, float u) { return bez(vec2(270.0, exitY(r)), ctrl(r), poolC(r), u); } // A channel from its gate exit to its pool, as far as the pool's rim. float channel(vec2 p, float r, float w, float k) { float v = 0.0; for (int i = 0; i < 8; i++) v = max(v, seg(p, chanAt(r, float(i) / 8.0 * 0.9), chanAt(r, float(i + 1) / 8.0 * 0.9), w, k)); return v; } // A pool: a disc with a bright rim, a ring per layer of the model, a core as hot as it is busy, and a flare. float pool(vec2 p, float r, float busy, float flare) { vec2 c = poolC(r); float R = poolR(r); float d = length(p - c) / R; float inside = 1.0 - sm(0.92, 1.0, d); float v = 0.46 * exp(-pow(d - 1.0, 2.0) / 0.006); float layers = r + 1.0; float q = d * (layers + 1.0); v += inside * 0.26 * exp(-pow(q - floor(q + 0.5), 2.0) / 0.03) * step(0.5, q) * step(q, layers + 0.5); v += inside * 0.13; v += blob(p, c, R * 0.55, busy); v += flare * (inside * (0.55 - 0.35 * d) + blob(p, c, R * 0.6, 0.6)); v += flare * 0.7 * exp(-pow(d - 1.05 - 0.5 * (1.0 - flare), 2.0) / 0.01); return v; } float field(vec2 p, float t) { if (p.x < 18.0 || p.x > 702.0) return 0.0; float ph = TAU * t / T; // the ribbon of prompts, a flow of tokens running right float rib = exp(-pow(p.y - 230.0, 2.0) / 70.0) * sm(IN0 - 6.0, IN0 + 40.0, p.x) * step(p.x, GX); float v = rib * (0.3 + 0.25 * pow(0.5 + 0.5 * sin(p.x * 0.0674 - ph * 10.0), 3.0)); // the gate: two rails, a faint interior, open where the ribbon comes in and at its three exits if (p.y > 110.0 && p.y < 350.0) { float openL = 1.0 - exp(-pow(p.y - 230.0, 2.0) / 60.0); float openR = 1.0 - exp(-pow(p.y - 150.0, 2.0) / 50.0) - exp(-pow(p.y - 230.0, 2.0) / 50.0) - exp(-pow(p.y - 310.0, 2.0) / 50.0); v += 0.46 * exp(-pow(p.x - 235.0, 2.0) / 8.0) * openL + 0.46 * exp(-pow(p.x - 270.0, 2.0) / 8.0) * max(openR, 0.0); v += 0.14 * step(238.0, p.x) * step(p.x, 266.0); } // the channels: wide and busy to the small pool, thin to the large one, each with its flow v += channel(p, 0.0, 8.0, 0.42 + 0.2 * pow(0.5 + 0.5 * sin(p.x * 0.09 - ph * 8.0), 2.0)); v += channel(p, 1.0, 6.5, 0.32 + 0.14 * pow(0.5 + 0.5 * sin(p.x * 0.07 - ph * 4.0), 2.0)); v += channel(p, 2.0, 5.0, 0.24); float hitS = 0.0, hitM = 0.0, flare = 0.0; for (int i = 0; i < 10; i++) { float r = route(i); float a0 = 0.22 + 0.44 * float(i); for (int w = -1; w <= 1; w++) { float a = a0 + float(w) * T; // when it reaches the gate // in the ribbon: as long and as dense as it is hard; the hard one runs three lines deep if (t > a - 1.0 && t < a) { vec2 c = vec2(GX - (a - t) * SPEED, 230.0); float len = r < 0.5 ? 9.0 : r < 1.5 ? 16.0 : 30.0; float ex = exp(-pow((p.x - c.x) / len, 4.0)); if (r > 1.5) v += ex * 1.3 * (exp(-pow(p.y - 220.6, 2.0) / 14.0) + exp(-pow(p.y - 230.0, 2.0) / 14.0) + exp(-pow(p.y - 239.4, 2.0) / 14.0)); else v += ex * (r < 0.5 ? 0.9 : 1.1) * exp(-pow(p.y - 230.0, 2.0) / 22.0); } // in the gate: it settles to its exit, the heavy one sinking float g = 0.2; if (t >= a && t < a + g) { float y = mix(230.0, exitY(r), ease((t - a) / g)); v += blob(p, vec2(GATE.x, y), r > 1.5 ? 12.0 : 8.0, r > 1.5 ? 1.35 : 1.1); } // down its channel to its pool float D = travel(r); if (t >= a + g && t < a + g + D) { float u = (t - a - g) / D; u = r > 1.5 ? mix(u, ease(u), 0.5) : u; float fade = 1.0 - sm(0.82, 1.0, u); if (r > 1.5) { v += blob(p, chanAt(r, u), 13.0, 1.4 * fade) + seg(p, chanAt(r, max(0.0, u - 0.16)), chanAt(r, u), 5.0, 0.55 * fade); } else v += blob(p, chanAt(r, u), r < 0.5 ? 7.5 : 9.0, 1.15 * fade); } float arr = a + g + D; float h = exp(-pow(t - arr, 2.0) / 0.012); if (r < 0.5) hitS += h; else if (r < 1.5) hitM += h; else flare += sm(arr - 0.04, arr + 0.06, t) * (1.0 - sm(arr + 0.25, arr + 1.5, t)); } } v += pool(p, 0.0, 0.8 + 0.35 * hitS, 0.0); v += pool(p, 1.0, 0.55 + 0.4 * hitM, 0.0); v += pool(p, 2.0, 0.28 + 0.6 * flare, flare); v += 0.6 * hitS * exp(-pow(length(p - poolC(0.0)) - 36.0, 2.0) / 20.0); return v; }
Context window float endAt(float t) { return t < 0.3 ? 494.0 : t < 0.9 ? mix(494.0, 284.0, ease((t - 0.3) / 0.6)) : t < 1.3 ? 284.0 : t < 3.4 ? mix(284.0, 494.0, (t - 1.3) / 2.1) : 494.0; } float field(vec2 p, float t) { float X0 = 67.0, LIMIT = 641.0, END = 494.0, COMPACT = 284.0; float e = endAt(t); float most = (END - X0) / (COMPACT - X0); float sq; float zone; if (t < 0.9) { sq = (END - X0) / (e - X0); zone = e; } else { sq = mix(1.0, most, 1.0 - sm(3.5, 4.1, t)); zone = COMPACT; } float squeezed = (sq - 1.0) / (most - 1.0); float tau = p.x <= zone ? X0 + (p.x - X0) * sq : p.x; // new tokens beyond the compacted zone: the pattern they had at t = 0 float k3[3]; k3[0] = 0.95; k3[1] = 0.85; k3[2] = 0.7; float y3[3]; y3[0] = 168.0; y3[1] = 232.0; y3[2] = 296.0; float r3[3]; r3[0] = 13.0; r3[1] = 17.0; r3[2] = 11.0; float v = 0.0; float wob = 5.0 * sin(p.y * 0.18 + TAU * 8.0 * t / T); // whole turns a cycle, so the loop closes for (int i = 0; i < 3; i++) { float band = exp(-pow(p.y - y3[i], 2.0) / (r3[i] * r3[i])); float on = step(0.28, hash(vec2(floor(tau / 7.0), float(i)))); float front = 1.0 - sm(e - 8.0, e + 6.0 + wob, p.x); if (p.x >= X0 && p.x <= LIMIT) { v += band * on * k3[i] * (p.x <= zone ? 1.0 + 0.45 * squeezed : 1.0) * front; v += band * 0.14 * (1.0 - front) * step(p.x, LIMIT); // the write head: a glow at the front while new tokens stream in if (t > 1.3 && t < 3.5) v += blob(p, vec2(e + 3.0, y3[i]), 9.0, 0.8 * sm(1.3, 1.5, t) * (1.0 - sm(3.3, 3.5, t))); } } return v; }
Long context

Reads the whole repo. Keeps what matters.

When a run's context fills up, Kestrel compacts it instead of cutting it off. Old turns are squeezed into a summary, and the agent keeps working with room to spare.

  • 1Mtokens of working context
  • 4xcompaction before anything is dropped
  • 0lost instructions across a run
Traces

See every step of every run

Each run records its steps as a trace: every file read, every tool call, every test. The slow step is obvious at a glance.

Run trace One agent run recorded as a trace on a time axis: a playhead moves along it and five steps run one after another, each with its tool calls nested under it; the test step takes most of the run and is marked slow, and once the evals finish the pull request opens. const float X0 = 158.0; const float PX = 6.6; // lit once the playhead (now, in seconds of the run) has reached column c, or the span's start a, whichever is later float L(float c, float a, float now) { return now >= max((4.0 + 7.0 * c - X0) / PX, a) ? 1.0 : 0.0; } float field(vec2 p, float t) { if (p.x < 18.0 || p.x > 702.0 || p.y < 18.0 || p.y > 442.0) return 0.0; float v = 0.0; float gr = floor(p.y / 9.4); // the cell row float c = floor((p.x - 4.0) / 7.0 + 0.5); // the bar column float hs = hash(vec2(c, gr) + 2.7); // This run's clock: before 0.6 s the last run is still on screen, so it reads the clock a cycle on and clears // from 0.3 to 0.5 s. float tt = t < 0.6 ? t + T : t; float env = 1.0 - sm(T + 0.3, T + 0.5, tt); float now = (tt - 0.6) / 0.0418; // seconds into the run float cEnd = 96.0; // The trace's frame: a faint gridline every 10 s of the axis, dotted, and a faint track along each step's row. if (c >= 22.0 && c <= 97.0) { float sx = (4.0 + 7.0 * c - X0) / PX; if (abs(sx - 10.0 * floor(sx / 10.0 + 0.5)) < 0.6 && gr >= 11.0 && gr <= 40.0 && mod(gr, 2.0) > 0.5) v = 0.17; if (gr == 13.0 && hs > 0.3) v = max(v, 0.2); if (gr == 18.0 && hs > 0.3) v = max(v, 0.2); if (gr == 24.0 && hs > 0.3) v = max(v, 0.2); if (gr == 30.0 && hs > 0.3) v = max(v, 0.2); if (gr == 38.0 && hs > 0.3) v = max(v, 0.2); } // The RUN root span: two rows of the densest bars from 0 to the playhead, and a row of notches under them, the // first column of each step marked dense. if (c >= 22.0 && c <= cEnd) { if (gr >= 4.0 && gr <= 5.0) v = max(v, env * L(c, 0.0, now) * 1.05); if (gr == 6.0) { bool mark = c == 22.0 || c == 24.0 || c == 38.0 || c == 44.0 || c == 90.0; v = max(v, env * L(c, 0.0, now) * (mark ? 1.05 : 0.3)); } } // The sandbox's CPU under the root span: a bar a column, as high as the CPU was busy then (low while the agent waits // on a model, high while tests run), drawn as the playhead reaches it. if (c >= 22.0 && c <= cEnd && gr >= 7.0 && gr <= 9.0) { float sx = (4.0 + 7.0 * c - X0) / PX; float busy = (sx < 0.3 ? 0.45 : (sx < 0.9 ? 0.5 : (sx < 1.5 ? 0.5 : (sx < 2.1 ? 0.45 : (sx < 8.3 ? 0.15 : (sx < 9.1 ? 0.5 : (sx < 10.2 ? 0.45 : (sx < 11.0 ? 0.5 : (sx < 16.9 ? 0.15 : (sx < 17.8 ? 0.45 : (sx < 21.5 ? 0.15 : (sx < 22.3 ? 0.4 : (sx < 23.2 ? 0.6 : (sx < 26.3 ? 0.65 : (sx < 40.9 ? 0.95 : (sx < 47.1 ? 0.9 : (sx < 56.9 ? 0.95 : (sx < 61.3 ? 0.85 : (sx < 68.6 ? 0.95 : (sx < 71.4 ? 0.8 : (sx < 72.9 ? 0.35 : (sx < 74.4 ? 0.3 : (sx < 75.9 ? 0.35 : (sx < 77.4 ? 0.3 : 0.35)))))))))))))))))))))))); float h = clamp(floor(busy * 3.0 * (0.72 + 0.45 * hash(vec2(c, 4.1))) + 0.5), 0.0, 3.0); float lv = 9.0 - gr; float bar = lv < h ? 1.05 : (lv < 0.5 ? 0.3 : 0.0); v = max(v, env * L(c, 0.0, now) * bar); } // The steps and their child spans. if (gr >= 12.0 && gr <= 12.0 && c >= 22.0 && c <= 23.0) v = max(v, env * L(c, 0.0, now) * 1.05); if (gr >= 13.0 && gr <= 13.0 && c >= 22.0 && c <= 23.0) v = max(v, env * L(c, 0.0, now) * (c == 22.0 || c == 23.0 ? 0.6 : 1.05)); if (gr >= 14.0 && gr <= 14.0 && c >= 22.0 && c <= 22.0) v = max(v, env * L(c, 0.0, now) * (c < 22.5 ? 0.7 : 0.42)); if (gr >= 15.0 && gr <= 15.0 && c >= 22.0 && c <= 22.0) v = max(v, env * L(c, 0.3, now) * (c < 22.5 ? 0.7 : 0.42)); if (gr >= 14.0 && gr <= 14.0 && c >= 23.0 && c <= 23.0) v = max(v, env * L(c, 0.9, now) * (c < 23.5 ? 0.7 : 0.42)); if (gr >= 15.0 && gr <= 15.0 && c >= 23.0 && c <= 23.0) v = max(v, env * L(c, 1.5, now) * (c < 23.5 ? 0.7 : 0.42)); if (gr >= 17.0 && gr <= 17.0 && c >= 24.0 && c <= 37.0) v = max(v, env * L(c, 2.1, now) * 1.05); if (gr >= 18.0 && gr <= 18.0 && c >= 24.0 && c <= 37.0) v = max(v, env * L(c, 2.1, now) * (c == 30.0 || c == 31.0 || c == 32.0 ? 0.6 : 1.05)); if (gr >= 19.0 && gr <= 19.0 && c >= 24.0 && c <= 29.0) v = max(v, env * L(c, 2.1, now) * 0.7); if (gr >= 20.0 && gr <= 20.0 && c >= 30.0 && c <= 30.0) v = max(v, env * L(c, 8.3, now) * (c < 30.5 ? 0.7 : 0.42)); if (gr >= 21.0 && gr <= 21.0 && c >= 31.0 && c <= 31.0) v = max(v, env * L(c, 9.1, now) * (c < 31.5 ? 0.7 : 0.42)); if (gr >= 20.0 && gr <= 20.0 && c >= 32.0 && c <= 32.0) v = max(v, env * L(c, 10.2, now) * (c < 32.5 ? 0.7 : 0.42)); if (gr >= 19.0 && gr <= 19.0 && c >= 32.0 && c <= 37.0) v = max(v, env * L(c, 11.0, now) * 0.7); if (gr >= 23.0 && gr <= 23.0 && c >= 38.0 && c <= 43.0) v = max(v, env * L(c, 16.9, now) * 1.05); if (gr >= 24.0 && gr <= 24.0 && c >= 38.0 && c <= 43.0) v = max(v, env * L(c, 16.9, now) * (c == 39.0 || c == 42.0 || c == 43.0 ? 0.6 : 1.05)); if (gr >= 26.0 && gr <= 26.0 && c >= 38.0 && c <= 38.0) v = max(v, env * L(c, 16.9, now) * (c < 38.5 ? 0.7 : 0.42)); if (gr >= 25.0 && gr <= 25.0 && c >= 39.0 && c <= 41.0) v = max(v, env * L(c, 17.8, now) * 0.7); if (gr >= 26.0 && gr <= 26.0 && c >= 42.0 && c <= 42.0) v = max(v, env * L(c, 21.5, now) * (c < 42.5 ? 0.7 : 0.42)); if (gr >= 26.0 && gr <= 26.0 && c >= 43.0 && c <= 43.0) v = max(v, env * L(c, 22.3, now) * (c < 43.5 ? 0.7 : 0.42)); if (gr >= 29.0 && gr <= 29.0 && c >= 44.0 && c <= 89.0) v = max(v, env * L(c, 23.2, now) * 1.05); if (gr >= 30.0 && gr <= 30.0 && c >= 44.0 && c <= 89.0) v = max(v, env * L(c, 23.2, now) * (c == 47.0 || c == 61.0 || c == 66.0 || c == 76.0 || c == 80.0 || c == 87.0 ? 0.6 : 1.05)); if (gr == 31.0 && c >= 44.0 && c <= 89.0) v = max(v, env * L(c, 23.2, now) * (c > 46.7971 && hash(vec2(c, 7.3)) > 0.42 ? 1.05 : 0.42)); if (gr >= 32.0 && gr <= 32.0 && c >= 44.0 && c <= 46.0) v = max(v, env * L(c, 23.2, now) * (c < 44.5 ? 0.7 : 0.42)); if (gr >= 33.0 && gr <= 33.0 && c >= 47.0 && c <= 60.0) v = max(v, env * L(c, 26.3, now) * 0.7); if (gr >= 34.0 && gr <= 34.0 && c >= 61.0 && c <= 65.0) v = max(v, env * L(c, 40.9, now) * 0.7); if (gr >= 32.0 && gr <= 32.0 && c >= 66.0 && c <= 75.0) v = max(v, env * L(c, 47.1, now) * 0.7); if (gr >= 33.0 && gr <= 33.0 && c >= 76.0 && c <= 79.0) v = max(v, env * L(c, 56.9, now) * 0.7); if (gr >= 34.0 && gr <= 34.0 && c >= 80.0 && c <= 86.0) v = max(v, env * L(c, 61.3, now) * 0.7); if (gr >= 32.0 && gr <= 32.0 && c >= 87.0 && c <= 88.0) v = max(v, env * L(c, 68.6, now) * 0.7); if (gr >= 37.0 && gr <= 37.0 && c >= 90.0 && c <= 96.0) v = max(v, env * L(c, 71.4, now) * 1.05); if (gr >= 38.0 && gr <= 38.0 && c >= 90.0 && c <= 96.0) v = max(v, env * L(c, 71.4, now) * (c == 91.0 || c == 92.0 || c == 94.0 || c == 95.0 ? 0.6 : 1.05)); if (gr >= 39.0 && gr <= 39.0 && c >= 90.0 && c <= 90.0) v = max(v, env * L(c, 71.4, now) * 0.7); if (gr >= 40.0 && gr <= 40.0 && c >= 91.0 && c <= 91.0) v = max(v, env * L(c, 72.9, now) * 0.7); if (gr >= 39.0 && gr <= 39.0 && c >= 92.0 && c <= 93.0) v = max(v, env * L(c, 74.4, now) * 0.7); if (gr >= 40.0 && gr <= 40.0 && c >= 94.0 && c <= 94.0) v = max(v, env * L(c, 75.9, now) * 0.7); if (gr >= 39.0 && gr <= 39.0 && c >= 95.0 && c <= 95.0) v = max(v, env * L(c, 77.4, now) * 0.7); // The run's end: the root span's last column flares as the run ends. if (c > cEnd - 1.5 && c < cEnd + 0.5 && gr >= 4.0 && gr <= 6.0) v += env * 0.6 * exp(-pow((tt - 3.95) / 0.06, 2.0)); // The playhead: a line down the trace at the column it is on, with a head on the ruler. This run's shows from // 0.4 s at 0 and moves at the run's pace; the last run's stays at the end until the trace clears. float pNew = t >= 0.4 ? sm(0.4, 0.6, t) : 0.0; float pOld = t < 0.6 ? env : 0.0; float cNew = floor((X0 + PX * clamp((t - 0.6) / 0.0418, 0.0, 78.9) - 4.0) / 7.0); float cOld = floor((X0 + PX * 78.9 - 4.0) / 7.0); float ph = max(c == cNew ? pNew : 0.0, c == cOld ? pOld : 0.0); if (ph > 0.0) { if (gr >= 3.0 && gr <= 40.0) v = max(v, 0.36 * ph); if (gr == 41.0 || gr == 42.0) v = max(v, 1.05 * ph); } float ph2 = max(abs(c - cNew) < 1.5 ? pNew : 0.0, abs(c - cOld) < 1.5 ? pOld : 0.0); if (gr == 42.0) v = max(v, 0.7 * ph2); return v; }
run 8f2c · fix flaky checkout testPR opened
StepModelTime
read_reposmall2.1 s
plan_fixlarge14.8 s
edit checkout.test.tsmedium6.3 s
run_testsnone48.2 s
evalssmall7.5 s
Queue backlog float field(vec2 p, float t) { if (p.x < 18.0 || p.x > 702.0) return 0.0; float ph = TAU * t / T; // how full the basin is: rises while the inflow is fast, drains after float level = 0.22 + 0.66 * (sm(0.2, 2.0, t) - sm(2.4, 4.2, t)); vec2 q = (p - vec2(360.0, 300.0)) / vec2(150.0, 110.0); float inside = step(abs(q.x), 1.0) * step(q.y, 1.0) * step(-1.0, q.y); float surface = 1.0 - 2.0 * level; float body = inside * sm(surface - 0.04, surface + 0.04, q.y) * (0.45 + 0.35 * (q.y - surface) / 2.0); float v = body * (0.85 + 0.15 * noise(p * 0.06 + 2.0 * vec2(cos(ph), sin(ph)))); // the inflow: heavy while the queue grows float pour = 0.25 + 0.6 * (1.0 - sm(1.6, 2.4, t)) * sm(0.0, 0.3, t); v += seg(p, vec2(140.0, 80.0), vec2(300.0, 300.0 - 220.0 * level + 10.0), 10.0, pour * 0.6); // three workers under the floor, pulsing as they take a job for (int i = 0; i < 3; i++) { float fi = float(i); v += blob(p, vec2(270.0 + 90.0 * fi, 432.0), 16.0, 0.5 + 0.35 * pow(0.5 + 0.5 * sin(ph * 3.0 - fi * 2.1), 4.0)); } return v; }
Scale

A thousand runs, one queue

Tasks queue up during a release and workers drain them as they free up. Nothing is dropped, and nothing jumps the line.

Rate limiting float rate(float x) { float P = 420.0; float b = 0.0; for (int j = -1; j <= 3; j++) b += exp(-pow(x - 420.0 - float(j) * P, 2.0) / 2116.0); return 70.0 + 36.0 * sin(TAU * 3.0 * x / P + 0.3) + 24.0 * sin(TAU * 7.0 * x / P + 1.0) + 190.0 * b; } float field(vec2 p, float t) { float X0 = 60.0, X1 = 655.0, FLOOR = 400.0, LIM = 220.0; if (p.x < X0 || p.x > X1 || p.y > FLOOR) return 0.0; float xx = p.x + 420.0 * t / T; float top = FLOOR - rate(xx); if (p.y < top) return 0.0; if (p.y >= LIM) { float flare = top < LIM ? 0.45 * exp(-pow(p.y - LIM, 2.0) / 50.0) : 0.0; return 0.42 + 0.5 * (p.y - max(top, LIM)) / (FLOOR - max(top, LIM)) + flare; } // above the limit: sheared off, breaking into spray that rises and fades. It moves 60 columns and 30 cells a cycle, // and its pattern repeats over exactly those, so the loop closes. float rise = (LIM - p.y) / (LIM - top + 1.0); float spray = step(0.6, hash(vec2(mod(floor(xx / 7.0), 60.0), mod(floor((p.y + 9.4 * 30.0 * t / T) / 9.4), 30.0)))); return spray * (0.55 - 0.42 * rise); }
Guardrails

Rate limits per repo

Set how fast each repo may spend. Bursts above the limit are turned away at the edge, before they cost anything.

Get started

Your first run in two commands

Point Kestrel at a repo and give it a task. It opens a pull request when the work is ready for review.

Terminal
$ npx kestrel init
$ kestrel run "fix the flaky checkout test"

✓ sandbox ready 0.8 s

✓ 48 of 48 checks passed

✓ pull request #412 opened

Pricing

Pay for runs, not seats you don't use

Hobby

$0

For trying it on one repo.

  • 100 runs a month
  • 1 repo
  • Seven days of traces
Start free
Most teams

Team

$40 per seat a month

For a team shipping every day.

  • Unlimited runs
  • Unlimited repos
  • Memory shared across the team
  • Rate limits per repo
Start a run

Enterprise

Custom

Your cloud, your models.

  • Runs inside your VPC
  • Bring your own models
  • SSO and audit log
Talk to us

Every plan, side by side: compare plans

Give your agents
a runtime.